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 (!Nflag) 209 printf("%s-%s", gname, name); 210 if (pflag) { 211 rv = efi_get_variable(*guid, name, &data, &datalen, &att); 212 213 if (rv < 0) 214 printf("\n --- Error getting value --- %d", errno); 215 else { 216 if (Aflag) 217 asciidump(data, datalen); 218 else if (bflag) 219 bindump(data, datalen); 220 else 221 hexdump(data, datalen); 222 } 223 } 224 free(gname); 225 if (!Nflag) 226 printf("\n"); 227 } 228 229 static void 230 print_variable(char *name) 231 { 232 char *vname; 233 efi_guid_t guid; 234 235 breakdown_name(name, &guid, &vname); 236 print_var(&guid, vname); 237 } 238 239 static void 240 print_variables(void) 241 { 242 int rv; 243 char *name = NULL; 244 efi_guid_t *guid = NULL; 245 246 while ((rv = efi_get_next_variable_name(&guid, &name)) > 0) 247 print_var(guid, name); 248 249 if (rv < 0) 250 err(1, "Error listing names"); 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:HlLNn:pRt:w", 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 'H': 277 Hflag++; 278 break; 279 case 'l': 280 lflag++; 281 break; 282 case 'L': 283 Lflag++; 284 break; 285 case 'n': 286 varname = optarg; 287 break; 288 case 'N': 289 Nflag++; 290 break; 291 case 'p': 292 pflag++; 293 break; 294 case 'R': 295 Rflag++; 296 break; 297 case 't': 298 attrib = strtoul(optarg, NULL, 16); 299 break; 300 case 'w': 301 wflag++; 302 break; 303 case 'f': 304 case 0: 305 errx(1, "unknown or unimplemented option\n"); 306 break; 307 default: 308 usage(); 309 } 310 } 311 argc -= optind; 312 argv += optind; 313 314 if (argc == 1) 315 varname = argv[0]; 316 317 if (aflag + Dflag + wflag > 1) { 318 warnx("Can only use one of -a (--append), " 319 "-D (--delete) and -w (--write)"); 320 usage(); 321 } 322 323 if (aflag + Dflag + wflag > 0 && varname == NULL) { 324 warnx("Must specify a variable for -a (--append), " 325 "-D (--delete) or -w (--write)"); 326 usage(); 327 } 328 329 if (aflag) 330 append_variable(varname, NULL); 331 else if (Dflag) 332 delete_variable(varname); 333 else if (wflag) 334 write_variable(varname, NULL); 335 else if (varname) { 336 pflag++; 337 print_variable(varname); 338 } else if (argc > 0) { 339 pflag++; 340 for (i = 0; i < argc; i++) 341 print_variable(argv[i]); 342 } else 343 print_variables(); 344 } 345 346 int 347 main(int argc, char **argv) 348 { 349 350 parse_args(argc, argv); 351 } 352