Blob Blame History Raw
From 3cf5b4b12d3d39fa858ff593adeecfe711cdddaf Mon Sep 17 00:00:00 2001
From: Iain Lane <iainl@gnome.org>
Date: Tue, 7 May 2019 15:35:23 +0100
Subject: [PATCH 42/51] GdmLocalDisplayFactory: Store VT number, not tty
 identifier

This makes the code a fair bit simpler.
---
 configure.ac                       |  6 ++--
 daemon/gdm-local-display-factory.c | 50 ++++++++++++++++--------------
 daemon/gdm-server.c                |  2 +-
 daemon/gdm-session-worker.c        |  2 +-
 4 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/configure.ac b/configure.ac
index c549146ce..0c138ab38 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1477,66 +1477,66 @@ fi
 AC_SUBST(DEBUG_CFLAGS)
 
 #
 # Enable Profiling
 #
 AC_ARG_ENABLE(profiling,
               AS_HELP_STRING([--enable-profiling],
                              [turn on profiling]),,
               enable_profiling=yes)
 
 if test "$enable_profiling" = "yes"; then
     AC_DEFINE(ENABLE_PROFILING,1,[enable profiling])
 fi
 
 #
 # Set SHELL to use in scripts.
 #
 if test x$os_solaris = xyes ; then
    XSESSION_SHELL=/bin/ksh
 else
    XSESSION_SHELL=/bin/sh
 fi
 
 #
 # Set VT to use for initial server
 #
 AC_ARG_WITH(initial-vt,
         AS_HELP_STRING([--with-initial-vt=<nr>],
                 [Initial virtual terminal to use]))
 if ! test -z "$with_initial_vt"; then
-        GDM_INITIAL_VT="$with_initial_vt"
+        GDM_INITIAL_VT=$with_initial_vt
 else
-        GDM_INITIAL_VT="1"
+        GDM_INITIAL_VT=1
 fi
 AC_SUBST(GDM_INITIAL_VT)
