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