]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg/Shell - Fix ASSERT() when FvSimpleFileSystemDxe is used
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index b0303962ff6939cb3771452973b6c537360aba74..def3bd35c208e6a7a669a744e55db1cd338231ee 100644 (file)
@@ -2,8 +2,8 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
-  (C) Copyright 2014, Hewlett-Packard Development Company, L.P.\r
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  Copyright (c) 2009 - 2015, 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
@@ -16,6 +16,8 @@
 \r
 #include "Shell.h"\r
 \r
+#define INIT_NAME_BUFFER_SIZE  128\r
+\r
 /**\r
   Close an open file handle.\r
 \r
@@ -447,38 +449,37 @@ EfiShellGetFilePathFromDevicePath(
           ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header)\r
          ){\r
         //\r
-        // all the rest should be file path nodes\r
+        // If any node is not a file path node, then the conversion can not be completed\r
         //\r
         if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
             (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) {\r
           FreePool(PathForReturn);\r
-          PathForReturn = NULL;\r
-          ASSERT(FALSE);\r
-        } else {\r
-          //\r
-          // append the path part onto the filepath.\r
-          //\r
-          ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
-\r
-          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
-          ASSERT (AlignedNode != NULL);\r
-\r
-          // File Path Device Path Nodes 'can optionally add a "\" separator to\r
-          //  the beginning and/or the end of the Path Name string.'\r
-          // (UEFI Spec 2.4 section 9.3.6.4).\r
-          // If necessary, add a "\", but otherwise don't\r
-          // (This is specified in the above section, and also implied by the\r
-          //  UEFI Shell spec section 3.7)\r
-          if ((PathSize != 0)                        &&\r
-              (PathForReturn != NULL)                &&\r
-              (PathForReturn[PathSize - 1] != L'\\') &&\r
-              (AlignedNode->PathName[0]    != L'\\')) {\r
-            PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
-          }\r
+          return NULL;\r
+        }\r
 \r
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
-          FreePool(AlignedNode);\r
+        //\r
+        // append the path part onto the filepath.\r
+        //\r
+        ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
+\r
+        AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
+        ASSERT (AlignedNode != NULL);\r
+\r
+        // File Path Device Path Nodes 'can optionally add a "\" separator to\r
+        //  the beginning and/or the end of the Path Name string.'\r
+        // (UEFI Spec 2.4 section 9.3.6.4).\r
+        // If necessary, add a "\", but otherwise don't\r
+        // (This is specified in the above section, and also implied by the\r
+        //  UEFI Shell spec section 3.7)\r
+        if ((PathSize != 0)                        &&\r
+            (PathForReturn != NULL)                &&\r
+            (PathForReturn[PathSize - 1] != L'\\') &&\r
+            (AlignedNode->PathName[0]    != L'\\')) {\r
+          PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
         }\r
+\r
+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
+        FreePool(AlignedNode);\r
       } // for loop of remaining nodes\r
     }\r
     if (PathForReturn != NULL) {\r
@@ -530,17 +531,18 @@ EfiShellGetDevicePathFromFilePath(
     if (Cwd == NULL) {\r
       return (NULL);\r
     }\r
-    Size = StrSize(Cwd) + StrSize(Path) - sizeof(CHAR16);\r
+    Size = StrSize(Cwd) + StrSize(Path);\r
     NewPath = AllocateZeroPool(Size);\r
     if (NewPath == NULL) {\r
       return (NULL);\r
     }\r
-    StrnCpy(NewPath, Cwd, Size/sizeof(CHAR16)-1);\r
+    StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd);\r
+    StrCatS(NewPath, Size/sizeof(CHAR16), L"\\");\r
     if (*Path == L'\\') {\r
       Path++;\r
       while (PathRemoveLastItem(NewPath)) ;\r
     }\r
-    StrnCat(NewPath, Path, Size/sizeof(CHAR16) - 1 - StrLen(NewPath));\r
+    StrCatS(NewPath, Size/sizeof(CHAR16), Path);\r
     DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
     FreePool(NewPath);\r
     return (DevicePathForReturn);\r
@@ -1498,7 +1500,7 @@ InternalShellExecuteDevicePath(
     ShellParamsProtocol.StdIn   = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
     ShellParamsProtocol.StdOut  = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
     ShellParamsProtocol.StdErr  = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
-    Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, NULL, NULL);\r
+    Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL);\r
     ASSERT_EFI_ERROR(Status);\r
     //\r
     // Replace Argv[0] with the full path of the binary we're executing:\r
@@ -1628,40 +1630,62 @@ EfiShellExecute(
   CHAR16                    *Temp;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   UINTN                     Size;\r
+  EFI_STATUS                CalleeStatusCode;\r
 \r
+  CalleeStatusCode = EFI_SUCCESS;\r
+  \r
   if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
     return (EFI_UNSUPPORTED);\r
   }\r
 \r
-  DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
+  if (Environment != NULL) {\r
+    // If Environment isn't null, load a new image of the shell with its own\r
+    // environment\r
+    DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
\r
+    DEBUG_CODE_BEGIN();\r
+    Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    DEBUG_CODE_END();\r
+\r
+    Temp = NULL;\r
+    Size = 0;\r
+    ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
+    StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
+    StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
 \r
-  DEBUG_CODE_BEGIN();\r
-  Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  DEBUG_CODE_END();\r
+    Status = InternalShellExecuteDevicePath(\r
+      ParentImageHandle,\r
+      DevPath,\r
+      Temp,\r
+      (CONST CHAR16**)Environment,\r
+      StatusCode);\r
 \r
-  Temp = NULL;\r
-  Size = 0;\r
-  ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
-  StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
-  StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
+    //\r
+    // de-allocate and return\r
+    //\r
+    FreePool(DevPath);\r
+    FreePool(Temp);\r
+  } else {\r
+    // If Environment is NULL, we are free to use and mutate the current shell\r
+    // environment. This is much faster as uses much less memory.\r
 \r
-  Status = InternalShellExecuteDevicePath(\r
-    ParentImageHandle,\r
-    DevPath,\r
-    Temp,\r
-    (CONST CHAR16**)Environment,\r
-    StatusCode);\r
+    if (CommandLine == NULL) {\r
+      CommandLine = L"";\r
+    }\r
+\r
+    Status = RunShellCommand (CommandLine, &CalleeStatusCode);\r
+\r
+    // Pass up the command's exit code if the caller wants it\r
+    if (StatusCode != NULL) {\r
+      *StatusCode = (EFI_STATUS) CalleeStatusCode;\r
+    }\r
+  }\r
 \r
-  //\r
-  // de-allocate and return\r
-  //\r
-  FreePool(DevPath);\r
-  FreePool(Temp);\r
   return(Status);\r
 }\r
 \r
@@ -2218,7 +2242,7 @@ ShellSearchHandle(
 \r
   CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));\r
   ASSERT(CurrentFilePattern != NULL);\r
-  StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern);\r
+  StrnCpyS(CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
 \r
   if (CurrentFilePattern[0]   == CHAR_NULL\r
     &&NextFilePatternStart[0] == CHAR_NULL\r
@@ -2282,8 +2306,8 @@ ShellSearchHandle(
             if (NewFullName == NULL) {\r
               Status = EFI_OUT_OF_RESOURCES;\r
             } else {\r
-              StrnCpy(NewFullName, MapName, Size/sizeof(CHAR16)-1);\r
-              StrnCat(NewFullName, ShellInfoNode->FullName+1, (Size/sizeof(CHAR16))-StrLen(NewFullName)-1);\r
+              StrCpyS(NewFullName, Size/sizeof(CHAR16), MapName);\r
+              StrCatS(NewFullName, Size/sizeof(CHAR16), ShellInfoNode->FullName+1);\r
               FreePool((VOID*)ShellInfoNode->FullName);\r
               ShellInfoNode->FullName = NewFullName;\r
             }\r
@@ -2493,6 +2517,7 @@ EfiShellOpenFileList(
     CurDir = EfiShellGetCurDir(NULL);\r
     ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
     StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
+    StrnCatGrow(&Path2, &Path2Size, L"\\", 0);\r
     if (*Path == L'\\') {\r
       Path++;\r
       while (PathRemoveLastItem(Path2)) ;\r
@@ -2613,7 +2638,10 @@ EfiShellGetEnvEx(
       ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
      ){\r
       ASSERT(Node->Key != NULL);\r
-      StrnCpy(CurrentWriteLocation, Node->Key,  (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)) - 1);\r
+      StrCpyS( CurrentWriteLocation, \r
+                (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)), \r
+                Node->Key\r
+                );\r
       CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
     }\r
 \r
@@ -2791,6 +2819,8 @@ EfiShellSetEnv(
   FileSystemMapping is not NULL, it returns the current directory associated with the\r
   FileSystemMapping. In both cases, the returned name includes the file system\r
   mapping (i.e. fs0:\current-dir).\r
+  \r
+  Note that the current directory string should exclude the tailing backslash character.\r
 \r
   @param FileSystemMapping      A pointer to the file system mapping. If NULL,\r
                                 then the current working directory is returned.\r
@@ -2847,6 +2877,8 @@ EfiShellGetCurDir(
   If the current working directory or the current working file system is changed then the\r
   %cwd% environment variable will be updated\r
 \r
+  Note that the current directory string should exclude the tailing backslash character.\r
+\r
   @param FileSystem             A pointer to the file system's mapped name. If NULL, then the current working\r
                                 directory is changed.\r
   @param Dir                    Points to the NULL-terminated directory on the device specified by FileSystem.\r
@@ -2934,9 +2966,11 @@ EfiShellSetCurDir(
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
     }\r
-    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
+    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
-      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+      if (MapListItem->CurrentDirectoryPath != NULL) {\r
+        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
+      }\r
     }\r
   } else {\r
     //\r
@@ -2968,9 +3002,9 @@ EfiShellSetCurDir(
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
-      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') {\r
+      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') {\r
         ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
-        MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
       }\r
     }\r
   }\r
@@ -3044,7 +3078,11 @@ EfiShellGetHelpText(
       FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
       ASSERT(FixCommand != NULL);\r
 \r
-      StrnCpy(FixCommand, Command, StrLen(Command)-4);\r
+      StrnCpyS( FixCommand, \r
+                (StrSize(Command) - 4 * sizeof (CHAR16))/sizeof(CHAR16), \r
+                Command, \r
+                StrLen(Command)-4\r
+                );\r
       Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
       FreePool(FixCommand);\r
       return Status;\r
@@ -3102,20 +3140,17 @@ EFIAPI
 InternalEfiShellGetListAlias(\r
   )\r
 {\r
-  UINT64            MaxStorSize;\r
-  UINT64            RemStorSize;\r
-  UINT64            MaxVarSize;\r
+  \r
   EFI_STATUS        Status;\r
   EFI_GUID          Guid;\r
   CHAR16            *VariableName;\r
   UINTN             NameSize;\r
+  UINTN             NameBufferSize;\r
   CHAR16            *RetVal;\r
   UINTN             RetSize;\r
 \r
-  Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
-  ASSERT_EFI_ERROR(Status);\r
-\r
-  VariableName  = AllocateZeroPool((UINTN)MaxVarSize);\r
+  NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
+  VariableName  = AllocateZeroPool(NameBufferSize);\r
   RetSize       = 0;\r
   RetVal        = NULL;\r
 \r
@@ -3126,22 +3161,38 @@ InternalEfiShellGetListAlias(
   VariableName[0] = CHAR_NULL;\r
 \r
   while (TRUE) {\r
-    NameSize = (UINTN)MaxVarSize;\r
+    NameSize = NameBufferSize;\r
     Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
     if (Status == EFI_NOT_FOUND){\r
       break;\r
-    }\r
-    ASSERT_EFI_ERROR(Status);\r
-    if (EFI_ERROR(Status)) {\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
+        SHELL_FREE_NON_NULL(RetVal);\r
+        RetVal = NULL;\r
+        break;\r
+      }\r
+      \r
+      NameSize = NameBufferSize;\r
+      Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
+    }\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      SHELL_FREE_NON_NULL(RetVal);\r
+      RetVal = NULL;\r
       break;\r
     }\r
+    \r
     if (CompareGuid(&Guid, &gShellAliasGuid)){\r
       ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
     } // compare guid\r
   } // while\r
-  FreePool(VariableName);\r
+  SHELL_FREE_NON_NULL(VariableName);\r
 \r
   return (RetVal);\r
 }\r
@@ -3199,6 +3250,7 @@ EfiShellGetAlias(
   UINT32      Attribs;\r
   EFI_STATUS  Status;\r
   CHAR16      *AliasLower;\r
+  CHAR16      *AliasVal;\r
 \r
   // Convert to lowercase to make aliases case-insensitive\r
   if (Alias != NULL) {\r
@@ -3207,7 +3259,8 @@ EfiShellGetAlias(
     ToLower (AliasLower);\r
 \r
     if (Volatile == NULL) {\r
-      return (AddBufferToFreeList(GetVariable(AliasLower, &gShellAliasGuid)));\r
+      GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
+      return (AddBufferToFreeList(AliasVal));\r
     }\r
     RetSize = 0;\r
     RetVal = NULL;\r