Blame SOURCES/0012-daemon-try-harder-to-get-to-a-login-screen-at-logout.patch

c90517
From 3a3b24a4dc6596bb70be86a68f3a228048472c7c Mon Sep 17 00:00:00 2001
c90517
From: Ray Strode <rstrode@redhat.com>
c90517
Date: Mon, 30 Jul 2018 16:21:29 -0400
c90517
Subject: [PATCH 12/48] daemon: try harder to get to a login screen at logout
c90517
c90517
commit 22c332ba and some follow up commits try to ensure the
c90517
user never stays on a blank VT by jumping to a login screen in
c90517
the event they'd end up on one.
c90517
c90517
Unfortunately, that part of the code can't start a login screen
c90517
if there's not one running at all.
c90517
c90517
This commit moves the code to GdmLocalDisplyFactory where the
c90517
login screens are created, so users won't end up on a blank
c90517
VT even if no login screen is yet running.
c90517
---
c90517
 daemon/gdm-local-display-factory.c |  36 +++++++-
c90517
 daemon/gdm-manager.c               | 143 -----------------------------
c90517
 2 files changed, 31 insertions(+), 148 deletions(-)
c90517
c90517
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
c90517
index e52360a56..0e454c880 100644
c90517
--- a/daemon/gdm-local-display-factory.c
c90517
+++ b/daemon/gdm-local-display-factory.c
c90517
@@ -1,60 +1,62 @@
c90517
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
c90517
  *
c90517
  * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
c90517
  *
c90517
  * This program is free software; you can redistribute it and/or modify
c90517
  * it under the terms of the GNU General Public License as published by
c90517
  * the Free Software Foundation; either version 2 of the License, or
c90517
  * (at your option) any later version.
c90517
  *
c90517
  * This program is distributed in the hope that it will be useful,
c90517
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
c90517
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
c90517
  * GNU General Public License for more details.
c90517
  *
c90517
  * You should have received a copy of the GNU General Public License
c90517
  * along with this program; if not, write to the Free Software
c90517
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
c90517
  *
c90517
  */
c90517
 
c90517
 #include "config.h"
c90517
 
c90517
 #include <stdlib.h>
c90517
 #include <stdio.h>
c90517
 
c90517
 #include <glib.h>
c90517
 #include <glib/gi18n.h>
c90517
 #include <glib-object.h>
c90517
 #include <gio/gio.h>
c90517
 
c90517
+#include <systemd/sd-login.h>
c90517
+
c90517
 #include "gdm-common.h"
c90517
 #include "gdm-manager.h"
c90517
 #include "gdm-display-factory.h"
c90517
 #include "gdm-local-display-factory.h"
c90517
 #include "gdm-local-display-factory-glue.h"
c90517
 
c90517
 #include "gdm-settings-keys.h"
c90517
 #include "gdm-settings-direct.h"
c90517
 #include "gdm-display-store.h"
c90517
 #include "gdm-local-display.h"
c90517
 #include "gdm-legacy-display.h"
c90517
 
c90517
 #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate))
c90517
 
c90517
 #define GDM_DBUS_PATH                       "/org/gnome/DisplayManager"
c90517
 #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
c90517
 #define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
c90517
 
c90517
 #define MAX_DISPLAY_FAILURES 5
c90517
 
c90517
 struct GdmLocalDisplayFactoryPrivate
c90517
 {
c90517
         GdmDBusLocalDisplayFactory *skeleton;
c90517
         GDBusConnection *connection;
c90517
         GHashTable      *used_display_numbers;
c90517
 
c90517
         /* FIXME: this needs to be per seat? */
c90517
         guint            num_failures;
c90517
 
c90517
         guint            seat_new_id;
c90517
@@ -240,174 +242,198 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
c90517
 
c90517
         store_display (factory, display);
c90517
 
c90517
         if (! gdm_display_manage (display)) {
c90517
                 display = NULL;
c90517
                 goto out;
c90517
         }
c90517
 
c90517
         if (! gdm_display_get_id (display, id, NULL)) {
c90517
                 display = NULL;
c90517
                 goto out;
c90517
         }
c90517
 
c90517
         ret = TRUE;
c90517
  out:
c90517
         /* ref either held by store or not at all */
c90517
         g_object_unref (display);
c90517
 
c90517
         return ret;
c90517
 }
