mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-23 17:34:00 +03:00
systemctl: add support for booting into boot menu/entry
(This also removes support for booting into the EFI firmware setup without logind. That's because otherwise the non-EFI fallback logind implements can't work.) Fixes: #9896
This commit is contained in:
parent
31b221cf5e
commit
97af80c5a7
@ -617,11 +617,30 @@
|
||||
<term><option>--firmware-setup</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with the <command>reboot</command> command,
|
||||
indicate to the system's firmware to boot into setup
|
||||
mode. Note that this is currently only supported on some EFI
|
||||
systems and only if the system was booted in EFI
|
||||
mode.</para>
|
||||
<para>When used with the <command>reboot</command> command, indicate to the system's firmware to reboot into
|
||||
the firmware setup interface. Note that this functionality is not available on all systems.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--boot-loader-menu=</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with the <command>reboot</command> command, indicate to the system's boot loader to show the
|
||||
boot loader menu on the following boot. Takes a time value as parameter — indicating the menu time-out. Pass
|
||||
zero in order to disable the menu time-out. Note that not all boot loaders support this
|
||||
functionality.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--boot-loader-entry=</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with the <command>reboot</command> command, indicate to the system's boot loader to boot into
|
||||
a specific boot loader entry on the following boot. Takes a boot loader entry identifier as argument, or
|
||||
<literal>help</literal> in order to list available entries. Note that not all boot loaders support this
|
||||
functionality.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -170,6 +170,8 @@ static unsigned arg_lines = 10;
|
||||
static OutputMode arg_output = OUTPUT_SHORT;
|
||||
static bool arg_plain = false;
|
||||
static bool arg_firmware_setup = false;
|
||||
static usec_t arg_boot_loader_menu = USEC_INFINITY;
|
||||
static const char *arg_boot_loader_entry = NULL;
|
||||
static bool arg_now = false;
|
||||
static bool arg_jobs_before = false;
|
||||
static bool arg_jobs_after = false;
|
||||
@ -3473,7 +3475,11 @@ static int logind_check_inhibitors(enum action a) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static int logind_prepare_firmware_setup(void) {
|
||||
static int prepare_firmware_setup(void) {
|
||||
|
||||
if (!arg_firmware_setup)
|
||||
return 0;
|
||||
|
||||
#if ENABLE_LOGIND
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus;
|
||||
@ -3497,27 +3503,75 @@ static int logind_prepare_firmware_setup(void) {
|
||||
|
||||
return 0;
|
||||
#else
|
||||
log_error("Cannot remotely indicate to EFI to boot into setup mode.");
|
||||
log_error("Booting into firmware setup not supported.");
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int prepare_firmware_setup(void) {
|
||||
int r;
|
||||
static int prepare_boot_loader_menu(void) {
|
||||
|
||||
if (!arg_firmware_setup)
|
||||
if (arg_boot_loader_menu == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
if (arg_transport == BUS_TRANSPORT_LOCAL) {
|
||||
#if ENABLE_LOGIND
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
r = efi_set_reboot_to_firmware(true);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
|
||||
else
|
||||
return r;
|
||||
}
|
||||
r = acquire_bus(BUS_FULL, &bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return logind_prepare_firmware_setup();
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"SetRebootToBootLoaderMenu",
|
||||
&error,
|
||||
NULL,
|
||||
"t", arg_boot_loader_menu);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
#else
|
||||
log_error("Booting into boot loader menu not supported.");
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int prepare_boot_loader_entry(void) {
|
||||
|
||||
if (!arg_boot_loader_entry)
|
||||
return 0;
|
||||
|
||||
#if ENABLE_LOGIND
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus;
|
||||
int r;
|
||||
|
||||
r = acquire_bus(BUS_FULL, &bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"SetRebootToBootLoaderEntry",
|
||||
&error,
|
||||
NULL,
|
||||
"s", arg_boot_loader_entry);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
#else
|
||||
log_error("Booting into boot loader entry not supported.");
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int load_kexec_kernel(void) {
|
||||
@ -3644,6 +3698,14 @@ static int start_special(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prepare_boot_loader_menu();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = prepare_boot_loader_entry();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (a == ACTION_REBOOT && argc > 1) {
|
||||
r = update_reboot_parameter_and_warn(argv[1]);
|
||||
if (r < 0)
|
||||
@ -7522,6 +7584,10 @@ static int systemctl_help(void) {
|
||||
" short-monotonic, short-unix,\n"
|
||||
" verbose, export, json, json-pretty, json-sse, cat)\n"
|
||||
" --firmware-setup Tell the firmware to show the setup menu on next boot\n"
|
||||
" --boot-loader-menu=TIME\n"
|
||||
" Boot into boot loader menu on next boot\n"
|
||||
" --boot-loader-entry=NAME\n"
|
||||
" Boot into a specific boot loader entry on next boot\n"
|
||||
" --plain Print unit dependencies as a list instead of a tree\n\n"
|
||||
"Unit Commands:\n"
|
||||
" list-units [PATTERN...] List units currently in memory\n"
|
||||
@ -7776,6 +7842,39 @@ static void help_states(void) {
|
||||
DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX);
|
||||
}
|
||||
|
||||
static int help_boot_loader_entry(void) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_free_ char **l = NULL;
|
||||
sd_bus *bus;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
r = acquire_bus(BUS_FULL, &bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_get_property_strv(
|
||||
bus,
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"BootLoaderEntries",
|
||||
&error,
|
||||
&l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
|
||||
|
||||
if (strv_isempty(l)) {
|
||||
log_error("No boot loader entries discovered.");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
puts(*i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
enum {
|
||||
ARG_FAIL = 0x100,
|
||||
@ -7806,6 +7905,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
ARG_JOB_MODE,
|
||||
ARG_PRESET_MODE,
|
||||
ARG_FIRMWARE_SETUP,
|
||||
ARG_BOOT_LOADER_MENU,
|
||||
ARG_BOOT_LOADER_ENTRY,
|
||||
ARG_NOW,
|
||||
ARG_MESSAGE,
|
||||
ARG_WAIT,
|
||||
@ -7855,6 +7956,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
{ "recursive", no_argument, NULL, 'r' },
|
||||
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
|
||||
{ "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
|
||||
{ "boot-loader-menu", required_argument, NULL, ARG_BOOT_LOADER_MENU },
|
||||
{ "boot-loader-entry", required_argument, NULL, ARG_BOOT_LOADER_ENTRY },
|
||||
{ "now", no_argument, NULL, ARG_NOW },
|
||||
{ "message", required_argument, NULL, ARG_MESSAGE },
|
||||
{}
|
||||
@ -8128,6 +8231,27 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
|
||||
arg_firmware_setup = true;
|
||||
break;
|
||||
|
||||
case ARG_BOOT_LOADER_MENU:
|
||||
|
||||
r = parse_sec(optarg, &arg_boot_loader_menu);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --boot-loader-menu= argument '%s': %m", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case ARG_BOOT_LOADER_ENTRY:
|
||||
|
||||
if (streq(optarg, "help")) { /* Yes, this means, "help" is not a valid boot loader entry name we can deal with */
|
||||
r = help_boot_loader_entry();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arg_boot_loader_entry = empty_to_null(optarg);
|
||||
break;
|
||||
|
||||
case ARG_STATE: {
|
||||
if (isempty(optarg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
|
Loading…
Reference in New Issue
Block a user