From 0d96caa5c052f59d5b0dbfa1df0730145fb5eb15 Mon Sep 17 00:00:00 2001 From: Deepak Rawat Date: Mon, 29 Mar 2021 20:22:16 -0700 Subject: [PATCH] logind: Add new flag for kexec reboot Add new flag to allow kexec reboot if kernel is already loaded. --- man/org.freedesktop.login1.xml | 5 ++++- src/basic/login-util.h | 5 +++-- src/login/logind-dbus.c | 5 +++++ src/systemctl/systemctl-compat-halt.c | 2 +- src/systemctl/systemctl-logind.c | 2 ++ src/systemctl/systemctl-start-special.c | 7 ++++--- 6 files changed, 19 insertions(+), 7 deletions(-) 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;