Merge pull request #15935 from poettering/cache-more-efi-vars
logind + efi-loader: cache more efi vars
This commit is contained in:
commit
956508cb5d
|
@ -102,7 +102,7 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>systemd-efi-options</option> <optional><replaceable>VALUE</replaceable></optional></term>
|
||||
<term><option>systemd-efi-options</option> <optional><replaceable>STRING</replaceable></optional></term>
|
||||
|
||||
<listitem><para>When called without the optional argument, prints the current value of the
|
||||
<literal>SystemdOptions</literal> EFI variable. When called with an argument, sets the
|
||||
|
@ -111,6 +111,17 @@
|
|||
for the meaning of that variable.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>reboot-to-firmware</option> <optional><replaceable>BOOL</replaceable></optional></term>
|
||||
|
||||
<listitem><para>Query or set the "Reboot-Into-Firmware-Setup" flag of the EFI firmware. Takes a
|
||||
boolean argument which controls whether to show the firmware setup on next system reboot. If the
|
||||
argument is omitted shows the current status of the flag, or whether the flag is supported. This
|
||||
controls the same flag as <command>systemctl reboot --firmware-setup</command>, but is more
|
||||
low-level and allows setting the flag independently from actually requesting a
|
||||
reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>list</option></term>
|
||||
|
||||
|
|
|
@ -69,19 +69,21 @@ int efi_get_variable(
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (DEBUG_LOGGING)
|
||||
if (DEBUG_LOGGING) {
|
||||
log_debug("Reading EFI variable %s.", p);
|
||||
begin = now(CLOCK_MONOTONIC);
|
||||
}
|
||||
|
||||
fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_debug_errno(errno, "open(\"%s\") failed: %m", p);
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
return log_debug_errno(errno, "fstat(\"%s\") failed: %m", p);
|
||||
if (st.st_size < 4)
|
||||
return -ENODATA;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "EFI variable %s is shorter than 4 bytes, refusing.", p);
|
||||
if (st.st_size > 4*1024*1024 + 4)
|
||||
return -E2BIG;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "EFI variable %s is ridiculously large, refusing.", p);
|
||||
|
||||
if (ret_value || ret_attribute) {
|
||||
/* The kernel ratelimits reads from the efivarfs because EFI is inefficient, and we'll
|
||||
|
@ -96,31 +98,34 @@ int efi_get_variable(
|
|||
n = read(fd, &a, sizeof(a));
|
||||
if (n >= 0)
|
||||
break;
|
||||
log_debug_errno(errno, "read from \"%s\" failed: %m", p);
|
||||
log_debug_errno(errno, "Reading from \"%s\" failed: %m", p);
|
||||
if (errno != EINTR)
|
||||
return -errno;
|
||||
if (try >= EFI_N_RETRIES)
|
||||
return -EBUSY;
|
||||
usleep(EFI_RETRY_DELAY);
|
||||
|
||||
(void) usleep(EFI_RETRY_DELAY);
|
||||
}
|
||||
|
||||
if (n != sizeof(a))
|
||||
return -EIO;
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Read %zi bytes from EFI variable %s, expected %zu.", n, p, sizeof(a));
|
||||
}
|
||||
|
||||
if (ret_value) {
|
||||
buf = malloc(st.st_size - 4 + 2);
|
||||
buf = malloc(st.st_size - 4 + 3);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
n = read(fd, buf, (size_t) st.st_size - 4);
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
return log_debug_errno(errno, "Failed to read value of EFI variable %s: %m", p);
|
||||
assert(n <= st.st_size - 4);
|
||||
|
||||
/* Always NUL terminate (2 bytes, to protect UTF-16) */
|
||||
/* Always NUL terminate (3 bytes, to properly protect UTF-16, even if truncated in the middle of a character) */
|
||||
((char*) buf)[n] = 0;
|
||||
((char*) buf)[n + 1] = 0;
|
||||
((char*) buf)[n + 2] = 0;
|
||||
} else
|
||||
/* Assume that the reported size is accurate */
|
||||
n = st.st_size - 4;
|
||||
|
@ -229,6 +234,14 @@ int efi_set_variable(
|
|||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* For some reason efivarfs doesn't update mtime automatically. Let's do it manually then. This is
|
||||
* useful for processes that cache EFI variables to detect when changes occurred. */
|
||||
if (futimens(fd, (struct timespec[2]) {
|
||||
{ .tv_nsec = UTIME_NOW },
|
||||
{ .tv_nsec = UTIME_NOW }
|
||||
}) < 0)
|
||||
log_debug_errno(errno, "Failed to update mtime/atime on %s, ignoring: %m", p);
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
|
|
|
@ -1041,7 +1041,10 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" remove Remove systemd-boot from the ESP and EFI variables\n"
|
||||
" is-installed Test whether systemd-boot is installed in the ESP\n"
|
||||
" random-seed Initialize random seed in ESP and EFI variables\n"
|
||||
" systemd-efi-options Query or set system options string in EFI variable\n"
|
||||
" systemd-efi-options [STRING]\n"
|
||||
" Query or set system options string in EFI variable\n"
|
||||
" reboot-to-firmware [BOOL]\n"
|
||||
" Query or set reboot-to-firmware EFI flag\n"
|
||||
"\nBoot Loader Entries Commands:\n"
|
||||
" list List boot loader entries\n"
|
||||
" set-default ID Set default boot loader entry\n"
|
||||
|
@ -1245,6 +1248,18 @@ static int verb_status(int argc, char *argv[], void *userdata) {
|
|||
printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal());
|
||||
printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot()));
|
||||
printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
|
||||
|
||||
r = efi_get_reboot_to_firmware();
|
||||
if (r > 0)
|
||||
printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
|
||||
else if (r == 0)
|
||||
printf(" Boot into FW: supported\n");
|
||||
else if (r == -EOPNOTSUPP)
|
||||
printf(" Boot into FW: not supported\n");
|
||||
else {
|
||||
errno = -r;
|
||||
printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Current Boot Loader:\n");
|
||||
|
@ -1311,6 +1326,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 +1349,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.");
|
||||
|
@ -1766,6 +1788,39 @@ static int verb_systemd_efi_options(int argc, char *argv[], void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int verb_reboot_to_firmware(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
if (argc < 2) {
|
||||
r = efi_get_reboot_to_firmware();
|
||||
if (r > 0) {
|
||||
puts("active");
|
||||
return EXIT_SUCCESS; /* success */
|
||||
}
|
||||
if (r == 0) {
|
||||
puts("supported");
|
||||
return 1; /* recognizable error #1 */
|
||||
}
|
||||
if (r == -EOPNOTSUPP) {
|
||||
puts("not supported");
|
||||
return 2; /* recognizable error #2 */
|
||||
}
|
||||
|
||||
log_error_errno(r, "Failed to query reboot-to-firmware state: %m");
|
||||
return 3; /* other kind of error */
|
||||
} else {
|
||||
r = parse_boolean(argv[1]);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse argument: %s", argv[1]);
|
||||
|
||||
r = efi_set_reboot_to_firmware(r);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set reboot-to-firmware option: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int bootctl_main(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "help", VERB_ANY, VERB_ANY, 0, help },
|
||||
|
@ -1779,6 +1834,7 @@ static int bootctl_main(int argc, char *argv[]) {
|
|||
{ "set-oneshot", 2, 2, 0, verb_set_default },
|
||||
{ "random-seed", VERB_ANY, 1, 0, verb_random_seed },
|
||||
{ "systemd-efi-options", VERB_ANY, 2, 0, verb_systemd_efi_options },
|
||||
{ "reboot-to-firmware", VERB_ANY, 2, 0, verb_reboot_to_firmware },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -1802,4 +1858,4 @@ static int run(int argc, char *argv[]) {
|
|||
return bootctl_main(argc, argv);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/********************************************************************************/
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include "io-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "utf8.h"
|
||||
|
@ -28,10 +30,11 @@
|
|||
#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
|
||||
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
|
||||
|
||||
#define boot_option__contents { \
|
||||
uint32_t attr; \
|
||||
uint16_t path_len; \
|
||||
uint16_t title[]; \
|
||||
#define boot_option__contents \
|
||||
{ \
|
||||
uint32_t attr; \
|
||||
uint16_t path_len; \
|
||||
uint16_t title[]; \
|
||||
}
|
||||
|
||||
struct boot_option boot_option__contents;
|
||||
|
@ -49,33 +52,39 @@ struct drive_path {
|
|||
uint8_t signature_type;
|
||||
} _packed_;
|
||||
|
||||
#define device_path__contents { \
|
||||
uint8_t type; \
|
||||
uint8_t sub_type; \
|
||||
uint16_t length; \
|
||||
union { \
|
||||
uint16_t path[0]; \
|
||||
struct drive_path drive; \
|
||||
}; \
|
||||
#define device_path__contents \
|
||||
{ \
|
||||
uint8_t type; \
|
||||
uint8_t sub_type; \
|
||||
uint16_t length; \
|
||||
union { \
|
||||
uint16_t path[0]; \
|
||||
struct drive_path drive; \
|
||||
}; \
|
||||
}
|
||||
|
||||
struct device_path device_path__contents;
|
||||
struct device_path__packed device_path__contents _packed_;
|
||||
assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
|
||||
|
||||
|
||||
int efi_reboot_to_firmware_supported(void) {
|
||||
_cleanup_free_ void *v = NULL;
|
||||
static int cache = -1;
|
||||
uint64_t b;
|
||||
size_t s;
|
||||
int r;
|
||||
|
||||
if (!is_efi_boot())
|
||||
if (cache > 0)
|
||||
return 0;
|
||||
if (cache == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!is_efi_boot())
|
||||
goto not_supported;
|
||||
|
||||
r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
|
||||
if (r == -ENOENT) /* variable doesn't exist? it's not supported then */
|
||||
return -EOPNOTSUPP;
|
||||
if (r == -ENOENT)
|
||||
goto not_supported; /* variable doesn't exist? it's not supported then */
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (s != sizeof(uint64_t))
|
||||
|
@ -83,36 +92,68 @@ int efi_reboot_to_firmware_supported(void) {
|
|||
|
||||
b = *(uint64_t*) v;
|
||||
if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
|
||||
return -EOPNOTSUPP; /* bit unset? it's not supported then */
|
||||
goto not_supported; /* bit unset? it's not supported then */
|
||||
|
||||
cache = 1;
|
||||
return 0;
|
||||
|
||||
not_supported:
|
||||
cache = 0;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int get_os_indications(uint64_t *os_indication) {
|
||||
static int get_os_indications(uint64_t *ret) {
|
||||
static struct stat cache_stat = {};
|
||||
_cleanup_free_ void *v = NULL;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
static uint64_t cache;
|
||||
struct stat new_stat;
|
||||
size_t s;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
/* Let's verify general support first */
|
||||
r = efi_reboot_to_firmware_supported();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fn = efi_variable_path(EFI_VENDOR_GLOBAL, "OsIndications");
|
||||
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) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
/* Doesn't exist? Then we can exit early (also see below) */
|
||||
*ret = 0;
|
||||
return 0;
|
||||
|
||||
} else if (stat_inode_unmodified(&new_stat, &cache_stat)) {
|
||||
/* inode didn't change, we can return the cached value */
|
||||
*ret = cache;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
|
||||
if (r == -ENOENT) {
|
||||
/* Some firmware implementations that do support OsIndications and report that with
|
||||
* OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's pretend it's 0
|
||||
* then, to hide this implementation detail. Note that this call will return -ENOENT then only if the
|
||||
* support for OsIndications is missing entirely, as determined by efi_reboot_to_firmware_supported()
|
||||
* above. */
|
||||
*os_indication = 0;
|
||||
* OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
|
||||
* pretend it's 0 then, to hide this implementation detail. Note that this call will return
|
||||
* -ENOENT then only if the support for OsIndications is missing entirely, as determined by
|
||||
* efi_reboot_to_firmware_supported() above. */
|
||||
*ret = 0;
|
||||
return 0;
|
||||
} else if (r < 0)
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (s != sizeof(uint64_t))
|
||||
if (s != sizeof(uint64_t))
|
||||
return -EINVAL;
|
||||
|
||||
*os_indication = *(uint64_t *)v;
|
||||
cache_stat = new_stat;
|
||||
*ret = cache = *(uint64_t *)v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue