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