lib/efi: Cleanup read/write routines
authorGeoff Levand <geoff@infradead.org>
Thu, 2 Aug 2018 17:29:36 +0000 (17:29 +0000)
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>
Tue, 7 Aug 2018 01:30:36 +0000 (11:30 +1000)
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 <geoff@infradead.org>
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
lib/efi/efivar.c
lib/efi/efivar.h

index 1ac69908d1f62f87fb770f0cc547c606f8537cfc..21c5d344f582b212eec8af2bcd53d93a11040b80 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/fs.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
 
 #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;
 }
index ebf73facb32e5d4f40d2815b65cfb92f761c244b..0d4410000e6402d61af6163ebfc63d2e29223283 100644 (file)
 #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 */