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