Home | History | Annotate | Line # | Download | only in efi
      1 /* $NetBSD: getvars.c,v 1.2 2025/03/02 00:03:41 riastradh Exp $ */
      2 
      3 /*
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     14  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     23  * SUCH DAMAGE.
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 #ifndef lint
     28 __RCSID("$NetBSD: getvars.c,v 1.2 2025/03/02 00:03:41 riastradh Exp $");
     29 #endif /* not lint */
     30 
     31 #include <sys/efiio.h>
     32 #include <sys/queue.h>
     33 
     34 #include <assert.h>
     35 #include <err.h>
     36 #include <regex.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <util.h>
     41 
     42 #include "defs.h"
     43 #include "efiio.h"
     44 #include "getvars.h"
     45 #include "utils.h"
     46 
     47 typedef SLIST_HEAD(efi_var_head, efi_var_elm) efi_var_head_t;
     48 
     49 typedef struct efi_var_elm {
     50 	efi_var_t	v;
     51 	SLIST_ENTRY(efi_var_elm) entry;
     52 } efi_var_elm_t;
     53 
     54 typedef efi_var_head_t getvars_hdl_t;
     55 
     56 struct fn_args {
     57 	efi_var_head_t *list_head;
     58 	regex_t preg;
     59 	char *name;
     60 };
     61 
     62 /****************************************/
     63 static void
     64 efi_var_cpy(efi_var_ioc_t *dst, efi_var_ioc_t *src)
     65 {
     66 
     67 	dst->name     = memdup(src->name, src->namesize);
     68 	dst->namesize = src->namesize;
     69 	dst->vendor   = src->vendor;
     70 	dst->attrib   = src->attrib;
     71 
     72 	/* do not dup the data buffer */
     73 	dst->data     = src->data;
     74 	dst->datasize = src->datasize;
     75 	src->data = NULL;
     76 	src->datasize = 0;
     77 }
     78 
     79 /****************************************/
     80 
     81 static int
     82 var_name_cmp(const void *a, const void *b)
     83 {
     84 	efi_var_t *x = *(efi_var_t * const *)a;
     85 	efi_var_t *y = *(efi_var_t * const *)b;
     86 	int rv;
     87 
     88 	rv = strcmp(x->name, y->name);
     89 	if (rv != 0)
     90 		return rv;
     91 
     92 	return memcmp(&y->ev.vendor, &x->ev.vendor, sizeof(x->ev.vendor));
     93 }
     94 
     95 /****************************************/
     96 
     97 static int
     98 save_variable(efi_var_ioc_t *ev, void *vp)
     99 {
    100 	struct fn_args *args = vp;
    101 	efi_var_head_t *head = args->list_head;
    102 	efi_var_elm_t *elm;
    103 
    104 	assert(args->name != NULL);
    105 
    106 	elm = ecalloc(sizeof(*elm), 1);
    107 	efi_var_cpy(&elm->v.ev, ev);
    108 
    109 	elm->v.name = args->name;
    110 
    111 	args->name = NULL;
    112 
    113 	SLIST_INSERT_HEAD(head, elm, entry);
    114 
    115 	return 0;
    116 }
    117 
    118 static bool
    119 choose_variable(efi_var_ioc_t *ev, void *vp)
    120 {
    121 	struct fn_args *args = vp;
    122 	bool rv;
    123 
    124 	args->name = ucs2_to_utf8(ev->name, ev->namesize, NULL, NULL);
    125 
    126 	rv = !regexec(&args->preg, args->name, 0, NULL, 0);
    127 	if (rv == false) {
    128 		free(args->name);
    129 		args->name = NULL;
    130 	}
    131 	return rv;
    132 }
    133 
    134 PUBLIC void *
    135 get_variables(int fd, const char *regexp, efi_var_t ***array_ptr,
    136     size_t *array_cnt)
    137 {
    138 	static efi_var_head_t list_head;
    139 	efi_var_elm_t *elm;
    140 	efi_var_t **var_array;
    141 	size_t var_cnt;
    142 	int i;
    143 	struct fn_args args;
    144 
    145 	assert(SLIST_EMPTY(&list_head));
    146 
    147 	SLIST_INIT(&list_head);
    148 
    149 	memset(&args, 0, sizeof(args));
    150 	args.list_head = &list_head;
    151 	if (regcomp(&args.preg, regexp, REG_EXTENDED) != 0)
    152 		err(EXIT_FAILURE, "regcomp: %s", regexp);
    153 
    154 	var_cnt = get_variable_info(fd, choose_variable, save_variable, &args);
    155 
    156 	regfree(&args.preg);
    157 
    158 	var_array = emalloc(var_cnt * sizeof(*var_array));
    159 	i = 0;
    160 	SLIST_FOREACH(elm, &list_head, entry) {
    161 		var_array[i++] = &elm->v;
    162 	}
    163 	qsort(var_array, var_cnt, sizeof(*var_array), var_name_cmp);
    164 
    165 	*array_ptr = var_array;
    166 	*array_cnt = var_cnt;
    167 
    168 	return &list_head;
    169 }
    170 
    171 static void
    172 free_efi_var_ioc(efi_var_ioc_t *ev)
    173 {
    174 
    175 	free(ev->name);
    176 	free(ev->data);
    177 	memset(ev, 0, sizeof(*ev));
    178 }
    179 
    180 static void
    181 free_efi_var(efi_var_t *v)
    182 {
    183 
    184 	free(v->name);
    185 	memset(v, 0, sizeof(*v));
    186 }
    187 
    188 PUBLIC void
    189 free_variables(void *vp)
    190 {
    191 	efi_var_head_t *list_head = vp;
    192 	efi_var_elm_t *elm;
    193 
    194 	while (!SLIST_EMPTY(list_head)) {
    195 		elm = SLIST_FIRST(list_head);
    196 		SLIST_REMOVE_HEAD(list_head, entry);
    197 		free_efi_var_ioc(&elm->v.ev);
    198 		free_efi_var(&elm->v);
    199 		free(elm);
    200 	}
    201 }
    202