/** @file\r
function declarations for shell environment functions.\r
\r
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
-#include <Uefi.h>\r
-#include <ShellBase.h>\r
-\r
-#include <Guid/ShellVariableGuid.h>\r
+#include "Shell.h"\r
\r
-#include <Library/BaseLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
+#define INIT_NAME_BUFFER_SIZE 128\r
+#define INIT_DATA_BUFFER_SIZE 1024\r
\r
-#include "ShellEnvVar.h"\r
+//\r
+// The list is used to cache the environment variables.\r
+//\r
+ENV_VAR_LIST gShellEnvVarList;\r
\r
/**\r
Reports whether an environment variable is Volatile or Non-Volatile.\r
\r
@param EnvVarName The name of the environment variable in question\r
+ @param Volatile Return TRUE if the environment variable is volatile\r
\r
- @retval TRUE This environment variable is Volatile\r
- @retval FALSE This environment variable is NON-Volatile\r
+ @retval EFI_SUCCESS The volatile attribute is returned successfully\r
+ @retval others Some errors happened.\r
**/\r
-BOOLEAN\r
-EFIAPI\r
+EFI_STATUS\r
IsVolatileEnv (\r
- IN CONST CHAR16 *EnvVarName\r
+ IN CONST CHAR16 *EnvVarName,\r
+ OUT BOOLEAN *Volatile\r
)\r
{\r
EFI_STATUS Status;\r
VOID *Buffer;\r
UINT32 Attribs;\r
\r
+ ASSERT (Volatile != NULL);\r
+\r
Size = 0;\r
Buffer = NULL;\r
\r
&Size,\r
Buffer);\r
if (Status == EFI_BUFFER_TOO_SMALL) {\r
- Buffer = AllocatePool(Size);\r
- ASSERT(Buffer != NULL);\r
+ Buffer = AllocateZeroPool(Size);\r
+ if (Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
Status = gRT->GetVariable((CHAR16*)EnvVarName,\r
&gShellVariableGuid,\r
&Attribs,\r
// not found means volatile\r
//\r
if (Status == EFI_NOT_FOUND) {\r
- return (TRUE);\r
+ *Volatile = TRUE;\r
+ return EFI_SUCCESS;\r
}\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // check for the Non Volatile bit\r
- //\r
- if ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE) {\r
- return (FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
//\r
- // everything else is volatile\r
+ // check for the Non Volatile bit\r
//\r
- return (TRUE);\r
+ *Volatile = !(BOOLEAN) ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE);\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
@param[in] List The pointer to pointer to list.\r
**/\r
VOID\r
-EFIAPI\r
FreeEnvironmentVariableList(\r
IN LIST_ENTRY *List\r
)\r
}\r
\r
for ( Node = (ENV_VAR_LIST*)GetFirstNode(List)\r
- ; IsListEmpty(List)\r
+ ; !IsListEmpty(List)\r
; Node = (ENV_VAR_LIST*)GetFirstNode(List)\r
){\r
ASSERT(Node != NULL);\r
/**\r
Creates a list of all Shell-Guid-based environment variables.\r
\r
- @param[in,out] ListHead The pointer to pointer to LIST ENTRY object for\r
- storing this list.\r
+ @param[in, out] ListHead The pointer to pointer to LIST ENTRY object for\r
+ storing this list.\r
\r
@retval EFI_SUCCESS the list was created sucessfully.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
GetEnvironmentVariableList(\r
IN OUT LIST_ENTRY *ListHead\r
)\r
{\r
CHAR16 *VariableName;\r
UINTN NameSize;\r
- UINT64 MaxStorSize;\r
- UINT64 RemStorSize;\r
- UINT64 MaxVarSize;\r
+ UINTN NameBufferSize;\r
EFI_STATUS Status;\r
EFI_GUID Guid;\r
UINTN ValSize;\r
+ UINTN ValBufferSize;\r
ENV_VAR_LIST *VarList;\r
\r
if (ListHead == NULL) {\r
return (EFI_INVALID_PARAMETER);\r
}\r
\r
- Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
- if (EFI_ERROR(Status)) {\r
- return (Status);\r
- }\r
+ Status = EFI_SUCCESS;\r
\r
- NameSize = (UINTN)MaxVarSize;\r
- VariableName = AllocatePool(NameSize);\r
+ ValBufferSize = INIT_DATA_BUFFER_SIZE;\r
+ NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
+ VariableName = AllocateZeroPool(NameBufferSize);\r
if (VariableName == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(VariableName, L"");\r
+ *VariableName = CHAR_NULL;\r
\r
while (!EFI_ERROR(Status)) {\r
- NameSize = (UINTN)MaxVarSize;\r
+ NameSize = NameBufferSize;\r
Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
if (Status == EFI_NOT_FOUND){\r
Status = EFI_SUCCESS;\r
break;\r
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
+ SHELL_FREE_NON_NULL(VariableName);\r
+ VariableName = AllocateZeroPool(NameBufferSize);\r
+ if (VariableName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+ NameSize = NameBufferSize;\r
+ Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
}\r
+\r
if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){\r
VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
if (VarList == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
} else {\r
- ValSize = 0;\r
+ ValSize = ValBufferSize;\r
+ //\r
+ // We need another CHAR16 to save '\0' in VarList->Val.\r
+ //\r
+ VarList->Val = AllocateZeroPool (ValSize + sizeof (CHAR16));\r
+ if (VarList->Val == NULL) {\r
+ SHELL_FREE_NON_NULL(VarList);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);\r
if (Status == EFI_BUFFER_TOO_SMALL){\r
- VarList->Val = AllocatePool(ValSize);\r
+ ValBufferSize = ValSize > ValBufferSize * 2 ? ValSize : ValBufferSize * 2;\r
+ SHELL_FREE_NON_NULL (VarList->Val);\r
+ //\r
+ // We need another CHAR16 to save '\0' in VarList->Val.\r
+ //\r
+ VarList->Val = AllocateZeroPool (ValBufferSize + sizeof (CHAR16));\r
if (VarList->Val == NULL) {\r
SHELL_FREE_NON_NULL(VarList);\r
Status = EFI_OUT_OF_RESOURCES;\r
- } else {\r
- Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);\r
+ break;\r
}\r
+\r
+ ValSize = ValBufferSize;\r
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val);\r
}\r
- if (!EFI_ERROR(Status) && VarList != NULL) {\r
- VarList->Key = AllocatePool(StrSize(VariableName));\r
+ if (!EFI_ERROR(Status)) {\r
+ VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);\r
if (VarList->Key == NULL) {\r
SHELL_FREE_NON_NULL(VarList->Val);\r
SHELL_FREE_NON_NULL(VarList);\r
Status = EFI_OUT_OF_RESOURCES;\r
} else {\r
- StrCpy(VarList->Key, VariableName);\r
InsertTailList(ListHead, &VarList->Link);\r
}\r
+ } else {\r
+ SHELL_FREE_NON_NULL(VarList->Val);\r
+ SHELL_FREE_NON_NULL(VarList);\r
}\r
- }\r
+ } // if (VarList == NULL) ... else ...\r
} // compare guid\r
} // while\r
- FreePool(VariableName);\r
+ SHELL_FREE_NON_NULL (VariableName);\r
\r
if (EFI_ERROR(Status)) {\r
FreeEnvironmentVariableList(ListHead);\r
@retval EFI_SUCCESS the list was Set sucessfully.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
SetEnvironmentVariableList(\r
IN LIST_ENTRY *ListHead\r
)\r
; !IsNull(ListHead, &Node->Link)\r
; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link)\r
){\r
- Size = StrSize(Node->Val);\r
+ Size = StrSize (Node->Val) - sizeof (CHAR16);\r
if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) {\r
Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val);\r
} else {\r
@sa SetEnvironmentVariableList\r
**/\r
EFI_STATUS\r
-EFIAPI\r
SetEnvironmentVariables(\r
IN CONST CHAR16 **Environment\r
)\r
UINTN CurrentCount;\r
ENV_VAR_LIST *VarList;\r
ENV_VAR_LIST *Node;\r
- UINTN NewSize;\r
\r
VarList = NULL;\r
\r
break;\r
}\r
ASSERT(StrStr(CurrentString, L"=") != NULL);\r
- Node = AllocatePool(sizeof(ENV_VAR_LIST));\r
- ASSERT(Node != NULL);\r
+ Node = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
+ if (Node == NULL) {\r
+ SetEnvironmentVariableList(&VarList->Link);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+\r
Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16));\r
- ASSERT(Node->Key != NULL);\r
- StrnCpy(Node->Key, CurrentString, StrStr(CurrentString, L"=") - CurrentString);\r
- NewSize = StrSize(CurrentString);\r
- NewSize -= StrLen(Node->Key) - 1;\r
- Node->Val = AllocateZeroPool(NewSize);\r
- ASSERT(Node->Val != NULL);\r
- StrCpy(Node->Val, CurrentString + StrLen(Node->Key) + 1);\r
+ if (Node->Key == NULL) {\r
+ SHELL_FREE_NON_NULL(Node);\r
+ SetEnvironmentVariableList(&VarList->Link);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+\r
+ //\r
+ // Copy the string into the Key, leaving the last character allocated as NULL to terminate\r
+ //\r
+ StrnCpyS( Node->Key,\r
+ StrStr(CurrentString, L"=") - CurrentString + 1,\r
+ CurrentString,\r
+ StrStr(CurrentString, L"=") - CurrentString\r
+ );\r
+\r
+ //\r
+ // ValueSize = TotalSize - already removed size - size for '=' + size for terminator (the last 2 items cancel each other)\r
+ //\r
+ Node->Val = AllocateCopyPool(StrSize(CurrentString) - StrSize(Node->Key), CurrentString + StrLen(Node->Key) + 1);\r
+ if (Node->Val == NULL) {\r
+ SHELL_FREE_NON_NULL(Node->Key);\r
+ SHELL_FREE_NON_NULL(Node);\r
+ SetEnvironmentVariableList(&VarList->Link);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+\r
Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
\r
if (VarList == NULL) {\r
VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST));\r
- ASSERT(VarList != NULL);\r
+ if (VarList == NULL) {\r
+ SHELL_FREE_NON_NULL(Node->Key);\r
+ SHELL_FREE_NON_NULL(Node->Val);\r
+ SHELL_FREE_NON_NULL(Node);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
InitializeListHead(&VarList->Link);\r
}\r
InsertTailList(&VarList->Link, &Node->Link);\r
//\r
return (SetEnvironmentVariableList(&VarList->Link));\r
}\r
+\r
+/**\r
+ Find an environment variable in the gShellEnvVarList.\r
+\r
+ @param Key The name of the environment variable.\r
+ @param Value The value of the environment variable, the buffer\r
+ shoule be freed by the caller.\r
+ @param ValueSize The size in bytes of the environment variable\r
+ including the tailing CHAR_NELL.\r
+ @param Atts The attributes of the variable.\r
+\r
+ @retval EFI_SUCCESS The command executed successfully.\r
+ @retval EFI_NOT_FOUND The environment variable is not found in\r
+ gShellEnvVarList.\r
+\r
+**/\r
+EFI_STATUS\r
+ShellFindEnvVarInList (\r
+ IN CONST CHAR16 *Key,\r
+ OUT CHAR16 **Value,\r
+ OUT UINTN *ValueSize,\r
+ OUT UINT32 *Atts OPTIONAL\r
+ )\r
+{\r
+ ENV_VAR_LIST *Node;\r
+\r
+ if (Key == NULL || Value == NULL || ValueSize == NULL) {\r
+ return SHELL_INVALID_PARAMETER;\r
+ }\r
+\r
+ for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
+ ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
+ ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
+ ){\r
+ if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
+ *Value = AllocateCopyPool(StrSize(Node->Val), Node->Val);\r
+ *ValueSize = StrSize(Node->Val);\r
+ if (Atts != NULL) {\r
+ *Atts = Node->Atts;\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Add an environment variable into gShellEnvVarList.\r
+\r
+ @param Key The name of the environment variable.\r
+ @param Value The value of environment variable.\r
+ @param ValueSize The size in bytes of the environment variable\r
+ including the tailing CHAR_NULL\r
+ @param Atts The attributes of the variable.\r
+\r
+ @retval EFI_SUCCESS The environment variable was added to list successfully.\r
+ @retval others Some errors happened.\r
+\r
+**/\r
+EFI_STATUS\r
+ShellAddEnvVarToList (\r
+ IN CONST CHAR16 *Key,\r
+ IN CONST CHAR16 *Value,\r
+ IN UINTN ValueSize,\r
+ IN UINT32 Atts\r
+ )\r
+{\r
+ ENV_VAR_LIST *Node;\r
+ CHAR16 *LocalKey;\r
+ CHAR16 *LocalValue;\r
+\r
+ if (Key == NULL || Value == NULL || ValueSize == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ LocalValue = AllocateCopyPool (ValueSize, Value);\r
+ if (LocalValue == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Update the variable value if it exists in gShellEnvVarList.\r
+ //\r
+ for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
+ ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
+ ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
+ ){\r
+ if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
+ Node->Atts = Atts;\r
+ SHELL_FREE_NON_NULL(Node->Val);\r
+ Node->Val = LocalValue;\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the environment varialbe key doesn't exist in list just insert\r
+ // a new node.\r
+ //\r
+ LocalKey = AllocateCopyPool (StrSize(Key), Key);\r
+ if (LocalKey == NULL) {\r
+ FreePool (LocalValue);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Node = (ENV_VAR_LIST*)AllocateZeroPool (sizeof(ENV_VAR_LIST));\r
+ if (Node == NULL) {\r
+ FreePool (LocalKey);\r
+ FreePool (LocalValue);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Node->Key = LocalKey;\r
+ Node->Val = LocalValue;\r
+ Node->Atts = Atts;\r
+ InsertTailList(&gShellEnvVarList.Link, &Node->Link);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Remove a specified environment variable in gShellEnvVarList.\r
+\r
+ @param Key The name of the environment variable.\r
+\r
+ @retval EFI_SUCCESS The command executed successfully.\r
+ @retval EFI_NOT_FOUND The environment variable is not found in\r
+ gShellEnvVarList.\r
+**/\r
+EFI_STATUS\r
+ShellRemvoeEnvVarFromList (\r
+ IN CONST CHAR16 *Key\r
+ )\r
+{\r
+ ENV_VAR_LIST *Node;\r
+\r
+ if (Key == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
+ ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
+ ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
+ ){\r
+ if (Node->Key != NULL && StrCmp(Key, Node->Key) == 0) {\r
+ SHELL_FREE_NON_NULL(Node->Key);\r
+ SHELL_FREE_NON_NULL(Node->Val);\r
+ RemoveEntryList(&Node->Link);\r
+ SHELL_FREE_NON_NULL(Node);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Initialize the gShellEnvVarList and cache all Shell-Guid-based environment\r
+ variables.\r
+\r
+**/\r
+EFI_STATUS\r
+ShellInitEnvVarList (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ InitializeListHead(&gShellEnvVarList.Link);\r
+ Status = GetEnvironmentVariableList (&gShellEnvVarList.Link);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Destructe the gShellEnvVarList.\r
+\r
+**/\r
+VOID\r
+ShellFreeEnvVarList (\r
+ VOID\r
+ )\r
+{\r
+ FreeEnvironmentVariableList (&gShellEnvVarList.Link);\r
+ InitializeListHead(&gShellEnvVarList.Link);\r
+\r
+ return;\r
+}\r
+\r