From: Lennart Poettering Date: Fri, 1 Mar 2019 17:35:26 +0000 (+0100) Subject: bootspec: move augmentation of loader-discovered entries into bootspec.c X-Git-Tag: v242-rc1~192^2~10 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=93f14ce28d8477ad70ba6a60299b84af794e18b0;p=thirdparty%2Fsystemd.git bootspec: move augmentation of loader-discovered entries into bootspec.c Previously, bootctl would show boot loader entries discovered by the boot loader which couldn't found locally separately in the output. Let's move this code into bootspec.c, and beef it up a bit. This way we can use it later on for logind, and correctly show automatically discovered windows/macos entries too. --- diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 6c0885198ad..b5f4b8e5a3d 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -311,13 +311,15 @@ static int status_variables(void) { 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\n" + " type: %s\n", ansi_highlight(), boot_entry_title(e), ansi_normal(), ansi_highlight_green(), show_as_default ? " (default)" : "", - ansi_normal()); + ansi_normal(), + boot_entry_type_to_string(e->type)); if (e->id) printf(" id: %s\n", e->id); @@ -1173,7 +1175,6 @@ static int verb_status(int argc, char *argv[], void *userdata) { static int verb_list(int argc, char *argv[], void *userdata) { _cleanup_(boot_config_free) BootConfig config = {}; - _cleanup_free_ char **found_by_loader = NULL; int r; /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn @@ -1196,9 +1197,7 @@ static int verb_list(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = efi_loader_get_entries(&found_by_loader); - if (r < 0 && !IN_SET(r, -ENOENT, -EOPNOTSUPP)) - log_debug_errno(r, "Failed to acquire boot loader discovered entries: %m"); + (void) boot_entries_augment_from_loader(&config, false); if (config.n_entries == 0) log_info("No boot loader entries found."); @@ -1216,20 +1215,9 @@ static int verb_list(int argc, char *argv[], void *userdata) { if (n+1 < config.n_entries) putchar('\n'); - - strv_remove(found_by_loader, config.entries[n].id); } } - if (!strv_isempty(found_by_loader)) { - char **i; - - printf("\nAutomatic/Other Entries Found by Boot Loader:\n\n"); - - STRV_FOREACH(i, found_by_loader) - puts(*i); - } - return 0; } diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index d5bd0ff75e1..d0841e8ee5f 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -22,6 +22,7 @@ #include "path-util.h" #include "pe-header.h" #include "stat-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "unaligned.h" @@ -50,7 +51,10 @@ static int boot_entry_load( const char *path, BootEntry *entry) { - _cleanup_(boot_entry_free) BootEntry tmp = {}; + _cleanup_(boot_entry_free) BootEntry tmp = { + .type = BOOT_ENTRY_CONF, + }; + _cleanup_fclose_ FILE *f = NULL; unsigned line = 1; char *b, *c; @@ -272,7 +276,9 @@ static int boot_entry_load_unified( BootEntry *ret) { _cleanup_free_ char *os_pretty_name = NULL, *os_id = NULL, *version_id = NULL, *build_id = NULL; - _cleanup_(boot_entry_free) BootEntry tmp = {}; + _cleanup_(boot_entry_free) BootEntry tmp = { + .type = BOOT_ENTRY_UNIFIED, + }; _cleanup_fclose_ FILE *f = NULL; const char *k; int r; @@ -664,6 +670,70 @@ int boot_entries_load_config( return 0; } +int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) { + + static const char * const title_table[] = { + /* Pretty names for a few well-known automatically discovered entries. */ + "auto-osx", "macOS", + "auto-windows", "Windows Boot Manager", + "auto-efi-shell", "EFI Shell", + "auto-efi-default", "EFI Default Loader", + "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface", + }; + + _cleanup_free_ char **found_by_loader = NULL; + size_t n_allocated; + char **i; + int r; + + assert(config); + + /* Let's add the entries discovered by the boot loader to the end of our list, unless they are + * already included there. */ + + r = efi_loader_get_entries(&found_by_loader); + if (IN_SET(r, -ENOENT, -EOPNOTSUPP)) + return log_debug_errno(r, "Boot loader reported no entries."); + if (r < 0) + return log_error_errno(r, "Failed to determine entries reported by boot loader: %m"); + + n_allocated = config->n_entries; + + STRV_FOREACH(i, found_by_loader) { + _cleanup_free_ char *c = NULL, *t = NULL; + char **a, **b; + + if (boot_config_has_entry(config, *i)) + continue; + + if (only_auto && !startswith(*i, "auto-")) + continue; + + c = strdup(*i); + if (!c) + return log_oom(); + + STRV_FOREACH_PAIR(a, b, (char**) title_table) + if (streq(*a, *i)) { + t = strdup(*b); + if (!t) + return log_oom(); + break; + } + + if (!GREEDY_REALLOC0(config->entries, n_allocated, config->n_entries + 1)) + return log_oom(); + + config->entries[config->n_entries++] = (BootEntry) { + .type = BOOT_ENTRY_LOADER, + .id = TAKE_PTR(c), + .title = TAKE_PTR(t), + }; + } + + return 0; +} + /********************************************************************************/ static int verify_esp_blkid( @@ -1327,3 +1397,11 @@ int find_default_boot_entry( return 0; } + +static const char* const boot_entry_type_table[_BOOT_ENTRY_MAX] = { + [BOOT_ENTRY_CONF] = "conf", + [BOOT_ENTRY_UNIFIED] = "unified", + [BOOT_ENTRY_LOADER] = "loader", +}; + +DEFINE_STRING_TABLE_LOOKUP(boot_entry_type, BootEntryType); diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index 695e86d8f7b..658905a4cbb 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -8,7 +8,18 @@ #include "sd-id128.h" +#include "string-util.h" + +typedef enum BootEntryType { + BOOT_ENTRY_CONF, /* Type #1 entries: *.conf files */ + BOOT_ENTRY_UNIFIED, /* Type #2 entries: *.efi files */ + BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI var */ + _BOOT_ENTRY_MAX, + _BOOT_ENTRY_INVALID = -1, +} BootEntryType; + typedef struct BootEntry { + BootEntryType type; char *id; /* This is the file basename without extension */ char *path; /* This is the full path to the drop-in file */ char *root; /* The root path in which the drop-in was found, i.e. to which 'kernel', 'efi' and 'initrd' are relative */ @@ -40,8 +51,19 @@ typedef struct BootConfig { ssize_t default_entry; } BootConfig; +static inline bool boot_config_has_entry(BootConfig *config, const char *id) { + size_t j; + + for (j = 0; j < config->n_entries; j++) + if (streq(config->entries[j].id, id)) + return true; + + return false; +} + void boot_config_free(BootConfig *config); int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config); +int boot_entries_augment_from_loader(BootConfig *config, bool only_auto); static inline const char* boot_entry_title(const BootEntry *entry) { return entry->show_title ?: entry->title ?: entry->id; @@ -51,3 +73,6 @@ int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid); int find_default_boot_entry(BootConfig *config, const BootEntry **e); + +const char* boot_entry_type_to_string(BootEntryType t) _const_; +BootEntryType boot_entry_type_from_string(const char *s) _pure_;