Blob Blame History Raw
From d8fd8d4d6ff6a119f6bd27eb07316384c4776d12 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 15 Sep 2021 11:23:17 -0400
Subject: [PATCH] local-display-factory: Don't try to respawn displays on
 shutdown

At the moment in the shutdown path we may try to respawn displays
that just got killed.

The respawning happens when things are half torn down leading to
crashes.

This commit makes sure we turn off the respawn logic in the shutdown
path.
---
 daemon/gdm-local-display-factory.c | 11 ++++++++++-
 daemon/gdm-manager.c               |  2 ++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 11dcda2c..a0884893 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -46,60 +46,62 @@
 #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
 #define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
 
 #define MAX_DISPLAY_FAILURES 5
 #define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
 #define SEAT0_GRAPHICS_CHECK_TIMEOUT 10 /* seconds */
 
 struct _GdmLocalDisplayFactory
 {
         GdmDisplayFactory              parent;
 
         GdmDBusLocalDisplayFactory *skeleton;
         GDBusConnection *connection;
         GHashTable      *used_display_numbers;
 
         /* FIXME: this needs to be per seat? */
         guint            num_failures;
 
         guint            seat_new_id;
         guint            seat_removed_id;
         guint            seat_properties_changed_id;
 
         gboolean         seat0_graphics_check_timed_out;
         guint            seat0_graphics_check_timeout_id;
 
 #if defined(ENABLE_USER_DISPLAY_SERVER)
         unsigned int     active_vt;
         guint            active_vt_watch_id;
         guint            wait_to_finish_timeout_id;
 #endif
+
+        gboolean         is_started;
 };
 
 enum {
         PROP_0,
 };
 
 static void     gdm_local_display_factory_class_init    (GdmLocalDisplayFactoryClass *klass);
 static void     gdm_local_display_factory_init          (GdmLocalDisplayFactory      *factory);
 static void     gdm_local_display_factory_finalize      (GObject                     *object);
 
 static void     ensure_display_for_seat                 (GdmLocalDisplayFactory      *factory,
                                                          const char                  *seat_id);
 
 static void     on_display_status_changed               (GdmDisplay                  *display,
                                                          GParamSpec                  *arg1,
                                                          GdmLocalDisplayFactory      *factory);
 
 static gboolean gdm_local_display_factory_sync_seats    (GdmLocalDisplayFactory *factory);
 static gpointer local_display_factory_object = NULL;
 static gboolean lookup_by_session_id (const char *id,
                                       GdmDisplay *display,
                                       gpointer    user_data);
 
 G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
 
 GQuark
 gdm_local_display_factory_error_quark (void)
 {
         static GQuark ret = 0;
         if (ret == 0) {
@@ -478,60 +480,64 @@ on_session_registered_cb (GObject *gobject,
                           GParamSpec *pspec,
                           gpointer user_data)
 {
         GdmDisplay *display = GDM_DISPLAY (gobject);
         GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data);
         gboolean registered;
 
         g_object_get (display, "session-registered", &registered, NULL);
 
         if (!registered)
                 return;
 
         g_debug ("GdmLocalDisplayFactory: session registered on display, looking for any background displays to kill");
 
         finish_waiting_displays_on_seat (factory, "seat0");
 }
 
 static void
 on_display_status_changed (GdmDisplay             *display,
                            GParamSpec             *arg1,
                            GdmLocalDisplayFactory *factory)
 {
         int              status;
         int              num;
         char            *seat_id = NULL;
         char            *session_type = NULL;
         char            *session_class = NULL;
         gboolean         is_initial = TRUE;
         gboolean         is_local = TRUE;
 
+
+        if (!factory->is_started)
+                return;
+
         num = -1;
         gdm_display_get_x11_display_number (display, &num, NULL);
 
         g_object_get (display,
                       "seat-id", &seat_id,
                       "is-initial", &is_initial,
                       "is-local", &is_local,
                       "session-type", &session_type,
                       "session-class", &session_class,
                       NULL);
 
         status = gdm_display_get_status (display);
 
         g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
         switch (status) {
         case GDM_DISPLAY_FINISHED:
                 /* remove the display number from factory->used_display_numbers
                    so that it may be reused */
                 if (num != -1) {
                         g_hash_table_remove (factory->used_display_numbers, GUINT_TO_POINTER (num));
                 }
                 gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
 
                 /* if this is a local display, do a full resync.  Only
                  * seats without displays will get created anyway.  This
                  * ensures we get a new login screen when the user logs out,
                  * if there isn't one.
                  */
                 if (is_local && g_strcmp0 (session_class, "greeter") != 0) {
                         /* reset num failures */
@@ -1250,99 +1256,102 @@ on_display_added (GdmDisplayStore        *display_store,
 
         display = gdm_display_store_lookup (display_store, id);
 
         if (display != NULL) {
                 g_signal_connect_object (display, "notify::status",
                                          G_CALLBACK (on_display_status_changed),
                                          factory,
                                          0);
 
                 g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
         }
 }
 
 static void
 on_display_removed (GdmDisplayStore        *display_store,
                     GdmDisplay             *display,
                     GdmLocalDisplayFactory *factory)
 {
         g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), factory);
         g_object_weak_unref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
 }
 
 static gboolean
 gdm_local_display_factory_start (GdmDisplayFactory *base_factory)
 {
         GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory);
         GdmDisplayStore *store;
 
         g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
 
+        factory->is_started = TRUE;
+
         store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
 
         g_signal_connect_object (G_OBJECT (store),
                                  "display-added",
                                  G_CALLBACK (on_display_added),
                                  factory,
                                  0);
 
         g_signal_connect_object (G_OBJECT (store),
                                  "display-removed",
                                  G_CALLBACK (on_display_removed),
                                  factory,
                                  0);
 
         gdm_local_display_factory_start_monitor (factory);
         return gdm_local_display_factory_sync_seats (factory);
 }
 
 static gboolean
 gdm_local_display_factory_stop (GdmDisplayFactory *base_factory)
 {
         GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory);
         GdmDisplayStore *store;
 
         g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
 
         gdm_local_display_factory_stop_monitor (factory);
 
         store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
 
         g_signal_handlers_disconnect_by_func (G_OBJECT (store),
                                               G_CALLBACK (on_display_added),
                                               factory);
         g_signal_handlers_disconnect_by_func (G_OBJECT (store),
                                               G_CALLBACK (on_display_removed),
                                               factory);
-
         g_clear_handle_id (&factory->seat0_graphics_check_timeout_id, g_source_remove);
 
+        factory->is_started = FALSE;
+
         return TRUE;
 }
 
 static void
 gdm_local_display_factory_set_property (GObject       *object,
                                         guint          prop_id,
                                         const GValue  *value,
                                         GParamSpec    *pspec)
 {
         switch (prop_id) {
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
         }
 }
 
 static void
 gdm_local_display_factory_get_property (GObject    *object,
                                         guint       prop_id,
                                         GValue     *value,
                                         GParamSpec *pspec)
 {
         switch (prop_id) {
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
         }
 }
 
 static gboolean
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index b3d0a2b5..4b62b8b1 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -2774,60 +2774,62 @@ unexport_display (const char *id,
                   GdmDisplay *display,
                   GdmManager *manager)
 {
         if (!g_dbus_connection_is_closed (manager->priv->connection))
                 g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
 }
 
 static void
 finish_display (const char *id,
                 GdmDisplay *display,
                 GdmManager *manager)
 {
         gdm_display_stop_greeter_session (display);
         if (gdm_display_get_status (display) == GDM_DISPLAY_MANAGED)
                 gdm_display_unmanage (display);
         gdm_display_finish (display);
 }
 
 static void
 gdm_manager_dispose (GObject *object)
 {
         GdmManager *manager;
 
         g_return_if_fail (object != NULL);
         g_return_if_fail (GDM_IS_MANAGER (object));
 
         manager = GDM_MANAGER (object);
 
         g_return_if_fail (manager->priv != NULL);
 
+        gdm_manager_stop (manager);
+
         g_clear_weak_pointer (&manager->priv->automatic_login_display);
 
 #ifdef HAVE_LIBXDMCP
         g_clear_object (&manager->priv->xdmcp_factory);
 #endif
         g_clear_object (&manager->priv->local_factory);
         g_clear_pointer (&manager->priv->open_reauthentication_requests,
                          g_hash_table_unref);
         g_clear_pointer (&manager->priv->transient_sessions,
                          g_hash_table_unref);
 
         g_list_foreach (manager->priv->user_sessions,
                         (GFunc) gdm_session_close,
                         NULL);
         g_list_free_full (manager->priv->user_sessions, (GDestroyNotify) g_object_unref);
         manager->priv->user_sessions = NULL;
 
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_added),
                                               manager);
         g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                               G_CALLBACK (on_display_removed),
                                               manager);
 
         if (!g_dbus_connection_is_closed (manager->priv->connection)) {
                 gdm_display_store_foreach (manager->priv->display_store,
                                            (GdmDisplayStoreFunc)unexport_display,
                                            manager);
                 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
         }
-- 
2.31.1