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
usage(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
breakdown_name(char * name,efi_guid_t * guid,char ** vname)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 *
get_value(char * val,size_t * datalen)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
append_variable(char * name,char * val)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
delete_variable(char * name)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
write_variable(char * name,char * val)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
devpath_dump(uint8_t * data,size_t datalen)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
pretty_guid(efi_guid_t * guid,char ** gname)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
print_var(efi_guid_t * guid,char * name)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
print_variable(char * name)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
print_variables(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
print_known_guid(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
parse_args(int argc,char ** argv)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
main(int argc,char ** argv)380 main(int argc, char **argv)
381 {
382
383 parse_args(argc, argv);
384 }
385