summaryrefslogtreecommitdiff
path: root/ShellPkg
diff options
context:
space:
mode:
authorBrendan Jackman <Brendan.Jackman@arm.com>2014-01-24 22:27:11 +0000
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>2014-01-24 22:27:11 +0000
commit5223c1213506f3a8f3c120a6620258d2b071db84 (patch)
tree403527c9156dde4d1b420c0ff8f5ffee4ff4a1c8 /ShellPkg
parentfed3be946c8bff1372e106eec8cfd73524036ceb (diff)
downloadedk2-5223c1213506f3a8f3c120a6620258d2b071db84.zip
edk2-5223c1213506f3a8f3c120a6620258d2b071db84.tar.gz
edk2-5223c1213506f3a8f3c120a6620258d2b071db84.tar.bz2
ShellPkg/Shell: Fix reporting of exit status in ShellProtocol.Execute
When the exit status of the command run by the shell is other than SHELL_SUCCESS, the shell image will now exit with EFI_ABORTED, placing the commands exit status (which is a SHELL_STATUS) in ExitData. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Brendan Jackman <Brendan.Jackman@arm.com> Reviewed-by: Olivier Martin <olivier.martin@arm.com> Reviewed-by: Jaben Carsey <Jaben.carsey@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15180 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ShellPkg')
-rw-r--r--ShellPkg/Application/Shell/Shell.c202
-rw-r--r--ShellPkg/Application/Shell/Shell.h34
-rw-r--r--ShellPkg/Application/Shell/ShellProtocol.c58
-rw-r--r--ShellPkg/Application/Shell/ShellProtocol.h6
4 files changed, 236 insertions, 64 deletions
diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c
index 134ec58..e56b3f8 100644
--- a/ShellPkg/Application/Shell/Shell.c
+++ b/ShellPkg/Application/Shell/Shell.c
@@ -244,6 +244,9 @@ UefiMain (
UINTN Size;
EFI_HANDLE ConInHandle;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ SHELL_STATUS ExitStatus;
if (PcdGet8(PcdShellSupportLevel) > 3) {
return (EFI_UNSUPPORTED);
@@ -406,7 +409,7 @@ UefiMain (
// Display the mapping
//
if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {
- Status = RunCommand(L"map");
+ Status = RunCommand(L"map", NULL);
ASSERT_EFI_ERROR(Status);
}
@@ -472,7 +475,11 @@ UefiMain (
//
// process the startup script or launch the called app.
//
- Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);
+ Status = DoStartupScript(
+ ShellInfoObject.ImageDevPath,
+ ShellInfoObject.FileDevPath,
+ &ExitStatus
+ );
}
if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {
@@ -505,6 +512,7 @@ UefiMain (
//
Status = DoShellPrompt();
} while (!ShellCommandGetExit());
+ ExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();
}
if (OldConIn != NULL && ConInHandle != NULL) {
CloseSimpleTextInOnFile (gST->ConIn);
@@ -575,10 +583,29 @@ UefiMain (
DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);
}
- if (ShellCommandGetExit()) {
- return ((EFI_STATUS)ShellCommandGetExitCode());
+ // If the command exited with an error, we pass this error out in the ExitData
+ // so that it can be retrieved by the EfiShellExecute function (which may
+ // start the shell with gBS->StartImage)
+ if (ExitStatus != SHELL_SUCCESS) {
+ // Allocate a buffer for exit data to pass to gBS->Exit().
+ // This buffer will contain the empty string immediately followed by
+ // the shell's exit status. (The empty string is required by the UEFI spec)
+ ExitDataSize = (sizeof (CHAR16) + sizeof (SHELL_STATUS));
+ ExitData = AllocatePool (ExitDataSize);
+ if (ExitData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ExitData[0] = '\0';
+ // Use CopyMem to avoid alignment faults
+ CopyMem ((ExitData + 1), &ExitStatus, sizeof (ExitStatus));
+
+ gBS->Exit (ImageHandle, EFI_ABORTED, ExitDataSize, ExitData);
+ } else {
+ return EFI_SUCCESS;
}
- return (Status);
+
+ ASSERT (FALSE);
+ return EFI_SUCCESS;
}
/**
@@ -872,13 +899,16 @@ ProcessCommandLine(
@param ImagePath the path to the image for shell. first place to look for the startup script
@param FilePath the path to the file for shell. second place to look for the startup script.
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+
@retval EFI_SUCCESS the variable is initialized.
**/
EFI_STATUS
EFIAPI
DoStartupScript(
- EFI_DEVICE_PATH_PROTOCOL *ImagePath,
- EFI_DEVICE_PATH_PROTOCOL *FilePath
+ IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -913,7 +943,7 @@ DoStartupScript(
StrCat(FileStringPath, L" ");
StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);
}
- Status = RunCommand(FileStringPath);
+ Status = RunCommand(FileStringPath, ExitStatus);
FreePool(FileStringPath);
return (Status);
@@ -990,7 +1020,13 @@ DoStartupScript(
// If we got a file, run it
//
if (!EFI_ERROR(Status) && FileHandle != NULL) {
- Status = RunScriptFile (mStartupScript, FileHandle, L"", ShellInfoObject.NewShellParametersProtocol);
+ Status = RunScriptFile (
+ mStartupScript,
+ FileHandle,
+ L"",
+ ShellInfoObject.NewShellParametersProtocol,
+ ExitStatus
+ );
ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);
} else {
FileStringPath = ShellFindFilePath(mStartupScript);
@@ -1001,7 +1037,13 @@ DoStartupScript(
Status = EFI_SUCCESS;
ASSERT(FileHandle == NULL);
} else {
- Status = RunScriptFile(FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);
+ Status = RunScriptFile(
+ FileStringPath,
+ NULL,
+ L"",
+ ShellInfoObject.NewShellParametersProtocol,
+ ExitStatus
+ );
FreePool(FileStringPath);
}
}
@@ -1066,7 +1108,7 @@ DoShellPrompt (
//
if (!EFI_ERROR (Status)) {
CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;
- Status = RunCommand(CmdLine);
+ Status = RunCommand(CmdLine, NULL);
}
//
@@ -1326,6 +1368,9 @@ ShellConvertVariables (
@param[in] StdIn The pointer to the Standard input.
@param[in] StdOut The pointer to the Standard output.
+ @param[out] ExitStatus The exit code of the last command in the pipeline.
+ Ignored if NULL.
+
@retval EFI_SUCCESS The split command is executed successfully.
@retval other Some error occurs when executing the split command.
**/
@@ -1334,7 +1379,8 @@ EFIAPI
RunSplitCommand(
IN CONST CHAR16 *CmdLine,
IN SHELL_FILE_HANDLE *StdIn,
- IN SHELL_FILE_HANDLE *StdOut
+ IN SHELL_FILE_HANDLE *StdOut,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -1388,7 +1434,7 @@ RunSplitCommand(
ASSERT(Split->SplitStdOut != NULL);
InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);
- Status = RunCommand(OurCommandLine);
+ Status = RunCommand(OurCommandLine, NULL);
//
// move the output from the first to the in to the second.
@@ -1403,7 +1449,7 @@ RunSplitCommand(
ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);
if (!EFI_ERROR(Status)) {
- Status = RunCommand(NextCommandLine);
+ Status = RunCommand(NextCommandLine, ExitStatus);
}
//
@@ -1695,7 +1741,9 @@ VerifySplit(
/**
Process a split based operation.
- @param[in] CmdLine pointer to the command line to process
+ @param[in] CmdLine Pointer to the command line to process
+ @param[out] ExitStatus The exit status of the command. Ignored if NULL.
+ Invalid if this function returns an error.
@retval EFI_SUCCESS The operation was successful
@return an error occured.
@@ -1703,7 +1751,8 @@ VerifySplit(
EFI_STATUS
EFIAPI
ProcessNewSplitCommandLine(
- IN CONST CHAR16 *CmdLine
+ IN CONST CHAR16 *CmdLine,
+ OUT SHELL_STATUS *ExitStatus
)
{
SPLIT_LIST *Split;
@@ -1724,9 +1773,14 @@ ProcessNewSplitCommandLine(
}
if (Split == NULL) {
- Status = RunSplitCommand(CmdLine, NULL, NULL);
+ Status = RunSplitCommand(CmdLine, NULL, NULL, ExitStatus);
} else {
- Status = RunSplitCommand(CmdLine, Split->SplitStdIn, Split->SplitStdOut);
+ Status = RunSplitCommand(
+ CmdLine,
+ Split->SplitStdIn,
+ Split->SplitStdOut,
+ ExitStatus
+ );
}
if (EFI_ERROR(Status)) {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, CmdLine);
@@ -1901,6 +1955,8 @@ ProcessCommandLineToFinal(
@param[in] FirstParameter the first parameter on the command line
@param[in] ParamProtocol the shell parameters protocol pointer
+ @param[out] ExitStatus The exit code of the command. Ignored if NULL.
+
@retval EFI_SUCCESS The command was completed.
@retval EFI_ABORTED The command's operation was aborted.
**/
@@ -1909,7 +1965,8 @@ EFIAPI
RunInternalCommand(
IN CONST CHAR16 *CmdLine,
IN CHAR16 *FirstParameter,
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,
+ OUT SHELL_STATUS *ExitStatus OPTIONAL
)
{
EFI_STATUS Status;
@@ -1936,6 +1993,9 @@ RunInternalCommand(
if (LastError) {
SetLastError(CommandReturnedStatus);
}
+ if (ExitStatus != NULL) {
+ *ExitStatus = CommandReturnedStatus;
+ }
//
// Pass thru the exitcode from the app.
@@ -1990,6 +2050,9 @@ RunInternalCommand(
@param[in] FirstParameter the first parameter on the command line
@param[in] ParamProtocol the shell parameters protocol pointer
+ @param[out] ExitStatus The exit code of the command or file.
+ Ignored if NULL.
+
@retval EFI_SUCCESS The command was completed.
@retval EFI_ABORTED The command's operation was aborted.
**/
@@ -1999,13 +2062,14 @@ RunCommandOrFile(
IN SHELL_OPERATION_TYPES Type,
IN CONST CHAR16 *CmdLine,
IN CHAR16 *FirstParameter,
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
- EFI_STATUS StatusCode;
CHAR16 *CommandWithPath;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ SHELL_STATUS CalleeExitStatus;
Status = EFI_SUCCESS;
CommandWithPath = NULL;
@@ -2013,7 +2077,12 @@ RunCommandOrFile(
switch (Type) {
case Internal_Command:
- Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol);
+ Status = RunInternalCommand(
+ CmdLine,
+ FirstParameter,
+ ParamProtocol,
+ &CalleeExitStatus
+ );
break;
case Script_File_Name:
case Efi_Application:
@@ -2048,7 +2117,13 @@ RunCommandOrFile(
}
switch (Type) {
case Script_File_Name:
- Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);
+ Status = RunScriptFile (
+ CommandWithPath,
+ NULL,
+ CmdLine,
+ ParamProtocol,
+ &CalleeExitStatus
+ );
break;
case Efi_Application:
//
@@ -2068,7 +2143,8 @@ RunCommandOrFile(
DevPath,
CmdLine,
NULL,
- &StatusCode
+ NULL,
+ NULL
);
SHELL_FREE_NON_NULL(DevPath);
@@ -2076,7 +2152,8 @@ RunCommandOrFile(
//
// Update last error status.
//
- SetLastError((SHELL_STATUS) StatusCode);
+ // Status is an EFI_STATUS. Clear top bit to convert to SHELL_STATUS
+ SetLastError((SHELL_STATUS) (Status & (~MAX_BIT)));
break;
default:
//
@@ -2094,6 +2171,10 @@ RunCommandOrFile(
SHELL_FREE_NON_NULL(CommandWithPath);
+ if (ExitStatus != NULL) {
+ *ExitStatus = CalleeExitStatus;
+ }
+
return (Status);
}
@@ -2105,16 +2186,20 @@ RunCommandOrFile(
@param[in] FirstParameter the first parameter on the command line.
@param[in] ParamProtocol the shell parameters protocol pointer
+ @param[out] ExitStatus The exit code of the command or file.
+ Ignored if NULL.
+
@retval EFI_SUCCESS The command was completed.
@retval EFI_ABORTED The command's operation was aborted.
**/
EFI_STATUS
EFIAPI
SetupAndRunCommandOrFile(
- IN SHELL_OPERATION_TYPES Type,
- IN CHAR16 *CmdLine,
- IN CHAR16 *FirstParameter,
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
+ IN SHELL_OPERATION_TYPES Type,
+ IN CHAR16 *CmdLine,
+ IN CHAR16 *FirstParameter,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -2133,7 +2218,13 @@ SetupAndRunCommandOrFile(
// Now run the command, script, or application
//
if (!EFI_ERROR(Status)) {
- Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol);
+ Status = RunCommandOrFile(
+ Type,
+ CmdLine,
+ FirstParameter,
+ ParamProtocol,
+ ExitStatus
+ );
}
//
@@ -2158,6 +2249,7 @@ SetupAndRunCommandOrFile(
command or dispatch an external application.
@param[in] CmdLine The command line to parse.
+ @param[out] ExitStatus The exit code of the command. Ignored if NULL.
@retval EFI_SUCCESS The command was completed.
@retval EFI_ABORTED The command's operation was aborted.
@@ -2165,7 +2257,8 @@ SetupAndRunCommandOrFile(
EFI_STATUS
EFIAPI
RunCommand(
- IN CONST CHAR16 *CmdLine
+ IN CONST CHAR16 *CmdLine,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -2207,7 +2300,7 @@ RunCommand(
// We dont do normal processing with a split command line (output from one command input to another)
//
if (ContainsSplit(CleanOriginal)) {
- Status = ProcessNewSplitCommandLine(CleanOriginal);
+ Status = ProcessNewSplitCommandLine(CleanOriginal, ExitStatus);
SHELL_FREE_NON_NULL(CleanOriginal);
return (Status);
}
@@ -2233,7 +2326,13 @@ RunCommand(
case Internal_Command:
case Script_File_Name:
case Efi_Application:
- Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol);
+ Status = SetupAndRunCommandOrFile(
+ Type,
+ CleanOriginal,
+ FirstParameter,
+ ShellInfoObject.NewShellParametersProtocol,
+ ExitStatus
+ );
break;
default:
//
@@ -2288,13 +2387,16 @@ IsValidCommandName(
@param[in] Handle The handle to the already opened file.
@param[in] Name The name of the script file.
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+
@retval EFI_SUCCESS the script completed sucessfully
**/
EFI_STATUS
EFIAPI
RunScriptFileHandle (
- IN SHELL_FILE_HANDLE Handle,
- IN CONST CHAR16 *Name
+ IN SHELL_FILE_HANDLE Handle,
+ IN CONST CHAR16 *Name,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -2310,6 +2412,7 @@ RunScriptFileHandle (
CONST CHAR16 *CurDir;
UINTN LineCount;
CHAR16 LeString[50];
+ SHELL_STATUS CalleeExitStatus = SHELL_SUCCESS;
ASSERT(!ShellCommandGetScriptExit());
@@ -2495,7 +2598,7 @@ RunScriptFileHandle (
//
PreCommandEchoState = ShellCommandGetEchoState();
ShellCommandSetEchoState(FALSE);
- Status = RunCommand(CommandLine3+1);
+ Status = RunCommand(CommandLine3+1, NULL);
//
// If command was "@echo -off" or "@echo -on" then don't restore echo state
@@ -2517,7 +2620,7 @@ RunScriptFileHandle (
}
ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);
}
- Status = RunCommand(CommandLine3);
+ Status = RunCommand(CommandLine3, NULL);
}
}
@@ -2525,7 +2628,8 @@ RunScriptFileHandle (
//
// ShellCommandGetExitCode() always returns a UINT64
//
- UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode());
+ CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();
+ UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", CalleeExitStatus);
DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););
InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);
@@ -2537,9 +2641,11 @@ RunScriptFileHandle (
break;
}
if (EFI_ERROR(Status)) {
+ CalleeExitStatus = (SHELL_STATUS) Status;
break;
}
if (ShellCommandGetExit()) {
+ CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();
break;
}
}
@@ -2571,6 +2677,11 @@ RunScriptFileHandle (
if (ShellCommandGetCurrentScriptFile()==NULL) {
ShellCommandSetEchoState(PreScriptEchoState);
}
+
+ if (ExitStatus != NULL) {
+ *ExitStatus = CalleeExitStatus;
+ }
+
return (EFI_SUCCESS);
}
@@ -2582,15 +2693,18 @@ RunScriptFileHandle (
@param[in] CmdLine the command line to run.
@param[in] ParamProtocol the shell parameters protocol pointer
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+
@retval EFI_SUCCESS the script completed sucessfully
**/
EFI_STATUS
EFIAPI
RunScriptFile (
- IN CONST CHAR16 *ScriptPath,
- IN SHELL_FILE_HANDLE Handle OPTIONAL,
- IN CONST CHAR16 *CmdLine,
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
+ IN CONST CHAR16 *ScriptPath,
+ IN SHELL_FILE_HANDLE Handle OPTIONAL,
+ IN CONST CHAR16 *CmdLine,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,
+ OUT SHELL_STATUS *ExitStatus
)
{
EFI_STATUS Status;
@@ -2617,7 +2731,7 @@ RunScriptFile (
//
// run it
//
- Status = RunScriptFileHandle(FileHandle, ScriptPath);
+ Status = RunScriptFileHandle(FileHandle, ScriptPath, ExitStatus);
//
// now close the file
@@ -2625,7 +2739,7 @@ RunScriptFile (
ShellCloseFile(&FileHandle);
}
} else {
- Status = RunScriptFileHandle(Handle, ScriptPath);
+ Status = RunScriptFileHandle(Handle, ScriptPath, ExitStatus);
}
}
diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h
index 1962dd6..72dde69 100644
--- a/ShellPkg/Application/Shell/Shell.h
+++ b/ShellPkg/Application/Shell/Shell.h
@@ -230,14 +230,17 @@ ProcessCommandLine(
@param[in] ImagePath The path to the image for shell. The first place to look for the startup script.
@param[in] FilePath The path to the file for shell. The second place to look for the startup script.
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+ Invalid when this function returns an error.
@retval EFI_SUCCESS The variable is initialized.
**/
EFI_STATUS
EFIAPI
DoStartupScript(
- IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT SHELL_STATUS *ExitStatus
);
/**
@@ -282,7 +285,8 @@ AddLineToCommandHistory(
This will determine if the command line represents an internal shell command or dispatch an external application.
- @param[in] CmdLine the command line to parse
+ @param[in] CmdLine the command line to parse
+ @param[out] ExitStatus The exit status of the command. Ignored if NULL.
@retval EFI_SUCCESS the command was completed
@retval EFI_ABORTED the command's operation was aborted
@@ -290,7 +294,8 @@ AddLineToCommandHistory(
EFI_STATUS
EFIAPI
RunCommand(
- IN CONST CHAR16 *CmdLine
+ IN CONST CHAR16 *CmdLine,
+ OUT SHELL_STATUS *ExitStatus
);
/**
@@ -314,13 +319,17 @@ IsValidCommandName(
@param[in] Handle The handle to the already opened file.
@param[in] Name The name of the script file.
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+ Invalid when this function returns an error.
+
@retval EFI_SUCCESS the script completed sucessfully
**/
EFI_STATUS
EFIAPI
RunScriptFileHandle (
- IN SHELL_FILE_HANDLE Handle,
- IN CONST CHAR16 *Name
+ IN SHELL_FILE_HANDLE Handle,
+ IN CONST CHAR16 *Name,
+ OUT SHELL_STATUS *ExitStatus
);
/**
@@ -331,17 +340,20 @@ RunScriptFileHandle (
@param[in] CmdLine the command line to run.
@param[in] ParamProtocol the shell parameters protocol pointer
+ @param[out] ExitStatus The exit code of the script. Ignored if NULL.
+ Invalid when this function returns an error.
+
@retval EFI_SUCCESS the script completed sucessfully
**/
EFI_STATUS
EFIAPI
RunScriptFile (
- IN CONST CHAR16 *ScriptPath,
- IN SHELL_FILE_HANDLE Handle OPTIONAL,
- IN CONST CHAR16 *CmdLine,
- IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
+ IN CONST CHAR16 *ScriptPath,
+ IN SHELL_FILE_HANDLE Handle OPTIONAL,
+ IN CONST CHAR16 *CmdLine,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,
+ OUT SHELL_STATUS *ExitStatus
);
-
#endif //_SHELL_INTERNAL_HEADER_
diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c
index c619ba1..7f5884f 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.c
+++ b/ShellPkg/Application/Shell/ShellProtocol.c
@@ -1358,6 +1358,9 @@ EfiShellEnablePageBreak (
is NULL, then the current shell environment is used.
@param StatusCode Points to the status code returned by the command.
+ @param[out] ExitDataSize ExitDataSize as returned from gBS->StartImage
+ @param[out] ExitData ExitData as returned from gBS->StartImage
+
@retval EFI_SUCCESS The command executed successfully. The status code
returned by the command is pointed to by StatusCode.
@retval EFI_INVALID_PARAMETER The parameters are invalid.
@@ -1371,7 +1374,8 @@ InternalShellExecuteDevicePath(
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN CONST CHAR16 *CommandLine OPTIONAL,
IN CONST CHAR16 **Environment OPTIONAL,
- OUT EFI_STATUS *StatusCode OPTIONAL
+ OUT UINTN *ExitDataSize OPTIONAL,
+ OUT CHAR16 **ExitData OPTIONAL
)
{
EFI_STATUS Status;
@@ -1379,6 +1383,16 @@ InternalShellExecuteDevicePath(
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
LIST_ENTRY OrigEnvs;
EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;
+ UINTN InternalExitDataSize;
+ UINTN *ExitDataSizePtr;
+
+ // ExitDataSize is not OPTIONAL for gBS->BootServices, provide somewhere for
+ // it to be dumped if the caller doesn't want it.
+ if (ExitData == NULL) {
+ ExitDataSizePtr = &InternalExitDataSize;
+ } else {
+ ExitDataSizePtr = ExitDataSize;
+ }
if (ParentImageHandle == NULL) {
return (EFI_INVALID_PARAMETER);
@@ -1445,14 +1459,14 @@ InternalShellExecuteDevicePath(
///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)
//
- // now start the image and if the caller wanted the return code pass it to them...
+ // now start the image, passing up exit data if the caller requested it
//
if (!EFI_ERROR(Status)) {
- if (StatusCode != NULL) {
- *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);
- } else {
- Status = gBS->StartImage(NewHandle, NULL, NULL);
- }
+ Status = gBS->StartImage(
+ NewHandle,
+ ExitDataSizePtr,
+ ExitData
+ );
}
//
@@ -1523,6 +1537,8 @@ EfiShellExecute(
CHAR16 *Temp;
EFI_DEVICE_PATH_PROTOCOL *DevPath;
UINTN Size;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
if ((PcdGet8(PcdShellSupportLevel) < 1)) {
return (EFI_UNSUPPORTED);
@@ -1550,7 +1566,33 @@ EfiShellExecute(
DevPath,
Temp,
(CONST CHAR16**)Environment,
- StatusCode);
+ &ExitDataSize,
+ &ExitData);
+
+ if (Status == EFI_ABORTED) {
+ // If the command exited with an error, the shell should put the exit
+ // status in ExitData, preceded by a null-terminated string.
+ ASSERT (ExitDataSize == StrSize (ExitData) + sizeof (SHELL_STATUS));
+
+ if (StatusCode != NULL) {
+ // Skip the null-terminated string
+ ExitData += StrLen (ExitData) + 1;
+
+ // Use CopyMem to avoid alignment faults
+ CopyMem (StatusCode, ExitData, sizeof (SHELL_STATUS));
+
+ // Convert from SHELL_STATUS to EFI_STATUS
+ // EFI_STATUSes have top bit set when they are errors.
+ // (See UEFI Spec Appendix D)
+ if (*StatusCode != SHELL_SUCCESS) {
+ *StatusCode = (EFI_STATUS) *StatusCode | MAX_BIT;
+ }
+ }
+ FreePool (ExitData);
+ Status = EFI_SUCCESS;
+ } else if ((StatusCode != NULL) && !EFI_ERROR(Status)) {
+ *StatusCode = EFI_SUCCESS;
+ }
//
// de-allocate and return
diff --git a/ShellPkg/Application/Shell/ShellProtocol.h b/ShellPkg/Application/Shell/ShellProtocol.h
index 7493c9f..4920d82 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.h
+++ b/ShellPkg/Application/Shell/ShellProtocol.h
@@ -443,6 +443,9 @@ EfiShellEnablePageBreak (
variables with the format 'x=y', where x is the
environment variable name and y is the value. If this
is NULL, then the current shell environment is used.
+ @param[out] ExitDataSize ExitDataSize as returned from gBS->StartImage
+ @param[out] ExitData ExitData as returned from gBS->StartImage
+
@param StatusCode Points to the status code returned by the command.
@retval EFI_SUCCESS The command executed successfully. The status code
@@ -458,7 +461,8 @@ InternalShellExecuteDevicePath(
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
IN CONST CHAR16 *CommandLine OPTIONAL,
IN CONST CHAR16 **Environment OPTIONAL,
- OUT EFI_STATUS *StatusCode OPTIONAL
+ OUT UINTN *ExitDataSize OPTIONAL,
+ OUT CHAR16 **ExitData OPTIONAL
);
/**