diff mbox series

[v2,16/30] lib/efi: Cleanup read/write routines

Message ID a9f0c314501190a21552ca985dde05594f1ceb34.1533230644.git.geoff@infradead.org
State Accepted
Headers show
Series [v2,01/30] docker: Add libfdt-dev | expand

Commit Message

Geoff Levand Aug. 2, 2018, 5:29 p.m. UTC
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>
---
 lib/efi/efivar.c | 201 ++++++++++++++++++++++++++++---------------------------
 lib/efi/efivar.h |  15 +++--
 2 files changed, 112 insertions(+), 104 deletions(-)
diff mbox series

Patch

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 <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;
 }
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 */