1 1.5 riastrad /* $NetBSD: main.c,v 1.5 2025/03/02 01:07:11 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.5 riastrad __RCSID("$NetBSD: main.c,v 1.5 2025/03/02 01:07:11 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.5 riastrad errx(EXIT_FAILURE, 308 1.5 riastrad "sorry: %s only runs on little-endian machines!", 309 1.1 christos getprogname()); 310 1.1 christos } 311 1.1 christos 312 1.1 christos setprogname(argv[0]); 313 1.1 christos 314 1.1 christos optreset = 1; 315 1.1 christos optind = 1; 316 1.1 christos opterr = 1; 317 1.1 christos while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { 318 1.1 christos switch (ch) { 319 1.1 christos case OPT_BRIEF: 320 1.1 christos opt.brief = true; 321 1.1 christos break; 322 1.1 christos 323 1.1 christos case OPT_DEBUG: 324 1.1 christos if (optarg) 325 1.1 christos opt.debug = strtous(optarg, NULL, 0); 326 1.1 christos else 327 1.1 christos opt.debug++; 328 1.1 christos opt.debug &= DEBUG_MASK; 329 1.1 christos break; 330 1.1 christos 331 1.1 christos case '@': 332 1.1 christos opt.opt_fname = estrdup(optarg); 333 1.1 christos break; 334 1.1 christos 335 1.1 christos case 'A': 336 1.1 christos if (optarg) 337 1.1 christos get_bootnum(&opt, optarg); 338 1.1 christos 339 1.1 christos opt.active = false; 340 1.1 christos action = act_set_active; 341 1.1 christos break; 342 1.1 christos 343 1.1 christos case 'a': 344 1.1 christos if (optarg) 345 1.1 christos get_bootnum(&opt, optarg); 346 1.1 christos 347 1.1 christos opt.active = true; 348 1.1 christos action = act_set_active; 349 1.1 christos break; 350 1.1 christos 351 1.1 christos case 'B': 352 1.1 christos if (optarg) 353 1.1 christos get_bootnum(&opt, optarg); 354 1.1 christos 355 1.1 christos action = act_del_variable; 356 1.1 christos break; 357 1.1 christos 358 1.1 christos case 'b': 359 1.1 christos get_bootnum(&opt, optarg); 360 1.1 christos break; 361 1.1 christos 362 1.1 christos case 'C': 363 1.1 christos opt.prefix_bootorder = false; 364 1.1 christos action = act_create; 365 1.1 christos break; 366 1.1 christos 367 1.1 christos case 'c': 368 1.1 christos opt.prefix_bootorder = true; 369 1.1 christos action = act_create; 370 1.1 christos break; 371 1.1 christos 372 1.1 christos case 'D': 373 1.1 christos action = act_del_bootorder_dups; 374 1.1 christos break; 375 1.1 christos 376 1.1 christos case 'd': 377 1.1 christos opt.device = estrdup(optarg); 378 1.1 christos break; 379 1.1 christos 380 1.1 christos case 'F': 381 1.1 christos opt.reconnect = false; 382 1.1 christos break; 383 1.1 christos 384 1.1 christos case 'f': 385 1.1 christos opt.reconnect = true; 386 1.1 christos break; 387 1.1 christos 388 1.1 christos case 'G': 389 1.1 christos fname = estrdup(optarg ? optarg : "."); 390 1.1 christos action = act_show_gpt; 391 1.1 christos break; 392 1.1 christos 393 1.1 christos case 'L': 394 1.1 christos opt.label = estrdup(optarg); 395 1.1 christos break; 396 1.1 christos 397 1.1 christos case 'l': 398 1.1 christos opt.loader = estrdup(optarg); 399 1.1 christos break; 400 1.1 christos 401 1.1 christos case 'N': 402 1.1 christos action = act_del_bootnext; 403 1.1 christos break; 404 1.1 christos 405 1.1 christos case 'n': 406 1.1 christos opt.b_flag = true; 407 1.1 christos opt.bootnum = strtous(optarg, NULL, 16); 408 1.1 christos action = act_set_bootnext; 409 1.1 christos break; 410 1.1 christos 411 1.1 christos case 'O': 412 1.1 christos action = act_del_bootorder; 413 1.1 christos break; 414 1.1 christos 415 1.1 christos case 'o': 416 1.1 christos opt.bootorder = estrdup(optarg); 417 1.1 christos action = act_set_bootorder; 418 1.1 christos break; 419 1.1 christos 420 1.1 christos case 'p': 421 1.1 christos opt.partnum = strtous(optarg, NULL, 0); 422 1.1 christos break; 423 1.1 christos 424 1.1 christos case 'R': 425 1.1 christos if (opt.regexp != NULL) 426 1.1 christos free(opt.regexp); 427 1.1 christos opt.regexp = estrdup(optarg); 428 1.1 christos break; 429 1.1 christos 430 1.1 christos case 'r': 431 1.1 christos if (opt.target != NULL) 432 1.1 christos errx(EXIT_FAILURE, 433 1.1 christos "only one of '-r' or '-y' are allowed"); 434 1.1 christos opt.target = TARGET_DRIVER; 435 1.1 christos break; 436 1.1 christos 437 1.1 christos case 'T': 438 1.1 christos action = act_del_timeout; 439 1.1 christos break; 440 1.1 christos 441 1.1 christos case 't': 442 1.1 christos opt.timeout = strtous(optarg, NULL, 0); 443 1.1 christos action = act_set_timeout; 444 1.1 christos break; 445 1.1 christos 446 1.1 christos case 'q': 447 1.1 christos opt.quiet = true; 448 1.1 christos opt.verbose = 0; 449 1.1 christos break; 450 1.1 christos 451 1.1 christos case 'V': 452 1.1 christos printf("version: %u\n", VERSION); 453 1.1 christos exit(EXIT_SUCCESS); 454 1.1 christos 455 1.1 christos case 'v': 456 1.1 christos opt.verbose++; 457 1.1 christos opt.brief = false; 458 1.1 christos break; 459 1.1 christos 460 1.1 christos case 'w': 461 1.1 christos if (optarg != NULL) { 462 1.1 christos opt.mbr_sig_write = MBR_SIG_WRITE_FORCE; 463 1.5 riastrad opt.mbr_sig = (uint32_t)estrtou(optarg, 0, 464 1.5 riastrad 0, 0xffffffff); 465 1.1 christos } 466 1.1 christos else { 467 1.1 christos opt.mbr_sig_write = MBR_SIG_WRITE_MAYBE; 468 1.1 christos srandom((uint)time(NULL)); 469 1.1 christos opt.mbr_sig = (uint32_t)random(); 470 1.1 christos } 471 1.1 christos break; 472 1.1 christos 473 1.1 christos case 'X': 474 1.1 christos action = act_remove_bootorder; 475 1.1 christos if (opt.csus != NULL) { 476 1.5 riastrad usage("Comma Separated Hex list" 477 1.5 riastrad " already specified!\n"); 478 1.1 christos } 479 1.1 christos opt.csus = estrdup(optarg); 480 1.1 christos break; 481 1.1 christos 482 1.1 christos case 'x': 483 1.1 christos action = act_prefix_bootorder; 484 1.1 christos if (opt.csus != NULL) { 485 1.5 riastrad usage("Comma Separated Hex list" 486 1.5 riastrad " already specified!\n"); 487 1.1 christos } 488 1.1 christos opt.csus = estrdup(optarg); 489 1.1 christos break; 490 1.1 christos 491 1.1 christos case 'y': 492 1.1 christos if (opt.target != NULL) 493 1.1 christos errx(EXIT_FAILURE, 494 1.1 christos "only one of '-r' or '-y' are allowed"); 495 1.1 christos opt.target = TARGET_SYSPREP; 496 1.1 christos break; 497 1.1 christos 498 1.1 christos case 'h': 499 1.1 christos usage(NULL); 500 1.1 christos default: 501 1.1 christos usage("unknown option: '%c'\n", ch); 502 1.1 christos } 503 1.1 christos } 504 1.1 christos if (opt.target == NULL) 505 1.1 christos opt.target = TARGET_BOOT; 506 1.1 christos 507 1.1 christos argv += optind; 508 1.1 christos argc -= optind; 509 1.1 christos 510 1.1 christos if (argc != 0) 511 1.1 christos usage(NULL); 512 1.1 christos 513 1.1 christos /* 514 1.1 christos * Check some option requirements/overrides here. 515 1.1 christos */ 516 1.1 christos if (opt.quiet) 517 1.1 christos opt.verbose = 0; 518 1.1 christos 519 1.1 christos switch (action) { 520 1.1 christos case act_create: 521 1.1 christos if (opt.regexp != NULL) {/* override any previous setting */ 522 1.1 christos printf("Ignoring specified regexp: '%s'\n", 523 1.1 christos opt.regexp); 524 1.1 christos free(opt.regexp); 525 1.1 christos } 526 1.1 christos break; 527 1.1 christos 528 1.1 christos case act_show_gpt: 529 1.1 christos return show_gpt(fname, opt.verbose); 530 1.1 christos 531 1.1 christos case act_set_active: 532 1.1 christos case act_del_variable: 533 1.1 christos if (!opt.b_flag) 534 1.1 christos usage("please specify a boot number\n"); 535 1.1 christos /*FALLTHROUGH*/ 536 1.1 christos default: 537 1.1 christos if (opt.mbr_sig_write) { 538 1.1 christos /* 539 1.1 christos * This overrides all but act_create and 540 1.1 christos * act_show_gpt. 541 1.1 christos */ 542 1.1 christos return mbr_sig_write(opt.device, opt.mbr_sig, 543 1.1 christos IS_MBR_SIG_FORCE(opt), opt.verbose); 544 1.1 christos } 545 1.1 christos break; 546 1.1 christos } 547 1.1 christos 548 1.1 christos efi_fd = open(_PATH_EFI, O_RDONLY); 549 1.1 christos if (efi_fd == -1) 550 1.1 christos err(EXIT_FAILURE, "open"); 551 1.1 christos 552 1.1 christos switch (action) { 553 1.1 christos case act_del_bootorder_dups: return del_bootorder_dups(efi_fd, opt.target); 554 1.1 christos case act_del_bootorder: return del_bootorder(efi_fd, opt.target); 555 1.1 christos case act_del_bootnext: return del_bootnext(efi_fd); 556 1.1 christos case act_del_timeout: return del_timeout(efi_fd); 557 1.1 christos case act_del_variable: return del_variable(efi_fd, opt.target, opt.bootnum); 558 1.1 christos 559 1.1 christos case act_set_active: return set_active(efi_fd, opt.target, opt.bootnum, opt.active); 560 1.1 christos case act_set_bootnext: return set_bootnext(efi_fd, opt.bootnum); 561 1.1 christos case act_set_bootorder: return set_bootorder(efi_fd, opt.target, opt.bootorder); 562 1.1 christos case act_set_timeout: return set_timeout(efi_fd, opt.timeout); 563 1.1 christos 564 1.1 christos case act_remove_bootorder: return remove_bootorder(efi_fd, opt.target, opt.csus, 0); 565 1.1 christos case act_prefix_bootorder: return prefix_bootorder(efi_fd, opt.target, opt.csus, 0); 566 1.1 christos 567 1.1 christos case act_show_gpt: assert(0); break; /* handled above */ 568 1.1 christos default: break; 569 1.1 christos } 570 1.4 riastrad 571 1.1 christos /* 572 1.1 christos * The following actions are handled below and require a call 573 1.1 christos * to get_variables() using a regexp. Setup the regexp here. 574 1.1 christos * XXX: merge with above switch()? 575 1.1 christos */ 576 1.1 christos switch (action) { 577 1.1 christos case act_create: 578 1.1 christos easprintf(&opt.regexp, "^%s[0-9,A-F]{4}$", opt.target); 579 1.1 christos break; 580 1.1 christos 581 1.1 christos case act_show: 582 1.1 christos default: 583 1.1 christos if (opt.regexp != NULL) 584 1.1 christos break; 585 1.1 christos 586 1.5 riastrad if (opt.b_flag) { 587 1.5 riastrad easprintf(&opt.regexp, "^%s%04X$", 588 1.5 riastrad opt.target, opt.bootnum); 589 1.5 riastrad } else { 590 1.1 christos easprintf(&opt.regexp, "^%s", opt.target); 591 1.5 riastrad } 592 1.1 christos break; 593 1.1 christos } 594 1.1 christos 595 1.1 christos var_hdl = get_variables(efi_fd, opt.regexp, &var_array, &var_cnt); 596 1.1 christos 597 1.1 christos free(opt.regexp); 598 1.1 christos opt.regexp = NULL; 599 1.1 christos 600 1.1 christos /* 601 1.1 christos * preform the remaining actions. 602 1.1 christos */ 603 1.1 christos switch (action) { 604 1.1 christos case act_create: { 605 1.1 christos uint16_t bootnum; 606 1.1 christos efi_var_t v; 607 1.1 christos uint32_t attrib; 608 1.1 christos int rv; 609 1.1 christos 610 1.1 christos if (opt.device == NULL) { 611 1.1 christos opt.device = DEFAULT_DEVICE; 612 1.1 christos if (opt.device == NULL) 613 1.1 christos errx(EXIT_FAILURE, "specify disk with '-d'"); 614 1.1 christos } 615 1.1 christos attrib = LOAD_OPTION_ACTIVE; 616 1.1 christos if (opt.reconnect && IS_TARGET_DRIVER(opt)) 617 1.1 christos attrib |= LOAD_OPTION_FORCE_RECONNECT; 618 1.1 christos 619 1.1 christos /* 620 1.1 christos * Get a new variable name 621 1.1 christos */ 622 1.5 riastrad bootnum = (uint16_t)find_new_bootvar(var_array, var_cnt, 623 1.5 riastrad opt.target); 624 1.1 christos easprintf(&v.name, "%s%04X", opt.target, bootnum); 625 1.4 riastrad 626 1.1 christos if (!opt.quiet) 627 1.1 christos printf("creating: %s\n", v.name); 628 1.1 christos 629 1.1 christos /* 630 1.1 christos * Initialize efi_ioc structure. 631 1.1 christos */ 632 1.1 christos efi_var_init(&v.ev, v.name, 633 1.1 christos &EFI_GLOBAL_VARIABLE, 634 1.1 christos EFI_VARIABLE_NON_VOLATILE | 635 1.1 christos EFI_VARIABLE_BOOTSERVICE_ACCESS | 636 1.1 christos EFI_VARIABLE_RUNTIME_ACCESS); 637 1.1 christos 638 1.1 christos /* 639 1.1 christos * Setup the efi_ioc data section 640 1.1 christos */ 641 1.1 christos v.ev.data = make_bootvar_data(opt.device, opt.partnum, 642 1.5 riastrad attrib, opt.label, opt.loader, opt.opt_fname, 643 1.5 riastrad &v.ev.datasize); 644 1.1 christos #if 1 645 1.1 christos if (!opt.quiet) { 646 1.1 christos /* 647 1.1 christos * Prompt user for confirmation. 648 1.1 christos * XXX: Should this go away? 649 1.1 christos */ 650 1.3 jakllsch opt.debug &= (uint)~DEBUG_BRIEF_BIT; 651 1.1 christos opt.debug |= DEBUG_VERBOSE_BIT; 652 1.1 christos show_variable(&v, opt.debug, 0); 653 1.4 riastrad 654 1.1 christos printf("are you sure? [y/n] "); 655 1.1 christos if (getchar() != 'y') 656 1.1 christos goto done; 657 1.1 christos } 658 1.1 christos #endif 659 1.1 christos /* 660 1.1 christos * Write the variable. 661 1.1 christos */ 662 1.1 christos rv = set_variable(efi_fd, &v.ev); 663 1.1 christos if (rv == -1) 664 1.1 christos err(EXIT_FAILURE, "set_variable"); 665 1.1 christos 666 1.1 christos /* 667 1.1 christos * Prefix the boot order if required. 668 1.1 christos */ 669 1.1 christos if (opt.prefix_bootorder) 670 1.1 christos rv = prefix_bootorder(efi_fd, opt.target, NULL, 671 1.1 christos bootnum); 672 1.1 christos 673 1.1 christos /* 674 1.1 christos * Possibly write the MBR signature. 675 1.1 christos * XXX: do we really want this here? 676 1.1 christos */ 677 1.1 christos if (opt.mbr_sig_write) { 678 1.1 christos assert(opt.device != NULL); 679 1.1 christos mbr_sig_write(opt.device, opt.mbr_sig, 680 1.1 christos IS_MBR_SIG_FORCE(opt), opt.verbose); 681 1.1 christos } 682 1.1 christos break; 683 1.1 christos } 684 1.1 christos 685 1.1 christos case act_show: { 686 1.1 christos uint max_namelen = get_max_namelen(var_array, var_cnt); 687 1.3 jakllsch uint flags = opt.debug; 688 1.1 christos 689 1.1 christos if (opt.verbose) 690 1.1 christos flags |= DEBUG_VERBOSE_BIT; 691 1.1 christos 692 1.1 christos if (opt.brief) 693 1.1 christos flags |= DEBUG_BRIEF_BIT; 694 1.1 christos 695 1.1 christos if (max_namelen > 32) 696 1.1 christos max_namelen = 32; 697 1.1 christos 698 1.1 christos for (i = 0; i < var_cnt; i++) { 699 1.1 christos if (opt.brief) 700 1.1 christos show_generic_data(var_array[i], max_namelen); 701 1.1 christos else 702 1.1 christos show_variable(var_array[i], flags, 0); 703 1.1 christos } 704 1.1 christos break; 705 1.1 christos } 706 1.1 christos 707 1.1 christos default: 708 1.1 christos assert(0); 709 1.1 christos break; 710 1.1 christos } 711 1.4 riastrad 712 1.1 christos done: 713 1.1 christos free_variables(var_hdl); 714 1.1 christos close(efi_fd); 715 1.4 riastrad 716 1.1 christos return 0; 717 1.1 christos } 718