diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 7fed32c3b4..d8ae0287ec 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2751,8 +2751,6 @@ static int property_get_reboot_to_boot_loader_menu( r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU"); if (r == -ENXIO) { - _cleanup_free_ char *v = NULL; - /* EFI case: returns the current value of LoaderConfigTimeoutOneShot. Three cases are distuingished: * * 1. Variable not set, boot into boot loader menu is not enabled (we return UINT64_MAX to the user) @@ -2760,20 +2758,10 @@ static int property_get_reboot_to_boot_loader_menu( * 3. Variable set to numeric value formatted in ASCII, boot into boot loader menu with the specified timeout in seconds */ - r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", &v); + r = efi_loader_get_config_timeout_one_shot(&x); if (r < 0) { if (r != -ENOENT) - log_warning_errno(r, "Failed to read LoaderConfigTimeoutOneShot variable: %m"); - } else { - uint64_t sec; - - r = safe_atou64(v, &sec); - if (r < 0) - log_warning_errno(r, "Failed to parse LoaderConfigTimeoutOneShot value '%s': %m", v); - else if (sec > (USEC_INFINITY / USEC_PER_SEC)) - log_warning("LoaderConfigTimeoutOneShot too large, ignoring: %m"); - else - x = sec * USEC_PER_SEC; /* return in µs */ + log_warning_errno(r, "Failed to read LoaderConfigTimeoutOneShot variable, ignoring: %m"); } } else if (r < 0) diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index b6ad43b856..ce9e78b274 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -734,3 +734,41 @@ char *efi_tilt_backslashes(char *s) { return s; } + +int efi_loader_get_config_timeout_one_shot(usec_t *ret) { + _cleanup_free_ char *v = NULL, *fn = NULL; + static struct stat cache_stat = {}; + struct stat new_stat; + static usec_t cache; + uint64_t sec; + int r; + + assert(ret); + + fn = efi_variable_path(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot"); + if (!fn) + return -ENOMEM; + + /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */ + if (stat(fn, &new_stat) < 0) + return -errno; + + if (stat_inode_unmodified(&new_stat, &cache_stat)) { + *ret = cache; + return 0; + } + + r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", &v); + if (r < 0) + return r; + + r = safe_atou64(v, &sec); + if (r < 0) + return r; + if (sec > USEC_INFINITY / USEC_PER_SEC) + return -ERANGE; + + cache_stat = new_stat; + *ret = cache = sec * USEC_PER_SEC; /* return in µs */ + return 0; +} diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 96208d25bf..98bb57ecbd 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -23,6 +23,8 @@ int efi_loader_get_entries(char ***ret); int efi_loader_get_features(uint64_t *ret); +int efi_loader_get_config_timeout_one_shot(usec_t *ret); + #else static inline int efi_reboot_to_firmware_supported(void) { @@ -77,6 +79,10 @@ static inline int efi_loader_get_features(uint64_t *ret) { return -EOPNOTSUPP; } +static inline int efi_loader_get_config_timeout_one_shot(usec_t *ret) { + return -EOPNOTSUPP; +} + #endif bool efi_loader_entry_name_valid(const char *s);