-AC_DEFINE_UNQUOTED(GDM_INITIAL_VT, "$GDM_INITIAL_VT", [Initial Virtual Terminal])
+AC_DEFINE_UNQUOTED(GDM_INITIAL_VT, $GDM_INITIAL_VT, [Initial Virtual Terminal])
 
 # Set configuration choices.
 #
 AC_SUBST(XSESSION_SHELL)
 AC_DEFINE_UNQUOTED(XSESSION_SHELL,"$XSESSION_SHELL",[xsession shell])
 AC_SUBST(SOUND_PROGRAM)
 AC_DEFINE_UNQUOTED(SOUND_PROGRAM,"$SOUND_PROGRAM",[])
 
 AC_SUBST(X_PATH)
 AC_SUBST(X_SERVER)
 AC_SUBST(X_SERVER_PATH)
 AC_DEFINE_UNQUOTED(X_SERVER,"$X_SERVER",[])
 AC_DEFINE_UNQUOTED(X_SERVER_PATH,"$X_SERVER_PATH",[])
 
 ## Stuff for debian/changelog.in
 #if test -e "debian/changelog"; then
 #  DEBIAN_DATESTAMP=`head -1 debian/changelog| sed -e 's/.*cvs.//' -e 's/).*//'`
 #  DEBIAN_DATE=`grep '^ --' debian/changelog | head -1 | sed -e 's/.*  //'`
 #else
 #  DEBIAN_DATESTAMP=`date +%Y%m%d%H%M%s`
 #  DEBIAN_DATE=`date -R`
 #fi
 #
 #AC_SUBST(DEBIAN_DATESTAMP)
 #AC_SUBST(DEBIAN_DATE)
 
 AC_CONFIG_FILES([
 Makefile
 pam-extensions/Makefile
 pam-extensions/gdm-pam-extensions.pc
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index d999596b5..7a013c694 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -37,61 +37,61 @@
 #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
 #define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
 
 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;
 
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
-        char            *tty_of_active_vt;
+        unsigned int     active_vt;
         guint            active_vt_watch_id;
         guint            wait_to_finish_timeout_id;
 #endif
 };
 
 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;
 static gboolean lookup_by_session_id (const char *id,
                                       GdmDisplay *display,
                                       gpointer    user_data);
 
 G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
 
@@ -641,157 +641,161 @@ maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
                 g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring");
                 return;
         }
 
         /* we can only stop greeter for wayland sessions, since
          * X server would jump back on exit */
         if (g_strcmp0 (display_session_type, "wayland") != 0) {
                 g_debug ("GdmLocalDisplayFactory: login window is running on Xorg, so ignoring");
                 return;
         }
 
         g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
         g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
 
         /* We stop the greeter after a timeout to avoid flicker */
         if (factory->priv->wait_to_finish_timeout_id != 0)
                 g_source_remove (factory->priv->wait_to_finish_timeout_id);
 
         factory->priv->wait_to_finish_timeout_id =
                 g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
                                        (GSourceFunc)wait_to_finish_timeout,
                                        factory);
 }
 
 static gboolean
 on_vt_changed (GIOChannel    *source,
                GIOCondition   condition,
                GdmLocalDisplayFactory *factory)
 {
         GIOStatus status;
-        static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
-        g_autofree char *tty_of_previous_vt = NULL;
         g_autofree char *tty_of_active_vt = NULL;
         g_autofree char *login_session_id = NULL;
         g_autofree char *active_session_id = NULL;
+        unsigned int previous_vt, new_vt;
         const char *session_type = NULL;
-        int ret;
+        int ret, n_returned;
 
         g_debug ("GdmLocalDisplayFactory: received VT change event");
         g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
 
         if (condition & G_IO_PRI) {
                 g_autoptr (GError) error = NULL;
                 status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
 
                 if (error != NULL) {
                         g_warning ("could not read active VT from kernel: %s", error->message);
                 }
                 switch (status) {
                         case G_IO_STATUS_ERROR:
                             return G_SOURCE_REMOVE;
                         case G_IO_STATUS_EOF:
                             return G_SOURCE_REMOVE;
                         case G_IO_STATUS_AGAIN:
                             return G_SOURCE_CONTINUE;
                         case G_IO_STATUS_NORMAL:
                             break;
                 }
         }
 
         if ((condition & G_IO_ERR) || (condition & G_IO_HUP)) {
                 g_debug ("GdmLocalDisplayFactory: kernel hung up active vt watch");
                 return G_SOURCE_REMOVE;
         }
 
         if (tty_of_active_vt == NULL) {
                 g_debug ("GdmLocalDisplayFactory: unable to read active VT from kernel");
                 return G_SOURCE_CONTINUE;
         }
 
         g_strchomp (tty_of_active_vt);
 
+        errno = 0;
+        n_returned = sscanf (tty_of_active_vt, "tty%u", &new_vt);
+
+        if (n_returned != 1 || errno != 0) {
+                g_critical ("GdmLocalDisplayFactory: Couldn't read active VT (got '%s')",
+                            tty_of_active_vt);
+                return G_SOURCE_CONTINUE;
+        }
+
         /* don't do anything if we're on the same VT we were before */
-        if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0) {
+        if (new_vt == factory->priv->active_vt) {
                 g_debug ("GdmLocalDisplayFactory: VT changed to the same VT, ignoring");
                 return G_SOURCE_CONTINUE;
         }
 
-        tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
-        factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
+        previous_vt = factory->priv->active_vt;
+        factory->priv->active_vt = new_vt;
 
         /* don't do anything at start up */
-        if (tty_of_previous_vt == NULL) {
-                g_debug ("GdmLocalDisplayFactory: VT is %s at startup",
-                         factory->priv->tty_of_active_vt);
+        if (previous_vt == 0) {
+                g_debug ("GdmLocalDisplayFactory: VT is %u at startup",
+                         factory->priv->active_vt);
                 return G_SOURCE_CONTINUE;
         }
 
-        g_debug ("GdmLocalDisplayFactory: VT changed from %s to %s",
-                 tty_of_previous_vt, factory->priv->tty_of_active_vt);
+        g_debug ("GdmLocalDisplayFactory: VT changed from %u to %u",
+                 previous_vt, factory->priv->active_vt);
 
         /* if the old VT was running a wayland login screen kill it
          */
         if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
-                unsigned int vt;
+                unsigned int login_window_vt;
 
-                ret = sd_session_get_vt (login_session_id, &vt);
-                if (ret == 0 && vt != 0) {
-                        g_autofree char *tty_of_login_window_vt = NULL;
-
-                        tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
-
-                        g_debug ("GdmLocalDisplayFactory: tty of login window is %s", tty_of_login_window_vt);
-                        if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
+                ret = sd_session_get_vt (login_session_id, &login_window_vt);
+                if (ret == 0 && login_window_vt != 0) {
+                        g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt);
+                        if (login_window_vt == previous_vt) {
                                 GdmDisplayStore *store;
                                 GdmDisplay *display;
 
                                 g_debug ("GdmLocalDisplayFactory: VT switched from login window");
 
                                 store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
                                 display = gdm_display_store_find (store,
                                                                   lookup_by_session_id,
                                                                   (gpointer) login_session_id);
 
                                 if (display != NULL)
                                         maybe_stop_greeter_in_background (factory, display);
                         } else {
                                 g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
                         }
                 }
         }
 
         /* if user jumped back to initial vt and it's empty put a login screen
          * on it (unless a login screen is already running elsewhere, then
          * jump to that login screen)
          */
-        if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
+        if (factory->priv->active_vt != GDM_INITIAL_VT) {
                 g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
                 return G_SOURCE_CONTINUE;
         }
 
         if (gdm_local_display_factory_use_wayland ())
                 session_type = "wayland";
 
         g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
 
         create_display (factory, "seat0", session_type, TRUE);
 
         return G_SOURCE_CONTINUE;
 }
 #endif
 
 static void
 gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
 {
         g_autoptr (GIOChannel) io_channel = NULL;
 
         factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
                                                                          "org.freedesktop.login1",
                                                                          "org.freedesktop.login1.Manager",
                                                                          "SeatNew",
                                                                          "/org/freedesktop/login1",
                                                                          NULL,
                                                                          G_DBUS_SIGNAL_FLAGS_NONE,
                                                                          on_seat_new,
                                                                          g_object_ref (factory),
                                                                          g_object_unref);
