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