diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-07-19 18:29:53 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2019-07-25 17:10:51 +0200 |
commit | c242a082793df77a1dc0bce7f470660ab0a86fe5 (patch) | |
tree | a66d1f53bf527bf9dc0e016d64d2758f52775038 /src/shared | |
parent | b19fa8126d8bc82cbac746ccc378454e3bd9bf91 (diff) | |
download | systemd-c242a082793df77a1dc0bce7f470660ab0a86fe5.tar.gz |
efivars: modernize efi_get_variable() a bit
Primarily, make sure the return parameters are all individually
optional.
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/efivars.c | 71 |
1 files changed, 44 insertions, 27 deletions
diff --git a/src/shared/efivars.c b/src/shared/efivars.c index a4a3c200ac..3597ddf4a7 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -207,25 +207,32 @@ char* efi_variable_path(sd_id128_t vendor, const char *name) { int efi_get_variable( sd_id128_t vendor, const char *name, - uint32_t *attribute, - void **value, - size_t *size) { + uint32_t *ret_attribute, + void **ret_value, + size_t *ret_size) { _cleanup_close_ int fd = -1; _cleanup_free_ char *p = NULL; + _cleanup_free_ void *buf = NULL; + struct stat st; uint32_t a; ssize_t n; - struct stat st; - _cleanup_free_ void *buf = NULL; assert(name); - assert(value); - assert(size); p = efi_variable_path(vendor, name); if (!p) return -ENOMEM; + if (!ret_value && !ret_size && !ret_attribute) { + /* If caller is not interested in anything, just check if the variable exists and is readable + * to us. */ + if (access(p, R_OK) < 0) + return -errno; + + return 0; + } + fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; @@ -237,31 +244,41 @@ int efi_get_variable( if (st.st_size > 4*1024*1024 + 4) return -E2BIG; - n = read(fd, &a, sizeof(a)); - if (n < 0) - return -errno; - if (n != sizeof(a)) - return -EIO; + if (ret_value || ret_attribute) { + n = read(fd, &a, sizeof(a)); + if (n < 0) + return -errno; + if (n != sizeof(a)) + return -EIO; + } - buf = malloc(st.st_size - 4 + 2); - if (!buf) - return -ENOMEM; + if (ret_value) { + buf = malloc(st.st_size - 4 + 2); + if (!buf) + return -ENOMEM; - n = read(fd, buf, (size_t) st.st_size - 4); - if (n < 0) - return -errno; - if (n != (ssize_t) st.st_size - 4) - return -EIO; + n = read(fd, buf, (size_t) st.st_size - 4); + if (n < 0) + return -errno; + if (n != st.st_size - 4) + return -EIO; + + /* Always NUL terminate (2 bytes, to protect UTF-16) */ + ((char*) buf)[st.st_size - 4] = 0; + ((char*) buf)[st.st_size - 4 + 1] = 0; + } + + /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable + * with a smaller value. */ - /* Always NUL terminate (2 bytes, to protect UTF-16) */ - ((char*) buf)[st.st_size - 4] = 0; - ((char*) buf)[st.st_size - 4 + 1] = 0; + if (ret_attribute) + *ret_attribute = a; - *value = TAKE_PTR(buf); - *size = (size_t) st.st_size - 4; + if (ret_value) + *ret_value = TAKE_PTR(buf); - if (attribute) - *attribute = a; + if (ret_size) + *ret_size = (size_t) st.st_size - 4; return 0; } |