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