From: Lennart Poettering Date: Tue, 26 May 2020 20:24:02 +0000 (+0200) Subject: efi: cache LoaderEntries EFI variable X-Git-Tag: v246-rc1~235^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d4bd786d69c6e9ee65cd4a7c5a9b2b4829546e10;p=thirdparty%2Fsystemd.git efi: cache LoaderEntries EFI variable Based-on: https://github.com/systemd/systemd/issues/14828#issuecomment-634202054 --- diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index a197668ce96..ab145d65f5b 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1311,6 +1311,7 @@ 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_strv_free_ char **efi_entries = NULL; int r; /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn @@ -1333,7 +1334,13 @@ static int verb_list(int argc, char *argv[], void *userdata) { if (r < 0) return r; - (void) boot_entries_augment_from_loader(&config, false); + r = efi_loader_get_entries(&efi_entries); + if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) + log_debug_errno(r, "Boot loader reported no entries."); + else if (r < 0) + log_warning_errno(r, "Failed to determine entries reported by boot loader, ignoring: %m"); + else + (void) boot_entries_augment_from_loader(&config, efi_entries, false); if (config.n_entries == 0) log_info("No boot loader entries found."); diff --git a/src/login/logind-core.c b/src/login/logind-core.c index c160f546bca..1375f438e4b 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -16,6 +16,7 @@ #include "cgroup-util.h" #include "conf-parser.h" #include "device-util.h" +#include "efi-loader.h" #include "errno-util.h" #include "fd-util.h" #include "limits-util.h" @@ -817,3 +818,27 @@ void manager_reconnect_utmp(Manager *m) { manager_connect_utmp(m); #endif } + +int manager_read_efi_boot_loader_entries(Manager *m) { +#if ENABLE_EFI + int r; + + assert(m); + if (m->efi_boot_loader_entries_set) + return 0; + + r = efi_loader_get_entries(&m->efi_boot_loader_entries); + if (r == -ENOENT || ERRNO_IS_NOT_SUPPORTED(r)) { + log_debug_errno(r, "Boot loader reported no entries."); + m->efi_boot_loader_entries_set = true; + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to determine entries reported by boot loader: %m"); + + m->efi_boot_loader_entries_set = true; + return 1; +#else + return 0; +#endif +} diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a88605232c4..7fed32c3b41 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2969,17 +2969,20 @@ static int property_get_reboot_to_boot_loader_entry( return sd_bus_message_append(reply, "s", v); } -static int boot_loader_entry_exists(const char *id) { +static int boot_loader_entry_exists(Manager *m, const char *id) { _cleanup_(boot_config_free) BootConfig config = {}; int r; + assert(m); assert(id); r = boot_entries_load_config_auto(NULL, NULL, &config); if (r < 0 && r != -ENOKEY) /* don't complain if no GPT is found, hence skip ENOKEY */ return r; - (void) boot_entries_augment_from_loader(&config, true); + r = manager_read_efi_boot_loader_entries(m); + if (r >= 0) + (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, true); return boot_config_has_entry(&config, id); } @@ -3004,7 +3007,7 @@ static int method_set_reboot_to_boot_loader_entry( if (isempty(v)) v = NULL; else if (efi_loader_entry_name_valid(v)) { - r = boot_loader_entry_exists(v); + r = boot_loader_entry_exists(m, v); if (r < 0) return r; if (r == 0) @@ -3123,18 +3126,21 @@ static int property_get_boot_loader_entries( sd_bus_error *error) { _cleanup_(boot_config_free) BootConfig config = {}; + Manager *m = userdata; size_t i; int r; assert(bus); assert(reply); - assert(userdata); + assert(m); r = boot_entries_load_config_auto(NULL, NULL, &config); if (r < 0 && r != -ENOKEY) /* don't complain if there's no GPT found */ return r; - (void) boot_entries_augment_from_loader(&config, true); + r = manager_read_efi_boot_loader_entries(m); + if (r >= 0) + (void) boot_entries_augment_from_loader(&config, m->efi_boot_loader_entries, true); r = sd_bus_message_open_container(reply, 'a', "s"); if (r < 0) diff --git a/src/login/logind.c b/src/login/logind.c index d167080c266..5a556f9ea4a 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -166,6 +166,8 @@ static Manager* manager_unref(Manager *m) { free(m->wall_message); free(m->action_job); + strv_free(m->efi_boot_loader_entries); + return mfree(m); } diff --git a/src/login/logind.h b/src/login/logind.h index e1d57277fa1..7dbf0c28e18 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -123,6 +123,9 @@ struct Manager { uint64_t runtime_dir_inodes; uint64_t sessions_max; uint64_t inhibitors_max; + + char **efi_boot_loader_entries; + bool efi_boot_loader_entries_set; }; void manager_reset_config(Manager *m); @@ -168,3 +171,5 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size); int manager_setup_wall_message_timer(Manager *m); bool logind_wall_tty_filter(const char *tty, void *userdata); + +int manager_read_efi_boot_loader_entries(Manager *m); diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 13d7b2f1607..11bba2c7edf 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -735,9 +735,12 @@ int boot_entries_load_config_auto( return boot_entries_load_config(esp_where, xbootldr_where, config); } -#if ENABLE_EFI -int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) { - static const char * const title_table[] = { +int boot_entries_augment_from_loader( + BootConfig *config, + char **found_by_loader, + 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", @@ -746,22 +749,14 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) { "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface", }; - _cleanup_strv_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) { @@ -803,7 +798,6 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) { return 0; } -#endif /********************************************************************************/ diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index b40680b643b..1075a41d541 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -76,13 +76,7 @@ static inline BootEntry* boot_config_default_entry(BootConfig *config) { void boot_config_free(BootConfig *config); int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config); int boot_entries_load_config_auto(const char *override_esp_path, const char *override_xbootldr_path, BootConfig *config); -#if ENABLE_EFI -int boot_entries_augment_from_loader(BootConfig *config, bool only_auto); -#else -static inline int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) { - return -EOPNOTSUPP; -} -#endif +int boot_entries_augment_from_loader(BootConfig *config, char **list, bool only_auto); static inline const char* boot_entry_title(const BootEntry *entry) { return entry->show_title ?: entry->title ?: entry->id;