539 lines
20 KiB
Diff
539 lines
20 KiB
Diff
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
|
|
|