]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg: Update CWD and current mapping when commands return
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index b39d81d0eeb8b710e56e71dbc414f1c494f690bf..5471930ba19140c42ec1ec9877a83e6c53c30fbe 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
   (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -1022,7 +1022,7 @@ ProcessCommandLine(
       }\r
     } else if (UnicodeCollation->StriColl (\r
                                    UnicodeCollation,\r
-                                   L"-_exit",\r
+                                   L"-exit",\r
                                    CurrentArg\r
                                    ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = TRUE;\r
@@ -1042,11 +1042,31 @@ ProcessCommandLine(
         continue;\r
       }\r
 \r
-      ShellInfoObject.ShellInitSettings.FileName = AllocateCopyPool(StrSize(CurrentArg), CurrentArg);\r
+      ShellInfoObject.ShellInitSettings.FileName = NULL;\r
+      Size = 0;\r
+      //\r
+      // If first argument contains a space, then add double quotes before the argument\r
+      //\r
+      if (StrStr (CurrentArg, L" ") != NULL) {\r
+        StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0);\r
+        if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
+          return (EFI_OUT_OF_RESOURCES);\r
+        }\r
+      }\r
+      StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, CurrentArg, 0);\r
       if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
       //\r
+      // If first argument contains a space, then add double quotes after the argument\r
+      //\r
+      if (StrStr (CurrentArg, L" ") != NULL) {\r
+        StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0);\r
+        if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
+          return (EFI_OUT_OF_RESOURCES);\r
+        }\r
+      }\r
+      //\r
       // We found `file-name`.\r
       //\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
@@ -1055,13 +1075,28 @@ ProcessCommandLine(
       // Add `file-name-options`\r
       for (Size = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
         ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
-        StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
-                    &Size,\r
-                    L" ",\r
-                    0);\r
-        if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
-          SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
-          return (EFI_OUT_OF_RESOURCES);\r
+        //\r
+        // Add a space between arguments\r
+        //\r
+        if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, &Size, L" ", 0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
+        }\r
+        //\r
+        // If an argumnent contains a space, then add double quotes before the argument\r
+        //\r
+        if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+                      &Size,\r
+                      L"\"",\r
+                      0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
         }\r
         StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
                     &Size,\r
@@ -1071,6 +1106,19 @@ ProcessCommandLine(
           SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
           return (EFI_OUT_OF_RESOURCES);\r
         }\r
+        //\r
+        // If an argumnent contains a space, then add double quotes after the argument\r
+        //\r
+        if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+                      &Size,\r
+                      L"\"",\r
+                      0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
+        }\r
       }\r
     }\r
   }\r
