efi_generate_file_device_path(uint8_t *buf, ssize_t size, const char * const filepath, uint32_t options, ...) { int rc; ssize_t ret = -1; char *child_devpath = NULL; char *parent_devpath = NULL; char *relpath = NULL; va_list ap; int saved_errno; rc = find_file(filepath, &child_devpath, &relpath); if (rc < 0) { efi_error("could not canonicalize fs path"); return -1; } rc = find_parent_devpath(child_devpath, &parent_devpath); if (rc < 0) { efi_error("could not find parent device for file"); return -1; } rc = get_partition_number(child_devpath); if (rc < 0) { efi_error("could not get partition number for device"); goto err; } va_start(ap, options); ret = efi_va_generate_file_device_path_from_esp(buf, size, parent_devpath, rc, relpath, options, ap); saved_errno = errno; va_end(ap); errno = saved_errno; if (ret < 0) efi_error("could not generate File DP from ESP"); err: saved_errno = errno; if (child_devpath) free(child_devpath); if (parent_devpath) free(parent_devpath); if (relpath) free(relpath); errno = saved_errno; return ret; }
efi_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { int rc; if (!ops->chmod_variable) { efi_error("chmod_variable() is not implemented"); errno = ENOSYS; return -1; } rc = ops->chmod_variable(guid, name, mode); if (rc < 0) efi_error("ops->chmod_variable() failed"); else efi_error_clear(); return rc; }
efi_get_next_variable_name(efi_guid_t **guid, char **name) { int rc; if (!ops->get_next_variable_name) { efi_error("get_next_variable_name() is not implemented"); errno = ENOSYS; return -1; } rc = ops->get_next_variable_name(guid, name); if (rc < 0) efi_error("ops->get_next_variable_name() failed"); else efi_error_clear(); return rc; }
efi_get_variable_size(efi_guid_t guid, const char *name, size_t *size) { int rc; if (!ops->get_variable_size) { efi_error("get_variable_size() is not implemented"); errno = ENOSYS; return -1; } rc = ops->get_variable_size(guid, name, size); if (rc < 0) efi_error("ops->get_variable_size() failed"); else efi_error_clear(); return rc; }
static void libefivar_init(void) { struct efi_var_operations *ops_list[] = { &efivarfs_ops, &vars_ops, &default_ops, NULL }; char *ops_name = getenv("LIBEFIVAR_OPS"); for (int i = 0; ops_list[i] != NULL; i++) { if (ops_name != NULL) { if (!strcmp(ops_list[i]->name, ops_name) || !strcmp(ops_list[i]->name, "default")) { ops = ops_list[i]; break; } } else { int rc = ops_list[i]->probe(); if (rc <= 0) { efi_error("ops_list[%d]->probe() failed", i); } else { efi_error_clear(); ops = ops_list[i]; break; } } } }
efi_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t *attributes) { int rc; if (!ops->get_variable_attributes) { efi_error("get_variable_attributes() is not implemented"); errno = ENOSYS; return -1; } rc = ops->get_variable_attributes(guid, name, attributes); if (rc < 0) efi_error("ops->get_variable_attributes() failed"); else efi_error_clear(); return rc; }
_efi_set_variable_variadic(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, ...) { int rc; rc = ops->set_variable(guid, name, data, data_size, attributes, 0600); if (rc < 0) efi_error("ops->set_variable() failed"); return rc; }
static int open_disk(struct disk_info *info, int flags) { char *diskpath = NULL; int rc; rc = asprintfa(&diskpath, "/dev/%s", info->disk_name); if (rc < 0) { efi_error("could not allocate buffer"); return -1; } rc = open(diskpath, flags); if (rc < 0) efi_error("could not open disk"); return rc; }
efi_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { int rc; if (!ops->append_variable) { rc = generic_append_variable(guid, name, data, data_size, attributes); if (rc < 0) efi_error("generic_append_variable() failed"); else efi_error_clear(); return rc; } rc = ops->append_variable(guid, name, data, data_size, attributes); if (rc < 0) efi_error("ops->append_variable() failed"); else efi_error_clear(); return rc; }
efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) { int rc; rc = ops->set_variable(guid, name, data, data_size, attributes, mode); if (rc < 0) efi_error("ops->set_variable() failed"); else efi_error_clear(); return rc; }
/** * is_mbr_valid(): test MBR for validity * @mbr: pointer to a legacy mbr structure * * Description: Returns 1 if MBR is valid, 0 otherwise. * Validity depends on one thing: * 1) MSDOS signature is in the last two bytes of the MBR */ static inline int is_mbr_valid(legacy_mbr *mbr) { int ret; if (!mbr) return 0; ret = (mbr->signature == MSDOS_MBR_SIGNATURE); if (!ret) { errno = ENOTTY; efi_error("mbr signature is not MSDOS_MBR_SIGNATURE"); } return ret; }
efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, ...) { ssize_t ret; int saved_errno; va_list ap; va_start(ap, options); ret = efi_va_generate_file_device_path_from_esp(buf, size, devpath, partition, relpath, options, ap); saved_errno = errno; va_end(ap); errno = saved_errno; if (ret < 0) efi_error("could not generate File DP from ESP"); return ret; }
find_file(const char * const filepath, char **devicep, char **relpathp) { struct stat fsb = { 0, }; int rc; int ret = -1; FILE *mounts = NULL; char linkbuf[PATH_MAX+1] = ""; ssize_t linklen = 0; linklen = strlen(filepath); if (linklen > PATH_MAX) { errno = ENAMETOOLONG; efi_error("filepath length exceeds PATH_MAX"); return -1; } strcpy(linkbuf, filepath); do { rc = stat(linkbuf, &fsb); if (rc < 0) return rc; if (S_ISLNK(fsb.st_mode)) { char tmp[PATH_MAX+1] = ""; ssize_t l; l = readlink(linkbuf, tmp, PATH_MAX); if (l < 0) { efi_error("readlink failed"); return -1; } tmp[l] = '\0'; linklen = l; strcpy(linkbuf, tmp); } else { break; } } while (1); mounts = fopen("/proc/self/mounts", "r"); if (mounts == NULL) { efi_error("couldn not open /proc/self/mounts"); return -1; } struct mntent *me; while (1) { struct stat dsb = { 0, }; errno = 0; me = getmntent(mounts); if (!me) { if (feof(mounts)) { errno = ENOENT; efi_error("could not find mountpoint"); } goto err; } if (me->mnt_fsname[0] != '/') continue; rc = stat(me->mnt_fsname, &dsb); if (rc < 0) { if (errno == ENOENT) continue; efi_error("could not stat mountpoint"); goto err; } if (!S_ISBLK(dsb.st_mode)) continue; if (dsb.st_rdev == fsb.st_dev) { ssize_t mntlen = strlen(me->mnt_dir); if (mntlen >= linklen) continue; if (strncmp(linkbuf, me->mnt_dir, mntlen)) continue; *devicep = strdup(me->mnt_fsname); if (!*devicep) { errno = ENOMEM; efi_error("strdup failed"); goto err; } *relpathp = strdup(linkbuf + mntlen); if (!*relpathp) { free(*devicep); *devicep = NULL; errno = ENOMEM; efi_error("strdup failed"); goto err; } ret = 0; break; } } err: if (mounts) endmntent(mounts); return ret; }
ssize_t efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, va_list ap) { int rc; ssize_t ret = -1, off=0, sz; struct disk_info info = { 0, }; int fd = -1; int saved_errno; fd = open(devpath, O_RDONLY); if (fd < 0) { efi_error("could not open device for ESP"); goto err; } rc = eb_disk_info_from_fd(fd, &info); if (rc < 0 && errno != ENOSYS) { efi_error("could not get ESP disk info"); goto err; } if (partition > 0) info.part = partition; if (options & EFIBOOT_ABBREV_EDD10) { va_list aq; va_copy(aq, ap); info.edd10_devicenum = va_arg(aq, uint32_t); va_end(aq); } if ((options & EFIBOOT_ABBREV_EDD10) && (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD))) { sz = efidp_make_edd10(buf, size, info.edd10_devicenum); if (sz < 0) { efi_error("could not make EDD 1.0 device path"); return -1; } off = sz; } else if (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD)) { /* * We're probably on a modern kernel, so just parse the * symlink from /sys/dev/block/$major:$minor and get it * from there. */ sz = make_blockdev_path(buf, size, &info); if (sz < 0) { efi_error("could not create device path"); return -1; } off += sz; } if (!(options & EFIBOOT_ABBREV_FILE)) { int disk_fd; int saved_errno; int rc; rc = set_disk_and_part_name(&info); if (rc < 0) { efi_error("could not set disk and partition name"); goto err; } disk_fd = open_disk(&info, (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE) ? O_RDWR : O_RDONLY); if (disk_fd < 0) { efi_error("could not open disk"); goto err; } sz = make_hd_dn(buf, size, off, disk_fd, info.part, options); saved_errno = errno; close(disk_fd); errno = saved_errno; if (sz < 0) { efi_error("could not make HD() DP node"); goto err; } off += sz; } char *filepath = strdupa(relpath); tilt_slashes(filepath); sz = efidp_make_file(buf+off, size?size-off:0, filepath); if (sz < 0) { efi_error("could not make File() DP node"); goto err; } off += sz; sz = efidp_make_end_entire(buf+off, size?size-off:0); if (sz < 0) { efi_error("could not make EndEntire DP node"); goto err; } off += sz; ret = off; err: saved_errno = errno; if (info.disk_name) { free(info.disk_name); info.disk_name = NULL; } if (info.part_name) { free(info.part_name); info.part_name = NULL; } if (fd >= 0) close(fd); errno = saved_errno; return ret; }