diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7a20965b6a..427faf8b24 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -968,14 +968,28 @@ static int verb_status(int argc, char *argv[], void *userdata) { (void) pager_open(arg_pager_flags); if (is_efi_boot()) { + static const struct { + uint64_t flag; + const char *name; + } flags[] = { + { EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" }, + { EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" }, + { EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" }, + { EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" }, + { EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" }, + }; + _cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL; sd_id128_t loader_part_uuid = SD_ID128_NULL; + uint64_t loader_features = 0; + size_t i; read_loader_efi_var("LoaderFirmwareType", &fw_type); read_loader_efi_var("LoaderFirmwareInfo", &fw_info); read_loader_efi_var("LoaderInfo", &loader); read_loader_efi_var("StubInfo", &stub); read_loader_efi_var("LoaderImageIdentifier", &loader_path); + (void) efi_loader_get_features(&loader_features); if (loader_path) efi_tilt_backslashes(loader_path); @@ -992,6 +1006,20 @@ static int verb_status(int argc, char *argv[], void *userdata) { printf("Current Boot Loader:\n"); printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal()); + + for (i = 0; i < ELEMENTSOF(flags); i++) { + + if (i == 0) + printf(" Features: "); + else + printf(" "); + + if (FLAGS_SET(loader_features, flags[i].flag)) + printf("%s%s%s %s\n", ansi_highlight_green(), special_glyph(CHECK_MARK), ansi_normal(), flags[i].name); + else + printf("%s%s%s %s\n", ansi_highlight_red(), special_glyph(CROSS_MARK), ansi_normal(), flags[i].name); + } + if (stub) printf(" Stub: %s\n", stub); if (!sd_id128_is_null(loader_part_uuid)) diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 7a9754096c..e536f0d94e 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -822,3 +822,53 @@ char *efi_tilt_backslashes(char *s) { return s; } + +int efi_loader_get_features(uint64_t *ret) { + _cleanup_free_ void *v = NULL; + size_t s; + int r; + + if (!is_efi_boot()) { + *ret = 0; + return 0; + } + + r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderFeatures", NULL, &v, &s); + if (r == -ENOENT) { + _cleanup_free_ char *info = NULL; + + /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */ + r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info); + if (r < 0) { + if (r != -ENOENT) + return r; + + /* Variable not set, definitely means not systemd-boot */ + + } else if (first_word(info, "systemd-boot")) { + + /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty + * static in all its versions. */ + + *ret = EFI_LOADER_FEATURE_CONFIG_TIMEOUT | + EFI_LOADER_FEATURE_ENTRY_DEFAULT | + EFI_LOADER_FEATURE_ENTRY_ONESHOT; + + return 0; + } + + /* No features supported */ + *ret = 0; + return 0; + } + if (r < 0) + return r; + + if (s != sizeof(uint64_t)) { + log_debug("LoaderFeatures EFI variable doesn't have the right size."); + return -EINVAL; + } + + memcpy(ret, v, sizeof(uint64_t)); + return 0; +} diff --git a/src/shared/efivars.h b/src/shared/efivars.h index 9b5ab39fee..feedbf91a6 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -18,6 +18,12 @@ #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 +#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT (UINT64_C(1) << 0) +#define EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT (UINT64_C(1) << 1) +#define EFI_LOADER_FEATURE_ENTRY_DEFAULT (UINT64_C(1) << 2) +#define EFI_LOADER_FEATURE_ENTRY_ONESHOT (UINT64_C(1) << 3) +#define EFI_LOADER_FEATURE_BOOT_COUNTING (UINT64_C(1) << 4) + #if ENABLE_EFI bool is_efi_boot(void); @@ -43,6 +49,8 @@ int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader); int efi_loader_get_entries(char ***ret); +int efi_loader_get_features(uint64_t *ret); + #else static inline bool is_efi_boot(void) { @@ -117,6 +125,10 @@ static inline int efi_loader_get_entries(char ***ret) { return -EOPNOTSUPP; } +static inline int efi_loader_get_features(uint64_t *ret) { + return -EOPNOTSUPP; +} + #endif char *efi_tilt_backslashes(char *s);