]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
utmp: drop setting runlevel entry in utmp
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 20 Apr 2025 21:27:35 +0000 (06:27 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 12 Jul 2025 20:49:00 +0000 (05:49 +0900)
This removes systemd-update-utmp-runlevel.service and related command.

TODO
man/rules/meson.build
man/systemd-update-utmp.service.xml
src/shared/utmp-wtmp.c
src/shared/utmp-wtmp.h
src/update-utmp/update-utmp.c
test/units/TEST-01-BASIC.sh
units/meson.build
units/systemd-update-utmp-runlevel.service.in [deleted file]

diff --git a/TODO b/TODO
index 7e23ddb2c8a45c0352e9ff4017ca5e5a395316b4..916c3096aa8a934f63509e72b6aea27d26d8b64f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2268,7 +2268,7 @@ Features:
 
 * clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed
 
-* on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?), get rid of systemd-update-utmp-runlevel
+* on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?)
 
 * make repeated alt-ctrl-del presses printing a dump
 
index 246a059fa5ab0b409a45688cb293b1d6ad8e97c9..1fcf30e6928ab48cf22a7f1a1f2b8281b57535aa 100644 (file)
@@ -1185,10 +1185,7 @@ manpages = [
    'systemd-udevd-varlink.socket'],
   ''],
  ['systemd-update-done.service', '8', ['systemd-update-done'], ''],
- ['systemd-update-utmp.service',
-  '8',
-  ['systemd-update-utmp', 'systemd-update-utmp-runlevel.service'],
-  'ENABLE_UTMP'],
+ ['systemd-update-utmp.service', '8', ['systemd-update-utmp'], 'ENABLE_UTMP'],
  ['systemd-user-sessions.service', '8', ['systemd-user-sessions'], 'HAVE_PAM'],
  ['systemd-userdbd.service', '8', ['systemd-userdbd'], 'ENABLE_USERDB'],
  ['systemd-validatefs@.service', '8', [], 'HAVE_BLKID'],
index 2d7dee9d3a5462b4f3e8afad652c33738f11d364..a3044e9739c092305371572608fe846145990611 100644 (file)
 
   <refnamediv>
     <refname>systemd-update-utmp.service</refname>
-    <refname>systemd-update-utmp-runlevel.service</refname>
     <refname>systemd-update-utmp</refname>
-    <refpurpose>Write audit and utmp updates at bootup, runlevel
-    changes and shutdown</refpurpose>
+    <refpurpose>Write audit and utmp updates at bootup and shutdown</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
     <para><filename>systemd-update-utmp.service</filename></para>
-    <para><filename>systemd-update-utmp-runlevel.service</filename></para>
     <para><filename>/usr/lib/systemd/systemd-update-utmp</filename></para>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-update-utmp-runlevel.service</filename> is
-    a service that writes SysV runlevel changes to utmp and wtmp, as
-    well as the audit logs, as they occur.
-    <filename>systemd-update-utmp.service</filename> does the same for
-    system reboots and shutdown requests.</para>
+    <para>
+      <filename>systemd-update-utmp.service</filename> is a service that writes system reboots and shutdown
+      requests to utmp and wtmp, as well as the audit logs.</para>
   </refsect1>
 
   <refsect1>
index 8a69e9692ba4d37917a54519b266fdf49b4ded8d..6d150e7dcf3efea09c4311a3e7ad91a8e8827fac 100644 (file)
 #include "time-util.h"
 #include "utmp-wtmp.h"
 
-int utmp_get_runlevel(int *runlevel, int *previous) {
-        _unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
-        struct utmpx *found, lookup = { .ut_type = RUN_LVL };
-        const char *e;
-
-        assert(runlevel);
-
-        /* If these values are set in the environment this takes
-         * precedence. Presumably, sysvinit does this to work around a
-         * race condition that would otherwise exist where we'd always
-         * go to disk and hence might read runlevel data that might be
-         * very new and not apply to the current script being executed. */
-
-        e = getenv("RUNLEVEL");
-        if (!isempty(e)) {
-                *runlevel = e[0];
-                if (previous)
-                        *previous = 0;
-
-                return 0;
-        }
-
-        if (utmpxname(UTMPX_FILE) < 0)
-                return -errno;
-
-        utmpx = utxent_start();
-
-        found = getutxid(&lookup);
-        if (!found)
-                return -errno;
-
-        *runlevel = found->ut_pid & 0xFF;
-        if (previous)
-                *previous = (found->ut_pid >> 8) & 0xFF;
-
-        return 0;
-}
-
 static void init_timestamp(struct utmpx *store, usec_t t) {
         assert(store);
 
@@ -237,33 +199,3 @@ int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
 
         return write_utmp_wtmp(&store, &store_wtmp);
 }
