#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: getvars.c,v 1.2 2025/03/02 00:03:41 riastradh Exp $");
#endif
#include <sys/efiio.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#include "defs.h"
#include "efiio.h"
#include "getvars.h"
#include "utils.h"
typedef SLIST_HEAD(efi_var_head, efi_var_elm) efi_var_head_t;
typedef struct efi_var_elm {
efi_var_t v;
SLIST_ENTRY(efi_var_elm) entry;
} efi_var_elm_t;
typedef efi_var_head_t getvars_hdl_t;
struct fn_args {
efi_var_head_t *list_head;
regex_t preg;
char *name;
};
static void
efi_var_cpy(efi_var_ioc_t *dst, efi_var_ioc_t *src)
{
dst->name = memdup(src->name, src->namesize);
dst->namesize = src->namesize;
dst->vendor = src->vendor;
dst->attrib = src->attrib;
dst->data = src->data;
dst->datasize = src->datasize;
src->data = NULL;
src->datasize = 0;
}
static int
var_name_cmp(const void *a, const void *b)
{
efi_var_t *x = *(efi_var_t * const *)a;
efi_var_t *y = *(efi_var_t * const *)b;
int rv;
rv = strcmp(x->name, y->name);
if (rv != 0)
return rv;
return memcmp(&y->ev.vendor, &x->ev.vendor, sizeof(x->ev.vendor));
}
static int
save_variable(efi_var_ioc_t *ev, void *vp)
{
struct fn_args *args = vp;
efi_var_head_t *head = args->list_head;
efi_var_elm_t *elm;
assert(args->name != NULL);
elm = ecalloc(sizeof(*elm), 1);
efi_var_cpy(&elm->v.ev, ev);
elm->v.name = args->name;
args->name = NULL;
SLIST_INSERT_HEAD(head, elm, entry);
return 0;
}
static bool
choose_variable(efi_var_ioc_t *ev, void *vp)
{
struct fn_args *args = vp;
bool rv;
args->name = ucs2_to_utf8(ev->name, ev->namesize, NULL, NULL);
rv = !regexec(&args->preg, args->name, 0, NULL, 0);
if (rv == false) {
free(args->name);
args->name = NULL;
}
return rv;
}
PUBLIC void *
get_variables(int fd, const char *regexp, efi_var_t ***array_ptr,
size_t *array_cnt)
{
static efi_var_head_t list_head;
efi_var_elm_t *elm;
efi_var_t **var_array;
size_t var_cnt;
int i;
struct fn_args args;
assert(SLIST_EMPTY(&list_head));
SLIST_INIT(&list_head);
memset(&args, 0, sizeof(args));
args.list_head = &list_head;
if (regcomp(&args.preg, regexp, REG_EXTENDED) != 0)
err(EXIT_FAILURE, "regcomp: %s", regexp);
var_cnt = get_variable_info(fd, choose_variable, save_variable, &args);
regfree(&args.preg);
var_array = emalloc(var_cnt * sizeof(*var_array));
i = 0;
SLIST_FOREACH(elm, &list_head, entry) {
var_array[i++] = &elm->v;
}
qsort(var_array, var_cnt, sizeof(*var_array), var_name_cmp);
*array_ptr = var_array;
*array_cnt = var_cnt;
return &list_head;
}
static void
free_efi_var_ioc(efi_var_ioc_t *ev)
{
free(ev->name);
free(ev->data);
memset(ev, 0, sizeof(*ev));
}
static void
free_efi_var(efi_var_t *v)
{
free(v->name);
memset(v, 0, sizeof(*v));
}
PUBLIC void
free_variables(void *vp)
{
efi_var_head_t *list_head = vp;
efi_var_elm_t *elm;
while (!SLIST_EMPTY(list_head)) {
elm = SLIST_FIRST(list_head);
SLIST_REMOVE_HEAD(list_head, entry);
free_efi_var_ioc(&elm->v.ev);
free_efi_var(&elm->v);
free(elm);
}
}