From 498d0cc426afc13fdadb0a385fd16c005645e0cf Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 6 Oct 2023 16:19:21 +0100 Subject: [PATCH 1/4] sd-boot: cast away reboot_into_firmware() return type As mentioned by Lennart, in a commit where I was adding similar piece of code: maybe cast this call to void, to tell static analyzers that we are ignoring the return value on purpose, not by accident Signed-off-by: Emil Velikov --- src/boot/efi/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 7b13cd21db4..e3f3a13ed73 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -825,7 +825,7 @@ static bool menu_run( if (firmware_setup) { firmware_setup = false; if (IN_SET(key, KEYPRESS(0, 0, '\r'), KEYPRESS(0, 0, '\n'))) - reboot_into_firmware(); + (void) reboot_into_firmware(); continue; } From a9bc49b4a8d1c6622de3e40876a04044bffc531c Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 6 Oct 2023 16:12:43 +0100 Subject: [PATCH 2/4] sd-boot: remove unneeded false assignment When the assignment is missing, the default 0/NULL/false value is used. So drop the explicit piece in config_load_defaults() Signed-off-by: Emil Velikov --- src/boot/efi/boot.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index e3f3a13ed73..c5806d83d97 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1596,7 +1596,6 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) { .editor = true, .auto_entries = true, .auto_firmware = true, - .reboot_for_bitlocker = false, .secure_boot_enroll = ENROLL_IF_SAFE, .idx_default_efivar = IDX_INVALID, .console_mode = CONSOLE_MODE_KEEP, From 28052aa8cd5ebebebeeccda88c045b5806cbc209 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 6 Oct 2023 16:16:23 +0100 Subject: [PATCH 3/4] sd-boot: sprinkle some ", ignoring" trailing messages As mentioned by Lennart: ... we typically suffix such messages with ", ignoring", to indicate that we don't consider this fatal for anything. Update config_defaults_load_from_file() to follow that pattern. Signed-off-by: Emil Velikov --- src/boot/efi/boot.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index c5806d83d97..0f61c302a38 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1217,7 +1217,8 @@ static void config_defaults_load_from_file(Config *config, char *content) { else { uint64_t u; if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX) { - log_error("Error parsing 'timeout' config option: %s", value); + log_error("Error parsing 'timeout' config option, ignoring: %s", + value); continue; } config->timeout_sec_config = u; @@ -1228,7 +1229,7 @@ static void config_defaults_load_from_file(Config *config, char *content) { if (streq8(key, "default")) { if (value[0] == '@' && !strcaseeq8(value, "@saved")) { - log_error("Unsupported special entry identifier: %s", value); + log_error("Unsupported special entry identifier, ignoring: %s", value); continue; } free(config->entry_default_config); @@ -1239,35 +1240,36 @@ static void config_defaults_load_from_file(Config *config, char *content) { if (streq8(key, "editor")) { err = parse_boolean(value, &config->editor); if (err != EFI_SUCCESS) - log_error("Error parsing 'editor' config option: %s", value); + log_error("Error parsing 'editor' config option, ignoring: %s", value); continue; } if (streq8(key, "auto-entries")) { err = parse_boolean(value, &config->auto_entries); if (err != EFI_SUCCESS) - log_error("Error parsing 'auto-entries' config option: %s", value); + log_error("Error parsing 'auto-entries' config option, ignoring: %s", value); continue; } if (streq8(key, "auto-firmware")) { err = parse_boolean(value, &config->auto_firmware); if (err != EFI_SUCCESS) - log_error("Error parsing 'auto-firmware' config option: %s", value); + log_error("Error parsing 'auto-firmware' config option, ignoring: %s", value); continue; } if (streq8(key, "beep")) { err = parse_boolean(value, &config->beep); if (err != EFI_SUCCESS) - log_error("Error parsing 'beep' config option: %s", value); + log_error("Error parsing 'beep' config option, ignoring: %s", value); continue; } if (streq8(key, "reboot-for-bitlocker")) { err = parse_boolean(value, &config->reboot_for_bitlocker); if (err != EFI_SUCCESS) - log_error("Error parsing 'reboot-for-bitlocker' config option: %s", value); + log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s", + value); } if (streq8(key, "secure-boot-enroll")) { @@ -1280,7 +1282,8 @@ static void config_defaults_load_from_file(Config *config, char *content) { else if (streq8(value, "off")) config->secure_boot_enroll = ENROLL_OFF; else - log_error("Error parsing 'secure-boot-enroll' config option: %s", value); + log_error("Error parsing 'secure-boot-enroll' config option, ignoring: %s", + value); continue; } @@ -1294,7 +1297,8 @@ static void config_defaults_load_from_file(Config *config, char *content) { else { uint64_t u; if (!parse_number8(value, &u, NULL) || u > CONSOLE_MODE_RANGE_MAX) { - log_error("Error parsing 'console-mode' config option: %s", value); + log_error("Error parsing 'console-mode' config option, ignoring: %s", + value); continue; } config->console_mode = u; From cb341090d061084accc9a45ec4b1d258954adba2 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Wed, 4 Oct 2023 11:51:47 +0100 Subject: [PATCH 4/4] sd-boot: add auto-reboot and auto-poweroff entries Currently only an auto-reboot-to-firmware entry is available. For other features - like reboot and power off - one needs to press the uppercase B and O respectively. Embedded devices may be missing a full fledged keyboard, so allow for sd-boot to generate those entries. v2: - add to the config parser/man/bootctl/sd-boot info screen - keep them off by default - add the (O)ff and re(B)oot help text if boot entries are not shown - drop irrelevant get_os_indications_supported() comment - s/ShutDown/Shutdown/ v3: - cast shutdown_system() reboot_system() to void v4: - shutdown -> poweroff - add trailing ",ignoring" in parser message - drop explicit default state assignment to "false" Signed-off-by: Emil Velikov --- man/loader.conf.xml | 8 ++++++ src/boot/efi/boot.c | 60 ++++++++++++++++++++++++++++++++++++++++--- src/shared/bootspec.c | 2 ++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/man/loader.conf.xml b/man/loader.conf.xml index c7794cd195f..748276c9cfd 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -100,6 +100,14 @@ auto-osx macOS + + auto-poweroff + Power Off The System + + + auto-reboot + Reboot The System + auto-reboot-to-firmware-setup Reboot Into Firmware Interface diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 0f61c302a38..de801ceb37d 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -86,6 +86,8 @@ typedef struct { bool editor; bool auto_entries; bool auto_firmware; + bool auto_poweroff; + bool auto_reboot; bool reboot_for_bitlocker; secure_boot_enroll secure_boot_enroll; bool force_menu; @@ -512,6 +514,8 @@ static void print_status(Config *config, char16_t *loaded_image_path) { printf(" editor: %ls\n", yes_no(config->editor)); printf(" auto-entries: %ls\n", yes_no(config->auto_entries)); printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware)); + printf(" auto-poweroff: %ls\n", yes_no(config->auto_poweroff)); + printf(" auto-reboot: %ls\n", yes_no(config->auto_reboot)); printf(" beep: %ls\n", yes_no(config->beep)); printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker)); @@ -618,6 +622,16 @@ static EFI_STATUS reboot_into_firmware(void) { assert_not_reached(); } +static EFI_STATUS poweroff_system(void) { + RT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + assert_not_reached(); +} + +static EFI_STATUS reboot_system(void) { + RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + assert_not_reached(); +} + static bool menu_run( Config *config, ConfigEntry **chosen_entry, @@ -886,7 +900,9 @@ static bool menu_run( case KEYPRESS(0, 0, 'H'): case KEYPRESS(0, 0, '?'): /* This must stay below 80 characters! Q/v/Ctrl+l/f deliberately not advertised. */ - status = xstrdup16(u"(d)efault (t/T)imeout (e)dit (r/R)esolution (p)rint (O)ff re(B)oot (h)elp"); + status = xasprintf("(d)efault (t/T)imeout (e)dit (r/R)esolution (p)rint %s%s(h)elp", + config->auto_poweroff ? "" : "(O)ff ", + config->auto_reboot ? "" : "re(B)oot "); break; case KEYPRESS(0, 0, 'Q'): @@ -1019,11 +1035,11 @@ static bool menu_run( break; case KEYPRESS(0, 0, 'O'): /* Only uppercase, so that it can't be hit so easily fat-fingered, but still works safely over serial */ - RT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + (void) poweroff_system(); break; case KEYPRESS(0, 0, 'B'): /* ditto */ - RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + (void) reboot_system(); break; default: @@ -1258,6 +1274,20 @@ static void config_defaults_load_from_file(Config *config, char *content) { continue; } + if (streq8(key, "auto-poweroff")) { + err = parse_boolean(value, &config->auto_poweroff); + if (err != EFI_SUCCESS) + log_error("Error parsing 'auto-poweroff' config option, ignoring: %s", value); + continue; + } + + if (streq8(key, "auto-reboot")) { + err = parse_boolean(value, &config->auto_reboot); + if (err != EFI_SUCCESS) + log_error("Error parsing 'auto-reboot' config option, ignoring: %s", value); + continue; + } + if (streq8(key, "beep")) { err = parse_boolean(value, &config->beep); if (err != EFI_SUCCESS) @@ -2648,6 +2678,30 @@ static void config_load_all_entries( config_add_entry(config, entry); } + if (config->auto_poweroff) { + ConfigEntry *entry = xnew(ConfigEntry, 1); + *entry = (ConfigEntry) { + .id = xstrdup16(u"auto-poweroff"), + .title = xstrdup16(u"Power Off The System"), + .call = poweroff_system, + .tries_done = -1, + .tries_left = -1, + }; + config_add_entry(config, entry); + } + + if (config->auto_reboot) { + ConfigEntry *entry = xnew(ConfigEntry, 1); + *entry = (ConfigEntry) { + .id = xstrdup16(u"auto-reboot"), + .title = xstrdup16(u"Reboot The System"), + .call = reboot_system, + .tries_done = -1, + .tries_left = -1, + }; + config_add_entry(config, entry); + } + /* find if secure boot signing keys exist and autoload them if necessary otherwise creates menu entries so that the user can load them manually if the secure-boot-enroll variable is set to no (the default), we do not diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 42d5fec754c..f347ccdd8a8 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -1145,6 +1145,8 @@ int boot_config_augment_from_loader( "auto-windows", "Windows Boot Manager", "auto-efi-shell", "EFI Shell", "auto-efi-default", "EFI Default Loader", + "auto-poweroff", "Power Off The System", + "auto-reboot", "Reboot The System", "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface", NULL, };