#include "bootctl.h"
#include "bootctl-set-efivar.h"
#include "efivars.h"
+#include "efi-loader.h"
#include "stdio-util.h"
#include "utf8.h"
#include "virt.h"
char utf8[DECIMAL_STR_MAX(usec_t)];
char16_t *encoded;
usec_t timeout;
+ bool menu_disabled = false;
int r;
assert(arg1);
assert(ret_timeout);
assert(ret_timeout_size);
+ assert_cc(STRLEN("menu-disabled") < ELEMENTSOF(utf8));
+
/* Note: Since there is no way to query if the booloader supports the string tokens, we explicitly
* set their numerical value(s) instead. This means that some of the sd-boot internal ABI has leaked
* although the ship has sailed and the side-effects are self-contained.
timeout = USEC_INFINITY;
else if (streq(arg1, "menu-hidden"))
timeout = 0;
- else {
+ else if (streq(arg1, "menu-disabled")) {
+ uint64_t loader_features = 0;
+
+ (void) efi_loader_get_features(&loader_features);
+ if (!(loader_features & EFI_LOADER_FEATURE_MENU_DISABLE)) {
+ if (!arg_graceful)
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Loader does not support 'menu-disabled': %m");
+
+ log_warning("Loader does not support 'menu-disabled', setting anyway.");
+ }
+ menu_disabled = true;
+ } else {
r = parse_time(arg1, &timeout, USEC_PER_SEC);
if (r < 0)
return log_error_errno(r, "Failed to parse timeout '%s': %m", arg1);
log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
}
- xsprintf(utf8, USEC_FMT, MIN(timeout / USEC_PER_SEC, UINT32_MAX));
+ if (menu_disabled)
+ xsprintf(utf8, "menu-disabled");
+ else
+ xsprintf(utf8, USEC_FMT, MIN(timeout / USEC_PER_SEC, UINT32_MAX));
encoded = utf8_to_utf16(utf8, SIZE_MAX);
if (!encoded)
size_t n_entries;
size_t idx_default;
size_t idx_default_efivar;
- uint32_t timeout_sec; /* Actual timeout used (efi_main() override > efivar > config). */
- uint32_t timeout_sec_config;
- uint32_t timeout_sec_efivar;
+ uint64_t timeout_sec; /* Actual timeout used (efi_main() override > efivar > config). */
+ uint64_t timeout_sec_config;
+ uint64_t timeout_sec_efivar;
char16_t *entry_default_config;
char16_t *entry_default_efivar;
char16_t *entry_oneshot;
*
* The other values may be set by systemd-boot itself and changing those will lead to functional regression
* when new version of systemd-boot is installed.
+ *
+ * All the 64bit values are not ABI and will never be written to an efi variable.
*/
enum {
- TIMEOUT_MIN = 1,
- TIMEOUT_MAX = UINT32_MAX - 2U,
- TIMEOUT_UNSET = UINT32_MAX - 1U,
- TIMEOUT_MENU_FORCE = UINT32_MAX,
- TIMEOUT_MENU_HIDDEN = 0,
- TIMEOUT_TYPE_MAX = UINT32_MAX,
+ TIMEOUT_MIN = 1,
+ TIMEOUT_MAX = UINT32_MAX - 2U,
+ TIMEOUT_UNSET = UINT32_MAX - 1U,
+ TIMEOUT_MENU_FORCE = UINT32_MAX,
+ TIMEOUT_MENU_HIDDEN = 0,
+ TIMEOUT_TYPE_MAX = UINT32_MAX,
+ TIMEOUT_MENU_DISABLED = (uint64_t)UINT32_MAX + 1U,
+ TIMEOUT_TYPE_MAX64 = UINT64_MAX,
};
enum {
case TIMEOUT_UNSET:
config->timeout_sec = inc ? TIMEOUT_MENU_FORCE : TIMEOUT_UNSET;
break;
+ case TIMEOUT_MENU_DISABLED:
+ config->timeout_sec = inc ? TIMEOUT_MIN : TIMEOUT_MENU_FORCE;
+ break;
case TIMEOUT_MENU_FORCE:
config->timeout_sec = inc ? TIMEOUT_MENU_HIDDEN : TIMEOUT_MENU_FORCE;
break;
switch (config->timeout_sec) {
case TIMEOUT_UNSET:
return xstrdup16(u"Menu timeout defined by configuration file.");
+ case TIMEOUT_MENU_DISABLED:
+ assert_not_reached();
case TIMEOUT_MENU_FORCE:
return xstrdup16(u"Timeout disabled, menu will always be shown.");
case TIMEOUT_MENU_HIDDEN:
- return xstrdup16(u"Menu disabled. Hold down key at bootup to show menu.");
+ return xstrdup16(u"Menu hidden. Hold down key at bootup to show menu.");
default:
- return xasprintf("Menu timeout set to %u s.", config->timeout_sec_efivar);
+ return xasprintf("Menu timeout set to %u s.", (uint32_t)config->timeout_sec_efivar);
}
}
!IN_SET(key, KEYPRESS(0, SCAN_ESC, 0), KEYPRESS(0, 0, 'q'), KEYPRESS(0, 0, 'Q'));
}
-static void print_timeout_status(const char *label, uint32_t t) {
+static void print_timeout_status(const char *label, uint64_t t) {
switch (t) {
case TIMEOUT_UNSET:
return;
+ case TIMEOUT_MENU_DISABLED:
+ return (void) printf("%s: menu-disabled\n", label);
case TIMEOUT_MENU_FORCE:
return (void) printf("%s: menu-force\n", label);
case TIMEOUT_MENU_HIDDEN:
return (void) printf("%s: menu-hidden\n", label);
default:
- return (void) printf("%s: %u s\n", label, t);
+ return (void) printf("%s: %u s\n", label, (uint32_t)t);
}
}
size_t x_start = 0, y_start = 0, y_status = 0, x_max, y_max;
_cleanup_(strv_freep) char16_t **lines = NULL;
_cleanup_free_ char16_t *clearline = NULL, *separator = NULL, *status = NULL;
- uint32_t timeout_efivar_saved = config->timeout_sec_efivar;
+ uint64_t timeout_efivar_saved = config->timeout_sec_efivar;
uint32_t timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
int64_t console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
size_t default_efivar_saved = config->idx_default_efivar;
case TIMEOUT_UNSET:
efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", EFI_VARIABLE_NON_VOLATILE);
break;
+ case TIMEOUT_MENU_DISABLED:
+ assert_not_reached();
case TIMEOUT_MENU_FORCE:
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
break;
efivar_set(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
break;
default:
+ assert(config->timeout_sec_efivar < UINT32_MAX);
efivar_set_uint_string(MAKE_GUID_PTR(LOADER), u"LoaderConfigTimeout",
config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
}
while ((line = line_get_key_value(content, " \t", &pos, &key, &value)))
if (streq8(key, "timeout")) {
- if (streq8( value, "menu-force"))
+ if (streq8(value, "menu-disabled"))
+ config->timeout_sec_config = TIMEOUT_MENU_DISABLED;
+ else if (streq8(value, "menu-force"))
config->timeout_sec_config = TIMEOUT_MENU_FORCE;
else if (streq8(value, "menu-hidden"))
config->timeout_sec_config = TIMEOUT_MENU_HIDDEN;
TAKE_PTR(entry);
}
-static EFI_STATUS efivar_get_timeout(const char16_t *var, uint32_t *ret_value) {
+static EFI_STATUS efivar_get_timeout(const char16_t *var, uint64_t *ret_value) {
_cleanup_free_ char16_t *value = NULL;
EFI_STATUS err;
if (err != EFI_SUCCESS)
return err;
+ if (streq16(value, u"menu-disabled")) {
+ *ret_value = TIMEOUT_MENU_DISABLED;
+ return EFI_SUCCESS;
+ }
if (streq16(value, u"menu-force")) {
*ret_value = TIMEOUT_MENU_FORCE;
return EFI_SUCCESS;
EFI_LOADER_FEATURE_DEVICETREE |
EFI_LOADER_FEATURE_SECUREBOOT_ENROLL |
EFI_LOADER_FEATURE_RETAIN_SHIM |
+ EFI_LOADER_FEATURE_MENU_DISABLE |
0;
_cleanup_free_ char16_t *infostr = NULL, *typestr = NULL;
"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
/* select entry or show menu when key is pressed or timeout is set */
- if (config.force_menu || config.timeout_sec > 0)
+ if (config.force_menu || !IN_SET(config.timeout_sec, TIMEOUT_MENU_HIDDEN, TIMEOUT_MENU_DISABLED))
menu = true;
- else {
+ else if (config.timeout_sec != TIMEOUT_MENU_DISABLED) {
uint64_t key;
/* Block up to 100ms to give firmware time to get input working. */