From 02429cabcddd3a12e0cddd975820b37e8440f1c7 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 22 May 2019 10:53:12 -0400 Subject: [PATCH] local-display-factory: don't spawn login screen if background session dies At the moment gdm conjures up a login screen any time a user session exits. This is the right behavior if the user explicitly logs out, but if an admin is killing a session on a background VT, then going to the login screen is wrong. This commit changes the code to detect when the killed session is in the foreground, and only then bring up a login screen. --- daemon/gdm-local-display-factory.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index cf4f5095c..6856d30d0 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -227,137 +227,159 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact store_display (factory, display); if (! gdm_display_manage (display)) { display = NULL; goto out; } 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; GdmDisplayStore *store; 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; num = -1; gdm_display_get_x11_display_number (display, &num, NULL); store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); 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_store_remove (store, display); /* 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; + /* reset num failures */ factory->priv->num_failures = 0; - create_display (factory, seat_id, session_type, is_initial); + ret = sd_seat_get_active (seat_id, &active_session, NULL); + + if (ret == 0) { + g_autofree char *state = NULL; + ret = sd_session_get_state (active_session, &state); + if (ret != 0 || + g_strcmp0 (state, "closing") == 0 || + g_strcmp0 (active_session, session_id) == 0) { + g_clear_pointer (&active_session, free); + } + } + + /* If this died in the foreground leaving us on a blank vt, + start a new login screen */ + if (!sd_seat_can_multi_session (seat_id) || active_session == NULL) { + create_display (factory, seat_id, session_type, is_initial); + } } break; case GDM_DISPLAY_FAILED: /* leave the display number in factory->priv->used_display_numbers so that it doesn't get reused */ gdm_display_store_remove (store, display); /* Create a new equivalent display if it was static */ if (is_local) { factory->priv->num_failures++; if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) { /* oh shit */ g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors"); } else { #ifdef ENABLE_WAYLAND_SUPPORT if (g_strcmp0 (session_type, "wayland") == 0) { g_free (session_type); session_type = NULL; } #endif create_display (factory, seat_id, session_type, is_initial); } } break; case GDM_DISPLAY_UNMANAGED: break; case GDM_DISPLAY_PREPARED: break; case GDM_DISPLAY_MANAGED: break; default: g_assert_not_reached (); break; } g_free (seat_id); + g_free (session_id); g_free (session_type); g_free (session_class); } static gboolean lookup_by_seat_id (const char *id, GdmDisplay *display, gpointer user_data) { const char *looking_for = user_data; char *current; gboolean res; g_object_get (G_OBJECT (display), "seat-id", ¤t, NULL); res = g_strcmp0 (current, looking_for) == 0; g_free(current); return res; } static gboolean activate_session_id (GdmLocalDisplayFactory *self, const char *seat_id, const char *session_id) { GError *error = NULL; GVariant *reply; -- 2.21.0