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