@@ -815,62 +819,60 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
                                         G_IO_PRI,
                                         (GIOFunc)
                                         on_vt_changed,
                                         factory);
         }
 #endif
 }
 
 static void
 gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
 {
         if (factory->priv->seat_new_id) {
                 g_dbus_connection_signal_unsubscribe (factory->priv->connection,
                                                       factory->priv->seat_new_id);
                 factory->priv->seat_new_id = 0;
         }
         if (factory->priv->seat_removed_id) {
                 g_dbus_connection_signal_unsubscribe (factory->priv->connection,
                                                       factory->priv->seat_removed_id);
                 factory->priv->seat_removed_id = 0;
         }
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
         if (factory->priv->wait_to_finish_timeout_id != 0) {
                 g_source_remove (factory->priv->wait_to_finish_timeout_id);
                 factory->priv->wait_to_finish_timeout_id = 0;
         }
         if (factory->priv->active_vt_watch_id) {
                 g_source_remove (factory->priv->active_vt_watch_id);
                 factory->priv->active_vt_watch_id = 0;
         }
-
-        g_clear_pointer (&factory->priv->tty_of_active_vt, g_free);
 #endif
 }
 
 static void
 on_display_added (GdmDisplayStore        *display_store,
                   const char             *id,
                   GdmLocalDisplayFactory *factory)
 {
         GdmDisplay *display;
 
         display = gdm_display_store_lookup (display_store, id);
 
         if (display != NULL) {
                 g_signal_connect_object (display, "notify::status",
                                          G_CALLBACK (on_display_status_changed),
                                          factory,
                                          0);
 
                 g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
         }
 }
 
 static void
 on_display_removed (GdmDisplayStore        *display_store,
                     GdmDisplay             *display,
                     GdmLocalDisplayFactory *factory)
 {
         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);
 }
diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c
index 83fba99c8..04406a61a 100644
--- a/daemon/gdm-server.c
+++ b/daemon/gdm-server.c
@@ -726,61 +726,61 @@ gdm_server_spawn (GdmServer    *server,
                                                           (GChildWatchFunc)server_child_watch,
                                                           server);
 
         ret = TRUE;
  out:
         g_strfreev (argv);
         if (env) {
                 g_ptr_array_foreach (env, (GFunc)g_free, NULL);
                 g_ptr_array_free (env, TRUE);
         }
         return ret;
 }
 
 /**
  * gdm_server_start:
  * @disp: Pointer to a GdmDisplay structure
  *
  * Starts a local X server. Handles retries and fatal errors properly.
  */
 
 gboolean
 gdm_server_start (GdmServer *server)
 {
         gboolean res = FALSE;
         const char *vtarg = NULL;
         GError *local_error = NULL;
         GError **error = &local_error;
 
         /* Hardcode the VT for the initial X server, but nothing else */
         if (server->priv->is_initial) {
-                vtarg = "vt" GDM_INITIAL_VT;
+                vtarg = "vt" G_STRINGIFY (GDM_INITIAL_VT);
         }
 
         /* fork X server process */
         if (!gdm_server_spawn (server, vtarg, error)) {
                 goto out;
         }
 
         res = TRUE;
  out:
         if (local_error) {
                 g_printerr ("%s\n", local_error->message);
                 g_clear_error (&local_error);
         }
         return res;
 }
 
 static void
 server_died (GdmServer *server)
 {
         int exit_status;
 
         g_debug ("GdmServer: Waiting on process %d", server->priv->pid);
         exit_status = gdm_wait_on_pid (server->priv->pid);
 
         if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
                 g_debug ("GdmServer: Wait on child process failed");
         } else {
                 /* exited normally */
         }
 
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 7ed2789da..b4befaa83 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2202,61 +2202,61 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
 
         g_debug ("GdmSessionWorker: state SESSION_STARTED");
         gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED);
 
         gdm_session_worker_watch_child (worker);
 
  out:
         if (error_code != PAM_SUCCESS) {
                 gdm_session_worker_uninitialize_pam (worker, error_code);
                 return FALSE;
         }
 
         return TRUE;
 }
 
 static gboolean
 set_up_for_new_vt (GdmSessionWorker *worker)
 {
         int fd;
         char vt_string[256], tty_string[256];
         int session_vt = 0;
 
         fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
 
         if (fd < 0) {
                 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
                 return FALSE;
         }
 
         if (worker->priv->display_is_initial) {
-                session_vt = atoi (GDM_INITIAL_VT);
+                session_vt = GDM_INITIAL_VT;
         } else {
                 if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
                         g_debug ("GdmSessionWorker: couldn't open new VT: %m");
                         goto fail;
                 }
         }
 
         worker->priv->session_vt = session_vt;
 
         close (fd);
         fd = -1;
 
         g_assert (session_vt > 0);
 
         g_snprintf (vt_string, sizeof (vt_string), "%d", session_vt);
 
         /* Set the VTNR. This is used by logind to configure a session in
          * the logind-managed case, but it doesn't hurt to set it always.
          * When logind gains support for XDG_VTNR=auto, we can make the
          * OPENQRY and this whole path only used by the new VT code. */
         gdm_session_worker_set_environment_variable (worker,
                                                      "XDG_VTNR",
                                                      vt_string);
 
         g_snprintf (tty_string, 256, "/dev/tty%d", session_vt);
         worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
         pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
 
         return TRUE;
 
-- 
2.27.0