utmp: drop setting runlevel entry in utmp

This removes systemd-update-utmp-runlevel.service and related command.
This commit is contained in:
Yu Watanabe
2025-07-13 05:49:00 +09:00
parent 8ba48d4bf8
commit dc1505555b
9 changed files with 6 additions and 260 deletions
-68
View File
@@ -11,44 +11,6 @@
#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);
}
-9
View 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;
}
-124
View 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 },
{}
};