From: Geoff Levand Date: Thu, 2 Aug 2018 17:29:36 +0000 (+0000) Subject: lib/efi: Cleanup read/write routines X-Git-Tag: v1.9.0~28 X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=c3dfc9b7b91045172d460651c0309b09b0ab121a;ds=sidebyside lib/efi: Cleanup read/write routines Make a new stucture struct efi_data to hold the info that describes an efi variable. Make a common routine efi_open that opens the efi variable file. Switch the efi get/set/del routines over to use efi_open. Signed-off-by: Geoff Levand Signed-off-by: Samuel Mendoza-Jonas --- diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c index 1ac6990..21c5d34 100644 --- a/lib/efi/efivar.c +++ b/lib/efi/efivar.c @@ -24,6 +24,7 @@ #include #include +#include #include "efivar.h" #include "log/log.h" @@ -42,150 +43,150 @@ inline const char *get_efivarfs_path(void) return efivarfs_path; } -int efi_del_variable(void *ctx, const char *guidstr, - const char *name) +static int efi_open(const char *name, const char *guidstr, int flags, + mode_t mode, char **path) { - int fd, flag, errno_value; - int rc = -1; - const char *dir; - char *path; + int fd; + + *path = NULL; - dir = get_efivarfs_path(); - if (!dir) + if (!get_efivarfs_path()) return -1; - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) + *path = talloc_asprintf(NULL, "%s%s-%s", get_efivarfs_path(), name, guidstr); + if (!*path) return -1; - fd = open(path, O_RDONLY|O_NONBLOCK); - if (fd == -1) - goto err; + flags = flags ? flags : O_RDONLY | O_NONBLOCK; + + fd = open(*path, flags, mode); + + if (fd < 0) { + pb_log("%s: open failed %s: %s\n", __func__, *path, + strerror(errno)); + talloc_free(*path); + *path = NULL; + return -1; + } + + return fd; +} + +int efi_del_variable(const char *guidstr, const char *name) +{ + int fd, flag; + int rc = -1; + char *path; + + fd = efi_open(name, guidstr, 0, 0, &path); + if (fd < 0) + return -1; rc = ioctl(fd, FS_IOC_GETFLAGS, &flag); if (rc == -1) - goto err; + goto exit; flag &= ~FS_IMMUTABLE_FL; rc = ioctl(fd, FS_IOC_SETFLAGS, &flag); if (rc == -1) - goto err; + goto exit; close(fd); + fd = 0; rc = unlink(path); - -err: - errno_value = errno; - if (fd > 0) - close(fd); - - errno = errno_value; +exit: + talloc_free(path); + close(fd); return rc; } int efi_get_variable(void *ctx, const char *guidstr, const char *name, - uint8_t **data, size_t *data_size, uint32_t *attributes) + struct efi_data **efi_data) { - int fd, errno_value; + int fd; int rc = -1; - void *p, *buf; - size_t bufsize = 4096; - size_t filesize = 0; - ssize_t sz; - const char *dir; + char *p; + char buf[4096]; + ssize_t total; + ssize_t count; char *path; - dir = get_efivarfs_path(); - if (!dir) - return EFAULT; + *efi_data = NULL; - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) - return ENOMEM; - - fd = open(path, O_RDONLY|O_NONBLOCK); + fd = efi_open(name, guidstr, 0, 0, &path); if (fd < 0) - goto err; + return -1; - buf = talloc_size(ctx, bufsize); - if (!buf) - goto err; - - do { - p = buf + filesize; - sz = read(fd, p, bufsize); - if (sz < 0 && errno == EAGAIN) { - continue; - } else if (sz == 0) { - break; + for (p = buf, total = 0; ; p = buf + count) { + count = read(fd, p, sizeof(buf) - total); + if (count < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + + pb_log("%s: read failed %s: (%ld) %s\n", __func__, path, + count, strerror(errno)); + goto exit; } - filesize += sz; - } while (1); + if (p >= (buf + sizeof(buf))) { + pb_log("%s: buffer full %s: (%ld)\n", __func__, path, + sizeof(buf)); + goto exit; + } + if (count == 0) + break; + total += count; + }; - *attributes = *(uint32_t *)buf; - *data = (uint8_t *)(buf + sizeof(uint32_t)); - *data_size = strlen(buf + sizeof(uint32_t)); - rc = 0; + *efi_data = (void*)talloc_zero_array(ctx, char, + sizeof (struct efi_data) + total); -err: - errno_value = errno; - if (fd > 0) - close(fd); + (*efi_data)->attributes = *(uint32_t *)buf; + (*efi_data)->data_size = total; + (*efi_data)->data = (*efi_data)->fill; + memcpy((*efi_data)->data, buf + sizeof (uint32_t), total); - errno = errno_value; + rc = 0; +exit: + talloc_free(path); + close(fd); return rc; } -int efi_set_variable(void *ctx, const char *guidstr, const char *name, - uint8_t *data, size_t data_size, uint32_t attributes) +int efi_set_variable(const char *guidstr, const char *name, + const struct efi_data *efi_data) { - int rc = -1, errno_value; - int fd = -1; - ssize_t len; - const char *dir; - char *path; + int rc = -1; + int fd; + ssize_t count; void *buf; size_t bufsize; - mode_t mask = 0644; - - dir = get_efivarfs_path(); - if (!dir) - return EFAULT; - - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) - return ENOMEM; + char *path; - if (!access(path, F_OK)) { - rc = efi_del_variable(ctx, guidstr, name); - if (rc < 0) { - goto err; - } - } + efi_del_variable(guidstr, name); - fd = open(path, O_CREAT|O_WRONLY, mask); + fd = efi_open(name, guidstr, O_CREAT | O_WRONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &path); if (fd < 0) - goto err; + return -1; - bufsize = sizeof(uint32_t) + data_size; - buf = talloc_size(ctx, bufsize); + bufsize = sizeof(uint32_t) + efi_data->data_size; + buf = talloc_size(path, bufsize); if (!buf) - goto err; - - *(uint32_t *)buf = attributes; - memcpy(buf + sizeof(uint32_t), data, data_size); + goto exit; - len = write(fd, buf, bufsize); - if ((size_t)len != bufsize) - goto err; - else - rc = 0; + *(uint32_t *)buf = efi_data->attributes; + memcpy(buf + sizeof(uint32_t), efi_data->data, efi_data->data_size); -err: - errno_value = errno; - if (fd > 0) - close(fd); + count = write(fd, buf, bufsize); + if ((size_t)count != bufsize) { + pb_log("%s: write failed %s: (%ld) %s\n", __func__, name, + count, strerror(errno)); + goto exit; + } + rc = 0; - errno = errno_value; +exit: + talloc_free(path); + close(fd); return rc; } diff --git a/lib/efi/efivar.h b/lib/efi/efivar.h index ebf73fa..0d44100 100644 --- a/lib/efi/efivar.h +++ b/lib/efi/efivar.h @@ -34,13 +34,20 @@ #define EFIVARFS_MAGIC 0xde5e81e4 #endif +struct efi_data { + uint32_t attributes; + size_t data_size; + void *data; + uint8_t fill[0]; +}; + void set_efivarfs_path(const char *path); const char *get_efivarfs_path(void); int efi_get_variable(void *ctx, const char *guidstr, const char *name, - uint8_t **data, size_t *data_size, uint32_t *attributes); -int efi_set_variable(void *ctx, const char *guidstr, const char *name, - uint8_t *data, size_t data_size, uint32_t attributes); -int efi_del_variable(void *ctx, const char *guidstr, const char *name); + struct efi_data **efi_data); +int efi_set_variable(const char *guidstr, const char *name, + const struct efi_data *efi_data); +int efi_del_variable(const char *guidstr, const char *name); #endif /* EFIVAR_H */