]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg/ShellProtocol.c: Handle memory allocation failure
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index 97b8c8d6fbee39a890b6b48216fec8d0dd723a88..713c317d7411bd5baede23f6368dd4f81abc7825 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2016, 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
@@ -33,6 +33,7 @@ SHELL_INFO ShellInfoObject = {
       0,\r
       0,\r
       0,\r
+      0,\r
       0\r
     }},\r
     0,\r
@@ -69,6 +70,9 @@ SHELL_INFO ShellInfoObject = {
 STATIC CONST CHAR16 mScriptExtension[]      = L".NSH";\r
 STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI";\r
 STATIC CONST CHAR16 mStartupScript[]        = L"startup.nsh";\r
+CONST CHAR16 mNoNestingEnvVarName[]         = L"nonesting";\r
+CONST CHAR16 mNoNestingTrue[]               = L"True";\r
+CONST CHAR16 mNoNestingFalse[]              = L"False";\r
 \r
 /**\r
   Cleans off leading and trailing spaces and tabs.\r
@@ -338,6 +342,7 @@ UefiMain (
   UINTN                           Size;\r
   EFI_HANDLE                      ConInHandle;\r
   EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *OldConIn;\r
+  SPLIT_LIST                      *Split;\r
 \r
   if (PcdGet8(PcdShellSupportLevel) > 3) {\r
     return (EFI_UNSUPPORTED);\r
@@ -441,6 +446,8 @@ UefiMain (
     Status = CommandInit();\r
     ASSERT_EFI_ERROR(Status);\r
 \r
+    Status = ShellInitEnvVarList ();\r
+\r
     //\r
     // Check the command line\r
     //\r
@@ -456,6 +463,29 @@ UefiMain (
       Status = ShellCommandCreateInitialMappingsAndPaths();\r
     }\r
 \r
+    //\r
+    // Set the environment variable for nesting support\r
+    //\r
+    Size = 0;\r
+    TempString = NULL;\r
+    if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
+      //\r
+      // No change.  require nesting in Shell Protocol Execute()\r
+      //\r
+      StrnCatGrow(&TempString,\r
+                  &Size,\r
+                  L"False",\r
+                  0);\r
+    } else {\r
+      StrnCatGrow(&TempString,\r
+                  &Size,\r
+                  mNoNestingTrue,\r
+                  0);\r
+    }\r
+    Status = InternalEfiShellSetEnv(mNoNestingEnvVarName, TempString, TRUE);\r
+    SHELL_FREE_NON_NULL(TempString);\r
+    Size = 0;\r
+\r
     //\r
     // save the device path for the loaded image and the device path for the filepath (under loaded image)\r
     // These are where to look for the startup.nsh file\r
@@ -646,7 +676,17 @@ FreeResources:
   }\r
 \r
   if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){\r
-    ASSERT(FALSE); ///@todo finish this de-allocation.\r
+    ASSERT(FALSE); ///@todo finish this de-allocation (free SplitStdIn/Out when needed).\r
+\r
+    for ( Split = (SPLIT_LIST*)GetFirstNode (&ShellInfoObject.SplitList.Link)\r
+        ; !IsNull (&ShellInfoObject.SplitList.Link, &Split->Link)\r
+        ; Split = (SPLIT_LIST *)GetNextNode (&ShellInfoObject.SplitList.Link, &Split->Link)\r
+     ) {\r
+      RemoveEntryList (&Split->Link);\r
+      FreePool (Split);\r
+    }\r
+\r
+    DEBUG_CODE (InitializeListHead (&ShellInfoObject.SplitList.Link););\r
   }\r
 \r
   if (ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
@@ -675,6 +715,8 @@ FreeResources:
     DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
   }\r
 \r
+  ShellFreeEnvVarList ();\r
+\r
   if (ShellCommandGetExit()) {\r
     return ((EFI_STATUS)ShellCommandGetExitCode());\r
   }\r
@@ -873,12 +915,19 @@ ProcessCommandLine(
   // like a shell option (which is assumed to be `file-name`).\r
 \r
   Status = gBS->LocateProtocol (\r
-                  &gEfiUnicodeCollationProtocolGuid,\r
+                  &gEfiUnicodeCollation2ProtocolGuid,\r
                   NULL,\r
                   (VOID **) &UnicodeCollation\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiUnicodeCollationProtocolGuid,\r
+                    NULL,\r
+                    (VOID **) &UnicodeCollation\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   // Set default options\r
@@ -891,6 +940,7 @@ ProcessCommandLine(
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion    = FALSE;\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay        = FALSE;\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = FALSE;\r
+  ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest       = FALSE;\r
   ShellInfoObject.ShellInitSettings.Delay = 5;\r
 \r
   //\r
@@ -950,6 +1000,13 @@ ProcessCommandLine(
                                  ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion    = TRUE;\r
     }\r
+    else if (UnicodeCollation->StriColl (\r
+                                 UnicodeCollation,\r
+                                 L"-nonest",\r
+                                 CurrentArg\r
+                                 ) == 0) {\r
+      ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest       = TRUE;\r
+    }\r
     else if (UnicodeCollation->StriColl (\r
                                  UnicodeCollation,\r
                                  L"-delay",\r
@@ -1205,6 +1262,7 @@ DoShellPrompt (
   CONST CHAR16  *CurDir;\r
   UINTN         BufferSize;\r
   EFI_STATUS    Status;\r
+  LIST_ENTRY    OldBufferList;\r
 \r
   CurDir  = NULL;\r
 \r
@@ -1218,6 +1276,7 @@ DoShellPrompt (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  SaveBufferList(&OldBufferList);\r
   CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
 \r
   //\r
@@ -1247,6 +1306,7 @@ DoShellPrompt (
   //\r
   // Done with this command\r
   //\r
+  RestoreBufferList(&OldBufferList);\r
   FreePool (CmdLine);\r
   return Status;\r
 }\r
@@ -1259,7 +1319,7 @@ DoShellPrompt (
 **/\r
 VOID*\r
 EFIAPI\r
-AddBufferToFreeList(\r
+AddBufferToFreeList (\r
   VOID *Buffer\r
   )\r
 {\r
@@ -1269,13 +1329,46 @@ AddBufferToFreeList(
     return (NULL);\r
   }\r
 \r
-  BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST));\r
-  ASSERT(BufferListEntry != NULL);\r
+  BufferListEntry = AllocateZeroPool (sizeof (BUFFER_LIST));\r
+  if (BufferListEntry == NULL) {\r
+    return NULL;\r
+  }\r
+\r
   BufferListEntry->Buffer = Buffer;\r
-  InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
+  InsertTailList (&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
   return (Buffer);\r
 }\r
 \r
+\r
+/**\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
+VOID\r
+SaveBufferList (\r
+  OUT LIST_ENTRY     *OldBufferList\r
+  )\r
+{\r
+  CopyMem (OldBufferList, &ShellInfoObject.BufferToFreeList.Link, sizeof (LIST_ENTRY));\r
+  InitializeListHead (&ShellInfoObject.BufferToFreeList.Link);\r
+}\r
+\r
+/**\r
+  Restore previous nodes into BufferToFreeList .\r
+\r
+  @param OldBufferList   The temporary list head used to store the nodes in BufferToFreeList.\r
+**/\r
+VOID\r
+RestoreBufferList (\r
+  IN OUT LIST_ENTRY     *OldBufferList\r
+  )\r
+{\r
+  FreeBufferList (&ShellInfoObject.BufferToFreeList);\r
+  CopyMem (&ShellInfoObject.BufferToFreeList.Link, OldBufferList, sizeof (LIST_ENTRY));\r
+}\r
+\r
+\r
 /**\r
   Add a buffer to the Line History List\r
 \r
@@ -1291,7 +1384,7 @@ AddLineToCommandHistory(
   BUFFER_LIST *Walker;\r
   UINT16       MaxHistoryCmdCount;\r
   UINT16       Count;\r
-  \r
+\r
   Count = 0;\r
   MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount);\r
   \r
@@ -1301,9 +1394,15 @@ AddLineToCommandHistory(
 \r
 \r
   Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
-  ASSERT(Node != NULL);\r
-  Node->Buffer = AllocateCopyPool(StrSize(Buffer), Buffer);\r
-  ASSERT(Node->Buffer != NULL);\r
+  if (Node == NULL) {\r
+    return;\r
+  }\r
+\r
+  Node->Buffer = AllocateCopyPool (StrSize (Buffer), Buffer);\r
+  if (Node->Buffer == NULL) {\r
+    FreePool (Node);\r
+    return;\r
+  }\r
 \r
   for ( Walker = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)\r
       ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Walker->Link)\r
@@ -1631,7 +1730,9 @@ RunSplitCommand(
   // make a SPLIT_LIST item and add to list\r
   //\r
   Split = AllocateZeroPool(sizeof(SPLIT_LIST));\r
-  ASSERT(Split != NULL);\r
+  if (Split == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
   Split->SplitStdIn   = StdIn;\r
   Split->SplitStdOut  = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL);\r
   ASSERT(Split->SplitStdOut != NULL);\r
@@ -1664,11 +1765,12 @@ RunSplitCommand(
   //\r
   // Note that the original StdIn is now the StdOut...\r
   //\r
-  if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) {\r
+  if (Split->SplitStdOut != NULL) {\r
     ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));\r
   }\r
   if (Split->SplitStdIn != NULL) {\r
     ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));\r
+    FreePool (Split->SplitStdIn);\r
   }\r
 \r
   FreePool(Split);\r
@@ -2419,7 +2521,7 @@ SetupAndRunCommandOrFile(
   IN   CHAR16                         *CmdLine,\r
   IN   CHAR16                         *FirstParameter,\r
   IN   EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol,\r
-  OUT EFI_STATUS                    *CommandStatus\r
+  OUT EFI_STATUS                      *CommandStatus\r
 )\r
 {\r
   EFI_STATUS                Status;\r
@@ -2427,6 +2529,7 @@ SetupAndRunCommandOrFile(
   SHELL_FILE_HANDLE         OriginalStdOut;\r
   SHELL_FILE_HANDLE         OriginalStdErr;\r
   SYSTEM_TABLE_INFO         OriginalSystemTableInfo;\r
+  CONST SCRIPT_FILE         *ConstScriptFile;\r
 \r
   //\r
   // Update the StdIn, StdOut, and StdErr for redirection to environment variables, files, etc... unicode and ASCII\r
@@ -2446,7 +2549,12 @@ SetupAndRunCommandOrFile(
   // Now print errors\r
   //\r
   if (EFI_ERROR(Status)) {\r
-    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
+    ConstScriptFile = ShellCommandGetCurrentScriptFile();\r
+    if (ConstScriptFile == NULL || ConstScriptFile->CurrentCommand == NULL) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
+    } else {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR_SCRIPT), ShellInfoObject.HiiHandle, (VOID*)(Status), ConstScriptFile->CurrentCommand->Line);\r
+    }\r
   }\r
 \r
   //\r
@@ -2661,6 +2769,7 @@ RunScriptFileHandle (
   CONST CHAR16        *CurDir;\r
   UINTN               LineCount;\r
   CHAR16              LeString[50];\r
+  LIST_ENTRY          OldBufferList;\r
 \r
   ASSERT(!ShellCommandGetScriptExit());\r
 \r
@@ -2763,6 +2872,8 @@ RunScriptFileHandle (
               PrintBuffSize/sizeof(CHAR16) - 1\r
               );\r
 \r
+    SaveBufferList(&OldBufferList);\r
+\r
     //\r
     // NULL out comments\r
     //\r
@@ -2897,15 +3008,19 @@ RunScriptFileHandle (
 \r
           ShellCommandRegisterExit(FALSE, 0);\r
           Status = EFI_SUCCESS;\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (ShellGetExecutionBreakFlag()) {\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (EFI_ERROR(Status)) {\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (ShellCommandGetExit()) {\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
       }\r
@@ -2924,6 +3039,7 @@ RunScriptFileHandle (
         NewScriptFile->CurrentCommand->Reset = TRUE;\r
       }\r
     }\r
+    RestoreBufferList(&OldBufferList);\r
   }\r
 \r
 \r