]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/efi/libefi/env.c
MFC r336424-r336425: loader command typos
[FreeBSD/FreeBSD.git] / stand / efi / libefi / env.c
1 /*
2  * Copyright (c) 2015 Netflix, Inc. All Rights Reserved.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <stand.h>
31 #include <string.h>
32 #include <efi.h>
33 #include <efilib.h>
34 #include <uuid.h>
35 #include <stdbool.h>
36 #include "bootstrap.h"
37
38 void
39 efi_init_environment(void)
40 {
41         char var[128];
42
43         snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
44             ST->Hdr.Revision & 0xffff);
45         env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
46 }
47
48 COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
49
50 static int
51 efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
52 {
53         UINTN           datasz, i;
54         EFI_STATUS      status;
55         UINT32          attr;
56         CHAR16          *data;
57         char            *str;
58         uint32_t        uuid_status;
59         int             is_ascii;
60
61         datasz = 0;
62         status = RS->GetVariable(varnamearg, matchguid, &attr,
63             &datasz, NULL);
64         if (status != EFI_BUFFER_TOO_SMALL) {
65                 printf("Can't get the variable: error %#lx\n",
66                     EFI_ERROR_CODE(status));
67                 return (CMD_ERROR);
68         }
69         data = malloc(datasz);
70         status = RS->GetVariable(varnamearg, matchguid, &attr,
71             &datasz, data);
72         if (status != EFI_SUCCESS) {
73                 printf("Can't get the variable: error %#lx\n",
74                     EFI_ERROR_CODE(status));
75                 return (CMD_ERROR);
76         }
77         uuid_to_string((uuid_t *)matchguid, &str, &uuid_status);
78         if (lflag) {
79                 printf("%s 0x%x %S", str, attr, varnamearg);
80         } else {
81                 printf("%s 0x%x %S=", str, attr, varnamearg);
82                 is_ascii = 1;
83                 free(str);
84                 str = (char *)data;
85                 for (i = 0; i < datasz - 1; i++) {
86                         /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */
87                         if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) {
88                                 is_ascii = 0;
89                                 break;
90                         }
91                 }
92                 if (str[datasz - 1] != '\0')
93                         is_ascii = 0;
94                 if (is_ascii)
95                         printf("%s", str);
96                 else {
97                         for (i = 0; i < datasz / 2; i++) {
98                                 if (isalnum(data[i]) || isspace(data[i]))
99                                         printf("%c", data[i]);
100                                 else
101                                         printf("\\x%02x", data[i]);
102                         }
103                 }
104         }
105         free(data);
106         if (pager_output("\n"))
107                 return (CMD_WARN);
108         return (CMD_OK);
109 }
110
111 static int
112 command_efi_show(int argc, char *argv[])
113 {
114         /*
115          * efi-show [-a]
116          *      print all the env
117          * efi-show -g UUID
118          *      print all the env vars tagged with UUID
119          * efi-show -v var
120          *      search all the env vars and print the ones matching var
121          * efi-show -g UUID -v var
122          * efi-show UUID var
123          *      print all the env vars that match UUID and var
124          */
125         /* NB: We assume EFI_GUID is the same as uuid_t */
126         int             aflag = 0, gflag = 0, lflag = 0, vflag = 0;
127         int             ch, rv;
128         unsigned        i;
129         EFI_STATUS      status;
130         EFI_GUID        varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
131         EFI_GUID        matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
132         uint32_t        uuid_status;
133         CHAR16          *varname;
134         CHAR16          *newnm;
135         CHAR16          varnamearg[128];
136         UINTN           varalloc;
137         UINTN           varsz;
138
139         while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
140                 switch (ch) {
141                 case 'a':
142                         aflag = 1;
143                         break;
144                 case 'g':
145                         gflag = 1;
146                         uuid_from_string(optarg, (uuid_t *)&matchguid,
147                             &uuid_status);
148                         if (uuid_status != uuid_s_ok) {
149                                 printf("uid %s could not be parsed\n", optarg);
150                                 return (CMD_ERROR);
151                         }
152                         break;
153                 case 'l':
154                         lflag = 1;
155                         break;
156                 case 'v':
157                         vflag = 1;
158                         if (strlen(optarg) >= nitems(varnamearg)) {
159                                 printf("Variable %s is longer than %zd characters\n",
160                                     optarg, nitems(varnamearg));
161                                 return (CMD_ERROR);
162                         }
163                         for (i = 0; i < strlen(optarg); i++)
164                                 varnamearg[i] = optarg[i];
165                         varnamearg[i] = 0;
166                         break;
167                 default:
168                         printf("Invalid argument %c\n", ch);
169                         return (CMD_ERROR);
170                 }
171         }
172
173         if (aflag && (gflag || vflag)) {
174                 printf("-a isn't compatible with -v or -u\n");
175                 return (CMD_ERROR);
176         }
177
178         if (aflag && optind < argc) {
179                 printf("-a doesn't take any args\n");
180                 return (CMD_ERROR);
181         }
182
183         if (optind == argc)
184                 aflag = 1;
185
186         argc -= optind;
187         argv += optind;
188
189         pager_open();
190         if (vflag && gflag) {
191                 rv = efi_print_var(varnamearg, &matchguid, lflag);
192                 pager_close();
193                 return (rv);
194         }
195
196         if (argc == 2) {
197                 optarg = argv[0];
198                 if (strlen(optarg) >= nitems(varnamearg)) {
199                         printf("Variable %s is longer than %zd characters\n",
200                             optarg, nitems(varnamearg));
201                         pager_close();
202                         return (CMD_ERROR);
203                 }
204                 for (i = 0; i < strlen(optarg); i++)
205                         varnamearg[i] = optarg[i];
206                 varnamearg[i] = 0;
207                 optarg = argv[1];
208                 uuid_from_string(optarg, (uuid_t *)&matchguid,
209                     &uuid_status);
210                 if (uuid_status != uuid_s_ok) {
211                         printf("uid %s could not be parsed\n", optarg);
212                         pager_close();
213                         return (CMD_ERROR);
214                 }
215                 rv = efi_print_var(varnamearg, &matchguid, lflag);
216                 pager_close();
217                 return (rv);
218         }
219
220         if (argc > 0) {
221                 printf("Too many args %d\n", argc);
222                 pager_close();
223                 return (CMD_ERROR);
224         }
225
226         /*
227          * Initiate the search -- note the standard takes pain
228          * to specify the initial call must be a poiner to a NULL
229          * character.
230          */
231         varalloc = 1024;
232         varname = malloc(varalloc);
233         if (varname == NULL) {
234                 printf("Can't allocate memory to get variables\n");
235                 pager_close();
236                 return (CMD_ERROR);
237         }
238         varname[0] = 0;
239         while (1) {
240                 varsz = varalloc;
241                 status = RS->GetNextVariableName(&varsz, varname, &varguid);
242                 if (status == EFI_BUFFER_TOO_SMALL) {
243                         varalloc = varsz;
244                         newnm = realloc(varname, varalloc);
245                         if (newnm == NULL) {
246                                 printf("Can't allocate memory to get variables\n");
247                                 free(varname);
248                                 pager_close();
249                                 return (CMD_ERROR);
250                         }
251                         varname = newnm;
252                         continue; /* Try again with bigger buffer */
253                 }
254                 if (status != EFI_SUCCESS)
255                         break;
256                 if (aflag) {
257                         if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
258                                 break;
259                         continue;
260                 }
261                 if (vflag) {
262                         if (wcscmp(varnamearg, varname) == 0) {
263                                 if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
264                                         break;
265                                 continue;
266                         }
267                 }
268                 if (gflag) {
269                         if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) {
270                                 if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
271                                         break;
272                                 continue;
273                         }
274                 }
275         }
276         free(varname);
277         pager_close();
278
279         return (CMD_OK);
280 }
281
282 COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
283
284 static int
285 command_efi_set(int argc, char *argv[])
286 {
287         char *uuid, *var, *val;
288         CHAR16 wvar[128];
289         EFI_GUID guid;
290         uint32_t status;
291         EFI_STATUS err;
292
293         if (argc != 4) {
294                 printf("efi-set uuid var new-value\n");
295                 return (CMD_ERROR);
296         }
297         uuid = argv[1];
298         var = argv[2];
299         val = argv[3];
300         uuid_from_string(uuid, (uuid_t *)&guid, &status);
301         if (status != uuid_s_ok) {
302                 printf("Invalid uuid %s %d\n", uuid, status);
303                 return (CMD_ERROR);
304         }
305         cpy8to16(var, wvar, sizeof(wvar));
306         err = RS->SetVariable(wvar, &guid,
307             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
308             strlen(val) + 1, val);
309         if (EFI_ERROR(err)) {
310                 printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err));
311                 return (CMD_ERROR);
312         }
313         return (CMD_OK);
314 }
315
316 COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
317
318 static int
319 command_efi_unset(int argc, char *argv[])
320 {
321         char *uuid, *var;
322         CHAR16 wvar[128];
323         EFI_GUID guid;
324         uint32_t status;
325         EFI_STATUS err;
326
327         if (argc != 3) {
328                 printf("efi-unset uuid var\n");
329                 return (CMD_ERROR);
330         }
331         uuid = argv[1];
332         var = argv[2];
333         uuid_from_string(uuid, (uuid_t *)&guid, &status);
334         if (status != uuid_s_ok) {
335                 printf("Invalid uuid %s\n", uuid);
336                 return (CMD_ERROR);
337         }
338         cpy8to16(var, wvar, sizeof(wvar));
339         err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
340         if (EFI_ERROR(err)) {
341                 printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err));
342                 return (CMD_ERROR);
343         }
344         return (CMD_OK);
345 }