diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index 03f5e4f05f..cb9d969441 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1053,6 +1053,7 @@ DoStartupScript( ) { EFI_STATUS Status; + EFI_STATUS CalleeStatus; UINTN Delay; EFI_INPUT_KEY Key; SHELL_FILE_HANDLE FileHandle; @@ -1084,7 +1085,10 @@ DoStartupScript( StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1); } - Status = RunCommand(FileStringPath); + Status = RunShellCommand(FileStringPath, &CalleeStatus); + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit == TRUE) { + ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (CONST UINT64)CalleeStatus); + } FreePool(FileStringPath); return (Status); @@ -2133,6 +2137,7 @@ ProcessCommandLineToFinal( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2142,7 +2147,8 @@ EFIAPI RunInternalCommand( IN CONST CHAR16 *CmdLine, IN CHAR16 *FirstParameter, - IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol + IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2175,6 +2181,14 @@ RunInternalCommand( Status = ShellCommandRunCommandHandler(FirstParameter, &CommandReturnedStatus, &LastError); if (!EFI_ERROR(Status)) { + if (CommandStatus != NULL) { + if (CommandReturnedStatus != SHELL_SUCCESS) { + *CommandStatus = (EFI_STATUS)(CommandReturnedStatus | MAX_BIT); + } else { + *CommandStatus = EFI_SUCCESS; + } + } + // // Update last error status. // some commands do not update last error. @@ -2236,6 +2250,7 @@ RunInternalCommand( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2246,7 +2261,8 @@ 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 EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2262,7 +2278,7 @@ RunCommandOrFile( switch (Type) { case Internal_Command: - Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol); + Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol, CommandStatus); break; case Script_File_Name: case Efi_Application: @@ -2328,6 +2344,10 @@ RunCommandOrFile( CalleeExitStatus = (SHELL_STATUS) StartStatus; } + if (CommandStatus != NULL) { + *CommandStatus = CalleeExitStatus; + } + // // Update last error status. // @@ -2360,6 +2380,7 @@ RunCommandOrFile( @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line. @param[in] ParamProtocol the shell parameters protocol pointer + @param[out] CommandStatus the status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. @@ -2367,10 +2388,11 @@ RunCommandOrFile( 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 EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2390,7 +2412,7 @@ SetupAndRunCommandOrFile( // if (!EFI_ERROR(Status)) { TrimSpaces(&CmdLine); - Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol); + Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol, CommandStatus); } // @@ -2415,14 +2437,16 @@ SetupAndRunCommandOrFile( command or dispatch an external application. @param[in] CmdLine The command line to parse. + @param[out] CommandStatus The status from the command line. @retval EFI_SUCCESS The command was completed. @retval EFI_ABORTED The command's operation was aborted. **/ EFI_STATUS EFIAPI -RunCommand( - IN CONST CHAR16 *CmdLine +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus ) { EFI_STATUS Status; @@ -2507,7 +2531,7 @@ 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, CommandStatus); break; default: // @@ -2528,6 +2552,27 @@ RunCommand( return (Status); } +/** + Function will process and run a command line. + + 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. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +EFIAPI +RunCommand( + IN CONST CHAR16 *CmdLine + ) +{ + return (RunShellCommand(CmdLine, NULL)); +} + + STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002}; /** Function determines if the CommandName COULD be a valid command. It does not determine whether diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index b6686256aa..7c876510dd 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -293,6 +293,25 @@ RunCommand( IN CONST CHAR16 *CmdLine ); +/** + Function will process and run a command line. + + 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[out] CommandStatus The status from the command line. + + @retval EFI_SUCCESS The command was completed. + @retval EFI_ABORTED The command's operation was aborted. +**/ +EFI_STATUS +EFIAPI +RunShellCommand( + IN CONST CHAR16 *CmdLine, + OUT EFI_STATUS *CommandStatus + ); + /** Function determines if the CommandName COULD be a valid command. It does not determine whether this is a valid command. It only checks for invalid characters. diff --git a/ShellPkg/Application/Shell/ShellEnvVar.c b/ShellPkg/Application/Shell/ShellEnvVar.c index 8ed14b34a2..a8f177e6ad 100644 --- a/ShellPkg/Application/Shell/ShellEnvVar.c +++ b/ShellPkg/Application/Shell/ShellEnvVar.c @@ -339,9 +339,10 @@ SetEnvironmentVariables( // // Copy the string into the Key, leaving the last character allocated as NULL to terminate // - StrCpyS( Node->Key, + StrnCpyS( Node->Key, StrStr(CurrentString, L"=") - CurrentString + 1, - CurrentString + CurrentString, + StrStr(CurrentString, L"=") - CurrentString ); // diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index 3a963849f2..af00fe401d 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -1631,40 +1631,60 @@ EfiShellExecute( CHAR16 *Temp; EFI_DEVICE_PATH_PROTOCOL *DevPath; UINTN Size; - + EFI_STATUS CalleeStatusCode; + if ((PcdGet8(PcdShellSupportLevel) < 1)) { return (EFI_UNSUPPORTED); } - DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + if (Environment != NULL) { + // If Environment isn't null, load a new image of the shell with its own + // environment + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + + DEBUG_CODE_BEGIN(); + Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); + FreePool(Temp); + DEBUG_CODE_END(); - DEBUG_CODE_BEGIN(); - Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); - FreePool(Temp); - Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); - FreePool(Temp); - Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE); - FreePool(Temp); - DEBUG_CODE_END(); + Temp = NULL; + Size = 0; + ASSERT((Temp == NULL && Size == 0) || (Temp != NULL)); + StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0); + StrnCatGrow(&Temp, &Size, CommandLine, 0); - Temp = NULL; - Size = 0; - ASSERT((Temp == NULL && Size == 0) || (Temp != NULL)); - StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0); - StrnCatGrow(&Temp, &Size, CommandLine, 0); + Status = InternalShellExecuteDevicePath( + ParentImageHandle, + DevPath, + Temp, + (CONST CHAR16**)Environment, + StatusCode); - Status = InternalShellExecuteDevicePath( - ParentImageHandle, - DevPath, - Temp, - (CONST CHAR16**)Environment, - StatusCode); + // + // de-allocate and return + // + FreePool(DevPath); + FreePool(Temp); + } else { + // If Environment is NULL, we are free to use and mutate the current shell + // environment. This is much faster as uses much less memory. + + if (CommandLine == NULL) { + CommandLine = L""; + } + + Status = RunShellCommand (CommandLine, &CalleeStatusCode); + + // Pass up the command's exit code if the caller wants it + if (StatusCode != NULL) { + *StatusCode = (EFI_STATUS) CalleeStatusCode; + } + } - // - // de-allocate and return - // - FreePool(DevPath); - FreePool(Temp); return(Status); }