1 /** @file
2   function declarations for shell environment functions.
3 
4   Copyright (c) 2009 - 2015, 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   Reports whether an environment variable is Volatile or Non-Volatile.
22 
23   @param EnvVarName             The name of the environment variable in question
24 
25   @retval TRUE                  This environment variable is Volatile
26   @retval FALSE                 This environment variable is NON-Volatile
27 **/
28 BOOLEAN
29 EFIAPI
IsVolatileEnv(IN CONST CHAR16 * EnvVarName)30 IsVolatileEnv (
31   IN CONST CHAR16 *EnvVarName
32   )
33 {
34   EFI_STATUS  Status;
35   UINTN       Size;
36   VOID        *Buffer;
37   UINT32      Attribs;
38 
39   Size = 0;
40   Buffer = NULL;
41 
42   //
43   // get the variable
44   //
45   Status = gRT->GetVariable((CHAR16*)EnvVarName,
46                             &gShellVariableGuid,
47                             &Attribs,
48                             &Size,
49                             Buffer);
50   if (Status == EFI_BUFFER_TOO_SMALL) {
51     Buffer = AllocateZeroPool(Size);
52     ASSERT(Buffer != NULL);
53     Status = gRT->GetVariable((CHAR16*)EnvVarName,
54                               &gShellVariableGuid,
55                               &Attribs,
56                               &Size,
57                               Buffer);
58     FreePool(Buffer);
59   }
60   //
61   // not found means volatile
62   //
63   if (Status == EFI_NOT_FOUND) {
64     return (TRUE);
65   }
66   ASSERT_EFI_ERROR(Status);
67 
68   //
69   // check for the Non Volatile bit
70   //
71   if ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE) {
72     return (FALSE);
73   }
74 
75   //
76   // everything else is volatile
77   //
78   return (TRUE);
79 }
80 
81 /**
82   free function for ENV_VAR_LIST objects.
83 
84   @param[in] List               The pointer to pointer to list.
85 **/
86 VOID
87 EFIAPI
FreeEnvironmentVariableList(IN LIST_ENTRY * List)88 FreeEnvironmentVariableList(
89   IN LIST_ENTRY *List
90   )
91 {
92   ENV_VAR_LIST *Node;
93 
94   ASSERT (List != NULL);
95   if (List == NULL) {
96     return;
97   }
98 
99   for ( Node = (ENV_VAR_LIST*)GetFirstNode(List)
100       ; !IsListEmpty(List)
101       ; Node = (ENV_VAR_LIST*)GetFirstNode(List)
102      ){
103     ASSERT(Node != NULL);
104     RemoveEntryList(&Node->Link);
105     if (Node->Key != NULL) {
106       FreePool(Node->Key);
107     }
108     if (Node->Val != NULL) {
109       FreePool(Node->Val);
110     }
111     FreePool(Node);
112   }
113 }
114 
115 /**
116   Creates a list of all Shell-Guid-based environment variables.
117 
118   @param[in, out] ListHead       The pointer to pointer to LIST ENTRY object for
119                                  storing this list.
120 
121   @retval EFI_SUCCESS           the list was created sucessfully.
122 **/
123 EFI_STATUS
124 EFIAPI
GetEnvironmentVariableList(IN OUT LIST_ENTRY * ListHead)125 GetEnvironmentVariableList(
126   IN OUT LIST_ENTRY *ListHead
127   )
128 {
129   CHAR16            *VariableName;
130   UINTN             NameSize;
131   UINTN             NameBufferSize;
132   EFI_STATUS        Status;
133   EFI_GUID          Guid;
134   UINTN             ValSize;
135   UINTN             ValBufferSize;
136   ENV_VAR_LIST      *VarList;
137 
138   if (ListHead == NULL) {
139     return (EFI_INVALID_PARAMETER);
140   }
141 
142   Status = EFI_SUCCESS;
143 
144   ValBufferSize = INIT_DATA_BUFFER_SIZE;
145   NameBufferSize = INIT_NAME_BUFFER_SIZE;
146   VariableName = AllocateZeroPool(NameBufferSize);
147   if (VariableName == NULL) {
148     return (EFI_OUT_OF_RESOURCES);
149   }
150   *VariableName = CHAR_NULL;
151 
152   while (!EFI_ERROR(Status)) {
153     NameSize = NameBufferSize;
154     Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
155     if (Status == EFI_NOT_FOUND){
156       Status = EFI_SUCCESS;
157       break;
158     } else if (Status == EFI_BUFFER_TOO_SMALL) {
159       NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;
160       SHELL_FREE_NON_NULL(VariableName);
161       VariableName = AllocateZeroPool(NameBufferSize);
162       if (VariableName == NULL) {
163         Status = EFI_OUT_OF_RESOURCES;
164         break;
165       }
166       NameSize = NameBufferSize;
167       Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);
168     }
169 
170     if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){
171       VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
172       if (VarList == NULL) {
173         Status = EFI_OUT_OF_RESOURCES;
174       } else {
175         ValSize = ValBufferSize;
176         VarList->Val = AllocateZeroPool(ValSize);
177         if (VarList->Val == NULL) {
178             SHELL_FREE_NON_NULL(VarList);
179             Status = EFI_OUT_OF_RESOURCES;
180             break;
181         }
182         Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
183         if (Status == EFI_BUFFER_TOO_SMALL){
184           ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2;
185           SHELL_FREE_NON_NULL (VarList->Val);
186           VarList->Val = AllocateZeroPool(ValBufferSize);
187           if (VarList->Val == NULL) {
188             SHELL_FREE_NON_NULL(VarList);
189             Status = EFI_OUT_OF_RESOURCES;
190             break;
191           }
192 
193           ValSize = ValBufferSize;
194           Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);
195         }
196         if (!EFI_ERROR(Status)) {
197           VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);
198           if (VarList->Key == NULL) {
199             SHELL_FREE_NON_NULL(VarList->Val);
200             SHELL_FREE_NON_NULL(VarList);
201             Status = EFI_OUT_OF_RESOURCES;
202           } else {
203             InsertTailList(ListHead, &VarList->Link);
204           }
205         } else {
206           SHELL_FREE_NON_NULL(VarList->Val);
207           SHELL_FREE_NON_NULL(VarList);
208         }
209       } // if (VarList == NULL) ... else ...
210     } // compare guid
211   } // while
212   SHELL_FREE_NON_NULL (VariableName);
213 
214   if (EFI_ERROR(Status)) {
215     FreeEnvironmentVariableList(ListHead);
216   }
217 
218   return (Status);
219 }
220 
221 /**
222   Sets a list of all Shell-Guid-based environment variables.  this will
223   also eliminate all existing shell environment variables (even if they
224   are not on the list).
225 
226   This function will also deallocate the memory from List.
227 
228   @param[in] ListHead           The pointer to LIST_ENTRY from
229                                 GetShellEnvVarList().
230 
231   @retval EFI_SUCCESS           the list was Set sucessfully.
232 **/
233 EFI_STATUS
234 EFIAPI
SetEnvironmentVariableList(IN LIST_ENTRY * ListHead)235 SetEnvironmentVariableList(
236   IN LIST_ENTRY *ListHead
237   )
238 {
239   ENV_VAR_LIST      VarList;
240   ENV_VAR_LIST      *Node;
241   EFI_STATUS        Status;
242   UINTN             Size;
243 
244   InitializeListHead(&VarList.Link);
245 
246   //
247   // Delete all the current environment variables
248   //
249   Status = GetEnvironmentVariableList(&VarList.Link);
250   ASSERT_EFI_ERROR(Status);
251 
252   for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link)
253       ; !IsNull(&VarList.Link, &Node->Link)
254       ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link)
255      ){
256     if (Node->Key != NULL) {
257       Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key);
258     }
259     ASSERT_EFI_ERROR(Status);
260   }
261 
262   FreeEnvironmentVariableList(&VarList.Link);
263 
264   //
265   // set all the variables fron the list
266   //
267   for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead)
268       ; !IsNull(ListHead, &Node->Link)
269       ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link)
270      ){
271     Size = StrSize(Node->Val);
272     if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) {
273       Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val);
274     } else {
275       Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val);
276     }
277     ASSERT_EFI_ERROR(Status);
278   }
279   FreeEnvironmentVariableList(ListHead);
280 
281   return (Status);
282 }
283 
284 /**
285   sets a list of all Shell-Guid-based environment variables.
286 
287   @param Environment        Points to a NULL-terminated array of environment
288                             variables with the format 'x=y', where x is the
289                             environment variable name and y is the value.
290 
291   @retval EFI_SUCCESS       The command executed successfully.
292   @retval EFI_INVALID_PARAMETER The parameter is invalid.
293   @retval EFI_OUT_OF_RESOURCES Out of resources.
294 
295   @sa SetEnvironmentVariableList
296 **/
297 EFI_STATUS
298 EFIAPI
SetEnvironmentVariables(IN CONST CHAR16 ** Environment)299 SetEnvironmentVariables(
300   IN CONST CHAR16 **Environment
301   )
302 {
303   CONST CHAR16  *CurrentString;
304   UINTN         CurrentCount;
305   ENV_VAR_LIST  *VarList;
306   ENV_VAR_LIST  *Node;
307 
308   VarList = NULL;
309 
310   if (Environment == NULL) {
311     return (EFI_INVALID_PARAMETER);
312   }
313 
314   //
315   // Build a list identical to the ones used for get/set list functions above
316   //
317   for ( CurrentCount = 0
318       ;
319       ; CurrentCount++
320      ){
321     CurrentString = Environment[CurrentCount];
322     if (CurrentString == NULL) {
323       break;
324     }
325     ASSERT(StrStr(CurrentString, L"=") != NULL);
326     Node = AllocateZeroPool(sizeof(ENV_VAR_LIST));
327     if (Node == NULL) {
328       SetEnvironmentVariableList(&VarList->Link);
329       return (EFI_OUT_OF_RESOURCES);
330     }
331 
332     Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16));
333     if (Node->Key == NULL) {
334       SHELL_FREE_NON_NULL(Node);
335       SetEnvironmentVariableList(&VarList->Link);
336       return (EFI_OUT_OF_RESOURCES);
337     }
338 
339     //
340     // Copy the string into the Key, leaving the last character allocated as NULL to terminate
341     //
342     StrnCpyS( Node->Key,
343               StrStr(CurrentString, L"=") - CurrentString + 1,
344               CurrentString,
345               StrStr(CurrentString, L"=") - CurrentString
346               );
347 
348     //
349     // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other)
350     //
351     Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1);
352     if (Node->Val == NULL) {
353       SHELL_FREE_NON_NULL(Node->Key);
354       SHELL_FREE_NON_NULL(Node);
355       SetEnvironmentVariableList(&VarList->Link);
356       return (EFI_OUT_OF_RESOURCES);
357     }
358 
359     Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS;
360 
361     if (VarList == NULL) {
362       VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));
363       if (VarList == NULL) {
364         SHELL_FREE_NON_NULL(Node->Key);
365         SHELL_FREE_NON_NULL(Node->Val);
366         SHELL_FREE_NON_NULL(Node);
367         return (EFI_OUT_OF_RESOURCES);
368       }
369       InitializeListHead(&VarList->Link);
370     }
371     InsertTailList(&VarList->Link, &Node->Link);
372 
373   } // for loop
374 
375   //
376   // set this new list as the set of all environment variables.
377   // this function also frees the memory and deletes all pre-existing
378   // shell-guid based environment variables.
379   //
380   return (SetEnvironmentVariableList(&VarList->Link));
381 }
382