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

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