/* $NetBSD: getvars.c,v 1.1 2025/02/24 13:47:56 christos Exp $ */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: getvars.c,v 1.1 2025/02/24 13:47:56 christos Exp $"); #endif /* not lint */ #include #include #include #include #include #include #include #include #include #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; /* do not dup the data buffer */ 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); } }