summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemctl.xml12
-rw-r--r--src/core/shutdown.c15
-rw-r--r--src/shared/def.h2
-rw-r--r--src/systemctl/systemctl.c30
4 files changed, 48 insertions, 11 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml
index c7313edcc..7f1e98f5c 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 aa9548e2a..377c1971a 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, &param);
+ } 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 edd0bcf7a..46b88a8a4 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 9d22aad28..6170cc93d 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, &param) == 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: