logind: Add new flag for kexec reboot

Add new flag to allow kexec reboot if kernel is already loaded.
This commit is contained in:
Deepak Rawat 2021-03-29 20:22:16 -07:00 committed by Zbigniew Jędrzejewski-Szmek
parent a93af34a40
commit 0d96caa5c0
6 changed files with 19 additions and 7 deletions

View file

@ -555,10 +555,13 @@ node /org/freedesktop/login1 {
extendability, defined as follows:</para>
<programlisting>
#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) &lt;&lt; 0)
#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) &lt;&lt; 1)
</programlisting>
<para> When the <varname>flags</varname> is 0 then these methods behave just like the versions
without flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active
inhibitors are honoured for privileged users too.</para>
inhibitors are honoured for privileged users too. When <constant>SD_LOGIND_KEXEC_REBOOT</constant>
(0x02) is set, then <function>RebootWithFlags()</function> perform kexec reboot if kexec
kernel is loaded.</para>
<para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation.
See the description of <command>reboot</command> in

View file

@ -5,12 +5,13 @@
#include <unistd.h>
#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);

View file

@ -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,

View file

@ -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;

View file

@ -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");

View file

@ -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;