From: Lennart Poettering Date: Wed, 2 Apr 2025 14:42:40 +0000 (+0200) Subject: logind: split utmp related code into logind-utmp.[ch] X-Git-Tag: v258-rc1~945^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=700f37c3675fffac5998435381af712f30248dbd;p=thirdparty%2Fsystemd.git logind: split utmp related code into logind-utmp.[ch] No real changes, just moving of code around. --- diff --git a/src/login/logind-core.c b/src/login/logind-core.c index f3102c31994..16192765206 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -20,6 +20,7 @@ #include "fd-util.h" #include "limits-util.h" #include "logind.h" +#include "logind-utmp.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -29,7 +30,6 @@ #include "udev-util.h" #include "user-util.h" #include "userdb.h" -#include "utmp-wtmp.h" void manager_reset_config(Manager *m) { assert(m); @@ -711,137 +711,6 @@ bool manager_all_buttons_ignored(Manager *m) { return true; } -int manager_read_utmp(Manager *m) { -#if ENABLE_UTMP - int r; - _unused_ _cleanup_(utxent_cleanup) bool utmpx = false; - - assert(m); - - if (utmpxname(UTMPX_FILE) < 0) - return log_error_errno(errno, "Failed to set utmp path to " UTMPX_FILE ": %m"); - - utmpx = utxent_start(); - - for (;;) { - _cleanup_free_ char *t = NULL; - struct utmpx *u; - const char *c; - Session *s; - - errno = 0; - u = getutxent(); - if (!u) { - if (errno == ENOENT) - log_debug_errno(errno, UTMPX_FILE " does not exist, ignoring."); - else if (errno != 0) - log_warning_errno(errno, "Failed to read " UTMPX_FILE ", ignoring: %m"); - return 0; - } - - if (u->ut_type != USER_PROCESS) - continue; - - if (!pid_is_valid(u->ut_pid)) - continue; - - t = strndup(u->ut_line, sizeof(u->ut_line)); - if (!t) - return log_oom(); - - c = path_startswith(t, "/dev/"); - if (c) { - r = free_and_strdup(&t, c); - if (r < 0) - return log_oom(); - } - - if (isempty(t)) - continue; - - if (manager_get_session_by_pidref(m, &PIDREF_MAKE_FROM_PID(u->ut_pid), &s) <= 0) - continue; - - if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) { - /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In - * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY - * information and never acquire it again. */ - - s->tty = mfree(s->tty); - s->tty_validity = TTY_UTMP_INCONSISTENT; - log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id); - continue; - } - - /* Never override what we figured out once */ - if (s->tty || s->tty_validity >= 0) - continue; - - s->tty = TAKE_PTR(t); - s->tty_validity = TTY_FROM_UTMP; - log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id); - } - -#else - return 0; -#endif -} - -#if ENABLE_UTMP -static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) { - Manager *m = ASSERT_PTR(userdata); - - /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's - * reestablish the watch on whatever there's now. */ - if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0) - manager_connect_utmp(m); - - (void) manager_read_utmp(m); - return 0; -} -#endif - -void manager_connect_utmp(Manager *m) { -#if ENABLE_UTMP - sd_event_source *s = NULL; - int r; - - assert(m); - - /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM - * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known - * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and - * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry. - * - * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle - * detection (which, for tty sessions, relies on the TTY used) */ - - r = sd_event_add_inotify(m->event, &s, UTMPX_FILE, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m); - if (r < 0) - log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " UTMPX_FILE ", ignoring: %m"); - else { - r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE); - if (r < 0) - log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m"); - - (void) sd_event_source_set_description(s, "utmp"); - } - - sd_event_source_unref(m->utmp_event_source); - m->utmp_event_source = s; -#endif -} - -void manager_reconnect_utmp(Manager *m) { -#if ENABLE_UTMP - assert(m); - - if (m->utmp_event_source) - return; - - manager_connect_utmp(m); -#endif -} int manager_read_efi_boot_loader_entries(Manager *m) { #if ENABLE_EFI diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index ed0db4a2ffc..404bee5a858 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -32,13 +32,14 @@ #include "fileio.h" #include "format-util.h" #include "fs-util.h" +#include "logind.h" #include "logind-action.h" #include "logind-dbus.h" #include "logind-polkit.h" #include "logind-seat-dbus.h" #include "logind-session-dbus.h" #include "logind-user-dbus.h" -#include "logind.h" +#include "logind-utmp.h" #include "mkdir-label.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c new file mode 100644 index 00000000000..d2a1331374c --- /dev/null +++ b/src/login/logind-utmp.c @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "logind-utmp.h" +#include "path-util.h" +#include "utmp-wtmp.h" + +int manager_read_utmp(Manager *m) { +#if ENABLE_UTMP + int r; + _unused_ _cleanup_(utxent_cleanup) bool utmpx = false; + + assert(m); + + if (utmpxname(UTMPX_FILE) < 0) + return log_error_errno(errno, "Failed to set utmp path to " UTMPX_FILE ": %m"); + + utmpx = utxent_start(); + + for (;;) { + _cleanup_free_ char *t = NULL; + struct utmpx *u; + const char *c; + Session *s; + + errno = 0; + u = getutxent(); + if (!u) { + if (errno == ENOENT) + log_debug_errno(errno, UTMPX_FILE " does not exist, ignoring."); + else if (errno != 0) + log_warning_errno(errno, "Failed to read " UTMPX_FILE ", ignoring: %m"); + return 0; + } + + if (u->ut_type != USER_PROCESS) + continue; + + if (!pid_is_valid(u->ut_pid)) + continue; + + t = strndup(u->ut_line, sizeof(u->ut_line)); + if (!t) + return log_oom(); + + c = path_startswith(t, "/dev/"); + if (c) { + r = free_and_strdup(&t, c); + if (r < 0) + return log_oom(); + } + + if (isempty(t)) + continue; + + if (manager_get_session_by_pidref(m, &PIDREF_MAKE_FROM_PID(u->ut_pid), &s) <= 0) + continue; + + if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) { + /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In + * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY + * information and never acquire it again. */ + + s->tty = mfree(s->tty); + s->tty_validity = TTY_UTMP_INCONSISTENT; + log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id); + continue; + } + + /* Never override what we figured out once */ + if (s->tty || s->tty_validity >= 0) + continue; + + s->tty = TAKE_PTR(t); + s->tty_validity = TTY_FROM_UTMP; + log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id); + } + +#else + return 0; +#endif +} + +#if ENABLE_UTMP +static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) { + Manager *m = ASSERT_PTR(userdata); + + /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's + * reestablish the watch on whatever there's now. */ + if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0) + manager_connect_utmp(m); + + (void) manager_read_utmp(m); + return 0; +} +#endif + +void manager_connect_utmp(Manager *m) { +#if ENABLE_UTMP + sd_event_source *s = NULL; + int r; + + assert(m); + + /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM + * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known + * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and + * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry. + * + * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle + * detection (which, for tty sessions, relies on the TTY used) */ + + r = sd_event_add_inotify(m->event, &s, UTMPX_FILE, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m); + if (r < 0) + log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " UTMPX_FILE ", ignoring: %m"); + else { + r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE); + if (r < 0) + log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m"); + + (void) sd_event_source_set_description(s, "utmp"); + } + + sd_event_source_unref(m->utmp_event_source); + m->utmp_event_source = s; +#endif +} + +void manager_reconnect_utmp(Manager *m) { +#if ENABLE_UTMP + assert(m); + + if (m->utmp_event_source) + return; + + manager_connect_utmp(m); +#endif +} diff --git a/src/login/logind-utmp.h b/src/login/logind-utmp.h new file mode 100644 index 00000000000..1358e27840f --- /dev/null +++ b/src/login/logind-utmp.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "logind.h" + +int manager_read_utmp(Manager *m); +void manager_connect_utmp(Manager *m); +void manager_reconnect_utmp(Manager *m); diff --git a/src/login/logind.c b/src/login/logind.c index ef1952b0cca..f1e2ea3c461 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -29,6 +29,7 @@ #include "logind-seat-dbus.h" #include "logind-session-dbus.h" #include "logind-user-dbus.h" +#include "logind-utmp.h" #include "logind-varlink.h" #include "main-func.h" #include "mkdir-label.h" diff --git a/src/login/logind.h b/src/login/logind.h index b19fbb7f3e0..35d4e9c257c 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -181,10 +181,6 @@ bool manager_is_docked_or_external_displays(Manager *m); bool manager_is_on_external_power(void); bool manager_all_buttons_ignored(Manager *m); -int manager_read_utmp(Manager *m); -void manager_connect_utmp(Manager *m); -void manager_reconnect_utmp(Manager *m); - /* gperf lookup function */ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/login/meson.build b/src/login/meson.build index b7448439336..2983819c56b 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -26,6 +26,7 @@ liblogind_core_sources = files( 'logind-session.c', 'logind-user-dbus.c', 'logind-user.c', + 'logind-utmp.c', 'logind-varlink.c', 'logind-wall.c', )