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