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 #include "efiutil.h" 42 #include "efichar.h" 43 44 /* options descriptor */ 45 static struct option longopts[] = { 46 { "append", no_argument, NULL, 'a' }, 47 { "ascii", no_argument, NULL, 'A' }, 48 { "attributes", required_argument, NULL, 't' }, 49 { "binary", no_argument, NULL, 'b' }, 50 { "delete", no_argument, NULL, 'D' }, 51 { "device", no_argument, NULL, 'd' }, 52 { "device-path", no_argument, NULL, 'd' }, 53 { "fromfile", required_argument, NULL, 'f' }, 54 { "guid", no_argument, NULL, 'g' }, 55 { "hex", no_argument, NULL, 'H' }, 56 { "list-guids", no_argument, NULL, 'L' }, 57 { "list", no_argument, NULL, 'l' }, 58 { "load-option", no_argument, NULL, 'O' }, 59 { "name", required_argument, NULL, 'n' }, 60 { "no-name", no_argument, NULL, 'N' }, 61 { "print", no_argument, NULL, 'p' }, 62 { "print-decimal", no_argument, NULL, 'd' }, 63 { "raw-guid", no_argument, NULL, 'R' }, 64 { "utf8", no_argument, NULL, 'u' }, 65 { "write", no_argument, NULL, 'w' }, 66 { NULL, 0, NULL, 0 } 67 }; 68 69 70 static int aflag, Aflag, bflag, dflag, Dflag, gflag, Hflag, Nflag, 71 lflag, Lflag, Rflag, wflag, pflag, uflag, load_opt_flag; 72 static char *varname; 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; 187 int rv; 188 189 pretty_guid(guid, &gname); 190 if (pflag) { 191 rv = efi_get_variable(*guid, name, &data, &datalen, &att); 192 193 if (rv < 0) 194 err(1, "%s-%s", gname, name); 195 196 if (!Nflag) 197 printf("%s-%s\n", gname, name); 198 if (load_opt_flag) 199 efi_print_load_option(data, datalen, Aflag, bflag, uflag); 200 else if (Aflag) 201 asciidump(data, datalen); 202 else if (uflag) 203 utf8dump(data, datalen); 204 else if (bflag) 205 bindump(data, datalen); 206 else if (dflag) 207 devpath_dump(data, datalen); 208 else 209 hexdump(data, datalen); 210 } else { 211 printf("%s-%s", gname, name); 212 } 213 free(gname); 214 if (!Nflag) 215 printf("\n"); 216 } 217 218 static void 219 print_variable(char *name) 220 { 221 char *vname; 222 efi_guid_t guid; 223 224 breakdown_name(name, &guid, &vname); 225 print_var(&guid, vname); 226 } 227 228 static void 229 print_variables(void) 230 { 231 int rv; 232 char *name = NULL; 233 efi_guid_t *guid = NULL; 234 235 while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) 236 print_var(guid, name); 237 238 if (rv < 0) 239 err(1, "Error listing names"); 240 } 241 242 static void 243 print_known_guid(void) 244 { 245 struct uuid_table *tbl; 246 int i, n; 247 248 n = efi_known_guid(&tbl); 249 for (i = 0; i < n; i++) 250 printf("%s %s\n", tbl[i].uuid_str, tbl[i].name); 251 } 252 253 static void 254 parse_args(int argc, char **argv) 255 { 256 int ch, i; 257 258 while ((ch = getopt_long(argc, argv, "aAbdDf:gHlLNn:OpRt:uw", 259 longopts, NULL)) != -1) { 260 switch (ch) { 261 case 'a': 262 aflag++; 263 break; 264 case 'A': 265 Aflag++; 266 break; 267 case 'b': 268 bflag++; 269 break; 270 case 'd': 271 dflag++; 272 break; 273 case 'D': 274 Dflag++; 275 break; 276 case 'g': 277 gflag++; 278 break; 279 case 'H': 280 Hflag++; 281 break; 282 case 'l': 283 lflag++; 284 break; 285 case 'L': 286 Lflag++; 287 break; 288 case 'n': 289 varname = optarg; 290 break; 291 case 'N': 292 Nflag++; 293 break; 294 case 'O': 295 load_opt_flag++; 296 break; 297 case 'p': 298 pflag++; 299 break; 300 case 'R': 301 Rflag++; 302 break; 303 case 't': 304 attrib = strtoul(optarg, NULL, 16); 305 break; 306 case 'u': 307 uflag++; 308 break; 309 case 'w': 310 wflag++; 311 break; 312 case 'f': 313 case 0: 314 errx(1, "unknown or unimplemented option\n"); 315 break; 316 default: 317 usage(); 318 } 319 } 320 argc -= optind; 321 argv += optind; 322 323 if (argc == 1) 324 varname = argv[0]; 325 326 if (aflag + Dflag + wflag > 1) { 327 warnx("Can only use one of -a (--append), " 328 "-D (--delete) and -w (--write)"); 329 usage(); 330 } 331 332 if (aflag + Dflag + wflag > 0 && varname == NULL) { 333 warnx("Must specify a variable for -a (--append), " 334 "-D (--delete) or -w (--write)"); 335 usage(); 336 } 337 338 if (aflag) 339 append_variable(varname, NULL); 340 else if (Dflag) 341 delete_variable(varname); 342 else if (wflag) 343 write_variable(varname, NULL); 344 else if (Lflag) 345 print_known_guid(); 346 else if (varname) { 347 pflag++; 348 print_variable(varname); 349 } else if (argc > 0) { 350 pflag++; 351 for (i = 0; i < argc; i++) 352 print_variable(argv[i]); 353 } else 354 print_variables(); 355 } 356 357 int 358 main(int argc, char **argv) 359 { 360 361 parse_args(argc, argv); 362 } 363