-
-int utmp_put_runlevel(int runlevel, int previous) {
-        struct utmpx store = {};
-        int r;
-
-        assert(runlevel > 0);
-
-        if (previous <= 0) {
-                /* Find the old runlevel automatically */
-
-                r = utmp_get_runlevel(&previous, NULL);
-                if (r < 0) {
-                        if (r != -ESRCH)
-                                return r;
-
-                        previous = 0;
-                }
-        }
-
-        if (previous == runlevel)
-                return 0;
-
-        init_entry(&store, 0);
-
-        store.ut_type = RUN_LVL;
-        store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8);
-        strncpy(store.ut_user, "runlevel", sizeof(store.ut_user));
-
-        return write_entry_both(&store);
-}
index f4b543e6c08cd4735aaa11f206f86b2c6fb467cd..72e8ff375b8d365fe1d4573ee1704d63033f6423 100644 (file)
@@ -6,11 +6,8 @@
 #if ENABLE_UTMP
 #include <utmpx.h>
 
-int utmp_get_runlevel(int *runlevel, int *previous);
-
 int utmp_put_shutdown(void);
 int utmp_put_reboot(usec_t timestamp);
-int utmp_put_runlevel(int runlevel, int previous);
 
 int utmp_put_dead_process(const char *id, pid_t pid, int code, int status);
 int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line, int ut_type, const char *user);
@@ -27,18 +24,12 @@ static inline void utxent_cleanup(bool *initialized) {
 
 #else /* ENABLE_UTMP */
 
-static inline int utmp_get_runlevel(int *runlevel, int *previous) {
-        return -ESRCH;
-}
 static inline int utmp_put_shutdown(void) {
         return 0;
 }
 static inline int utmp_put_reboot(usec_t timestamp) {
         return 0;
 }
-static inline int utmp_put_runlevel(int runlevel, int previous) {
-        return 0;
-}
 static inline int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) {
         return 0;
 }
index 78c693012e21d6021c2d1c08988c051130a18bf2..4f96f3a377b42a99a84cf129bff851d323b193c8 100644 (file)
@@ -57,81 +57,6 @@ static int get_startup_monotonic_time(Context *c, usec_t *ret) {
         return 0;
 }
 
