]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg/UefiShellLib.c: Execute: Return a Command status even in the old shell
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index df4874a23cf0df1fed392f27e23731c9bf9eda2d..0d3839783eb31f94c198394d024997560c8bc7ee 100644 (file)
@@ -2,7 +2,7 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
-  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2014, 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
@@ -115,27 +115,19 @@ InternalShellProtocolDebugPrintMessage (
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
   )\r
 {\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
   EFI_STATUS                        Status;\r
   CHAR16                            *Temp;\r
 \r
   Status = EFI_SUCCESS;\r
   DEBUG_CODE_BEGIN();\r
-  DevicePathToText = NULL;\r
 \r
-  Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid,\r
-                               NULL,\r
-                               (VOID**)&DevicePathToText);\r
   if (Mapping != NULL) {\r
     DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));\r
   }\r
-  if (!EFI_ERROR(Status)) {\r
-    if (DevicePath != NULL) {\r
-      Temp = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-      DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
-      FreePool(Temp);\r
-    }\r
-  }\r
+  Temp = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+  DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
+  FreePool(Temp);\r
+\r
   DEBUG_CODE_END();\r
   return (Status);\r
 }\r
@@ -647,15 +639,12 @@ EfiShellGetDeviceName(
 {\r
   EFI_STATUS                        Status;\r
   EFI_COMPONENT_NAME2_PROTOCOL      *CompName2;\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
   EFI_HANDLE                        *HandleList;\r
   UINTN                             HandleCount;\r
   UINTN                             LoopVar;\r
   CHAR16                            *DeviceNameToReturn;\r
   CHAR8                             *Lang;\r
-  CHAR8                             *TempChar;\r
-\r
   UINTN                             ParentControllerCount;\r
   EFI_HANDLE                        *ParentControllerBuffer;\r
   UINTN                             ParentDriverCount;\r
@@ -712,23 +701,7 @@ EfiShellGetDeviceName(
       if (EFI_ERROR(Status)) {\r
         continue;\r
       }\r
-      if (Language == NULL) {\r
-        Lang = AllocateZeroPool(AsciiStrSize(CompName2->SupportedLanguages));\r
-        if (Lang == NULL) {\r
-          return (EFI_OUT_OF_RESOURCES);\r
-        }\r
-        AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
-        TempChar = AsciiStrStr(Lang, ";");\r
-        if (TempChar != NULL){\r
-          *TempChar = CHAR_NULL;\r
-        }\r
-      } else {\r
-        Lang = AllocateZeroPool(AsciiStrSize(Language));\r
-        if (Lang == NULL) {\r
-          return (EFI_OUT_OF_RESOURCES);\r
-        }\r
-        AsciiStrCpy(Lang, Language);\r
-      }\r
+      Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
       Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
       FreePool(Lang);\r
       Lang = NULL;\r
@@ -771,23 +744,7 @@ EfiShellGetDeviceName(
           if (EFI_ERROR(Status)) {\r
             continue;\r
           }\r
-          if (Language == NULL) {\r
-            Lang = AllocateZeroPool(AsciiStrSize(CompName2->SupportedLanguages));\r
-            if (Lang == NULL) {\r
-              return (EFI_OUT_OF_RESOURCES);\r
-            }\r
-            AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
-            TempChar = AsciiStrStr(Lang, ";");\r
-            if (TempChar != NULL){\r
-              *TempChar = CHAR_NULL;\r
-            }\r
-          } else {\r
-            Lang = AllocateZeroPool(AsciiStrSize(Language));\r
-            if (Lang == NULL) {\r
-              return (EFI_OUT_OF_RESOURCES);\r
-            }\r
-            AsciiStrCpy(Lang, Language);\r
-          }\r
+          Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
           Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
           FreePool(Lang);\r
           Lang = NULL;\r
@@ -815,28 +772,19 @@ EfiShellGetDeviceName(
     }\r
   }\r
   if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
-    Status = gBS->LocateProtocol(\r
-      &gEfiDevicePathToTextProtocolGuid,\r
+    Status = gBS->OpenProtocol(\r
+      DeviceHandle,\r
+      &gEfiDevicePathProtocolGuid,\r
+      (VOID**)&DevicePath,\r
+      gImageHandle,\r
       NULL,\r
-      (VOID**)&DevicePathToText);\r
-    //\r
-    // we now have the device path to text protocol\r
-    //\r
+      EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
     if (!EFI_ERROR(Status)) {\r
-      Status = gBS->OpenProtocol(\r
-        DeviceHandle,\r
-        &gEfiDevicePathProtocolGuid,\r
-        (VOID**)&DevicePath,\r
-        gImageHandle,\r
-        NULL,\r
-        EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
-      if (!EFI_ERROR(Status)) {\r
-        //\r
-        // use device path to text on the device path\r
-        //\r
-        *BestDeviceName = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-        return (EFI_SUCCESS);\r
-      }\r
+      //\r
+      // use device path to text on the device path\r
+      //\r
+      *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+      return (EFI_SUCCESS);\r
     }\r
   }\r
   //\r
@@ -1410,6 +1358,9 @@ EfiShellEnablePageBreak (
                             is NULL, then the current shell environment is used.\r
   @param StatusCode         Points to the status code returned by the command.\r
 \r
+  @param[out] ExitDataSize  ExitDataSize as returned from gBS->StartImage\r
+  @param[out] ExitData      ExitData as returned from gBS->StartImage\r
+\r
   @retval EFI_SUCCESS       The command executed successfully. The  status code\r
                             returned by the command is pointed to by StatusCode.\r
   @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
@@ -1423,14 +1374,26 @@ InternalShellExecuteDevicePath(
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
   IN CONST CHAR16                   *CommandLine OPTIONAL,\r
   IN CONST CHAR16                   **Environment OPTIONAL,\r
-  OUT EFI_STATUS                    *StatusCode OPTIONAL\r
+  OUT UINTN                         *ExitDataSize OPTIONAL,\r
+  OUT CHAR16                        **ExitData OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanupStatus;\r
   EFI_HANDLE                    NewHandle;\r
   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
   LIST_ENTRY                    OrigEnvs;\r
   EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
+  UINTN                         InternalExitDataSize;\r
+  UINTN                         *ExitDataSizePtr;\r
+\r
+  // ExitDataSize is not OPTIONAL for gBS->BootServices, provide somewhere for\r
+  // it to be dumped if the caller doesn't want it.\r
+  if (ExitData == NULL) {\r
+    ExitDataSizePtr = &InternalExitDataSize;\r
+  } else {\r
+    ExitDataSizePtr = ExitDataSize;\r
+  }\r
 \r
   if (ParentImageHandle == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
@@ -1497,32 +1460,43 @@ InternalShellExecuteDevicePath(
     ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
 \r
     //\r
-    // now start the image and if the caller wanted the return code pass it to them...\r
+    // now start the image, passing up exit data if the caller requested it\r
     //\r
     if (!EFI_ERROR(Status)) {\r
-      if (StatusCode != NULL) {\r
-        *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);\r
-      } else {\r
-        Status      = gBS->StartImage(NewHandle, NULL, NULL);\r
-      }\r
+      Status      = gBS->StartImage(\r
+                          NewHandle,\r
+                          ExitDataSizePtr,\r
+                          ExitData\r
+                          );\r
     }\r
 \r
     //\r
     // Cleanup (and dont overwrite errors)\r
     //\r
     if (EFI_ERROR(Status)) {\r
-      gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
+      CleanupStatus = gBS->UninstallProtocolInterface(\r
+                            NewHandle,\r
+                            &gEfiShellParametersProtocolGuid,\r
+                            &ShellParamsProtocol\r
+                            );\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     } else {\r
-      Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
-      ASSERT_EFI_ERROR(Status);\r
+      CleanupStatus = gBS->UninstallProtocolInterface(\r
+                            NewHandle,\r
+                            &gEfiShellParametersProtocolGuid,\r
+                            &ShellParamsProtocol\r
+                            );\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     }\r
   }\r
 \r
   if (!IsListEmpty(&OrigEnvs)) {\r
     if (EFI_ERROR(Status)) {\r
-      SetEnvironmentVariableList(&OrigEnvs);\r
+      CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     } else {\r
-      Status = SetEnvironmentVariableList(&OrigEnvs);\r
+      CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+      ASSERT_EFI_ERROR (CleanupStatus);\r
     }\r
   }\r
 \r
@@ -1575,6 +1549,8 @@ EfiShellExecute(
   CHAR16                    *Temp;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   UINTN                     Size;\r
+  UINTN                     ExitDataSize;\r
+  CHAR16                    *ExitData;\r
 \r
   if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
     return (EFI_UNSUPPORTED);\r
@@ -1583,11 +1559,11 @@ EfiShellExecute(
   DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
 \r
   DEBUG_CODE_BEGIN();\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+  Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
   FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+  Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
   FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
+  Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
   FreePool(Temp);\r
   DEBUG_CODE_END();\r
 \r
@@ -1602,7 +1578,33 @@ EfiShellExecute(
     DevPath,\r
     Temp,\r
     (CONST CHAR16**)Environment,\r
-    StatusCode);\r
+    &ExitDataSize,\r
+    &ExitData);\r
+\r
+    if (Status == EFI_ABORTED) {\r
+      // If the command exited with an error, the shell should put the exit\r
+      // status in ExitData, preceded by a null-terminated string.\r
+      ASSERT (ExitDataSize == StrSize (ExitData) + sizeof (SHELL_STATUS));\r
+\r
+      if (StatusCode != NULL) {\r
+        // Skip the null-terminated string\r
+        ExitData += StrLen (ExitData) + 1;\r
+\r
+        // Use CopyMem to avoid alignment faults\r
+        CopyMem (StatusCode, ExitData, sizeof (SHELL_STATUS));\r
+\r
+        // Convert from SHELL_STATUS to EFI_STATUS\r
+        // EFI_STATUSes have top bit set when they are errors.\r
+        // (See UEFI Spec Appendix D)\r
+        if (*StatusCode != SHELL_SUCCESS) {\r
+          *StatusCode = (EFI_STATUS) *StatusCode | MAX_BIT;\r
+        }\r
+      }\r
+      FreePool (ExitData);\r
+      Status = EFI_SUCCESS;\r
+    } else if ((StatusCode != NULL) && !EFI_ERROR(Status)) {\r
+      *StatusCode = EFI_SUCCESS;\r
+    }\r
 \r
   //\r
   // de-allocate and return\r
@@ -1671,6 +1673,8 @@ EfiShellFreeFileList(
     RemoveEntryList(&ShellFileListItem->Link);\r
     InternalFreeShellFileInfoNode(ShellFileListItem);\r
   }\r
+  InternalFreeShellFileInfoNode(*FileList);\r
+  *FileList = NULL;\r
   return(EFI_SUCCESS);\r
 }\r
 \r
@@ -1766,7 +1770,6 @@ InternalDuplicateShellFileInfo(
 \r
   @param[in] BasePath         the Path to prepend onto filename for FullPath\r
   @param[in] Status           Status member initial value.\r
-  @param[in] FullName         FullName member initial value.\r
   @param[in] FileName         FileName member initial value.\r
   @param[in] Handle           Handle member initial value.\r
   @param[in] Info             Info struct to copy.\r
@@ -1779,7 +1782,6 @@ EFIAPI
 CreateAndPopulateShellFileInfo(\r
   IN CONST CHAR16 *BasePath,\r
   IN CONST EFI_STATUS Status,\r
-  IN CONST CHAR16 *FullName,\r
   IN CONST CHAR16 *FileName,\r
   IN CONST SHELL_FILE_HANDLE Handle,\r
   IN CONST EFI_FILE_INFO *Info\r
@@ -1888,6 +1890,7 @@ EfiShellFindFilesInDir(
     Size              = 0;\r
     TempString        = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);\r
     if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
     TempSpot          = StrStr(TempString, L";");\r
@@ -1898,8 +1901,10 @@ EfiShellFindFilesInDir(
 \r
     TempString        = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
     if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
+    SHELL_FREE_NON_NULL(BasePath);\r
     BasePath          = TempString;\r
   }\r
 \r
@@ -1914,20 +1919,14 @@ EfiShellFindFilesInDir(
       ; !EFI_ERROR(Status) && !NoFile\r
       ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)\r
      ){\r
-    TempString  = NULL;\r
-    Size        = 0;\r
     //\r
     // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
     //\r
-    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
-    TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
-    TempString = StrnCatGrow(&TempString, &Size, FileInfo->FileName, 0);\r
     ShellFileListItem = CreateAndPopulateShellFileInfo(\r
       BasePath,\r
-      EFI_SUCCESS, // success since we didnt fail to open it...\r
-      TempString,\r
+      EFI_SUCCESS,  // success since we didnt fail to open it...\r
       FileInfo->FileName,\r
-      NULL, // no handle since not open\r
+      NULL,         // no handle since not open\r
       FileInfo);\r
 \r
     if (ShellFileList == NULL) {\r
@@ -2821,15 +2820,33 @@ EfiShellGetHelpText(
   )\r
 {\r
   CONST CHAR16  *ManFileName;\r
+  CHAR16        *FixCommand;\r
+  EFI_STATUS    Status;\r
 \r
   ASSERT(HelpText != NULL);\r
+  FixCommand = NULL;\r
 \r
   ManFileName = ShellCommandGetManFileNameHandler(Command);\r
 \r
   if (ManFileName != NULL) {\r
     return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));\r
   } else {\r
-    return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    if ((StrLen(Command)> 4)\r
+    && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I')\r
+    && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F')\r
+    && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E')\r
+    && (Command[StrLen(Command)-4] == L'.')\r
+    ) {\r
+      FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
+      ASSERT(FixCommand != NULL);\r
+\r
+      StrnCpy(FixCommand, Command, StrLen(Command)-4);\r
+      Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
+      FreePool(FixCommand);\r
+      return Status;\r
+    } else {\r
+      return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    }\r
   }\r
 }\r
 \r
@@ -3331,7 +3348,6 @@ NotificationFunction(
   IN EFI_KEY_DATA *KeyData\r
   )\r
 {\r
-  EFI_INPUT_KEY Key;\r
   if ( ((KeyData->Key.UnicodeChar == L'c') &&\r
         (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) ||\r
       (KeyData->Key.UnicodeChar == 3)\r
@@ -3344,12 +3360,6 @@ NotificationFunction(
               (KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))\r
               ){ \r
     ShellInfoObject.HaltOutput = TRUE;\r
-\r
-    //\r
-    // Make sure that there are no pending keystrokes to pervent the pause.\r
-    //\r
-    gST->ConIn->Reset(gST->ConIn, FALSE);\r
-    while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key)==EFI_SUCCESS);\r
   }\r
   return (EFI_SUCCESS);\r
 }\r