summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-07-19 18:29:53 +0200
committerLennart Poettering <lennart@poettering.net>2019-07-25 17:10:51 +0200
commitc242a082793df77a1dc0bce7f470660ab0a86fe5 (patch)
treea66d1f53bf527bf9dc0e016d64d2758f52775038 /src/shared
parentb19fa8126d8bc82cbac746ccc378454e3bd9bf91 (diff)
downloadsystemd-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.c71
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;
}