diff options
-rw-r--r-- | man/systemctl.xml | 12 | ||||
-rw-r--r-- | src/core/shutdown.c | 15 | ||||
-rw-r--r-- | src/shared/def.h | 2 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 30 |
4 files changed, 48 insertions, 11 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml index c7313edcc2..7f1e98f5c5 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1179,7 +1179,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service </listitem> </varlistentry> <varlistentry> - <term><command>reboot</command></term> + <term><command>reboot <optional><replaceable>arg</replaceable></optional></command></term> <listitem> <para>Shut down and reboot the system. This is mostly @@ -1192,6 +1192,16 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service specified twice, the operation is immediately executed without terminating any processes or unmounting any file systems. This may result in data loss.</para> + + <para>If the optional argument + <replaceable>arg</replaceable> is given, it will be passed + as the optional argument to the + <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> + system call. The value is architecture and firmware + specific. As an example, <literal>recovery</literal> might + be used to trigger system recovery, and + <literal>fota</literal> might be used to trigger a + <quote>firmware over the air</quote> update.</para> </listitem> </varlistentry> <varlistentry> diff --git a/src/core/shutdown.c b/src/core/shutdown.c index aa9548e2a4..377c1971a3 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -47,6 +47,7 @@ #include "watchdog.h" #include "killall.h" #include "cgroup-util.h" +#include "def.h" #define FINALIZE_ATTEMPTS 50 @@ -134,7 +135,7 @@ static int pivot_to_new_root(void) { int main(int argc, char *argv[]) { bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; bool in_container, use_watchdog = false; - _cleanup_free_ char *line = NULL, *cgroup = NULL; + _cleanup_free_ char *line = NULL, *cgroup = NULL, *param = NULL; char *arguments[3]; unsigned retries; int cmd, r; @@ -173,9 +174,11 @@ int main(int argc, char *argv[]) { in_container = detect_container(NULL) > 0; - if (streq(argv[1], "reboot")) + if (streq(argv[1], "reboot")) { cmd = RB_AUTOBOOT; - else if (streq(argv[1], "poweroff")) + /* if this fails, that's OK */ + read_one_line_file(REBOOT_PARAM_FILE, ¶m); + } else if (streq(argv[1], "poweroff")) cmd = RB_POWER_OFF; else if (streq(argv[1], "halt")) cmd = RB_HALT_SYSTEM; @@ -337,7 +340,11 @@ int main(int argc, char *argv[]) { cmd = RB_AUTOBOOT; } - reboot(cmd); + if (param) + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, param); + else + reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked diff --git a/src/shared/def.h b/src/shared/def.h index edd0bcf7a4..46b88a8a49 100644 --- a/src/shared/def.h +++ b/src/shared/def.h @@ -38,3 +38,5 @@ #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS + +#define REBOOT_PARAM_FILE "/run/systemd/reboot-param" diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 9d22aad287..6170cc93d5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -20,6 +20,8 @@ ***/ #include <sys/reboot.h> +#include <linux/reboot.h> +#include <sys/syscall.h> #include <stdio.h> #include <getopt.h> #include <locale.h> @@ -4804,7 +4806,7 @@ static int systemctl_help(void) { " emergency Enter system emergency mode\n" " halt Shut down and halt the system\n" " poweroff Shut down and power-off the system\n" - " reboot Shut down and reboot the system\n" + " reboot [ARG] Shut down and reboot the system\n" " kexec Shut down and reboot the system with kexec\n" " exit Request user instance exit\n" " switch-root [ROOT] [INIT] Change to a different root file system\n" @@ -4818,7 +4820,7 @@ static int systemctl_help(void) { static int halt_help(void) { - printf("%s [OPTIONS...]\n\n" + printf("%s [OPTIONS...]%s\n\n" "%s the system.\n\n" " --help Show this help\n" " --halt Halt the machine\n" @@ -4829,6 +4831,7 @@ static int halt_help(void) { " -d --no-wtmp Don't write wtmp record\n" " --no-wall Don't send wall message before halt/power-off/reboot\n", program_invocation_short_name, + arg_action == ACTION_REBOOT ? " [ARG]" : "", arg_action == ACTION_REBOOT ? "Reboot" : arg_action == ACTION_POWEROFF ? "Power off" : "Halt"); @@ -5253,7 +5256,7 @@ static int halt_parse_argv(int argc, char *argv[]) { {} }; - int c, runlevel; + int c, r, runlevel; assert(argc >= 0); assert(argv); @@ -5311,7 +5314,14 @@ static int halt_parse_argv(int argc, char *argv[]) { } } - if (optind < argc) { + if (arg_action == ACTION_REBOOT && argc == optind + 1) { + r = write_string_file(REBOOT_PARAM_FILE, argv[optind]); + if (r < 0) { + log_error("Failed to write reboot param to " + REBOOT_PARAM_FILE": %s", strerror(-r)); + return r; + } + } else if (optind < argc) { log_error("Too many arguments."); return -EINVAL; } @@ -5944,6 +5954,8 @@ done: static _noreturn_ void halt_now(enum action a) { + _cleanup_free_ char *param = NULL; + /* Make sure C-A-D is handled by the kernel from this * point on... */ reboot(RB_ENABLE_CAD); @@ -5961,8 +5973,14 @@ static _noreturn_ void halt_now(enum action a) { break; case ACTION_REBOOT: - log_info("Rebooting."); - reboot(RB_AUTOBOOT); + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) == 0) { + log_info("Rebooting with arg '%s'.", param); + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, param); + } else { + log_info("Rebooting."); + reboot(RB_AUTOBOOT); + } break; default: |