diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml
index bf7a5fa3402..70410fc7267 100644
--- a/man/org.freedesktop.login1.xml
+++ b/man/org.freedesktop.login1.xml
@@ -555,10 +555,13 @@ node /org/freedesktop/login1 {
extendability, defined as follows:
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0)
+#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1)
When the flags is 0 then these methods behave just like the versions
without flags. When SD_LOGIND_ROOT_CHECK_INHIBITORS (0x01) is set, active
- inhibitors are honoured for privileged users too.
+ inhibitors are honoured for privileged users too. When SD_LOGIND_KEXEC_REBOOT
+ (0x02) is set, then RebootWithFlags() perform kexec reboot if kexec
+ kernel is loaded.
SetRebootParameter() sets a parameter for a subsequent reboot operation.
See the description of reboot in
diff --git a/src/basic/login-util.h b/src/basic/login-util.h
index dff87697a64..dc63fffdea3 100644
--- a/src/basic/login-util.h
+++ b/src/basic/login-util.h
@@ -5,12 +5,13 @@
#include
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0)
+#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1)
/* For internal use only */
#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63)
-#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS)
-#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE)
+#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_KEXEC_REBOOT)
+#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE)
bool session_id_valid(const char *id);
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a539a2e9797..532be12e7a3 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1880,6 +1880,8 @@ static int method_do_shutdown_or_sleep(
return r;
if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
+ if (!streq(unit_name, SPECIAL_REBOOT_TARGET) && (flags & SD_LOGIND_KEXEC_REBOOT))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
} else {
/* Old style method: no flags parameter, but interactive bool passed as boolean in
* payload. Let's convert this argument to the new-style flags parameter for our internal
@@ -1893,6 +1895,9 @@ static int method_do_shutdown_or_sleep(
flags = interactive ? SD_LOGIND_INTERACTIVE : 0;
}
+ if ((flags & SD_LOGIND_KEXEC_REBOOT) && kexec_loaded())
+ unit_name = SPECIAL_KEXEC_TARGET;
+
/* Don't allow multiple jobs being executed at the same time */
if (m->action_what > 0)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c
index 82cb3df6cdd..51a89ae4a73 100644
--- a/src/systemctl/systemctl-compat-halt.c
+++ b/src/systemctl/systemctl-compat-halt.c
@@ -161,7 +161,7 @@ int halt_main(void) {
/* Try logind if we are a normal user and no special mode applies. Maybe polkit allows us to
* shutdown the machine. */
- if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_KEXEC, ACTION_HALT)) {
r = logind_reboot(arg_action);
if (r >= 0)
return r;
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index 103f81647d2..15e396ebd7a 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -50,6 +50,7 @@ int logind_reboot(enum action a) {
} actions[_ACTION_MAX] = {
[ACTION_POWEROFF] = { "PowerOff", "power off system" },
[ACTION_REBOOT] = { "Reboot", "reboot system" },
+ [ACTION_KEXEC] = { "Reboot", "kexec reboot system" },
[ACTION_HALT] = { "Halt", "halt system" },
[ACTION_SUSPEND] = { "Suspend", "suspend system" },
[ACTION_HIBERNATE] = { "Hibernate", "hibernate system" },
@@ -79,6 +80,7 @@ int logind_reboot(enum action a) {
return 0;
SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
+ SET_FLAG(flags, SD_LOGIND_KEXEC_REBOOT, a == ACTION_KEXEC);
method_with_flags = strjoina(actions[a].method, "WithFlags");
diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c
index 15d2ea7941f..3edb65be617 100644
--- a/src/systemctl/systemctl-start-special.c
+++ b/src/systemctl/systemctl-start-special.c
@@ -201,6 +201,7 @@ int start_special(int argc, char *argv[], void *userdata) {
if (IN_SET(a,
ACTION_POWEROFF,
ACTION_REBOOT,
+ ACTION_KEXEC,
ACTION_HALT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
@@ -220,9 +221,9 @@ int start_special(int argc, char *argv[], void *userdata) {
arg_no_block = true;
- } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
- /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make
- * them asynchronous, in order to not confuse the user needlessly with unexpected
+ } else if (IN_SET(a, ACTION_EXIT))
+ /* Since exit is so close in behaviour to power-off/reboot, let's also make
+ * it asynchronous, in order to not confuse the user needlessly with unexpected
* behaviour. */
arg_no_block = true;