X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Fefivars.c;h=840e4e0c350cbbbfeb873375c19f783317f523ae;hp=e16c61029ba65c982f9290965f1a4ee327cf3747;hb=46ba8aae2b82bc5c87ba347e6bf914ecd5e9d51e;hpb=7b4d7cc08283e5485dcfa49ffdf1915de1d5e81b diff --git a/src/shared/efivars.c b/src/shared/efivars.c index e16c61029..840e4e0c3 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -22,16 +22,23 @@ #include #include #include +#include #include "util.h" #include "utf8.h" #include "efivars.h" -bool is_efiboot(void) { +bool is_efi_boot(void) { return access("/sys/firmware/efi", F_OK) >= 0; } -int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) { +int efi_get_variable( + sd_id128_t vendor, + const char *name, + uint32_t *attribute, + void **value, + size_t *size) { + _cleanup_close_ int fd = -1; _cleanup_free_ char *p = NULL; uint32_t a; @@ -61,7 +68,7 @@ int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, v n = read(fd, &a, sizeof(a)); if (n < 0) - return (int) n; + return -errno; if (n != sizeof(a)) return -EIO; @@ -92,15 +99,22 @@ int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, v return 0; } -char *efi_get_variable_string(sd_id128_t vendor, const char *name) { +int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) { _cleanup_free_ void *s = NULL; size_t ss; - int err; + int r; + char *x; - err = efi_get_variable(vendor, name, NULL, &s, &ss); - if (err < 0) - return NULL; - return utf16_to_utf8(s, ss); + r = efi_get_variable(vendor, name, NULL, &s, &ss); + if (r < 0) + return r; + + x = utf16_to_utf8(s, ss); + if (!x) + return -ENOMEM; + + *p = x; + return 0; } static size_t utf16_size(const uint16_t *s) { @@ -108,6 +122,7 @@ static size_t utf16_size(const uint16_t *s) { while (s[l] > 0) l++; + return (l+1) * sizeof(uint16_t); } @@ -131,7 +146,12 @@ static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) { memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4)); } -int efi_get_boot_option(uint32_t id, uint32_t *attributes, char **title, sd_id128_t *part_uuid, char **path, char **data, size_t *data_size) { +int efi_get_boot_option( + uint16_t id, + char **title, + sd_id128_t *part_uuid, + char **path) { + struct boot_option { uint32_t attr; uint16_t path_len; @@ -157,23 +177,20 @@ int efi_get_boot_option(uint32_t id, uint32_t *attributes, char **title, sd_id12 }; } _packed_; - char boot_id[32]; - _cleanup_free_ char *buf = NULL; + char boot_id[9]; + _cleanup_free_ uint8_t *buf = NULL; size_t l; struct boot_option *header; size_t title_size; char *s = NULL; char *p = NULL; sd_id128_t p_uuid = SD_ID128_NULL; - char *d = NULL; - size_t d_size = 0; int err; snprintf(boot_id, sizeof(boot_id), "Boot%04X", id); err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l); if (err < 0) return err; - if (l < sizeof(struct boot_option)) return -ENOENT; @@ -189,7 +206,7 @@ int efi_get_boot_option(uint32_t id, uint32_t *attributes, char **title, sd_id12 } if (header->path_len > 0) { - char *dbuf; + uint8_t *dbuf; size_t dnext; dbuf = buf + offsetof(struct boot_option, title) + title_size; @@ -233,65 +250,131 @@ int efi_get_boot_option(uint32_t id, uint32_t *attributes, char **title, sd_id12 } } - *title = s; + if (title) + *title = s; if (part_uuid) *part_uuid = p_uuid; if (path) *path = p; - if (data) - *data = d; - if (data_size) - *data_size = d_size; + return 0; err: free(s); free(p); - free(d); return err; } -int efi_get_boot_order(uint16_t **order, size_t *count) { +int efi_get_boot_order(uint16_t **order) { void *buf; size_t l; - int err; + int r; - err = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l); - if (err < 0) - return err; + r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l); + if (r < 0) + return r; - if (l == 0) { + if (l <= 0) { free(buf); return -ENOENT; } - if ((l % sizeof(uint16_t) > 0)) { + if ((l % sizeof(uint16_t) > 0) || + (l / sizeof(uint16_t) > INT_MAX)) { free(buf); return -EINVAL; } *order = buf; - *count = l / sizeof(uint16_t); + return (int) (l / sizeof(uint16_t)); +} + +static int boot_id_hex(const char s[4]) { + int i; + int id = 0; + + for (i = 0; i < 4; i++) + if (s[i] >= '0' && s[i] <= '9') + id |= (s[i] - '0') << (3 - i) * 4; + else if (s[i] >= 'A' && s[i] <= 'F') + id |= (s[i] - 'A' + 10) << (3 - i) * 4; + else + return -1; + + return id; +} + +static int cmp_uint16(const void *_a, const void *_b) { + const uint16_t *a = _a, *b = _b; + + if (*a < *b) + return -1; + if (*a > *b) + return 1; + return 0; } +int efi_get_boot_options(uint16_t **options) { + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *de; + uint16_t *list = NULL; + int count = 0, r; + + assert(options); + + dir = opendir("/sys/firmware/efi/efivars/"); + if (!dir) + return -errno; + + FOREACH_DIRENT(de, dir, r = -errno; goto fail) { + int id; + uint16_t *t; + + if (strncmp(de->d_name, "Boot", 4) != 0) + continue; + + if (strlen(de->d_name) != 45) + continue; + + if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0) + continue; + + id = boot_id_hex(de->d_name + 4); + if (id < 0) + continue; + + t = realloc(list, (count + 1) * sizeof(uint16_t)); + if (!t) { + r = -ENOMEM; + goto fail; + } + + list = t; + list[count ++] = id; + } + + qsort(list, count, sizeof(uint16_t), cmp_uint16); + + *options = list; + return count; + +fail: + free(list); + return r; +} + static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) { - _cleanup_free_ void *i = NULL; _cleanup_free_ char *j = NULL; - size_t is; int r; uint64_t x; assert(name); assert(u); - r = efi_get_variable(EFI_VENDOR_LOADER, name, NULL, &i, &is); + r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j); if (r < 0) return r; - j = utf16_to_utf8(i, is); - if (!j) - return -ENOMEM; - r = safe_atou64(j, &x); if (r < 0) return r; @@ -364,22 +447,16 @@ int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, d } int efi_get_loader_device_part_uuid(sd_id128_t *u) { - _cleanup_free_ void *s = NULL; _cleanup_free_ char *p = NULL; - size_t ss; int r, parsed[16]; unsigned i; assert(u); - r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", NULL, &s, &ss); + r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p); if (r < 0) return r; - p = utf16_to_utf8(s, ss); - if (!p) - return -ENOMEM; - if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", &parsed[0], &parsed[1], &parsed[2], &parsed[3], &parsed[4], &parsed[5], &parsed[6], &parsed[7],