main.c revision 1.4 1 1.4 riastrad /* $NetBSD: main.c,v 1.4 2025/03/02 00:03:41 riastradh Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Redistribution and use in source and binary forms, with or without
5 1.1 christos * modification, are permitted provided that the following conditions
6 1.1 christos * are met:
7 1.1 christos * 1. Redistributions of source code must retain the above copyright
8 1.1 christos * notice, this list of conditions and the following disclaimer.
9 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
10 1.1 christos * notice, this list of conditions and the following disclaimer in the
11 1.1 christos * documentation and/or other materials provided with the distribution.
12 1.1 christos *
13 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 1.1 christos * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 1.1 christos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 1.1 christos * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 1.1 christos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 1.1 christos * SUCH DAMAGE.
24 1.1 christos */
25 1.1 christos
26 1.1 christos #include <sys/cdefs.h>
27 1.1 christos #ifndef lint
28 1.4 riastrad __RCSID("$NetBSD: main.c,v 1.4 2025/03/02 00:03:41 riastradh Exp $");
29 1.1 christos #endif /* not lint */
30 1.1 christos
31 1.1 christos #include <sys/efiio.h>
32 1.1 christos #include <sys/queue.h>
33 1.1 christos
34 1.1 christos #include <assert.h>
35 1.1 christos #include <ctype.h>
36 1.1 christos #include <err.h>
37 1.1 christos #include <errno.h>
38 1.1 christos #include <fcntl.h>
39 1.1 christos #include <getopt.h>
40 1.1 christos #include <inttypes.h>
41 1.1 christos #include <limits.h>
42 1.1 christos #include <regex.h>
43 1.1 christos #include <stdbool.h>
44 1.1 christos #include <stdio.h>
45 1.1 christos #include <stdlib.h>
46 1.1 christos #include <string.h>
47 1.1 christos #include <time.h>
48 1.1 christos #include <util.h>
49 1.1 christos
50 1.1 christos #include "efiio.h"
51 1.1 christos #include "defs.h"
52 1.1 christos #include "bootvar.h"
53 1.1 christos #include "devpath.h"
54 1.1 christos #include "getvars.h"
55 1.1 christos #include "gptsubr.h"
56 1.1 christos #include "map.h"
57 1.1 christos #include "setvar.h"
58 1.1 christos #include "showvar.h"
59 1.1 christos #include "utils.h"
60 1.1 christos
61 1.1 christos /*
62 1.1 christos * The UEFI spec is quite clear that it is intended for little endian
63 1.1 christos * machines only. As a result (and lazyness), byte ordering is
64 1.1 christos * ignored in this code and we build/run only on little endian
65 1.1 christos * machines.
66 1.1 christos */
67 1.1 christos __CTASSERT(_BYTE_ORDER == _LITTLE_ENDIAN);
68 1.1 christos
69 1.1 christos #define _PATH_EFI "/dev/efi" /* XXX: should be in <paths.h> */
70 1.1 christos
71 1.1 christos #define DEFAULT_PARTITION 1
72 1.1 christos #define DEFAULT_LABEL "NetBSD"
73 1.1 christos #define DEFAULT_LOADER "\\EFI\\NetBSD\\grubx64.efi"
74 1.1 christos #define DEFAULT_DEVICE parent_of_fname(".")
75 1.1 christos
76 1.1 christos /****************************************/
77 1.1 christos
78 1.1 christos static uint __used
79 1.1 christos get_max_namelen(efi_var_t **var_array, size_t var_cnt)
80 1.1 christos {
81 1.1 christos uint max_len = 0;
82 1.1 christos
83 1.1 christos for (size_t i = 0; i < var_cnt; i++) {
84 1.1 christos uint len = (uint)strlen(var_array[i]->name);
85 1.1 christos if (len > max_len)
86 1.1 christos max_len = len;
87 1.1 christos }
88 1.1 christos return max_len;
89 1.1 christos }
90 1.1 christos
91 1.1 christos /************************************************************************/
92 1.1 christos
93 1.1 christos enum {
94 1.1 christos OPT_BRIEF = UCHAR_MAX + 1,
95 1.1 christos OPT_DEBUG = UCHAR_MAX + 2,
96 1.1 christos };
97 1.1 christos
98 1.1 christos #define OPTIONS "@:A::a::B::b:CcDd:FfG::hL:l:Nn:Oo:p:qR:rTt:Vvw::X:x:y"
99 1.1 christos #define OPTION_LIST \
100 1.1 christos _X("brief", _NA, OPT_BRIEF, "set brief mode") \
101 1.1 christos _X("debug", _OA, OPT_DEBUG, "raise or set the debug level") \
102 1.1 christos _X("append-binary-args",_RA, '@', "Append extra variable args from file") \
103 1.1 christos _X("inactive", _OA, 'A', "clear active bit on '-b' variable") \
104 1.1 christos _X("active", _OA, 'a', "set active bit on '-b' variable") \
105 1.1 christos _X("delete-bootnum", _OA, 'B', "delete '-b' variable or arg") \
106 1.1 christos _X("bootnum", _RA, 'b', "specify a boot number") \
107 1.1 christos _X("create-only", _NA, 'C', "create a new boot variable") \
108 1.1 christos _X("create", _NA, 'c', "create a new boot variable and prefix BootOrder") \
109 1.1 christos _X("remove-dups", _NA, 'D', "remove duplicates in BootOrder") \
110 1.1 christos _X("disk", _RA, 'd', "specify disk device") \
111 1.1 christos _X("no-reconnect", _NA, 'F', "do not force driver reconnect after loading (requires '-r')") \
112 1.1 christos _X("reconnect", _NA, 'f', "force driver reconnect after loading (requires '-r')") \
113 1.1 christos _X("show-gpt", _OA, 'G', "show GPT for device") \
114 1.1 christos _X("help", _NA, 'h', "this help") \
115 1.1 christos _X("label", _RA, 'L', "specify boot label") \
116 1.1 christos _X("loader", _RA, 'l', "specify boot loader on EFI partition") \
117 1.1 christos _X("delete-bootnext", _NA, 'N', "delete NextBoot variable") \
118 1.1 christos _X("bootnext", _RA, 'n', "set NextBoot variable") \
119 1.1 christos _X("delete-bootorder", _NA, 'O', "delete BootOrder entirely") \
120 1.1 christos _X("bootorder", _RA, 'o', "set BootOrder") \
121 1.1 christos _X("part", _RA, 'p', "specify partition number") \
122 1.1 christos _X("quiet", _NA, 'q', "quiet mode") \
123 1.1 christos _X("regexp", _RA, 'R', "regular expression for variable search (default: '^Boot')") \
124 1.1 christos _X("driver", _NA, 'r', "operate on Driver#### instead of Boot####") \
125 1.1 christos _X("delete-timeout", _NA, 'T', "delete timeout") \
126 1.1 christos _X("timeout", _RA, 't', "set timeout to argument, in seconds") \
127 1.1 christos _X("version", _NA, 'V', "show Version") \
128 1.1 christos _X("verbose", _NA, 'v', "increment verboseness") \
129 1.1 christos _X("write-signature", _OA, 'w', "write MBR signature") \
130 1.1 christos _X("remove-bootorder", _RA, 'X', "remove argument from BootOrder") \
131 1.1 christos _X("prefix-bootorder", _RA, 'x', "prefix argument to BootOrder") \
132 1.1 christos _X("sysprep", _NA, 'y', "operate on SysPrep#### instead of Boot####")
133 1.1 christos
134 1.1 christos #define TARGET_BOOT "Boot"
135 1.1 christos #define TARGET_DRIVER "Driver"
136 1.1 christos #define TARGET_SYSPREP "SysPrep"
137 1.1 christos
138 1.1 christos #define IS_TARGET_DRIVER(opt) ((opt).target[0] == TARGET_DRIVER[0])
139 1.1 christos
140 1.1 christos #define ACTION_LIST \
141 1.1 christos _X(active, NULL) \
142 1.1 christos _X(create, NULL) \
143 1.1 christos _X(delete, NULL) \
144 1.1 christos _X(del_bootnext, del_bootnext) \
145 1.1 christos _X(set_bootnext, set_bootnext) \
146 1.1 christos _X(del_bootorder, del_bootorder) \
147 1.1 christos _X(set_bootorder, set_bootorder) \
148 1.1 christos _X(prefix_bootorder, prefix_bootorder) \
149 1.1 christos _X(remove_bootorder, remove_bootorder) \
150 1.1 christos _X(del_bootorder_dups, del_bootorder_dups) \
151 1.1 christos _X(set_timeout, set_timeout) \
152 1.1 christos _X(show, NULL) \
153 1.1 christos _X(show_gpt, show_gpt)
154 1.1 christos
155 1.2 christos static void __dead __printflike(1, 2)
156 1.1 christos usage(const char *fmt, ...)
157 1.1 christos {
158 1.1 christos const char *progname = getprogname();
159 1.1 christos struct {
160 1.1 christos const char *help;
161 1.1 christos const char *name;
162 1.1 christos int opt;
163 1.1 christos } tbl[] = {
164 1.1 christos #define _NA ""
165 1.1 christos #define _OA "[=arg]"
166 1.1 christos #define _RA "=<arg>"
167 1.1 christos #define _X(n,a,o,m) { .name = n a, .opt = o, .help = m, },
168 1.1 christos OPTION_LIST
169 1.1 christos #undef _X
170 1.1 christos #undef _RA
171 1.1 christos #undef _OA
172 1.1 christos #undef _NA
173 1.1 christos };
174 1.1 christos
175 1.1 christos if (fmt != NULL) {
176 1.1 christos va_list ap;
177 1.4 riastrad
178 1.1 christos va_start(ap, fmt);
179 1.1 christos vfprintf(stderr, fmt, ap);
180 1.1 christos va_end(ap);
181 1.1 christos }
182 1.1 christos
183 1.1 christos printf("%s version %u\n", progname, VERSION);
184 1.1 christos printf("Usage: %s [options]\n", progname);
185 1.1 christos for (size_t i = 0; i < __arraycount(tbl); i++) {
186 1.1 christos int n;
187 1.1 christos if (isprint(tbl[i].opt))
188 1.1 christos n = printf("-%c | --%s", tbl[i].opt, tbl[i].name);
189 1.1 christos else
190 1.1 christos n = printf(" --%s", tbl[i].name);
191 1.1 christos printf("%*s %s\n", 32 - n, "", tbl[i].help);
192 1.1 christos }
193 1.1 christos exit(EXIT_SUCCESS);
194 1.1 christos }
195 1.1 christos
196 1.1 christos static int __used
197 1.1 christos append_optional_data(const char *fname, efi_var_ioc_t *ev)
198 1.1 christos {
199 1.1 christos char *buf, *cp;
200 1.1 christos size_t cnt;
201 1.1 christos
202 1.1 christos buf = read_file(fname, &cnt);
203 1.1 christos
204 1.1 christos ev->data = erealloc(ev->data, ev->datasize + cnt);
205 1.1 christos cp = ev->data;
206 1.1 christos cp += ev->datasize;
207 1.1 christos memcpy(cp, buf, cnt);
208 1.1 christos ev->datasize += cnt;
209 1.1 christos
210 1.1 christos return 0;
211 1.1 christos }
212 1.1 christos
213 1.1 christos typedef enum {
214 1.1 christos MBR_SIG_WRITE_NEVER = 0,
215 1.1 christos MBR_SIG_WRITE_MAYBE,
216 1.1 christos MBR_SIG_WRITE_FORCE,
217 1.1 christos } mbr_sig_write_t;
218 1.1 christos
219 1.1 christos #define OPT_LIST \
220 1.1 christos _X(bool, active, false ) \
221 1.1 christos _X(bool, b_flag, false ) \
222 1.1 christos _X(bool, brief, false ) \
223 1.1 christos _X(bool, prefix_bootorder, false ) \
224 1.1 christos _X(bool, quiet, false ) \
225 1.1 christos _X(bool, reconnect, false ) \
226 1.1 christos _X(char *, bootorder, NULL ) \
227 1.1 christos _X(char *, csus, NULL ) \
228 1.1 christos _X(char *, device, NULL ) \
229 1.1 christos _X(char *, opt_fname, NULL ) \
230 1.1 christos _X(char *, regexp, NULL ) \
231 1.1 christos _X(const char *, label, DEFAULT_LABEL ) \
232 1.1 christos _X(const char *, loader, DEFAULT_LOADER ) \
233 1.1 christos _X(const char *, target, NULL ) \
234 1.1 christos _X(int, verbose, 0 ) \
235 1.3 jakllsch _X(uint, debug, 0 ) \
236 1.1 christos _X(mbr_sig_write_t, mbr_sig_write, MBR_SIG_WRITE_NEVER ) \
237 1.1 christos _X(uint16_t, bootnum, 0 ) \
238 1.1 christos _X(uint16_t, partnum, DEFAULT_PARTITION ) \
239 1.1 christos _X(uint16_t, timeout, 0 ) \
240 1.1 christos _X(uint32_t, mbr_sig, 0 )
241 1.1 christos
242 1.1 christos #define IS_MBR_SIG_FORCE(o) ((o).mbr_sig_write == MBR_SIG_WRITE_FORCE)
243 1.1 christos
244 1.4 riastrad static struct options { /* setable options */
245 1.1 christos #define _X(t,n,v) t n;
246 1.1 christos OPT_LIST
247 1.1 christos #undef _X
248 1.1 christos } opt = {
249 1.1 christos #define _X(t,n,v) .n = v,
250 1.1 christos OPT_LIST
251 1.1 christos #undef _X
252 1.1 christos };
253 1.1 christos
254 1.1 christos static inline void
255 1.1 christos get_bootnum(struct options *op, const char *oarg)
256 1.1 christos {
257 1.1 christos
258 1.1 christos op->b_flag = true;
259 1.1 christos op->bootnum = strtous(oarg, NULL, 16);
260 1.1 christos }
261 1.1 christos
262 1.1 christos int
263 1.1 christos main(int argc, char **argv)
264 1.1 christos {
265 1.1 christos static struct option longopts[] = {
266 1.1 christos #define _NA no_argument
267 1.1 christos #define _OA optional_argument
268 1.1 christos #define _RA required_argument
269 1.1 christos #define _X(n,a,o,m) { n, a, NULL, o },
270 1.1 christos OPTION_LIST
271 1.1 christos { NULL, 0, NULL, 0 },
272 1.1 christos #undef _X
273 1.1 christos #undef _RA
274 1.1 christos #undef _OA
275 1.1 christos #undef _NA
276 1.1 christos };
277 1.1 christos enum {
278 1.1 christos act_create,
279 1.1 christos act_set_active,
280 1.1 christos act_del_variable,
281 1.1 christos act_del_bootnext,
282 1.1 christos act_set_bootnext,
283 1.1 christos act_del_bootorder,
284 1.1 christos act_set_bootorder,
285 1.1 christos act_prefix_bootorder,
286 1.1 christos act_remove_bootorder,
287 1.1 christos act_del_bootorder_dups,
288 1.1 christos act_set_timeout,
289 1.1 christos act_del_timeout,
290 1.1 christos act_show,
291 1.1 christos act_show_gpt,
292 1.1 christos } action = act_show;
293 1.1 christos efi_var_t **var_array;
294 1.1 christos void *var_hdl;
295 1.1 christos char *fname = NULL;
296 1.1 christos size_t i, var_cnt;
297 1.1 christos int ch, efi_fd;
298 1.1 christos
299 1.1 christos union { /* Just in case the above __CTASSERT() is ignored ... */
300 1.1 christos uint32_t val;
301 1.1 christos uint8_t b[4];
302 1.1 christos } byte_order = { .val = 0x01020304, };
303 1.1 christos if (byte_order.b[0] != 4 ||
304 1.1 christos byte_order.b[1] != 3 ||
305 1.1 christos byte_order.b[2] != 2 ||
306 1.1 christos byte_order.b[3] != 1) {
307 1.1 christos errx(EXIT_FAILURE, "sorry: %s only runs on little-endian machines!",
308 1.1 christos getprogname());
309 1.1 christos }
310 1.1 christos
311 1.1 christos setprogname(argv[0]);
312 1.1 christos
313 1.1 christos optreset = 1;
314 1.1 christos optind = 1;
315 1.1 christos opterr = 1;
316 1.1 christos while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) {
317 1.1 christos switch (ch) {
318 1.1 christos case OPT_BRIEF:
319 1.1 christos opt.brief = true;
320 1.1 christos break;
321 1.1 christos
322 1.1 christos case OPT_DEBUG:
323 1.1 christos if (optarg)
324 1.1 christos opt.debug = strtous(optarg, NULL, 0);
325 1.1 christos else
326 1.1 christos opt.debug++;
327 1.1 christos opt.debug &= DEBUG_MASK;
328 1.1 christos break;
329 1.1 christos
330 1.1 christos case '@':
331 1.1 christos opt.opt_fname = estrdup(optarg);
332 1.1 christos break;
333 1.1 christos
334 1.1 christos case 'A':
335 1.1 christos if (optarg)
336 1.1 christos get_bootnum(&opt, optarg);
337 1.1 christos
338 1.1 christos opt.active = false;
339 1.1 christos action = act_set_active;
340 1.1 christos break;
341 1.1 christos
342 1.1 christos case 'a':
343 1.1 christos if (optarg)
344 1.1 christos get_bootnum(&opt, optarg);
345 1.1 christos
346 1.1 christos opt.active = true;
347 1.1 christos action = act_set_active;
348 1.1 christos break;
349 1.1 christos
350 1.1 christos case 'B':
351 1.1 christos if (optarg)
352 1.1 christos get_bootnum(&opt, optarg);
353 1.1 christos
354 1.1 christos action = act_del_variable;
355 1.1 christos break;
356 1.1 christos
357 1.1 christos case 'b':
358 1.1 christos get_bootnum(&opt, optarg);
359 1.1 christos break;
360 1.1 christos
361 1.1 christos case 'C':
362 1.1 christos opt.prefix_bootorder = false;
363 1.1 christos action = act_create;
364 1.1 christos break;
365 1.1 christos
366 1.1 christos case 'c':
367 1.1 christos opt.prefix_bootorder = true;
368 1.1 christos action = act_create;
369 1.1 christos break;
370 1.1 christos
371 1.1 christos case 'D':
372 1.1 christos action = act_del_bootorder_dups;
373 1.1 christos break;
374 1.1 christos
375 1.1 christos case 'd':
376 1.1 christos opt.device = estrdup(optarg);
377 1.1 christos break;
378 1.1 christos
379 1.1 christos case 'F':
380 1.1 christos opt.reconnect = false;
381 1.1 christos break;
382 1.1 christos
383 1.1 christos case 'f':
384 1.1 christos opt.reconnect = true;
385 1.1 christos break;
386 1.1 christos
387 1.1 christos case 'G':
388 1.1 christos fname = estrdup(optarg ? optarg : ".");
389 1.1 christos action = act_show_gpt;
390 1.1 christos break;
391 1.1 christos
392 1.1 christos case 'L':
393 1.1 christos opt.label = estrdup(optarg);
394 1.1 christos break;
395 1.1 christos
396 1.1 christos case 'l':
397 1.1 christos opt.loader = estrdup(optarg);
398 1.1 christos break;
399 1.1 christos
400 1.1 christos case 'N':
401 1.1 christos action = act_del_bootnext;
402 1.1 christos break;
403 1.1 christos
404 1.1 christos case 'n':
405 1.1 christos opt.b_flag = true;
406 1.1 christos opt.bootnum = strtous(optarg, NULL, 16);
407 1.1 christos action = act_set_bootnext;
408 1.1 christos break;
409 1.1 christos
410 1.1 christos case 'O':
411 1.1 christos action = act_del_bootorder;
412 1.1 christos break;
413 1.1 christos
414 1.1 christos case 'o':
415 1.1 christos opt.bootorder = estrdup(optarg);
416 1.1 christos action = act_set_bootorder;
417 1.1 christos break;
418 1.1 christos
419 1.1 christos case 'p':
420 1.1 christos opt.partnum = strtous(optarg, NULL, 0);
421 1.1 christos break;
422 1.1 christos
423 1.1 christos case 'R':
424 1.1 christos if (opt.regexp != NULL)
425 1.1 christos free(opt.regexp);
426 1.1 christos opt.regexp = estrdup(optarg);
427 1.1 christos break;
428 1.1 christos
429 1.1 christos case 'r':
430 1.1 christos if (opt.target != NULL)
431 1.1 christos errx(EXIT_FAILURE,
432 1.1 christos "only one of '-r' or '-y' are allowed");
433 1.1 christos opt.target = TARGET_DRIVER;
434 1.1 christos break;
435 1.1 christos
436 1.1 christos case 'T':
437 1.1 christos action = act_del_timeout;
438 1.1 christos break;
439 1.1 christos
440 1.1 christos case 't':
441 1.1 christos opt.timeout = strtous(optarg, NULL, 0);
442 1.1 christos action = act_set_timeout;
443 1.1 christos break;
444 1.1 christos
445 1.1 christos case 'q':
446 1.1 christos opt.quiet = true;
447 1.1 christos opt.verbose = 0;
448 1.1 christos break;
449 1.1 christos
450 1.1 christos case 'V':
451 1.1 christos printf("version: %u\n", VERSION);
452 1.1 christos exit(EXIT_SUCCESS);
453 1.1 christos
454 1.1 christos case 'v':
455 1.1 christos opt.verbose++;
456 1.1 christos opt.brief = false;
457 1.1 christos break;
458 1.1 christos
459 1.1 christos case 'w':
460 1.1 christos if (optarg != NULL) {
461 1.1 christos opt.mbr_sig_write = MBR_SIG_WRITE_FORCE;
462 1.1 christos opt.mbr_sig = (uint32_t)estrtou(optarg, 0, 0, 0xffffffff);
463 1.1 christos }
464 1.1 christos else {
465 1.1 christos opt.mbr_sig_write = MBR_SIG_WRITE_MAYBE;
466 1.1 christos srandom((uint)time(NULL));
467 1.1 christos opt.mbr_sig = (uint32_t)random();
468 1.1 christos }
469 1.1 christos break;
470 1.1 christos
471 1.1 christos case 'X':
472 1.1 christos action = act_remove_bootorder;
473 1.1 christos if (opt.csus != NULL) {
474 1.1 christos usage("Comma Separated Hex list already specified!\n");
475 1.1 christos }
476 1.1 christos opt.csus = estrdup(optarg);
477 1.1 christos break;
478 1.1 christos
479 1.1 christos case 'x':
480 1.1 christos action = act_prefix_bootorder;
481 1.1 christos if (opt.csus != NULL) {
482 1.1 christos usage("Comma Separated Hex list already specified!\n");
483 1.1 christos }
484 1.1 christos opt.csus = estrdup(optarg);
485 1.1 christos break;
486 1.1 christos
487 1.1 christos case 'y':
488 1.1 christos if (opt.target != NULL)
489 1.1 christos errx(EXIT_FAILURE,
490 1.1 christos "only one of '-r' or '-y' are allowed");
491 1.1 christos opt.target = TARGET_SYSPREP;
492 1.1 christos break;
493 1.1 christos
494 1.1 christos case 'h':
495 1.1 christos usage(NULL);
496 1.1 christos default:
497 1.1 christos usage("unknown option: '%c'\n", ch);
498 1.1 christos }
499 1.1 christos }
500 1.1 christos if (opt.target == NULL)
501 1.1 christos opt.target = TARGET_BOOT;
502 1.1 christos
503 1.1 christos argv += optind;
504 1.1 christos argc -= optind;
505 1.1 christos
506 1.1 christos if (argc != 0)
507 1.1 christos usage(NULL);
508 1.1 christos
509 1.1 christos /*
510 1.1 christos * Check some option requirements/overrides here.
511 1.1 christos */
512 1.1 christos if (opt.quiet)
513 1.1 christos opt.verbose = 0;
514 1.1 christos
515 1.1 christos switch (action) {
516 1.1 christos case act_create:
517 1.1 christos if (opt.regexp != NULL) {/* override any previous setting */
518 1.1 christos printf("Ignoring specified regexp: '%s'\n",
519 1.1 christos opt.regexp);
520 1.1 christos free(opt.regexp);
521 1.1 christos }
522 1.1 christos break;
523 1.1 christos
524 1.1 christos case act_show_gpt:
525 1.1 christos return show_gpt(fname, opt.verbose);
526 1.1 christos
527 1.1 christos case act_set_active:
528 1.1 christos case act_del_variable:
529 1.1 christos if (!opt.b_flag)
530 1.1 christos usage("please specify a boot number\n");
531 1.1 christos /*FALLTHROUGH*/
532 1.1 christos default:
533 1.1 christos if (opt.mbr_sig_write) {
534 1.1 christos /*
535 1.1 christos * This overrides all but act_create and
536 1.1 christos * act_show_gpt.
537 1.1 christos */
538 1.1 christos return mbr_sig_write(opt.device, opt.mbr_sig,
539 1.1 christos IS_MBR_SIG_FORCE(opt), opt.verbose);
540 1.1 christos }
541 1.1 christos break;
542 1.1 christos }
543 1.1 christos
544 1.1 christos efi_fd = open(_PATH_EFI, O_RDONLY);
545 1.1 christos if (efi_fd == -1)
546 1.1 christos err(EXIT_FAILURE, "open");
547 1.1 christos
548 1.1 christos switch (action) {
549 1.1 christos case act_del_bootorder_dups: return del_bootorder_dups(efi_fd, opt.target);
550 1.1 christos case act_del_bootorder: return del_bootorder(efi_fd, opt.target);
551 1.1 christos case act_del_bootnext: return del_bootnext(efi_fd);
552 1.1 christos case act_del_timeout: return del_timeout(efi_fd);
553 1.1 christos case act_del_variable: return del_variable(efi_fd, opt.target, opt.bootnum);
554 1.1 christos
555 1.1 christos case act_set_active: return set_active(efi_fd, opt.target, opt.bootnum, opt.active);
556 1.1 christos case act_set_bootnext: return set_bootnext(efi_fd, opt.bootnum);
557 1.1 christos case act_set_bootorder: return set_bootorder(efi_fd, opt.target, opt.bootorder);
558 1.1 christos case act_set_timeout: return set_timeout(efi_fd, opt.timeout);
559 1.1 christos
560 1.1 christos case act_remove_bootorder: return remove_bootorder(efi_fd, opt.target, opt.csus, 0);
561 1.1 christos case act_prefix_bootorder: return prefix_bootorder(efi_fd, opt.target, opt.csus, 0);
562 1.1 christos
563 1.1 christos case act_show_gpt: assert(0); break; /* handled above */
564 1.1 christos default: break;
565 1.1 christos }
566 1.4 riastrad
567 1.1 christos /*
568 1.1 christos * The following actions are handled below and require a call
569 1.1 christos * to get_variables() using a regexp. Setup the regexp here.
570 1.1 christos * XXX: merge with above switch()?
571 1.1 christos */
572 1.1 christos switch (action) {
573 1.1 christos case act_create:
574 1.1 christos easprintf(&opt.regexp, "^%s[0-9,A-F]{4}$", opt.target);
575 1.1 christos break;
576 1.1 christos
577 1.1 christos case act_show:
578 1.1 christos default:
579 1.1 christos if (opt.regexp != NULL)
580 1.1 christos break;
581 1.1 christos
582 1.1 christos if (opt.b_flag)
583 1.1 christos easprintf(&opt.regexp, "^%s%04X$", opt.target, opt.bootnum);
584 1.1 christos else
585 1.1 christos easprintf(&opt.regexp, "^%s", opt.target);
586 1.1 christos break;
587 1.1 christos }
588 1.1 christos
589 1.1 christos var_hdl = get_variables(efi_fd, opt.regexp, &var_array, &var_cnt);
590 1.1 christos
591 1.1 christos free(opt.regexp);
592 1.1 christos opt.regexp = NULL;
593 1.1 christos
594 1.1 christos /*
595 1.1 christos * preform the remaining actions.
596 1.1 christos */
597 1.1 christos switch (action) {
598 1.1 christos case act_create: {
599 1.1 christos uint16_t bootnum;
600 1.1 christos efi_var_t v;
601 1.1 christos uint32_t attrib;
602 1.1 christos int rv;
603 1.1 christos
604 1.1 christos if (opt.device == NULL) {
605 1.1 christos opt.device = DEFAULT_DEVICE;
606 1.1 christos if (opt.device == NULL)
607 1.1 christos errx(EXIT_FAILURE, "specify disk with '-d'");
608 1.1 christos }
609 1.1 christos attrib = LOAD_OPTION_ACTIVE;
610 1.1 christos if (opt.reconnect && IS_TARGET_DRIVER(opt))
611 1.1 christos attrib |= LOAD_OPTION_FORCE_RECONNECT;
612 1.1 christos
613 1.1 christos /*
614 1.1 christos * Get a new variable name
615 1.1 christos */
616 1.1 christos bootnum = (uint16_t)find_new_bootvar(var_array, var_cnt, opt.target);
617 1.1 christos easprintf(&v.name, "%s%04X", opt.target, bootnum);
618 1.4 riastrad
619 1.1 christos if (!opt.quiet)
620 1.1 christos printf("creating: %s\n", v.name);
621 1.1 christos
622 1.1 christos /*
623 1.1 christos * Initialize efi_ioc structure.
624 1.1 christos */
625 1.1 christos efi_var_init(&v.ev, v.name,
626 1.1 christos &EFI_GLOBAL_VARIABLE,
627 1.1 christos EFI_VARIABLE_NON_VOLATILE |
628 1.1 christos EFI_VARIABLE_BOOTSERVICE_ACCESS |
629 1.1 christos EFI_VARIABLE_RUNTIME_ACCESS);
630 1.1 christos
631 1.1 christos /*
632 1.1 christos * Setup the efi_ioc data section
633 1.1 christos */
634 1.1 christos v.ev.data = make_bootvar_data(opt.device, opt.partnum,
635 1.1 christos attrib, opt.label, opt.loader, opt.opt_fname, &v.ev.datasize);
636 1.1 christos #if 1
637 1.1 christos if (!opt.quiet) {
638 1.1 christos /*
639 1.1 christos * Prompt user for confirmation.
640 1.1 christos * XXX: Should this go away?
641 1.1 christos */
642 1.3 jakllsch opt.debug &= (uint)~DEBUG_BRIEF_BIT;
643 1.1 christos opt.debug |= DEBUG_VERBOSE_BIT;
644 1.1 christos show_variable(&v, opt.debug, 0);
645 1.4 riastrad
646 1.1 christos printf("are you sure? [y/n] ");
647 1.1 christos if (getchar() != 'y')
648 1.1 christos goto done;
649 1.1 christos }
650 1.1 christos #endif
651 1.1 christos /*
652 1.1 christos * Write the variable.
653 1.1 christos */
654 1.1 christos rv = set_variable(efi_fd, &v.ev);
655 1.1 christos if (rv == -1)
656 1.1 christos err(EXIT_FAILURE, "set_variable");
657 1.1 christos
658 1.1 christos /*
659 1.1 christos * Prefix the boot order if required.
660 1.1 christos */
661 1.1 christos if (opt.prefix_bootorder)
662 1.1 christos rv = prefix_bootorder(efi_fd, opt.target, NULL,
663 1.1 christos bootnum);
664 1.1 christos
665 1.1 christos /*
666 1.1 christos * Possibly write the MBR signature.
667 1.1 christos * XXX: do we really want this here?
668 1.1 christos */
669 1.1 christos if (opt.mbr_sig_write) {
670 1.1 christos assert(opt.device != NULL);
671 1.1 christos mbr_sig_write(opt.device, opt.mbr_sig,
672 1.1 christos IS_MBR_SIG_FORCE(opt), opt.verbose);
673 1.1 christos }
674 1.1 christos break;
675 1.1 christos }
676 1.1 christos
677 1.1 christos case act_show: {
678 1.1 christos uint max_namelen = get_max_namelen(var_array, var_cnt);
679 1.3 jakllsch uint flags = opt.debug;
680 1.1 christos
681 1.1 christos if (opt.verbose)
682 1.1 christos flags |= DEBUG_VERBOSE_BIT;
683 1.1 christos
684 1.1 christos if (opt.brief)
685 1.1 christos flags |= DEBUG_BRIEF_BIT;
686 1.1 christos
687 1.1 christos if (max_namelen > 32)
688 1.1 christos max_namelen = 32;
689 1.1 christos
690 1.1 christos for (i = 0; i < var_cnt; i++) {
691 1.1 christos if (opt.brief)
692 1.1 christos show_generic_data(var_array[i], max_namelen);
693 1.1 christos else
694 1.1 christos show_variable(var_array[i], flags, 0);
695 1.1 christos }
696 1.1 christos break;
697 1.1 christos }
698 1.1 christos
699 1.1 christos default:
700 1.1 christos assert(0);
701 1.1 christos break;
702 1.1 christos }
703 1.4 riastrad
704 1.1 christos done:
705 1.1 christos free_variables(var_hdl);
706 1.1 christos close(efi_fd);
707 1.4 riastrad
708 1.1 christos return 0;
709 1.1 christos }
710