c90517
 
c90517
 static void
c90517
 on_display_status_changed (GdmDisplay             *display,
c90517
                            GParamSpec             *arg1,
c90517
                            GdmLocalDisplayFactory *factory)
c90517
 {
c90517
         int              status;
c90517
         int              num;
c90517
         char            *seat_id = NULL;
c90517
         char            *session_type = NULL;
c90517
+        char            *session_class = NULL;
c90517
         gboolean         is_initial = TRUE;
c90517
         gboolean         is_local = TRUE;
c90517
 
c90517
         num = -1;
c90517
         gdm_display_get_x11_display_number (display, &num, NULL);
c90517
 
c90517
         g_object_get (display,
c90517
                       "seat-id", &seat_id,
c90517
                       "is-initial", &is_initial,
c90517
                       "is-local", &is_local,
c90517
                       "session-type", &session_type,
c90517
+                      "session-class", &session_class,
c90517
                       NULL);
c90517
 
c90517
         status = gdm_display_get_status (display);
c90517
 
c90517
         g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
c90517
         switch (status) {
c90517
         case GDM_DISPLAY_FINISHED:
c90517
                 /* remove the display number from factory->priv->used_display_numbers
c90517
                    so that it may be reused */
c90517
                 if (num != -1) {
c90517
                         g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num));
c90517
                 }
c90517
                 gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c90517
 
c90517
                 /* if this is a local display, do a full resync.  Only
c90517
                  * seats without displays will get created anyway.  This
c90517
                  * ensures we get a new login screen when the user logs out,
c90517
                  * if there isn't one.
c90517
                  */
c90517
-                if (is_local) {
c90517
+                if (is_local && g_strcmp0 (session_class, "greeter") != 0) {
c90517
                         /* reset num failures */
c90517
                         factory->priv->num_failures = 0;
c90517
 
c90517
                         gdm_local_display_factory_sync_seats (factory);
c90517
                 }
c90517
                 break;
c90517
         case GDM_DISPLAY_FAILED:
c90517
                 /* leave the display number in factory->priv->used_display_numbers
c90517
                    so that it doesn't get reused */
c90517
                 gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
c90517
 
c90517
                 /* Create a new equivalent display if it was static */
c90517
                 if (is_local) {
c90517
 
c90517
                         factory->priv->num_failures++;
c90517
 
c90517
                         if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
c90517
                                 /* oh shit */
c90517
                                 g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
c90517
                         } else {
c90517
 #ifdef ENABLE_WAYLAND_SUPPORT
c90517
                                 if (g_strcmp0 (session_type, "wayland") == 0) {
c90517
                                         g_free (session_type);
c90517
                                         session_type = NULL;
c90517
 
c90517
                                         /* workaround logind race for now
c90517
                                          * bug 1643874
c90517
                                          */
c90517
                                         sleep (2);
c90517
                                 }
c90517
 
c90517
 #endif
c90517
                                 create_display (factory, seat_id, session_type, is_initial);
c90517
                         }
c90517
                 }
c90517
                 break;
c90517
         case GDM_DISPLAY_UNMANAGED:
c90517
                 break;
c90517
         case GDM_DISPLAY_PREPARED:
c90517
                 break;
c90517
         case GDM_DISPLAY_MANAGED:
c90517
                 break;
c90517
         default:
c90517
                 g_assert_not_reached ();
c90517
                 break;
c90517
         }
c90517
 
c90517
         g_free (seat_id);
c90517
         g_free (session_type);
c90517
+        g_free (session_class);
c90517
 }
c90517
 
c90517
 static gboolean
c90517
 lookup_by_seat_id (const char *id,
c90517
                    GdmDisplay *display,
c90517
                    gpointer    user_data)
c90517
 {
c90517
         const char *looking_for = user_data;
c90517
         char *current;
c90517
         gboolean res;
c90517
 
c90517
         g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
c90517
 
c90517
         res = g_strcmp0 (current, looking_for) == 0;
c90517
 
c90517
         g_free(current);
c90517
 
c90517
         return res;
c90517
 }
c90517
 
c90517
 static GdmDisplay *
c90517
 create_display (GdmLocalDisplayFactory *factory,
c90517
                 const char             *seat_id,
c90517
                 const char             *session_type,
c90517
                 gboolean                initial)
