c15b918a94
Resolves: #1340203 - Address crash in fail whale Related: #1384508
459 lines
15 KiB
Diff
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
|
|
|