]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg/ShellProtocol.c: Don't overwrite Status in InternalShellExecuteDevicePath
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index b67aefb71c95486ac7773e4ea04704056ef4c700..0d3839783eb31f94c198394d024997560c8bc7ee 100644 (file)
@@ -1358,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
@@ -1371,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
@@ -1445,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
@@ -1523,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
@@ -1550,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
@@ -1620,6 +1674,7 @@ EfiShellFreeFileList(
     InternalFreeShellFileInfoNode(ShellFileListItem);\r
   }\r
   InternalFreeShellFileInfoNode(*FileList);\r
+  *FileList = NULL;\r
   return(EFI_SUCCESS);\r
 }\r
 \r