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

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