From c251ce4583529e59bbd4b2745ab2fe43e9945c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jezer=20Mej=C3=ADa?= Date: Fri, 12 Jul 2024 18:25:01 +0000 Subject: [PATCH 1/2] Add finish_behavior property to greeter --- debian/liblightdm-gobject-1-0.symbols | 1 + doc/lightdm-gobject-1-sections.txt | 1 + liblightdm-gobject/greeter.c | 34 +++++++++++++++++++++------ liblightdm-gobject/lightdm/greeter.h | 15 ++++++++++++ liblightdm-qt/QLightDM/greeter.h | 7 ++++++ liblightdm-qt/greeter.cpp | 24 +++++++++++++++++++ src/greeter.c | 24 ++++++++++--------- src/greeter.h | 10 +++++++- src/seat.c | 21 +++++++++++++---- 9 files changed, 113 insertions(+), 24 deletions(-) diff --git a/debian/liblightdm-gobject-1-0.symbols b/debian/liblightdm-gobject-1-0.symbols index 5782b0e82..82cb5f421 100644 --- a/debian/liblightdm-gobject-1-0.symbols +++ b/debian/liblightdm-gobject-1-0.symbols @@ -52,6 +52,7 @@ liblightdm-gobject-1.so.0 liblightdm-gobject-1-0 #MINVER# lightdm_greeter_respond@Base 0.9.2 lightdm_greeter_set_language@Base 0.9.8 lightdm_greeter_set_resettable@Base 1.11.1 + lightdm_greeter_set_finish_behavior@Base 1.33.0 lightdm_greeter_start_session@Base 1.11.1 lightdm_greeter_start_session_finish@Base 1.11.1 lightdm_greeter_start_session_sync@Base 0.9.2 diff --git a/doc/lightdm-gobject-1-sections.txt b/doc/lightdm-gobject-1-sections.txt index 6a4437563..00e2de2bd 100644 --- a/doc/lightdm-gobject-1-sections.txt +++ b/doc/lightdm-gobject-1-sections.txt @@ -7,6 +7,7 @@ LightDMGreeterError lightdm_greeter_error_quark lightdm_greeter_new lightdm_greeter_set_resettable +lightdm_greeter_set_finish_behavior lightdm_greeter_connect_to_daemon lightdm_greeter_connect_to_daemon_finish lightdm_greeter_connect_to_daemon_sync diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c index f8bc6854d..d8f68f115 100644 --- a/liblightdm-gobject/greeter.c +++ b/liblightdm-gobject/greeter.c @@ -121,8 +121,8 @@ typedef struct /* API version the daemon is using */ guint32 api_version; - /* TRUE if the daemon can reuse this greeter */ - gboolean resettable; + /* Defines the finish behavior for the greeter; either to be resettable, killed immediately or terminated gracefully */ + LightDMGreeterFinishBehavior finish_behavior; /* Socket connection to daemon */ GSocket *socket; @@ -297,6 +297,7 @@ lightdm_greeter_new (void) * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in * * Set whether the greeter will be reset instead of killed after the user logs in. + * Use lightdm_greeter_set_finish_behavior to set more behaviors after logged in. * This must be called before lightdm_greeter_connect is called. **/ void @@ -307,7 +308,26 @@ lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable) LightDMGreeterPrivate *priv = lightdm_greeter_get_instance_private (greeter); g_return_if_fail (!priv->connected); - priv->resettable = resettable; + priv->finish_behavior = resettable ? LIGHTDM_GREETER_FINISH_BEHAVIOR_RESETTABLE : LIGHTDM_GREETER_FINISH_BEHAVIOR_IMMEDIATE; +} + +/** + * lightdm_greeter_set_finish_behavior: + * @greeter: A #LightDMGreeter + * @finish_behavior: The finish behavior of the greeter when the user logs in + * + * Set whether the greeter will be reset, killed immediately or terminated gracefully. + * This must be called before lightdm_greeter_connect is called. + **/ +void +lightdm_greeter_set_finish_behavior (LightDMGreeter *greeter, LightDMGreeterFinishBehavior finish_behavior) +{ + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + LightDMGreeterPrivate *priv = lightdm_greeter_get_instance_private (greeter); + + g_return_if_fail (!priv->connected); + priv->finish_behavior = finish_behavior; } static Request * @@ -921,14 +941,14 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) } static gboolean -send_connect (LightDMGreeter *greeter, gboolean resettable, GError **error) +send_connect (LightDMGreeter *greeter, LightDMGreeterFinishBehavior finish_behavior, GError **error) { g_debug ("Connecting to display manager..."); guint8 message[MAX_MESSAGE_LENGTH]; gsize offset = 0; return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length () * 2, &offset, error) && write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset, error) && - write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset, error) && + write_int (message, MAX_MESSAGE_LENGTH, finish_behavior, &offset, error) && write_int (message, MAX_MESSAGE_LENGTH, API_VERSION, &offset, error) && send_message (greeter, message, offset, error); } @@ -982,7 +1002,7 @@ lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancel Request *request = request_new (greeter, cancellable, callback, user_data); GError *error = NULL; - if (send_connect (greeter, priv->resettable, &error)) + if (send_connect (greeter, priv->finish_behavior, &error)) priv->connect_requests = g_list_append (priv->connect_requests, request); else { @@ -1030,7 +1050,7 @@ lightdm_greeter_connect_to_daemon_sync (LightDMGreeter *greeter, GError **error) LightDMGreeterPrivate *priv = lightdm_greeter_get_instance_private (greeter); /* Read until we are connected */ - if (!send_connect (greeter, priv->resettable, error)) + if (!send_connect (greeter, priv->finish_behavior, error)) return FALSE; Request *request = request_new (greeter, NULL, NULL, NULL); priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request)); diff --git a/liblightdm-gobject/lightdm/greeter.h b/liblightdm-gobject/lightdm/greeter.h index 8ef500d5f..02df31905 100644 --- a/liblightdm-gobject/lightdm/greeter.h +++ b/liblightdm-gobject/lightdm/greeter.h @@ -114,6 +114,19 @@ typedef enum LIGHTDM_GREETER_ERROR_INVALID_USER } LightDMGreeterError; +/** + * LightDMGreeterFinishBehavior: + * @LIGHTDM_GREETER_FINISH_BEHAVIOR_IMMEDIATE: greeter is killed immediately. + * @LIGHTDM_GREETER_FINISH_BEHAVIOR_RESETTABLE: greeter can be reset. + * @LIGHTDM_GREETER_FINISH_BEHAVIOR_GRACEFUL: greeter is terminated gracefully. + */ +typedef enum +{ + LIGHTDM_GREETER_FINISH_BEHAVIOR_IMMEDIATE, + LIGHTDM_GREETER_FINISH_BEHAVIOR_RESETTABLE, + LIGHTDM_GREETER_FINISH_BEHAVIOR_GRACEFUL, +} LightDMGreeterFinishBehavior; + GQuark lightdm_greeter_error_quark (void); GType lightdm_greeter_error_get_type (void); @@ -124,6 +137,8 @@ LightDMGreeter *lightdm_greeter_new (void); void lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable); +void lightdm_greeter_set_finish_behavior (LightDMGreeter *greeter, LightDMGreeterFinishBehavior finish_behavior); + void lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); gboolean lightdm_greeter_connect_to_daemon_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error); diff --git a/liblightdm-qt/QLightDM/greeter.h b/liblightdm-qt/QLightDM/greeter.h index 720574fa2..b4a1e4486 100644 --- a/liblightdm-qt/QLightDM/greeter.h +++ b/liblightdm-qt/QLightDM/greeter.h @@ -53,6 +53,12 @@ class Q_DECL_EXPORT Greeter : public QObject MessageTypeError }; + enum FinishBehavior { + BehaviorImmediate, + BehaviorResettable, + BehaviorGraceful + }; + explicit Greeter(QObject* parent=0); virtual ~Greeter(); @@ -93,6 +99,7 @@ public Q_SLOTS: void cancelAutologin(); void setLanguage (const QString &language); void setResettable (bool resettable); + void setFinishBehavior (QLightDM::Greeter::FinishBehavior finishBehavior); bool startSessionSync(const QString &session=QString()); QString ensureSharedDataDirSync(const QString &username); diff --git a/liblightdm-qt/greeter.cpp b/liblightdm-qt/greeter.cpp index 462f69133..ca7f38a9d 100644 --- a/liblightdm-qt/greeter.cpp +++ b/liblightdm-qt/greeter.cpp @@ -11,6 +11,7 @@ #include "QLightDM/greeter.h" +#include "lightdm/greeter.h" #include #include @@ -202,6 +203,29 @@ void Greeter::setResettable (bool resettable) lightdm_greeter_set_resettable(d->ldmGreeter, resettable); } +void Greeter::setFinishBehavior (QLightDM::Greeter::FinishBehavior finishBehavior) +{ + Q_D(Greeter); + LightDMGreeterFinishBehavior behavior; + + switch (finishBehavior) + { + case BehaviorResettable: + behavior = LIGHTDM_GREETER_FINISH_BEHAVIOR_RESETTABLE; + break; + case BehaviorGraceful: + behavior = LIGHTDM_GREETER_FINISH_BEHAVIOR_GRACEFUL; + break; + break; + case BehaviorImmediate: + default: + behavior = LIGHTDM_GREETER_FINISH_BEHAVIOR_IMMEDIATE; + break; + } + + lightdm_greeter_set_finish_behavior(d->ldmGreeter, behavior); +} + bool Greeter::startSessionSync(const QString &session) { Q_D(Greeter); diff --git a/src/greeter.c b/src/greeter.c index 366726670..8c5edf68f 100644 --- a/src/greeter.c +++ b/src/greeter.c @@ -66,8 +66,8 @@ typedef struct /* TRUE if the PAM session is being cancelled */ gboolean cancelling; - /* TRUE if a the greeter can handle a reset; else we will just kill it instead */ - gboolean resettable; + /* Defines the finish behavior for the greeter; either to be resettable, killed immediately or terminated gracefully */ + FinishBehavior finish_behavior; /* TRUE if a user has been authenticated and the session requested to start */ gboolean start_session; @@ -327,14 +327,14 @@ string_length (const gchar *value) } static void -handle_connect (Greeter *greeter, const gchar *version, gboolean resettable, guint32 api_version) +handle_connect (Greeter *greeter, const gchar *version, FinishBehavior finish_behavior, guint32 api_version) { GreeterPrivate *priv = greeter_get_instance_private (greeter); - g_debug ("Greeter connected version=%s api=%u resettable=%s", version, api_version, resettable ? "true" : "false"); + g_debug ("Greeter connected version=%s api=%u finish_behavior=%d", version, api_version, finish_behavior); priv->api_version = api_version; - priv->resettable = resettable; + priv->finish_behavior = finish_behavior; guint32 env_length = 0; GHashTableIter iter; @@ -941,13 +941,15 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data) case GREETER_MESSAGE_CONNECT: { g_autofree gchar *version = read_string (greeter, &offset); - gboolean resettable = FALSE; + FinishBehavior finish_behavior = BEHAVIOR_IMMEDIATE; if (offset < length) - resettable = read_int (greeter, &offset) != 0; + finish_behavior = read_int (greeter, &offset); + if (finish_behavior >= LAST_BEHAVIOR) + finish_behavior = BEHAVIOR_IMMEDIATE; guint32 api_version = 0; if (offset < length) api_version = read_int (greeter, &offset); - handle_connect (greeter, version, resettable, api_version); + handle_connect (greeter, version, finish_behavior, api_version); } break; case GREETER_MESSAGE_AUTHENTICATE: @@ -1044,12 +1046,12 @@ greeter_take_authentication_session (Greeter *greeter) return session; } -gboolean -greeter_get_resettable (Greeter *greeter) +FinishBehavior +greeter_get_finish_behavior (Greeter *greeter) { GreeterPrivate *priv = greeter_get_instance_private (greeter); g_return_val_if_fail (greeter != NULL, FALSE); - return priv->resettable; + return priv->finish_behavior; } gboolean diff --git a/src/greeter.h b/src/greeter.h index 4038e694e..0300071b5 100644 --- a/src/greeter.h +++ b/src/greeter.h @@ -46,6 +46,14 @@ typedef struct gboolean (*start_session)(Greeter *greeter, SessionType type, const gchar *session); } GreeterClass; +typedef enum +{ + BEHAVIOR_IMMEDIATE, + BEHAVIOR_RESETTABLE, + BEHAVIOR_GRACEFUL, + LAST_BEHAVIOR, +} FinishBehavior; + G_DEFINE_AUTOPTR_CLEANUP_FUNC (Greeter, g_object_unref) GType greeter_get_type (void); @@ -74,7 +82,7 @@ Session *greeter_take_authentication_session (Greeter *greeter); gboolean greeter_get_start_session (Greeter *greeter); -gboolean greeter_get_resettable (Greeter *greeter); +FinishBehavior greeter_get_finish_behavior (Greeter *greeter); const gchar *greeter_get_active_username (Greeter *greeter); diff --git a/src/seat.c b/src/seat.c index 0b55906c0..1cfa4b6b0 100644 --- a/src/seat.c +++ b/src/seat.c @@ -15,9 +15,11 @@ #include "seat.h" #include "configuration.h" +#include "greeter.h" #include "guest-account.h" #include "greeter-session.h" #include "session-config.h" +#include "session.h" enum { SESSION_ADDED, @@ -267,7 +269,8 @@ seat_set_active_session (Seat *seat, Session *session) if (IS_GREETER_SESSION (s)) { Greeter *greeter = greeter_session_get_greeter (GREETER_SESSION (s)); - if (greeter_get_resettable (greeter)) + FinishBehavior finish_behavior = greeter_get_finish_behavior(greeter); + if (finish_behavior == BEHAVIOR_RESETTABLE) { if (priv->active_session == s) { @@ -563,7 +566,7 @@ find_resettable_greeter (Seat *seat) { Session *session = link->data; if (!session_get_is_stopping (session) && IS_GREETER_SESSION (session) && - greeter_get_resettable (greeter_session_get_greeter (GREETER_SESSION (session)))) + greeter_get_finish_behavior (greeter_session_get_greeter (GREETER_SESSION (session))) == BEHAVIOR_RESETTABLE) return GREETER_SESSION (session); } @@ -1214,7 +1217,7 @@ greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *sessi { DisplayServer *display_server = session_get_display_server (greeter_session); if (display_server && - !greeter_get_resettable (greeter) && + greeter_get_finish_behavior (greeter) != BEHAVIOR_RESETTABLE && can_share_display_server (seat, display_server) && strcmp (display_server_get_session_type (display_server), session_get_session_type (session)) == 0) { @@ -1223,8 +1226,16 @@ greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *sessi /* Run on the same display server after the greeter has stopped */ session_set_display_server (session, display_server); - /* Stop the greeter */ - session_stop (greeter_session); + FinishBehavior finish_behavior = greeter_get_finish_behavior(greeter); + if (finish_behavior == BEHAVIOR_GRACEFUL) + { + l_debug (seat, "Waiting for greeter to terminate"); + } + else + { + /* Stop the greeter */ + session_stop (greeter_session); + } return TRUE; } From e6c329a34693ada58cc65d7b184f56828be72f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jezer=20Mej=C3=ADa?= Date: Fri, 12 Jul 2024 23:20:31 -0600 Subject: [PATCH 2/2] Add greeter-grace-timeout option --- common/configuration.c | 1 + data/lightdm.conf | 2 ++ src/seat.c | 18 ++++++++++++++++++ src/session.c | 36 ++++++++++++++++++++++++++++++++---- src/session.h | 2 ++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/common/configuration.c b/common/configuration.c index 30580ead6..a2f0616cf 100644 --- a/common/configuration.c +++ b/common/configuration.c @@ -371,6 +371,7 @@ config_init (Configuration *config) g_hash_table_insert (config->priv->seat_keys, "greeter-allow-guest", GINT_TO_POINTER (KEY_SUPPORTED)); g_hash_table_insert (config->priv->seat_keys, "greeter-show-manual-login", GINT_TO_POINTER (KEY_SUPPORTED)); g_hash_table_insert (config->priv->seat_keys, "greeter-show-remote-login", GINT_TO_POINTER (KEY_SUPPORTED)); + g_hash_table_insert (config->priv->seat_keys, "greeter-grace-timeout", GINT_TO_POINTER (KEY_SUPPORTED)); g_hash_table_insert (config->priv->seat_keys, "user-session", GINT_TO_POINTER (KEY_SUPPORTED)); g_hash_table_insert (config->priv->seat_keys, "allow-user-switching", GINT_TO_POINTER (KEY_SUPPORTED)); g_hash_table_insert (config->priv->seat_keys, "allow-guest", GINT_TO_POINTER (KEY_SUPPORTED)); diff --git a/data/lightdm.conf b/data/lightdm.conf index 60e3e8b40..fa05f3113 100644 --- a/data/lightdm.conf +++ b/data/lightdm.conf @@ -64,6 +64,7 @@ # greeter-allow-guest = True if the greeter should show a guest login option # greeter-show-manual-login = True if the greeter should offer a manual login option # greeter-show-remote-login = True if the greeter should offer a remote login option +# greeter-grace-timeout = Number of seconds to wait before killing the greeter # user-session = Session to load for users # allow-user-switching = True if allowed to switch users # allow-guest = True if guest login is allowed @@ -104,6 +105,7 @@ #greeter-allow-guest=true #greeter-show-manual-login=false #greeter-show-remote-login=true +#greeter-grace-timeout=0 #user-session=default #allow-user-switching=true #allow-guest=true diff --git a/src/seat.c b/src/seat.c index 1cfa4b6b0..c58eb0389 100644 --- a/src/seat.c +++ b/src/seat.c @@ -1131,6 +1131,18 @@ greeter_create_session_cb (Greeter *greeter, Seat *seat) return g_object_ref (session); } +static void +greeter_grace_timeout_cb (gpointer data) +{ + Session *session = data; + + if (!session_get_is_started(session)) + return; + + l_debug (session, "Greeter timed out"); + session_stop (session); +} + static gboolean greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *session_name, Seat *seat) { @@ -1230,6 +1242,12 @@ greeter_start_session_cb (Greeter *greeter, SessionType type, const gchar *sessi if (finish_behavior == BEHAVIOR_GRACEFUL) { l_debug (seat, "Waiting for greeter to terminate"); + int timeout = seat_get_integer_property (seat, "greeter-grace-timeout"); + if (timeout > 0) { + g_timeout_add_seconds_once(timeout, greeter_grace_timeout_cb, greeter_session); + } + + session_wait_for_finish(greeter_session); } else { diff --git a/src/session.c b/src/session.c index d0d8a2351..3460df880 100644 --- a/src/session.c +++ b/src/session.c @@ -934,13 +934,11 @@ session_activate (Session *session) } } -void -session_stop (Session *session) +static void +session_stop_processes(Session *session) { SessionPrivate *priv = session_get_instance_private (session); - g_return_if_fail (session != NULL); - if (priv->stopping) return; priv->stopping = TRUE; @@ -966,7 +964,37 @@ session_stop (Session *session) write_data (session, &n, sizeof (n)); // command return; } +} + +static void +session_finish_cb (GPid pid, gint status, gpointer data) +{ + Session *session = data; + g_return_if_fail (session != NULL); + + session_stop_processes(session); + + // Call default callback + session_watch_cb(pid, status, data); +} + +void +session_wait_for_finish(Session *session) +{ + SessionPrivate *priv = session_get_instance_private (session); + + if (priv->child_watch) + g_source_remove (priv->child_watch); + + priv->child_watch = g_child_watch_add_full(G_PRIORITY_HIGH, priv->pid, session_finish_cb, session, NULL); +} + +void +session_stop (Session *session) +{ + g_return_if_fail (session != NULL); + session_stop_processes(session); return SESSION_GET_CLASS (session)->stop (session); } diff --git a/src/session.h b/src/session.h index ed9bacf40..4f2b78091 100644 --- a/src/session.h +++ b/src/session.h @@ -148,6 +148,8 @@ void session_unlock (Session *session); void session_activate (Session *session); +void session_wait_for_finish(Session *session); + void session_stop (Session *session); gboolean session_get_is_stopping (Session *session);