]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellEnvVar.c
ShellPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellEnvVar.c
index b94711142af6c3ff4532ed1b6127e2b70eea9e31..dbeb8216986a0fd70f936e5ba386ace954451f2c 100644 (file)
@@ -1,31 +1,34 @@
 /** @file\r
   function declarations for shell environment functions.\r
 \r
-  Copyright (c) 2009 - 2011, 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 "Shell.h"\r
 \r
+#define INIT_NAME_BUFFER_SIZE  128\r
+#define INIT_DATA_BUFFER_SIZE  1024\r
+\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
@@ -33,6 +36,8 @@ IsVolatileEnv (
   VOID        *Buffer;\r
   UINT32      Attribs;\r
 \r
+  ASSERT (Volatile != NULL);\r
+\r
   Size = 0;\r
   Buffer = NULL;\r
 \r
@@ -46,7 +51,9 @@ IsVolatileEnv (
                             Buffer);\r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
     Buffer = AllocateZeroPool(Size);\r
-    ASSERT(Buffer != NULL);\r
+    if (Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
     Status = gRT->GetVariable((CHAR16*)EnvVarName,\r
                               &gShellVariableGuid,\r
                               &Attribs,\r
@@ -58,21 +65,18 @@ IsVolatileEnv (
   // 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
@@ -81,7 +85,6 @@ IsVolatileEnv (
   @param[in] List               The pointer to pointer to list.\r
 **/\r
 VOID\r
-EFIAPI\r
 FreeEnvironmentVariableList(\r
   IN LIST_ENTRY *List\r
   )\r
@@ -118,66 +121,84 @@ FreeEnvironmentVariableList(
   @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
-  if (gRT->Hdr.Revision >= EFI_2_00_SYSTEM_TABLE_REVISION) {\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
-  } else {\r
-    Status = EFI_SUCCESS;\r
-    MaxVarSize = 16384;\r
-  }\r
+  Status = EFI_SUCCESS;\r
 \r
-  NameSize = (UINTN)MaxVarSize;\r
-  VariableName = AllocateZeroPool(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
   *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 = AllocateZeroPool(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
+        if (!EFI_ERROR(Status)) {\r
           VarList->Key = AllocateCopyPool(StrSize(VariableName), VariableName);\r
           if (VarList->Key == NULL) {\r
             SHELL_FREE_NON_NULL(VarList->Val);\r
@@ -186,11 +207,14 @@ GetEnvironmentVariableList(
           } else {\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
@@ -212,7 +236,6 @@ GetEnvironmentVariableList(
   @retval EFI_SUCCESS           the list was Set sucessfully.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 SetEnvironmentVariableList(\r
   IN LIST_ENTRY *ListHead\r
   )\r
@@ -249,7 +272,7 @@ SetEnvironmentVariableList(
       ; !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
@@ -276,7 +299,6 @@ SetEnvironmentVariableList(
   @sa SetEnvironmentVariableList\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 SetEnvironmentVariables(\r
   IN CONST CHAR16 **Environment\r
   )\r
@@ -320,7 +342,11 @@ SetEnvironmentVariables(
     //\r
     // Copy the string into the Key, leaving the last character allocated as NULL to terminate\r
     //\r
-    StrnCpy(Node->Key, CurrentString, StrStr(CurrentString, L"=") - CurrentString);\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
@@ -356,3 +382,191 @@ SetEnvironmentVariables(
   //\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