Commit d45610fe authored by Ray Strode's avatar Ray Strode
Browse files

wip: start adding systemd support

Only started, still more to do, just sketching at this point.
parent 1f0356a6
......@@ -161,10 +161,22 @@ AC_PATH_PROG([XSLTPROC], [xsltproc])
# systemd
PKG_CHECK_MODULES(SYSTEMD, [libsystemd-login libsystemd-daemon],
[have_systemd=yes], [have_systemd=no])
AC_SUBST(SYSTEMD_CFLAGS)
AC_SUBST(SYSTEMD_LIBS)
LIBACCOUNTSSERVICE_LIBS="$LIBACCOUNTSSERVICE_LIBS $SYSTEMD_LIBS"
LIBACCOUNTSSERVICE_CFLAGS="$LIBACCOUNTSSERVICE_CFLAGS $SYSTEMD_CFLAGS"
if test "x$have_systemd" != "no" ; then
AC_DEFINE(WITH_SYSTEMD, 1, [Define to enable systemd support])
fi
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[],
[with_systemdsystemunitdir=yes])
[with_systemdsystemunitdir=$have_systemd])
if test "x$with_systemdsystemunitdir" = "xyes"; then
with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
fi
......
......@@ -39,6 +39,12 @@
#include <glib/gstdio.h>
#include <glib-object.h>
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#ifdef WITH_SYSTEMD
#include <systemd/sd-daemon.h>
#include <systemd/sd-login.h>
#endif
#include "act-user-manager.h"
#include "act-user-private.h"
......@@ -76,6 +82,10 @@ typedef struct
char *session_id;
ConsoleKitSeat *seat_proxy;
ConsoleKitSession *session_proxy;
#ifdef WITH_SYSTEMD
sd_login_monitor *session_monitor;
GInputStream *session_monitor_stream;
#endif
} ActUserManagerSeat;
typedef enum {
......@@ -195,33 +205,14 @@ act_user_manager_error_quark (void)
}
static gboolean
start_new_login_session (ActUserManager *manager)
{
GError *error;
gboolean res;
res = g_spawn_command_line_async ("gdmflexiserver -s", &error);
if (! res) {
if (error != NULL) {
g_warning ("Unable to start new login: %s", error->message);
g_error_free (error);
} else {
g_warning ("Unable to start new login");
}
}
return res;
}
static gboolean
activate_session_id (ActUserManager *manager,
const char *seat_id,
const char *session_id)
activate_console_kit_session_id (ActUserManager *manager,
const char *seat_id,
const char *session_id)
{
ConsoleKitSeat *proxy;
GError *error = NULL;
gboolean res = FALSE;
proxy = console_kit_seat_proxy_new_sync (manager->priv->connection,
G_DBUS_PROXY_FLAGS_NONE,
CK_NAME,
......@@ -243,9 +234,57 @@ activate_session_id (ActUserManager *manager,
return TRUE;
}
#ifdef WITH_SYSTEMD
static gboolean
session_is_login_window (ActUserManager *manager,
const char *session_id)
activate_systemd_session_id (ActUserManager *manager,
const char *seat_id,
const char *session_id)
{
GDBusConnection *connection;
GVariant *reply;
GError *error;
error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
goto failed;
}
reply = g_dbus_connection_call_sync (connection,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"ActivateSessionOnSeat",
g_variant_new ("(ss)",
seat_id,
session_id),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
g_object_unref (connection);
if (reply == NULL) {
goto failed;
}
g_object_unref (reply);
return TRUE;
failed:
g_warning ("Unable to activate session: %s", error->message);
g_error_free (error);
return FALSE;
}
#endif
static gboolean
_ck_session_is_login_window (ActUserManager *manager,
const char *session_id)
{
ConsoleKitSession *proxy;
GError *error = NULL;
......@@ -280,99 +319,94 @@ session_is_login_window (ActUserManager *manager,
return ret;
}
static char *
_get_login_window_session_id (ActUserManager *manager)
#ifdef WITH_SYSTEMD
static gboolean
_systemd_session_is_login_window (ActUserManager *manager,
const char *session_id)
{
gboolean can_activate_sessions;
GError *error = NULL;
gchar **sessions, **i;
char *primary_ssid;
if (manager->priv->seat.id == NULL || manager->priv->seat.id[0] == '\0') {
g_debug ("ActUserManager: display seat ID is not set; can't switch sessions");
return NULL;
}
int res;
int ret;
char *session_class;
can_activate_sessions = act_user_manager_can_switch (manager);
ret = FALSE;
res = sd_session_get_class (session_id, &session_class);
if (! can_activate_sessions) {
g_debug ("ActUserManager: seat is unable to activate sessions");
return NULL;
if (res < 0) {
g_debug ("failed to determine class of session %s: %s",
session_id,
strerror (-res));
goto out;
}
if (!console_kit_seat_call_get_sessions_sync (manager->priv->seat.seat_proxy, &sessions, NULL, &error)) {
if (error != NULL) {
g_warning ("unable to determine sessions for user: %s",
error->message);
g_error_free (error);
} else {
g_warning ("unable to determine sessions for user");
}
return NULL;
if (g_strcmp0 (session_class, "greeter") == 0) {
ret = TRUE;
}
primary_ssid = NULL;
for (i = sessions; i; i++) {
if (session_is_login_window (manager, *i)) {
primary_ssid = g_strdup (*i);
break;
}
free (session_class);
out:
return ret;
}
#endif
static gboolean
session_is_login_window (ActUserManager *manager,
const char *session_id)
{
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
return _systemd_session_is_login_window (manager, session_id);
}
g_strfreev (sessions);
#endif
return primary_ssid;
return _ck_session_is_login_window (manager, session_id);
}
gboolean
act_user_manager_goto_login_session (ActUserManager *manager)
{
gboolean ret;
gboolean res;
char *ssid;
GError *error;
g_return_val_if_fail (ACT_IS_USER_MANAGER (manager), FALSE);
g_return_val_if_fail (manager->priv->is_loaded, FALSE);
ret = FALSE;
/* First look for any existing LoginWindow sessions on the seat.
If none are found, create a new one. */
ssid = _get_login_window_session_id (manager);
if (ssid != NULL) {
res = activate_session_id (manager, manager->priv->seat.id, ssid);
if (res) {
ret = TRUE;
res = g_spawn_command_line_async ("gdmflexiserver", &error);
if (! res) {
if (error != NULL) {
g_warning ("Unable to start new login: %s", error->message);
g_error_free (error);
} else {
g_warning ("Unable to start new login");
}
}
if (! ret) {
res = start_new_login_session (manager);
if (res) {
ret = TRUE;
}
}
return res;
return ret;
}
#ifdef WITH_SYSTEMD
gboolean
act_user_manager_can_switch (ActUserManager *manager)
_can_activate_systemd_sessions (ActUserManager *manager)
{
gboolean can_activate_sessions;
GError *error = NULL;
int res;
if (!manager->priv->is_loaded) {
g_debug ("ActUserManager: Unable to switch sessions until fully loaded");
res = sd_seat_can_multi_session (manager->priv->seat.id);
if (res < 0) {
g_warning ("unable to determine if seat can activate sessions: %s",
strerror (-res));
return FALSE;
}
if (manager->priv->seat.id == NULL || manager->priv->seat.id[0] == '\0') {
g_debug ("ActUserManager: display seat ID is not set; can't switch sessions");
return FALSE;
}
return res > 0;
}
#endif
g_debug ("ActUserManager: checking if seat can activate sessions");
gboolean
_can_activate_console_kit_sessions (ActUserManager *manager)
{
GError *error = NULL;
gboolean can_activate_sessions = FALSE;
if (!console_kit_seat_call_can_activate_sessions_sync (manager->priv->seat.seat_proxy, &can_activate_sessions, NULL, &error)) {
if (error != NULL) {
......@@ -388,6 +422,31 @@ act_user_manager_can_switch (ActUserManager *manager)
return can_activate_sessions;
}
gboolean
act_user_manager_can_switch (ActUserManager *manager)
{
if (!manager->priv->is_loaded) {
g_debug ("ActUserManager: Unable to switch sessions until fully loaded");
return FALSE;
}
if (manager->priv->seat.id == NULL || manager->priv->seat.id[0] == '\0') {
g_debug ("ActUserManager: display seat ID is not set; can't switch sessions");
return FALSE;
}
g_debug ("ActUserManager: checking if seat can activate sessions");
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
return _can_activate_systemd_sessions (manager);
}
#endif
return _can_activate_console_kit_sessions (manager);
}
gboolean
act_user_manager_activate_user_session (ActUserManager *manager,
ActUser *user)
......@@ -415,7 +474,13 @@ act_user_manager_activate_user_session (ActUserManager *manager,
goto out;
}
res = activate_session_id (manager, manager->priv->seat.id, ssid);
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
return activate_systemd_session_id (manager, manager->priv->seat.id, ssid);
}
#endif
res = activate_console_kit_session_id (manager, manager->priv->seat.id, ssid);
if (! res) {
g_debug ("ActUserManager: unable to activate session: %s", ssid);
goto out;
......@@ -499,9 +564,42 @@ on_get_seat_id_finished (GObject *object,
g_object_unref (manager);
}
#ifdef WITH_SYSTEMD
static void
_get_systemd_seat_id (ActUserManager *manager)
{
int res;
char *seat_id;
res = sd_session_get_seat (manager->priv->seat.session_id,
&seat_id);
if (res < 0) {
g_warning ("Could not get seat of session '%s': %s",
manager->priv->seat.session_id,
strerror (-res));
unload_seat (manager);
return;
}
manager->priv->seat.id = g_strdup (seat_id);
free (seat_id);
manager->priv->seat.state++;
load_seat_incrementally (manager);
}
#endif
static void
get_seat_id_for_current_session (ActUserManager *manager)
{
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
_get_systemd_seat_id (manager);
return;
}
#endif
console_kit_session_call_get_seat_id (manager->priv->seat.session_proxy,
NULL,
on_get_seat_id_finished,
......@@ -808,9 +906,41 @@ on_get_current_session_finished (GObject *object,
g_object_unref (manager);
}
#ifdef WITH_SYSTEMD
static void
_get_current_systemd_session_id (ActUserManager *manager)
{
char *session_id;
int res;
res = sd_seat_get_active ("seat0", &session_id, NULL);
if (res < 0) {
g_debug ("Failed to identify the current session: %s",
strerror (-res));
unload_seat (manager);
return;
}
manager->priv->seat.session_id = g_strdup (session_id);
free (session_id);
manager->priv->seat.state++;
load_seat_incrementally (manager);
}
#endif
static void
get_current_session_id (ActUserManager *manager)
{
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
_get_current_systemd_session_id (manager);
return;
}
#endif
console_kit_manager_call_get_current_session (manager->priv->ck_manager_proxy, NULL,
on_get_current_session_finished,
g_object_ref (manager));
......@@ -841,6 +971,13 @@ static void
get_proxy_for_new_session (ActUserManagerNewSession *new_session)
{
GError *error = NULL;
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
new_session->state++;
load_new_session_incrementally (new_session);
return;
}
#endif
new_session->proxy = console_kit_session_proxy_new_sync (new_session->manager->priv->connection,
G_DBUS_PROXY_FLAGS_NONE,
......@@ -893,9 +1030,40 @@ on_get_unix_user_finished (GObject *object,
load_new_session_incrementally (new_session);
}
#ifdef WITH_SYSTEMD
static void
_get_uid_for_new_systemd_session (ActUserManagerNewSession *new_session)
{
uid_t uid;
int res;
res = sd_session_get_uid (new_session->id, &uid);
if (res < 0) {
g_debug ("Failed to get uid of session '%s': %s",
new_session->id,
strerror (-res));
unload_new_session (new_session);
return;
}
new_session->uid = uid;
new_session->state++;
load_new_session_incrementally (new_session);
}
#endif
static void
get_uid_for_new_session (ActUserManagerNewSession *new_session)
{
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
_get_uid_for_new_systemd_session (new_session);
return;
}
#endif
g_assert (new_session->proxy != NULL);
console_kit_session_call_get_unix_user (new_session->proxy,
......@@ -1061,9 +1229,45 @@ on_get_x11_display_finished (GObject *object,
load_new_session_incrementally (new_session);
}
#ifdef WITH_SYSTEMD
static void
_get_x11_display_for_new_systemd_session (ActUserManagerNewSession *new_session)
{
char *x11_display;
int res;
res = sd_session_get_display (new_session->id,
&x11_display);
if (res < 0) {
g_debug ("ActUserManager: Failed to get the x11 display of session '%s': %s",
new_session->id,
strerror (-res));
unload_new_session (new_session);
return;
}
g_debug ("ActUserManager: Found x11 display of session '%s': %s",
new_session->id, x11_display);
new_session->x11_display = g_strdup (x11_display);
free (x11_display);
new_session->state++;
load_new_session_incrementally (new_session);
}
#endif
static void
get_x11_display_for_new_session (ActUserManagerNewSession *new_session)
{
#ifdef WITH_SYSTEMD
if (sd_booted () > 0) {
_get_x11_display_for_new_systemd_session (new_session);
return;
}
#endif
g_assert (new_session->proxy != NULL);
console_kit_session_call_get_x11_display (new_session->proxy,
......@@ -1186,9 +1390,8 @@ match_new_session_cmpfunc (gconstpointer a,
}
static void
seat_session_removed (GDBusProxy *seat_proxy,
const char *session_id,
ActUserManager *manager)
_remove_session (ActUserManager *manager,
const char *session_id)
{
ActUser *user;
GSList *found;
......@@ -1239,11 +1442,209 @@ seat_session_removed (GDBusProxy *seat_proxy,
_act_user_remove_session (user, session_id);
}
static void
seat_session_removed (GDBusProxy *seat_proxy,
const char *session_id,
ActUserManager *manager)
{
_remove_session (manager, session_id);
}
#ifdef WITH_SYSTEMD
static gboolean
_session_recognized (ActUserManager *manager,
const char *session_id)
{
GSList *node;
if (g_hash_table_contains (manager->priv->sessions,
session_id)) {
return TRUE;
}
node = manager->priv->new_sessions;
while (node != NULL) {
ActUserManagerNewSession *new_session = node->data;
if (g_strcmp0 (new_session->id, session_id) == 0) {
return TRUE;
}
node = node->next;
}
return FALSE;
}
static void
_add_systemd_session (ActUserManager *manager,
const char *session_id)
{
load_new_session (manager, session_id);
}
static void
_add_new_systemd_sessions (ActUserManager *manager,
GHashTable *systemd_sessions)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, systemd_sessions);
while (g_hash_table_iter_next (&iter, &key, &value)) {
char *session_id = key;
if (!_session_recognized (manager, session_id)) {
_add_systemd_session (manager, session_id);
}
}
}
static void
_remove_systemd_session (ActUserManager *manager,
const char *session_id)
{
_remove_session (manager, session_id);
}
static void
_remove_stale_systemd_sessions (ActUserManager *manager,
GHashTable *systemd_sessions)
{
GHashTableIter iter;
gpointer key, value;
GSList *node