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