Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix systemd support #153

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 194 additions & 17 deletions src/gs-listener-dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
#define dbus_bus_request_name(connection, name, flags, err) dbus_bus_acquire_service(connection, name, flags, err)
#endif

#define SYSTEMD_SESSION_REQUIRE_ONLINE 0

static void gs_listener_class_init (GSListenerClass *klass);
static void gs_listener_init (GSListener *listener);
static void gs_listener_finalize (GObject *object);
Expand All @@ -80,7 +82,6 @@ struct GSListenerPrivate

#ifdef WITH_SYSTEMD
gboolean have_systemd;
char *sd_session_id;
int delay_fd;
#endif

Expand Down Expand Up @@ -138,7 +139,7 @@ gs_listener_send_switch_greeter (GSListener *listener)
/* Compare with 0. On failure this will return < 0.
* In the later case we probably aren't using systemd.
*/
if (sd_session_is_active (listener->priv->sd_session_id) == 0) {
if (sd_session_is_active (listener->priv->session_id) == 0) {
gs_debug ("Refusing to switch to greeter");
return;
};
Expand Down Expand Up @@ -179,7 +180,7 @@ gs_listener_send_lock_session (GSListener *listener)
/* Compare with 0. On failure this will return < 0.
* In the later case we probably aren't using systemd.
*/
if (sd_session_is_active (listener->priv->sd_session_id) == 0) {
if (sd_session_is_active (listener->priv->session_id) == 0) {
gs_debug ("Refusing to lock session");
return;
};
Expand Down Expand Up @@ -1996,17 +1997,196 @@ query_session_id (GSListener *listener)
}

#ifdef WITH_SYSTEMD
static gboolean session_is_graphical (char const *session_id)
{
char const *const graphical_session_types[] = { "wayland", "x11", "mir", NULL };

int error_code;
char *type;

error_code = sd_session_get_type(session_id, &type);
if (error_code < 0)
{
g_warning (
"Couldn't get type for session '%s': %s",
session_id,
g_strerror (-error_code));

return FALSE;
}

if (!g_strv_contains (graphical_session_types, type))
{
g_debug (
"Session '%s' is not a graphical session (type: '%s')",
session_id,
type);

free (type);

return FALSE;
}

free (type);

return TRUE;
}

static gboolean session_is_active (char const *session_id)
{
char const *const active_states[] = { "active", "online", NULL };

int error_code;
char *state;

error_code = sd_session_get_state (session_id, &state);
if (error_code < 0)
{
g_warning (
"Couldn't get state for session '%s': %s",
session_id,
g_strerror (-error_code));

return FALSE;
}

if (!g_strv_contains (active_states, state))
{
g_debug ("Session '%s' is not active or online", session_id);

free (state);

return FALSE;
}

free (state);

return TRUE;
}

static char *
find_graphical_session (GSListener *listener)
{
DBusMessage *message, *reply;
DBusError error;

char **sessions;
int session_count;
char *found_session;

gs_debug ("Finding a graphical session for user %d", getuid());

session_count = sd_uid_get_sessions (
getuid(),
SYSTEMD_SESSION_REQUIRE_ONLINE,
&sessions);

if (session_count < 0)
{
gs_debug ("Failed to get sessions for user %d", getuid());
return NULL;
}

for (int i = 0; i < session_count; ++i)
{
g_debug ("Trying session '%s'", sessions[i]);

if (!session_is_graphical (sessions[i]))
continue;

if (!session_is_active (sessions[i]))
continue;

found_session = sessions[i];
}

if (found_session)
{
dbus_error_init(&error); /* FIXME: potential leak? */

message = dbus_message_new_method_call (
SYSTEMD_LOGIND_SERVICE,
SYSTEMD_LOGIND_PATH,
SYSTEMD_LOGIND_INTERFACE,
"GetSession");

if (message == NULL)
{
gs_debug ("Couldn't allocate dbus message");
found_session = NULL;
goto cleanup;
}

if (dbus_message_append_args (
message,
DBUS_TYPE_STRING,
&found_session,
DBUS_TYPE_INVALID) == FALSE)
{
gs_debug ("Couldn't add args to the dbus message");
dbus_message_unref (message);
found_session = NULL;
goto cleanup;
}

/* FIXME: use async? */
reply = dbus_connection_send_with_reply_and_block (
listener->priv->system_connection,
message,
-1,
&error);
dbus_message_unref (message);

if (dbus_error_is_set (&error))
{
gs_debug ("%s raised:\n %s\n\n", error.name, error.message);
dbus_error_free (&error);
found_session = NULL;
goto cleanup;
}

if (dbus_message_get_args(
reply,
&error,
DBUS_TYPE_OBJECT_PATH,
&found_session,
DBUS_TYPE_INVALID))
found_session = g_strdup (found_session);

dbus_message_unref (reply);

if (dbus_error_is_set (&error))
{
gs_debug ("%s raised:\n %s\n\n", error.name, error.message);
dbus_error_free (&error);
found_session = NULL;
}
}

cleanup:
for (int i = 0; i < session_count; ++i)
free (sessions[i]);

free (sessions);

return found_session;
}

static char *
query_sd_session_id (GSListener *listener)
{
char *ssid;
char *t;
int r;

r = sd_pid_get_session (0, &t);
if (r < 0) {
gs_debug ("Couldn't determine our own sd session id: %s", strerror (-r));
return NULL;
r = sd_pid_get_session (getpid(), &t);
if (r < 0)
{
gs_debug (
"Couldn't determine our own sd session id directly: %s",
strerror (-r));

return find_graphical_session (listener);
}

ssid = g_strdup (t);
Expand All @@ -2022,19 +2202,20 @@ init_session_id (GSListener *listener)
g_free (listener->priv->session_id);
listener->priv->session_id = query_session_id (listener);
if (listener->priv->session_id == NULL)
g_error ("session_id is not set, is /proc mounted with hidepid>0?");
gs_debug ("session_id is not set, is /proc mounted with hidepid>0?");
else
gs_debug ("Got session-id: %s", listener->priv->session_id);

#ifdef WITH_SYSTEMD
g_free (listener->priv->sd_session_id);
listener->priv->sd_session_id = query_sd_session_id (listener);
if (listener->priv->sd_session_id == NULL)
g_free (listener->priv->session_id);
/* FIXME: WMs like i3 might want to use the DBus method instead, needs testing */
listener->priv->session_id = find_graphical_session (listener);
if (listener->priv->session_id == NULL)
{
gs_debug ("Falling back to XDG_SESSION_ID environment variable");
listener->priv->sd_session_id = g_strdup(getenv("XDG_SESSION_ID"));
listener->priv->session_id = g_strdup(getenv("XDG_SESSION_ID"));
}
gs_debug ("Got sd-session-id: %s", listener->priv->sd_session_id);
gs_debug ("Got sd-session-id: %s", listener->priv->session_id);
#endif
}

Expand Down Expand Up @@ -2152,10 +2333,6 @@ gs_listener_finalize (GObject *object)
g_free (listener->priv->session_id);
g_free (listener->priv->seat_path);

#ifdef WITH_SYSTEMD
g_free (listener->priv->sd_session_id);
#endif

G_OBJECT_CLASS (gs_listener_parent_class)->finalize (object);
}

Expand Down