gnome-session/0002-system-add-api-for-detecting-if-this-is-the-last-ses.patch
Ray Strode c15b918a94 - Kill bus clients at log out
Resolves: #1340203

- Address crash in fail whale
  Related: #1384508
2017-06-30 16:51:23 +02:00

459 lines
15 KiB
Diff

From f708bbbf2df41ea9683f7667c745d0297e584968 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 20 Jun 2017 16:51:00 -0400
Subject: [PATCH 2/3] system: add api for detecting if this is the last session
for a user
https://bugzilla.gnome.org/show_bug.cgi?id=764029
---
gnome-session/gsm-consolekit.c | 7 +++++
gnome-session/gsm-system.c | 7 +++++
gnome-session/gsm-system.h | 3 ++
gnome-session/gsm-systemd.c | 63 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 80 insertions(+)
diff --git a/gnome-session/gsm-consolekit.c b/gnome-session/gsm-consolekit.c
index 4de5c1eb..3d3891e2 100644
--- a/gnome-session/gsm-consolekit.c
+++ b/gnome-session/gsm-consolekit.c
@@ -1012,59 +1012,66 @@ gsm_consolekit_add_inhibitor (GsmSystem *system,
{
}
static void
gsm_consolekit_remove_inhibitor (GsmSystem *system,
const gchar *id)
{
}
static void
gsm_consolekit_prepare_shutdown (GsmSystem *system,
gboolean restart)
{
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
consolekit->priv->restarting = restart;
g_signal_emit_by_name (system, "shutdown-prepared", TRUE);
}
static void
gsm_consolekit_complete_shutdown (GsmSystem *system)
{
GsmConsolekit *consolekit = GSM_CONSOLEKIT (system);
if (consolekit->priv->restarting)
gsm_consolekit_attempt_restart (system);
else
gsm_consolekit_attempt_stop (system);
}
+static gboolean
+gsm_consolekit_is_last_session_for_user (GsmSystem *system)
+{
+ return FALSE;
+}
+
static void
gsm_consolekit_system_init (GsmSystemInterface *iface)
{
iface->can_switch_user = gsm_consolekit_can_switch_user;
iface->can_stop = gsm_consolekit_can_stop;
iface->can_restart = gsm_consolekit_can_restart;
iface->can_suspend = gsm_consolekit_can_suspend;
iface->can_hibernate = gsm_consolekit_can_hibernate;
iface->attempt_stop = gsm_consolekit_attempt_stop;
iface->attempt_restart = gsm_consolekit_attempt_restart;
iface->suspend = gsm_consolekit_suspend;
iface->hibernate = gsm_consolekit_hibernate;
iface->set_session_idle = gsm_consolekit_set_session_idle;
iface->is_login_session = gsm_consolekit_is_login_session;
iface->add_inhibitor = gsm_consolekit_add_inhibitor;
iface->remove_inhibitor = gsm_consolekit_remove_inhibitor;
iface->prepare_shutdown = gsm_consolekit_prepare_shutdown;
iface->complete_shutdown = gsm_consolekit_complete_shutdown;
+ iface->is_last_session_for_user = gsm_consolekit_is_last_session_for_user;
}
GsmConsolekit *
gsm_consolekit_new (void)
{
GsmConsolekit *manager;
manager = g_object_new (GSM_TYPE_CONSOLEKIT, NULL);
return manager;
}
diff --git a/gnome-session/gsm-system.c b/gnome-session/gsm-system.c
index c24a9550..a78409d6 100644
--- a/gnome-session/gsm-system.c
+++ b/gnome-session/gsm-system.c
@@ -70,60 +70,61 @@ gsm_system_default_init (GsmSystemInterface *iface)
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
g_object_interface_install_property (iface, pspec);
}
typedef GObject GsmSystemNull;
typedef GObjectClass GsmSystemNullClass;
static void do_nothing (void) { }
static gboolean return_true (void) { return TRUE; }
static gboolean return_false (void) { return TRUE; }
static void
gsm_system_null_init_iface (GsmSystemInterface *iface)
{
iface->can_switch_user = (void *) return_false;
iface->can_stop = (void *) return_false;
iface->can_restart = (void *) return_false;
iface->can_suspend = (void *) return_false;
iface->can_hibernate = (void *) return_false;
iface->attempt_stop = (void *) do_nothing;
iface->attempt_restart = (void *) do_nothing;
iface->suspend = (void *) do_nothing;
iface->hibernate = (void *) do_nothing;
iface->set_session_idle = (void *) do_nothing;
iface->is_login_session = (void *) return_true;
iface->add_inhibitor = (void *) do_nothing;
iface->remove_inhibitor = (void *) do_nothing;
iface->prepare_shutdown = (void *) do_nothing;
iface->complete_shutdown = (void *) do_nothing;
+ iface->is_last_session_for_user = (void *) return_false;
}
static void
gsm_system_null_init (GsmSystemNull *gsn)
{
}
static void
gsm_system_null_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
g_value_set_boolean (value, TRUE);
}
static void
gsm_system_null_class_init (GsmSystemNullClass *class)
{
class->get_property = gsm_system_null_get_property;
class->set_property = (void *) do_nothing;
g_object_class_override_property (class, 1, "active");
}
static GType gsm_system_null_get_type (void);
G_DEFINE_TYPE_WITH_CODE (GsmSystemNull, gsm_system_null, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GSM_TYPE_SYSTEM, gsm_system_null_init_iface))
GQuark
gsm_system_error_quark (void)
{
@@ -191,60 +192,66 @@ gsm_system_hibernate (GsmSystem *system)
}
void
gsm_system_set_session_idle (GsmSystem *system,
gboolean is_idle)
{
GSM_SYSTEM_GET_IFACE (system)->set_session_idle (system, is_idle);
}
void
gsm_system_add_inhibitor (GsmSystem *system,
const gchar *id,
GsmInhibitorFlag flag)
{
GSM_SYSTEM_GET_IFACE (system)->add_inhibitor (system, id, flag);
}
void
gsm_system_remove_inhibitor (GsmSystem *system,
const gchar *id)
{
GSM_SYSTEM_GET_IFACE (system)->remove_inhibitor (system, id);
}
gboolean
gsm_system_is_login_session (GsmSystem *system)
{
return GSM_SYSTEM_GET_IFACE (system)->is_login_session (system);
}
+gboolean
+gsm_system_is_last_session_for_user (GsmSystem *system)
+{
+ return GSM_SYSTEM_GET_IFACE (system)->is_last_session_for_user (system);
+}
+
/**
* gsm_system_is_active:
*
* Returns: %TRUE if the current session is in the foreground
* Since: 3.8
*/
gboolean
gsm_system_is_active (GsmSystem *system)
{
gboolean is_active;
g_object_get ((GObject*)system, "active", &is_active, NULL);
return is_active;
}
void
gsm_system_prepare_shutdown (GsmSystem *system,
gboolean restart)
{
GSM_SYSTEM_GET_IFACE (system)->prepare_shutdown (system, restart);
}
void
gsm_system_complete_shutdown (GsmSystem *system)
{
GSM_SYSTEM_GET_IFACE (system)->complete_shutdown (system);
}
GsmSystem *
gsm_get_system (void)
{
diff --git a/gnome-session/gsm-system.h b/gnome-session/gsm-system.h
index cc1c06a0..3a34b508 100644
--- a/gnome-session/gsm-system.h
+++ b/gnome-session/gsm-system.h
@@ -43,83 +43,86 @@ typedef enum _GsmSystemError GsmSystemError;
struct _GsmSystemInterface
{
GTypeInterface base_interface;
void (* request_completed) (GsmSystem *system,
GError *error);
void (* shutdown_prepared) (GsmSystem *system,
gboolean success);
gboolean (* can_switch_user) (GsmSystem *system);
gboolean (* can_stop) (GsmSystem *system);
gboolean (* can_restart) (GsmSystem *system);
gboolean (* can_suspend) (GsmSystem *system);
gboolean (* can_hibernate) (GsmSystem *system);
void (* attempt_stop) (GsmSystem *system);
void (* attempt_restart) (GsmSystem *system);
void (* suspend) (GsmSystem *system);
void (* hibernate) (GsmSystem *system);
void (* set_session_idle) (GsmSystem *system,
gboolean is_idle);
gboolean (* is_login_session) (GsmSystem *system);
void (* add_inhibitor) (GsmSystem *system,
const gchar *id,
GsmInhibitorFlag flags);
void (* remove_inhibitor) (GsmSystem *system,
const gchar *id);
void (* prepare_shutdown) (GsmSystem *system,
gboolean restart);
void (* complete_shutdown)(GsmSystem *system);
+ gboolean (* is_last_session_for_user) (GsmSystem *system);
};
enum _GsmSystemError {
GSM_SYSTEM_ERROR_RESTARTING = 0,
GSM_SYSTEM_ERROR_STOPPING
};
GType gsm_system_get_type (void);
GQuark gsm_system_error_quark (void);
GsmSystem *gsm_get_system (void);
gboolean gsm_system_can_switch_user (GsmSystem *system);
gboolean gsm_system_can_stop (GsmSystem *system);
gboolean gsm_system_can_restart (GsmSystem *system);
gboolean gsm_system_can_suspend (GsmSystem *system);
gboolean gsm_system_can_hibernate (GsmSystem *system);
void gsm_system_attempt_stop (GsmSystem *system);
void gsm_system_attempt_restart (GsmSystem *system);
void gsm_system_suspend (GsmSystem *system);
void gsm_system_hibernate (GsmSystem *system);
void gsm_system_set_session_idle (GsmSystem *system,
gboolean is_idle);
gboolean gsm_system_is_login_session (GsmSystem *system);
+gboolean gsm_system_is_last_session_for_user (GsmSystem *system);
+
gboolean gsm_system_is_active (GsmSystem *system);
void gsm_system_add_inhibitor (GsmSystem *system,
const gchar *id,
GsmInhibitorFlag flags);
void gsm_system_remove_inhibitor (GsmSystem *system,
const gchar *id);
void gsm_system_prepare_shutdown (GsmSystem *system,
gboolean restart);
void gsm_system_complete_shutdown (GsmSystem *system);
G_END_DECLS
#endif /* __GSM_SYSTEM_H__ */
diff --git a/gnome-session/gsm-systemd.c b/gnome-session/gsm-systemd.c
index ee43bfab..f42767ad 100644
--- a/gnome-session/gsm-systemd.c
+++ b/gnome-session/gsm-systemd.c
@@ -862,78 +862,141 @@ gsm_systemd_prepare_shutdown (GsmSystem *system,
g_variant_get (res, "(h)", &idx);
systemd->priv->delay_inhibit_fd = g_unix_fd_list_get (fd_list, idx, NULL);
g_debug ("GsmSystemd: got delay inhibitor, fd = %d", systemd->priv->delay_inhibit_fd);
g_variant_unref (res);
g_object_unref (fd_list);
systemd->priv->prepare_for_shutdown_expected = TRUE;
g_dbus_proxy_call (systemd->priv->sd_proxy,
restart ? "Reboot" : "PowerOff",
g_variant_new ("(b)", TRUE),
0,
G_MAXINT,
NULL,
reboot_or_poweroff_done,
systemd);
}
static void
gsm_systemd_complete_shutdown (GsmSystem *system)
{
GsmSystemd *systemd = GSM_SYSTEMD (system);
/* remove delay inhibitor, if any */
drop_delay_inhibitor (systemd);
}
+static gboolean
+gsm_systemd_is_last_session_for_user (GsmSystem *system)
+{
+ char **sessions = NULL;
+ char *session = NULL;
+ gboolean is_last_session;
+ int ret, i;
+
+ ret = sd_pid_get_session (getpid (), &session);
+
+ if (ret != 0) {
+ return FALSE;
+ }
+
+ ret = sd_uid_get_sessions (getuid (), FALSE, &sessions);
+
+ if (ret <= 0) {
+ free (session);
+ return FALSE;
+ }
+
+ is_last_session = TRUE;
+ for (i = 0; sessions[i]; i++) {
+ char *state = NULL;
+ char *type = NULL;
+
+ if (g_strcmp0 (sessions[i], session) == 0)
+ continue;
+
+ ret = sd_session_get_state (sessions[i], &state);
+
+ if (ret != 0)
+ continue;
+
+ if (g_strcmp0 (state, "closing") == 0) {
+ free (state);
+ continue;
+ }
+ free (state);
+
+ ret = sd_session_get_type (sessions[i], &type);
+
+ if (ret != 0)
+ continue;
+
+ if (g_strcmp0 (type, "x11") != 0 &&
+ g_strcmp0 (type, "wayland") != 0) {
+ free (type);
+ continue;
+ }
+
+ is_last_session = FALSE;
+ }
+
+ for (i = 0; sessions[i]; i++)
+ free (sessions[i]);
+ free (sessions);
+ free (session);
+
+ return is_last_session;
+}
+
static void
gsm_systemd_system_init (GsmSystemInterface *iface)
{
iface->can_switch_user = gsm_systemd_can_switch_user;
iface->can_stop = gsm_systemd_can_stop;
iface->can_restart = gsm_systemd_can_restart;
iface->can_suspend = gsm_systemd_can_suspend;
iface->can_hibernate = gsm_systemd_can_hibernate;
iface->attempt_stop = gsm_systemd_attempt_stop;
iface->attempt_restart = gsm_systemd_attempt_restart;
iface->suspend = gsm_systemd_suspend;
iface->hibernate = gsm_systemd_hibernate;
iface->set_session_idle = gsm_systemd_set_session_idle;
iface->is_login_session = gsm_systemd_is_login_session;
iface->add_inhibitor = gsm_systemd_add_inhibitor;
iface->remove_inhibitor = gsm_systemd_remove_inhibitor;
iface->prepare_shutdown = gsm_systemd_prepare_shutdown;
iface->complete_shutdown = gsm_systemd_complete_shutdown;
+ iface->is_last_session_for_user = gsm_systemd_is_last_session_for_user;
}
GsmSystemd *
gsm_systemd_new (void)
{
GsmSystemd *manager;
/* logind is not running ? */
if (access("/run/systemd/seats/", F_OK) < 0)
return NULL;
manager = g_object_new (GSM_TYPE_SYSTEMD, NULL);
return manager;
}
static void
sd_proxy_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
GsmSystemd *systemd = user_data;
gboolean is_about_to_shutdown;
g_debug ("GsmSystemd: received logind signal: %s", signal_name);
if (g_strcmp0 (signal_name, "PrepareForShutdown") != 0) {
g_debug ("GsmSystemd: ignoring %s signal", signal_name);
--
2.13.0