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