From 86cff2e65b3d1f1186b378d7b5818531ff6b1d94 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 25 Oct 2019 09:27:15 -0400 Subject: [PATCH 6/7] manager: ensure factories are stopped at shutdown GDM doesn't currently stop it's display handling logic when it's asked to shutdown. That can lead to X servers attempting to start themsevles as GDM is tearing itself down. This commit addresses the problem adding some stop calls to the code. --- daemon/gdm-local-display-factory.c | 15 +++++++++++++-- daemon/gdm-manager.c | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 1c7daeb14..ad128d2c8 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -34,60 +34,62 @@ #include "gdm-manager.h" #include "gdm-display-factory.h" #include "gdm-local-display-factory.h" #include "gdm-local-display-factory-glue.h" #include "gdm-settings-keys.h" #include "gdm-settings-direct.h" #include "gdm-display-store.h" #include "gdm-local-display.h" #include "gdm-legacy-display.h" #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate)) #define GDM_DBUS_PATH "/org/gnome/DisplayManager" #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 struct GdmLocalDisplayFactoryPrivate { 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; + + gboolean 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 GdmDisplay *create_display (GdmLocalDisplayFactory *factory, const char *seat_id, const char *session_type, gboolean initial_display); 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; 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) { ret = g_quark_from_static_string ("gdm_local_display_factory_error"); @@ -233,60 +235,63 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact } if (! gdm_display_get_id (display, id, NULL)) { display = NULL; goto out; } ret = TRUE; out: /* ref either held by store or not at all */ g_object_unref (display); return ret; } static void on_display_status_changed (GdmDisplay *display, GParamSpec *arg1, GdmLocalDisplayFactory *factory) { int status; int num; char *seat_id = NULL; char *session_id = NULL; char *session_type = NULL; char *session_class = NULL; gboolean is_initial = TRUE; gboolean is_local = TRUE; int ret; + if (!factory->priv->started) + return; + num = -1; gdm_display_get_x11_display_number (display, &num, NULL); g_object_get (display, "seat-id", &seat_id, "session-id", &session_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->priv->used_display_numbers so that it may be reused */ if (num != -1) { g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num)); } gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); /* if this is a local display, recreate the display so * a new login screen comes up if one is missing. */ if (is_local && g_strcmp0 (session_class, "greeter") != 0) { g_autofree char *active_session = NULL; @@ -739,82 +744,88 @@ on_display_removed (GdmDisplayStore *display_store, if (display != NULL) { 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); 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); + + gdm_local_display_factory_sync_seats (factory); + + factory->priv->started = TRUE; + return TRUE; } 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); + factory->priv->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 @@ -906,50 +917,50 @@ gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass) factory_class->stop = gdm_local_display_factory_stop; g_type_class_add_private (klass, sizeof (GdmLocalDisplayFactoryPrivate)); } static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory) { factory->priv = GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE (factory); factory->priv->used_display_numbers = g_hash_table_new (NULL, NULL); } static void gdm_local_display_factory_finalize (GObject *object) { GdmLocalDisplayFactory *factory; g_return_if_fail (object != NULL); g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (object)); factory = GDM_LOCAL_DISPLAY_FACTORY (object); g_return_if_fail (factory->priv != NULL); g_clear_object (&factory->priv->connection); g_clear_object (&factory->priv->skeleton); g_hash_table_destroy (factory->priv->used_display_numbers); - gdm_local_display_factory_stop_monitor (factory); + gdm_local_display_factory_stop (GDM_DISPLAY_FACTORY (factory)); G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->finalize (object); } GdmLocalDisplayFactory * gdm_local_display_factory_new (GdmDisplayStore *store) { if (local_display_factory_object != NULL) { g_object_ref (local_display_factory_object); } else { local_display_factory_object = g_object_new (GDM_TYPE_LOCAL_DISPLAY_FACTORY, "display-store", store, NULL); g_object_add_weak_pointer (local_display_factory_object, (gpointer *) &local_display_factory_object); } return GDM_LOCAL_DISPLAY_FACTORY (local_display_factory_object); } diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index 1db291587..779b716be 100644 --- a/daemon/gdm-manager.c +++ b/daemon/gdm-manager.c @@ -1621,60 +1621,63 @@ greeter_display_started (GdmManager *manager, if (manager->priv->ran_once) { return; } maybe_start_pending_initial_login (manager, display); } static void on_display_status_changed (GdmDisplay *display, GParamSpec *arg1, GdmManager *manager) { int status; int display_number = -1; char *session_type = NULL; #ifdef WITH_PLYMOUTH gboolean display_is_local = FALSE; gboolean quit_plymouth = FALSE; g_object_get (display, "is-local", &display_is_local, NULL); quit_plymouth = display_is_local && manager->priv->plymouth_is_running; #endif g_object_get (display, "x11-display-number", &display_number, "session-type", &session_type, NULL); + if (!manager->priv->started) + return; + status = gdm_display_get_status (display); switch (status) { case GDM_DISPLAY_PREPARED: case GDM_DISPLAY_MANAGED: if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) || (display_number != -1 && status == GDM_DISPLAY_MANAGED)) { char *session_class; g_object_get (display, "session-class", &session_class, NULL); if (g_strcmp0 (session_class, "greeter") == 0) set_up_session (manager, display); g_free (session_class); } if (status == GDM_DISPLAY_MANAGED) { greeter_display_started (manager, display); } break; case GDM_DISPLAY_FAILED: case GDM_DISPLAY_UNMANAGED: case GDM_DISPLAY_FINISHED: #ifdef WITH_PLYMOUTH if (quit_plymouth) { plymouth_quit_without_transition (); manager->priv->plymouth_is_running = FALSE; } #endif @@ -2737,60 +2740,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); + #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, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&manager->priv->transient_sessions, (GDestroyNotify) 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.21.0