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