diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 7130a996a4..44fddbde7b 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -16,6 +16,7 @@ #include "alloc-util.h" #include "async.h" #include "binfmt-util.h" +#include "build.h" #include "cgroup-setup.h" #include "cgroup-util.h" #include "constants.h" @@ -49,6 +50,7 @@ #include "terminal-util.h" #include "time-util.h" #include "umount.h" +#include "verbs.h" #include "virt.h" #include "watchdog.h" @@ -60,6 +62,13 @@ static const char *arg_verb = NULL; static uint8_t arg_exit_code = 0; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; +COMMAND( + "systemd-shutdown\0", + "Execute the final phase of system shutdown.", + .argspec = "reboot|poweroff|halt|kexec|exit\0", + .man_pages = "systemd-shutdown.8\0", +); + static int parse_argv(int argc, char *argv[]) { assert(argc >= 1); assert(argv); @@ -75,6 +84,15 @@ static int parse_argv(int argc, char *argv[]) { FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { + OPTION_COMMON_HELP: + return command_print_help(); + + OPTION_COMMON_VERSION: + return version(); + + OPTION_COMMON_INTROSPECT_CLI: + return introspect_cli(SD_JSON_FORMAT_OFF); + OPTION_COMMON_LOG_LEVEL: r = log_set_max_level_from_string(opts.arg); if (r < 0) @@ -149,7 +167,7 @@ static int parse_argv(int argc, char *argv[]) { if (!arg_verb) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Verb argument missing."); - return 0; + return 1; /* Further action */ } static int switch_root_initramfs(void) { @@ -403,9 +421,17 @@ static int run(int argc, char *argv[]) { log_set_prohibit_ipc(true); log_parse_environment(); - if (getpid_cached() != 1) + r = parse_argv(argc, argv); + if (getpid_cached() != 1) { + /* If we're a normal user space process, our work is done. Either we hit an error, or were + * called with --help, --version, or another option that was handled by parse_argv(), or it + * looks like we're being asked to do some real work, but we should do that only as part of + * the real shutdown sequence. */ + if (r <= 0) + return r; return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not executed by init (PID 1). Refusing to operate."); + } log_set_always_reopen_console(true); @@ -414,8 +440,7 @@ static int run(int argc, char *argv[]) { * through kernel. */ (void) reboot(RB_ENABLE_CAD); - r = parse_argv(argc, argv); - if (r < 0) + if (r <= 0) goto error; log_open(); @@ -711,9 +736,14 @@ static int run(int argc, char *argv[]) { r = log_error_errno(errno, "Failed to invoke reboot(): %m"); error: - log_struct_errno(LOG_EMERG, r, - LOG_MESSAGE("Critical error while doing system shutdown: %m"), - LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR)); + if (r == 0) + log_struct(LOG_EMERG, + LOG_MESSAGE("Non-shutdown operation requested, cannot operate."), + LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR)); + else + log_struct_errno(LOG_EMERG, r, + LOG_MESSAGE("Critical error while doing system shutdown: %m"), + LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN_ERROR_STR)); freeze(); } diff --git a/test/units/TEST-74-AUX-UTILS.introspect-cli.sh b/test/units/TEST-74-AUX-UTILS.introspect-cli.sh index 78d329bfc5..cfdbe5c5ef 100755 --- a/test/units/TEST-74-AUX-UTILS.introspect-cli.sh +++ b/test/units/TEST-74-AUX-UTILS.introspect-cli.sh @@ -115,6 +115,7 @@ INTROSPECTABLE=( systemd-resolved systemd-run systemd-sbsign + systemd-shutdown systemd-sleep systemd-socket-activate systemd-socket-proxyd