From 8be0ba36fc347bac7199e7dbb8d373ea5e4bf0af Mon Sep 17 00:00:00 2001 From: jcarsey Date: Tue, 16 Nov 2010 22:31:47 +0000 Subject: [PATCH] fixes for IPF, CTRL-C support, and file redirection. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11066 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ConsoleLogger.c | 9 + ShellPkg/Application/Shell/ConsoleWrappers.c | 477 ++++++++++++++++++ ShellPkg/Application/Shell/ConsoleWrappers.h | 81 +++ ShellPkg/Application/Shell/Shell.c | 26 +- ShellPkg/Application/Shell/Shell.h | 4 + ShellPkg/Application/Shell/Shell.inf | 10 +- ShellPkg/Application/Shell/Shell.uni | Bin 3868 -> 4142 bytes ShellPkg/Application/Shell/ShellEnvVar.c | 37 +- .../Shell/ShellParametersProtocol.c | 91 +++- .../Shell/ShellParametersProtocol.h | 35 +- ShellPkg/Application/Shell/ShellProtocol.c | 224 ++++++-- ShellPkg/Application/Shell/ShellProtocol.h | 13 + 12 files changed, 911 insertions(+), 96 deletions(-) create mode 100644 ShellPkg/Application/Shell/ConsoleWrappers.c create mode 100644 ShellPkg/Application/Shell/ConsoleWrappers.h diff --git a/ShellPkg/Application/Shell/ConsoleLogger.c b/ShellPkg/Application/Shell/ConsoleLogger.c index 2b84d87adb..4b237bf6e9 100644 --- a/ShellPkg/Application/Shell/ConsoleLogger.c +++ b/ShellPkg/Application/Shell/ConsoleLogger.c @@ -76,10 +76,19 @@ ConsoleLoggerInstall( Status = ConsoleLoggerResetBuffers(*ConsoleInfo); if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL((*ConsoleInfo)); + *ConsoleInfo = NULL; return (Status); } Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut)); + if (EFI_ERROR(Status)) { + SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer); + SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes); + SHELL_FREE_NON_NULL((*ConsoleInfo)); + *ConsoleInfo = NULL; + return (Status); + } (*ConsoleInfo)->OldConOut = gST->ConOut; (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle; diff --git a/ShellPkg/Application/Shell/ConsoleWrappers.c b/ShellPkg/Application/Shell/ConsoleWrappers.c new file mode 100644 index 0000000000..61b6a5ee52 --- /dev/null +++ b/ShellPkg/Application/Shell/ConsoleWrappers.c @@ -0,0 +1,477 @@ +/** @file + Function definitions for shell simple text in and out on top of file handles. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +#include "ConsoleWrappers.h" +#include "Shell.h" + +typedef struct { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn; + SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE TheHandle; +} SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +typedef struct { + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOut; + SHELL_FILE_HANDLE FileHandle; + EFI_HANDLE TheHandle; +} SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +/** + Event notification function for EFI_SIMPLE_TEXT_INPUT_PROTOCOL.WaitForKey event + Signal the event if there is key available + + @param Event Indicates the event that invoke this function. + @param Context Indicates the calling context. + +**/ +VOID +EFIAPI +ConInWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT64 Position; + UINT64 Size; + // + // Someone is waiting on the keystroke event, if there's + // a key pending, signal the event + // + // Context is the pointer to EFI_SIMPLE_TEXT_INPUT_PROTOCOL + // + ShellInfoObject.NewEfiShellProtocol->GetFilePosition(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Context)->FileHandle, &Position); + ShellInfoObject.NewEfiShellProtocol->GetFileSize (((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Context)->FileHandle, &Size ); + if (Position < Size) { + gBS->SignalEvent (Event); + } +} + +/** + Reset function for the fake simple text input. + + @param[in] This A pointer to the SimpleTextIn structure. + @param[in] ExtendedVerification TRUE for extra validation, FALSE otherwise. + + @retval EFI_SUCCESS The reset was successful. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextInReset( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return (EFI_SUCCESS); +} + +/** + ReadKeyStroke function for the fake simple text input. + + @param[in] This A pointer to the SimpleTextIn structure. + @param[out] Key A pointer to the Key structure to fill. + + @retval EFI_SUCCESS The read was successful. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextInReadKeyStroke( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + IN EFI_INPUT_KEY *Key + ) +{ + UINTN Size; + Size = sizeof(CHAR16); + if (Key == NULL || This == NULL) { + return (EFI_INVALID_PARAMETER); + } + Key->ScanCode = 0; + return (ShellInfoObject.NewEfiShellProtocol->ReadFile( + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)This)->FileHandle, + &Size, + &Key->UnicodeChar)); +} + +/** + Function to create a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_INPUT_PROTOCOL* +EFIAPI +CreateSimpleTextInOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ) +{ + SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ProtocolToReturn; + EFI_STATUS Status; + + if (HandleLocation == NULL || FileHandleToUse == NULL) { + return (NULL); + } + + ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL)); + if (ProtocolToReturn == NULL) { + return (NULL); + } + ProtocolToReturn->FileHandle = FileHandleToUse; + ProtocolToReturn->SimpleTextIn.Reset = FileBasedSimpleTextInReset; + ProtocolToReturn->SimpleTextIn.ReadKeyStroke = FileBasedSimpleTextInReadKeyStroke; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_WAIT, + TPL_NOTIFY, + ConInWaitForKey, + &ProtocolToReturn->SimpleTextIn, + &ProtocolToReturn->SimpleTextIn.WaitForKey + ); + + if (EFI_ERROR(Status)) { + FreePool(ProtocolToReturn); + return (NULL); + } + ///@todo possibly also install SimpleTextInputEx on the handle at this point. + Status = gBS->InstallProtocolInterface( + &(ProtocolToReturn->TheHandle), + &gEfiSimpleTextInProtocolGuid, + EFI_NATIVE_INTERFACE, + &(ProtocolToReturn->SimpleTextIn)); + if (!EFI_ERROR(Status)) { + *HandleLocation = ProtocolToReturn->TheHandle; + return ((EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)ProtocolToReturn); + } else { + FreePool(ProtocolToReturn); + return (NULL); + } +} + +/** + Function to close a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] SimpleTextIn The pointer to the SimpleTextIn to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +EFIAPI +CloseSimpleTextInOnFile( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn + ) +{ + EFI_STATUS Status; + EFI_STATUS Status1; + + if (SimpleTextIn == NULL) { + return (EFI_INVALID_PARAMETER); + } + + Status = gBS->CloseEvent(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)SimpleTextIn)->SimpleTextIn.WaitForKey); + + Status1 = gBS->UninstallProtocolInterface( + ((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->TheHandle, + &gEfiSimpleTextInProtocolGuid, + &(((SHELL_EFI_SIMPLE_TEXT_INPUT_PROTOCOL*)SimpleTextIn)->SimpleTextIn)); + + FreePool(SimpleTextIn); + if (!EFI_ERROR(Status)) { + return (Status1); + } else { + return (Status); + } +} + +/** + Reset the text output device hardware and optionaly run diagnostics. + + @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + @param ExtendedVerification Indicates that a more extensive test may be performed + + @retval EFI_SUCCESS The text output device was reset. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + return (EFI_SUCCESS); +} + +/** + Verifies that all characters in a Unicode string can be output to the + target device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be examined. + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + return (EFI_SUCCESS); +} + +/** + Returns information for an available text mode that the output device(s) + supports. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to return information on. + @param[out] Columns Upon return, the number of columns in the selected geometry + @param[out] Rows Upon return, the number of rows in the selected geometry + + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + Sets the output device(s) to a specified mode. + + @param[in] This Protocol instance pointer. + @param[in] ModeNumber The mode number to set. + + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + Sets the background and foreground colors for the OutputString () and + ClearScreen () functions. + + @param[in] This Protocol instance pointer. + @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and + bits 4..6 are the background color. All other bits are undefined + and must be zero. The valid Attributes are defined in this file. + + @retval EFI_SUCCESS The attribute was set. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + return (EFI_SUCCESS); +} + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + return (EFI_SUCCESS); +} + +/** + Sets the current coordinates of the cursor position + + @param[in] This Protocol instance pointer. + @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode + @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode + + @retval EFI_SUCCESS The operation completed successfully. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + return (EFI_SUCCESS); +} + +/** + Makes the cursor visible or invisible + + @param[in] This Protocol instance pointer. + @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is + set to be invisible. + + @retval EFI_SUCCESS The operation completed successfully. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +{ + return (EFI_SUCCESS); +} + +/** + Write a Unicode string to the output device. + + @param[in] This Protocol instance pointer. + @param[in] WString The NULL-terminated Unicode string to be displayed on the output + device(s). All output devices must also support the Unicode + drawing defined in this file. + @retval EFI_SUCCESS The string was output to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to output + the text. + @retval EFI_UNSUPPORTED The output device's mode is not currently in a + defined text mode. + @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the + characters in the Unicode string could not be + rendered and were skipped. +**/ +EFI_STATUS +EFIAPI +FileBasedSimpleTextOutOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + UINTN Size; + Size = StrLen(WString) * sizeof(CHAR16); + return (ShellInfoObject.NewEfiShellProtocol->WriteFile( + ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)This)->FileHandle, + &Size, + WString)); +} + +/** + Function to create a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* +EFIAPI +CreateSimpleTextOutOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ) +{ + SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ProtocolToReturn; + EFI_STATUS Status; + + if (HandleLocation == NULL || FileHandleToUse == NULL) { + return (NULL); + } + + ProtocolToReturn = AllocateZeroPool(sizeof(SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL)); + if (ProtocolToReturn == NULL) { + return (NULL); + } + ProtocolToReturn->FileHandle = FileHandleToUse; + ProtocolToReturn->SimpleTextOut.Reset = FileBasedSimpleTextOutReset; + ProtocolToReturn->SimpleTextOut.TestString = FileBasedSimpleTextOutTestString; + ProtocolToReturn->SimpleTextOut.QueryMode = FileBasedSimpleTextOutQueryMode; + ProtocolToReturn->SimpleTextOut.SetMode = FileBasedSimpleTextOutSetMode; + ProtocolToReturn->SimpleTextOut.SetAttribute = FileBasedSimpleTextOutSetAttribute; + ProtocolToReturn->SimpleTextOut.ClearScreen = FileBasedSimpleTextOutClearScreen; + ProtocolToReturn->SimpleTextOut.SetCursorPosition = FileBasedSimpleTextOutSetCursorPosition; + ProtocolToReturn->SimpleTextOut.EnableCursor = FileBasedSimpleTextOutEnableCursor; + ProtocolToReturn->SimpleTextOut.OutputString = FileBasedSimpleTextOutOutputString; + ProtocolToReturn->SimpleTextOut.Mode = AllocateZeroPool(sizeof(EFI_SIMPLE_TEXT_OUTPUT_MODE)); + if (ProtocolToReturn->SimpleTextOut.Mode == NULL) { + FreePool(ProtocolToReturn); + return (NULL); + } + ProtocolToReturn->SimpleTextOut.Mode->MaxMode = 0; + ProtocolToReturn->SimpleTextOut.Mode->Mode = 0; + ProtocolToReturn->SimpleTextOut.Mode->Attribute = 0; + ProtocolToReturn->SimpleTextOut.Mode->CursorColumn = 0; + ProtocolToReturn->SimpleTextOut.Mode->CursorRow = 0; + ProtocolToReturn->SimpleTextOut.Mode->CursorVisible = FALSE; + + Status = gBS->InstallProtocolInterface( + &(ProtocolToReturn->TheHandle), + &gEfiSimpleTextOutProtocolGuid, + EFI_NATIVE_INTERFACE, + &(ProtocolToReturn->SimpleTextOut)); + if (!EFI_ERROR(Status)) { + *HandleLocation = ProtocolToReturn->TheHandle; + return ((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)ProtocolToReturn); + } else { + FreePool(ProtocolToReturn); + return (NULL); + } +} + +/** + Function to close a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] SimpleTextOut The pointer to the SimpleTextOUT to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +EFIAPI +CloseSimpleTextOutOnFile( + OUT EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut + ) +{ + EFI_STATUS Status; + if (SimpleTextOut == NULL) { + return (EFI_INVALID_PARAMETER); + } + Status = gBS->UninstallProtocolInterface( + ((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->TheHandle, + &gEfiSimpleTextOutProtocolGuid, + &(((SHELL_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)SimpleTextOut)->SimpleTextOut)); + FreePool(SimpleTextOut); + return (Status); +} diff --git a/ShellPkg/Application/Shell/ConsoleWrappers.h b/ShellPkg/Application/Shell/ConsoleWrappers.h new file mode 100644 index 0000000000..966a9225fa --- /dev/null +++ b/ShellPkg/Application/Shell/ConsoleWrappers.h @@ -0,0 +1,81 @@ +/** @file + Function definitions for shell simple text in and out on top of file handles. + + Copyright (c) 2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SHELL_CONSOLE_WRAPPERS_HEADER_ +#define _SHELL_CONSOLE_WRAPPERS_HEADER_ + +/** + Function to create a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_INPUT_PROTOCOL* +EFIAPI +CreateSimpleTextInOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ); + +/** + Function to close a EFI_SIMPLE_TEXT_INPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting input from a file. + + @param[in] SimpleTextIn The pointer to the SimpleTextIn to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +EFIAPI +CloseSimpleTextInOnFile( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn + ); + +/** + Function to create a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] FileHandleToUse The pointer to the SHELL_FILE_HANDLE to use. + @param[in] HandleLocation The pointer of a location to copy handle with protocol to. + + @retval NULL There was insufficient memory available. + @return A pointer to the allocated protocol structure; +**/ +EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL* +EFIAPI +CreateSimpleTextOutOnFile( + IN SHELL_FILE_HANDLE FileHandleToUse, + IN EFI_HANDLE *HandleLocation + ); + +/** + Function to close a EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL on top of a + SHELL_FILE_HANDLE to support redirecting output from a file. + + @param[in] SimpleTextOut The pointer to the SimpleTextOUT to close. + + @retval EFI_SUCCESS The object was closed. +**/ +EFI_STATUS +EFIAPI +CloseSimpleTextOutOnFile( + OUT EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut + ); + +#endif //_SHELL_CONSOLE_WRAPPERS_HEADER_ + diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index ddd5d1712a..b626ec2ac1 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -52,6 +52,10 @@ SHELL_INFO ShellInfoObject = { NULL, {0,0,NULL,NULL}, {0,0}, + NULL, + NULL, + NULL, + NULL }; STATIC CONST CHAR16 mScriptExtension[] = L".NSH"; @@ -271,9 +275,7 @@ UefiMain ( // // Set up the event for CTRL-C monitoring... // - - ///@todo add support for using SimpleInputEx here - // if SimpleInputEx is not available display a warning. + Status = InernalEfiShellStartMonitor(); } if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) { @@ -303,6 +305,11 @@ UefiMain ( ShellInfoObject.ConsoleInfo->Enabled = TRUE; ShellInfoObject.ConsoleInfo->RowCounter = 0; + // + // Reset the CTRL-C event (yes we ignore the return values) + // + Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); + // // Display Prompt // @@ -319,11 +326,6 @@ UefiMain ( gBS->CloseEvent(ShellInfoObject.UserBreakTimer); DEBUG_CODE(ShellInfoObject.UserBreakTimer = NULL;); } - - if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){ - ShellInfoObject.NewEfiShellProtocol->SetEnv(L"cwd", L"", TRUE); - } - if (ShellInfoObject.ImageDevPath != NULL) { FreePool(ShellInfoObject.ImageDevPath); DEBUG_CODE(ShellInfoObject.ImageDevPath = NULL;); @@ -337,6 +339,9 @@ UefiMain ( DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;); } if (ShellInfoObject.NewEfiShellProtocol != NULL){ + if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){ + ShellInfoObject.NewEfiShellProtocol->SetEnv(L"cwd", L"", TRUE); + } CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol); DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;); } @@ -1186,6 +1191,7 @@ RunCommand( SHELL_FILE_HANDLE OriginalStdIn; SHELL_FILE_HANDLE OriginalStdOut; SHELL_FILE_HANDLE OriginalStdErr; + SYSTEM_TABLE_INFO OriginalSystemTableInfo; CHAR16 *TempLocation3; UINTN Count; UINTN Count2; @@ -1311,7 +1317,7 @@ RunCommand( - Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr); + Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo); if (EFI_ERROR(Status)) { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle); } else { @@ -1430,7 +1436,7 @@ RunCommand( RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc); - RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr); + RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo); } if (CommandName != NULL) { if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) { diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h index 6f165e5515..ec32355b6c 100644 --- a/ShellPkg/Application/Shell/Shell.h +++ b/ShellPkg/Application/Shell/Shell.h @@ -105,6 +105,10 @@ typedef struct { EFI_SHELL_PARAMETERS_PROTOCOL *OldShellParameters; ///< old shell parameters to reinstall upon exiting. SHELL_PROTOCOL_HANDLE_LIST OldShellList; ///< List of other instances to reinstall when closing. SPLIT_LIST SplitList; ///< List of Splits in FILO stack. + EFI_HANDLE CtrlCNotifyHandle1; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + EFI_HANDLE CtrlCNotifyHandle2; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + EFI_HANDLE CtrlCNotifyHandle3; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. + EFI_HANDLE CtrlCNotifyHandle4; ///< The NotifyHandle returned from SimpleTextInputEx.RegisterKeyNotify. } SHELL_INFO; extern SHELL_INFO ShellInfoObject; diff --git a/ShellPkg/Application/Shell/Shell.inf b/ShellPkg/Application/Shell/Shell.inf index e2649a7251..e690e2e7f3 100644 --- a/ShellPkg/Application/Shell/Shell.inf +++ b/ShellPkg/Application/Shell/Shell.inf @@ -44,6 +44,8 @@ Shell.uni ConsoleLogger.c ConsoleLogger.h + ConsoleWrappers.c + ConsoleWrappers.h [Packages] MdePkg/MdePkg.dec @@ -75,12 +77,16 @@ [Protocols] gEfiShellProtocolGuid # ALWAYS_PRODUCED + # SOMETIMES_CONSUMED gEfiShellParametersProtocolGuid # ALWAYS_PRODUCED - gEfiShellEnvironment2Guid # SOMETIMES_PRODUCED - gEfiShellInterfaceGuid # SOMETIMES_PRODUCED + # SOMETIMES_CONSUMED + +# gEfiShellEnvironment2Guid # SOMETIMES_PRODUCED +# gEfiShellInterfaceGuid # SOMETIMES_PRODUCED gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextInputExProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextInProtocolGuid # ALWAYS_CONSUMED gEfiSimpleTextOutProtocolGuid # ALWAYS_CONSUMED gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED diff --git a/ShellPkg/Application/Shell/Shell.uni b/ShellPkg/Application/Shell/Shell.uni index 82a87aeb3f6717f0273b5db63c1ae1d655db5492..e7327f3dbb5400649ca413f9fd26dc38bfe25928 100644 GIT binary patch delta 185 zcmbOuw@zV$4F6;+K848(xOw>f82lOH89W*MfTSx!#N>ypl9MNJsZ4&u%U7=e6e$A2 zd?40iPz9<{075??Ux6W*A(J7Op@1QWA(bHnh$|RMfTrXDMM{AzS0G=3p`0O+p%_S~ z0dIh=+VbBG#6oBS{)Z_uxlmO{cATN<231luWPKLG;5(5BQ Cq9eZm delta 7 OcmZ3dFh_2K3_k!1WCCOW diff --git a/ShellPkg/Application/Shell/ShellEnvVar.c b/ShellPkg/Application/Shell/ShellEnvVar.c index cd55fa907b..f22fb705dd 100644 --- a/ShellPkg/Application/Shell/ShellEnvVar.c +++ b/ShellPkg/Application/Shell/ShellEnvVar.c @@ -13,6 +13,7 @@ **/ #include +#include #include @@ -24,7 +25,6 @@ #include "ShellEnvVar.h" - /** Reports whether an environment variable is Volatile or Non-Volatile. @@ -169,18 +169,31 @@ GetEnvironmentVariableList( } if (!EFI_ERROR(Status) && CompareGuid(&Guid, &gShellVariableGuid)){ VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST)); - ValSize = 0; - Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); - if (Status == EFI_BUFFER_TOO_SMALL){ - VarList->Val = AllocatePool(ValSize); - ASSERT(VarList->Val != NULL); + if (VarList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + ValSize = 0; Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); - } - if (!EFI_ERROR(Status)) { - VarList->Key = AllocatePool(StrSize(VariableName)); - ASSERT(VarList->Key != NULL); - StrCpy(VarList->Key, VariableName); - InsertTailList(ListHead, &VarList->Link); + if (Status == EFI_BUFFER_TOO_SMALL){ + VarList->Val = AllocatePool(ValSize); + if (VarList->Val == NULL) { + SHELL_FREE_NON_NULL(VarList); + Status = EFI_OUT_OF_RESOURCES; + } else { + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); + } + } + if (!EFI_ERROR(Status)) { + VarList->Key = AllocatePool(StrSize(VariableName)); + if (VarList->Key == NULL) { + SHELL_FREE_NON_NULL(VarList->Val); + SHELL_FREE_NON_NULL(VarList); + Status = EFI_OUT_OF_RESOURCES; + } else { + StrCpy(VarList->Key, VariableName); + InsertTailList(ListHead, &VarList->Link); + } + } } } // compare guid } // while diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c index 5e3e48b414..b594d3434f 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -14,6 +14,7 @@ **/ #include "ShellParametersProtocol.h" +#include "ConsoleWrappers.h" /** return the next parameter from a command line string; @@ -423,13 +424,14 @@ CleanUpShellParametersProtocol ( structure by parsing NewCommandLine. The current values are returned to the user. - If OldStdIn or OldStdOut is NULL then that value is not returned. + This will also update the system table. @param[in,out] ShellParameters Pointer to parameter structure to modify. @param[in] NewCommandLine The new command line to parse and use. @param[out] OldStdIn Pointer to old StdIn. @param[out] OldStdOut Pointer to old StdOut. @param[out] OldStdErr Pointer to old StdErr. + @param[out] SystemTableInfo Pointer to old system table information. @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @@ -441,7 +443,8 @@ UpdateStdInStdOutStdErr( IN CONST CHAR16 *NewCommandLine, OUT SHELL_FILE_HANDLE *OldStdIn, OUT SHELL_FILE_HANDLE *OldStdOut, - OUT SHELL_FILE_HANDLE *OldStdErr + OUT SHELL_FILE_HANDLE *OldStdErr, + OUT SYSTEM_TABLE_INFO *SystemTableInfo ) { CHAR16 *CommandLineCopy; @@ -464,7 +467,6 @@ UpdateStdInStdOutStdErr( CHAR16 TagBuffer[2]; SPLIT_LIST *Split; - ASSERT(ShellParameters != NULL); OutUnicode = TRUE; InUnicode = TRUE; ErrUnicode = TRUE; @@ -478,16 +480,20 @@ UpdateStdInStdOutStdErr( OutAppend = FALSE; CommandLineCopy = NULL; - if (OldStdIn != NULL) { - *OldStdIn = ShellParameters->StdIn; - } - if (OldStdOut != NULL) { - *OldStdOut = ShellParameters->StdOut; - } - if (OldStdErr != NULL) { - *OldStdErr = ShellParameters->StdErr; + if (ShellParameters == NULL || SystemTableInfo == NULL || OldStdIn == NULL || OldStdOut == NULL || OldStdErr == NULL) { + return (EFI_INVALID_PARAMETER); } + SystemTableInfo->ConIn = gST->ConIn; + SystemTableInfo->ConInHandle = gST->ConsoleInHandle; + SystemTableInfo->ConOut = gST->ConOut; + SystemTableInfo->ConOutHandle = gST->ConsoleOutHandle; + SystemTableInfo->ConErr = gST->StdErr; + SystemTableInfo->ConErrHandle = gST->StandardErrorHandle; + *OldStdIn = ShellParameters->StdIn; + *OldStdOut = ShellParameters->StdOut; + *OldStdErr = ShellParameters->StdErr; + if (NewCommandLine == NULL) { return (EFI_SUCCESS); } @@ -726,6 +732,7 @@ UpdateStdInStdOutStdErr( } if (!EFI_ERROR(Status)) { ShellParameters->StdErr = TempHandle; + gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle); } } @@ -766,6 +773,7 @@ UpdateStdInStdOutStdErr( } if (!EFI_ERROR(Status)) { ShellParameters->StdOut = TempHandle; + gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle); } } } @@ -787,6 +795,7 @@ UpdateStdInStdOutStdErr( ASSERT(TempHandle != NULL); } ShellParameters->StdOut = TempHandle; + gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle); } // @@ -806,6 +815,7 @@ UpdateStdInStdOutStdErr( ASSERT(TempHandle != NULL); } ShellParameters->StdErr = TempHandle; + gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle); } // @@ -822,6 +832,7 @@ UpdateStdInStdOutStdErr( Status = EFI_INVALID_PARAMETER; } else { ShellParameters->StdIn = TempHandle; + gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle); } } @@ -839,11 +850,16 @@ UpdateStdInStdOutStdErr( } if (!EFI_ERROR(Status)) { ShellParameters->StdIn = TempHandle; + gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle); } } } } FreePool(CommandLineCopy); + + if (gST->ConIn == NULL ||gST->ConOut == NULL) { + return (EFI_OUT_OF_RESOURCES); + } return (Status); } @@ -851,38 +867,69 @@ UpdateStdInStdOutStdErr( Funcion will replace the current StdIn and StdOut in the ShellParameters protocol structure with StdIn and StdOut. The current values are de-allocated. - @param[in,out] ShellParameters pointer to parameter structure to modify - @param[out] OldStdIn Pointer to old StdIn. - @param[out] OldStdOut Pointer to old StdOut. - @param[out] OldStdErr Pointer to old StdErr. + @param[in,out] ShellParameters Pointer to parameter structure to modify. + @param[in] OldStdIn Pointer to old StdIn. + @param[in] OldStdOut Pointer to old StdOut. + @param[in] OldStdErr Pointer to old StdErr. + @param[in] SystemTableInfo Pointer to old system table information. **/ EFI_STATUS EFIAPI RestoreStdInStdOutStdErr ( IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, - OUT SHELL_FILE_HANDLE *OldStdIn OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdOut OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdErr OPTIONAL + IN SHELL_FILE_HANDLE *OldStdIn, + IN SHELL_FILE_HANDLE *OldStdOut, + IN SHELL_FILE_HANDLE *OldStdErr, + IN SYSTEM_TABLE_INFO *SystemTableInfo ) { SPLIT_LIST *Split; + + if (ShellParameters == NULL + ||OldStdIn == NULL + ||OldStdOut == NULL + ||OldStdErr == NULL + ||SystemTableInfo == NULL) { + return (EFI_INVALID_PARAMETER); + } if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); } else { Split = NULL; } - if (OldStdIn != NULL && ShellParameters->StdIn != *OldStdIn) { + if (ShellParameters->StdIn != *OldStdIn) { if ((Split != NULL && Split->SplitStdIn != ShellParameters->StdIn) || Split == NULL) { gEfiShellProtocol->CloseFile(ShellParameters->StdIn); } - ShellParameters->StdIn = OldStdIn==NULL?NULL:*OldStdIn; + ShellParameters->StdIn = *OldStdIn; } - if (OldStdOut != NULL && ShellParameters->StdOut != *OldStdOut) { + if (ShellParameters->StdOut != *OldStdOut) { if ((Split != NULL && Split->SplitStdOut != ShellParameters->StdOut) || Split == NULL) { gEfiShellProtocol->CloseFile(ShellParameters->StdOut); } - ShellParameters->StdOut = OldStdOut==NULL?NULL:*OldStdOut; + ShellParameters->StdOut = *OldStdOut; + } + if (ShellParameters->StdErr != *OldStdErr) { + gEfiShellProtocol->CloseFile(ShellParameters->StdErr); + ShellParameters->StdErr = *OldStdErr; + } + + if (gST->ConIn != SystemTableInfo->ConIn) { + CloseSimpleTextInOnFile(gST->ConIn); + gST->ConIn = SystemTableInfo->ConIn; + gST->ConsoleInHandle = SystemTableInfo->ConInHandle; + } + if (gST->ConOut != SystemTableInfo->ConOut) { + CloseSimpleTextOutOnFile(gST->ConOut); + gST->ConOut = SystemTableInfo->ConOut; + gST->ConsoleOutHandle = SystemTableInfo->ConOutHandle; } + if (gST->StdErr != SystemTableInfo->ConErr) { + CloseSimpleTextOutOnFile(gST->StdErr); + gST->StdErr = SystemTableInfo->ConErr; + gST->StandardErrorHandle = SystemTableInfo->ConErrHandle; + } + return (EFI_SUCCESS); } /** diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.h b/ShellPkg/Application/Shell/ShellParametersProtocol.h index 3a5fc30bcb..2d19587610 100644 --- a/ShellPkg/Application/Shell/ShellParametersProtocol.h +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -116,6 +118,15 @@ RestoreArgcArgv( IN UINTN *OldArgc ); +typedef struct { + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; + EFI_HANDLE ConInHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + EFI_HANDLE ConOutHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConErr; + EFI_HANDLE ConErrHandle; +} SYSTEM_TABLE_INFO; + /** Funcion will replace the current StdIn and StdOut in the ShellParameters protocol structure by parsing NewCommandLine. The current values are returned to the @@ -128,6 +139,7 @@ RestoreArgcArgv( @param[out] OldStdIn Pointer to old StdIn. @param[out] OldStdOut Pointer to old StdOut. @param[out] OldStdErr Pointer to old StdErr. + @param[out] SystemTableInfo Pointer to old system table information. @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @@ -137,27 +149,30 @@ EFIAPI UpdateStdInStdOutStdErr( IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, IN CONST CHAR16 *NewCommandLine, - OUT SHELL_FILE_HANDLE *OldStdIn OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdOut OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdErr OPTIONAL + OUT SHELL_FILE_HANDLE *OldStdIn, + OUT SHELL_FILE_HANDLE *OldStdOut, + OUT SHELL_FILE_HANDLE *OldStdErr, + OUT SYSTEM_TABLE_INFO *SystemTableInfo ); /** Funcion will replace the current StdIn and StdOut in the ShellParameters protocol structure with StdIn and StdOut. The current values are de-allocated. - @param[in,out] ShellParameters pointer to parameter structure to modify - @param[out] OldStdIn Pointer to old StdIn. - @param[out] OldStdOut Pointer to old StdOut. - @param[out] OldStdErr Pointer to old StdErr. + @param[in,out] ShellParameters Pointer to parameter structure to modify. + @param[in] OldStdIn Pointer to old StdIn. + @param[in] OldStdOut Pointer to old StdOut. + @param[in] OldStdErr Pointer to old StdErr. + @param[in] SystemTableInfo Pointer to old system table information. **/ EFI_STATUS EFIAPI RestoreStdInStdOutStdErr ( IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, - OUT SHELL_FILE_HANDLE *OldStdIn OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdOut OPTIONAL, - OUT SHELL_FILE_HANDLE *OldStdErr OPTIONAL + IN SHELL_FILE_HANDLE *OldStdIn, + IN SHELL_FILE_HANDLE *OldStdOut, + IN SHELL_FILE_HANDLE *OldStdErr, + IN SYSTEM_TABLE_INFO *SystemTableInfo ); /** diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c index eaec87971d..392298989e 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.c +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -34,7 +34,7 @@ EfiShellClose ( ) { ShellFileHandleRemove(FileHandle); - return (FileHandleClose(FileHandle)); + return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle))); } /** @@ -475,8 +475,12 @@ EfiShellGetDevicePathFromFilePath( EFI_HANDLE Handle; EFI_STATUS Status; + if (Path == NULL) { + return (NULL); + } + MapName = NULL; - ASSERT(Path != NULL); + NewPath = NULL; if (StrStr(Path, L":") == NULL) { Cwd = EfiShellGetCurDir(NULL); @@ -488,7 +492,7 @@ EfiShellGetDevicePathFromFilePath( NewPath = AllocateZeroPool(Size); ASSERT(NewPath != NULL); StrCpy(NewPath, Cwd); - if ((NewPath[0] == (CHAR16)L'\\') && + if ((Path[0] == (CHAR16)L'\\') && (NewPath[StrLen(NewPath)-1] == (CHAR16)L'\\') ) { ((CHAR16*)NewPath)[StrLen(NewPath)-1] = CHAR_NULL; @@ -803,6 +807,7 @@ EfiShellOpenRootByHandle( could not be opened. @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted. @retval EFI_DEVICE_ERROR The device had an error + @retval EFI_INVALID_PARAMETER FileHandle is NULL. **/ EFI_STATUS EFIAPI @@ -814,6 +819,10 @@ EfiShellOpenRoot( EFI_STATUS Status; EFI_HANDLE Handle; + if (FileHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + // // find the handle of the device with that device handle and the file system // @@ -876,11 +885,19 @@ InternalOpenFileDevicePath( EFI_FILE_PROTOCOL *Handle1; EFI_FILE_PROTOCOL *Handle2; EFI_DEVICE_PATH_PROTOCOL *DpCopy; + FILEPATH_DEVICE_PATH *AlignedNode; - ASSERT(FileHandle != NULL); - *FileHandle = NULL; - Handle1 = NULL; - DpCopy = DevicePath; + if (FileHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = NULL; + Handle1 = NULL; + Handle2 = NULL; + Handle = NULL; + DpCopy = DevicePath; + ShellHandle = NULL; + FilePathNode = NULL; + AlignedNode = NULL; Status = EfiShellOpenRoot(DevicePath, &ShellHandle); @@ -903,6 +920,8 @@ InternalOpenFileDevicePath( ; !IsDevicePathEnd (&FilePathNode->Header) ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header) ){ + SHELL_FREE_NON_NULL(AlignedNode); + AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode); // // For file system access each node should be a file path component // @@ -926,7 +945,7 @@ InternalOpenFileDevicePath( Status = Handle2->Open ( Handle2, &Handle1, - FilePathNode->PathName, + AlignedNode->PathName, OpenMode, Attributes ); @@ -944,7 +963,7 @@ InternalOpenFileDevicePath( Status = Handle2->Open ( Handle2, &Handle1, - FilePathNode->PathName, + AlignedNode->PathName, OpenMode &~EFI_FILE_MODE_CREATE, Attributes ); @@ -956,7 +975,7 @@ InternalOpenFileDevicePath( Status = Handle2->Open ( Handle2, &Handle1, - FilePathNode->PathName, + AlignedNode->PathName, OpenMode, Attributes ); @@ -965,7 +984,7 @@ InternalOpenFileDevicePath( // // Close the last node // - Handle2->Close (Handle2); + ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2); // // If there's been an error, stop @@ -976,9 +995,10 @@ InternalOpenFileDevicePath( } // for loop } } + SHELL_FREE_NON_NULL(AlignedNode); if (EFI_ERROR(Status)) { if (Handle1 != NULL) { - Handle1->Close(Handle1); + ShellInfoObject.NewEfiShellProtocol->CloseFile(Handle1); } } else { *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle)); @@ -1867,11 +1887,6 @@ UpdateFileName( If FileHandle is a file and matches all of the remaining Pattern (which would be on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList. - if FileList is NULL, then ASSERT - if FilePattern is NULL, then ASSERT - if UnicodeCollation is NULL, then ASSERT - if FileHandle is NULL, then ASSERT - Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call FreeFileList with FileList. @@ -1880,6 +1895,7 @@ UpdateFileName( @param[in] FileHandle The FileHandle to start with @param[in,out] FileList pointer to pointer to list of found files. @param[in] ParentNode The node for the parent. Same file as identified by HANDLE. + @param[in] MapName The file system name this file is on. @retval EFI_SUCCESS all files were found and the FileList contains a list. @retval EFI_NOT_FOUND no files were found @@ -1892,7 +1908,8 @@ ShellSearchHandle( IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation, IN SHELL_FILE_HANDLE FileHandle, IN OUT EFI_SHELL_FILE_INFO **FileList, - IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL + IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL, + IN CONST CHAR16 *MapName ) { EFI_STATUS Status; @@ -1902,6 +1919,8 @@ ShellSearchHandle( EFI_SHELL_FILE_INFO *ShellInfoNode; EFI_SHELL_FILE_INFO *NewShellNode; BOOLEAN Directory; + CHAR16 *NewFullName; + UINTN Size; if ( FilePattern == NULL || UnicodeCollation == NULL @@ -1965,7 +1984,20 @@ ShellSearchHandle( ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link) ){ if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){ - if (Directory){ + if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) { + Size = StrSize(ShellInfoNode->FullName); + Size += StrSize(MapName) + sizeof(CHAR16); + NewFullName = AllocateZeroPool(Size); + if (NewFullName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + StrCpy(NewFullName, MapName); + StrCat(NewFullName, ShellInfoNode->FullName+1); + FreePool((VOID*)ShellInfoNode->FullName); + ShellInfoNode->FullName = NewFullName; + } + } + if (Directory && !EFI_ERROR(Status)){ // // should be a directory // @@ -1991,9 +2023,9 @@ ShellSearchHandle( // // recurse with the next part of the pattern // - Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode); + Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName); } - } else { + } else if (!EFI_ERROR(Status)) { // // should be a file // @@ -2109,18 +2141,14 @@ EfiShellFindFiles( ; *PatternCurrentLocation != ':' ; PatternCurrentLocation++); PatternCurrentLocation++; - Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL); + Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName); } FreePool(RootDevicePath); } } - if (PatternCopy != NULL) { - FreePool(PatternCopy); - } - if (MapName != NULL) { - FreePool(MapName); - } + SHELL_FREE_NON_NULL(PatternCopy); + SHELL_FREE_NON_NULL(MapName); return(Status); } @@ -2996,23 +3024,26 @@ CreatePopulateInstallShellProtocol ( UINTN HandleCounter; SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode; + if (NewShell == NULL) { + return (EFI_INVALID_PARAMETER); + } + BufferSize = 0; Buffer = NULL; OldProtocolNode = NULL; InitializeListHead(&ShellInfoObject.OldShellList.Link); - ASSERT(NewShell != NULL); - // // Initialize EfiShellProtocol object... // - *NewShell = &mShellProtocol; Status = gBS->CreateEvent(0, 0, NULL, NULL, &mShellProtocol.ExecutionBreak); - ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return (Status); + } // // Get the size of the buffer we need. @@ -3027,13 +3058,18 @@ CreatePopulateInstallShellProtocol ( // Allocate and recall with buffer of correct size // Buffer = AllocateZeroPool(BufferSize); - ASSERT(Buffer != NULL); + if (Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } Status = gBS->LocateHandle(ByProtocol, &gEfiShellProtocolGuid, NULL, &BufferSize, Buffer); - ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + FreePool(Buffer); + return (Status); + } // // now overwrite each of them, but save the info to restore when we end. // @@ -3056,7 +3092,7 @@ CreatePopulateInstallShellProtocol ( OldProtocolNode->Handle, &gEfiShellProtocolGuid, OldProtocolNode->Interface, - (VOID*)(*NewShell)); + (VOID*)(&mShellProtocol)); if (!EFI_ERROR(Status)) { // // we reinstalled sucessfully. log this so we can reverse it later. @@ -3079,7 +3115,7 @@ CreatePopulateInstallShellProtocol ( &gImageHandle, &gEfiShellProtocolGuid, EFI_NATIVE_INTERFACE, - (VOID*)(*NewShell)); + (VOID*)(&mShellProtocol)); } if (PcdGetBool(PcdShellSupportOldProtocols)){ @@ -3087,6 +3123,9 @@ CreatePopulateInstallShellProtocol ( ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also? } + if (!EFI_ERROR(Status)) { + *NewShell = &mShellProtocol; + } return (Status); } @@ -3106,8 +3145,9 @@ CleanUpShellProtocol ( IN OUT EFI_SHELL_PROTOCOL *NewShell ) { - EFI_STATUS Status; - SHELL_PROTOCOL_HANDLE_LIST *Node2; + EFI_STATUS Status; + SHELL_PROTOCOL_HANDLE_LIST *Node2; + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; // // if we need to restore old protocols... @@ -3122,7 +3162,6 @@ CleanUpShellProtocol ( &gEfiShellProtocolGuid, NewShell, Node2->Interface); - ASSERT_EFI_ERROR(Status); FreePool(Node2); } } else { @@ -3132,11 +3171,116 @@ CleanUpShellProtocol ( Status = gBS->UninstallProtocolInterface(gImageHandle, &gEfiShellProtocolGuid, NewShell); - ASSERT_EFI_ERROR(Status); } Status = gBS->CloseEvent(NewShell->ExecutionBreak); + NewShell->ExecutionBreak = NULL; + + Status = gBS->OpenProtocol( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&SimpleEx, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1); + Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2); return (Status); } +/** + Notification function for keystrokes. + + @param[in] KeyData The key that was pressed. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +NotificationFunction( + IN EFI_KEY_DATA *KeyData + ) +{ + if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) { + return (EFI_UNSUPPORTED); + } + return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak)); +} + +/** + Function to start monitoring for CTRL-C using SimpleTextInputEx. This + feature's enabled state was not known when the shell initially launched. + + @retval EFI_SUCCESS The feature is enabled. + @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available. +**/ +EFI_STATUS +EFIAPI +InernalEfiShellStartMonitor( + VOID + ) +{ + EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx; + EFI_KEY_DATA KeyData; + EFI_STATUS Status; + + Status = gBS->OpenProtocol( + gST->ConsoleInHandle, + &gEfiSimpleTextInputExProtocolGuid, + (VOID**)&SimpleEx, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_SHELL_NO_IN_EX), + ShellInfoObject.HiiHandle); + return (EFI_SUCCESS); + } + if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) { + return (EFI_UNSUPPORTED); + } + + KeyData.KeyState.KeyToggleState = 0; + KeyData.Key.ScanCode = 0; + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = L'c'; + + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle1); + + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle2); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED; + KeyData.Key.UnicodeChar = 3; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle3); + } + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; + if (!EFI_ERROR(Status)) { + Status = SimpleEx->RegisterKeyNotify( + SimpleEx, + &KeyData, + NotificationFunction, + &ShellInfoObject.CtrlCNotifyHandle4); + } + return (Status); +} diff --git a/ShellPkg/Application/Shell/ShellProtocol.h b/ShellPkg/Application/Shell/ShellProtocol.h index d03a382f6d..38e71b40dc 100644 --- a/ShellPkg/Application/Shell/ShellProtocol.h +++ b/ShellPkg/Application/Shell/ShellProtocol.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -946,5 +947,17 @@ InternalEfiShellSetEnv( IN BOOLEAN Volatile ); +/** + Function to start monitoring for CTRL-C using SimpleTextInputEx. This + feature's enabled state was not known when the shell initially launched. + + @retval EFI_SUCCESS The feature is enabled. + @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available. +**/ +EFI_STATUS +EFIAPI +InernalEfiShellStartMonitor( + VOID + ); #endif //_SHELL_PROTOCOL_HEADER_ -- 2.39.2