From e7a650b88b92c3381eccef7bf4765fa814389aaa Mon Sep 17 00:00:00 2001 From: Ray Strode 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 . * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gsm-manager.h" #include "org.gnome.SessionManager.h" +#include "org.freedesktop.DBus.h" #ifdef HAVE_SYSTEMD #include #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