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 <efivar-dp.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <getopt.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 /* options descriptor */ 43 static struct option longopts[] = { 44 { "append", no_argument, NULL, 'a' }, 45 { "ascii", no_argument, NULL, 'A' }, 46 { "attributes", required_argument, NULL, 't' }, 47 { "binary", no_argument, NULL, 'b' }, 48 { "delete", no_argument, NULL, 'D' }, 49 { "device", no_argument, NULL, 'd' }, 50 { "device-path", no_argument, NULL, 'd' }, 51 { "fromfile", required_argument, NULL, 'f' }, 52 { "guid", no_argument, NULL, 'g' }, 53 { "hex", no_argument, NULL, 'H' }, 54 { "list-guids", no_argument, NULL, 'L' }, 55 { "list", no_argument, NULL, 'l' }, 56 { "name", required_argument, NULL, 'n' }, 57 { "no-name", no_argument, NULL, 'N' }, 58 { "print", no_argument, NULL, 'p' }, 59 { "print-decimal", no_argument, NULL, 'd' }, 60 { "raw-guid", no_argument, NULL, 'R' }, 61 { "write", no_argument, NULL, 'w' }, 62 { NULL, 0, NULL, 0 } 63 }; 64 65 66 static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, 67 lflag, Lflag, Rflag, wflag, pflag; 68 static char *varname; 69 static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; 70 71 static void 72 usage(void) 73 { 74 75 errx(1, "efivar [-abdDHlLNpRtw] [-n name] [-f file] [--append] [--ascii]\n" 76 "\t[--attributes] [--binary] [--delete] [--fromfile file] [--hex]\n" 77 "\t[--list-guids] [--list] [--name name] [--no-name] [--print]\n" 78 "\t[--print-decimal] [--raw-guid] [--write] name[=value]"); 79 } 80 81 static void 82 breakdown_name(char *name, efi_guid_t *guid, char **vname) 83 { 84 char *cp; 85 86 cp = strrchr(name, '-'); 87 if (cp == NULL) 88 errx(1, "Invalid name: %s", name); 89 *vname = cp + 1; 90 *cp = '\0'; 91 if (efi_name_to_guid(name, guid) < 0) 92 errx(1, "Invalid guid %s", name); 93 } 94 95 static uint8_t * 96 get_value(char *val, size_t *datalen) 97 { 98 static char buffer[16*1024]; 99 100 if (val != NULL) { 101 *datalen = strlen(val); 102 return ((uint8_t *)val); 103 } 104 /* Read from stdin */ 105 *datalen = sizeof(buffer); 106 *datalen = read(0, buffer, *datalen); 107 return ((uint8_t *)buffer); 108 } 109 110 static void 111 append_variable(char *name, char *val) 112 { 113 char *vname; 114 efi_guid_t guid; 115 size_t datalen; 116 uint8_t *data; 117 118 breakdown_name(name, &guid, &vname); 119 data = get_value(val, &datalen); 120 if (efi_append_variable(guid, vname, data, datalen, attrib) < 0) 121 err(1, "efi_append_variable"); 122 } 123 124 static void 125 delete_variable(char *name) 126 { 127 char *vname; 128 efi_guid_t guid; 129 130 breakdown_name(name, &guid, &vname); 131 if (efi_del_variable(guid, vname) < 0) 132 err(1, "efi_del_variable"); 133 } 134 135 static void 136 write_variable(char *name, char *val) 137 { 138 char *vname; 139 efi_guid_t guid; 140 size_t datalen; 141 uint8_t *data; 142 143 breakdown_name(name, &guid, &vname); 144 data = get_value(val, &datalen); 145 if (efi_set_variable(guid, vname, data, datalen, attrib, 0) < 0) 146 err(1, "efi_set_variable"); 147 } 148 149 static void 150 asciidump(uint8_t *data, size_t datalen) 151 { 152 size_t i; 153 int len; 154 155 len = 0; 156 if (!Nflag) 157 printf("\n"); 158 for (i = 0; i < datalen; i++) { 159 if (isprint(data[i])) { 160 len++; 161 if (len > 80) { 162 len = 0; 163 printf("\n"); 164 } 165 printf("%c", data[i]); 166 } else { 167 len +=3; 168 if (len > 80) { 169 len = 0; 170 printf("\n"); 171 } 172 printf("%%%02x", data[i]); 173 } 174 } 175 printf("\n"); 176 } 177 178 static void 179 hexdump(uint8_t *data, size_t datalen) 180 { 181 size_t i; 182 183 if (!Nflag) 184 printf("\n"); 185 for (i = 0; i < datalen; i++) { 186 if (i % 16 == 0) { 187 if (i != 0) 188 printf("\n"); 189 printf("%04x: ", (int)i); 190 } 191 printf("%02x ", data[i]); 192 } 193 printf("\n"); 194 } 195 196 static void 197 bindump(uint8_t *data, size_t datalen) 198 { 199 write(1, data, datalen); 200 } 201 202 static void 203 devpath_dump(uint8_t *data, size_t datalen) 204 { 205 char buffer[1024]; 206 207 efidp_format_device_path(buffer, sizeof(buffer), 208 (const_efidp)data, datalen); 209 if (!Nflag) 210 printf(": "); 211 printf("%s\n", buffer); 212 } 213 214 static void 215 pretty_guid(efi_guid_t *guid, char **gname) 216 { 217 char *pretty = NULL; 218 219 if (gflag) 220 efi_guid_to_name(guid, &pretty); 221 222 if (pretty == NULL) 223 efi_guid_to_str(guid, gname); 224 else 225 *gname = pretty; 226 } 227 228 static void 229 print_var(efi_guid_t *guid, char *name) 230 { 231 uint32_t att; 232 uint8_t *data; 233 size_t datalen; 234 char *gname; 235 int rv; 236 237 pretty_guid(guid, &gname); 238 if (pflag) { 239 rv = efi_get_variable(*guid, name, &data, &datalen, &att); 240 241 if (rv < 0) 242 err(1, "%s-%s", gname, name); 243 244 if (!Nflag) 245 printf("%s-%s", gname, name); 246 if (Aflag) 247 asciidump(data, datalen); 248 else if (bflag) 249 bindump(data, datalen); 250 else if (dflag) 251 devpath_dump(data, datalen); 252 else 253 hexdump(data, datalen); 254 } else { 255 printf("%s-%s", gname, name); 256 } 257 free(gname); 258 if (!Nflag) 259 printf("\n"); 260 } 261 262 static void 263 print_variable(char *name) 264 { 265 char *vname; 266 efi_guid_t guid; 267 268 breakdown_name(name, &guid, &vname); 269 print_var(&guid, vname); 270 } 271 272 static void 273 print_variables(void) 274 { 275 int rv; 276 char *name = NULL; 277 efi_guid_t *guid = NULL; 278 279 while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) 280 print_var(guid, name); 281 282 if (rv < 0) 283 err(1, "Error listing names"); 284 } 285 286 static void 287 print_known_guid(void) 288 { 289 struct uuid_table *tbl; 290 int i, n; 291 292 n = efi_known_guid(&tbl); 293 for (i = 0; i < n; i++) 294 printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); 295 } 296 297 static void 298 parse_args(int argc, char **argv) 299 { 300 int ch, i; 301 302 while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:pRt:w", 303 longopts, NULL)) != -1) { 304 switch (ch) { 305 case 'a': 306 aflag++; 307 break; 308 case 'A': 309 Aflag++; 310 break; 311 case 'b': 312 bflag++; 313 break; 314 case 'd': 315 dflag++; 316 break; 317 case 'D': 318 Dflag++; 319 break; 320 case 'g': 321 gflag++; 322 break; 323 case 'H': 324 Hflag++; 325 break; 326 case 'l': 327 lflag++; 328 break; 329 case 'L': 330 Lflag++; 331 break; 332 case 'n': 333 varname = optarg; 334 break; 335 case 'N': 336 Nflag++; 337 break; 338 case 'p': 339 pflag++; 340 break; 341 case 'R': 342 Rflag++; 343 break; 344 case 't': 345 attrib = strtoul(optarg, NULL, 16); 346 break; 347 case 'w': 348 wflag++; 349 break; 350 case 'f': 351 case 0: 352 errx(1, "unknown or unimplemented option\n"); 353 break; 354 default: 355 usage(); 356 } 357 } 358 argc -= optind; 359 argv += optind; 360 361 if (argc == 1) 362 varname = argv[0]; 363 364 if (aflag + Dflag + wflag > 1) { 365 warnx("Can only use one of -a (--append), " 366 "-D (--delete) and -w (--write)"); 367 usage(); 368 } 369 370 if (aflag + Dflag + wflag > 0 && varname == NULL) { 371 warnx("Must specify a variable for -a (--append), " 372 "-D (--delete) or -w (--write)"); 373 usage(); 374 } 375 376 if (aflag) 377 append_variable(varname, NULL); 378 else if (Dflag) 379 delete_variable(varname); 380 else if (wflag) 381 write_variable(varname, NULL); 382 else if (Lflag) 383 print_known_guid(); 384 else if (varname) { 385 pflag++; 386 print_variable(varname); 387 } else if (argc > 0) { 388 pflag++; 389 for (i = 0; i < argc; i++) 390 print_variable(argv[i]); 391 } else 392 print_variables(); 393 } 394 395 int 396 main(int argc, char **argv) 397 { 398 399 parse_args(argc, argv); 400 } 401