1 /*- 2 * Copyright (c) 2016 Netflix, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <ctype.h> 31 #include <efivar.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <getopt.h> 35 #include <stddef.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 /* options descriptor */ 42 static struct option longopts[] = { 43 { "append", no_argument, NULL, 'a' }, 44 { "ascii", no_argument, NULL, 'A' }, 45 { "attributes", required_argument, NULL, 't' }, 46 { "binary", no_argument, NULL, 'b' }, 47 { "delete", no_argument, NULL, 'D' }, 48 { "device", no_argument, NULL, 'd' }, 49 { "device-path", no_argument, NULL, 'd' }, 50 { "fromfile", required_argument, NULL, 'f' }, 51 { "guid", no_argument, NULL, 'g' }, 52 { "hex", no_argument, NULL, 'H' }, 53 { "list-guids", no_argument, NULL, 'L' }, 54 { "list", no_argument, NULL, 'l' }, 55 { "name", required_argument, NULL, 'n' }, 56 { "no-name", no_argument, NULL, 'N' }, 57 { "print", no_argument, NULL, 'p' }, 58 { "print-decimal", no_argument, NULL, 'd' }, 59 { "raw-guid", no_argument, NULL, 'R' }, 60 { "write", no_argument, NULL, 'w' }, 61 { NULL, 0, NULL, 0 } 62 }; 63 64 65 static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, 66 lflag, Lflag, Rflag, wflag, pflag; 67 static char *varname; 68 static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; 69 70 static void 71 usage(void) 72 { 73 74 errx(1, "efivar [-abdDHlLNpRtw] [-n name] [-f file] [--append] [--ascii]\n" 75 "\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" 76 "\t[--list-guids] [--list] [--name name] [--no-name] [--print]\n" 77 "\t[--print-decimal] [--raw-guid] [--write] name[=value]"); 78 } 79 80 static void 81 breakdown_name(char *name, efi_guid_t *guid, char **vname) 82 { 83 char *cp; 84 85 cp = strrchr(name, '-'); 86 if (cp == NULL) 87 errx(1, "Invalid name: %s", name); 88 *vname = cp + 1; 89 *cp = '\0'; 90 if (efi_name_to_guid(name, guid) < 0) 91 errx(1, "Invalid guid %s", name); 92 } 93 94 static uint8_t * 95 get_value(char *val, size_t *datalen) 96 { 97 static char buffer[16*1024]; 98 99 if (val != NULL) { 100 *datalen = strlen(val); 101 return ((uint8_t *)val); 102 } 103 /* Read from stdin */ 104 *datalen = sizeof(buffer); 105 *datalen = read(0, buffer, *datalen); 106 return ((uint8_t *)buffer); 107 } 108 109 static void 110 append_variable(char *name, char *val) 111 { 112 char *vname; 113 efi_guid_t guid; 114 size_t datalen; 115 uint8_t *data; 116 117 breakdown_name(name, &guid, &vname); 118 data = get_value(val, &datalen); 119 if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) 120 err(1, "efi_append_variable"); 121 } 122 123 static void 124 delete_variable(char *name) 125 { 126 char *vname; 127 efi_guid_t guid; 128 129 breakdown_name(name, &guid, &vname); 130 if (efi_del_variable(guid, vname) < 0) 131 err(1, "efi_del_variable"); 132 } 133 134 static void 135 write_variable(char *name, char *val) 136 { 137 char *vname; 138 efi_guid_t guid; 139 size_t datalen; 140 uint8_t *data; 141 142 breakdown_name(name, &guid, &vname); 143 data = get_value(val, &datalen); 144 if (efi_set_variable(guid, vname, data, datalen, attrib, 0) < 0) 145 err(1, "efi_set_variable"); 146 } 147 148 static void 149 asciidump(uint8_t *data, size_t datalen) 150 { 151 size_t i; 152 int len; 153 154 len = 0; 155 if (!Nflag) 156 printf("\n"); 157 for (i = 0; i < datalen; i++) { 158 if (isprint(data[i])) { 159 len++; 160 if (len > 80) { 161 len = 0; 162 printf("\n"); 163 } 164 printf("%c", data[i]); 165 } else { 166 len +=3; 167 if (len > 80) { 168 len = 0; 169 printf("\n"); 170 } 171 printf("%%%02x", data[i]); 172 } 173 } 174 printf("\n"); 175 } 176 177 static void 178 hexdump(uint8_t *data, size_t datalen) 179 { 180 size_t i; 181 182 if (!Nflag) 183 printf("\n"); 184 for (i = 0; i < datalen; i++) { 185 if (i % 16 == 0) { 186 if (i != 0) 187 printf("\n"); 188 printf("%04x: ", (int)i); 189 } 190 printf("%02x ", data[i]); 191 } 192 printf("\n"); 193 } 194 195 static void 196 bindump(uint8_t *data, size_t datalen) 197 { 198 write(1, data, datalen); 199 } 200 201 static void 202 devpath_dump(uint8_t *data, size_t datalen) 203 { 204 205 fprintf(stderr, "junk %p %zu\n", data, datalen); 206 } 207 208 static void 209 pretty_guid(efi_guid_t *guid, char **gname) 210 { 211 char *pretty = NULL; 212 213 if (gflag) 214 efi_guid_to_name(guid, &pretty); 215 216 if (pretty == NULL) 217 efi_guid_to_str(guid, gname); 218 else 219 *gname = pretty; 220 } 221 222 static void 223 print_var(efi_guid_t *guid, char *name) 224 { 225 uint32_t att; 226 uint8_t *data; 227 size_t datalen; 228 char *gname; 229 int rv; 230 231 pretty_guid(guid, &gname); 232 if (pflag) { 233 rv = efi_get_variable(*guid, name, &data, &datalen, &att); 234 235 if (rv < 0) 236 err(1, "%s-%s", gname, name); 237 238 if (!Nflag) 239 printf("%s-%s", gname, name); 240 if (Aflag) 241 asciidump(data, datalen); 242 else if (bflag) 243 bindump(data, datalen); 244 else if (dflag) 245 devpath_dump(data, datalen); 246 else 247 hexdump(data, datalen); 248 } else { 249 printf("%s-%s", gname, name); 250 } 251 free(gname); 252 if (!Nflag) 253 printf("\n"); 254 } 255 256 static void 257 print_variable(char *name) 258 { 259 char *vname; 260 efi_guid_t guid; 261 262 breakdown_name(name, &guid, &vname); 263 print_var(&guid, vname); 264 } 265 266 static void 267 print_variables(void) 268 { 269 int rv; 270 char *name = NULL; 271 efi_guid_t *guid = NULL; 272 273 while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) 274 print_var(guid, name); 275 276 if (rv < 0) 277 err(1, "Error listing names"); 278 } 279 280 static void 281 print_known_guid(void) 282 { 283 struct uuid_table *tbl; 284 int i, n; 285 286 n = efi_known_guid(&tbl); 287 for (i = 0; i < n; i++) 288 printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); 289 } 290 291 static void 292 parse_args(int argc, char **argv) 293 { 294 int ch, i; 295 296 while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:pRt:w", 297 longopts, NULL)) != -1) { 298 switch (ch) { 299 case 'a': 300 aflag++; 301 break; 302 case 'A': 303 Aflag++; 304 break; 305 case 'b': 306 bflag++; 307 break; 308 case 'd': 309 dflag++; 310 break; 311 case 'D': 312 Dflag++; 313 break; 314 case 'g': 315 gflag++; 316 break; 317 case 'H': 318 Hflag++; 319 break; 320 case 'l': 321 lflag++; 322 break; 323 case 'L': 324 Lflag++; 325 break; 326 case 'n': 327 varname = optarg; 328 break; 329 case 'N': 330 Nflag++; 331 break; 332 case 'p': 333 pflag++; 334 break; 335 case 'R': 336 Rflag++; 337 break; 338 case 't': 339 attrib = strtoul(optarg, NULL, 16); 340 break; 341 case 'w': 342 wflag++; 343 break; 344 case 'f': 345 case 0: 346 errx(1, "unknown or unimplemented option\n"); 347 break; 348 default: 349 usage(); 350 } 351 } 352 argc -= optind; 353 argv += optind; 354 355 if (argc == 1) 356 varname = argv[0]; 357 358 if (aflag + Dflag + wflag > 1) { 359 warnx("Can only use one of -a (--append), " 360 "-D (--delete) and -w (--write)"); 361 usage(); 362 } 363 364 if (aflag + Dflag + wflag > 0 && varname == NULL) { 365 warnx("Must specify a variable for -a (--append), " 366 "-D (--delete) or -w (--write)"); 367 usage(); 368 } 369 370 if (aflag) 371 append_variable(varname, NULL); 372 else if (Dflag) 373 delete_variable(varname); 374 else if (wflag) 375 write_variable(varname, NULL); 376 else if (Lflag) 377 print_known_guid(); 378 else if (varname) { 379 pflag++; 380 print_variable(varname); 381 } else if (argc > 0) { 382 pflag++; 383 for (i = 0; i < argc; i++) 384 print_variable(argv[i]); 385 } else 386 print_variables(); 387 } 388 389 int 390 main(int argc, char **argv) 391 { 392 393 parse_args(argc, argv); 394 } 395