]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg: add array index check for shell delay option
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index 5471930ba19140c42ec1ec9877a83e6c53c30fbe..ec344137d355e2dad689bc54f71c3839a896d7f5 100644 (file)
@@ -1,8 +1,9 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
   (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  Copyright 2015-2018 Dell Technologies.<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
@@ -104,7 +105,7 @@ TrimSpaces(
 }\r
 \r
 /**\r
-  Parse for the next instance of one string within another string. Can optionally make sure that \r
+  Parse for the next instance of one string within another string. Can optionally make sure that\r
   the string was not escaped (^ character) per the shell specification.\r
 \r
   @param[in] SourceString             The string to search within\r
@@ -160,13 +161,13 @@ IsValidEnvironmentVariableName(
   )\r
 {\r
   CONST CHAR16    *Walker;\r
-  \r
+\r
   Walker = NULL;\r
 \r
   ASSERT (BeginPercent != NULL);\r
   ASSERT (EndPercent != NULL);\r
   ASSERT (BeginPercent < EndPercent);\r
-  \r
+\r
   if ((BeginPercent + 1) == EndPercent) {\r
     return FALSE;\r
   }\r
@@ -212,9 +213,9 @@ ContainsSplit(
   SecondQuote   = NULL;\r
   TempSpot      = FindFirstCharacter(CmdLine, L"|", L'^');\r
 \r
-  if (FirstQuote == NULL    || \r
-      TempSpot == NULL      || \r
-      TempSpot == CHAR_NULL || \r
+  if (FirstQuote == NULL    ||\r
+      TempSpot == NULL      ||\r
+      TempSpot == CHAR_NULL ||\r
       FirstQuote > TempSpot\r
       ) {\r
     return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
@@ -223,7 +224,7 @@ ContainsSplit(
   while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) {\r
     if (FirstQuote == NULL || FirstQuote > TempSpot) {\r
       break;\r
-    }    \r
+    }\r
     SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE);\r
     if (SecondQuote == NULL) {\r
       break;\r
@@ -235,14 +236,14 @@ ContainsSplit(
       FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);\r
       TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');\r
       continue;\r
-    } \r
+    }\r
   }\r
-  \r
+\r
   return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
 }\r
 \r
 /**\r
-  Function to start monitoring for CTRL-S using SimpleTextInputEx.  This \r
+  Function to start monitoring for CTRL-S using SimpleTextInputEx.  This\r
   feature's enabled state was not known when the shell initially launched.\r
 \r
   @retval EFI_SUCCESS           The feature is enabled.\r
@@ -266,8 +267,8 @@ InternalEfiShellStartCtrlSMonitor(
     EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
   if (EFI_ERROR(Status)) {\r
     ShellPrintHiiEx(\r
-      -1, \r
-      -1, \r
+      -1,\r
+      -1,\r
       NULL,\r
       STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
       ShellInfoObject.HiiHandle);\r
@@ -284,7 +285,7 @@ InternalEfiShellStartCtrlSMonitor(
     &KeyData,\r
     NotificationFunction,\r
     &ShellInfoObject.CtrlSNotifyHandle1);\r
-  \r
+\r
   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
   if (!EFI_ERROR(Status)) {\r
     Status = SimpleEx->RegisterKeyNotify(\r
@@ -302,7 +303,7 @@ InternalEfiShellStartCtrlSMonitor(
       &KeyData,\r
       NotificationFunction,\r
       &ShellInfoObject.CtrlSNotifyHandle3);\r
-  }  \r
+  }\r
   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
   if (!EFI_ERROR(Status)) {\r
     Status = SimpleEx->RegisterKeyNotify(\r
@@ -620,11 +621,6 @@ UefiMain (
           ShellInfoObject.ConsoleInfo->Enabled    = TRUE;\r
           ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
 \r
-          //\r
-          // Reset the CTRL-C event (yes we ignore the return values)\r
-          //\r
-          Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
-\r
           //\r
           // Display Prompt\r
           //\r
@@ -726,6 +722,7 @@ FreeResources:
 **/\r
 EFI_STATUS\r
 SetBuiltInAlias(\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -1005,7 +1002,11 @@ ProcessCommandLine(
                                  ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay        = TRUE;\r
       // Check for optional delay value following "-delay"\r
-      DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+      if ((LoopVar + 1) >= gEfiShellParametersProtocol->Argc) {\r
+        DelayValueStr = NULL;\r
+      } else {\r
+        DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+      }\r
       if (DelayValueStr != NULL){\r
         if (*DelayValueStr == L':') {\r
           DelayValueStr++;\r
@@ -1133,7 +1134,7 @@ ProcessCommandLine(
 \r
 /**\r
   Function try to find location of the Startup.nsh file.\r
-  \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
@@ -1160,7 +1161,7 @@ LocateStartupScript (
   // 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
+  if (MapName != NULL) {\r
     StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0);\r
     if (StartupScriptPath == NULL) {\r
       //\r
@@ -1173,6 +1174,8 @@ LocateStartupScript (
       *TempSpot = CHAR_NULL;\r
     }\r
 \r
+    InternalEfiShellSetEnv(L"homefilesystem", StartupScriptPath, TRUE);\r
+\r
     StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0);\r
     PathRemoveLastItem (StartupScriptPath);\r
     StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0);\r
@@ -1210,6 +1213,7 @@ DoStartupScript(
   UINTN                         Delay;\r
   EFI_INPUT_KEY                 Key;\r
   CHAR16                        *FileStringPath;\r
+  CHAR16                        *FullFileStringPath;\r
   UINTN                         NewSize;\r
 \r
   Key.UnicodeChar = CHAR_NULL;\r
@@ -1277,7 +1281,13 @@ DoStartupScript(
 \r
   FileStringPath = LocateStartupScript (ImagePath, FilePath);\r
   if (FileStringPath != NULL) {\r
-    Status = RunScriptFile (FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
+    FullFileStringPath = FullyQualifyPath(FileStringPath);\r
+    if (FullFileStringPath == NULL) {\r
+      Status = RunScriptFile (FileStringPath, NULL, FileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
+    } else {\r
+      Status = RunScriptFile (FullFileStringPath, NULL, FullFileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
+      FreePool(FullFileStringPath);\r
+    }\r
     FreePool (FileStringPath);\r
   } else {\r
     //\r
@@ -1345,9 +1355,14 @@ DoShellPrompt (
   // Null terminate the string and parse it\r
   //\r
   if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Reset the CTRL-C event just before running the command (yes we ignore the return values)\r
+    //\r
+    Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
+\r
     CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
     Status = RunCommand(CmdLine);\r
-    }\r
+  }\r
 \r
   //\r
   // Done with this command\r
@@ -1386,7 +1401,7 @@ AddBufferToFreeList (
 \r
 \r
 /**\r
-  Create a new buffer list and stores the old one to OldBufferList \r
+  Create a new buffer list and stores the old one to OldBufferList\r
 \r
   @param OldBufferList   The temporary list head used to store the nodes in BufferToFreeList.\r
 **/\r
@@ -1431,7 +1446,7 @@ AddLineToCommandHistory(
 \r
   Count = 0;\r
   MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount);\r
-  \r
+\r
   if (MaxHistoryCmdCount == 0) {\r
     return ;\r
   }\r
@@ -1545,7 +1560,7 @@ StripUnreplacedEnvironmentVariables(
       }\r
       continue;\r
     }\r
-    \r
+\r
     if (FirstQuote == NULL || SecondPercent < FirstQuote) {\r
       if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) {\r
         //\r
@@ -1646,7 +1661,7 @@ ShellConvertVariables (
   //\r
   // now do the replacements...\r
   //\r
-  NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\r
+  NewCommandLine1 = AllocateZeroPool (NewSize);\r
   NewCommandLine2 = AllocateZeroPool(NewSize);\r
   ItemTemp        = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
   if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
@@ -1655,20 +1670,22 @@ ShellConvertVariables (
     SHELL_FREE_NON_NULL(ItemTemp);\r
     return (NULL);\r
   }\r
+  CopyMem (NewCommandLine1, OriginalCommandLine, StrSize (OriginalCommandLine));\r
+\r
   for (MasterEnvList = EfiShellGetEnv(NULL)\r
     ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
     ;  MasterEnvList += StrLen(MasterEnvList) + 1\r
    ){\r
-    StrCpyS( ItemTemp, \r
-              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+    StrCpyS( ItemTemp,\r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
               L"%"\r
               );\r
-    StrCatS( ItemTemp, \r
-              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+    StrCatS( ItemTemp,\r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
               MasterEnvList\r
               );\r
-    StrCatS( ItemTemp, \r
-              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+    StrCatS( ItemTemp,\r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
               L"%"\r
               );\r
     ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
@@ -1694,7 +1711,7 @@ ShellConvertVariables (
   //\r
   ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
   StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
-  \r
+\r
   FreePool(NewCommandLine2);\r
   FreePool(ItemTemp);\r
 \r
@@ -1820,7 +1837,7 @@ RunSplitCommand(
 }\r
 \r
 /**\r
-  Take the original command line, substitute any variables, free \r
+  Take the original command line, substitute any variables, free\r
   the original string, return the modified copy.\r
 \r
   @param[in] CmdLine  pointer to the command line to update.\r
@@ -1844,7 +1861,7 @@ ShellSubstituteVariables(
 }\r
 \r
 /**\r
-  Take the original command line, substitute any alias in the first group of space delimited characters, free \r
+  Take the original command line, substitute any alias in the first group of space delimited characters, free\r
   the original string, return the modified copy.\r
 \r
   @param[in] CmdLine  pointer to the command line to update.\r
@@ -1903,7 +1920,7 @@ ShellSubstituteAliases(
 \r
   SHELL_FREE_NON_NULL(*CmdLine);\r
   SHELL_FREE_NON_NULL(CommandName);\r
\r
+\r
   //\r
   // re-assign the passed in double pointer to point to our newly allocated buffer\r
   //\r
@@ -1916,7 +1933,7 @@ ShellSubstituteAliases(
   Takes the Argv[0] part of the command line and determine the meaning of it.\r
 \r
   @param[in] CmdName  pointer to the command line to update.\r
-  \r
+\r
   @retval Internal_Command    The name is an internal command.\r
   @retval File_Sys_Change     the name is a file system change.\r
   @retval Script_File_Name    the name is a NSH script file.\r
@@ -1944,7 +1961,7 @@ GetOperationType(
   // Test for file system change request.  anything ending with first : and cant have spaces.\r
   //\r
   if (CmdName[(StrLen(CmdName)-1)] == L':') {\r
-    if ( StrStr(CmdName, L" ") != NULL \r
+    if ( StrStr(CmdName, L" ") != NULL\r
       || StrLen(StrStr(CmdName, L":")) > 1\r
       ) {\r
       return (Unknown_Invalid);\r
@@ -1974,7 +1991,7 @@ GetOperationType(
     SHELL_FREE_NON_NULL(FileWithPath);\r
     return (Efi_Application);\r
   }\r
-  \r
+\r
   SHELL_FREE_NON_NULL(FileWithPath);\r
   //\r
   // No clue what this is... return invalid flag...\r
@@ -1991,7 +2008,7 @@ GetOperationType(
   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
   @retval EFI_NOT_FOUND         The operation type is unknown or invalid.\r
 **/\r
-EFI_STATUS \r
+EFI_STATUS\r
 IsValidSplit(\r
   IN CONST CHAR16 *CmdLine\r
   )\r
@@ -2076,13 +2093,13 @@ VerifySplit(
   // recurse to verify the next item\r
   //\r
   TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;\r
-  if (*TempSpot == L'a' && \r
+  if (*TempSpot == L'a' &&\r
       (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL)\r
      ) {\r
     // If it's an ASCII pipe '|a'\r
     TempSpot += 1;\r
   }\r
-  \r
+\r
   return (VerifySplit(TempSpot));\r
 }\r
 \r
@@ -2146,7 +2163,7 @@ ChangeMappedDrive(
   // make sure we are the right operation\r
   //\r
   ASSERT(CmdLine[(StrLen(CmdLine)-1)] == L':' && StrStr(CmdLine, L" ") == NULL);\r
-  \r
+\r
   //\r
   // Call the protocol API to do the work\r
   //\r
@@ -2291,7 +2308,7 @@ ProcessCommandLineToFinal(
   Run an internal shell command.\r
 \r
   This API will update the shell's environment since these commands are libraries.\r
-  \r
+\r
   @param[in] CmdLine          the command line to run.\r
   @param[in] FirstParameter   the first parameter on the command line\r
   @param[in] ParamProtocol    the shell parameters protocol pointer\r
@@ -2314,7 +2331,7 @@ RunInternalCommand(
   SHELL_STATUS              CommandReturnedStatus;\r
   BOOLEAN                   LastError;\r
   CHAR16                    *Walker;\r
-  CHAR16                    *NewCmdLine;  \r
+  CHAR16                    *NewCmdLine;\r
 \r
   NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
   if (NewCmdLine == NULL) {\r
@@ -2424,6 +2441,7 @@ RunCommandOrFile(
   EFI_STATUS                Status;\r
   EFI_STATUS                StartStatus;\r
   CHAR16                    *CommandWithPath;\r
+  CHAR16                    *FullCommandWithPath;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   SHELL_STATUS              CalleeExitStatus;\r
 \r
@@ -2469,7 +2487,13 @@ RunCommandOrFile(
       }\r
       switch (Type) {\r
         case   Script_File_Name:\r
-          Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
+          FullCommandWithPath = FullyQualifyPath(CommandWithPath);\r
+          if (FullCommandWithPath == NULL) {\r
+            Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
+          } else {\r
+            Status = RunScriptFile (FullCommandWithPath, NULL, CmdLine, ParamProtocol);\r
+            FreePool(FullCommandWithPath);\r
+          }\r
           break;\r
         case   Efi_Application:\r
           //\r
@@ -2594,7 +2618,7 @@ SetupAndRunCommandOrFile(
 /**\r
   Function will process and run a command line.\r
 \r
-  This will determine if the command line represents an internal shell \r
+  This will determine if the command line represents an internal shell\r
   command or dispatch an external application.\r
 \r
   @param[in] CmdLine      The command line to parse.\r
@@ -2670,7 +2694,7 @@ RunShellCommand(
     Status = ProcessNewSplitCommandLine(CleanOriginal);\r
     SHELL_FREE_NON_NULL(CleanOriginal);\r
     return (Status);\r
-  } \r
+  }\r
 \r
   //\r
   // We need the first parameter information so we can determine the operation type\r
@@ -2731,7 +2755,7 @@ RunShellCommand(
 /**\r
   Function will process and run a command line.\r
 \r
-  This will determine if the command line represents an internal shell \r
+  This will determine if the command line represents an internal shell\r
   command or dispatch an external application.\r
 \r
   @param[in] CmdLine      The command line to parse.\r
@@ -2747,38 +2771,6 @@ RunCommand(
   return (RunShellCommand(CmdLine, NULL));\r
 }\r
 \r
-\r
-STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
-/**\r
-  Function determines if the CommandName COULD be a valid command.  It does not determine whether\r
-  this is a valid command.  It only checks for invalid characters.\r
-\r
-  @param[in] CommandName    The name to check\r
-\r
-  @retval TRUE              CommandName could be a command name\r
-  @retval FALSE             CommandName could not be a valid command name\r
-**/\r
-BOOLEAN\r
-IsValidCommandName(\r
-  IN CONST CHAR16     *CommandName\r
-  )\r
-{\r
-  UINTN Count;\r
-  if (CommandName == NULL) {\r
-    ASSERT(FALSE);\r
-    return (FALSE);\r
-  }\r
-  for ( Count = 0\r
-      ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
-      ; Count++\r
-     ){\r
-    if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
-      return (FALSE);\r
-    }\r
-  }\r
-  return (TRUE);\r
-}\r
-\r
 /**\r
   Function to process a NSH script file via SHELL_FILE_HANDLE.\r
 \r
@@ -2839,7 +2831,12 @@ RunScriptFileHandle (
       DeleteScriptFileStruct(NewScriptFile);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
-    for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
+    //\r
+    // Put the full path of the script file into Argv[0] as required by section\r
+    // 3.6.2 of version 2.2 of the shell specification.\r
+    //\r
+    NewScriptFile->Argv[0] = StrnCatGrow(&NewScriptFile->Argv[0], NULL, NewScriptFile->ScriptName, 0);\r
+    for (LoopVar = 1 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
       ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
       NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
       if (NewScriptFile->Argv[LoopVar] == NULL) {\r
@@ -2904,8 +2901,8 @@ RunScriptFileHandle (
       ; // conditional increment in the body of the loop\r
   ){\r
     ASSERT(CommandLine2 != NULL);\r
-    StrnCpyS( CommandLine2, \r
-              PrintBuffSize/sizeof(CHAR16), \r
+    StrnCpyS( CommandLine2,\r
+              PrintBuffSize/sizeof(CHAR16),\r
               NewScriptFile->CurrentCommand->Cl,\r
               PrintBuffSize/sizeof(CHAR16) - 1\r
               );\r
@@ -2931,8 +2928,8 @@ RunScriptFileHandle (
       //\r
       // Due to variability in starting the find and replace action we need to have both buffers the same.\r
       //\r
-      StrnCpyS( CommandLine, \r
-                PrintBuffSize/sizeof(CHAR16), \r
+      StrnCpyS( CommandLine,\r
+                PrintBuffSize/sizeof(CHAR16),\r
                 CommandLine2,\r
                 PrintBuffSize/sizeof(CHAR16) - 1\r
                 );\r
@@ -2987,8 +2984,8 @@ RunScriptFileHandle (
       Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%8", L"\"\"", FALSE, FALSE);\r
       Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%9", L"\"\"", FALSE, FALSE);\r
 \r
-      StrnCpyS( CommandLine2, \r
-                PrintBuffSize/sizeof(CHAR16), \r
+      StrnCpyS( CommandLine2,\r
+                PrintBuffSize/sizeof(CHAR16),\r
                 CommandLine,\r
                 PrintBuffSize/sizeof(CHAR16) - 1\r
                 );\r