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;
#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;
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) {
+static int prepare_boot_loader_menu(void) {
+
+ if (arg_boot_loader_menu == USEC_INFINITY)
+ return 0;
+
+#if ENABLE_LOGIND
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
int r;
- if (!arg_firmware_setup)
+ 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",
+ "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 (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;
+
+ 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 logind_prepare_firmware_setup();
+ return 0;
+#else
+ log_error("Booting into boot loader entry not supported.");
+ return -ENOSYS;
+#endif
}
static int load_kexec_kernel(void) {
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)
" 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"
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,
ARG_JOB_MODE,
ARG_PRESET_MODE,
ARG_FIRMWARE_SETUP,
+ ARG_BOOT_LOADER_MENU,
+ ARG_BOOT_LOADER_ENTRY,
ARG_NOW,
ARG_MESSAGE,
ARG_WAIT,
{ "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 },
{}
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),