#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: efiio.c,v 1.4 2025/03/30 14:36:48 riastradh Exp $");
#endif
#include <sys/efiio.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <util.h>
#include "defs.h"
#include "efiio.h"
#include "utils.h"
#if 0
struct efi_var_ioc {
uint16_t * name;
size_t namesize;
struct uuid vendor;
uint32_t attrib;
void * data;
size_t datasize;
};
#endif
static int
xioctl(int fd, unsigned long request, void *buf)
{
int rv;
rv = ioctl(fd, request, buf);
if (rv == -1 && errno != ENOENT)
err(EXIT_FAILURE, "%s: ioctl", __func__);
return rv;
}
PUBLIC int
set_variable(int fd, struct efi_var_ioc *ev)
{
return ioctl(fd, EFIIOC_VAR_SET, ev);
}
static inline int
get_variable_core(int fd, struct efi_var_ioc *ev)
{
if (xioctl(fd, EFIIOC_VAR_GET, ev) == -1)
return -1;
ev->data = emalloc(ev->datasize);
xioctl(fd, EFIIOC_VAR_GET, ev);
return 0;
}
PUBLIC struct efi_var_ioc
get_variable(int fd, const char *name, struct uuid *vendor,
uint32_t attrib)
{
struct efi_var_ioc ev;
efi_var_init(&ev, name, vendor, attrib);
get_variable_core(fd, &ev);
return ev;
}
PUBLIC struct efi_var_ioc *
get_next_variable(int fd, struct efi_var_ioc *ev)
{
int rv;
rv = ioctl(fd, EFIIOC_VAR_NEXT, ev);
if (rv == -1 && errno != ENOENT)
err(EXIT_FAILURE, "%s: ioctl", __func__);
return ev;
}
PUBLIC void *
get_table(int fd, struct uuid *uuid, size_t *buflen)
{
struct efi_get_table_ioc egt;
memset(&egt, 0, sizeof(egt));
memcpy(&egt.uuid, uuid, sizeof(egt.uuid));
xioctl(fd, EFIIOC_GET_TABLE, &egt);
egt.buf = ecalloc(egt.table_len, 1);
egt.buf_len = egt.table_len;
xioctl(fd, EFIIOC_GET_TABLE, &egt);
*buflen = egt.table_len;
return egt.buf;
}
PUBLIC size_t
get_variable_info(int fd, bool (*choose)(struct efi_var_ioc *, void *),
int (*fn)(struct efi_var_ioc *ev, void *), void *arg)
{
struct efi_var_ioc ev;
size_t cnt;
int rv;
assert(fn != NULL);
assert(arg != NULL);
memset(&ev, 0, sizeof(ev));
ev.name = ecalloc(EFI_VARNAME_MAXBYTES, 1);
cnt = 0;
for (;;) {
ev.namesize = EFI_VARNAME_MAXBYTES;
if (ioctl(fd, EFIIOC_VAR_NEXT, &ev) == -1) {
char *buf;
if (errno == ENOENT)
break;
buf = ucs2_to_utf8(ev.name, ev.namesize, NULL, NULL);
err(EXIT_FAILURE, "%s: '%s'", __func__, buf);
}
if (choose != NULL && !choose(&ev, arg))
continue;
rv = get_variable_core(fd, &ev);
assert(rv == 0);
if (rv == -1)
err(EXIT_FAILURE, "get_variable_core");
cnt++;
fn(&ev, arg);
free(ev.data);
}
free(ev.name);
return cnt;
}