getvars.c revision 1.1 1 /* $NetBSD: getvars.c,v 1.1 2025/02/24 13:47:56 christos 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.1 2025/02/24 13:47:56 christos 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