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