gnome-session/0003-manager-kill-off-bus-clients-at-log-out.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

375 lines
13 KiB
Diff

From e7a650b88b92c3381eccef7bf4765fa814389aaa Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 20 Jun 2017 16:28:10 -0400
Subject: [PATCH 3/3] manager: kill off bus clients at log out
https://bugzilla.gnome.org/show_bug.cgi?id=764029
---
gnome-session/gsm-manager.c | 104 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 012f3d3f..3aa6863b 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -12,60 +12,61 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <locale.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include <gio/gio.h>
#include "gsm-manager.h"
#include "org.gnome.SessionManager.h"
+#include "org.freedesktop.DBus.h"
#ifdef HAVE_SYSTEMD
#include <systemd/sd-journal.h>
#endif
#include "gsm-store.h"
#include "gsm-inhibitor.h"
#include "gsm-presence.h"
#include "gsm-shell.h"
#include "gsm-xsmp-server.h"
#include "gsm-xsmp-client.h"
#include "gsm-dbus-client.h"
#include "gsm-autostart-app.h"
#include "gsm-util.h"
#include "gsm-icon-names.h"
#include "gsm-system.h"
#include "gsm-session-save.h"
#include "gsm-shell-extensions.h"
#include "gsm-fail-whale.h"
#define GSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_MANAGER, GsmManagerPrivate))
/* UUIDs for log messages */
#define GSM_MANAGER_STARTUP_SUCCEEDED_MSGID "0ce153587afa4095832d233c17a88001"
#define GSM_MANAGER_UNRECOVERABLE_FAILURE_MSGID "10dd2dc188b54a5e98970f56499d1f73"
#define GSM_MANAGER_DBUS_PATH "/org/gnome/SessionManager"
@@ -129,60 +130,61 @@ struct GsmManagerPrivate
/* Current status */
GsmManagerPhase phase;
guint phase_timeout_id;
GSList *required_apps;
GSList *pending_apps;
GsmManagerLogoutMode logout_mode;
GSList *query_clients;
guint query_timeout_id;
/* This is used for GSM_MANAGER_PHASE_END_SESSION only at the moment,
* since it uses a sublist of all running client that replied in a
* specific way */
GSList *next_query_clients;
/* This is the action that will be done just before we exit */
GsmManagerLogoutType logout_type;
/* List of clients which were disconnected due to disabled condition
* and shouldn't be automatically restarted */
GSList *condition_clients;
GSList *pending_end_session_tasks;
GCancellable *end_session_cancellable;
GSettings *settings;
GSettings *session_settings;
GSettings *screensaver_settings;
GSettings *lockdown_settings;
GsmSystem *system;
GDBusConnection *connection;
+ GsmBus *bus_proxy;
GsmExportedManager *skeleton;
gboolean dbus_disconnected : 1;
GsmShell *shell;
guint shell_end_session_dialog_canceled_id;
guint shell_end_session_dialog_open_failed_id;
guint shell_end_session_dialog_confirmed_logout_id;
guint shell_end_session_dialog_confirmed_shutdown_id;
guint shell_end_session_dialog_confirmed_reboot_id;
};
enum {
PROP_0,
PROP_CLIENT_STORE,
PROP_SESSION_NAME,
PROP_FALLBACK,
PROP_FAILSAFE
};
enum {
PHASE_CHANGED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0 };
static void gsm_manager_class_init (GsmManagerClass *klass);
static void gsm_manager_init (GsmManager *manager);
static gboolean auto_save_is_enabled (GsmManager *manager);
@@ -908,69 +910,157 @@ do_phase_end_session_part_2 (GsmManager *manager)
&data);
g_slist_free (manager->priv->next_query_clients);
manager->priv->next_query_clients = NULL;
} else {
end_phase (manager);
}
}
static gboolean
_client_stop (const char *id,
GsmClient *client,
gpointer user_data)
{
gboolean ret;
GError *error;
error = NULL;
ret = gsm_client_stop (client, &error);
if (! ret) {
g_warning ("Unable to stop client: %s", error->message);
g_error_free (error);
/* FIXME: what should we do if we can't communicate with client? */
} else {
g_debug ("GsmManager: stopped client: %s", gsm_client_peek_id (client));
}
return FALSE;
}
+static GPid *
+get_pids_for_bus_clients (GsmManager *manager,
+ const char * const *bus_clients)
+{
+ GHashTable *process_id_hash;
+ GHashTableIter iter;
+ gpointer key, value;
+ GPid *process_ids;
+ int i, j;
+
+ process_id_hash = g_hash_table_new (NULL, NULL);
+
+ for (i = 0; bus_clients[i] != NULL; i++) {
+ gboolean ret;
+ GError *error;
+ guint pid;
+
+ error = NULL;
+ ret = gsm_bus_call_get_connection_unix_process_id_sync (manager->priv->bus_proxy,
+ bus_clients[i],
+ &pid,
+ NULL,
+ &error);
+
+ if (! ret) {
+ g_debug ("GsmManager: couldn't get process id of client '%s': %s",
+ bus_clients[i], error->message);
+ g_error_free (error);
+ continue;
+ }
+
+ g_hash_table_add (process_id_hash, GUINT_TO_POINTER (pid));
+ }
+
+ j = 0;
+ process_ids = g_new0 (GPid, g_hash_table_size (process_id_hash) + 1);
+ g_hash_table_iter_init (&iter, process_id_hash);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ process_ids[j++] = (GPid) GPOINTER_TO_UINT (key);
+ }
+
+ g_hash_table_unref (process_id_hash);
+
+ return process_ids;
+}
+
+static void
+maybe_kill_bus_clients (GsmManager *manager)
+{
+ GsmSystem *system;
+ gboolean ret;
+ GError *error;
+ GPid *process_ids;
+ char **bus_clients;
+ int i;
+
+ if (manager->priv->dbus_disconnected)
+ return;
+
+ system = gsm_get_system ();
+
+ if (!gsm_system_is_last_session_for_user (system))
+ return;
+
+ error = NULL;
+ ret = gsm_bus_call_list_names_sync (manager->priv->bus_proxy,
+ &bus_clients,
+ NULL,
+ &error);
+
+ if (! ret) {
+ g_warning ("Unable to list bus clients: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ process_ids = get_pids_for_bus_clients (manager, (const char * const *) bus_clients);
+ g_strfreev (bus_clients);
+
+ for (i = 0; process_ids[i] != 0; i++) {
+ kill (process_ids[i], SIGTERM);
+ }
+
+ g_free (process_ids);
+}
+
static void
do_phase_exit (GsmManager *manager)
{
if (gsm_store_size (manager->priv->clients) > 0) {
gsm_store_foreach (manager->priv->clients,
(GsmStoreFunc)_client_stop,
NULL);
}
+ maybe_kill_bus_clients (manager);
+
end_phase (manager);
}
static gboolean
_client_query_end_session (const char *id,
GsmClient *client,
ClientEndSessionData *data)
{
gboolean ret;
GError *error;
error = NULL;
ret = gsm_client_query_end_session (client, data->flags, &error);
if (! ret) {
g_warning ("Unable to query client: %s", error->message);
g_error_free (error);
/* FIXME: what should we do if we can't communicate with client? */
} else {
g_debug ("GsmManager: adding client to query clients: %s", gsm_client_peek_id (client));
data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients,
client);
}
return FALSE;
}
static gboolean
inhibitor_has_flag (gpointer key,
GsmInhibitor *inhibitor,
gpointer data)
@@ -3047,60 +3137,74 @@ static void
on_session_connection_closed (GDBusConnection *connection,
gboolean remote_peer_vanished,
GError *error,
gpointer user_data)
{
GsmManager *manager;
manager = GSM_MANAGER (user_data);
g_debug ("GsmManager: dbus disconnected; disconnecting dbus clients...");
manager->priv->dbus_disconnected = TRUE;
remove_clients_for_connection (manager, NULL);
}
static gboolean
register_manager (GsmManager *manager)
{
GDBusConnection *connection;
GsmExportedManager *skeleton;
GError *error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (error != NULL) {
g_critical ("error getting session bus: %s", error->message);
g_error_free (error);
exit (1);
}
+ manager->priv->bus_proxy = gsm_bus_proxy_new_sync (connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ NULL,
+ &error);
+
+ if (error != NULL) {
+ g_critical ("error getting proxy to bus daemon: %s", error->message);
+ g_error_free (error);
+
+ exit (1);
+ }
+
skeleton = gsm_exported_manager_skeleton_new ();
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
connection,
GSM_MANAGER_DBUS_PATH, &error);
if (error != NULL) {
g_critical ("error exporting manager on session bus: %s", error->message);
g_error_free (error);
exit (1);
}
g_signal_connect (skeleton, "handle-can-shutdown",
G_CALLBACK (gsm_manager_can_shutdown), manager);
g_signal_connect (skeleton, "handle-get-clients",
G_CALLBACK (gsm_manager_get_clients), manager);
g_signal_connect (skeleton, "handle-get-inhibitors",
G_CALLBACK (gsm_manager_get_inhibitors), manager);
g_signal_connect (skeleton, "handle-get-locale",
G_CALLBACK (gsm_manager_get_locale), manager);
g_signal_connect (skeleton, "handle-inhibit",
G_CALLBACK (gsm_manager_inhibit), manager);
g_signal_connect (skeleton, "handle-initialization-error",
G_CALLBACK (gsm_manager_initialization_error), manager);
g_signal_connect (skeleton, "handle-is-autostart-condition-handled",
G_CALLBACK (gsm_manager_is_autostart_condition_handled), manager);
g_signal_connect (skeleton, "handle-is-inhibited",
G_CALLBACK (gsm_manager_is_inhibited), manager);
g_signal_connect (skeleton, "handle-is-session-running",
G_CALLBACK (gsm_manager_is_session_running), manager);
--
2.13.0