diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:49:52 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:49:52 +0000 |
commit | 55944e5e40b1be2afc4855d8d2baf4b73d1876b5 (patch) | |
tree | 33f869f55a1b149e9b7c2b7e201867ca5dd52992 /src/sulogin-shell/sulogin-shell.c | |
parent | Initial commit. (diff) | |
download | systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.tar.xz systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.zip |
Adding upstream version 255.4.upstream/255.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/sulogin-shell/sulogin-shell.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c new file mode 100644 index 0000000..b26663d --- /dev/null +++ b/src/sulogin-shell/sulogin-shell.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/*** + Copyright © 2017 Felipe Sateler +***/ + +#include <errno.h> +#include <sys/prctl.h> + +#include "sd-bus.h" + +#include "bus-error.h" +#include "bus-locator.h" +#include "bus-unit-util.h" +#include "bus-util.h" +#include "constants.h" +#include "env-util.h" +#include "initrd-util.h" +#include "log.h" +#include "main-func.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "signal-util.h" +#include "special.h" +#include "unit-def.h" + +static int target_is_inactive(sd_bus *bus, const char *target) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL, *state = NULL; + int r; + + path = unit_dbus_path_from_name(target); + if (!path) + return log_oom(); + + r = sd_bus_get_property_string(bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &state); + if (r < 0) + return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r)); + + return streq_ptr(state, "inactive"); +} + +static int start_target(sd_bus *bus, const char *target) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + log_info("Starting %s", target); + + /* Start this unit only if we can replace basic.target with it */ + r = bus_call_method( + bus, + bus_systemd_mgr, + "StartUnit", + &error, + NULL, + "ss", target, "isolate"); + + if (r < 0) + return log_error_errno(r, "Failed to start %s: %s", target, bus_error_message(&error, r)); + + return 0; +} + +static int fork_wait(const char* const cmdline[]) { + pid_t pid; + int r; + + r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); + if (r < 0) + return r; + if (r == 0) { + /* Child */ + execv(cmdline[0], (char**) cmdline); + log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]); + _exit(EXIT_FAILURE); /* Operational error */ + } + + return wait_for_terminate_and_check(cmdline[0], pid, WAIT_LOG_ABNORMAL); +} + +static void print_mode(const char* mode) { + printf("You are in %s mode. After logging in, type \"journalctl -xb\" to view\n" + "system logs, \"systemctl reboot\" to reboot, or \"exit\"\n" "to continue bootup.\n", mode); + fflush(stdout); +} + +static int run(int argc, char *argv[]) { + const char* sulogin_cmdline[] = { + SULOGIN, + NULL, /* --force */ + NULL + }; + bool force = false; + int r; + + log_setup(); + + print_mode(argc > 1 ? argv[1] : ""); + + if (getenv_bool("SYSTEMD_SULOGIN_FORCE") > 0) + force = true; + + if (!force) { + /* We look the argument in the kernel cmdline under the same name as the environment variable + * to express that this is not supported at the same level as the regular kernel cmdline + * switches. */ + r = proc_cmdline_get_bool("SYSTEMD_SULOGIN_FORCE", /* flags = */ 0, &force); + if (r < 0) + log_debug_errno(r, "Failed to parse SYSTEMD_SULOGIN_FORCE from kernel command line, ignoring: %m"); + } + + if (force) + /* allows passwordless logins if root account is locked. */ + sulogin_cmdline[1] = "--force"; + + for (;;) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + + (void) fork_wait(sulogin_cmdline); + + r = bus_connect_system_systemd(&bus); + if (r < 0) { + log_warning_errno(r, "Failed to get D-Bus connection: %m"); + goto fallback; + } + + log_info("Reloading system manager configuration."); + r = bus_service_manager_reload(bus); + if (r < 0) + goto fallback; + + const char *target = in_initrd() ? SPECIAL_INITRD_TARGET : SPECIAL_DEFAULT_TARGET; + + r = target_is_inactive(bus, target); + if (r < 0) + goto fallback; + if (!r) { + log_warning("%s is not inactive. Please review the %s setting.", target, target); + goto fallback; + } + + if (start_target(bus, target) >= 0) + break; + + fallback: + log_warning("Fallback to the single-user shell."); + } + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); |