@@ -1083,6 +1131,64 @@ ProcessCommandLine(
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Function try to find location of the Startup.nsh file.\r
+  \r
+  The buffer is callee allocated and should be freed by the caller.\r
+\r
+  @param    ImageDevicePath       The path to the image for shell.  first place to look for the startup script\r
+  @param    FileDevicePath        The path to the file for shell.  second place to look for the startup script.\r
+\r
+  @retval   NULL                  No Startup.nsh file was found.\r
+  @return   !=NULL                Pointer to NULL-terminated path.\r
+**/\r
+CHAR16 *\r
+LocateStartupScript (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *FileDevicePath\r
+  )\r
+{\r
+  CHAR16          *StartupScriptPath;\r
+  CHAR16          *TempSpot;\r
+  CONST CHAR16    *MapName;\r
+  UINTN           Size;\r
+\r
+  StartupScriptPath = NULL;\r
+  Size              = 0;\r
+\r
+  //\r
+  // Try to find 'Startup.nsh' in the directory where the shell itself was launched.\r
+  //\r
+  MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath (&ImageDevicePath);\r
+  if (MapName != NULL) {   \r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0);\r
+    if (StartupScriptPath == NULL) {\r
+      //\r
+      // Do not locate the startup script in sys path when out of resource.\r
+      //\r
+      return NULL;\r
+    }\r
+    TempSpot = StrStr (StartupScriptPath, L";");\r
+    if (TempSpot != NULL) {\r
+      *TempSpot = CHAR_NULL;\r
+    }\r
+\r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0);\r
+    PathRemoveLastItem (StartupScriptPath);\r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0);\r
+  }\r
+\r
+  //\r
+  // Try to find 'Startup.nsh' in the execution path defined by the envrionment variable PATH.\r
+  //\r
+  if ((StartupScriptPath == NULL) || EFI_ERROR (ShellIsFile (StartupScriptPath))) {\r
+    SHELL_FREE_NON_NULL (StartupScriptPath);\r
+    StartupScriptPath = ShellFindFilePath (mStartupScript);\r
+  }\r
+\r
+  return StartupScriptPath;\r
+}\r
+\r
 /**\r
   Handles all interaction with the default startup script.\r
 \r
@@ -1103,17 +1209,11 @@ DoStartupScript(
   EFI_STATUS                    CalleeStatus;\r
   UINTN                         Delay;\r
   EFI_INPUT_KEY                 Key;\r
-  SHELL_FILE_HANDLE             FileHandle;\r
-  EFI_DEVICE_PATH_PROTOCOL      *NewPath;\r
-  EFI_DEVICE_PATH_PROTOCOL      *NamePath;\r
   CHAR16                        *FileStringPath;\r
-  CHAR16                        *TempSpot;\r
   UINTN                         NewSize;\r
-  CONST CHAR16                  *MapName;\r
 \r
   Key.UnicodeChar = CHAR_NULL;\r
   Key.ScanCode    = 0;\r
-  FileHandle      = NULL;\r
 \r
   if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
     //\r
@@ -1175,60 +1275,17 @@ DoStartupScript(
     return (EFI_SUCCESS);\r
   }\r
 \r
-  //\r
-  // Try the first location (must be file system)\r
-  //\r
-  MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath(&ImagePath);\r
-  if (MapName != NULL) {\r
-    FileStringPath = NULL;\r
-    NewSize = 0;\r
-    FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, MapName, 0);\r
-    if (FileStringPath == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-    } else {\r
-      TempSpot = StrStr(FileStringPath, L";");\r
-      if (TempSpot != NULL) {\r
-        *TempSpot = CHAR_NULL;\r
-      }\r
-      FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, ((FILEPATH_DEVICE_PATH*)FilePath)->PathName, 0);\r
-      PathRemoveLastItem(FileStringPath);\r
-      FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, mStartupScript, 0);\r
-      Status = ShellInfoObject.NewEfiShellProtocol->OpenFileByName(FileStringPath, &FileHandle, EFI_FILE_MODE_READ);\r
-      FreePool(FileStringPath);\r
-    }\r
-  }\r
-  if (EFI_ERROR(Status)) {\r
-    NamePath = FileDevicePath (NULL, mStartupScript);\r
-    NewPath = AppendDevicePathNode (ImagePath, NamePath);\r
-    FreePool(NamePath);\r
-\r
+  FileStringPath = LocateStartupScript (ImagePath, FilePath);\r
+  if (FileStringPath != NULL) {\r
+    Status = RunScriptFile (FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
+    FreePool (FileStringPath);\r
+  } else {\r
     //\r
-    // Try the location\r
+    // we return success since startup script is not mandatory.\r
     //\r
-    Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
-    FreePool(NewPath);\r
-  }\r
-  //\r
-  // If we got a file, run it\r
-  //\r
-  if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
-    Status = RunScriptFile (mStartupScript, FileHandle, L"", ShellInfoObject.NewShellParametersProtocol);\r
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
-  } else {\r
-    FileStringPath = ShellFindFilePath(mStartupScript);\r
-    if (FileStringPath == NULL) {\r
-      //\r
-      // we return success since we don't need to have a startup script\r
-      //\r
-      Status = EFI_SUCCESS;\r
-      ASSERT(FileHandle == NULL);\r
-    } else {\r
-      Status = RunScriptFile(FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
-      FreePool(FileStringPath);\r
-    }\r
+    Status = EFI_SUCCESS;\r
   }\r
 \r
-\r
   return (Status);\r
 }\r
 \r
@@ -1657,8 +1714,8 @@ ShellConvertVariables (
 EFI_STATUS\r
 RunSplitCommand(\r
   IN CONST CHAR16             *CmdLine,\r
-  IN       SHELL_FILE_HANDLE  *StdIn,\r
-  IN       SHELL_FILE_HANDLE  *StdOut\r
+  IN       SHELL_FILE_HANDLE  StdIn,\r
+  IN       SHELL_FILE_HANDLE  StdOut\r
   )\r
 {\r
   EFI_STATUS        Status;\r
@@ -1667,7 +1724,7 @@ RunSplitCommand(
   UINTN             Size1;\r
   UINTN             Size2;\r
   SPLIT_LIST        *Split;\r
-  SHELL_FILE_HANDLE *TempFileHandle;\r
+  SHELL_FILE_HANDLE TempFileHandle;\r
   BOOLEAN           Unicode;\r
 \r
   ASSERT(StdOut == NULL);\r
@@ -1733,7 +1790,7 @@ RunSplitCommand(
     Split->SplitStdOut  = Split->SplitStdIn;\r
   }\r
   Split->SplitStdIn   = TempFileHandle;\r
-  ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
+  ShellInfoObject.NewEfiShellProtocol->SetFilePosition (Split->SplitStdIn, 0);\r
 \r
   if (!EFI_ERROR(Status)) {\r
     Status = RunCommand(NextCommandLine);\r
@@ -1749,11 +1806,10 @@ RunSplitCommand(
   // Note that the original StdIn is now the StdOut...\r
   //\r
   if (Split->SplitStdOut != NULL) {\r
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));\r
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdOut);\r
   }\r
   if (Split->SplitStdIn != NULL) {\r
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));\r
-    FreePool (Split->SplitStdIn);\r
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn);\r
   }\r
 \r
   FreePool(Split);\r
@@ -2558,6 +2614,7 @@ RunShellCommand(
   CHAR16                    *FirstParameter;\r
   CHAR16                    *TempWalker;\r
   SHELL_OPERATION_TYPES     Type;\r
+  CONST CHAR16              *CurDir;\r
 \r
   ASSERT(CmdLine != NULL);\r
   if (StrLen(CmdLine) == 0) {\r
@@ -2649,7 +2706,22 @@ RunShellCommand(
     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
     SetLastError(SHELL_NOT_FOUND);\r
   }\r
\r
+  //\r
+  // Check whether the current file system still exists. If not exist, we need update "cwd" and gShellCurMapping.\r
+  //\r
+  CurDir = EfiShellGetCurDir (NULL);\r
+  if (CurDir != NULL) {\r
+    if (EFI_ERROR(ShellFileExists (CurDir))) {\r
+      //\r
+      // EfiShellSetCurDir() cannot set current directory to NULL.\r
+      // EfiShellSetEnv() is not allowed to set the "cwd" variable.\r
+      // Only InternalEfiShellSetEnv () is allowed setting the "cwd" variable.\r
+      //\r
+      InternalEfiShellSetEnv (L"cwd", NULL, TRUE);\r
+      gShellCurMapping = NULL;\r
+    }\r
+  }\r
+\r
   SHELL_FREE_NON_NULL(CleanOriginal);\r
   SHELL_FREE_NON_NULL(FirstParameter);\r
 \r