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