]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ShellEnvVar.c
ShellPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellEnvVar.c
1 /** @file
2 function declarations for shell environment functions.
3
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Shell.h"
10
11 #define INIT_NAME_BUFFER_SIZE 128
12 #define INIT_DATA_BUFFER_SIZE 1024
13
14 //
15 // The list is used to cache the environment variables.
16 //
17 ENV_VAR_LIST gShellEnvVarList;
18
19 /**
20 Reports whether an environment variable is Volatile or Non-Volatile.
21
22 @param EnvVarName The name of the environment variable in question
23 @param Volatile Return TRUE if the environment variable is volatile
24
25 @retval EFI_SUCCESS The volatile attribute is returned successfully
26 @retval others Some errors happened.
27 **/
28 EFI_STATUS
29 IsVolatileEnv (
30 IN CONST CHAR16 *EnvVarName,
31 OUT BOOLEAN *Volatile
32 )
33 {
34 EFI_STATUS Status;
35 UINTN Size;
36 VOID *Buffer;
37 UINT32 Attribs;
38
39 ASSERT (Volatile != NULL);
40
41 Size = 0;
42 Buffer = NULL;
43
44 //
45 // get the variable
46 //
47 Status = gRT->GetVariable((CHAR16*)EnvVarName,
48 &gShellVariableGuid,
49 &Attribs,
50 &Size,
51 Buffer);
52 if (Status == EFI_BUFFER_TOO_SMALL) {
53 Buffer = AllocateZeroPool(Size);
54 if (Buffer == NULL) {
55 return EFI_OUT_OF_RESOURCES;
56 }
57 Status = gRT->GetVariable((CHAR16*)EnvVarName,
58 &gShellVariableGuid,
59 &Attribs,
60 &Size,
61 Buffer);
62 FreePool(Buffer);
63 }
64 //
65 // not found means volatile
66 //
67 if (Status == EFI_NOT_FOUND) {
68 *Volatile = TRUE;
69 return EFI_SUCCESS;
70 }
71 if (EFI_ERROR (Status)) {
72 return Status;
73 }
74
75 //
76 // check for the Non Volatile bit
77 //
78 *Volatile = !(BOOLEAN) ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE);
79 return EFI_SUCCESS;
80 }
81
82 /**
83 free function for ENV_VAR_LIST objects.
84
85 @param[in] List The pointer to pointer to list.
86 **/
87 VOID
88 FreeEnvironmentVariableList(
89 IN LIST_ENTRY *List
90 )
91 {
92 ENV_VAR_LIST *Node;
93
94 ASSERT (List != NULL);
95 if (List == NULL) {
96 return;
97 }
98
99 for ( Node = (ENV_VAR_LIST*)GetFirstNode(List)
100 ; !IsListEmpty(List)
101 ; Node = (ENV_VAR_LIST*)GetFirstNode(List)
102 ){
103 ASSERT(Node != NULL);
104 RemoveEntryList(&Node->Link);
105 if (Node->Key != NULL) {
106 FreePool(Node->Key);
107 }
108 if (Node->Val != NULL) {
109 FreePool(Node->Val);
110 }
111 FreePool(Node);
112 }
113 }
114
115 /**
116 Creates a list of all Shell-Guid-based environment variables.
117
118 @param[in, out] ListHead The pointer to pointer to LIST ENTRY object for
119 storing this list.
120
121 @retval EFI_SUCCESS the list was created sucessfully.
122 **/
123 EFI_STATUS
124 GetEnvironmentVariableList(
125 IN OUT LIST_ENTRY *ListHead
126 )
127 {
128 CHAR16 *VariableName;
129 UINTN NameSize;
130 UINTN NameBufferSize;
131 EFI_STATUS Status;
132 EFI_GUID Guid;
133 UINTN ValSize;
134 UINTN ValBufferSize;
135 ENV_VAR_LIST *VarList;
136
137 if (ListHead == NULL) {
138 return (EFI_INVALID_PARAMETER);
139 }
140
141 Status = EFI_SUCCESS;
142
143 ValBufferSize = INIT_DATA_BUFFER_SIZE;
144 NameBufferSize = INIT_NAME_BUFFER_SIZE;
145 VariableName = AllocateZeroPool(NameBufferSize);
146 if (VariableName == NULL) {
147 return (EFI_OUT_OF_RESOURCES);
148 }
149 *VariableName = CHAR_NULL;
150
151 while (!EFI_ERROR(Status)) {
152 NameSize = NameBufferSize;
153 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
154 if (Status == EFI_NOT_FOUND){
155 Status = EFI_SUCCESS;
156 break;
157 } else if (Status == EFI_BUFFER_TOO_SMALL) {
158 NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;
159 SHELL_FREE_NON_NULL(VariableName);
160 VariableName = AllocateZeroPool(NameBufferSize);
161 if (VariableName == NULL) {
162 Status = EFI_OUT_OF_RESOURCES;
163 break;
164 }
165 NameSize = NameBufferSize;
166 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
167 }
168
169 if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){
170 VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
171 if (VarList == NULL) {
172 Status = EFI_OUT_OF_RESOURCES;
173 } else {
174 ValSize = ValBufferSize;
175 //
176 // We need another CHAR16 to save '\0' in VarList->Val.
177 //
178 VarList->Val = AllocateZeroPool (ValSize + sizeof (CHAR16));
179 if (VarList->Val == NULL) {
180 SHELL_FREE_NON_NULL(VarList);
181 Status = EFI_OUT_OF_RESOURCES;
182 break;
183 }
184 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
185 if (Status == EFI_BUFFER_TOO_SMALL){
186 ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2;
187 SHELL_FREE_NON_NULL (VarList->Val);
188 //
189 // We need another CHAR16 to save '\0' in VarList->Val.
190 //
191 VarList->Val = AllocateZeroPool (ValBufferSize + sizeof (CHAR16));
192 if (VarList->Val == NULL) {
193 SHELL_FREE_NON_NULL(VarList);
194 Status = EFI_OUT_OF_RESOURCES;
195 break;
196 }
197
198 ValSize = ValBufferSize;
199 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
200 }
201 if (!EFI_ERROR(Status)) {
202 VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);
203 if (VarList->Key == NULL) {
204 SHELL_FREE_NON_NULL(VarList->Val);
205 SHELL_FREE_NON_NULL(VarList);
206 Status = EFI_OUT_OF_RESOURCES;
207 } else {
208 InsertTailList(ListHead, &VarList->Link);
209 }
210 } else {
211 SHELL_FREE_NON_NULL(VarList->Val);
212 SHELL_FREE_NON_NULL(VarList);
213 }
214 } // if (VarList == NULL) ... else ...
215 } // compare guid
216 } // while
217 SHELL_FREE_NON_NULL (VariableName);
218
219 if (EFI_ERROR(Status)) {
220 FreeEnvironmentVariableList(ListHead);
221 }
222
223 return (Status);
224 }
225
226 /**
227 Sets a list of all Shell-Guid-based environment variables. this will
228 also eliminate all existing shell environment variables (even if they
229 are not on the list).
230
231 This function will also deallocate the memory from List.
232
233 @param[in] ListHead The pointer to LIST_ENTRY from
234 GetShellEnvVarList().
235
236 @retval EFI_SUCCESS the list was Set sucessfully.
237 **/
238 EFI_STATUS
239 SetEnvironmentVariableList(
240 IN LIST_ENTRY *ListHead
241 )
242 {
243 ENV_VAR_LIST VarList;
244 ENV_VAR_LIST *Node;
245 EFI_STATUS Status;
246 UINTN Size;
247
248 InitializeListHead(&VarList.Link);
249
250 //
251 // Delete all the current environment variables
252 //
253 Status = GetEnvironmentVariableList(&VarList.Link);
254 ASSERT_EFI_ERROR(Status);
255
256 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link)
257 ; !IsNull(&VarList.Link, &Node->Link)
258 ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link)
259 ){
260 if (Node->Key != NULL) {
261 Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key);
262 }
263 ASSERT_EFI_ERROR(Status);
264 }
265
266 FreeEnvironmentVariableList(&VarList.Link);
267
268 //
269 // set all the variables fron the list
270 //
271 for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead)
272 ; !IsNull(ListHead, &Node->Link)
273 ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link)
274 ){
275 Size = StrSize (Node->Val) - sizeof (CHAR16);
276 if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) {
277 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val);
278 } else {
279 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val);
280 }
281 ASSERT_EFI_ERROR(Status);
282 }
283 FreeEnvironmentVariableList(ListHead);
284
285 return (Status);
286 }
287
288 /**
289 sets a list of all Shell-Guid-based environment variables.
290
291 @param Environment Points to a NULL-terminated array of environment
292 variables with the format 'x=y', where x is the
293 environment variable name and y is the value.
294
295 @retval EFI_SUCCESS The command executed successfully.
296 @retval EFI_INVALID_PARAMETER The parameter is invalid.
297 @retval EFI_OUT_OF_RESOURCES Out of resources.
298
299 @sa SetEnvironmentVariableList
300 **/
301 EFI_STATUS
302 SetEnvironmentVariables(
303 IN CONST CHAR16 **Environment
304 )
305 {
306 CONST CHAR16 *CurrentString;
307 UINTN CurrentCount;
308 ENV_VAR_LIST *VarList;
309 ENV_VAR_LIST *Node;
310
311 VarList = NULL;
312
313 if (Environment == NULL) {
314 return (EFI_INVALID_PARAMETER);
315 }
316
317 //
318 // Build a list identical to the ones used for get/set list functions above
319 //
320 for ( CurrentCount = 0
321 ;
322 ; CurrentCount++
323 ){
324 CurrentString = Environment[CurrentCount];
325 if (CurrentString == NULL) {
326 break;
327 }
328 ASSERT(StrStr(CurrentString, L"=") != NULL);
329 Node = AllocateZeroPool(sizeof(ENV_VAR_LIST));
330 if (Node == NULL) {
331 SetEnvironmentVariableList(&VarList->Link);
332 return (EFI_OUT_OF_RESOURCES);
333 }
334
335 Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16));
336 if (Node->Key == NULL) {
337 SHELL_FREE_NON_NULL(Node);
338 SetEnvironmentVariableList(&VarList->Link);
339 return (EFI_OUT_OF_RESOURCES);
340 }
341
342 //
343 // Copy the string into the Key, leaving the last character allocated as NULL to terminate
344 //
345 StrnCpyS( Node->Key,
346 StrStr(CurrentString, L"=") - CurrentString + 1,
347 CurrentString,
348 StrStr(CurrentString, L"=") - CurrentString
349 );
350
351 //
352 // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other)
353 //
354 Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1);
355 if (Node->Val == NULL) {
356 SHELL_FREE_NON_NULL(Node->Key);
357 SHELL_FREE_NON_NULL(Node);
358 SetEnvironmentVariableList(&VarList->Link);
359 return (EFI_OUT_OF_RESOURCES);
360 }
361
362 Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS;
363
364 if (VarList == NULL) {
365 VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
366 if (VarList == NULL) {
367 SHELL_FREE_NON_NULL(Node->Key);
368 SHELL_FREE_NON_NULL(Node->Val);
369 SHELL_FREE_NON_NULL(Node);
370 return (EFI_OUT_OF_RESOURCES);
371 }
372 InitializeListHead(&VarList->Link);
373 }
374 InsertTailList(&VarList->Link, &Node->Link);
375
376 } // for loop
377
378 //
379 // set this new list as the set of all environment variables.
380 // this function also frees the memory and deletes all pre-existing
381 // shell-guid based environment variables.
382 //
383 return (SetEnvironmentVariableList(&VarList->Link));
384 }
385
386 /**
387 Find an environment variable in the gShellEnvVarList.
388
389 @param Key The name of the environment variable.
390 @param Value The value of the environment variable, the buffer
391 shoule be freed by the caller.
392 @param ValueSize The size in bytes of the environment variable
393 including the tailing CHAR_NELL.
394 @param Atts The attributes of the variable.
395
396 @retval EFI_SUCCESS The command executed successfully.
397 @retval EFI_NOT_FOUND The environment variable is not found in
398 gShellEnvVarList.
399
400 **/
401 EFI_STATUS
402 ShellFindEnvVarInList (
403 IN CONST CHAR16 *Key,
404 OUT CHAR16 **Value,
405 OUT UINTN *ValueSize,
406 OUT UINT32 *Atts OPTIONAL
407 )
408 {
409 ENV_VAR_LIST *Node;
410
411 if (Key == NULL || Value == NULL || ValueSize == NULL) {
412 return SHELL_INVALID_PARAMETER;
413 }
414
415 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
416 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
417 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
418 ){
419 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
420 *Value = AllocateCopyPool(StrSize(Node->Val), Node->Val);
421 *ValueSize = StrSize(Node->Val);
422 if (Atts != NULL) {
423 *Atts = Node->Atts;
424 }
425 return EFI_SUCCESS;
426 }
427 }
428
429 return EFI_NOT_FOUND;
430 }
431
432 /**
433 Add an environment variable into gShellEnvVarList.
434
435 @param Key The name of the environment variable.
436 @param Value The value of environment variable.
437 @param ValueSize The size in bytes of the environment variable
438 including the tailing CHAR_NULL
439 @param Atts The attributes of the variable.
440
441 @retval EFI_SUCCESS The environment variable was added to list successfully.
442 @retval others Some errors happened.
443
444 **/
445 EFI_STATUS
446 ShellAddEnvVarToList (
447 IN CONST CHAR16 *Key,
448 IN CONST CHAR16 *Value,
449 IN UINTN ValueSize,
450 IN UINT32 Atts
451 )
452 {
453 ENV_VAR_LIST *Node;
454 CHAR16 *LocalKey;
455 CHAR16 *LocalValue;
456
457 if (Key == NULL || Value == NULL || ValueSize == 0) {
458 return EFI_INVALID_PARAMETER;
459 }
460
461 LocalValue = AllocateCopyPool (ValueSize, Value);
462 if (LocalValue == NULL) {
463 return EFI_OUT_OF_RESOURCES;
464 }
465
466 //
467 // Update the variable value if it exists in gShellEnvVarList.
468 //
469 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
470 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
471 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
472 ){
473 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
474 Node->Atts = Atts;
475 SHELL_FREE_NON_NULL(Node->Val);
476 Node->Val = LocalValue;
477 return EFI_SUCCESS;
478 }
479 }
480
481 //
482 // If the environment varialbe key doesn't exist in list just insert
483 // a new node.
484 //
485 LocalKey = AllocateCopyPool (StrSize(Key), Key);
486 if (LocalKey == NULL) {
487 FreePool (LocalValue);
488 return EFI_OUT_OF_RESOURCES;
489 }
490 Node = (ENV_VAR_LIST*)AllocateZeroPool (sizeof(ENV_VAR_LIST));
491 if (Node == NULL) {
492 FreePool (LocalKey);
493 FreePool (LocalValue);
494 return EFI_OUT_OF_RESOURCES;
495 }
496 Node->Key = LocalKey;
497 Node->Val = LocalValue;
498 Node->Atts = Atts;
499 InsertTailList(&gShellEnvVarList.Link, &Node->Link);
500
501 return EFI_SUCCESS;
502 }
503
504 /**
505 Remove a specified environment variable in gShellEnvVarList.
506
507 @param Key The name of the environment variable.
508
509 @retval EFI_SUCCESS The command executed successfully.
510 @retval EFI_NOT_FOUND The environment variable is not found in
511 gShellEnvVarList.
512 **/
513 EFI_STATUS
514 ShellRemvoeEnvVarFromList (
515 IN CONST CHAR16 *Key
516 )
517 {
518 ENV_VAR_LIST *Node;
519
520 if (Key == NULL) {
521 return EFI_INVALID_PARAMETER;
522 }
523
524 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)
525 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)
526 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)
527 ){
528 if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {
529 SHELL_FREE_NON_NULL(Node->Key);
530 SHELL_FREE_NON_NULL(Node->Val);
531 RemoveEntryList(&Node->Link);
532 SHELL_FREE_NON_NULL(Node);
533 return EFI_SUCCESS;
534 }
535 }
536
537 return EFI_NOT_FOUND;
538 }
539
540 /**
541 Initialize the gShellEnvVarList and cache all Shell-Guid-based environment
542 variables.
543
544 **/
545 EFI_STATUS
546 ShellInitEnvVarList (
547 VOID
548 )
549 {
550 EFI_STATUS Status;
551
552 InitializeListHead(&gShellEnvVarList.Link);
553 Status = GetEnvironmentVariableList (&gShellEnvVarList.Link);
554
555 return Status;
556 }
557
558 /**
559 Destructe the gShellEnvVarList.
560
561 **/
562 VOID
563 ShellFreeEnvVarList (
564 VOID
565 )
566 {
567 FreeEnvironmentVariableList (&gShellEnvVarList.Link);
568 InitializeListHead(&gShellEnvVarList.Link);
569
570 return;
571 }
572