diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index d94a2a586ba..adc66788f85 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -411,7 +411,11 @@ static void boot_entry_file_list(const char *field, const char *root, const char *ret_status = status; } -static int boot_entry_show(const BootEntry *e, bool show_as_default) { +static int boot_entry_show( + const BootEntry *e, + bool show_as_default, + bool show_as_selected) { + int status = 0; /* Returns 0 on success, negative on processing error, and positive if something is wrong with the @@ -419,9 +423,10 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) { assert(e); - printf(" title: %s%s%s" "%s%s%s\n", + printf(" title: %s%s%s" "%s%s%s" "%s%s%s\n", ansi_highlight(), boot_entry_title(e), ansi_normal(), - ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal()); + ansi_highlight_green(), show_as_default ? " (default)" : "", ansi_normal(), + ansi_highlight_magenta(), show_as_selected ? " (selected)" : "", ansi_normal()); if (e->id) printf(" id: %s\n", e->id); @@ -519,7 +524,7 @@ static int status_entries( else { printf("Default Boot Loader Entry:\n"); - r = boot_entry_show(config.entries + config.default_entry, false); + r = boot_entry_show(config.entries + config.default_entry, /* show_as_default= */ false, /* show_as_selected= */ false); if (r > 0) /* < 0 is already logged by the function itself, let's just emit an extra warning if the default entry is broken */ @@ -1624,7 +1629,10 @@ static int verb_list(int argc, char *argv[], void *userdata) { printf("Boot Loader Entries:\n"); for (size_t n = 0; n < config.n_entries; n++) { - r = boot_entry_show(config.entries + n, n == (size_t) config.default_entry); + r = boot_entry_show( + config.entries + n, + n == (size_t) config.default_entry, + n == (size_t) config.selected_entry); if (r < 0) return r; diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 65a040f26dd..2d1d2b440b2 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -182,6 +182,7 @@ void boot_config_free(BootConfig *config) { free(config->entry_oneshot); free(config->entry_default); + free(config->entry_selected); for (i = 0; i < config->n_entries; i++) boot_entry_free(config->entries + i); @@ -669,6 +670,55 @@ static int boot_entries_select_default(const BootConfig *config) { return config->n_entries - 1; } +static int boot_entries_select_selected(const BootConfig *config) { + + assert(config); + assert(config->entries || config->n_entries == 0); + + if (!config->entry_selected || config->n_entries == 0) + return -1; + + for (int i = config->n_entries - 1; i >= 0; i--) + if (streq(config->entry_selected, config->entries[i].id)) + return i; + + return -1; +} + +static int boot_load_efi_entry_pointers(BootConfig *config) { + int r; + + assert(config); + + if (!is_efi_boot()) + return 0; + + /* Loads the three "pointers" to boot loader entries from their EFI variables */ + + r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &config->entry_oneshot); + if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) { + log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\": %m"); + if (r == -ENOMEM) + return r; + } + + r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryDefault), &config->entry_default); + if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) { + log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\": %m"); + if (r == -ENOMEM) + return r; + } + + r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected); + if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) { + log_warning_errno(r, "Failed to read EFI variable \"LoaderEntrySelected\": %m"); + if (r == -ENOMEM) + return r; + } + + return 1; +} + int boot_entries_load_config( const char *esp_path, const char *xbootldr_path, @@ -714,23 +764,13 @@ int boot_entries_load_config( if (r < 0) return log_error_errno(r, "Failed to uniquify boot entries: %m"); - if (is_efi_boot()) { - r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &config->entry_oneshot); - if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) { - log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\": %m"); - if (r == -ENOMEM) - return r; - } - - r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryDefault), &config->entry_default); - if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) { - log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\": %m"); - if (r == -ENOMEM) - return r; - } - } + r = boot_load_efi_entry_pointers(config); + if (r < 0) + return r; config->default_entry = boot_entries_select_default(config); + config->selected_entry = boot_entries_select_selected(config); + return 0; } diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index 62b3f6ce5f1..8649e93bcef 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -49,10 +49,12 @@ typedef struct BootConfig { char *entry_oneshot; char *entry_default; + char *entry_selected; BootEntry *entries; size_t n_entries; ssize_t default_entry; + ssize_t selected_entry; } BootConfig; static inline bool boot_config_has_entry(BootConfig *config, const char *id) {