From 3cf5b4b12d3d39fa858ff593adeecfe711cdddaf Mon Sep 17 00:00:00 2001 From: Iain Lane 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=], [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