X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=lib%2Fefi%2Fefivar.c;h=f1dd0021cea0c8070a8da86ac303ac07723b82ee;hp=1ac69908d1f62f87fb770f0cc547c606f8537cfc;hb=15751f10a1368f56ca10b2bc84011253216103aa;hpb=a915889b7fbbc4be11f9a37ea7afb5b3f3d41173 diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c index 1ac6990..f1dd002 100644 --- a/lib/efi/efivar.c +++ b/lib/efi/efivar.c @@ -17,6 +17,7 @@ * Author: Ge Song */ +#include #include #include #include @@ -24,168 +25,226 @@ #include #include +#include +#include #include "efivar.h" #include "log/log.h" #include "talloc/talloc.h" -static const char *efivarfs_path; +void efi_init_mount(struct efi_mount *efi_mount, const char *path, + const char *guid) +{ + assert(efi_mount); + + efi_mount->path = path; + efi_mount->guid = guid; + + pb_debug_fn("%s--%s", efi_mount->path, efi_mount->guid); +} -inline void set_efivarfs_path(const char *path) +bool efi_check_mount_magic(const struct efi_mount *efi_mount, bool check_magic) { - efivarfs_path = path; + struct statfs s; + + assert(efi_mount); + + if (!efi_mount->guid) { + pb_debug_fn("guid not set\n"); + return false; + } + + if (access(efi_mount->path, R_OK | W_OK)) { + pb_debug_fn("Can't access %s\n", efi_mount->path); + return false; + } + + memset(&s, '\0', sizeof(s)); + if (statfs(efi_mount->path, &s)) { + pb_debug_fn("statfs failed: %s: (%d) %s\n", efi_mount->path, + errno, strerror(errno)); + return false; + } + + if (check_magic && s.f_type != EFIVARFS_MAGIC) { + pb_debug_fn("Bad magic = 0x%lx\n", (unsigned long)s.f_type); + return false; + } + + return true; } -inline const char *get_efivarfs_path(void) +static int efi_open(const struct efi_mount *efi_mount, const char *name, + int flags, mode_t mode, char **path) { + int fd; - return efivarfs_path; + assert(efi_mount); + + *path = NULL; + + if (!efi_mount->path || !efi_mount->guid) + return -1; + + *path = talloc_asprintf(NULL, "%s/%s-%s", efi_mount->path, name, + efi_mount->guid); + if (!*path) + return -1; + + flags = flags ? flags : O_RDONLY | O_NONBLOCK; + + fd = open(*path, flags, mode); + + if (fd < 0) { + pb_log("%s: open failed '%s': (%d) %s\n", __func__, *path, + errno, strerror(errno)); + talloc_free(*path); + *path = NULL; + return -1; + } + + return fd; } -int efi_del_variable(void *ctx, const char *guidstr, - const char *name) +int efi_del_variable(const struct efi_mount *efi_mount, const char *name) { - int fd, flag, errno_value; + int fd, flag; int rc = -1; - const char *dir; char *path; - dir = get_efivarfs_path(); - if (!dir) - return -1; + assert(efi_mount); - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) + fd = efi_open(efi_mount, name, 0, 0, &path); + if (fd < 0) return -1; - fd = open(path, O_RDONLY|O_NONBLOCK); - if (fd == -1) - goto err; - rc = ioctl(fd, FS_IOC_GETFLAGS, &flag); - if (rc == -1) - goto err; + if (rc == -1 && errno == ENOTTY) { + pb_debug_fn("'%s' does not support ioctl_iflags.\n", + efi_mount->path); + goto delete; + } else if (rc == -1) { + pb_log_fn("FS_IOC_GETFLAGS failed: (%d) %s\n", errno, + strerror(errno)); + goto exit; + } flag &= ~FS_IMMUTABLE_FL; rc = ioctl(fd, FS_IOC_SETFLAGS, &flag); - if (rc == -1) - goto err; + if (rc == -1) { + pb_log_fn("FS_IOC_SETFLAGS failed: (%d) %s\n", errno, + strerror(errno)); + goto exit; + } +delete: close(fd); + fd = 0; rc = unlink(path); - -err: - errno_value = errno; - if (fd > 0) - close(fd); - - errno = errno_value; + if (rc == -1) { + pb_log_fn("unlink failed: (%d) %s\n", errno, strerror(errno)); + goto exit; + } + pb_debug_fn("Deleted: '%s'\n", name); +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) +int efi_get_variable(void *ctx, const struct efi_mount *efi_mount, + const char *name, 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; + assert(efi_mount); - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) - return ENOMEM; + *efi_data = NULL; - fd = open(path, O_RDONLY|O_NONBLOCK); + fd = efi_open(efi_mount, name, 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) (%d) %s\n", __func__, path, + count, errno, 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); + pb_debug_fn("Found: '%s'='%s'\n", name, (const char *)(*efi_data)->data); - 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 struct efi_mount *efi_mount, 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; + char *path; - dir = get_efivarfs_path(); - if (!dir) - return EFAULT; + assert(efi_mount); - path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr); - if (!path) - return ENOMEM; + efi_del_variable(efi_mount, name); - if (!access(path, F_OK)) { - rc = efi_del_variable(ctx, guidstr, name); - if (rc < 0) { - goto err; - } - } - - fd = open(path, O_CREAT|O_WRONLY, mask); + fd = efi_open(efi_mount, name, 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) (%d) %s\n", __func__, name, + count, errno, strerror(errno)); + goto exit; + } + rc = 0; + pb_debug_fn("Set: '%s'='%s'\n", name, (const char *)efi_data->data); - errno = errno_value; +exit: + talloc_free(path); + close(fd); return rc; }