c90517
 {
c90517
         GdmDisplayStore *store;
c90517
         GdmDisplay      *display = NULL;
c90517
+        char            *active_session_id = NULL;
c90517
+        int              ret;
c90517
 
c90517
-        /* Ensure we don't create the same display more than once */
c90517
         store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
c90517
-        display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
c90517
-        if (display != NULL) {
c90517
-                return NULL;
c90517
+
c90517
+        ret = sd_seat_get_active (seat_id, &active_session_id, NULL);
c90517
+
c90517
+        if (ret == 0) {
c90517
+                char *login_session_id = NULL;
c90517
+
c90517
+                /* If we already have a login window, switch to it */
c90517
+                if (gdm_get_login_window_session_id (seat_id, &login_session_id)) {
c90517
+                        if (g_strcmp0 (active_session_id, login_session_id) != 0) {
c90517
+                                gdm_activate_session_by_id (factory->priv->connection, seat_id, login_session_id);
c90517
+                        }
c90517
+                        g_clear_pointer (&login_session_id, g_free);
c90517
+                        g_clear_pointer (&active_session_id, g_free);
c90517
+                        return NULL;
c90517
+                }
c90517
+                g_clear_pointer (&active_session_id, g_free);
c90517
+        } else {
c90517
+                /* Ensure we don't create the same display more than once */
c90517
+                display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id);
c90517
+
c90517
+                if (display != NULL) {
c90517
+                        return NULL;
c90517
+                }
c90517
         }
c90517
 
c90517
         g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
c90517
 
c90517
 #ifdef ENABLE_USER_DISPLAY_SERVER
c90517
         if (g_strcmp0 (seat_id, "seat0") == 0) {
c90517
                 display = gdm_local_display_new ();
c90517
                 if (session_type != NULL) {
c90517
                         g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
c90517
                 }
c90517
         }
c90517
 #endif
c90517
 
c90517
         if (display == NULL) {
c90517
                 guint32 num;
c90517
 
c90517
                 num = take_next_display_number (factory);
c90517
 
c90517
                 display = gdm_legacy_display_new (num);
c90517
         }
c90517
 
c90517
         g_object_set (display, "seat-id", seat_id, NULL);
c90517
         g_object_set (display, "is-initial", initial, NULL);
c90517
 
c90517
         store_display (factory, display);
c90517
 
c90517
         /* let store own the ref */
c90517
         g_object_unref (display);
c90517
 
c90517
         if (! gdm_display_manage (display)) {
c90517
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
c90517
index ede22e771..80f60d24c 100644
c90517
--- a/daemon/gdm-manager.c
c90517
+++ b/daemon/gdm-manager.c
c90517
@@ -1322,202 +1322,60 @@ maybe_start_pending_initial_login (GdmManager *manager,
c90517
         char *user_session_seat_id = NULL;
c90517
 
c90517
         /* There may be a user session waiting to be started.
c90517
          * This would happen if we couldn't start it earlier because
c90517
          * the login screen X server was coming up and two X servers
c90517
          * can't be started on the same seat at the same time.
c90517
          */
c90517
 
c90517
         if (manager->priv->initial_login_operation == NULL) {
c90517
                 return;
c90517
         }
c90517
 
c90517
         operation = manager->priv->initial_login_operation;
c90517
 
c90517
         g_object_get (G_OBJECT (greeter_display),
c90517
                       "seat-id", &greeter_seat_id,
c90517
                       NULL);
c90517
         g_object_get (G_OBJECT (operation->session),
c90517
                       "display-seat-id", &user_session_seat_id,
c90517
                       NULL);
c90517
 
c90517
         if (g_strcmp0 (greeter_seat_id, user_session_seat_id) == 0) {
c90517
                 start_user_session (manager, operation);
c90517
                 manager->priv->initial_login_operation = NULL;
c90517
         }
c90517
 
c90517
         g_free (greeter_seat_id);
c90517
         g_free (user_session_seat_id);
c90517
 }
c90517
 
c90517
-static gboolean
c90517
-get_login_window_session_id (const char  *seat_id,
c90517
-                             char       **session_id)
c90517
-{
c90517
-        gboolean   ret;
c90517
-        int        res, i;
c90517
-        char     **sessions;
c90517
-        char      *service_id;
c90517
-        char      *service_class;
c90517
-        char      *state;
c90517
-
c90517
-        res = sd_seat_get_sessions (seat_id, &sessions, NULL, NULL);
c90517
-        if (res < 0) {
c90517
-                g_debug ("Failed to determine sessions: %s", strerror (-res));
c90517
-                return FALSE;
c90517
-        }
c90517
-
c90517
-        if (sessions == NULL || sessions[0] == NULL) {
c90517
-                *session_id = NULL;
c90517
-                ret = FALSE;
c90517
-                goto out;
c90517
-        }
c90517
-
c90517
-        for (i = 0; sessions[i]; i ++) {
c90517
-
c90517
-                res = sd_session_get_class (sessions[i], &service_class);
c90517
-                if (res < 0) {
c90517
-                        if (res == -ENOENT) {
c90517
-                                free (service_class);
c90517
-                                continue;
c90517
-                        }
c90517
-
c90517
-                        g_debug ("failed to determine class of session %s: %s", sessions[i], strerror (-res));
c90517
-                        ret = FALSE;
c90517
-                        goto out;
c90517
-                }
c90517
-
c90517
-                if (strcmp (service_class, "greeter") != 0) {
c90517
-                        free (service_class);
c90517
-                        continue;
c90517
-                }
c90517
-
c90517
-                free (service_class);
c90517
-
c90517
-                ret = sd_session_get_state (sessions[i], &state);
c90517
-                if (ret < 0) {
c90517
-                        if (res == -ENOENT)
c90517
-                                continue;
c90517
-
c90517
-                        g_debug ("failed to determine state of session %s: %s", sessions[i], strerror (-res));
c90517
-                        ret = FALSE;
c90517
-                        goto out;
c90517
-                }
c90517
-
c90517
-                if (g_strcmp0 (state, "closing") == 0) {
c90517
-                        free (state);
c90517
-                        continue;
c90517
-                }
c90517
-                free (state);
c90517
-
c90517
-                res = sd_session_get_service (sessions[i], &service_id);
c90517
-                if (res < 0) {
c90517
-                        if (res == -ENOENT)
c90517
-                                continue;
c90517
-                        g_debug ("failed to determine service of session %s: %s", sessions[i], strerror (-res));
c90517
-                        ret = FALSE;
c90517
-                        goto out;
c90517
-                }
c90517
-
c90517
-                if (strcmp (service_id, "gdm-launch-environment") == 0) {
c90517
-                        *session_id = g_strdup (sessions[i]);
c90517
-                        ret = TRUE;
c90517
-
c90517
-                        free (service_id);
c90517
-                        goto out;
c90517
-                }
c90517
-
c90517
-                free (service_id);
c90517
-        }
c90517
-
c90517
-        *session_id = NULL;
c90517
-        ret = FALSE;
c90517
-
c90517
-out:
c90517
-        if (sessions) {
c90517
-                for (i = 0; sessions[i]; i ++) {
c90517
-                        free (sessions[i]);
c90517
-                }
c90517
-
c90517
-                free (sessions);
c90517
-        }
c90517
-
c90517
-        return ret;
c90517
-}
c90517
-
c90517
-static void
c90517
-activate_login_window_session_on_seat (GdmManager *self,
c90517
-                                       const char *seat_id)
c90517
-{
c90517
-        char *session_id;
c90517
-
c90517
-        if (!gdm_get_login_window_session_id (seat_id, &session_id)) {
c90517
-                return;
c90517
-        }
c90517
-
c90517
-        if (session_id) {
c90517
-                activate_session_id (self, seat_id, session_id);
c90517
-                g_free (session_id);
c90517
-        }
c90517
-}
c90517
-
c90517
-static void
c90517
-maybe_activate_other_session (GdmManager *self,
c90517
-                              GdmDisplay *old_display)
c90517
-{
c90517
-        char *seat_id = NULL;
c90517
-        char *session_id = NULL;
c90517
-        int ret;
c90517
-
c90517
-        g_object_get (G_OBJECT (old_display),
c90517
-                      "seat-id", &seat_id,
c90517
-                      NULL);
c90517
-
c90517
-        ret = sd_seat_get_active (seat_id, &session_id, NULL);
c90517
-
c90517
-        if (ret == 0) {
c90517
-                GdmDisplay *display;
c90517
-
c90517
-                display = gdm_display_store_find (self->priv->display_store,
c90517
-                                                  lookup_by_session_id,
c90517
-                                                  (gpointer) session_id);
c90517
-
c90517
-                if (display == NULL || gdm_display_get_status (display) == GDM_DISPLAY_FINISHED) {
c90517
-                        activate_login_window_session_on_seat (self, seat_id);
c90517
-                }
c90517
-
c90517
-                g_free (session_id);
c90517
-        }
c90517
-
c90517
-        g_free (seat_id);
c90517
-}
c90517
-
c90517
 static const char *
c90517
 get_username_for_greeter_display (GdmManager *manager,
c90517
                                   GdmDisplay *display)
c90517
 {
c90517
         gboolean doing_initial_setup = FALSE;
c90517
 
c90517
         g_object_get (G_OBJECT (display),
c90517
                       "doing-initial-setup", &doing_initial_setup,
c90517
                       NULL);
c90517
 
c90517
         if (doing_initial_setup) {
c90517
                 return INITIAL_SETUP_USERNAME;
c90517
         } else {
c90517
                 return GDM_USERNAME;
c90517
         }
c90517
 }
c90517
 
c90517
 static void
c90517
 set_up_automatic_login_session (GdmManager *manager,
c90517
                                 GdmDisplay *display)
c90517
 {
c90517
         GdmSession *session;
c90517
         char       *display_session_type = NULL;
c90517
         gboolean is_initial;
c90517
 
c90517
         /* 0 is root user; since the daemon talks to the session object
c90517
          * directly, itself, for automatic login
c90517
          */
c90517
         session = create_user_session_for_display (manager, display, 0);
c90517
 
c90517
@@ -1709,61 +1567,60 @@ on_display_status_changed (GdmDisplay *display,
c90517
                         if ((display_number == -1 && status == GDM_DISPLAY_PREPARED) ||
c90517
                             (display_number != -1 && status == GDM_DISPLAY_MANAGED)) {
c90517
                                 char *session_class;
c90517
 
c90517
                                 g_object_get (display,
c90517
                                               "session-class", &session_class,
c90517
                                               NULL);
c90517
                                 if (g_strcmp0 (session_class, "greeter") == 0)
c90517
                                         set_up_session (manager, display);
c90517
                                 g_free (session_class);
c90517
                         }
c90517
 
c90517
                         if (status == GDM_DISPLAY_MANAGED) {
c90517
                                 greeter_display_started (manager, display);
c90517
                         }
c90517
                         break;
c90517
                 case GDM_DISPLAY_FAILED:
c90517
                 case GDM_DISPLAY_UNMANAGED:
c90517
                 case GDM_DISPLAY_FINISHED:
c90517
 #ifdef WITH_PLYMOUTH
c90517
                         if (quit_plymouth) {
c90517
                                 plymouth_quit_without_transition ();
c90517
                                 manager->priv->plymouth_is_running = FALSE;
c90517
                         }
c90517
 #endif
c90517
 
c90517
                         if (status == GDM_DISPLAY_FINISHED || g_strcmp0 (session_type, "x11") == 0) {
c90517
                                 manager->priv->ran_once = TRUE;
c90517
                         }
c90517
                         maybe_start_pending_initial_login (manager, display);
c90517
-                        maybe_activate_other_session (manager, display);
c90517
                         break;
c90517
                 default:
c90517
                         break;
c90517
         }
c90517
 
c90517
 }
c90517
 
c90517
 static void
c90517
 on_display_removed (GdmDisplayStore *display_store,
c90517
                     GdmDisplay      *display,
c90517
                     GdmManager      *manager)
c90517
 {
c90517
         char    *id;
c90517
 
c90517
         gdm_display_get_id (display, &id, NULL);
c90517
         g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
c90517
         g_free (id);
c90517
 
c90517
         g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), manager);
c90517
 
c90517
         g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, display);
c90517
 }
c90517
 
c90517
 static void
c90517
 destroy_start_user_session_operation (StartUserSessionOperation *operation)
c90517
 {
c90517
         g_object_set_data (G_OBJECT (operation->session),
c90517
                            "start-user-session-operation",
c90517
                            NULL);
c90517
         g_object_unref (operation->session);
c90517
-- 
c90517
2.26.0
c90517