-#define MAX_ATTEMPTS 64u
-
-static int get_current_runlevel(Context *c) {
-        static const struct {
-                const int runlevel;
-                const char *special;
-        } table[] = {
-                /* The first target of this list that is active or has a job scheduled wins. We prefer
-                 * runlevels 5 and 3 here over the others, since these are the main runlevels used on Fedora.
-                 * It might make sense to change the order on some distributions. */
-                { '5', SPECIAL_GRAPHICAL_TARGET  },
-                { '3', SPECIAL_MULTI_USER_TARGET },
-                { '1', SPECIAL_RESCUE_TARGET     },
-        };
-        int r;
-
-        assert(c);
-
-        for (unsigned n_attempts = 0;;) {
-                if (n_attempts++ > 0) {
-                        /* systemd might have dropped off momentarily, let's not make this an error,
-                        * and wait some random time. Let's pick a random time in the range 100ms…2000ms,
-                        * linearly scaled by the number of failed attempts. */
-                        c->bus = sd_bus_flush_close_unref(c->bus);
-
-                        usec_t usec =
-                                UINT64_C(100) * USEC_PER_MSEC +
-                                random_u64_range(UINT64_C(1900) * USEC_PER_MSEC * n_attempts / MAX_ATTEMPTS);
-                        (void) usleep_safe(usec);
-                }
-
-                if (!c->bus) {
-                        r = bus_connect_system_systemd(&c->bus);
-                        if (r == -ECONNREFUSED && n_attempts < 64) {
-                                log_debug_errno(r, "Failed to %s to system bus, retrying after a slight delay: %m",
-                                                n_attempts <= 1 ? "connect" : "reconnect");
-                                continue;
-                        }
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to reconnect to system bus: %m");
-                }
-
-                FOREACH_ELEMENT(e, table) {
-                        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                        _cleanup_free_ char *state = NULL, *path = NULL;
-
-                        path = unit_dbus_path_from_name(e->special);
-                        if (!path)
-                                return log_oom();
-
-                        r = sd_bus_get_property_string(
-                                        c->bus,
-                                        "org.freedesktop.systemd1",
-                                        path,
-                                        "org.freedesktop.systemd1.Unit",
-                                        "ActiveState",
-                                        &error,
-                                        &state);
-                        if ((r == -ENOTCONN || bus_error_is_connection(&error)) &&
-                            n_attempts < MAX_ATTEMPTS) {
-                                log_debug_errno(r, "Failed to get state of %s, retrying after a slight delay: %s",
-                                                e->special, bus_error_message(&error, r));
-                                break;
-                        }
-                        if (r < 0)
-                                return log_warning_errno(r, "Failed to get state of %s: %s", e->special, bus_error_message(&error, r));
-
-                        if (STR_IN_SET(state, "active", "reloading"))
-                                return e->runlevel;
-                }
-                if (r >= 0)
-                        return 0;
-        }
-}
-
 static int on_reboot(int argc, char *argv[], void *userdata) {
         Context *c = ASSERT_PTR(userdata);
         usec_t t = 0, boottime;
@@ -182,59 +107,10 @@ static int on_shutdown(int argc, char *argv[], void *userdata) {
         return q;
 }
 
-static int on_runlevel(int argc, char *argv[], void *userdata) {
-        Context *c = ASSERT_PTR(userdata);
-        int r, q = 0, previous, runlevel;
-
-        /* We finished changing runlevel, so let's write the utmp record and send the audit msg. */
-
-        /* First, get last runlevel */
-        r = utmp_get_runlevel(&previous, NULL);
-        if (r < 0) {
-                if (!IN_SET(r, -ESRCH, -ENOENT))
-                        return log_error_errno(r, "Failed to get the last runlevel from utmp: %m");
-
-                previous = 0;
-        }
-
-        /* Secondly, get new runlevel */
-        runlevel = get_current_runlevel(c);
-        if (runlevel < 0)
-                return runlevel;
-        if (runlevel == 0) {
-                log_warning("Failed to get the current runlevel, utmp update skipped.");
-                return 0;
-        }
-
-        if (previous == runlevel)
-                return 0;
-
-#if HAVE_AUDIT
-        if (c->audit_fd >= 0) {
-                char s[STRLEN("old-level=_ new-level=_") + 1];
-
-                xsprintf(s, "old-level=%c new-level=%c",
-                         previous > 0 ? previous : 'N',
-                         runlevel);
-
-                if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s,
-                                                "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM)
-                        q = log_error_errno(errno, "Failed to send audit message: %m");
-        }
-#endif
-
-        r = utmp_put_runlevel(runlevel, previous);
-        if (r < 0 && !IN_SET(r, -ESRCH, -ENOENT))
-                return log_error_errno(r, "Failed to write utmp record: %m");
-
-        return q;
-}
-
 static int run(int argc, char *argv[]) {
         static const Verb verbs[] = {
                 { "reboot",   1, 1, 0, on_reboot   },
                 { "shutdown", 1, 1, 0, on_shutdown },
-                { "runlevel", 1, 1, 0, on_runlevel },
                 {}
         };
 
index bb3ff2f1e9e5ce9919d26ee8e792a0cb836a557a..780f37ee128116028248e1c7be3d6f00aa018772 100755 (executable)
@@ -45,19 +45,4 @@ systemctl daemon-reload
 # of systemd-analyze blame. See issue #27187.
 systemd-analyze blame
 
-# Test for 'systemd-update-utmp runlevel' vs 'systemctl daemon-reexec'.
-# See issue #27163.
-# shellcheck disable=SC2034
-if [[ -x /usr/lib/systemd/systemd-update-utmp ]]; then
-    for _ in {0..10}; do
-        systemctl daemon-reexec &
-        pid_reexec=$!
-        # shellcheck disable=SC2034
-        for _ in {0..10}; do
-            SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-update-utmp runlevel
-        done
-        wait "$pid_reexec"
-    done
-fi
-
 touch /testok
index bc67a6ee8abbbaf662338efaf343b787dbb7b313..34b3222f1140f4fd2e71638132afb9c5d35e00bd 100644 (file)
@@ -818,11 +818,6 @@ units = [
           'file' : 'systemd-update-done.service.in',
           'symlinks' : ['sysinit.target.wants/'],
         },
-        {
-          'file' : 'systemd-update-utmp-runlevel.service.in',
-          'conditions' : ['ENABLE_UTMP', 'HAVE_SYSV_COMPAT'],
-          'symlinks' : ['multi-user.target.wants/', 'graphical.target.wants/', 'rescue.target.wants/'],
-        },
         {
           'file' : 'systemd-update-utmp.service.in',
           'conditions' : ['ENABLE_UTMP'],
diff --git a/units/systemd-update-utmp-runlevel.service.in b/units/systemd-update-utmp-runlevel.service.in
deleted file mode 100644 (file)
index 17772d4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#  SPDX-License-Identifier: LGPL-2.1-or-later
-#
-#  This file is part of systemd.
-#
-#  systemd is free software; you can redistribute it and/or modify it
-#  under the terms of the GNU Lesser General Public License as published by
-#  the Free Software Foundation; either version 2.1 of the License, or
-#  (at your option) any later version.
-
-[Unit]
-Description=Record Runlevel Change in UTMP
-Documentation=man:systemd-update-utmp-runlevel.service(8) man:utmp(5)
-ConditionPathExists=!/etc/initrd-release
-
-DefaultDependencies=no
-RequiresMountsFor=/var/log/wtmp
-Conflicts=shutdown.target
-Requisite=systemd-update-utmp.service
-After=systemd-update-utmp.service
-After=runlevel1.target runlevel2.target runlevel3.target runlevel4.target runlevel5.target
-Before=shutdown.target
-
-[Service]
-Type=oneshot
-ExecStart={{LIBEXECDIR}}/systemd-update-utmp runlevel