From a405b86d274d32b92f69842bfb9a1ab143128f57 Mon Sep 17 00:00:00 2001 From: jcarsey Date: Tue, 14 Sep 2010 05:18:09 +0000 Subject: udk2010.up2.shell initial release. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10874 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Application/Shell/ConsoleLogger.c | 1151 ++++++++ ShellPkg/Application/Shell/ConsoleLogger.h | 341 +++ ShellPkg/Application/Shell/FileHandleInternal.h | 68 + ShellPkg/Application/Shell/FileHandleWrappers.c | 1563 ++++++++++ ShellPkg/Application/Shell/FileHandleWrappers.h | 95 + ShellPkg/Application/Shell/Shell.c | 1707 +++++++++++ ShellPkg/Application/Shell/Shell.h | 292 ++ ShellPkg/Application/Shell/Shell.inf | 105 + ShellPkg/Application/Shell/Shell.uni | Bin 0 -> 3868 bytes ShellPkg/Application/Shell/ShellEnvVar.c | 326 ++ ShellPkg/Application/Shell/ShellEnvVar.h | 210 ++ ShellPkg/Application/Shell/ShellManParser.c | 615 ++++ ShellPkg/Application/Shell/ShellManParser.h | 86 + .../Application/Shell/ShellParametersProtocol.c | 949 ++++++ .../Application/Shell/ShellParametersProtocol.h | 208 ++ ShellPkg/Application/Shell/ShellProtocol.c | 3122 ++++++++++++++++++++ ShellPkg/Application/Shell/ShellProtocol.h | 950 ++++++ ShellPkg/Application/ShellLibTestApp/sa3.c | 2 +- ShellPkg/Include/Guid/ShellAliasGuid.h | 25 + ShellPkg/Include/Guid/ShellEnvironment2Ext.h | 6 +- ShellPkg/Include/Guid/ShellMapGuid.h | 25 + ShellPkg/Include/Guid/ShellVariableGuid.h | 25 + ShellPkg/Include/Library/FileHandleLib.h | 226 +- ShellPkg/Include/Library/HandleParsingLib.h | 342 +++ ShellPkg/Include/Library/ShellCEntryLib.h | 6 +- ShellPkg/Include/Library/ShellCommandLib.h | 757 +++++ ShellPkg/Include/Library/ShellLib.h | 433 +-- ShellPkg/Include/Library/SortLib.h | 53 +- ShellPkg/Include/Protocol/EfiShell.h | 76 +- ShellPkg/Include/Protocol/EfiShellEnvironment2.h | 256 +- ShellPkg/Include/Protocol/EfiShellInterface.h | 32 +- ShellPkg/Include/Protocol/EfiShellParameters.h | 14 +- ShellPkg/Include/ShellBase.h | 17 +- .../Library/BaseFileHandleLib/BaseFileHandleLib.c | 318 +- .../BaseFileHandleLib/BaseFileHandleLib.inf | 8 +- ShellPkg/Library/BaseSortLib/BaseSortLib.c | 31 +- ShellPkg/Library/BaseSortLib/BaseSortLib.inf | 10 +- .../UefiHandleParsingLib/UefiHandleParsingLib.c | 1420 +++++++++ .../UefiHandleParsingLib/UefiHandleParsingLib.h | 142 + .../UefiHandleParsingLib/UefiHandleParsingLib.inf | 158 + .../UefiHandleParsingLib/UefiHandleParsingLib.uni | Bin 0 -> 17336 bytes .../UefiShellCEntryLib/UefiShellCEntryLib.c | 8 +- .../UefiShellCEntryLib/UefiShellCEntryLib.inf | 10 +- .../Library/UefiShellCommandLib/ConsistMapping.c | 1310 ++++++++ .../UefiShellCommandLib/UefiShellCommandLib.c | 1511 ++++++++++ .../UefiShellCommandLib/UefiShellCommandLib.h | 79 + .../UefiShellCommandLib/UefiShellCommandLib.inf | 61 + .../UefiShellCommandLib/UefiShellCommandLib.uni | Bin 0 -> 17400 bytes .../Library/UefiShellDriver1CommandsLib/Connect.c | 273 ++ .../Library/UefiShellDriver1CommandsLib/Devices.c | 164 + .../Library/UefiShellDriver1CommandsLib/OpenInfo.c | 243 ++ .../UefiShellDriver1CommandsLib.c | 137 + .../UefiShellDriver1CommandsLib.h | 71 + .../UefiShellDriver1CommandsLib.inf | 57 + .../UefiShellDriver1CommandsLib.uni | Bin 0 -> 3476 bytes ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c | 81 + ShellPkg/Library/UefiShellLevel1CommandsLib/For.c | 581 ++++ ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c | 92 + ShellPkg/Library/UefiShellLevel1CommandsLib/If.c | 962 ++++++ .../UefiShellLevel1CommandsLib/NoOpScriptCommand.c | 40 + .../Library/UefiShellLevel1CommandsLib/Shift.c | 63 + .../UefiShellLevel1CommandsLib.c | 251 ++ .../UefiShellLevel1CommandsLib.h | 182 ++ .../UefiShellLevel1CommandsLib.inf | 54 + .../UefiShellLevel1CommandsLib.uni | Bin 0 -> 36138 bytes .../Library/UefiShellLevel2CommandsLib/Attrib.c | 271 ++ ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c | 218 ++ ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c | 599 ++++ ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c | 282 ++ ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c | 564 ++++ ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c | 1116 +++++++ .../Library/UefiShellLevel2CommandsLib/MkDir.c | 128 + ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c | 478 +++ .../Library/UefiShellLevel2CommandsLib/Parse.c | 190 ++ .../Library/UefiShellLevel2CommandsLib/Reset.c | 131 + ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c | 296 ++ ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c | 169 ++ .../Library/UefiShellLevel2CommandsLib/TimeDate.c | 772 +++++ .../UefiShellLevel2CommandsLib.c | 329 +++ .../UefiShellLevel2CommandsLib.h | 297 ++ .../UefiShellLevel2CommandsLib.inf | 82 + .../UefiShellLevel2CommandsLib.uni | Bin 0 -> 105810 bytes .../Library/UefiShellLevel3CommandsLib/Alias.c | 162 + ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c | 135 + ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c | 116 + .../Library/UefiShellLevel3CommandsLib/GetMtc.c | 101 + ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c | 183 ++ .../Library/UefiShellLevel3CommandsLib/Pause.c | 106 + .../Library/UefiShellLevel3CommandsLib/Touch.c | 265 ++ ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c | 239 ++ .../UefiShellLevel3CommandsLib.c | 94 + .../UefiShellLevel3CommandsLib.h | 156 + .../UefiShellLevel3CommandsLib.inf | 68 + .../UefiShellLevel3CommandsLib.uni | Bin 0 -> 42206 bytes ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c | 145 + ShellPkg/Library/UefiShellLib/UefiShellLib.c | 1079 ++++--- ShellPkg/Library/UefiShellLib/UefiShellLib.inf | 8 +- ShellPkg/Library/UefiSortLib/UefiSortLib.c | 27 +- ShellPkg/Library/UefiSortLib/UefiSortLib.inf | 10 +- ShellPkg/ShellPkg.dec | 90 +- ShellPkg/ShellPkg.dsc | 62 +- ShellPkg/UDK2010.UP2.Shell.txt | 89 + 102 files changed, 30418 insertions(+), 1039 deletions(-) create mode 100644 ShellPkg/Application/Shell/ConsoleLogger.c create mode 100644 ShellPkg/Application/Shell/ConsoleLogger.h create mode 100644 ShellPkg/Application/Shell/FileHandleInternal.h create mode 100644 ShellPkg/Application/Shell/FileHandleWrappers.c create mode 100644 ShellPkg/Application/Shell/FileHandleWrappers.h create mode 100644 ShellPkg/Application/Shell/Shell.c create mode 100644 ShellPkg/Application/Shell/Shell.h create mode 100644 ShellPkg/Application/Shell/Shell.inf create mode 100644 ShellPkg/Application/Shell/Shell.uni create mode 100644 ShellPkg/Application/Shell/ShellEnvVar.c create mode 100644 ShellPkg/Application/Shell/ShellEnvVar.h create mode 100644 ShellPkg/Application/Shell/ShellManParser.c create mode 100644 ShellPkg/Application/Shell/ShellManParser.h create mode 100644 ShellPkg/Application/Shell/ShellParametersProtocol.c create mode 100644 ShellPkg/Application/Shell/ShellParametersProtocol.h create mode 100644 ShellPkg/Application/Shell/ShellProtocol.c create mode 100644 ShellPkg/Application/Shell/ShellProtocol.h create mode 100644 ShellPkg/Include/Guid/ShellAliasGuid.h create mode 100644 ShellPkg/Include/Guid/ShellMapGuid.h create mode 100644 ShellPkg/Include/Guid/ShellVariableGuid.h create mode 100644 ShellPkg/Include/Library/HandleParsingLib.h create mode 100644 ShellPkg/Include/Library/ShellCommandLib.h create mode 100644 ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c create mode 100644 ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h create mode 100644 ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf create mode 100644 ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni create mode 100644 ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c create mode 100644 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c create mode 100644 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h create mode 100644 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf create mode 100644 ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.uni create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/For.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/If.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/NoOpScriptCommand.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni create mode 100644 ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c create mode 100644 ShellPkg/UDK2010.UP2.Shell.txt (limited to 'ShellPkg') diff --git a/ShellPkg/Application/Shell/ConsoleLogger.c b/ShellPkg/Application/Shell/ConsoleLogger.c new file mode 100644 index 0000000000..4b0d94d245 --- /dev/null +++ b/ShellPkg/Application/Shell/ConsoleLogger.c @@ -0,0 +1,1151 @@ +/** @file + Provides interface to shell console logger. + + Copyright (c) 2009 - 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 "ConsoleLogger.h" +#include "Shell.h" + +STATIC CONST CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL }; + +/** + Install our intermediate ConOut into the system table to + keep a log of all the info that is displayed to the user. + + @param[in] ScreensToSave Sets how many screen-worths of data to save. + @param[out] ConsoleInfo The object to pass into later functions. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. + + @sa ConsoleLoggerResetBuffers + @sa InstallProtocolInterface +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerInstall( + IN CONST UINTN ScreensToSave, + OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo + ) +{ + EFI_STATUS Status; + ASSERT(ConsoleInfo != NULL); + + *ConsoleInfo = AllocatePool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA)); + ASSERT(ConsoleInfo != NULL); + + (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE; + (*ConsoleInfo)->OldConOut = NULL; + (*ConsoleInfo)->OldConHandle = NULL; + (*ConsoleInfo)->Buffer = NULL; + (*ConsoleInfo)->BufferSize = 0; + (*ConsoleInfo)->OriginalStartRow = 0; + (*ConsoleInfo)->CurrentStartRow = 0; + (*ConsoleInfo)->RowsPerScreen = 0; + (*ConsoleInfo)->ColsPerScreen = 0; + (*ConsoleInfo)->Attributes = NULL; + (*ConsoleInfo)->AttribSize = 0; + (*ConsoleInfo)->ScreenCount = ScreensToSave; + (*ConsoleInfo)->HistoryMode.MaxMode = 1; + (*ConsoleInfo)->HistoryMode.Mode = 0; + (*ConsoleInfo)->HistoryMode.Attribute = 0; + (*ConsoleInfo)->HistoryMode.CursorColumn = 0; + (*ConsoleInfo)->HistoryMode.CursorRow = 0; + (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE; + (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset; + (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString; + (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString; + (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode; + (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode; + (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute; + (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen; + (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition; + (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor; + (*ConsoleInfo)->OurConOut.Mode = NULL; + (*ConsoleInfo)->Enabled = TRUE; + + Status = ConsoleLoggerResetBuffers(*ConsoleInfo); + if (EFI_ERROR(Status)) { + return (Status); + } + + Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut)); + + (*ConsoleInfo)->OldConOut = gST->ConOut; + (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle; + + gST->ConsoleOutHandle = gImageHandle; + gST->ConOut = &(*ConsoleInfo)->OurConOut; + + return (Status); +} + +/** + Return the system to the state it was before InstallConsoleLogger + was installed. + + @param[in,out] ConsoleInfo The object from the install function. + + @retval EFI_SUCCESS The operation was successful + @return other The operation failed. This was from UninstallProtocolInterface. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerUninstall( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT(ConsoleInfo != NULL); + ASSERT(ConsoleInfo->OldConOut != NULL); + + if (ConsoleInfo->Buffer != NULL) { + FreePool(ConsoleInfo->Buffer); + DEBUG_CODE(ConsoleInfo->Buffer = NULL;); + DEBUG_CODE(ConsoleInfo->BufferSize = 0;); + } + if (ConsoleInfo->Attributes != NULL) { + FreePool(ConsoleInfo->Attributes); + DEBUG_CODE(ConsoleInfo->Attributes = NULL;); + DEBUG_CODE(ConsoleInfo->AttribSize = 0;); + } + + gST->ConsoleOutHandle = ConsoleInfo->OldConHandle; + gST->ConOut = ConsoleInfo->OldConOut; + + return (gBS->UninstallProtocolInterface(gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID*)&ConsoleInfo->OurConOut)); +} + +/** + Displays previously logged output back to the screen. + + This will scroll the screen forwards and backwards through the log of previous + output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows + is (UINTN)(-1) then the size of the screen will be scrolled. + + @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer). + If FALSE then the log will be displayed backwards (scroll to older). + @param[in] Rows Determines how many rows the log should scroll. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerDisplayHistory( + IN CONST BOOLEAN Forward, + IN CONST UINTN Rows, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + UINTN RowChange; + + ASSERT(ConsoleInfo != NULL); + + // + // Calculate the row number change + // + switch (Rows) { + case ((UINTN)(-1)): + RowChange = ConsoleInfo->RowsPerScreen; + break; + case (0): + RowChange = ConsoleInfo->RowsPerScreen / 2; + break; + default: + RowChange = Rows; + break; + } + + // + // Do the math for direction + // + if (Forward) { + if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) { + RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow; + } + } else { + if (ConsoleInfo->CurrentStartRow < RowChange) { + RowChange = ConsoleInfo->CurrentStartRow; + } + } + + // + // If we are already at one end or the other + // + if (RowChange == 0) { + return (EFI_SUCCESS); + } + + // + // Clear the screen + // + ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut); + + // + // Set the new start row + // + if (Forward) { + ConsoleInfo->CurrentStartRow += RowChange; + } else { + ConsoleInfo->CurrentStartRow -= RowChange; + } + + // + // Change the screen + // + return (UpdateDisplayFromHistory(ConsoleInfo)); +} + +/** + Function to return to normal output whent he scrolling is complete. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. See UpdateDisplayFromHistory. + + @sa UpdateDisplayFromHistory +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerStopHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + ASSERT(ConsoleInfo != NULL); + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + return (EFI_SUCCESS); + } + ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow; + return (UpdateDisplayFromHistory(ConsoleInfo)); +} + +/** + Updates the hidden ConOut to be displaying the correct stuff. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. +**/ +EFI_STATUS +EFIAPI +UpdateDisplayFromHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + EFI_STATUS RetVal; + CHAR16 *Screen; + INT32 *Attributes; + UINTN CurrentRow; + CHAR16 TempCharHolder; + UINTN Column; + INT32 CurrentAttrib; + UINTN CurrentColumn; + CHAR16 *StringSegment; + CHAR16 *StringSegmentEnd; + CHAR16 StringSegmentEndChar; + + ASSERT(ConsoleInfo != NULL); + TempCharHolder = CHAR_NULL; + RetVal = EFI_SUCCESS; + + // + // Disable cursor visibility and move it to the top left corner + // + ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE); + ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0); + + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( CurrentRow = 0 + ; CurrentRow < ConsoleInfo->RowsPerScreen + ; CurrentRow++ + , Screen += (ConsoleInfo->ColsPerScreen + 2) + , Attributes += ConsoleInfo->ColsPerScreen + ){ + // + // dont use the last char - prevents screen scroll + // + if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)){ + TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1]; + Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL; + } + + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++ + ){ + if (Screen[Column] != CHAR_NULL) { + CurrentAttrib = Attributes[Column]; + CurrentColumn = Column; + StringSegment = &Screen[Column]; + + // + // Find the first char with a different arrribute and make that temporarily NULL + // so we can do fewer printout statements. (later) restore that one and we will + // start at that collumn on the next loop. + // + StringSegmentEndChar = CHAR_NULL; + for ( StringSegmentEnd = StringSegment + ; StringSegmentEnd != CHAR_NULL + ; StringSegmentEnd++ + , Column++ + ){ + if (Attributes[Column] != CurrentAttrib) { + StringSegmentEndChar = *StringSegmentEnd; + *StringSegmentEnd = CHAR_NULL; + break; + } + } // StringSegmentEnd loop + + // + // Now write out as much as had the same Attributes + // + + ConsoleInfo->OldConOut->SetAttribute(ConsoleInfo->OldConOut, CurrentAttrib); + ConsoleInfo->OldConOut->SetCursorPosition(ConsoleInfo->OldConOut, CurrentColumn, CurrentRow); + Status = ConsoleInfo->OldConOut->OutputString(ConsoleInfo->OldConOut, StringSegment); + + if (EFI_ERROR(Status)) { + ASSERT(FALSE); + RetVal = Status; + } + + // + // If we found a change in attribute put the character back and decrement the column + // so when it increments it will point at that character and we will start printing + // a segment with that new attribute + // + if (StringSegmentEndChar != CHAR_NULL) { + *StringSegmentEnd = StringSegmentEndChar; + StringSegmentEndChar = CHAR_NULL; + Column--; + } + } + } // column for loop + + // + // If we removed the last char and this was the last row put it back + // + if (TempCharHolder != CHAR_NULL) { + Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder; + TempCharHolder = CHAR_NULL; + } + } // row for loop + + // + // If we are setting the screen back to original turn on the cursor and make it visible + // and set the attributes back to what they were + // + if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) { + ConsoleInfo->OldConOut->SetAttribute ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.Attribute + ); + ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorColumn, + ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow + ); + + Status = ConsoleInfo->OldConOut->EnableCursor ( + ConsoleInfo->OldConOut, + ConsoleInfo->HistoryMode.CursorVisible + ); + if (EFI_ERROR (Status)) { + RetVal = Status; + } + } + + return (RetVal); +} + +/** + 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. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + EFI_STATUS Status; + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleLoggerResetBuffers(ConsoleInfo); + } + + return Status; +} + +/** + Appends a string to the history buffer. If the buffer is full then the oldest + information in the buffer will be dropped. Information is added in a line by + line manner such that an empty line takes up just as much space as a full line. + + @param[in] String String pointer to add. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +EFIAPI +AppendStringToHistory( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + UINTN CopySize; + UINTN PrintIndex; + UINTN Index; + + ASSERT(ConsoleInfo != NULL); + + for ( Walker = String + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ){ + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->HistoryMode.CursorColumn > 0) { + ConsoleInfo->HistoryMode.CursorColumn--; + } + break; + case (CHAR_LINEFEED): + if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) { + // + // Should never be bigger + // + ASSERT(ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)); + + // + // scroll history attributes 'up' 1 row and set the last row to default attribute + // + CopySize = ConsoleInfo->ColsPerScreen + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof(ConsoleInfo->Attributes[0]); + ASSERT(CopySize < ConsoleInfo->AttribSize); + CopyMem( + ConsoleInfo->Attributes, + ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen, + CopySize + ); + + for ( Index = 0 + ; Index < ConsoleInfo->ColsPerScreen + ; Index++ + ){ + *(ConsoleInfo->Attributes + (CopySize/sizeof(ConsoleInfo->Attributes)) + Index) = ConsoleInfo->HistoryMode.Attribute; + } + + // + // scroll history buffer 'up' 1 row and set the last row to spaces (L' ') + // + CopySize = (ConsoleInfo->ColsPerScreen + 2) + * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1) + * sizeof(ConsoleInfo->Buffer[0]); + ASSERT(CopySize < ConsoleInfo->BufferSize); + CopyMem( + ConsoleInfo->Buffer, + ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2), + CopySize + ); + + // + // Set that last row of chars to spaces + // + SetMem16(((UINT8*)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof(CHAR16), L' '); + } else { + // + // we are not on the last row + // + + // + // We should not be scrolling history + // + ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow); + // + // are we at the end of a row? + // + if (ConsoleInfo->HistoryMode.CursorRow == (INT32) (ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) { + ConsoleInfo->OriginalStartRow++; + ConsoleInfo->CurrentStartRow++; + } + ConsoleInfo->HistoryMode.CursorRow++; + } + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->HistoryMode.CursorColumn = 0; + break; + default: + // + // Acrtually print characters into the history buffer + // + + PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn; + + for ( // no initializer needed + ; ConsoleInfo->HistoryMode.CursorColumn < (INT32) ConsoleInfo->ColsPerScreen + ; ConsoleInfo->HistoryMode.CursorColumn++ + , PrintIndex++ + , Walker++ + ){ + if (*Walker == CHAR_NULL + ||*Walker == CHAR_BACKSPACE + ||*Walker == CHAR_LINEFEED + ||*Walker == CHAR_CARRIAGE_RETURN + ){ + Walker--; + break; + } + // + // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row. + // + + ASSERT(PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize); + ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker; + ASSERT(PrintIndex < ConsoleInfo->AttribSize); + ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute; + } // for loop + + // + // Add the carriage return and line feed at the end of the lines + // + if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) { + AppendStringToHistory(L"\r\n", ConsoleInfo); + Walker--; + } + + break; + } // switch for character + } // for loop + + return (EFI_SUCCESS); +} + +/** + Worker function to handle printing the output to the screen + and the history buffer + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @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 +ConsoleLoggerOutputStringSplit( + IN CONST CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16*)String); + + if (EFI_ERROR(Status)) { + return (Status); + } + + return (AppendStringToHistory(String, ConsoleInfo)); +} + +/** + Function to handle page break mode. + + This function will prompt for continue or break. + + @retval EFI_SUCCESS Continue was choosen + @return other Break was choosen +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerDoPageBreak( + VOID + ) +{ + SHELL_PROMPT_RESPONSE *Resp; + EFI_STATUS Status; + + Resp = NULL; + ASSERT(ShellInfoObject.PageBreakEnabled); + ShellInfoObject.PageBreakEnabled = FALSE; + Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN(STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID**)&Resp); + ShellInfoObject.PageBreakEnabled = TRUE; + ASSERT(Resp != NULL); + if (Resp == NULL) { + return (EFI_NOT_FOUND); + } + if (EFI_ERROR(Status)) { + if (Resp != NULL) { + FreePool(Resp); + } + return (Status); + } + if (*Resp == ShellPromptResponseContinue) { + FreePool(Resp); + ShellInfoObject.ConsoleInfo->RowCounter = 0; + return (EFI_SUCCESS); + } else if (*Resp == ShellPromptResponseQuit) { + FreePool(Resp); + ShellInfoObject.ConsoleInfo->Enabled = FALSE; + return (EFI_DEVICE_ERROR); + } else { + ASSERT(FALSE); + } + return (EFI_SUCCESS); +} +/** + Worker function to handle printing the output with page breaks. + + @param[in] String The string to output + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The string was printed + @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 +ConsoleLoggerPrintWithPageBreak( + IN CHAR16 *String, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + CONST CHAR16 *Walker; + CONST CHAR16 *LineStart; + CHAR16 TempChar; + + for ( Walker = String + , LineStart = String + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ){ + switch (*Walker) { + case (CHAR_BACKSPACE): + if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) { + ConsoleInfo->OurConOut.Mode->CursorColumn--; + } + break; + case (CHAR_LINEFEED): + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16*)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to it's original character + // + *((CHAR16*)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker + 1; + + // + // increment row count + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + + break; + case (CHAR_CARRIAGE_RETURN): + // + // Move the cursor to the beginning of the current row. + // + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + break; + default: + // + // increment column count + // + ConsoleInfo->OurConOut.Mode->CursorColumn++; + // + // check if that is the last column + // + if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn - 1) { + // + // output a line similar to the linefeed character. + // + + // + // add a temp NULL terminator + // + TempChar = *(Walker + 1); + *((CHAR16*)(Walker+1)) = CHAR_NULL; + + // + // output the string + // + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + + // + // restore the temp NULL terminator to it's original character + // + *((CHAR16*)(Walker+1)) = TempChar; + + // + // Update LineStart Variable + // + LineStart = Walker; + + // + // increment row count and zero the column + // + ShellInfoObject.ConsoleInfo->RowCounter++; + ConsoleInfo->OurConOut.Mode->CursorRow++; + ConsoleInfo->OurConOut.Mode->CursorColumn = 0; + } // last column on line + break; + } // switch for character + + // + // check if that was the last printable row. If yes handle PageBreak mode + // + if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) { + if (EFI_ERROR(ConsoleLoggerDoPageBreak())) { + // + // We got an error which means 'break' and halt the printing + // + return (EFI_DEVICE_ERROR); + } + } + } // for loop + + if (LineStart != NULL && *LineStart != CHAR_NULL) { + ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo); + } + + 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 +ConsoleLoggerOutputString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + ASSERT(ShellInfoObject.ConsoleInfo == ConsoleInfo); + if (!ShellInfoObject.ConsoleInfo->Enabled) { + return (EFI_DEVICE_ERROR); + } else if (ShellInfoObject.PageBreakEnabled) { + return (ConsoleLoggerPrintWithPageBreak(WString, ConsoleInfo)); + } else { + return (ConsoleLoggerOutputStringSplit(WString, ConsoleInfo)); + } +} + +/** + 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 for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString)); +} + +/** + 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_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not + complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ) +{ + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + return (ConsoleInfo->OldConOut->QueryMode ( + ConsoleInfo->OldConOut, + ModeNumber, + Columns, + Rows + )); +} + +/** + 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_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber); + + // + // Check that the buffers are still correct for logging + // + if (!EFI_ERROR (Status)) { + ConsoleLoggerResetBuffers(ConsoleInfo); + } + + return Status; +} + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.Attribute = (INT32) Attribute; + } + + return Status; +} + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ) +{ + EFI_STATUS Status; + CHAR16 *Screen; + INT32 *Attributes; + UINTN Row; + UINTN Column; + + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 1) * ConsoleInfo->CurrentStartRow]; + Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow]; + for ( Row = ConsoleInfo->OriginalStartRow + ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) + ; Row++ + ){ + for ( Column = 0 + ; Column < ConsoleInfo->ColsPerScreen + ; Column++ + , Screen++ + , Attributes++ + ){ + *Screen = L' '; + *Attributes = ConsoleInfo->OldConOut->Mode->Attribute; + } + // + // Skip the NULL on each column end in text buffer only + // + Screen++; + } + ConsoleInfo->HistoryMode.CursorColumn = 0; + ConsoleInfo->HistoryMode.CursorRow = 0; + } + + return Status; +} + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->SetCursorPosition ( + ConsoleInfo->OldConOut, + Column, + Row + ); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column; + ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row); + } + + return Status; +} + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ) +{ + EFI_STATUS Status; + + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; + ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This); + // + // Forward the request to the original ConOut + // + Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible); + + // + // Record console output history + // + if (!EFI_ERROR (Status)) { + ConsoleInfo->HistoryMode.CursorVisible = Visible; + } + + return Status; +} + +/** + Function to update and verify that the current buffers are correct. + + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + This will be used when a mode has changed or a reset ocurred to verify all + history buffers. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerResetBuffers( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ) +{ + EFI_STATUS Status; + + if (ConsoleInfo->Buffer != NULL) { + FreePool(ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + ConsoleInfo->BufferSize = 0; + } + if (ConsoleInfo->Attributes != NULL) { + FreePool(ConsoleInfo->Attributes); + ConsoleInfo->Attributes = NULL; + ConsoleInfo->AttribSize = 0; + } + + Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen); + if (EFI_ERROR(Status)){ + return (Status); + } + + ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Buffer[0]); + ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Attributes[0]); + + ConsoleInfo->Buffer = (CHAR16*)AllocateZeroPool(ConsoleInfo->BufferSize); + + if (ConsoleInfo->Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + ConsoleInfo->Attributes = (INT32*)AllocateZeroPool(ConsoleInfo->AttribSize); + if (ConsoleInfo->Attributes == NULL) { + FreePool(ConsoleInfo->Buffer); + ConsoleInfo->Buffer = NULL; + return (EFI_OUT_OF_RESOURCES); + } + + ConsoleInfo->OurConOut.Mode = gST->ConOut->Mode; + ConsoleInfo->OldConOut = gST->ConOut; + CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE)); + + return (EFI_SUCCESS); +} diff --git a/ShellPkg/Application/Shell/ConsoleLogger.h b/ShellPkg/Application/Shell/ConsoleLogger.h new file mode 100644 index 0000000000..847c64c8ab --- /dev/null +++ b/ShellPkg/Application/Shell/ConsoleLogger.h @@ -0,0 +1,341 @@ +/** @file + Provides interface to shell console logger. + + Copyright (c) 2009 - 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 _CONSOLE_LOGGER_HEADER_ +#define _CONSOLE_LOGGER_HEADER_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('c', 'o', 'P', 'D') + +typedef struct _CONSOLE_LOGGER_PRIVATE_DATA{ + UINTN Signature; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL OurConOut; ///< the protocol we installed onto the system table + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *OldConOut; ///< old protocol to reinstall upon exiting + EFI_HANDLE OldConHandle; ///< old protocol handle + UINTN ScreenCount; ///< How many screens worth of data to save + CHAR16 *Buffer; ///< Buffer to save data + UINTN BufferSize; ///< size of buffer in bytes + + // start row is the top of the screen + UINTN OriginalStartRow; ///< What the originally visible start row was + UINTN CurrentStartRow; ///< what the currently visible start row is + + UINTN RowsPerScreen; ///< how many rows the screen can display + UINTN ColsPerScreen; ///< how many columns the screen can display + + INT32 *Attributes; ///< Buffer for Attribute to be saved for each character + UINTN AttribSize; ///< Size of Attributes in bytes + + EFI_SIMPLE_TEXT_OUTPUT_MODE HistoryMode; ///< mode of the history log + BOOLEAN Enabled; ///< Set to FALSE when a break is requested. + UINTN RowCounter; ///< Initial row of each print job. +} CONSOLE_LOGGER_PRIVATE_DATA; + +#define CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(a) CR (a, CONSOLE_LOGGER_PRIVATE_DATA, OurConOut, CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE) + +/** + Install our intermediate ConOut into the system table to + keep a log of all the info that is displayed to the user. + + @param[in] ScreensToSave Sets how many screen-worths of data to save. + @param[out] ConsoleInfo The object to pass into later functions. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. + + @sa ConsoleLoggerResetBuffers + @sa InstallProtocolInterface +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerInstall( + IN CONST UINTN ScreensToSave, + OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo + ); + +/** + Return the system to the state it was before InstallConsoleLogger + was installed. + + @param[in,out] ConsoleInfo The object from the install function. + + @retval EFI_SUCCESS The operation was successful + @return other The operation failed. This was from UninstallProtocolInterface. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerUninstall( + IN OUT CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Displays previously logged output back to the screen. + + This will scroll the screen forwards and backwards through the log of previous + output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows + is (UINTN)(-1) then the size of the screen will be scrolled. + + @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer). + If FALSE then the log will be displayed backwards (scroll to older). + @param[in] Rows Determines how many rows the log should scroll. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerDisplayHistory( + IN CONST BOOLEAN Forward, + IN CONST UINTN Rows, + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Function to return to normal output whent he scrolling is complete. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. See UpdateDisplayFromHistory. + + @sa UpdateDisplayFromHistory +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerStopHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + Updates the hidden ConOut to be displaying the correct stuff. + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + @retval EFI_SUCCESS The operation was successful. + @return other The operation failed. +**/ +EFI_STATUS +EFIAPI +UpdateDisplayFromHistory( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +/** + 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. + @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and + could not be reset. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerReset ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + 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 +ConsoleLoggerOutputString( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +/** + 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 for the output + device(s). + + @retval EFI_SUCCESS The device(s) are capable of rendering the output string. + @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be + rendered by one or more of the output devices mapped + by the EFI handle. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerTestString ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *WString + ); + +/** + 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_SUCCESS The requested mode information was returned. + @retval EFI_DEVICE_ERROR The device had an error and could not + complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerQueryMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber, + OUT UINTN *Columns, + OUT UINTN *Rows + ); + +/** + 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_SUCCESS The requested text mode was set. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The mode number was not valid. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetMode ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The attribute requested is not defined. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetAttribute ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Attribute + ); + +/** + Clears the output device(s) display to the currently selected background + color. + + @param[in] This Protocol instance pointer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerClearScreen ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and + could not complete the request. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the + cursor position is invalid for the current mode. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerSetCursorPosition ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN UINTN Column, + IN UINTN Row + ); + +/** + 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. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request, or the device does not support changing + the cursor mode. + @retval EFI_UNSUPPORTED The output device is not in a valid text mode. + +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerEnableCursor ( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN BOOLEAN Visible + ); + +/** + Function to update and verify that the current buffers are correct. + + @param[in] ConsoleInfo The pointer to the instance of the console logger information. + + This will be used when a mode has changed or a reset ocurred to verify all + history buffers. +**/ +EFI_STATUS +EFIAPI +ConsoleLoggerResetBuffers( + IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo + ); + +#endif //_CONSOLE_LOGGER_HEADER_ + diff --git a/ShellPkg/Application/Shell/FileHandleInternal.h b/ShellPkg/Application/Shell/FileHandleInternal.h new file mode 100644 index 0000000000..ec55a6e4eb --- /dev/null +++ b/ShellPkg/Application/Shell/FileHandleInternal.h @@ -0,0 +1,68 @@ +/** @file + internal worker functions for FileHandleWrappers to use + + Copyright (c) 2009 - 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 _FILE_HANDLE_INTERNAL_HEADER_ +#define _FILE_HANDLE_INTERNAL_HEADER_ + +/** + Move the cursor position one character backward. + + @param[in] LineLength Length of a line. Get it by calling QueryMode + @param[in,out] Column Current column of the cursor position + @param[in,out] Row Current row of the cursor position +**/ +VOID +EFIAPI +MoveCursorBackward ( + IN UINTN LineLength, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ); + +/** + Move the cursor position one character forward. + + @param[in] LineLength Length of a line. + @param[in] TotalRow Total row of a screen + @param[in,out] Column Current column of the cursor position + @param[in,out] Row Current row of the cursor position +**/ +VOID +EFIAPI +MoveCursorForward ( + IN UINTN LineLength, + IN UINTN TotalRow, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ); + +/** + Prints out each previously typed command in the command list history log. + + When each screen is full it will pause for a key before continuing. + + @param[in] TotalCols How many columns are on the screen + @param[in] TotalRows How many rows are on the screen + @param[in] StartColumn which column to start at +**/ +VOID +EFIAPI +PrintCommandHistory ( + IN CONST UINTN TotalCols, + IN CONST UINTN TotalRows, + IN CONST UINTN StartColumn + ); + +#endif //_FILE_HANDLE_INTERNAL_HEADER_ + diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.c b/ShellPkg/Application/Shell/FileHandleWrappers.c new file mode 100644 index 0000000000..02e42e3c9d --- /dev/null +++ b/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -0,0 +1,1563 @@ +/** @file + EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, + StdIn, StdOut, StdErr, etc...). + + Copyright (c) 2009 - 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 "Shell.h" +#include "FileHandleInternal.h" + +/** + File style interface for console (Open). + + @param[in] This Ignored. + @param[out] NewHandle Ignored. + @param[in] FileName Ignored. + @param[in] OpenMode Ignored. + @param[in] Attributes Ignored. + + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +EFIAPI +FileInterfaceOpenNotFound( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + return (EFI_NOT_FOUND); +} + +/** + File style interface for console (Close, Delete, & Flush) + + @param[in] This Ignored. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGeneric( + IN EFI_FILE_PROTOCOL *This + ) +{ + return (EFI_SUCCESS); +} + +/** + File style interface for console (GetPosition). + + @param[in] This Ignored. + @param[out] Position Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (SetPosition). + + @param[in] This Ignored. + @param[in] Position Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopSetPosition( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (GetInfo). + + @param[in] This Ignored. + @param[in] InformationType Ignored. + @param[in,out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopGetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console (SetInfo). + + @param[in] This Ignored. + @param[in] InformationType Ignored. + @param[in] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceNopSetInfo( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for StdOut (Write). + + Writes data to the screen. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_UNSUPPORTED No output console is supported. + @return A return value from gST->ConOut->OutputString. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdOutWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { + return (EFI_UNSUPPORTED); + } else { + return (gST->ConOut->OutputString(gST->ConOut, Buffer)); + } +} + +/** + File style interface for StdIn (Write). + + @param[in] This Ignored. + @param[in] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdInWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console StdErr (Write). + + Writes error to the error output. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @return A return value from gST->StdErr->OutputString. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdErrWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (gST->StdErr->OutputString(gST->StdErr, Buffer)); +} + +/** + File style interface for console StdOut (Read). + + @param[in] This Ignored. + @param[in,out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdOutRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for console StdErr (Read). + + @param[in] This Ignored. + @param[in,out] BufferSize Ignored. + @param[out] Buffer Ignored. + + @retval EFI_UNSUPPORTED +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdErrRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_UNSUPPORTED); +} + +/** + File style interface for NUL file (Read). + + @param[in] This Ignored. + @param[in,out] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceNulRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (EFI_SUCCESS); +} + +/** + File style interface for NUL file (Write). + + @param[in] This Ignored. + @param[in,out] BufferSize Ignored. + @param[in] Buffer Ignored. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceNulWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + return (EFI_SUCCESS); +} + +/** + File style interface for console (Read). + + This will return a single line of input from the console. + + @param This A pointer to the EFI_FILE_PROTOCOL instance that is the + file handle to read data from. Not used. + @param BufferSize On input, the size of the Buffer. On output, the amount + of data returned in Buffer. In both cases, the size is + measured in bytes. + @param Buffer The buffer into which the data is read. + + + @retval EFI_SUCCESS The data was read. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. + @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory + entry. BufferSize has been updated with the size + needed to complete the request. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceStdInRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + CHAR16 *CurrentString; + BOOLEAN Done; + UINTN Column; // Column of current cursor + UINTN Row; // Row of current cursor + UINTN StartColumn; // Column at the beginning of the line + UINTN Update; // Line index for update + UINTN Delete; // Num of chars to delete from console after update + UINTN StringLen; // Total length of the line + UINTN StringCurPos; // Line index corresponding to the cursor + UINTN MaxStr; // Maximum possible line length + UINTN Index; + UINTN TotalColumn; // Num of columns in the console + UINTN TotalRow; // Num of rows in the console + UINTN SkipLength; + UINTN OutputLength; // Length of the update string + UINTN TailRow; // Row of end of line + UINTN TailColumn; // Column of end of line + EFI_INPUT_KEY Key; + + BUFFER_LIST *LinePos; + BUFFER_LIST *NewPos; + BOOLEAN InScrolling; + EFI_STATUS Status; + BOOLEAN InTabScrolling; // Whether in TAB-completion state + EFI_SHELL_FILE_INFO *FoundFileList; + EFI_SHELL_FILE_INFO *TabLinePos; + EFI_SHELL_FILE_INFO *TempPos; + CHAR16 *TabStr; + CHAR16 *TabOutputStr; + BOOLEAN InQuotationMode; + CHAR16 *TempStr; + UINTN TabPos; // Start index of the string to search for TAB completion. + UINTN TabUpdatePos; // Start index of the string updated by TAB stroke +// UINTN Count; + UINTN EventIndex; + CONST CHAR16 *Cwd; + + // + // If buffer is not large enough to hold a CHAR16, return minimum buffer size + // + if (*BufferSize < sizeof (CHAR16) * 2) { + *BufferSize = sizeof (CHAR16) * 2; + return (EFI_BUFFER_TOO_SMALL); + } + + Done = FALSE; + CurrentString = Buffer; + StringLen = 0; + StringCurPos = 0; + OutputLength = 0; + Update = 0; + Delete = 0; + LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory); + InScrolling = FALSE; + InTabScrolling = FALSE; + Status = EFI_SUCCESS; + TabLinePos = NULL; + FoundFileList = NULL; + TempPos = NULL; + TabPos = 0; + TabUpdatePos = 0; + + // + // Allocate buffers + // + TabStr = AllocateZeroPool (*BufferSize); + if (TabStr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + TabOutputStr = AllocateZeroPool (*BufferSize); + if (TabOutputStr == NULL) { + FreePool(TabStr); + return EFI_OUT_OF_RESOURCES; + } + + // + // Get the screen setting and the current cursor location + // + Column = StartColumn = gST->ConOut->Mode->CursorColumn; + Row = gST->ConOut->Mode->CursorRow; + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow); + + // + // Limit the line length to the buffer size or the minimun size of the + // screen. (The smaller takes effect) + // + MaxStr = TotalColumn * (TotalRow - 1) - StartColumn; + if (MaxStr > *BufferSize / sizeof (CHAR16)) { + MaxStr = *BufferSize / sizeof (CHAR16); + } + ZeroMem (CurrentString, MaxStr * sizeof (CHAR16)); + do { + // + // Read a key + // + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Press PageUp or PageDown to scroll the history screen up or down. + // Press any other key to quit scrolling. + // + if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) { + if (Key.ScanCode == SCAN_PAGE_UP) { + ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo); + } else if (Key.ScanCode == SCAN_PAGE_DOWN) { + ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo); + } + + InScrolling = TRUE; + } else { + if (InScrolling) { + ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo); + InScrolling = FALSE; + } + } + + // + // If we are quitting TAB scrolling... + // + if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) { + if (FoundFileList != NULL) { + ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList); + DEBUG_CODE(FoundFileList = NULL;); + } + InTabScrolling = FALSE; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + // + // All done, print a newline at the end of the string + // + TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; + ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n"); + Done = TRUE; + break; + + case CHAR_BACKSPACE: + if (StringCurPos != 0) { + // + // If not move back beyond string beginning, move all characters behind + // the current position one character forward + // + StringCurPos--; + Update = StringCurPos; + Delete = 1; + CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); + + // + // Adjust the current column and row + // + MoveCursorBackward (TotalColumn, &Column, &Row); + } + break; + + case CHAR_TAB: + // + // handle auto complete of file and directory names... + // + if (InTabScrolling) { + ASSERT(FoundFileList != NULL); + ASSERT(TabLinePos != NULL); + TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link); + if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) { + TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link); + } + } else { + TabPos = 0; + TabUpdatePos = 0; + InQuotationMode = FALSE; + for (Index = 0; Index < StringLen; Index++) { + if (CurrentString[Index] == L'\"') { + InQuotationMode = (BOOLEAN)(!InQuotationMode); + } + if (CurrentString[Index] == L' ' && !InQuotationMode) { + TabPos = Index + 1; + TabUpdatePos = Index + 1; + } + if (CurrentString[Index] == L'\\') { + TabUpdatePos = Index + 1; + } + } + if (StrStr(CurrentString + TabPos, L":") == NULL) { + Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL); + if (Cwd != NULL) { + StrCpy(TabStr, Cwd); + if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) { + TabStr[StrLen(TabStr)-1] = CHAR_NULL; + } + StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16)); + } else { + StrCpy(TabStr, L""); + StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16)); + } + } else { + StrCpy(TabStr, CurrentString + TabPos); + } + StrCat(TabStr, L"*"); + FoundFileList = NULL; +// TabStr = CleanPath(TabStr); + Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList); + for ( TempStr = CurrentString + ; *TempStr == L' ' + ; TempStr++); // note the ';'... empty for loop + // + // make sure we have a list before we do anything more... + // + if (EFI_ERROR (Status) || FoundFileList == NULL) { + InTabScrolling = FALSE; + TabLinePos = NULL; + continue; + } else { + // + // enumerate through the list of files + // + for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link)) + ; !IsNull(&FoundFileList->Link, &TempPos->Link) + ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link)) + ){ + // + // If "cd" is typed, only directory name will be auto-complete filled + // in either case . and .. will be removed. + // + if ((((TempStr[0] == L'c' || TempStr[0] == L'C') && + (TempStr[1] == L'd' || TempStr[1] == L'D') + ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS) + ||(StrCmp(TempPos->FileName, L".") == 0) + ||(StrCmp(TempPos->FileName, L"..") == 0) + )) || ((StrCmp(TempPos->FileName, L".") == 0) + ||(StrCmp(TempPos->FileName, L"..") == 0))){ + TabLinePos = TempPos; + TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink); + InternalFreeShellFileInfoNode(TabLinePos); + } + } + if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) { + TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link); + InTabScrolling = TRUE; + } else { + FreePool(FoundFileList); + FoundFileList = NULL; + } + } + } + break; + + default: + if (Key.UnicodeChar >= ' ') { + // + // If we are at the buffer's end, drop the key + // + if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) { + break; + } + // + // If in insert mode, make space by moving each other character 1 + // space higher in the array + // + if (ShellInfoObject.ViewingSettings.InsertMode) { + CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0])); + } + + CurrentString[StringCurPos] = Key.UnicodeChar; + Update = StringCurPos; + + StringCurPos += 1; + OutputLength = 1; + } + break; + + case 0: + switch (Key.ScanCode) { + case SCAN_DELETE: + // + // Move characters behind current position one character forward + // + if (StringLen != 0) { + Update = StringCurPos; + Delete = 1; + CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); + } + break; + + case SCAN_UP: + // + // Prepare to print the previous command + // + NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) { + NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + } + break; + + case SCAN_DOWN: + // + // Prepare to print the next command + // + NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) { + NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); + } + break; + + case SCAN_LEFT: + // + // Adjust current cursor position + // + if (StringCurPos != 0) { + --StringCurPos; + MoveCursorBackward (TotalColumn, &Column, &Row); + } + break; + + case SCAN_RIGHT: + // + // Adjust current cursor position + // + if (StringCurPos < StringLen) { + ++StringCurPos; + MoveCursorForward (TotalColumn, TotalRow, &Column, &Row); + } + break; + + case SCAN_HOME: + // + // Move current cursor position to the beginning of the command line + // + Row -= (StringCurPos + StartColumn) / TotalColumn; + Column = StartColumn; + StringCurPos = 0; + break; + + case SCAN_END: + // + // Move current cursor position to the end of the command line + // + TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; + Row = TailRow; + Column = TailColumn; + StringCurPos = StringLen; + break; + + case SCAN_ESC: + // + // Prepare to clear the current command line + // + CurrentString[0] = 0; + Update = 0; + Delete = StringLen; + Row -= (StringCurPos + StartColumn) / TotalColumn; + Column = StartColumn; + OutputLength = 0; + break; + + case SCAN_INSERT: + // + // Toggle the SEnvInsertMode flag + // + ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode; + break; + + case SCAN_F7: + // + // Print command history + // + PrintCommandHistory (TotalColumn, TotalRow, 4); + *CurrentString = CHAR_NULL; + Done = TRUE; + break; + } + } + + if (Done) { + break; + } + + // + // If we are in auto-complete mode, we are preparing to print + // the next file or directory name + // + if (InTabScrolling) { + // + // Adjust the column and row to the start of TAB-completion string. + // + Column = (StartColumn + TabUpdatePos) % TotalColumn; + Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn; + OutputLength = StrLen (TabLinePos->FileName); + // + // if the output string contains blank space, quotation marks L'\"' + // should be added to the output. + // + if (StrStr(TabLinePos->FileName, L" ") != NULL){ + TabOutputStr[0] = L'\"'; + CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16)); + TabOutputStr[OutputLength + 1] = L'\"'; + TabOutputStr[OutputLength + 2] = CHAR_NULL; + } else { + CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16)); + TabOutputStr[OutputLength] = CHAR_NULL; + } + OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1; + CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16)); + CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL; + StringCurPos = TabUpdatePos + OutputLength; + Update = TabUpdatePos; + if (StringLen > TabUpdatePos + OutputLength) { + Delete = StringLen - TabUpdatePos - OutputLength; + } + } + + // + // If we have a new position, we are preparing to print a previous or + // next command. + // + if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) { + Column = StartColumn; + Row -= (StringCurPos + StartColumn) / TotalColumn; + + LinePos = NewPos; + NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory); + + OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1; + CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16)); + CurrentString[OutputLength] = CHAR_NULL; + + StringCurPos = OutputLength; + + // + // Draw new input string + // + Update = 0; + if (StringLen > OutputLength) { + // + // If old string was longer, blank its tail + // + Delete = StringLen - OutputLength; + } + } + // + // If we need to update the output do so now + // + if (Update != (UINTN) -1) { + ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L""); + StringLen = StrLen (CurrentString); + + if (Delete != 0) { + SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL); + } + + if (StringCurPos > StringLen) { + StringCurPos = StringLen; + } + + Update = (UINTN) -1; + + // + // After using print to reflect newly updates, if we're not using + // BACKSPACE and DELETE, we need to move the cursor position forward, + // so adjust row and column here. + // + if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) { + // + // Calulate row and column of the tail of current string + // + TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn; + TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn; + + // + // If the tail of string reaches screen end, screen rolls up, so if + // Row does not equal TailRow, Row should be decremented + // + // (if we are recalling commands using UPPER and DOWN key, and if the + // old command is too long to fit the screen, TailColumn must be 79. + // + if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) { + Row--; + } + // + // Calculate the cursor position after current operation. If cursor + // reaches line end, update both row and column, otherwise, only + // column will be changed. + // + if (Column + OutputLength >= TotalColumn) { + SkipLength = OutputLength - (TotalColumn - Column); + + Row += SkipLength / TotalColumn + 1; + if (Row > TotalRow - 1) { + Row = TotalRow - 1; + } + + Column = SkipLength % TotalColumn; + } else { + Column += OutputLength; + } + } + + Delete = 0; + } + // + // Set the cursor position for this key + // + gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); + } while (!Done); + + if (CurrentString != NULL && StrLen(CurrentString) > 0) { + // + // add the line to the history buffer + // + AddLineToCommandHistory(CurrentString); + } + + FreePool (TabStr); + FreePool (TabOutputStr); + // + // Return the data to the caller + // + *BufferSize = StringLen * sizeof (CHAR16); + + // + // if this was used it should be deallocated by now... + // prevent memory leaks... + // + ASSERT(FoundFileList == NULL); + + return EFI_SUCCESS; +} + +// +// FILE sytle interfaces for StdIn/StdOut/StdErr +// +EFI_FILE_PROTOCOL FileInterfaceStdIn = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdInRead, + FileInterfaceStdInWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceStdOut = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdOutRead, + FileInterfaceStdOutWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceStdErr = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceStdErrRead, + FileInterfaceStdErrWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + +EFI_FILE_PROTOCOL FileInterfaceNulFile = { + EFI_FILE_REVISION, + FileInterfaceOpenNotFound, + FileInterfaceNopGeneric, + FileInterfaceNopGeneric, + FileInterfaceNulRead, + FileInterfaceNulWrite, + FileInterfaceNopGetPosition, + FileInterfaceNopSetPosition, + FileInterfaceNopGetInfo, + FileInterfaceNopSetInfo, + FileInterfaceNopGeneric +}; + + + + +// +// This is identical to EFI_FILE_PROTOCOL except for the additional member +// for the name. +// + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + CHAR16 Name[1]; +} EFI_FILE_PROTOCOL_ENVIRONMENT; +//ANSI compliance helper to get size of the struct. +#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name) + +/** + File style interface for Environment Variable (Close). + + Frees the memory for this object. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This); + return (EFI_SUCCESS); +} + +/** + File style interface for Environment Variable (Delete). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval The return value from FileInterfaceEnvClose(). +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvDelete( + IN EFI_FILE_PROTOCOL *This + ) +{ + SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name); + return (FileInterfaceEnvClose(This)); +} + +/** + File style interface for Environment Variable (Read). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[out] Buffer The pointer to the buffer to fill. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + return (SHELL_GET_ENVIRONMENT_VARIABLE( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + BufferSize, + Buffer)); +} + +/** + File style interface for Volatile Environment Variable (Write). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvVolWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + VOID* NewBuffer; + UINTN NewSize; + EFI_STATUS Status; + + NewBuffer = NULL; + NewSize = 0; + + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + if (Status == EFI_BUFFER_TOO_SMALL){ + NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16)); + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + } + if (!EFI_ERROR(Status) && NewBuffer != NULL) { + while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) { + // + // We want to overwrite the CHAR_NULL + // + NewSize -= 2; + } + CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize); + Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer); + FreePool(NewBuffer); + return (Status); + } else { + SHELL_FREE_NON_NULL(NewBuffer); + return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer)); + } +} + + +/** + File style interface for Non Volatile Environment Variable (Write). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceEnvNonVolWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + VOID* NewBuffer; + UINTN NewSize; + EFI_STATUS Status; + + NewBuffer = NULL; + NewSize = 0; + + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + if (Status == EFI_BUFFER_TOO_SMALL){ + NewBuffer = AllocateZeroPool(NewSize + *BufferSize); + Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); + } + if (!EFI_ERROR(Status)) { + CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize); + return (SHELL_SET_ENVIRONMENT_VARIABLE_NV( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + NewSize + *BufferSize, + NewBuffer)); + } else { + return (SHELL_SET_ENVIRONMENT_VARIABLE_NV( + ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, + *BufferSize, + Buffer)); + } +} + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + environment variables through file operations. + + @param EnvName The name of the Environment Variable to be operated on. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +EFIAPI +CreateFileInterfaceEnv( + IN CONST CHAR16 *EnvName + ) +{ + EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface; + + if (EnvName == NULL) { + return (NULL); + } + + // + // Get some memory + // + EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+StrSize(EnvName)); + if (EnvFileInterface == NULL){ + return (NULL); + } + + // + // Assign the generic members + // + EnvFileInterface->Revision = EFI_FILE_REVISION; + EnvFileInterface->Open = FileInterfaceOpenNotFound; + EnvFileInterface->Close = FileInterfaceEnvClose; + EnvFileInterface->GetPosition = FileInterfaceNopGetPosition; + EnvFileInterface->SetPosition = FileInterfaceNopSetPosition; + EnvFileInterface->GetInfo = FileInterfaceNopGetInfo; + EnvFileInterface->SetInfo = FileInterfaceNopSetInfo; + EnvFileInterface->Flush = FileInterfaceNopGeneric; + EnvFileInterface->Delete = FileInterfaceEnvDelete; + EnvFileInterface->Read = FileInterfaceEnvRead; + + StrCpy(EnvFileInterface->Name, EnvName); + + // + // Assign the different members for Volatile and Non-Volatile variables + // + if (IsVolatileEnv(EnvName)) { + EnvFileInterface->Write = FileInterfaceEnvVolWrite; + } else { + EnvFileInterface->Write = FileInterfaceEnvNonVolWrite; + } + return ((EFI_FILE_PROTOCOL *)EnvFileInterface); +} + +/** + Move the cursor position one character backward. + + @param[in] LineLength Length of a line. Get it by calling QueryMode + @param[in,out] Column Current column of the cursor position + @param[in,out] Row Current row of the cursor position +**/ +VOID +EFIAPI +MoveCursorBackward ( + IN UINTN LineLength, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ) +{ + // + // If current column is 0, move to the last column of the previous line, + // otherwise, just decrement column. + // + if (*Column == 0) { + *Column = LineLength - 1; + if (*Row > 0) { + (*Row)--; + } + return; + } + (*Column)--; +} + +/** + Move the cursor position one character forward. + + @param[in] LineLength Length of a line. + @param[in] TotalRow Total row of a screen + @param[in,out] Column Current column of the cursor position + @param[in,out] Row Current row of the cursor position +**/ +VOID +EFIAPI +MoveCursorForward ( + IN UINTN LineLength, + IN UINTN TotalRow, + IN OUT UINTN *Column, + IN OUT UINTN *Row + ) +{ + // + // Increment Column. + // If this puts column past the end of the line, move to first column + // of the next row. + // + (*Column)++; + if (*Column >= LineLength) { + (*Column) = 0; + if ((*Row) < TotalRow - 1) { + (*Row)++; + } + } +} + +/** + Prints out each previously typed command in the command list history log. + + When each screen is full it will pause for a key before continuing. + + @param[in] TotalCols How many columns are on the screen + @param[in] TotalRows How many rows are on the screen + @param[in] StartColumn which column to start at +**/ +VOID +EFIAPI +PrintCommandHistory ( + IN CONST UINTN TotalCols, + IN CONST UINTN TotalRows, + IN CONST UINTN StartColumn + ) +{ + BUFFER_LIST *Node; + UINTN Index; + UINTN LineNumber; + UINTN LineCount; + + ShellPrintEx (-1, -1, L"\n"); + Index = 0; + LineNumber = 0; + // + // go through history list... + // + for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link) + ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) + ){ + Index++; + LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1; + + if (LineNumber + LineCount >= TotalRows) { + ShellPromptForResponseHii( + ShellPromptResponseTypeEnterContinue, + STRING_TOKEN (STR_SHELL_ENTER_TO_CONT), + ShellInfoObject.HiiHandle, + NULL + ); + LineNumber = 0; + } + ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer); + LineNumber += LineCount; + } +} + + + + + + +// +// This is identical to EFI_FILE_PROTOCOL except for the additional members +// for the buffer, size, and position. +// + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + VOID *Buffer; + UINT64 Position; + UINT64 BufferSize; + BOOLEAN Unicode; +} EFI_FILE_PROTOCOL_MEM; + +/** + File style interface for Mem (SetPosition). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[out] Position The position to set. + + @retval EFI_SUCCESS The position was successfully changed. + @retval EFI_INVALID_PARAMETER The Position was invalid. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemSetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 Position + ) +{ + if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) { + ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position; + return (EFI_SUCCESS); + } else { + return (EFI_INVALID_PARAMETER); + } +} + +/** + File style interface for Mem (GetPosition). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[out] Position The pointer to the position. + + @retval EFI_SUCCESS The position was retrieved. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemGetPosition( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position; + return (EFI_SUCCESS); +} + +/** + File style interface for Mem (Write). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was written. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + CHAR8 *AsciiBuffer; + if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) { + // + // Unicode + // + if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { + ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + (*BufferSize) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); + ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10; + } + CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize); + ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize); + return (EFI_SUCCESS); + } else { + // + // Ascii + // + AsciiBuffer = AllocatePool(*BufferSize); + AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); + if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { + ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + AsciiStrSize(AsciiBuffer) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); + ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10; + } + CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer)); + ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer); + FreePool(AsciiBuffer); + return (EFI_SUCCESS); + } +} + +/** + File style interface for Mem (Read). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in,out] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to fill. + + @retval EFI_SUCCESS The data was read. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemRead( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) { + (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position)); + } + CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize)); + ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize); + return (EFI_SUCCESS); +} + +/** + File style interface for Mem (Close). + + Frees all memory associated with this object. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS The 'file' was closed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceMemClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); + SHELL_FREE_NON_NULL((EFI_FILE_PROTOCOL_MEM*)This); + return (EFI_SUCCESS); +} + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely in memory through file operations. + + @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii. + + @retval NULL Memory could not be allocated. + @return other A pointer to an EFI_FILE_PROTOCOL structure. +**/ +EFI_FILE_PROTOCOL* +EFIAPI +CreateFileInterfaceMem( + IN CONST BOOLEAN Unicode + ) +{ + EFI_FILE_PROTOCOL_MEM *FileInterface; + + // + // Get some memory + // + FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM)); + if (FileInterface == NULL){ + return (NULL); + } + + // + // Assign the generic members + // + FileInterface->Revision = EFI_FILE_REVISION; + FileInterface->Open = FileInterfaceOpenNotFound; + FileInterface->Close = FileInterfaceMemClose; + FileInterface->GetPosition = FileInterfaceMemGetPosition; + FileInterface->SetPosition = FileInterfaceMemSetPosition; + FileInterface->GetInfo = FileInterfaceNopGetInfo; + FileInterface->SetInfo = FileInterfaceNopSetInfo; + FileInterface->Flush = FileInterfaceNopGeneric; + FileInterface->Delete = FileInterfaceNopGeneric; + FileInterface->Read = FileInterfaceMemRead; + FileInterface->Write = FileInterfaceMemWrite; + FileInterface->Unicode = Unicode; + + ASSERT(FileInterface->Buffer == NULL); + ASSERT(FileInterface->BufferSize == 0); + ASSERT(FileInterface->Position == 0); + + return ((EFI_FILE_PROTOCOL *)FileInterface); +} + +typedef struct { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + EFI_FILE_SET_INFO SetInfo; + EFI_FILE_FLUSH Flush; + BOOLEAN Unicode; + EFI_FILE_PROTOCOL *Orig; +} EFI_FILE_PROTOCOL_FILE; + +/** + File style interface for File (Close). + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + + @retval EFI_SUCCESS The file was closed. +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileClose( + IN EFI_FILE_PROTOCOL *This + ) +{ + ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); + FreePool(This); + return (EFI_SUCCESS); +} + +/** + File style interface for File (Write). + + If the file was opened with ASCII mode the data will be processed through + AsciiSPrint before writing. + + @param[in] This The pointer to the EFI_FILE_PROTOCOL object. + @param[in] BufferSize Size in bytes of Buffer. + @param[in] Buffer The pointer to the buffer to write. + + @retval EFI_SUCCESS The data was written. +**/ +EFI_STATUS +EFIAPI +FileInterfaceFileWrite( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + CHAR8 *AsciiBuffer; + UINTN Size; + EFI_STATUS Status; + if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { + // + // Unicode + // + return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); + } else { + // + // Ascii + // + AsciiBuffer = AllocatePool(*BufferSize); + AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); + Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator) + Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); + FreePool(AsciiBuffer); + return (Status); + } +} + +/** + Create a file interface with unicode information. + + This will create a new EFI_FILE_PROTOCOL identical to the Templace + except that the new one has Unicode and Ascii knowledge. + + @param[in] Template A pointer to the EFI_FILE_PROTOCOL object. + @param[in] Unicode TRUE for UCS-2, FALSE for ASCII. + + @return a new EFI_FILE_PROTOCOL object to be used instead of the template. +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceFile( + IN CONST EFI_FILE_PROTOCOL *Template, + IN CONST BOOLEAN Unicode + ) +{ + EFI_FILE_PROTOCOL_FILE *NewOne; + + NewOne = AllocatePool(sizeof(EFI_FILE_PROTOCOL_FILE)); + CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE)); + NewOne->Orig = (EFI_FILE_PROTOCOL *)Template; + NewOne->Unicode = Unicode; + NewOne->Close = FileInterfaceFileClose; + NewOne->Write = FileInterfaceFileWrite; + + return ((EFI_FILE_PROTOCOL *)NewOne); +} diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.h b/ShellPkg/Application/Shell/FileHandleWrappers.h new file mode 100644 index 0000000000..af133b0963 --- /dev/null +++ b/ShellPkg/Application/Shell/FileHandleWrappers.h @@ -0,0 +1,95 @@ +/** @file + EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, StdIn, StdOut, StdErr, etc...) + + Copyright (c) 2009 - 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_FILE_HANDLE_WRAPPERS_HEADER_ +#define _SHELL_FILE_HANDLE_WRAPPERS_HEADER_ + +typedef struct { + LIST_ENTRY Link; + CHAR16* Buffer; +} SHELL_LINE_LIST; + +typedef struct { + UINTN LogCount; + SHELL_LINE_LIST *Log; +} SHELL_LINE_LOG; + +/// +/// FILE sytle interfaces for StdIn. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdIn; + +/// +/// FILE sytle interfaces for StdOut. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdOut; + +/// +/// FILE sytle interfaces for StdErr. +/// +extern EFI_FILE_PROTOCOL FileInterfaceStdErr; + +/// +/// FILE style interface for NUL file. +/// +extern EFI_FILE_PROTOCOL FileInterfaceNulFile; + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + environment variables through file operations. + + @param EnvName The name of the Environment Variable to be operated on. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +EFIAPI +CreateFileInterfaceEnv( + CONST CHAR16 *EnvName + ); + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely in memory through file operations. + + @param[in] Unicode TRUE if the data is UNICODE, FALSE otherwise. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +EFIAPI +CreateFileInterfaceMem( + IN CONST BOOLEAN Unicode + ); + +/** + Creates a EFI_FILE_PROTOCOL (almost) object for using to access + a file entirely with unicode awareness through file operations. + + @param[in] Template The pointer to the handle to start with. + @param[in] Unicode TRUE if the data is UNICODE, FALSE otherwise. + + @retval NULL Memory could not be allocated. + @return other a pointer to an EFI_FILE_PROTOCOL structure +**/ +EFI_FILE_PROTOCOL* +CreateFileInterfaceFile( + IN CONST EFI_FILE_PROTOCOL *Template, + IN CONST BOOLEAN Unicode + ); + +#endif //_SHELL_FILE_HANDLE_WRAPPERS_HEADER_ + diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c new file mode 100644 index 0000000000..3401bc0644 --- /dev/null +++ b/ShellPkg/Application/Shell/Shell.c @@ -0,0 +1,1707 @@ +/** @file + This is THE shell (application) + + Copyright (c) 2009 - 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 "Shell.h" + +// +// Initialize the global structure +// +SHELL_INFO ShellInfoObject = { + NULL, + NULL, + FALSE, + FALSE, + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + NULL, + NULL + }, + {0,0}, + { + {0,0}, + 0, + 0, + TRUE + }, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + {0,0,NULL,NULL}, + {0,0}, +}; + +STATIC CONST CHAR16 mScriptExtension[] = L".NSH"; +STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI"; + +/** + The entry point for the application. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CHAR16 *TempString; + UINTN Size; +// EFI_INPUT_KEY Key; + +// gST->ConOut->OutputString(gST->ConOut, L"ReadKeyStroke Calling\r\n"); +// +// Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); +// +// gST->ConOut->OutputString(gST->ConOut, L"ReadKeyStroke Done\r\n"); +// gBS->Stall (1000000); + + if (PcdGet8(PcdShellSupportLevel) > 3) { + return (EFI_UNSUPPORTED); + } + + // + // Clear the screen + // + Status = gST->ConOut->ClearScreen(gST->ConOut); + ASSERT_EFI_ERROR(Status); + + // + // Populate the global structure from PCDs + // + ShellInfoObject.ImageDevPath = NULL; + ShellInfoObject.FileDevPath = NULL; + ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault); + ShellInfoObject.ViewingSettings.InsertMode = PcdGetBool(PcdShellInsertModeDefault); + ShellInfoObject.LogScreenCount = PcdGet8 (PcdShellScreenLogCount ); + + // + // verify we dont allow for spec violation + // + ASSERT(ShellInfoObject.LogScreenCount >= 3); + + // + // Initialize the LIST ENTRY objects... + // + InitializeListHead(&ShellInfoObject.BufferToFreeList.Link); + InitializeListHead(&ShellInfoObject.ViewingSettings.CommandHistory.Link); + InitializeListHead(&ShellInfoObject.SplitList.Link); + + // + // Check PCDs for optional features that are not implemented yet. + // + if ( PcdGetBool(PcdShellSupportOldProtocols) + || !FeaturePcdGet(PcdShellRequireHiiPlatform) + || FeaturePcdGet(PcdShellSupportFrameworkHii) + ) { + return (EFI_UNSUPPORTED); + } + + // + // turn off the watchdog timer + // + gBS->SetWatchdogTimer (0, 0, 0, NULL); + + // + // install our console logger. This will keep a log of the output for back-browsing + // + Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo); + ASSERT_EFI_ERROR(Status); + + // + // Enable the cursor to be visible + // + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + // + // If supporting EFI 1.1 we need to install HII protocol + // only do this if PcdShellRequireHiiPlatform == FALSE + // + // remove EFI_UNSUPPORTED check above when complete. + ///@todo add support for Framework HII + + // + // install our (solitary) HII package + // + ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL); + if (ShellInfoObject.HiiHandle == NULL) { + if (PcdGetBool(PcdShellSupportFrameworkHii)) { + ///@todo Add our package into Framework HII + } + if (ShellInfoObject.HiiHandle == NULL) { + return (EFI_NOT_STARTED); + } + } + + // + // create and install the EfiShellParametersProtocol + // + Status = CreatePopulateInstallShellParametersProtocol(&ShellInfoObject.NewShellParametersProtocol, &ShellInfoObject.RootShellInstance); + ASSERT_EFI_ERROR(Status); + ASSERT(ShellInfoObject.NewShellParametersProtocol != NULL); + + // + // create and install the EfiShellProtocol + // + Status = CreatePopulateInstallShellProtocol(&ShellInfoObject.NewEfiShellProtocol); + ASSERT_EFI_ERROR(Status); + ASSERT(ShellInfoObject.NewEfiShellProtocol != NULL); + + // + // Now initialize the shell library (it requires Shell Parameters protocol) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // Check the command line + // + Status = ProcessCommandLine(); + + // + // If shell support level is >= 1 create the mappings and paths + // + if (PcdGet8(PcdShellSupportLevel) >= 1) { + Status = ShellCommandCreateInitialMappingsAndPaths(); + } + + // + // save the device path for the loaded image and the device path for the filepath (under loaded image) + // These are where to look for the startup.nsh file + // + Status = GetDevicePathsForImageAndFile(&ShellInfoObject.ImageDevPath, &ShellInfoObject.FileDevPath); + ASSERT_EFI_ERROR(Status); + + // + // Display the version + // + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_MAIN), + ShellInfoObject.HiiHandle, + SupportLevel[PcdGet8(PcdShellSupportLevel)], + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion, + (gST->Hdr.Revision&0xffff0000)>>16, + (gST->Hdr.Revision&0x0000ffff), + gST->FirmwareVendor, + gST->FirmwareRevision + ); + } + + // + // Display the mapping + // + if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) { + Status = RunCommand(L"map"); + ASSERT_EFI_ERROR(Status); + } + + // + // init all the built in alias' + // + Status = SetBuiltInAlias(); + ASSERT_EFI_ERROR(Status); + + // + // Initialize environment variables + // + if (ShellCommandGetProfileList() != NULL) { + Status = InternalEfiShellSetEnv(L"profiles", ShellCommandGetProfileList(), TRUE); + ASSERT_EFI_ERROR(Status); + } + + Size = 100; + TempString = AllocateZeroPool(Size); + + UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel)); + Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + UnicodeSPrint(TempString, Size, L"%d.%d", ShellInfoObject.NewEfiShellProtocol->MajorVersion, ShellInfoObject.NewEfiShellProtocol->MinorVersion); + Status = InternalEfiShellSetEnv(L"uefishellversion", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + UnicodeSPrint(TempString, Size, L"%d.%d", (gST->Hdr.Revision & 0xFFFF0000) >> 16, gST->Hdr.Revision & 0x0000FFFF); + Status = InternalEfiShellSetEnv(L"uefiversion", TempString, TRUE); + ASSERT_EFI_ERROR(Status); + + FreePool(TempString); + + if (!EFI_ERROR(Status)) { + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) { + // + // Set up the event for CTRL-C monitoring... + // + + ///@todo add support for using SimpleInputEx here + // if SimpleInputEx is not available display a warning. + } + + if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) { + // + // process the startup script or launch the called app. + // + Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + } + + if ((PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) { + // + // begin the UI waiting loop + // + do { + // + // clean out all the memory allocated for CONST * return values + // between each shell prompt presentation + // + if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){ + FreeBufferList(&ShellInfoObject.BufferToFreeList); + } + + // + // Reset page break back to default. + // + ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault); + ShellInfoObject.ConsoleInfo->Enabled = TRUE; + ShellInfoObject.ConsoleInfo->RowCounter = 0; + + // + // Display Prompt + // + Status = DoShellPrompt(); + } while (!ShellCommandGetExit()); + } + } + // + // uninstall protocols / free memory / etc... + // + if (ShellInfoObject.UserBreakTimer != NULL) { + 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;); + } + if (ShellInfoObject.FileDevPath != NULL) { + FreePool(ShellInfoObject.FileDevPath); + DEBUG_CODE(ShellInfoObject.FileDevPath = NULL;); + } + if (ShellInfoObject.NewShellParametersProtocol != NULL) { + CleanUpShellParametersProtocol(ShellInfoObject.NewShellParametersProtocol); + DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;); + } + if (ShellInfoObject.NewEfiShellProtocol != NULL){ + CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol); + DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;); + } + + if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){ + FreeBufferList(&ShellInfoObject.BufferToFreeList); + } + + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){ + ASSERT(FALSE); + } + + if (ShellInfoObject.ShellInitSettings.FileName != NULL) { + FreePool(ShellInfoObject.ShellInitSettings.FileName); + DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileName = NULL;); + } + + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + FreePool(ShellInfoObject.ShellInitSettings.FileOptions); + DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileOptions = NULL;); + } + + if (ShellInfoObject.HiiHandle != NULL) { + HiiRemovePackages(ShellInfoObject.HiiHandle); + DEBUG_CODE(ShellInfoObject.HiiHandle = NULL;); + } + + if (!IsListEmpty(&ShellInfoObject.ViewingSettings.CommandHistory.Link)){ + FreeBufferList(&ShellInfoObject.ViewingSettings.CommandHistory); + } + + ASSERT(ShellInfoObject.ConsoleInfo != NULL); + if (ShellInfoObject.ConsoleInfo != NULL) { + ConsoleLoggerUninstall(ShellInfoObject.ConsoleInfo); + FreePool(ShellInfoObject.ConsoleInfo); + DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;); + } + + return (Status); +} + +/** + Sets all the alias' that were registered with the ShellCommandLib library. + + @retval EFI_SUCCESS all init commands were run sucessfully. +**/ +EFI_STATUS +EFIAPI +SetBuiltInAlias( + ) +{ + EFI_STATUS Status; + CONST ALIAS_LIST *List; + ALIAS_LIST *Node; + + // + // Get all the commands we want to run + // + List = ShellCommandGetInitAliasList(); + + // + // for each command in the List + // + for ( Node = (ALIAS_LIST*)GetFirstNode(&List->Link) + ; !IsNull (&List->Link, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(&List->Link, &Node->Link) + ){ + // + // install the alias' + // + Status = InternalSetAlias(Node->CommandString, Node->Alias, TRUE); + ASSERT_EFI_ERROR(Status); + } + return (EFI_SUCCESS); +} + +/** + Internal function to determine if 2 command names are really the same. + + @param[in] Command1 The pointer to the first command name. + @param[in] Command2 The pointer to the second command name. + + @retval TRUE The 2 command names are the same. + @retval FALSE The 2 command names are not the same. +**/ +BOOLEAN +EFIAPI +IsCommand( + IN CONST CHAR16 *Command1, + IN CONST CHAR16 *Command2 + ) +{ + if (StringNoCaseCompare(&Command1, &Command2) == 0) { + return (TRUE); + } + return (FALSE); +} + +/** + Internal function to determine if a command is a script only command. + + @param[in] CommandName The pointer to the command name. + + @retval TRUE The command is a script only command. + @retval FALSE The command is not a script only command. +**/ +BOOLEAN +EFIAPI +IsScriptOnlyCommand( + IN CONST CHAR16 *CommandName + ) +{ + if (IsCommand(CommandName, L"for") + ||IsCommand(CommandName, L"endfor") + ||IsCommand(CommandName, L"if") + ||IsCommand(CommandName, L"else") + ||IsCommand(CommandName, L"endif") + ||IsCommand(CommandName, L"goto")) { + return (TRUE); + } + return (FALSE); +} + + + +/** + This function will populate the 2 device path protocol parameters based on the + global gImageHandle. The DevPath will point to the device path for the handle that has + loaded image protocol installed on it. The FilePath will point to the device path + for the file that was loaded. + + @param[in,out] DevPath On a sucessful return the device path to the loaded image. + @param[in,out] FilePath On a sucessful return the device path to the file. + + @retval EFI_SUCCESS The 2 device paths were sucessfully returned. + @retval other A error from gBS->HandleProtocol. + + @sa HandleProtocol +**/ +EFI_STATUS +EFIAPI +GetDevicePathsForImageAndFile ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + + ASSERT(DevPath != NULL); + ASSERT(FilePath != NULL); + + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&ImageDevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + *DevPath = DuplicateDevicePath (ImageDevicePath); + *FilePath = DuplicateDevicePath (LoadedImage->FilePath); + } + gBS->CloseProtocol( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + gImageHandle, + NULL); + } + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = { + {L"-nostartup", TypeFlag}, + {L"-startup", TypeFlag}, + {L"-noconsoleout", TypeFlag}, + {L"-noconsolein", TypeFlag}, + {L"-nointerrupt", TypeFlag}, + {L"-nomap", TypeFlag}, + {L"-noversion", TypeFlag}, + {L"-startup", TypeFlag}, + {L"-delay", TypeValue}, + {NULL, TypeMax} + }; +/** + Process all Uefi Shell 2.0 command line options. + + see Uefi Shell 2.0 section 3.2 for full details. + + the command line must resemble the following: + + shell.efi [ShellOpt-options] [options] [file-name [file-name-options]] + + ShellOpt-options Options which control the initialization behavior of the shell. + These options are read from the EFI global variable "ShellOpt" + and are processed before options or file-name. + + options Options which control the initialization behavior of the shell. + + file-name The name of a UEFI shell application or script to be executed + after initialization is complete. By default, if file-name is + specified, then -nostartup is implied. Scripts are not supported + by level 0. + + file-name-options The command-line options that are passed to file-name when it + is invoked. + + This will initialize the ShellInfoObject.ShellInitSettings global variable. + + @retval EFI_SUCCESS The variable is initialized. +**/ +EFI_STATUS +EFIAPI +ProcessCommandLine( + VOID + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + UINTN Size; + CONST CHAR16 *TempConst; + UINTN Count; + UINTN LoopVar; + CHAR16 *ProblemParam; + + Package = NULL; + ProblemParam = NULL; + + Status = ShellCommandLineParse (mShellParamList, &Package, NULL, FALSE); + + Count = 1; + Size = 0; + TempConst = ShellCommandLineGetRawValue(Package, Count++); + if (TempConst != NULL && StrLen(TempConst)) { + ShellInfoObject.ShellInitSettings.FileName = AllocatePool(StrSize(TempConst)); + StrCpy(ShellInfoObject.ShellInitSettings.FileName, TempConst); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1; + for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + if (StrCmp(gEfiShellParametersProtocol->Argv[LoopVar], ShellInfoObject.ShellInitSettings.FileName)==0) { + LoopVar++; + // + // We found the file... add the rest of the params... + // + for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL)); + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, + &Size, + L" ", + 0); + StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, + &Size, + gEfiShellParametersProtocol->Argv[LoopVar], + 0); + } + } + } + } else { + ShellCommandLineFreeVarList(Package); + Package = NULL; + Status = ShellCommandLineParse (mShellParamList, &Package, &ProblemParam, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), ShellInfoObject.HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellCommandLineFreeVarList(Package); + return (EFI_INVALID_PARAMETER); + } + } + + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = ShellCommandLineGetFlag(Package, L"-startup"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = ShellCommandLineGetFlag(Package, L"-nostartup"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = ShellCommandLineGetFlag(Package, L"-noconsoleout"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = ShellCommandLineGetFlag(Package, L"-noconsolein"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = ShellCommandLineGetFlag(Package, L"-nointerrupt"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = ShellCommandLineGetFlag(Package, L"-nomap"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = ShellCommandLineGetFlag(Package, L"-noversion"); + ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = ShellCommandLineGetFlag(Package, L"-delay"); + + if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay) { + TempConst = ShellCommandLineGetValue(Package, L"-delay"); + if (TempConst != NULL) { + ShellInfoObject.ShellInitSettings.Delay = StrDecimalToUintn (TempConst); + } else { + ShellInfoObject.ShellInitSettings.Delay = 5; + } + } else { + ShellInfoObject.ShellInitSettings.Delay = 5; + } + + ShellCommandLineFreeVarList(Package); + + return (Status); +} + +/** + Handles all interaction with the default startup script. + + this will check that the correct command line parameters were passed, handle the delay, and then start running the script. + + @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. + + @retval EFI_SUCCESS the variable is initialized. +**/ +EFI_STATUS +EFIAPI +DoStartupScript( + EFI_DEVICE_PATH_PROTOCOL *ImagePath, + EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + EFI_STATUS Status; + UINTN Delay; + EFI_INPUT_KEY Key; + SHELL_FILE_HANDLE FileHandle; + EFI_DEVICE_PATH_PROTOCOL *NewPath; + EFI_DEVICE_PATH_PROTOCOL *NamePath; + CHAR16 *FileStringPath; + UINTN NewSize; + + Key.UnicodeChar = CHAR_NULL; + Key.ScanCode = 0; + FileHandle = NULL; + + if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) { + // + // launch something else instead + // + NewSize = StrSize(ShellInfoObject.ShellInitSettings.FileName); + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + NewSize += StrSize(ShellInfoObject.ShellInitSettings.FileOptions) + sizeof(CHAR16); + } + FileStringPath = AllocateZeroPool(NewSize); + StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName); + if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) { + StrCat (FileStringPath, L" "); + StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions); + } + Status = RunCommand(FileStringPath); + FreePool(FileStringPath); + return (Status); + + } + + // + // for shell level 0 we do no scripts + // Without the Startup bit overriding we allow for nostartup to prevent scripts + // + if ( (PcdGet8(PcdShellSupportLevel) < 1) + || (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup) + ){ + return (EFI_SUCCESS); + } + + // + // print out our warning and see if they press a key + // + for ( Status = EFI_UNSUPPORTED, Delay = (ShellInfoObject.ShellInitSettings.Delay * 10) + ; Delay > 0 && EFI_ERROR(Status) + ; Delay-- + ){ + ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay/10); + gBS->Stall (100000); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle); + + // + // ESC was pressed + // + if (Status == EFI_SUCCESS && Key.UnicodeChar == 0 && Key.ScanCode == SCAN_ESC) { + return (EFI_SUCCESS); + } + + NamePath = FileDevicePath (NULL, L"startup.nsh"); + // + // Try the first location + // + NewPath = AppendDevicePathNode (ImagePath, NamePath); + Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + // + // Try the second location + // + FreePool(NewPath); + NewPath = AppendDevicePathNode (FilePath , NamePath); + Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0); + } + + // + // If we got a file, run it + // + if (!EFI_ERROR(Status)) { + Status = RunScriptFileHandle (FileHandle, L"startup.nsh"); + ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle); + } else { + // + // we return success since we dont need to have a startup script + // + Status = EFI_SUCCESS; + ASSERT(FileHandle == NULL); + } + + FreePool(NamePath); + FreePool(NewPath); + + return (Status); +} + +/** + Function to perform the shell prompt looping. It will do a single prompt, + dispatch the result, and then return. It is expected that the caller will + call this function in a loop many times. + + @retval EFI_SUCCESS + @retval RETURN_ABORTED +**/ +EFI_STATUS +EFIAPI +DoShellPrompt ( + VOID + ) +{ + UINTN Column; + UINTN Row; + CHAR16 *CmdLine; + CONST CHAR16 *CurDir; + UINTN BufferSize; + EFI_STATUS Status; + + CurDir = NULL; + + // + // Get screen setting to decide size of the command line buffer + // + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Column, &Row); + BufferSize = Column * Row * sizeof (CHAR16); + CmdLine = AllocateZeroPool (BufferSize); + if (CmdLine == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd"); + + // + // Prompt for input + // + gST->ConOut->SetCursorPosition (gST->ConOut, 0, gST->ConOut->Mode->CursorRow); + + if (CurDir != NULL && StrLen(CurDir) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle); + } + + // + // Read a line from the console + // + Status = ShellInfoObject.NewEfiShellProtocol->ReadFile(ShellInfoObject.NewShellParametersProtocol->StdIn, &BufferSize, CmdLine); + + // + // Null terminate the string and parse it + // + if (!EFI_ERROR (Status)) { + CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL; + Status = RunCommand(CmdLine); + } + + // + // Done with this command + // + FreePool (CmdLine); + return Status; +} + +/** + Add a buffer to the Buffer To Free List for safely returning buffers to other + places without risking letting them modify internal shell information. + + @param Buffer Something to pass to FreePool when the shell is exiting. +**/ +VOID* +EFIAPI +AddBufferToFreeList( + VOID *Buffer + ) +{ + BUFFER_LIST *BufferListEntry; + + if (Buffer == NULL) { + return (NULL); + } + + BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST)); + ASSERT(BufferListEntry != NULL); + BufferListEntry->Buffer = Buffer; + InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link); + return (Buffer); +} + +/** + Add a buffer to the Line History List + + @param Buffer The line buffer to add. +**/ +VOID +EFIAPI +AddLineToCommandHistory( + IN CONST CHAR16 *Buffer + ) +{ + BUFFER_LIST *Node; + + Node = AllocateZeroPool(sizeof(BUFFER_LIST)); + ASSERT(Node != NULL); + Node->Buffer = AllocateZeroPool(StrSize(Buffer)); + ASSERT(Node->Buffer != NULL); + StrCpy(Node->Buffer, Buffer); + + InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link); +} + +/** + Checks if a string is an alias for another command. If yes, then it replaces the alias name + with the correct command name. + + @param[in,out] CommandString Upon entry the potential alias. Upon return the + command name if it was an alias. If it was not + an alias it will be unchanged. This function may + change the buffer to fit the command name. + + @retval EFI_SUCCESS The name was changed. + @retval EFI_SUCCESS The name was not an alias. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +ShellConvertAlias( + IN OUT CHAR16 **CommandString + ) +{ + CONST CHAR16 *NewString; + + NewString = ShellInfoObject.NewEfiShellProtocol->GetAlias(*CommandString, NULL); + if (NewString == NULL) { + return (EFI_SUCCESS); + } + FreePool(*CommandString); + *CommandString = AllocatePool(StrSize(NewString)); + if (*CommandString == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + StrCpy(*CommandString, NewString); + return (EFI_SUCCESS); +} + +/** + Function allocates a new command line and replaces all instances of environment + variable names that are correctly preset to their values. + + If the return value is not NULL the memory must be caller freed. + + @param[in] OriginalCommandLine The original command line + + @retval NULL An error ocurred. + @return The new command line with no environment variables present. +**/ +CHAR16* +EFIAPI +ShellConvertVariables ( + IN CONST CHAR16 *OriginalCommandLine + ) +{ + CONST CHAR16 *MasterEnvList; + UINTN NewSize; + CHAR16 *NewCommandLine1; + CHAR16 *NewCommandLine2; + CHAR16 *Temp; + UINTN ItemSize; + CHAR16 *ItemTemp; + SCRIPT_FILE *CurrentScriptFile; + ALIAS_LIST *AliasListNode; + + ASSERT(OriginalCommandLine != NULL); + + ItemSize = 0; + NewSize = StrSize(OriginalCommandLine); + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + Temp = NULL; + + ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ? + + // + // calculate the size required for the post-conversion string... + // + if (CurrentScriptFile != NULL) { + for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList) + ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ){ + for (Temp = StrStr(OriginalCommandLine, AliasListNode->Alias) + ; Temp != NULL + ; Temp = StrStr(Temp+1, AliasListNode->Alias) + ){ + // + // we need a preceeding and if there is space no ^ preceeding (if no space ignore) + // + if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) { + NewSize += StrSize(AliasListNode->CommandString); + } + } + } + } + + for (MasterEnvList = EfiShellGetEnv(NULL) + ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL + ; MasterEnvList += StrLen(MasterEnvList) + 1 + ){ + if (StrSize(MasterEnvList) > ItemSize) { + ItemSize = StrSize(MasterEnvList); + } + for (Temp = StrStr(OriginalCommandLine, MasterEnvList) + ; Temp != NULL + ; Temp = StrStr(Temp+1, MasterEnvList) + ){ + // + // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore) + // + if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' && + ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) { + NewSize+=StrSize(EfiShellGetEnv(MasterEnvList)); + } + } + } + + // + // Quick out if none were found... + // + if (NewSize == StrSize(OriginalCommandLine)) { + ASSERT(Temp == NULL); + Temp = StrnCatGrow(&Temp, NULL, OriginalCommandLine, 0); + return (Temp); + } + + // + // now do the replacements... + // + NewCommandLine1 = AllocateZeroPool(NewSize); + NewCommandLine2 = AllocateZeroPool(NewSize); + ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16))); + StrCpy(NewCommandLine1, OriginalCommandLine); + for (MasterEnvList = EfiShellGetEnv(NULL) + ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL + ; MasterEnvList += StrLen(MasterEnvList) + 1 + ){ + StrCpy(ItemTemp, L"%"); + StrCat(ItemTemp, MasterEnvList); + StrCat(ItemTemp, L"%"); + ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE); + StrCpy(NewCommandLine1, NewCommandLine2); + } + if (CurrentScriptFile != NULL) { + for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList) + ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link) + ){ + ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE); + StrCpy(NewCommandLine1, NewCommandLine2); + } + } + + FreePool(NewCommandLine2); + FreePool(ItemTemp); + + return (NewCommandLine1); +} + +/** + Internal function to run a command line with pipe usage. + + @param[in] CmdLine The pointer to the command line. + @param[in] StdIn The pointer to the Standard input. + @param[in] StdOut The pointer to the Standard output. + + @retval EFI_SUCCESS The split command is executed successfully. + @retval other Some error occurs when executing the split command. +**/ +EFI_STATUS +EFIAPI +RunSplitCommand( + IN CONST CHAR16 *CmdLine, + IN SHELL_FILE_HANDLE *StdIn, + IN SHELL_FILE_HANDLE *StdOut + ) +{ + EFI_STATUS Status; + CHAR16 *NextCommandLine; + CHAR16 *OurCommandLine; + UINTN Size1; + UINTN Size2; + SPLIT_LIST *Split; + SHELL_FILE_HANDLE *TempFileHandle; + BOOLEAN Unicode; + + ASSERT(StdOut == NULL); + + ASSERT(StrStr(CmdLine, L"|") != NULL); + + Status = EFI_SUCCESS; + NextCommandLine = NULL; + OurCommandLine = NULL; + Size1 = 0; + Size2 = 0; + + NextCommandLine = StrnCatGrow(&NextCommandLine, &Size1, StrStr(CmdLine, L"|")+1, 0); + OurCommandLine = StrnCatGrow(&OurCommandLine , &Size2, CmdLine , StrStr(CmdLine, L"|") - CmdLine); + if (NextCommandLine[0] != CHAR_NULL && + NextCommandLine[0] == L'a' && + NextCommandLine[1] == L' ' + ){ + CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0])); + Unicode = FALSE; + } else { + Unicode = TRUE; + } + + + // + // make a SPLIT_LIST item and add to list + // + Split = AllocateZeroPool(sizeof(SPLIT_LIST)); + ASSERT(Split != NULL); + Split->SplitStdIn = StdIn; + Split->SplitStdOut = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL); + ASSERT(Split->SplitStdOut != NULL); + InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link); + + ASSERT(StrStr(OurCommandLine, L"|") == NULL); + Status = RunCommand(OurCommandLine); + + // + // move the output from the first to the in to the second. + // + TempFileHandle = Split->SplitStdOut; + if (Split->SplitStdIn == StdIn) { + Split->SplitStdOut = NULL; + } else { + Split->SplitStdOut = Split->SplitStdIn; + } + Split->SplitStdIn = TempFileHandle; + ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0); + + if (!EFI_ERROR(Status)) { + Status = RunCommand(NextCommandLine); + } + + // + // remove the top level from the ScriptList + // + ASSERT((SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link) == Split); + RemoveEntryList(&Split->Link); + + // + // Note that the original StdIn is now the StdOut... + // + if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) { + ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut)); + } + if (Split->SplitStdIn != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn)); + } + + FreePool(Split); + FreePool(NextCommandLine); + FreePool(OurCommandLine); + + 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 + ) +{ + EFI_STATUS Status; + CHAR16 *CommandName; + SHELL_STATUS ShellStatus; + UINTN Argc; + CHAR16 **Argv; + BOOLEAN LastError; + CHAR16 LeString[11]; + CHAR16 *PostAliasCmdLine; + UINTN PostAliasSize; + CHAR16 *PostVariableCmdLine; + CHAR16 *CommandWithPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + CONST CHAR16 *TempLocation; + CONST CHAR16 *TempLocation2; + SHELL_FILE_HANDLE OriginalStdIn; + SHELL_FILE_HANDLE OriginalStdOut; + SHELL_FILE_HANDLE OriginalStdErr; + CHAR16 *TempLocation3; + UINTN Count; + UINTN Count2; + CHAR16 *CleanOriginal; + SPLIT_LIST *Split; + + ASSERT(CmdLine != NULL); + if (StrLen(CmdLine) == 0) { + return (EFI_SUCCESS); + } + + CommandName = NULL; + PostVariableCmdLine = NULL; + PostAliasCmdLine = NULL; + CommandWithPath = NULL; + DevPath = NULL; + Status = EFI_SUCCESS; + CleanOriginal = NULL; + Split = NULL; + + CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0); + while (CleanOriginal[StrLen(CleanOriginal)-1] == L' ') { + CleanOriginal[StrLen(CleanOriginal)-1] = CHAR_NULL; + } + while (CleanOriginal[0] == L' ') { + CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0])); + } + + CommandName = NULL; + if (StrStr(CleanOriginal, L" ") == NULL){ + StrnCatGrow(&CommandName, NULL, CleanOriginal, 0); + } else { + StrnCatGrow(&CommandName, NULL, CleanOriginal, StrStr(CleanOriginal, L" ") - CleanOriginal); + } + + ASSERT(PostAliasCmdLine == NULL); + if (!ShellCommandIsCommandOnList(CommandName)) { + // + // Convert via alias + // + Status = ShellConvertAlias(&CommandName); + PostAliasSize = 0; + PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, CommandName, 0); + PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, StrStr(CleanOriginal, L" "), 0); + ASSERT_EFI_ERROR(Status); + } else { + PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, NULL, CleanOriginal, 0); + } + + if (CleanOriginal != NULL) { + FreePool(CleanOriginal); + CleanOriginal = NULL; + } + + if (CommandName != NULL) { + FreePool(CommandName); + CommandName = NULL; + } + + PostVariableCmdLine = ShellConvertVariables(PostAliasCmdLine); + + // + // we can now free the modified by alias command line + // + if (PostAliasCmdLine != NULL) { + FreePool(PostAliasCmdLine); + PostAliasCmdLine = NULL; + } + + while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') { + PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL; + } + while (PostVariableCmdLine[0] == L' ') { + CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0])); + } + + // + // We dont do normal processing with a split command line (output from one command input to another) + // + TempLocation3 = NULL; + if (StrStr(PostVariableCmdLine, L"|") != NULL) { + for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) { + if (*TempLocation3 == L'^' && *(TempLocation3+1) == L'|') { + TempLocation3++; + } else if (*TempLocation3 == L'|') { + break; + } + } + } + if (TempLocation3 != NULL && *TempLocation3 != CHAR_NULL) { + // + // are we in an existing split??? + // + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + } + + if (Split == NULL) { + Status = RunSplitCommand(PostVariableCmdLine, NULL, NULL); + } else { + Status = RunSplitCommand(PostVariableCmdLine, Split->SplitStdIn, Split->SplitStdOut); + } + } else { + + // + // If this is a mapped drive change handle that... + // + if (PostVariableCmdLine[(StrLen(PostVariableCmdLine)-1)] == L':' && StrStr(PostVariableCmdLine, L" ") == NULL) { + Status = ShellInfoObject.NewEfiShellProtocol->SetCurDir(NULL, PostVariableCmdLine); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_MAPPING), ShellInfoObject.HiiHandle, PostVariableCmdLine); + } + FreePool(PostVariableCmdLine); + return (Status); + } + + ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file... + /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files... + + + + Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle); + } else { + // + // remove the < and/or > from the command line now + // + for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) { + if (*TempLocation3 == L'^') { + if (*(TempLocation3+1) == L'<' || *(TempLocation3+1) == L'>') { + CopyMem(TempLocation3, TempLocation3+1, StrSize(TempLocation3) - sizeof(TempLocation3[0])); + } + } else if (*TempLocation3 == L'>') { + *TempLocation3 = CHAR_NULL; + } else if ((*TempLocation3 == L'1' || *TempLocation3 == L'2')&&(*(TempLocation3+1) == L'>')) { + *TempLocation3 = CHAR_NULL; + } + } + + while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') { + PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL; + } + while (PostVariableCmdLine[0] == L' ') { + CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0])); + } + + // + // get the argc and argv updated for internal commands + // + Status = UpdateArgcArgv(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &Argv, &Argc); + ASSERT_EFI_ERROR(Status); + + for (Count = 0 ; Count < ShellInfoObject.NewShellParametersProtocol->Argc ; Count++) { + if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[Count], L"-?") == ShellInfoObject.NewShellParametersProtocol->Argv[Count] + || (ShellInfoObject.NewShellParametersProtocol->Argv[0][0] == L'?' && ShellInfoObject.NewShellParametersProtocol->Argv[0][1] == CHAR_NULL) + ) { + // + // We need to redo the arguments since a parameter was -? + // move them all down 1 to the end, then up one then replace the first with help + // + FreePool(ShellInfoObject.NewShellParametersProtocol->Argv[Count]); + ShellInfoObject.NewShellParametersProtocol->Argv[Count] = NULL; + for (Count2 = Count ; (Count2 + 1) < ShellInfoObject.NewShellParametersProtocol->Argc ; Count2++) { + ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2+1]; + } + ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = NULL; + for (Count2 = ShellInfoObject.NewShellParametersProtocol->Argc -1 ; Count2 > 0 ; Count2--) { + ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2-1]; + } + ShellInfoObject.NewShellParametersProtocol->Argv[0] = NULL; + ShellInfoObject.NewShellParametersProtocol->Argv[0] = StrnCatGrow(&ShellInfoObject.NewShellParametersProtocol->Argv[0], NULL, L"help", 0); + break; + } + } + + // + // command or file? + // + if (ShellCommandIsCommandOnList(ShellInfoObject.NewShellParametersProtocol->Argv[0])) { + // + // Run the command (which was converted if it was an alias) + // + if (!EFI_ERROR(Status)) { + Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError); + ASSERT_EFI_ERROR(Status); + UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%08x", ShellStatus); + DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE);); + if (LastError) { + InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE); + } + // + // Pass thru the exitcode from the app. + // + if (ShellCommandGetExit()) { + Status = ShellStatus; + } else if (ShellStatus != 0 && IsScriptOnlyCommand(ShellInfoObject.NewShellParametersProtocol->Argv[0])) { + Status = EFI_ABORTED; + } + } + } else { + // + // run an external file (or script) + // + if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[0], L":") != NULL) { + ASSERT (CommandWithPath == NULL); + if (ShellIsFile(ShellInfoObject.NewShellParametersProtocol->Argv[0]) == EFI_SUCCESS) { + CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0); + } + } + if (CommandWithPath == NULL) { + CommandWithPath = ShellFindFilePathEx(ShellInfoObject.NewShellParametersProtocol->Argv[0], mExecutableExtensions); + } + if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]); + } else { + // + // Check if it's a NSH (script) file. + // + TempLocation = CommandWithPath+StrLen(CommandWithPath)-4; + TempLocation2 = mScriptExtension; + if ((StrLen(CommandWithPath) > 4) && (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0)) { + Status = RunScriptFile (CommandWithPath); + } else { + DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath); + ASSERT(DevPath != NULL); + Status = InternalShellExecuteDevicePath( + &gImageHandle, + DevPath, + PostVariableCmdLine, + NULL, + NULL + ); + } + } + } + CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0); + + RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc); + + RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr); + } + if (CommandName != NULL) { + if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) { + // + // if this is NOT a scipt only command return success so the script won't quit. + // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...) + // + Status = EFI_SUCCESS; + } + } + } + + SHELL_FREE_NON_NULL(CommandName); + SHELL_FREE_NON_NULL(CommandWithPath); + SHELL_FREE_NON_NULL(PostVariableCmdLine); + SHELL_FREE_NON_NULL(DevPath); + + return (Status); +} + +STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002}; +/** + Function determins if the CommandName COULD be a valid command. It does not determine whether + this is a valid command. It only checks for invalid characters. + + @param[in] CommandName The name to check + + @retval TRUE CommandName could be a command name + @retval FALSE CommandName could not be a valid command name +**/ +BOOLEAN +EFIAPI +IsValidCommandName( + IN CONST CHAR16 *CommandName + ) +{ + UINTN Count; + if (CommandName == NULL) { + ASSERT(FALSE); + return (FALSE); + } + for ( Count = 0 + ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0]) + ; Count++ + ){ + if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) { + return (FALSE); + } + } + return (TRUE); +} + +/** + Function to process a NSH script file via SHELL_FILE_HANDLE. + + @param[in] Handle The handle to the already opened file. + @param[in] Name The name of the script file. + + @retval EFI_SUCCESS the script completed sucessfully +**/ +EFI_STATUS +EFIAPI +RunScriptFileHandle ( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *NewScriptFile; + UINTN LoopVar; + CHAR16 *CommandLine; + CHAR16 *CommandLine2; + CHAR16 *CommandLine3; + SCRIPT_COMMAND_LIST *LastCommand; + BOOLEAN Ascii; + BOOLEAN PreScriptEchoState; + CONST CHAR16 *CurDir; + UINTN LineCount; + + ASSERT(!ShellCommandGetScriptExit()); + + PreScriptEchoState = ShellCommandGetEchoState(); + + NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE)); + ASSERT(NewScriptFile != NULL); + + // + // Set up the name + // + ASSERT(NewScriptFile->ScriptName == NULL); + NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0); + + // + // Save the parameters (used to replace %0 to %9 later on) + // + NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc; + if (NewScriptFile->Argc != 0) { + NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*)); + ASSERT(NewScriptFile->Argv != NULL); + for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) { + ASSERT(NewScriptFile->Argv[LoopVar] == NULL); + NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0); + } + } else { + NewScriptFile->Argv = NULL; + } + + InitializeListHead(&NewScriptFile->CommandList); + InitializeListHead(&NewScriptFile->SubstList); + + // + // Now build the list of all script commands. + // + LineCount = 0; + while(!ShellFileHandleEof(Handle)) { + CommandLine = ShellFileHandleReturnLine(Handle, &Ascii); + LineCount++; + if (CommandLine == NULL || StrLen(CommandLine) == 0) { + continue; + } + NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST)); + ASSERT(NewScriptFile->CurrentCommand != NULL); + + NewScriptFile->CurrentCommand->Cl = CommandLine; + NewScriptFile->CurrentCommand->Data = NULL; + NewScriptFile->CurrentCommand->Line = LineCount; + + InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + } + + // + // Add this as the topmost script file + // + ShellCommandSetNewScript (NewScriptFile); + + // + // Now enumerate through the commands and run each one. + // + CommandLine = AllocatePool(PcdGet16(PcdShellPrintBufferSize)); + CommandLine2 = AllocatePool(PcdGet16(PcdShellPrintBufferSize)); + + for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList) + ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link) + ; // conditional increment in the body of the loop + ){ + StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl); + + // + // NULL out comments + // + for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) { + if (*CommandLine3 == L'^') { + if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') { + CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0])); + } + } else if (*CommandLine3 == L'#') { + *CommandLine3 = CHAR_NULL; + } + } + + if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) { + // + // Due to variability in starting the find and replace action we need to have both buffers the same. + // + StrCpy(CommandLine, CommandLine2); + + // + // Remove the %0 to %9 from the command line (if we have some arguments) + // + if (NewScriptFile->Argv != NULL) { + switch (NewScriptFile->Argc) { + default: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 9: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 8: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 7: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 6: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 5: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 4: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 3: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 2: + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + case 1: + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE); + ASSERT_EFI_ERROR(Status); + break; + case 0: + break; + } + } + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE); + Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE); + + StrCpy(CommandLine2, CommandLine); + + LastCommand = NewScriptFile->CurrentCommand; + + for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++); + + if (CommandLine3[0] == L':' ) { + // + // This line is a goto target / label + // + } else { + if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) { + if (ShellCommandGetEchoState()) { + CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd"); + if (CurDir != NULL && StrLen(CurDir) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle); + } + ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2); + } + Status = RunCommand(CommandLine3); + } + + if (ShellCommandGetScriptExit()) { + ShellCommandRegisterExit(FALSE); + Status = EFI_SUCCESS; + break; + } + if (EFI_ERROR(Status)) { + break; + } + if (ShellCommandGetExit()) { + break; + } + } + // + // If that commend did not update the CurrentCommand then we need to advance it... + // + if (LastCommand == NewScriptFile->CurrentCommand) { + NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) { + NewScriptFile->CurrentCommand->Reset = TRUE; + } + } + } else { + NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link); + if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) { + NewScriptFile->CurrentCommand->Reset = TRUE; + } + } + } + + ShellCommandSetEchoState(PreScriptEchoState); + + FreePool(CommandLine); + FreePool(CommandLine2); + ShellCommandSetNewScript (NULL); + return (EFI_SUCCESS); +} + +/** + Function to process a NSH script file. + + @param[in] ScriptPath Pointer to the script file name (including file system path). + + @retval EFI_SUCCESS the script completed sucessfully +**/ +EFI_STATUS +EFIAPI +RunScriptFile ( + IN CONST CHAR16 *ScriptPath + ) +{ + EFI_STATUS Status; + SHELL_FILE_HANDLE FileHandle; + + if (ShellIsFile(ScriptPath) != EFI_SUCCESS) { + return (EFI_INVALID_PARAMETER); + } + + Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + return (Status); + } + + Status = RunScriptFileHandle(FileHandle, ScriptPath); + + ShellCloseFile(&FileHandle); + + return (Status); +} diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h new file mode 100644 index 0000000000..6f165e5515 --- /dev/null +++ b/ShellPkg/Application/Shell/Shell.h @@ -0,0 +1,292 @@ +/** @file + function definitions for internal to shell functions. + + Copyright (c) 2009 - 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_INTERNAL_HEADER_ +#define _SHELL_INTERNAL_HEADER_ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ShellParametersProtocol.h" +#include "ShellProtocol.h" +#include "ShellEnvVar.h" +#include "ConsoleLogger.h" +#include "ShellManParser.h" + +typedef struct { + LIST_ENTRY Link; ///< Standard linked list handler. + SHELL_FILE_HANDLE *SplitStdOut; ///< ConsoleOut for use in the split. + SHELL_FILE_HANDLE *SplitStdIn; ///< ConsoleIn for use in the split. +} SPLIT_LIST; + +typedef struct { + UINT32 Startup:1; ///< Was "-startup" found on command line. + UINT32 NoStartup:1; ///< Was "-nostartup" found on command line. + UINT32 NoConsoleOut:1; ///< Was "-noconsoleout" found on command line. + UINT32 NoConsoleIn:1; ///< Was "-noconsolein" found on command line. + UINT32 NoInterrupt:1; ///< Was "-nointerrupt" found on command line. + UINT32 NoMap:1; ///< Was "-nomap" found on command line. + UINT32 NoVersion:1; ///< Was "-noversion" found on command line. + UINT32 Delay:1; ///< Was "-delay[:n] found on command line + UINT32 Reserved:8; ///< Extra bits +} SHELL_BITS; + +typedef union { + SHELL_BITS Bits; + UINT16 AllBits; +} SHELL_BIT_UNION; + +typedef struct { + SHELL_BIT_UNION BitUnion; + UINTN Delay; ///< Seconds of delay default:5. + CHAR16 *FileName; ///< Filename to run upon successful initialization. + CHAR16 *FileOptions; ///< Options to pass to FileName. +} SHELL_INIT_SETTINGS; + +typedef struct { + BUFFER_LIST CommandHistory; + UINTN VisibleRowNumber; + UINTN OriginalVisibleRowNumber; + BOOLEAN InsertMode; ///< Is the current typing mode insert (FALSE = overwrite). +} SHELL_VIEWING_SETTINGS; + +typedef struct { + EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParametersProtocol; + EFI_SHELL_PROTOCOL *NewEfiShellProtocol; + BOOLEAN PageBreakEnabled; + BOOLEAN RootShellInstance; + SHELL_INIT_SETTINGS ShellInitSettings; + BUFFER_LIST BufferToFreeList; ///< List of buffers that were returned to the user to free. + SHELL_VIEWING_SETTINGS ViewingSettings; + EFI_HII_HANDLE HiiHandle; ///< Handle from HiiLib. + UINTN LogScreenCount; ///< How many screens of log information to save. + EFI_EVENT UserBreakTimer; ///< Timer event for polling for CTRL-C. + EFI_DEVICE_PATH_PROTOCOL *ImageDevPath; ///< DevicePath for ourselves. + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; ///< DevicePath for ourselves. + CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo; ///< Pointer for ConsoleInformation. + 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. +} SHELL_INFO; + +extern SHELL_INFO ShellInfoObject; + +/** + Sets all the alias' that were registered with the ShellCommandLib library. + + @retval EFI_SUCCESS all init commands were run sucessfully. +**/ +EFI_STATUS +EFIAPI +SetBuiltInAlias( + VOID + ); + +/** + This function will populate the 2 device path protocol parameters based on the + global gImageHandle. the DevPath will point to the device path for the handle that has + loaded image protocol installed on it. the FilePath will point to the device path + for the file that was loaded. + + @param[in,out] DevPath on a sucessful return the device path to the loaded image + @param[in,out] FilePath on a sucessful return the device path to the file + + @retval EFI_SUCCESS the 2 device paths were sucessfully returned. + @return other a error from gBS->HandleProtocol + + @sa HandleProtocol +**/ +EFI_STATUS +EFIAPI +GetDevicePathsForImageAndFile ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath, + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath + ); + +/** + Process all Uefi Shell 2.0 command line options. + + see Uefi Shell 2.0 section 3.2 for full details. + + the command line should resemble the following: + + shell.efi [ShellOpt-options] [options] [file-name [file-name-options]] + + ShellOpt options Options which control the initialization behavior of the shell. + These options are read from the EFI global variable "ShellOpt" + and are processed before options or file-name. + + options Options which control the initialization behavior of the shell. + + file-name The name of a UEFI shell application or script to be executed + after initialization is complete. By default, if file-name is + specified, then -nostartup is implied. Scripts are not supported + by level 0. + + file-nameoptions The command-line options that are passed to file-name when it + is invoked. + + This will initialize the ShellInitSettings global variable. + + @retval EFI_SUCCESS the variable is initialized. +**/ +EFI_STATUS +EFIAPI +ProcessCommandLine( + VOID + ); + +/** + Handles all interaction with the default startup script. + + this will check that the correct command line parameters were passed, handle the delay, and then start running the script. + + @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. + + @retval EFI_SUCCESS The variable is initialized. +**/ +EFI_STATUS +EFIAPI +DoStartupScript( + IN EFI_DEVICE_PATH_PROTOCOL *ImagePath, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ); + +/** + Function to perform the shell prompt looping. It will do a single prompt, + dispatch the result, and then return. It is expected that the caller will + call this function in a loop many times. + + @retval EFI_SUCCESS + @retval RETURN_ABORTED +**/ +EFI_STATUS +EFIAPI +DoShellPrompt ( + VOID + ); + +/** + Add a buffer to the Buffer To Free List for safely returning buffers to other + places without risking letting them modify internal shell information. + + @param Buffer Something to pass to FreePool when the shell is exiting. +**/ +VOID* +EFIAPI +AddBufferToFreeList( + VOID *Buffer + ); + +/** + Add a buffer to the Command History List. + + @param Buffer[in] The line buffer to add. +**/ +VOID +EFIAPI +AddLineToCommandHistory( + IN CONST CHAR16 *Buffer + ); + +/** + 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 + ); + +/** + Function determins if the CommandName COULD be a valid command. It does not determine whether + this is a valid command. It only checks for invalid characters. + + @param[in] CommandName The name to check + + @retval TRUE CommandName could be a command name + @retval FALSE CommandName could not be a valid command name +**/ +BOOLEAN +EFIAPI +IsValidCommandName( + IN CONST CHAR16 *CommandName + ); + +/** + Function to process a NSH script file via SHELL_FILE_HANDLE. + + @param[in] Handle The handle to the already opened file. + @param[in] Name The name of the script file. + + @retval EFI_SUCCESS the script completed sucessfully +**/ +EFI_STATUS +EFIAPI +RunScriptFileHandle ( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Name + ); + +/** + Function to process a NSH script file. + + @param[in] ScriptPath Pointer to the script file name (including file system path). + + @retval EFI_SUCCESS the script completed sucessfully +**/ +EFI_STATUS +EFIAPI +RunScriptFile ( + IN CONST CHAR16 *ScriptPath + ); + + +#endif //_SHELL_INTERNAL_HEADER_ + diff --git a/ShellPkg/Application/Shell/Shell.inf b/ShellPkg/Application/Shell/Shell.inf new file mode 100644 index 0000000000..c50e5607d8 --- /dev/null +++ b/ShellPkg/Application/Shell/Shell.inf @@ -0,0 +1,105 @@ +## @file +# This is the shell application +# +# Copyright (c) 2009-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. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = Shell + FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Shell.c + Shell.h + ShellParametersProtocol.c + ShellParametersProtocol.h + ShellProtocol.c + ShellProtocol.h + FileHandleWrappers.c + FileHandleWrappers.h + FileHandleInternal.h + ShellEnvVar.c + ShellEnvVar.h + ShellManParser.c + ShellManParser.h + Shell.uni + ConsoleLogger.c + ConsoleLogger.h + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + BaseLib + UefiApplicationEntryPoint + UefiLib + DebugLib + MemoryAllocationLib + ShellCommandLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + DevicePathLib + BaseMemoryLib + PcdLib + FileHandleLib + PrintLib + HiiLib + SortLib + HandleParsingLib + +[Guids] + gShellVariableGuid # ALWAYS_CONSUMED + gShellMapGuid # ALWAYS_CONSUMED + gShellAliasGuid # ALWAYS_CONSUMED + +[Protocols] + gEfiShellProtocolGuid # ALWAYS_PRODUCED + gEfiShellParametersProtocolGuid # ALWAYS_PRODUCED + gEfiShellEnvironment2Guid # SOMETIMES_PRODUCED + gEfiShellInterfaceGuid # SOMETIMES_PRODUCED + + gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextInputExProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextOutProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED + gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED + gEfiComponentName2ProtocolGuid # ALWAYS_CONSUMED + gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellSupportOldProtocols # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellRequireHiiPlatform # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellSupportFrameworkHii # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellPageBreakDefault # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellInsertModeDefault # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellScreenLogCount # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellMapNameLength # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellForceConsole # ALWAYS_CONSUMED + diff --git a/ShellPkg/Application/Shell/Shell.uni b/ShellPkg/Application/Shell/Shell.uni new file mode 100644 index 0000000000..82a87aeb3f Binary files /dev/null and b/ShellPkg/Application/Shell/Shell.uni differ diff --git a/ShellPkg/Application/Shell/ShellEnvVar.c b/ShellPkg/Application/Shell/ShellEnvVar.c new file mode 100644 index 0000000000..ff353c4e2a --- /dev/null +++ b/ShellPkg/Application/Shell/ShellEnvVar.c @@ -0,0 +1,326 @@ +/** @file + function declarations for shell environment functions. + + Copyright (c) 2009 - 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 +#include +#include +#include +#include + +#include "ShellEnvVar.h" + + +/** + Reports whether an environment variable is Volatile or Non-Volatile. + + @param EnvVarName The name of the environment variable in question + + @retval TRUE This environment variable is Volatile + @retval FALSE This environment variable is NON-Volatile +**/ +BOOLEAN +EFIAPI +IsVolatileEnv ( + IN CONST CHAR16 *EnvVarName + ) +{ + EFI_STATUS Status; + UINTN Size; + VOID *Buffer; + UINT32 Attribs; + + Size = 0; + Buffer = NULL; + + // + // get the variable + // + Status = gRT->GetVariable((CHAR16*)EnvVarName, + &gShellVariableGuid, + &Attribs, + &Size, + Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocatePool(Size); + ASSERT(Buffer != NULL); + Status = gRT->GetVariable((CHAR16*)EnvVarName, + &gShellVariableGuid, + &Attribs, + &Size, + Buffer); + FreePool(Buffer); + } + // + // not found means volatile + // + if (Status == EFI_NOT_FOUND) { + return (TRUE); + } + ASSERT_EFI_ERROR(Status); + + // + // check for the Non Volatile bit + // + if ((Attribs & EFI_VARIABLE_NON_VOLATILE) == EFI_VARIABLE_NON_VOLATILE) { + return (FALSE); + } + + // + // everything else is volatile + // + return (TRUE); +} + +/** + free function for ENV_VAR_LIST objects. + + @param[in] List The pointer to pointer to list. +**/ +VOID +EFIAPI +FreeEnvironmentVariableList( + IN LIST_ENTRY *List + ) +{ + ENV_VAR_LIST *Node; + + ASSERT (List != NULL); + if (List == NULL) { + return; + } + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(List) + ; IsListEmpty(List) + ; Node = (ENV_VAR_LIST*)GetFirstNode(List) + ){ + ASSERT(Node != NULL); + RemoveEntryList(&Node->Link); + if (Node->Key != NULL) { + FreePool(Node->Key); + } + if (Node->Val != NULL) { + FreePool(Node->Val); + } + FreePool(Node); + } +} + +/** + Creates a list of all Shell-Guid-based environment variables. + + @param[in,out] ListHead The pointer to pointer to LIST ENTRY object for + storing this list. + + @retval EFI_SUCCESS the list was created sucessfully. +**/ +EFI_STATUS +EFIAPI +GetEnvironmentVariableList( + IN OUT LIST_ENTRY *ListHead + ) +{ + CHAR16 *VariableName; + UINTN NameSize; + UINT64 MaxStorSize; + UINT64 RemStorSize; + UINT64 MaxVarSize; + EFI_STATUS Status; + EFI_GUID Guid; + UINTN ValSize; + ENV_VAR_LIST *VarList; + + ASSERT(ListHead != NULL); + + Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize); + ASSERT_EFI_ERROR(Status); + + NameSize = (UINTN)MaxVarSize; + VariableName = AllocatePool(NameSize); + StrCpy(VariableName, L""); + + while (TRUE) { + NameSize = (UINTN)MaxVarSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + if (Status == EFI_NOT_FOUND){ + Status = EFI_SUCCESS; + break; + } + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + break; + } + if (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); + Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(VariableName, &VarList->Atts, &ValSize, VarList->Val); + } + ASSERT_EFI_ERROR(Status); + VarList->Key = AllocatePool(StrSize(VariableName)); + ASSERT(VarList->Key != NULL); + StrCpy(VarList->Key, VariableName); + + InsertTailList(ListHead, &VarList->Link); + } // compare guid + } // while + FreePool(VariableName); + + if (EFI_ERROR(Status)) { + FreeEnvironmentVariableList(ListHead); + } + + return (Status); +} + +/** + Sets a list of all Shell-Guid-based environment variables. this will + also eliminate all existing shell environment variables (even if they + are not on the list). + + This function will also deallocate the memory from List. + + @param[in] ListHead The pointer to LIST_ENTRY from + GetShellEnvVarList(). + + @retval EFI_SUCCESS the list was Set sucessfully. +**/ +EFI_STATUS +EFIAPI +SetEnvironmentVariableList( + IN LIST_ENTRY *ListHead + ) +{ + ENV_VAR_LIST VarList; + ENV_VAR_LIST *Node; + EFI_STATUS Status; + UINTN Size; + + InitializeListHead(&VarList.Link); + + // + // Delete all the current environment variables + // + Status = GetEnvironmentVariableList(&VarList.Link); + ASSERT_EFI_ERROR(Status); + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&VarList.Link) + ; !IsNull(&VarList.Link, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&VarList.Link, &Node->Link) + ){ + if (Node->Key != NULL) { + Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Node->Key); + } + ASSERT_EFI_ERROR(Status); + } + + FreeEnvironmentVariableList(&VarList.Link); + + // + // set all the variables fron the list + // + for ( Node = (ENV_VAR_LIST*)GetFirstNode(ListHead) + ; !IsNull(ListHead, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(ListHead, &Node->Link) + ){ + Size = StrSize(Node->Val); + if (Node->Atts & EFI_VARIABLE_NON_VOLATILE) { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Node->Key, Size, Node->Val); + } else { + Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (Node->Key, Size, Node->Val); + } + ASSERT_EFI_ERROR(Status); + } + FreeEnvironmentVariableList(ListHead); + + return (Status); +} + +/** + sets a list of all Shell-Guid-based environment variables. + + @param Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + + @sa SetEnvironmentVariableList +**/ +EFI_STATUS +EFIAPI +SetEnvironmentVariables( + IN CONST CHAR16 **Environment + ) +{ + CONST CHAR16 *CurrentString; + UINTN CurrentCount; + ENV_VAR_LIST *VarList; + ENV_VAR_LIST *Node; + UINTN NewSize; + + VarList = NULL; + + if (Environment == NULL) { + return (EFI_INVALID_PARAMETER); + } + + // + // Build a list identical to the ones used for get/set list functions above + // + for ( CurrentCount = 0 + ; + ; CurrentCount++ + ){ + CurrentString = Environment[CurrentCount]; + if (CurrentString == NULL) { + break; + } + ASSERT(StrStr(CurrentString, L"=") != NULL); + Node = AllocatePool(sizeof(ENV_VAR_LIST)); + ASSERT(Node != NULL); + Node->Key = AllocateZeroPool((StrStr(CurrentString, L"=") - CurrentString + 1) * sizeof(CHAR16)); + ASSERT(Node->Key != NULL); + StrnCpy(Node->Key, CurrentString, StrStr(CurrentString, L"=") - CurrentString); + NewSize = StrSize(CurrentString); + NewSize -= StrLen(Node->Key) - 1; + Node->Val = AllocateZeroPool(NewSize); + ASSERT(Node->Val != NULL); + StrCpy(Node->Val, CurrentString + StrLen(Node->Key) + 1); + Node->Atts = EFI_VARIABLE_BOOTSERVICE_ACCESS; + + if (VarList == NULL) { + VarList = AllocateZeroPool(sizeof(ENV_VAR_LIST)); + ASSERT(VarList != NULL); + InitializeListHead(&VarList->Link); + } + InsertTailList(&VarList->Link, &Node->Link); + + } // for loop + + // + // set this new list as the set of all environment variables. + // this function also frees the memory and deletes all pre-existing + // shell-guid based environment variables. + // + return (SetEnvironmentVariableList(&VarList->Link)); +} diff --git a/ShellPkg/Application/Shell/ShellEnvVar.h b/ShellPkg/Application/Shell/ShellEnvVar.h new file mode 100644 index 0000000000..277895994a --- /dev/null +++ b/ShellPkg/Application/Shell/ShellEnvVar.h @@ -0,0 +1,210 @@ +/** @file + function definitions for shell environment functions. + + the following includes are required: +//#include +//#include + + + Copyright (c) 2009 - 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_ENVIRONMENT_VARIABLE_HEADER_ +#define _SHELL_ENVIRONMENT_VARIABLE_HEADER_ + +typedef struct { + LIST_ENTRY Link; + CHAR16 *Key; + CHAR16 *Val; + UINT32 Atts; +} ENV_VAR_LIST; + +/** + Reports whether an environment variable is Volatile or Non-Volatile + + This will use the Runtime Services call GetVariable to to search for the variable. + + @param EnvVarName The name of the environment variable in question + + @retval TRUE This environment variable is Volatile + @retval FALSE This environment variable is NON-Volatile +**/ +BOOLEAN +EFIAPI +IsVolatileEnv ( + IN CONST CHAR16 *EnvVarName + ); + +/** + Delete a Non-Violatile environment variable. + + This will use the Runtime Services call SetVariable to remove a non-violatile variable. + + @param EnvVarName The name of the environment variable in question + + @retval EFI_SUCCESS The variable was deleted sucessfully + @retval other An error ocurred + @sa SetVariable +**/ +#define SHELL_DELETE_ENVIRONMENT_VARIABLE(EnvVarName) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + 0, \ + 0, \ + NULL)) + +/** + Set a Non-Violatile environment variable. + + This will use the Runtime Services call SetVariable to set a non-violatile variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize UINTN size of Buffer + @param Buffer Pointer to value to set variable to + + @retval EFI_SUCCESS The variable was changed sucessfully + @retval other An error ocurred + @sa SetVariable +**/ +#define SHELL_SET_ENVIRONMENT_VARIABLE_NV(EnvVarName,BufferSize,Buffer) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, \ + BufferSize, \ + (VOID*)Buffer)) + +/** + Get an environment variable. + + This will use the Runtime Services call GetVariable to get a variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize Pointer to the UINTN size of Buffer + @param Buffer Pointer buffer to get variable value into + + @retval EFI_SUCCESS The variable's value was retrieved sucessfully + @retval other An error ocurred + @sa SetVariable +**/ +#define SHELL_GET_ENVIRONMENT_VARIABLE(EnvVarName,BufferSize,Buffer) \ + (gRT->GetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + 0, \ + BufferSize, \ + Buffer)) + +/** + Get an environment variable. + + This will use the Runtime Services call GetVariable to get a variable. + + @param EnvVarName The name of the environment variable in question + @param Atts Pointer to the UINT32 for attributes (or NULL) + @param BufferSize Pointer to the UINTN size of Buffer + @param Buffer Pointer buffer to get variable value into + + @retval EFI_SUCCESS The variable's value was retrieved sucessfully + @retval other An error ocurred + @sa SetVariable +**/ +#define SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(EnvVarName,Atts,BufferSize,Buffer) \ + (gRT->GetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + Atts, \ + BufferSize, \ + Buffer)) + +/** + Set a Violatile environment variable. + + This will use the Runtime Services call SetVariable to set a violatile variable. + + @param EnvVarName The name of the environment variable in question + @param BufferSize UINTN size of Buffer + @param Buffer Pointer to value to set variable to + + @retval EFI_SUCCESS The variable was changed sucessfully + @retval other An error ocurred + @sa SetVariable +**/ +#define SHELL_SET_ENVIRONMENT_VARIABLE_V(EnvVarName,BufferSize,Buffer) \ + (gRT->SetVariable((CHAR16*)EnvVarName, \ + &gShellVariableGuid, \ + EFI_VARIABLE_BOOTSERVICE_ACCESS, \ + BufferSize, \ + (VOID*)Buffer)) + +/** + Creates a list of all Shell-Guid-based environment variables. + + @param[in,out] List The pointer to pointer to LIST_ENTRY object for + storing this list. + + @retval EFI_SUCCESS the list was created sucessfully. +**/ +EFI_STATUS +EFIAPI +GetEnvironmentVariableList( + IN OUT LIST_ENTRY *List + ); + +/** + Sets a list of all Shell-Guid-based environment variables. this will + also eliminate all pre-existing shell environment variables (even if they + are not on the list). + + This function will also deallocate the memory from List. + + @param[in] List The pointer to LIST_ENTRY from + GetShellEnvVarList(). + + @retval EFI_SUCCESS The list was Set sucessfully. +**/ +EFI_STATUS +EFIAPI +SetEnvironmentVariableList( + IN LIST_ENTRY *List + ); + +/** + sets all Shell-Guid-based environment variables. this will + also eliminate all pre-existing shell environment variables (even if they + are not on the list). + + @param[in] Environment Points to a NULL-terminated array of environment + variables with the format 'x=y', where x is the + environment variable name and y is the value. + + @retval EFI_SUCCESS The command executed successfully. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Out of resources. + + @sa SetEnvironmentVariableList +**/ +EFI_STATUS +EFIAPI +SetEnvironmentVariables( + IN CONST CHAR16 **Environment + ); + +/** + free function for ENV_VAR_LIST objects. + + @param[in] List The pointer to pointer to list. +**/ +VOID +EFIAPI +FreeEnvironmentVariableList( + IN LIST_ENTRY *List + ); + +#endif //_SHELL_ENVIRONMENT_VARIABLE_HEADER_ + diff --git a/ShellPkg/Application/Shell/ShellManParser.c b/ShellPkg/Application/Shell/ShellManParser.c new file mode 100644 index 0000000000..fe9facb483 --- /dev/null +++ b/ShellPkg/Application/Shell/ShellManParser.c @@ -0,0 +1,615 @@ +/** @file + Provides interface to shell MAN file parser. + + Copyright (c) 2009 - 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 "Shell.h" + +/** + Verifies that the filename has .MAN on the end. + + allocates a new buffer and copies the name (appending .MAN if necessary) + + ASSERT if ManFileName is NULL + + @param[in] ManFileName original filename + + @return the new filename with .man as the extension. +**/ +CHAR16 * +EFIAPI +GetManFileName( + IN CONST CHAR16 *ManFileName + ) +{ + CHAR16 *Buffer; + ASSERT(ManFileName != NULL); + // + // Fix the file name + // + if (StrnCmp(ManFileName+StrLen(ManFileName)-4, L".man", 4)==0) { + Buffer = AllocateZeroPool(StrSize(ManFileName)); + StrCpy(Buffer, ManFileName); + } else { + Buffer = AllocateZeroPool(StrSize(ManFileName) + 4*sizeof(CHAR16)); + StrCpy(Buffer, ManFileName); + StrCat(Buffer, L".man"); + } + return (Buffer); +} + +/** + Search the path environment variable for possible locations and test for + which one contains a man file with the name specified. If a valid file is found + stop searching and return the (opened) SHELL_FILE_HANDLE for that file. + + @param[in] FileName Name of the file to find and open. + @param[out] Handle Pointer to the handle of the found file. The + value of this is undefined for return values + except EFI_SUCCESS. + + @retval EFI_SUCCESS The file was found. Handle is a valid SHELL_FILE_HANDLE + @retval EFI_INVALID_PARAMETER A parameter had an invalid value. + @retval EFI_NOT_FOUND The file was not found. +**/ +EFI_STATUS +EFIAPI +SearchPathForFile( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *Handle + ) +{ + CHAR16 *FullFileName; + EFI_STATUS Status; + + if ( FileName == NULL + || Handle == NULL + || StrLen(FileName) == 0 + ){ + return (EFI_INVALID_PARAMETER); + } + + FullFileName = ShellFindFilePath(FileName); + if (FullFileName == NULL) { + return (EFI_NOT_FOUND); + } + + // + // now open that file + // + Status = EfiShellOpenFileByName(FullFileName, Handle, EFI_FILE_MODE_READ); + FreePool(FullFileName); + + return (Status); +} + +/** + parses through Buffer (which is MAN file formatted) and returns the + detailed help for any sub section specified in the comma seperated list of + sections provided. If the end of the file or a .TH section is found then + return. + + Upon a sucessful return the caller is responsible to free the memory in *HelpText + + @param[in] Buffer Buffer to read from + @param[in] Sections name of command's sub sections to find + @param[in] HelpText pointer to pointer to string where text goes. + @param[in] HelpSize pointer to size of allocated HelpText (may be updated) + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description sotred in + an alloceted buffer. +**/ +EFI_STATUS +EFIAPI +ManBufferFindSections( + IN CONST CHAR16 *Buffer, + IN CONST CHAR16 *Sections, + IN CHAR16 **HelpText, + IN UINTN *HelpSize + ) +{ + EFI_STATUS Status; + CONST CHAR16 *CurrentLocation; + BOOLEAN CurrentlyReading; + CHAR16 *SectionName; + UINTN SectionLen; + BOOLEAN Found; + CHAR16 *TempString; + CHAR16 *TempString2; + + if ( Buffer == NULL + || HelpText == NULL + || HelpSize == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + CurrentlyReading = FALSE; + Found = FALSE; + + for (CurrentLocation = Buffer,TempString = NULL + ; CurrentLocation != NULL && *CurrentLocation != CHAR_NULL + ; CurrentLocation=StrStr(CurrentLocation, L"\r\n"),TempString = NULL + ){ + while(CurrentLocation[0] == L'\r' || CurrentLocation[0] == L'\n') { + CurrentLocation++; + } + if (CurrentLocation[0] == L'#') { + // + // Skip comment lines + // + continue; + } + if (StrnCmp(CurrentLocation, L".TH", 3) == 0) { + // + // we hit the end of this commands section so stop. + // + break; + } + if (StrnCmp(CurrentLocation, L".SH ", 4) == 0) { + if (Sections == NULL) { + CurrentlyReading = TRUE; + continue; + } else if (CurrentlyReading) { + CurrentlyReading = FALSE; + } + CurrentLocation += 4; + // + // is this a section we want to read in? + // + if (StrLen(CurrentLocation)!=0) { + TempString2 = StrStr(CurrentLocation, L" "); + TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\r")); + TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n")); + ASSERT(TempString == NULL); + TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation); + SectionName = TempString; + SectionLen = StrLen(SectionName); + SectionName = StrStr(Sections, SectionName); + if (SectionName == NULL) { + continue; + } + if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') { + CurrentlyReading = TRUE; + } + } + } else if (CurrentlyReading) { + Found = TRUE; + if (StrLen(CurrentLocation)!=0) { + TempString2 = StrStr(CurrentLocation, L"\r"); + TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n")); + ASSERT(TempString == NULL); + TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation); + // + // copy and save the current line. + // + ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL)); + StrnCatGrow (HelpText, HelpSize, TempString, 0); + StrnCatGrow (HelpText, HelpSize, L"\r\n", 0); + } + } + SHELL_FREE_NON_NULL(TempString); + } + if (!Found && !EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + return (Status); +} + +/** + parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + detailed help for any sub section specified in the comma seperated list of + sections provided. If the end of the file or a .TH section is found then + return. + + Upon a sucessful return the caller is responsible to free the memory in *HelpText + + @param[in] Handle FileHandle to read from + @param[in] Sections name of command's sub sections to find + @param[out] HelpText pointer to pointer to string where text goes. + @param[out] HelpSize pointer to size of allocated HelpText (may be updated) + @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description sotred in + an alloceted buffer. +**/ +EFI_STATUS +EFIAPI +ManFileFindSections( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Sections, + OUT CHAR16 **HelpText, + OUT UINTN *HelpSize, + IN BOOLEAN Ascii + ) +{ + EFI_STATUS Status; + CHAR16 *ReadLine; + UINTN Size; + BOOLEAN CurrentlyReading; + CHAR16 *SectionName; + UINTN SectionLen; + BOOLEAN Found; + + if ( Handle == NULL + || HelpText == NULL + || HelpSize == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + CurrentlyReading = FALSE; + Size = 1024; + Found = FALSE; + + ReadLine = AllocateZeroPool(Size); + if (ReadLine == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for (;!ShellFileHandleEof(Handle);Size = 1024) { + Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, &Ascii); + if (ReadLine[0] == L'#') { + // + // Skip comment lines + // + continue; + } + // + // ignore too small of buffer... + // + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = EFI_SUCCESS; + } + if (EFI_ERROR(Status)) { + break; + } else if (StrnCmp(ReadLine, L".TH", 3) == 0) { + // + // we hit the end of this commands section so stop. + // + break; + } else if (StrnCmp(ReadLine, L".SH", 3) == 0) { + if (Sections == NULL) { + CurrentlyReading = TRUE; + continue; + } + // + // we found a section + // + if (CurrentlyReading) { + CurrentlyReading = FALSE; + } + // + // is this a section we want to read in? + // + for ( SectionName = ReadLine + 3 + ; *SectionName == L' ' + ; SectionName++); + SectionLen = StrLen(SectionName); + SectionName = StrStr(Sections, SectionName); + if (SectionName == NULL) { + continue; + } + if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') { + CurrentlyReading = TRUE; + } + } else if (CurrentlyReading) { + Found = TRUE; + // + // copy and save the current line. + // + ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL)); + StrnCatGrow (HelpText, HelpSize, ReadLine, 0); + StrnCatGrow (HelpText, HelpSize, L"\r\n", 0); + } + } + FreePool(ReadLine); + if (!Found && !EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + return (Status); +} + +/** + parses through the MAN file formatted Buffer and returns the + "Brief Description" for the .TH section as specified by Command. If the + command section is not found return EFI_NOT_FOUND. + + Upon a sucessful return the caller is responsible to free the memory in *BriefDesc + + @param[in] Handle Buffer to read from + @param[in] Command name of command's section to find + @param[in] BriefDesc pointer to pointer to string where description goes. + @param[in] BriefSize pointer to size of allocated BriefDesc + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description sotred in + an alloceted buffer. +**/ +EFI_STATUS +EFIAPI +ManBufferFindTitleSection( + IN CHAR16 **Buffer, + IN CONST CHAR16 *Command, + IN CHAR16 **BriefDesc, + IN UINTN *BriefSize + ) +{ + EFI_STATUS Status; + CHAR16 *TitleString; + CHAR16 *TitleEnd; + CHAR16 *CurrentLocation; + + if ( Buffer == NULL + || Command == NULL + || (BriefDesc != NULL && BriefSize == NULL) + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + + TitleString = AllocatePool((7*sizeof(CHAR16)) + StrSize(Command)); + if (TitleString == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + StrCpy(TitleString, L".TH "); + StrCat(TitleString, Command); + StrCat(TitleString, L" 0 "); + + CurrentLocation = StrStr(*Buffer, TitleString); + if (CurrentLocation == NULL){ + Status = EFI_NOT_FOUND; + } else { + // + // we found it so copy out the rest of the line into BriefDesc + // After skipping any spaces or zeroes + // + for (CurrentLocation += StrLen(TitleString) + ; *CurrentLocation == L' ' || *CurrentLocation == L'0' || *CurrentLocation == L'1' || *CurrentLocation == L'\"' + ; CurrentLocation++); + + TitleEnd = StrStr(CurrentLocation, L"\""); + ASSERT(TitleEnd != NULL); + if (BriefDesc != NULL) { + *BriefSize = StrSize(TitleEnd); + *BriefDesc = AllocateZeroPool(*BriefSize); + if (*BriefDesc == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + StrnCpy(*BriefDesc, CurrentLocation, TitleEnd-CurrentLocation); + } + } + + for (CurrentLocation = TitleEnd + ; *CurrentLocation != L'\n' + ; CurrentLocation++); + for ( + ; *CurrentLocation == L' ' || *CurrentLocation == L'\n' || *CurrentLocation == L'\r' + ; CurrentLocation++); + *Buffer = CurrentLocation; + } + + FreePool(TitleString); + return (Status); +} + +/** + parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + "Brief Description" for the .TH section as specified by Command. if the + command section is not found return EFI_NOT_FOUND. + + Upon a sucessful return the caller is responsible to free the memory in *BriefDesc + + @param[in] Handle FileHandle to read from + @param[in] Command name of command's section to find + @param[out] BriefDesc pointer to pointer to string where description goes. + @param[out] BriefSize pointer to size of allocated BriefDesc + @param[in,out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be + set if the file handle is at the 0 position. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description sotred in + an alloceted buffer. +**/ +EFI_STATUS +EFIAPI +ManFileFindTitleSection( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Command, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT UINTN *BriefSize OPTIONAL, + IN OUT BOOLEAN *Ascii + ) +{ + EFI_STATUS Status; + CHAR16 *TitleString; + CHAR16 *ReadLine; + UINTN Size; + CHAR16 *TitleEnd; + UINTN TitleLen; + BOOLEAN Found; + + if ( Handle == NULL + || Command == NULL + || (BriefDesc != NULL && BriefSize == NULL) + ){ + return (EFI_INVALID_PARAMETER); + } + + Status = EFI_SUCCESS; + Size = 1024; + Found = FALSE; + + ReadLine = AllocateZeroPool(Size); + if (ReadLine == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + TitleString = AllocatePool((4*sizeof(CHAR16)) + StrSize(Command)); + if (TitleString == NULL) { + FreePool(ReadLine); + return (EFI_OUT_OF_RESOURCES); + } + StrCpy(TitleString, L".TH "); + StrCat(TitleString, Command); + TitleLen = StrLen(TitleString); + for (;!ShellFileHandleEof(Handle);Size = 1024) { + Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, Ascii); + if (ReadLine[0] == L'#') { + // + // Skip comment lines + // + continue; + } + // + // ignore too small of buffer... + // + if (Status == EFI_BUFFER_TOO_SMALL) { + Status = EFI_SUCCESS; + } + if (EFI_ERROR(Status)) { + break; + } + if (StrnCmp(ReadLine, TitleString, TitleLen) == 0) { + Found = TRUE; + // + // we found it so copy out the rest of the line into BriefDesc + // After skipping any spaces or zeroes + // + for ( TitleEnd = ReadLine+TitleLen + ; *TitleEnd == L' ' || *TitleEnd == L'0' || *TitleEnd == L'1' + ; TitleEnd++); + if (BriefDesc != NULL) { + *BriefSize = StrSize(TitleEnd); + *BriefDesc = AllocateZeroPool(*BriefSize); + if (*BriefDesc == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + StrCpy(*BriefDesc, TitleEnd); + } + break; + } + } + FreePool(ReadLine); + FreePool(TitleString); + if (!Found && !EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + return (Status); +} + +/** + This function returns the help information for the specified command. The help text + will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B) + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + if BriefDesc is NULL, then the breif description will not be savedd seperatly, + but placed first in the main HelpText. + + @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name. + @param[in] Command Points to the NULL-terminated UEFI Shell command name. + @param[in] Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param[out] BriefDesc On return, points to a callee-allocated buffer + containing brief description text. + @param[out] HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +ProcessManFile( + IN CONST CHAR16 *ManFileName, + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **BriefDesc OPTIONAL, + OUT CHAR16 **HelpText + ) +{ + CHAR16 *TempString; + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + UINTN HelpSize; + UINTN BriefSize; + BOOLEAN Ascii; + CHAR16 *TempString2; + EFI_DEVICE_PATH_PROTOCOL *FileDevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + if ( ManFileName == NULL + || Command == NULL + || HelpText == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + HelpSize = 0; + BriefSize = 0; + TempString = NULL; + // + // See if it's in HII first + // + TempString = ShellCommandGetCommandHelp(Command); + if (TempString != NULL) { + TempString2 = TempString; + Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, &BriefSize); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize); + } + } else { + FileHandle = NULL; + TempString = GetManFileName(ManFileName); + + Status = SearchPathForFile(TempString, &FileHandle); + if (EFI_ERROR(Status)) { + FileDevPath = FileDevicePath(NULL, TempString); + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath); + Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0); + FreePool(FileDevPath); + FreePool(DevPath); + } + + if (!EFI_ERROR(Status)) { + HelpSize = 0; + BriefSize = 0; + Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii); + if (!EFI_ERROR(Status) && HelpText != NULL){ + Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii); + } + ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle); + } else { + *HelpText = NULL; + } + } + if (TempString != NULL) { + FreePool(TempString); + } + + return (Status); +} diff --git a/ShellPkg/Application/Shell/ShellManParser.h b/ShellPkg/Application/Shell/ShellManParser.h new file mode 100644 index 0000000000..3807eec9b2 --- /dev/null +++ b/ShellPkg/Application/Shell/ShellManParser.h @@ -0,0 +1,86 @@ +/** @file + Provides interface to shell MAN file parser. + + Copyright (c) 2009 - 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_MAN_FILE_PARSER_HEADER_ +#define _SHELL_MAN_FILE_PARSER_HEADER_ + +/** + This function returns the help information for the specified command. The help text + will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B) + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + if BriefDesc is NULL, then the breif description will not be savedd seperatly, + but placed first in the main HelpText. + + @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name. + @param[in] Command Points to the NULL-terminated UEFI Shell command name. + @param[in] Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param[out] BriefDesc On return, points to a callee-allocated buffer + containing brief description text. + @param[out] HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +ProcessManFile( + IN CONST CHAR16 *ManFileName, + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **BriefDesc, + OUT CHAR16 **HelpText + ); + +/** + parses through the MAN file specified by SHELL_FILE_HANDLE and returns the + detailed help for any sub section specified in the comma seperated list of + sections provided. If the end of the file or a .TH section is found then + return. + + Upon a sucessful return the caller is responsible to free the memory in *HelpText + + @param[in] Handle FileHandle to read from + @param[in] Sections name of command's sub sections to find + @param[out] HelpText pointer to pointer to string where text goes. + @param[out] HelpSize pointer to size of allocated HelpText (may be updated) + @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise. + + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. + @retval EFI_SUCCESS the section was found and its description sotred in + an alloceted buffer. +**/ +EFI_STATUS +EFIAPI +ManFileFindSections( + IN SHELL_FILE_HANDLE Handle, + IN CONST CHAR16 *Sections, + OUT CHAR16 **HelpText, + OUT UINTN *HelpSize, + IN BOOLEAN Ascii + ); + +#endif //_SHELL_MAN_FILE_PARSER_HEADER_ + diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c b/ShellPkg/Application/Shell/ShellParametersProtocol.c new file mode 100644 index 0000000000..914853fdbf --- /dev/null +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -0,0 +1,949 @@ +/** @file + Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL. + + Copyright (c) 2009 - 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 "ShellParametersProtocol.h" + +/** + return the next parameter from a command line string; + + This function moves the next parameter from Walker into TempParameter and moves + Walker up past that parameter for recursive calling. When the final parameter + is moved *Walker will be set to NULL; + + Temp Parameter must be large enough to hold the parameter before calling this + function. + + @param[in,out] Walker pointer to string of command line. Adjusted to + reminaing command line on return + @param[in,out] TempParameter pointer to string of command line item extracted. + +**/ +VOID +EFIAPI +GetNextParameter( + CHAR16 **Walker, + CHAR16 **TempParameter + ) +{ + CHAR16 *NextDelim; + CHAR16 *TempLoc; + + ASSERT(Walker != NULL); + ASSERT(*Walker != NULL); + ASSERT(TempParameter != NULL); + ASSERT(*TempParameter != NULL); + + // + // make sure we dont have any leading spaces + // + while ((*Walker)[0] == L' ') { + (*Walker)++; + } + + // + // make sure we still have some params now... + // + if (StrLen(*Walker) == 0) { + ASSERT((*Walker)[0] == CHAR_NULL); + *Walker = NULL; + return; + } + + // + // we have a quoted parameter + // could be the last parameter, but SHOULD have a trailing quote + // + if ((*Walker)[0] == L'\"') { + NextDelim = NULL; + for (TempLoc = *Walker + 1 ; TempLoc != NULL && *TempLoc != CHAR_NULL ; TempLoc++) { + if (*TempLoc == L'^' && *(TempLoc+1) == L'^') { + TempLoc++; + } else if (*TempLoc == L'^' && *(TempLoc+1) == L'\"') { + TempLoc++; + } else if (*TempLoc == L'^' && *(TempLoc+1) == L'|') { + TempLoc++; + } else if (*TempLoc == L'^') { + *TempLoc = L' '; + } else if (*TempLoc == L'\"') { + NextDelim = TempLoc; + break; + } + } + + if (NextDelim - ((*Walker)+1) == 0) { + // + // found "" + // + StrCpy(*TempParameter, L""); + *Walker = NextDelim + 1; + } else if (NextDelim != NULL) { + StrnCpy(*TempParameter, (*Walker)+1, NextDelim - ((*Walker)+1)); + *Walker = NextDelim + 1; + } else { + // + // last one... someone forgot the training quote! + // + StrCpy(*TempParameter, *Walker); + *Walker = NULL; + } + for (TempLoc = *TempParameter ; TempLoc != NULL && *TempLoc != CHAR_NULL ; TempLoc++) { + if ((*TempLoc == L'^' && *(TempLoc+1) == L'^') + || (*TempLoc == L'^' && *(TempLoc+1) == L'|') + || (*TempLoc == L'^' && *(TempLoc+1) == L'\"') + ){ + CopyMem(TempLoc, TempLoc+1, StrSize(TempLoc) - sizeof(TempLoc[0])); + } + } + } else { + // + // we have a regular parameter (no quote) OR + // we have the final parameter (no trailing space) + // + NextDelim = StrStr((*Walker), L" "); + if (NextDelim != NULL) { + StrnCpy(*TempParameter, *Walker, NextDelim - (*Walker)); + (*TempParameter)[NextDelim - (*Walker)] = CHAR_NULL; + *Walker = NextDelim+1; + } else { + // + // last one. + // + StrCpy(*TempParameter, *Walker); + *Walker = NULL; + } + for (NextDelim = *TempParameter ; NextDelim != NULL && *NextDelim != CHAR_NULL ; NextDelim++) { + if (*NextDelim == L'^' && *(NextDelim+1) == L'^') { + CopyMem(NextDelim, NextDelim+1, StrSize(NextDelim) - sizeof(NextDelim[0])); + } else if (*NextDelim == L'^') { + *NextDelim = L' '; + } + } + while ((*TempParameter)[StrLen(*TempParameter)-1] == L' ') { + (*TempParameter)[StrLen(*TempParameter)-1] = CHAR_NULL; + } + while ((*TempParameter)[0] == L' ') { + CopyMem(*TempParameter, (*TempParameter)+1, StrSize(*TempParameter) - sizeof((*TempParameter)[0])); + } + } + return; +} + +/** + function to populate Argc and Argv. + + This function parses the CommandLine and divides it into standard C style Argc/Argv + parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space + delimited and quote surrounded parameter definition. + + @param[in] CommandLine String of command line to parse + @param[in,out] Argv pointer to array of strings; one for each parameter + @param[in,out] Argc pointer to number of strings in Argv array + + @return EFI_SUCCESS the operation was sucessful + @return EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +EFIAPI +ParseCommandLineToArgs( + IN CONST CHAR16 *CommandLine, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc + ) +{ + UINTN Count; + CHAR16 *TempParameter; + CHAR16 *Walker; + CHAR16 *NewParam; + UINTN Size; + + ASSERT(Argc != NULL); + ASSERT(Argv != NULL); + + if (CommandLine == NULL || StrLen(CommandLine)==0) { + (*Argc) = 0; + (*Argv) = NULL; + return (EFI_SUCCESS); + } + + Size = StrSize(CommandLine); + TempParameter = AllocateZeroPool(Size); + if (TempParameter == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + for ( Count = 0 + , Walker = (CHAR16*)CommandLine + ; Walker != NULL && *Walker != CHAR_NULL + ; GetNextParameter(&Walker, &TempParameter) + , Count++ + ); + +/* Count = 0; + Walker = (CHAR16*)CommandLine; + while(Walker != NULL) { + GetNextParameter(&Walker, &TempParameter); + Count++; + } +*/ + // + // lets allocate the pointer array + // + (*Argv) = AllocateZeroPool((Count)*sizeof(CHAR16*)); + if (*Argv == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + *Argc = 0; + Walker = (CHAR16*)CommandLine; + while(Walker != NULL && *Walker != CHAR_NULL) { + SetMem16(TempParameter, Size, CHAR_NULL); + GetNextParameter(&Walker, &TempParameter); + NewParam = AllocateZeroPool(StrSize(TempParameter)); + ASSERT(NewParam != NULL); + StrCpy(NewParam, TempParameter); + ((CHAR16**)(*Argv))[(*Argc)] = NewParam; + (*Argc)++; + } + ASSERT(Count >= (*Argc)); + return (EFI_SUCCESS); +} + +/** + creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then + installs it on our handle and if there is an existing version of the protocol + that one is cached for removal later. + + @param[in,out] NewShellParameters on a successful return, a pointer to pointer + to the newly installed interface. + @param[in,out] RootShellInstance on a successful return, pointer to boolean. + TRUE if this is the root shell instance. + + @retval EFI_SUCCESS the operation completed successfully. + @return other the operation failed. + @sa ReinstallProtocolInterface + @sa InstallProtocolInterface + @sa ParseCommandLineToArgs +**/ +EFI_STATUS +EFIAPI +CreatePopulateInstallShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters, + IN OUT BOOLEAN *RootShellInstance + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *FullCommandLine; + UINTN Size; + + Size = 0; + FullCommandLine = NULL; + LoadedImage = NULL; + + // + // Assert for valid parameters + // + ASSERT(NewShellParameters != NULL); + ASSERT(RootShellInstance != NULL); + + // + // See if we have a shell parameters placed on us + // + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **) &ShellInfoObject.OldShellParameters, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + // + // if we don't then we must be the root shell (error is expected) + // + if (EFI_ERROR (Status)) { + *RootShellInstance = TRUE; + } + + // + // Allocate the new structure + // + *NewShellParameters = AllocateZeroPool(sizeof(EFI_SHELL_PARAMETERS_PROTOCOL)); + ASSERT(NewShellParameters != NULL); + + // + // get loaded image protocol + // + Status = gBS->OpenProtocol ( + gImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **) &LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR(Status); + // + // Build the full command line + // + Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, &FullCommandLine); + if (Status == EFI_BUFFER_TOO_SMALL) { + FullCommandLine = AllocateZeroPool(Size + LoadedImage->LoadOptionsSize); + Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, &FullCommandLine); + } + if (Status == EFI_NOT_FOUND) { + // + // no parameters via environment... ok + // + } else { + ASSERT_EFI_ERROR(Status); + } + if (Size == 0 && LoadedImage->LoadOptionsSize != 0) { + // + // Now we need to include a NULL terminator in the size. + // + Size = LoadedImage->LoadOptionsSize + sizeof(FullCommandLine[0]); + FullCommandLine = AllocateZeroPool(Size); + } + if (LoadedImage->LoadOptionsSize != 0){ + StrCpy(FullCommandLine, LoadedImage->LoadOptions); + } + if (FullCommandLine != NULL) { + // + // Populate Argc and Argv + // + Status = ParseCommandLineToArgs(FullCommandLine, + &(*NewShellParameters)->Argv, + &(*NewShellParameters)->Argc); + + FreePool(FullCommandLine); + + ASSERT_EFI_ERROR(Status); + } else { + (*NewShellParameters)->Argv = NULL; + (*NewShellParameters)->Argc = 0; + } + + // + // Populate the 3 faked file systems... + // + if (*RootShellInstance) { + (*NewShellParameters)->StdIn = &FileInterfaceStdIn; + (*NewShellParameters)->StdOut = &FileInterfaceStdOut; + (*NewShellParameters)->StdErr = &FileInterfaceStdErr; + Status = gBS->InstallProtocolInterface(&gImageHandle, + &gEfiShellParametersProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID*)(*NewShellParameters)); + } else { + // + // copy from the existing ones + // + (*NewShellParameters)->StdIn = ShellInfoObject.OldShellParameters->StdIn; + (*NewShellParameters)->StdOut = ShellInfoObject.OldShellParameters->StdOut; + (*NewShellParameters)->StdErr = ShellInfoObject.OldShellParameters->StdErr; + Status = gBS->ReinstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)ShellInfoObject.OldShellParameters, + (VOID*)(*NewShellParameters)); + } + + return (Status); +} + +/** + frees all memory used by createion and installation of shell parameters protocol + and if there was an old version installed it will restore that one. + + @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is + being cleaned up. + + @retval EFI_SUCCESS the cleanup was successful + @return other the cleanup failed + @sa ReinstallProtocolInterface + @sa UninstallProtocolInterface +**/ +EFI_STATUS +EFIAPI +CleanUpShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters + ) +{ + EFI_STATUS Status; + UINTN LoopCounter; + + // + // If the old exists we need to restore it + // + if (ShellInfoObject.OldShellParameters != NULL) { + Status = gBS->ReinstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)NewShellParameters, + (VOID*)ShellInfoObject.OldShellParameters); + DEBUG_CODE(ShellInfoObject.OldShellParameters = NULL;); + } else { + // + // No old one, just uninstall us... + // + Status = gBS->UninstallProtocolInterface(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID*)NewShellParameters); + } + if (NewShellParameters->Argv != NULL) { + for ( LoopCounter = 0 + ; LoopCounter < NewShellParameters->Argc + ; LoopCounter++ + ){ + FreePool(NewShellParameters->Argv[LoopCounter]); + } + FreePool(NewShellParameters->Argv); + } + FreePool(NewShellParameters); + return (Status); +} + +/** + Funcion will replace the current StdIn and StdOut in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + If OldStdIn or OldStdOut is NULL then that value is not returned. + + @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. + + @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +UpdateStdInStdOutStdErr( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CONST CHAR16 *NewCommandLine, + OUT SHELL_FILE_HANDLE *OldStdIn, + OUT SHELL_FILE_HANDLE *OldStdOut, + OUT SHELL_FILE_HANDLE *OldStdErr + ) +{ + CHAR16 *CommandLineCopy; + CHAR16 *CommandLineWalker; + CHAR16 *StdErrFileName; + CHAR16 *StdOutFileName; + CHAR16 *StdInFileName; + CHAR16 *StdInVarName; + CHAR16 *StdOutVarName; + CHAR16 *StdErrVarName; + EFI_STATUS Status; + SHELL_FILE_HANDLE TempHandle; + UINT64 FileSize; + BOOLEAN OutUnicode; + BOOLEAN InUnicode; + BOOLEAN ErrUnicode; + BOOLEAN OutAppend; + BOOLEAN ErrAppend; + UINTN Size; + CHAR16 TagBuffer[2]; + SPLIT_LIST *Split; + + ASSERT(ShellParameters != NULL); + OutUnicode = TRUE; + InUnicode = TRUE; + ErrUnicode = TRUE; + StdInVarName = NULL; + StdOutVarName = NULL; + StdErrVarName = NULL; + StdErrFileName = NULL; + StdInFileName = NULL; + StdOutFileName = NULL; + ErrAppend = FALSE; + OutAppend = FALSE; + CommandLineCopy = NULL; + + if (OldStdIn != NULL) { + *OldStdIn = ShellParameters->StdIn; + } + if (OldStdOut != NULL) { + *OldStdOut = ShellParameters->StdOut; + } + if (OldStdErr != NULL) { + *OldStdErr = ShellParameters->StdErr; + } + + if (NewCommandLine == NULL) { + return (EFI_SUCCESS); + } + + CommandLineCopy = StrnCatGrow(&CommandLineCopy, NULL, NewCommandLine, 0); + Status = EFI_SUCCESS; + Split = NULL; + + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + if (Split != NULL && Split->SplitStdIn != NULL) { + ShellParameters->StdIn = Split->SplitStdIn; + } + if (Split != NULL && Split->SplitStdOut != NULL) { + ShellParameters->StdOut = Split->SplitStdOut; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>>v ")) != NULL) { + StdErrVarName = CommandLineWalker += 6; + ErrAppend = TRUE; + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>v ")) != NULL) { + StdOutVarName = CommandLineWalker += 6; + OutAppend = TRUE; + } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>v ")) != NULL) { + StdOutVarName = CommandLineWalker += 5; + OutAppend = TRUE; + } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >v ")) != NULL) { + StdOutVarName = CommandLineWalker += 4; + OutAppend = FALSE; + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>a ")) != NULL) { + StdOutFileName = CommandLineWalker += 6; + OutAppend = TRUE; + OutUnicode = FALSE; + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>> ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = TRUE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >> ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = TRUE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>a ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = TRUE; + OutUnicode = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>a ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 5; + OutAppend = FALSE; + OutUnicode = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >a ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = FALSE; + OutUnicode = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>> ")) != NULL) { + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 5; + ErrAppend = TRUE; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>v ")) != NULL) { + if (StdErrVarName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrVarName = CommandLineWalker += 5; + ErrAppend = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>v ")) != NULL) { + if (StdOutVarName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutVarName = CommandLineWalker += 5; + OutAppend = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>a ")) != NULL) { + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 5; + ErrAppend = FALSE; + ErrUnicode = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2> ")) != NULL) { + if (StdErrFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdErrFileName = CommandLineWalker += 4; + ErrAppend = FALSE; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1> ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 4; + OutAppend = FALSE; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" > ")) != NULL) { + if (StdOutFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdOutFileName = CommandLineWalker += 3; + OutAppend = FALSE; + } + } + + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" < ")) != NULL) { + if (StdInFileName != NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + StdInFileName = CommandLineWalker += 3; + OutAppend = FALSE; + } + } + if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" SplitStdIn != NULL && (StdInVarName != NULL || StdInFileName != NULL)) + ||(Split != NULL && Split->SplitStdOut != NULL && (StdOutVarName != NULL || StdOutFileName != NULL)) + ||(StdErrFileName != NULL && StdErrVarName != NULL) + ||(StdOutFileName != NULL && StdOutVarName != NULL) + ||(StdInFileName != NULL && StdInVarName != NULL) + ||(StdErrVarName != NULL && !IsVolatileEnv(StdErrVarName)) + ||(StdOutVarName != NULL && !IsVolatileEnv(StdOutVarName)) + ){ + Status = EFI_INVALID_PARAMETER; + } else { + // + // Open the Std and we should not have conflicts here... + // + + // + // StdErr to a file + // + if (StdErrFileName != NULL) { + if (!ErrAppend) { + // + // delete existing file. + // + ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdErrFileName); + } + Status = ShellOpenFileByName(StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0); + ASSERT(TempHandle != NULL); + if (!ErrAppend && ErrUnicode && !EFI_ERROR(Status)) { + // + // Write out the UnicodeFileTag + // + Size = sizeof(CHAR16); + TagBuffer[0] = UnicodeFileTag; + TagBuffer[1] = CHAR_NULL; + ShellInfoObject.NewEfiShellProtocol->WriteFile(TempHandle, &Size, TagBuffer); + } + if (!ErrUnicode && !EFI_ERROR(Status)) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + if (!EFI_ERROR(Status)) { + ShellParameters->StdErr = TempHandle; + } + } + + // + // StdOut to a file + // + if (!EFI_ERROR(Status) && StdOutFileName != NULL) { + if (!OutAppend) { + // + // delete existing file. + // + ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdOutFileName); + } + Status = ShellOpenFileByName(StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0); + ASSERT(TempHandle != NULL); + if (!OutAppend && OutUnicode && !EFI_ERROR(Status)) { + // + // Write out the UnicodeFileTag + // + Size = sizeof(CHAR16); + TagBuffer[0] = UnicodeFileTag; + TagBuffer[1] = CHAR_NULL; + ShellInfoObject.NewEfiShellProtocol->WriteFile(TempHandle, &Size, TagBuffer); + } else if (OutAppend) { + // + // Move to end of file + // + Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize(TempHandle, &FileSize); + if (!EFI_ERROR(Status)) { + Status = ShellInfoObject.NewEfiShellProtocol->SetFilePosition(TempHandle, FileSize); + } + } + if (!OutUnicode && !EFI_ERROR(Status)) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + if (!EFI_ERROR(Status)) { + ShellParameters->StdOut = TempHandle; + } + } + + // + // StdOut to a var + // + if (!EFI_ERROR(Status) && StdOutVarName != NULL) { + if (!OutAppend) { + // + // delete existing variable. + // + SHELL_SET_ENVIRONMENT_VARIABLE_V(StdOutVarName, 0, L""); + } + TempHandle = CreateFileInterfaceEnv(StdOutVarName); + ASSERT(TempHandle != NULL); + if (!OutUnicode) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + ShellParameters->StdOut = TempHandle; + } + + // + // StdErr to a var + // + if (!EFI_ERROR(Status) && StdErrVarName != NULL) { + if (!ErrAppend) { + // + // delete existing variable. + // + SHELL_SET_ENVIRONMENT_VARIABLE_V(StdErrVarName, 0, L""); + } + TempHandle = CreateFileInterfaceEnv(StdErrVarName); + ASSERT(TempHandle != NULL); + if (!ErrUnicode) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + ASSERT(TempHandle != NULL); + } + ShellParameters->StdErr = TempHandle; + } + + // + // StdIn from a var + // + if (!EFI_ERROR(Status) && StdInVarName != NULL) { + TempHandle = CreateFileInterfaceEnv(StdInVarName); + if (!InUnicode) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + } + Size = 0; + ASSERT(TempHandle != NULL); + if (((EFI_FILE_PROTOCOL*)TempHandle)->Read(TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL) { + Status = EFI_INVALID_PARAMETER; + } else { + ShellParameters->StdIn = TempHandle; + } + } + + // + // StdIn from a file + // + if (!EFI_ERROR(Status) && StdInFileName != NULL) { + Status = ShellOpenFileByName( + StdInFileName, + &TempHandle, + EFI_FILE_MODE_READ, + 0); + if (!InUnicode && !EFI_ERROR(Status)) { + TempHandle = CreateFileInterfaceFile(TempHandle, FALSE); + } + if (!EFI_ERROR(Status)) { + ShellParameters->StdIn = TempHandle; + } + } + } + } + FreePool(CommandLineCopy); + return (Status); +} + +/** + 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. +**/ +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 + ) +{ + SPLIT_LIST *Split; + if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) { + Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link); + } else { + Split = NULL; + } + if (OldStdIn != NULL && ShellParameters->StdIn != *OldStdIn) { + if ((Split != NULL && Split->SplitStdIn != ShellParameters->StdIn) || Split == NULL) { + gEfiShellProtocol->CloseFile(ShellParameters->StdIn); + } + ShellParameters->StdIn = OldStdIn==NULL?NULL:*OldStdIn; + } + if (OldStdOut != NULL && ShellParameters->StdOut != *OldStdOut) { + if ((Split != NULL && Split->SplitStdOut != ShellParameters->StdOut) || Split == NULL) { + gEfiShellProtocol->CloseFile(ShellParameters->StdOut); + } + ShellParameters->StdOut = OldStdOut==NULL?NULL:*OldStdOut; + } + return (EFI_SUCCESS); +} +/** + Funcion will replace the current Argc and Argv in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + If OldArgv or OldArgc is NULL then that value is not returned. + + @param[in,out] ShellParameters Pointer to parameter structure to modify. + @param[in] NewCommandLine The new command line to parse and use. + @param[out] OldArgv Pointer to old list of parameters. + @param[out] OldArgc Pointer to old number of items in Argv list. + + @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +UpdateArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CONST CHAR16 *NewCommandLine, + OUT CHAR16 ***OldArgv OPTIONAL, + OUT UINTN *OldArgc OPTIONAL + ) +{ + ASSERT(ShellParameters != NULL); + + if (OldArgc != NULL) { + *OldArgc = ShellParameters->Argc; + } + if (OldArgc != NULL) { + *OldArgv = ShellParameters->Argv; + } + + return (ParseCommandLineToArgs(NewCommandLine, &(ShellParameters->Argv), &(ShellParameters->Argc))); +} + +/** + Funcion will replace the current Argc and Argv in the ShellParameters protocol + structure with Argv and Argc. The current values are de-allocated and the + OldArgv must not be deallocated by the caller. + + @param[in,out] ShellParameters pointer to parameter structure to modify + @param[in] OldArgv pointer to old list of parameters + @param[in] OldArgc pointer to old number of items in Argv list +**/ +VOID +EFIAPI +RestoreArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 ***OldArgv, + IN UINTN *OldArgc + ) +{ + UINTN LoopCounter; + ASSERT(ShellParameters != NULL); + ASSERT(OldArgv != NULL); + ASSERT(OldArgc != NULL); + + if (ShellParameters->Argv != NULL) { + for ( LoopCounter = 0 + ; LoopCounter < ShellParameters->Argc + ; LoopCounter++ + ){ + FreePool(ShellParameters->Argv[LoopCounter]); + } + FreePool(ShellParameters->Argv); + } + ShellParameters->Argv = *OldArgv; + *OldArgv = NULL; + ShellParameters->Argc = *OldArgc; + *OldArgc = 0; +} diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.h b/ShellPkg/Application/Shell/ShellParametersProtocol.h new file mode 100644 index 0000000000..3a5fc30bcb --- /dev/null +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.h @@ -0,0 +1,208 @@ +/** @file + Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL. + + Copyright (c) 2009 - 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_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ +#define _SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ShellEnvVar.h" +#include "FileHandleWrappers.h" +#include "Shell.h" + +/** + creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then + installs it on our handle and if there is an existing version of the protocol + that one is cached for removal later. + + @param[in,out] NewShellParameters on a successful return, a pointer to pointer + to the newly installed interface. + @param[in,out] RootShellInstance on a successful return, pointer to boolean. + TRUE if this is the root shell instance. + + @retval EFI_SUCCESS the operation completed successfully. + @return other the operation failed. + @sa ReinstallProtocolInterface + @sa InstallProtocolInterface + @sa ParseCommandLineToArgs +**/ +EFI_STATUS +EFIAPI +CreatePopulateInstallShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters, + IN OUT BOOLEAN *RootShellInstance + ); + +/** + frees all memory used by createion and installation of shell parameters protocol + and if there was an old version installed it will restore that one. + + @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is + being cleaned up. + + @retval EFI_SUCCESS the cleanup was successful + @return other the cleanup failed + @sa ReinstallProtocolInterface + @sa UninstallProtocolInterface +**/ +EFI_STATUS +EFIAPI +CleanUpShellParametersProtocol ( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters + ); + +/** + Funcion will replace the current Argc and Argv in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + @param[in,out] ShellParameters pointer to parameter structure to modify + @param[in] NewCommandLine the new command line to parse and use + @param[out] OldArgv pointer to old list of parameters + @param[out] OldArgc pointer to old number of items in Argv list + + @retval EFI_SUCCESS operation was sucessful, Argv and Argc are valid + @retval EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +EFIAPI +UpdateArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CONST CHAR16 *NewCommandLine, + OUT CHAR16 ***OldArgv, + OUT UINTN *OldArgc + ); + +/** + Funcion will replace the current Argc and Argv in the ShellParameters protocol + structure with Argv and Argc. The current values are de-allocated and the + OldArgv must not be deallocated by the caller. + + @param[in,out] ShellParameters pointer to parameter structure to modify + @param[in] OldArgv pointer to old list of parameters + @param[in] OldArgc pointer to old number of items in Argv list +**/ +VOID +EFIAPI +RestoreArgcArgv( + IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, + IN CHAR16 ***OldArgv, + IN UINTN *OldArgc + ); + +/** + Funcion will replace the current StdIn and StdOut in the ShellParameters protocol + structure by parsing NewCommandLine. The current values are returned to the + user. + + If OldStdIn or OldStdOut is NULL then that value is not returned. + + @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. + + @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +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 + ); + +/** + 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. +**/ +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 + ); + +/** + function to populate Argc and Argv. + + This function parses the CommandLine and divides it into standard C style Argc/Argv + parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space + delimited and quote surrounded parameter definition. + + @param[in] CommandLine String of command line to parse + @param[in,out] Argv pointer to array of strings; one for each parameter + @param[in,out] Argc pointer to number of strings in Argv array + + @return EFI_SUCCESS the operation was sucessful + @return EFI_OUT_OF_RESOURCES a memory allocation failed. +**/ +EFI_STATUS +EFIAPI +ParseCommandLineToArgs( + IN CONST CHAR16 *CommandLine, + IN OUT CHAR16 ***Argv, + IN OUT UINTN *Argc + ); + +/** + return the next parameter from a command line string; + + This function moves the next parameter from Walker into TempParameter and moves + Walker up past that parameter for recursive calling. When the final parameter + is moved *Walker will be set to NULL; + + Temp Parameter must be large enough to hold the parameter before calling this + function. + + @param[in,out] Walker pointer to string of command line. Adjusted to + reminaing command line on return + @param[in,out] TempParameter pointer to string of command line item extracted. + +**/ +VOID +EFIAPI +GetNextParameter( + CHAR16 **Walker, + CHAR16 **TempParameter + ); + +#endif //_SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_ + diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c new file mode 100644 index 0000000000..214693f2ae --- /dev/null +++ b/ShellPkg/Application/Shell/ShellProtocol.c @@ -0,0 +1,3122 @@ +/** @file + Member functions of EFI_SHELL_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PROTOCOL. + + Copyright (c) 2009 - 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 "Shell.h" +#include + +/** + Close an open file handle. + + This function closes a specified file handle. All "dirty" cached file data is + flushed to the device, and the file is closed. In all cases the handle is + closed. + + @param[in] FileHandle The file handle to close. + + @retval EFI_SUCCESS The file handle was closed successfully. +**/ +EFI_STATUS +EFIAPI +EfiShellClose ( + IN SHELL_FILE_HANDLE FileHandle + ) +{ + ShellFileHandleRemove(FileHandle); + return (FileHandleClose(FileHandle)); +} + +/** + Internal worker to determine whether there is a file system somewhere + upon the device path specified. + + @param[in] DevicePath The device path to test. + + @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path + @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found. +**/ +BOOLEAN +EFIAPI +InternalShellProtocolIsSimpleFileSystemPresent( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + + DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath; + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle); + + if ((Handle != NULL) && (!EFI_ERROR(Status))) { + return (TRUE); + } + return (FALSE); +} + +/** + Internal worker debug helper function to print out maps as they are added. + + @param[in] Mapping string mapping that has been added + @param[in] DevicePath pointer to device path that has been mapped. + + @retval EFI_SUCCESS the operation was successful. + @return other an error ocurred + + @sa LocateHandle + @sa OpenProtocol +**/ +EFI_STATUS +EFIAPI +InternalShellProtocolDebugPrintMessage ( + IN CONST CHAR16 *Mapping, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToText; + EFI_STATUS Status; + CHAR16 *Temp; + + Status = EFI_SUCCESS; + DEBUG_CODE_BEGIN(); + DevicePathToText = NULL; + + Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID**)&DevicePathToText); + if (Mapping != NULL) { + DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping)); + } + if (!EFI_ERROR(Status)) { + if (DevicePath != NULL) { + Temp = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE); + DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp)); + FreePool(Temp); + } + } + DEBUG_CODE_END(); + return (Status); +} + +/** + This function creates a mapping for a device path. + + If both DeviecPath and Mapping are NULL, this will reset the mapping to default values. + + @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping, + then the mapping will be deleted. + @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':' + + @retval EFI_SUCCESS Mapping created or deleted successfully. + @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the + boot service function LocateDevicePath(). + @retval EFI_ACCESS_DENIED The mapping is a built-in alias. + @retval EFI_INVALID_PARAMETER Mapping was NULL + @retval EFI_INVALID_PARAMETER Mapping did not end with a ':' + @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed. + @retval EFI_NOT_FOUND There was no mapping found to delete + @retval EFI_OUT_OF_RESOURCES Memory allocation failed +**/ +EFI_STATUS +EFIAPI +EfiShellSetMap( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, + IN CONST CHAR16 *Mapping + ) +{ + EFI_STATUS Status; + SHELL_MAP_LIST *MapListNode; + + if (Mapping == NULL){ + return (EFI_INVALID_PARAMETER); + } + + if (Mapping[StrLen(Mapping)-1] != ':') { + return (EFI_INVALID_PARAMETER); + } + + // + // Delete the mapping + // + if (DevicePath == NULL) { + if (IsListEmpty(&gShellMapList.Link)) { + return (EFI_NOT_FOUND); + } + for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListNode->Link) + ; MapListNode = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListNode->Link) + ){ + if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) { + RemoveEntryList(&MapListNode->Link); + FreePool(MapListNode); + return (EFI_SUCCESS); + } + } // for loop + + // + // We didnt find one to delete + // + return (EFI_NOT_FOUND); + } + + // + // make sure this is a valid to add device path + // + ///@todo add BlockIo to this test... + if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)) { + return (EFI_INVALID_PARAMETER); + } + + // + // First make sure there is no old mapping + // + Status = EfiShellSetMap(NULL, Mapping); + if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) { + return (Status); + } + + // + // now add the new one. + // + Status = ShellCommandAddMapItemAndUpdatePath(Mapping, DevicePath, 0, FALSE); + + return(Status); +} + +/** + Gets the device path from the mapping. + + This function gets the device path associated with a mapping. + + @param Mapping A pointer to the mapping + + @retval !=NULL Pointer to the device path that corresponds to the + device mapping. The returned pointer does not need + to be freed. + @retval NULL There is no device path associated with the + specified mapping. +**/ +CONST EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromMap( + IN CONST CHAR16 *Mapping + ) +{ + SHELL_MAP_LIST *MapListItem; + CHAR16 *NewName; + UINTN Size; + + NewName = NULL; + Size = 0; + + StrnCatGrow(&NewName, &Size, Mapping, 0); + if (Mapping[StrLen(Mapping)-1] != L':') { + StrnCatGrow(&NewName, &Size, L":", 0); + } + + MapListItem = ShellCommandFindMapItem(NewName); + + FreePool(NewName); + + if (MapListItem != NULL) { + return (MapListItem->DevicePath); + } + return(NULL); +} + +/** + Gets the mapping(s) that most closely matches the device path. + + This function gets the mapping which corresponds to the device path *DevicePath. If + there is no exact match, then the mapping which most closely matches *DevicePath + is returned, and *DevicePath is updated to point to the remaining portion of the + device path. If there is an exact match, the mapping is returned and *DevicePath + points to the end-of-device-path node. + + If there are multiple map names they will be semi-colon seperated in the + NULL-terminated string. + + @param DevicePath On entry, points to a device path pointer. On + exit, updates the pointer to point to the + portion of the device path after the mapping. + + @retval NULL No mapping was found. + @return !=NULL Pointer to NULL-terminated mapping. The buffer + is callee allocated and should be freed by the caller. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetMapFromDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + SHELL_MAP_LIST *Node; + CHAR16 *PathForReturn; + UINTN PathSize; +// EFI_HANDLE PathHandle; +// EFI_HANDLE MapHandle; +// EFI_STATUS Status; +// EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; +// EFI_DEVICE_PATH_PROTOCOL *MapPathCopy; + + if (DevicePath == NULL || *DevicePath == NULL) { + return (NULL); + } + + PathForReturn = NULL; + PathSize = 0; + + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + // + // check for exact match + // + if (DevicePathCompare(DevicePath, &Node->DevicePath) == 0) { + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + if (PathSize != 0) { + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + } + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + } + } + if (PathForReturn != NULL) { + while (!IsDevicePathEndType (*DevicePath)) { + *DevicePath = NextDevicePathNode (*DevicePath); + } + SetDevicePathEndNode (*DevicePath); + } +/* + ///@todo finish code for inexact matches. + if (PathForReturn == NULL) { + PathSize = 0; + + DevicePathCopy = DuplicateDevicePath(*DevicePath); + ASSERT(DevicePathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle); + ASSERT_EFI_ERROR(Status); + // + // check each of the device paths we have to get the root of the path for consist mappings + // + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) { + continue; + } + MapPathCopy = DuplicateDevicePath(Node->DevicePath); + ASSERT(MapPathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + + *DevicePath = DevicePathCopy; + + MapPathCopy = NULL; + DevicePathCopy = NULL; + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + break; + } + } + // + // now add on the non-consistent mappings + // + for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &Node->Link) + ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link) + ){ + if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) { + continue; + } + MapPathCopy = Node->DevicePath; + ASSERT(MapPathCopy != NULL); + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0); + break; + } + } + } +*/ + + return (AddBufferToFreeList(PathForReturn)); +} + +/** + Converts a device path to a file system-style path. + + This function converts a device path to a file system path by replacing part, or all, of + the device path with the file-system mapping. If there are more than one application + file system mappings, the one that most closely matches Path will be used. + + @param Path The pointer to the device path + + @retval NULL the device path could not be found. + @return all The pointer of the NULL-terminated file path. The path + is callee-allocated and should be freed by the caller. +**/ +CHAR16 * +EFIAPI +EfiShellGetFilePathFromDevicePath( + IN CONST EFI_DEVICE_PATH_PROTOCOL *Path + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_DEVICE_PATH_PROTOCOL *MapPathCopy; + SHELL_MAP_LIST *MapListItem; + CHAR16 *PathForReturn; + UINTN PathSize; + EFI_HANDLE PathHandle; + EFI_HANDLE MapHandle; + EFI_STATUS Status; + FILEPATH_DEVICE_PATH *FilePath; + + PathForReturn = NULL; + PathSize = 0; + + DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)Path; + ASSERT(DevicePathCopy != NULL); + if (DevicePathCopy == NULL) { + return (NULL); + } + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle); + + if (EFI_ERROR(Status)) { + return (NULL); + } + // + // check each of the device paths we have to get the root of the path + // + for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListItem->Link) + ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link) + ){ + MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL*)MapListItem->DevicePath; + ASSERT(MapPathCopy != NULL); + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle); + if (MapHandle == PathHandle) { + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, MapListItem->MapName, 0); + // + // go through all the remaining nodes in the device path + // + for ( FilePath = (FILEPATH_DEVICE_PATH*)DevicePathCopy + ; !IsDevicePathEnd (&FilePath->Header) + ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header) + ){ + // + // all the rest should be file path nodes + // + if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) || + (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) { + FreePool(PathForReturn); + PathForReturn = NULL; + ASSERT(FALSE); + } else { + // + // append the path part onto the filepath. + // + ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL)); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L"\\", 1); + PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, FilePath->PathName, 0); + } + } // for loop of remaining nodes + } + if (PathForReturn != NULL) { + break; + } + } // for loop of paths to check + return(PathForReturn); +} + +/** + Converts a file system style name to a device path. + + This function converts a file system style name to a device path, by replacing any + mapping references to the associated device path. + + @param Path the pointer to the path + + @return all The pointer of the file path. The file path is callee + allocated and should be freed by the caller. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromFilePath( + IN CONST CHAR16 *Path + ) +{ + CHAR16 *MapName; + CHAR16 *NewPath; + CONST CHAR16 *Cwd; + UINTN Size; + CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy; + EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree; + EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn; + EFI_HANDLE Handle; + EFI_STATUS Status; + + MapName = NULL; + ASSERT(Path != NULL); + + if (StrStr(Path, L":") == NULL) { + Cwd = EfiShellGetCurDir(NULL); + if (Cwd == NULL) { + return (NULL); + } + Size = StrSize(Cwd); + Size += StrSize(Path); + NewPath = AllocateZeroPool(Size); + ASSERT(NewPath != NULL); + StrCpy(NewPath, Cwd); + if (NewPath[StrLen(NewPath)-1] == Path[0] == (CHAR16)L'\\') { + ((CHAR16*)NewPath)[StrLen(NewPath)-1] = CHAR_NULL; + } + StrCat(NewPath, Path); + DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath); + FreePool(NewPath); + return (DevicePathForReturn); + } + + Size = 0; + // + // find the part before (but including) the : for the map name + // + ASSERT((MapName == NULL && Size == 0) || (MapName != NULL)); + MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1)); + if (MapName[StrLen(MapName)-1] != L':') { + ASSERT(FALSE); + return (NULL); + } + + // + // look up the device path in the map + // + DevicePath = EfiShellGetDevicePathFromMap(MapName); + if (DevicePath == NULL) { + // + // Must have been a bad Mapname + // + return (NULL); + } + + // + // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with) + // + DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath); + if (DevicePathCopy == NULL) { + ASSERT(FALSE); + FreePool(MapName); + return (NULL); + } + + // + // get the handle + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle); + if (EFI_ERROR(Status)) { + if (DevicePathCopyForFree != NULL) { + FreePool(DevicePathCopyForFree); + } + FreePool(MapName); + return (NULL); + } + + // + // build the full device path + // + DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName)+1); + + FreePool(MapName); + if (DevicePathCopyForFree != NULL) { + FreePool(DevicePathCopyForFree); + } + + return (DevicePathForReturn); +} + +/** + Gets the name of the device specified by the device handle. + + This function gets the user-readable name of the device specified by the device + handle. If no user-readable name could be generated, then *BestDeviceName will be + NULL and EFI_NOT_FOUND will be returned. + + If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the + device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on + DeviceHandle. + + If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the + device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle. + If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and + EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then + EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority. + + @param DeviceHandle The handle of the device. + @param Flags Determines the possible sources of component names. + Valid bits are: + EFI_DEVICE_NAME_USE_COMPONENT_NAME + EFI_DEVICE_NAME_USE_DEVICE_PATH + @param Language A pointer to the language specified for the device + name, in the same format as described in the UEFI + specification, Appendix M + @param BestDeviceName On return, points to the callee-allocated NULL- + terminated name of the device. If no device name + could be found, points to NULL. The name must be + freed by the caller... + + @retval EFI_SUCCESS Get the name successfully. + @retval EFI_NOT_FOUND Fail to get the device name. + @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set. + @retval EFI_INVALID_PARAMETER BestDeviceName was NULL + @retval EFI_INVALID_PARAMETER DeviceHandle was NULL +**/ +EFI_STATUS +EFIAPI +EfiShellGetDeviceName( + IN EFI_HANDLE DeviceHandle, + IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, + IN CHAR8 *Language, + OUT CHAR16 **BestDeviceName + ) +{ + EFI_STATUS Status; + EFI_COMPONENT_NAME2_PROTOCOL *CompName2; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToText; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE *HandleList; + UINTN HandleCount; + UINTN LoopVar; + CHAR16 *DeviceNameToReturn; + CHAR8 *Lang; + CHAR8 *TempChar; + + if (BestDeviceName == NULL || + DeviceHandle == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + + // + // make sure one of the 2 supported bits is on + // + if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) && + ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0)) { + return (EFI_INVALID_PARAMETER); + } + + DeviceNameToReturn = NULL; + *BestDeviceName = NULL; + HandleList = NULL; + HandleCount = 0; + Lang = NULL; + + if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) { + Status = ParseHandleDatabaseByRelationship( + NULL, + DeviceHandle, + HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER, + &HandleCount, + &HandleList); + for (LoopVar = 0; LoopVar < HandleCount ; LoopVar++){ + // + // Go through those handles until we get one that passes for GetComponentName + // + Status = gBS->OpenProtocol( + HandleList[LoopVar], + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Status = gBS->OpenProtocol( + HandleList[LoopVar], + &gEfiComponentNameProtocolGuid, + (VOID**)&CompName2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + + if (EFI_ERROR(Status)) { + continue; + } + if (Language == NULL) { + Lang = AllocatePool(AsciiStrSize(CompName2->SupportedLanguages)); + AsciiStrCpy(Lang, CompName2->SupportedLanguages); + TempChar = AsciiStrStr(Lang, ";"); + if (TempChar != NULL){ + *TempChar = CHAR_NULL; + } + } else { + Lang = AllocatePool(AsciiStrSize(Language)); + AsciiStrCpy(Lang, Language); + } + Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn); + FreePool(Lang); + Lang = NULL; + if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) { + break; + } + } + if (HandleList != NULL) { + FreePool(HandleList); + } + if (DeviceNameToReturn != NULL){ + ASSERT(BestDeviceName == NULL); + StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0); + return (EFI_SUCCESS); + } + // + // dont return on fail since we will try device path if that bit is on + // + } + if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) { + Status = gBS->LocateProtocol( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID**)&DevicePathToText); + // + // we now have the device path to text protocol + // + if (!EFI_ERROR(Status)) { + Status = gBS->OpenProtocol( + DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + // + // use device path to text on the device path + // + *BestDeviceName = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE); + return (EFI_SUCCESS); + } + } + } + // + // none of the selected bits worked. + // + return (EFI_NOT_FOUND); +} + +/** + Opens the root directory of a device on a handle + + This function opens the root directory of a device and returns a file handle to it. + + @param DeviceHandle The handle of the device that contains the volume. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + 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 +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRootByHandle( + IN EFI_HANDLE DeviceHandle, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_FILE_PROTOCOL *RealFileHandle; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + + // + // get the simple file system interface + // + Status = gBS->OpenProtocol(DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&SimpleFileSystem, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + + Status = gBS->OpenProtocol(DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + // + // Open the root volume now... + // + Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle); + *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath)); + return (Status); +} + +/** + Opens the root directory of a device. + + This function opens the root directory of a device and returns a file handle to it. + + @param DevicePath Points to the device path corresponding to the device where the + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + 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 +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRoot( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + // + // find the handle of the device with that device handle and the file system + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, + &DevicePath, + &Handle); + if (EFI_ERROR(Status)) { + return (EFI_NOT_FOUND); + } + + return (EfiShellOpenRootByHandle(Handle, FileHandle)); +} + +/** + Returns whether any script files are currently being processed. + + @retval TRUE There is at least one script file active. + @retval FALSE No script files are active now. + +**/ +BOOLEAN +EFIAPI +EfiShellBatchIsActive ( + VOID + ) +{ + if (ShellCommandGetCurrentScriptFile() == NULL) { + return (FALSE); + } + return (TRUE); +} + +/** + Worker function to open a file based on a device path. this will open the root + of the volume and then traverse down to the file itself. + + @param DevicePath Device Path of the file. + @param FileHandle Pointer to the file upon a successful return. + @param OpenMode mode to open file in. + @param Attributes the File Attributes to use when creating a new file. + + @retval EFI_SUCCESS the file is open and FileHandle is valid + @retval EFI_UNSUPPORTED the device path cotained non-path elements + @retval other an error ocurred. +**/ +EFI_STATUS +EFIAPI +InternalOpenFileDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + FILEPATH_DEVICE_PATH *FilePathNode; + EFI_HANDLE Handle; + SHELL_FILE_HANDLE ShellHandle; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; + EFI_DEVICE_PATH_PROTOCOL *DpCopy; + + ASSERT(FileHandle != NULL); + *FileHandle = NULL; + Handle1 = NULL; + DpCopy = DevicePath; + + Status = EfiShellOpenRoot(DevicePath, &ShellHandle); + + if (!EFI_ERROR(Status)) { + Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle); + // + // chop off the begining part before the file system part... + // + ///@todo BlockIo? + Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, + &DevicePath, + &Handle); + if (!EFI_ERROR(Status)) { + // + // To access as a file system, the file path should only + // contain file path components. Follow the file path nodes + // and find the target file + // + for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath + ; !IsDevicePathEnd (&FilePathNode->Header) + ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header) + ){ + // + // For file system access each node should be a file path component + // + if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH || + DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP + ) { + Status = EFI_UNSUPPORTED; + break; + } + + // + // Open this file path node + // + Handle2 = Handle1; + Handle1 = NULL; + + // + // if this is the last node in the DevicePath always create (if that was requested). + // + if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) { + Status = Handle2->Open ( + Handle2, + &Handle1, + FilePathNode->PathName, + OpenMode, + Attributes + ); + } else { + + // + // This is not the last node and we dont want to 'create' existing + // directory entries... + // + + // + // open without letting it create + // prevents error on existing files/directories + // + Status = Handle2->Open ( + Handle2, + &Handle1, + FilePathNode->PathName, + OpenMode &~EFI_FILE_MODE_CREATE, + Attributes + ); + // + // if above failed now open and create the 'item' + // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above) + // + if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) { + Status = Handle2->Open ( + Handle2, + &Handle1, + FilePathNode->PathName, + OpenMode, + Attributes + ); + } + } + // + // Close the last node + // + Handle2->Close (Handle2); + + // + // If there's been an error, stop + // + if (EFI_ERROR (Status)) { + break; + } + } // for loop + } + } + if (EFI_ERROR(Status)) { + if (Handle1 != NULL) { + Handle1->Close(Handle1); + } + } else { + *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle)); + } + return (Status); +} + +/** + Creates a file or directory by name. + + This function creates an empty new file or directory with the specified attributes and + returns the new file's handle. If the file already exists and is read-only, then + EFI_INVALID_PARAMETER will be returned. + + If the file already existed, it is truncated and its attributes updated. If the file is + created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL. + + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + already exists and is non-volatile then EFI_INVALID_PARAMETER is returned. + + @param FileName Pointer to NULL-terminated file path + @param FileAttribs The new file's attrbiutes. the different attributes are + described in EFI_FILE_PROTOCOL.Open(). + @param FileHandle On return, points to the created file handle or directory's handle + + @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED could not open the file path + @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not + file the file system on the device. + @retval EFI_NO_MEDIA the device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the DirName. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +EfiShellCreateFile( + IN CONST CHAR16 *FileName, + IN UINT64 FileAttribs, + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + + // + // Is this for an environment variable + // do we start with >v + // + if (StrStr(FileName, L">v") == FileName) { + if (!IsVolatileEnv(FileName+2)) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = CreateFileInterfaceEnv(FileName+2); + return (EFI_SUCCESS); + } + + // + // We are opening a regular file. + // + DevicePath = EfiShellGetDevicePathFromFilePath(FileName); + if (DevicePath == NULL) { + return (EFI_NOT_FOUND); + } + + Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs); // 0 = no specific file attributes + FreePool(DevicePath); + + return(Status); +} + +/** + Opens a file or a directory by file name. + + This function opens the specified file in the specified OpenMode and returns a file + handle. + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then + EFI_INVALID_PARAMETER is returned. + + If the file name is >i, then the file handle which is returned refers to the standard + input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >o, then the file handle which is returned refers to the standard + output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >e, then the file handle which is returned refers to the standard + error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is NUL, then the file handle that is returned refers to the standard NUL + file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is + returned. + + If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the + FileHandle is NULL. + + @param FileName Points to the NULL-terminated UCS-2 encoded file name. + @param FileHandle On return, points to the file handle. + @param OpenMode File open mode. Either EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE from section 12.4 of the UEFI + Specification. + @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL. + @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL. + @retval EFI_NOT_FOUND The specified file could not be found on the device or the file + system could not be found on the device. FileHandle is NULL. + @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. FileHandle is NULL. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the FileName. FileHandle is NULL. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. FileHandle is NULL. + @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle + is NULL. + @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_STATUS Status; + + *FileHandle = NULL; + + // + // Is this for StdIn + // + if (StrCmp(FileName, L">i") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn; + ASSERT(*FileHandle != NULL); + return (EFI_SUCCESS); + } + + // + // Is this for StdOut + // + if (StrCmp(FileName, L">o") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_READ) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = &FileInterfaceStdOut; + return (EFI_SUCCESS); + } + + // + // Is this for NUL file + // + if (StrCmp(FileName, L"NUL") == 0) { + *FileHandle = &FileInterfaceNulFile; + return (EFI_SUCCESS); + } + + // + // Is this for StdErr + // + if (StrCmp(FileName, L">e") == 0) { + // + // make sure not writing to StdIn + // + if ((OpenMode & EFI_FILE_MODE_READ) != 0) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = &FileInterfaceStdErr; + return (EFI_SUCCESS); + } + + // + // Is this for an environment variable + // do we start with >v + // + if (StrStr(FileName, L">v") == FileName) { + if (!IsVolatileEnv(FileName+2) && + ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) { + return (EFI_INVALID_PARAMETER); + } + *FileHandle = CreateFileInterfaceEnv(FileName+2); + return (EFI_SUCCESS); + } + + // + // We are opening a regular file. + // + DevicePath = EfiShellGetDevicePathFromFilePath(FileName); +// DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath);); + if (DevicePath == NULL) { + return (EFI_NOT_FOUND); + } + + // + // Copy the device path, open the file, then free the memory + // + Status = InternalOpenFileDevicePath(DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes + FreePool(DevicePath); + + return(Status); +} + +/** + Deletes the file specified by the file name. + + This function deletes a file. + + @param FileName Points to the NULL-terminated file name. + + @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + @sa EfiShellCreateFile +**/ +EFI_STATUS +EFIAPI +EfiShellDeleteFileByName( + IN CONST CHAR16 *FileName + ) +{ + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + + // + // get a handle to the file + // + Status = EfiShellCreateFile(FileName, + 0, + &FileHandle); + if (EFI_ERROR(Status)) { + return (Status); + } + // + // now delete the file + // + return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle)); +} + +/** + Disables the page break output mode. +**/ +VOID +EFIAPI +EfiShellDisablePageBreak ( + VOID + ) +{ + ShellInfoObject.PageBreakEnabled = FALSE; +} + +/** + Enables the page break output mode. +**/ +VOID +EFIAPI +EfiShellEnablePageBreak ( + VOID + ) +{ + ShellInfoObject.PageBreakEnabled = TRUE; +} + +/** + internal worker function to load and run an image via device path. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param DevicePath device path of the file to execute + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + 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 StatusCode Points to the status code returned by the command. + + @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. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +EFIAPI +InternalShellExecuteDevicePath( + IN CONST EFI_HANDLE *ParentImageHandle, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST CHAR16 *CommandLine OPTIONAL, + IN CONST CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE NewHandle; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + LIST_ENTRY OrigEnvs; + EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol; + + if (ParentImageHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + InitializeListHead(&OrigEnvs); + + NewHandle = NULL; + + // + // Load the image with: + // FALSE - not from boot manager and NULL, 0 being not already in memory + // + Status = gBS->LoadImage( + FALSE, + *ParentImageHandle, + (EFI_DEVICE_PATH_PROTOCOL*)DevicePath, + NULL, + 0, + &NewHandle); + + if (EFI_ERROR(Status)) { + if (NewHandle != NULL) { + gBS->UnloadImage(NewHandle); + } + return (Status); + } + Status = gBS->OpenProtocol( + NewHandle, + &gEfiLoadedImageProtocolGuid, + (VOID**)&LoadedImage, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR(Status)) { + ASSERT(LoadedImage->LoadOptionsSize == 0); + if (CommandLine != NULL) { + LoadedImage->LoadOptionsSize = (UINT32)StrSize(CommandLine); + LoadedImage->LoadOptions = (VOID*)CommandLine; + } + + // + // Save our current environment settings for later restoration if necessary + // + if (Environment != NULL) { + Status = GetEnvironmentVariableList(&OrigEnvs); + if (!EFI_ERROR(Status)) { + Status = SetEnvironmentVariables(Environment); + } + } + + // + // Initialize and install a shell parameters protocol on the image. + // + ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn; + ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut; + ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr; + Status = UpdateArgcArgv(&ShellParamsProtocol, CommandLine, NULL, NULL); + ASSERT_EFI_ERROR(Status); + Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol); + ASSERT_EFI_ERROR(Status); + + ///@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... + // + if (!EFI_ERROR(Status)) { + if (StatusCode != NULL) { + *StatusCode = gBS->StartImage(NewHandle, NULL, NULL); + } else { + Status = gBS->StartImage(NewHandle, NULL, NULL); + } + } + + // + // Cleanup (and dont overwrite errors) + // + if (EFI_ERROR(Status)) { + gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol); + } else { + Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol); + ASSERT_EFI_ERROR(Status); + } + } + + if (!IsListEmpty(&OrigEnvs)) { + if (EFI_ERROR(Status)) { + SetEnvironmentVariableList(&OrigEnvs); + } else { + Status = SetEnvironmentVariableList(&OrigEnvs); + } + } + + return(Status); +} +/** + Execute the command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + + The CommandLine is executed from the current working directory on the current + device. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + 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 StatusCode Points to the status code returned by the command. + + @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. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. + @retval EFI_UNSUPPORTED The support level required for this function is not present. + + @sa InternalShellExecuteDevicePath +**/ +EFI_STATUS +EFIAPI +EfiShellExecute( + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ) +{ + EFI_STATUS Status; + CHAR16 *Temp; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + UINTN Size; + + if ((PcdGet8(PcdShellSupportLevel) < 1)) { + return (EFI_UNSUPPORTED); + } + + DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath); + + DEBUG_CODE_BEGIN(); + Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE); + FreePool(Temp); + Temp = gDevPathToText->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 ", 0); + StrnCatGrow(&Temp, &Size, CommandLine, 0); + + Status = InternalShellExecuteDevicePath( + ParentImageHandle, + DevPath, + Temp, + (CONST CHAR16**)Environment, + StatusCode); + + // + // de-allocate and return + // + FreePool(DevPath); + FreePool(Temp); + return(Status); +} + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +EFIAPI +InternalFreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ) +{ + if (FileListNode->Info != NULL) { + FreePool((VOID*)FileListNode->Info); + } + if (FileListNode->FileName != NULL) { + FreePool((VOID*)FileListNode->FileName); + } + if (FileListNode->FullName != NULL) { + FreePool((VOID*)FileListNode->FullName); + } + if (FileListNode->Handle != NULL) { + ShellInfoObject.NewEfiShellProtocol->CloseFile(FileListNode->Handle); + } + FreePool(FileListNode); +} +/** + Frees the file list. + + This function cleans up the file list and any related data structures. It has no + impact on the files themselves. + + @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is + defined in OpenFileList() + + @retval EFI_SUCCESS Free the file list successfully. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellFreeFileList( + IN EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_SHELL_FILE_INFO *ShellFileListItem; + + if (FileList == NULL || *FileList == NULL) { + return (EFI_INVALID_PARAMETER); + } + + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsListEmpty(&(*FileList)->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ){ + RemoveEntryList(&ShellFileListItem->Link); + InternalFreeShellFileInfoNode(ShellFileListItem); + } + return(EFI_SUCCESS); +} + +/** + Deletes the duplicate file names files in the given file list. + + This function deletes the reduplicate files in the given file list. + + @param FileList A pointer to the first entry in the file list. + + @retval EFI_SUCCESS Always success. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellRemoveDupInFileList( + IN EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_SHELL_FILE_INFO *ShellFileListItem; + EFI_SHELL_FILE_INFO *ShellFileListItem2; + + if (FileList == NULL || *FileList == NULL) { + return (EFI_INVALID_PARAMETER); + } + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ){ + for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem2->Link) + ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem2->Link) + ){ + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)ShellFileListItem->FullName, + (CHAR16*)ShellFileListItem2->FullName) == 0 + ){ + RemoveEntryList(&ShellFileListItem2->Link); + InternalFreeShellFileInfoNode(ShellFileListItem2); + } + } + } + return (EFI_SUCCESS); +} +/** + Allocates and duplicates a EFI_SHELL_FILE_INFO node. + + @param[in] Node The node to copy from. + @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise. + + @retval NULL a memory allocation error ocurred + @return != NULL a pointer to the new node +**/ +EFI_SHELL_FILE_INFO* +EFIAPI +InternalDuplicateShellFileInfo( + IN EFI_SHELL_FILE_INFO *Node, + IN BOOLEAN Save + ) +{ + EFI_SHELL_FILE_INFO *NewNode; + + NewNode = AllocatePool(sizeof(EFI_SHELL_FILE_INFO)); + if (NewNode == NULL) { + return (NULL); + } + NewNode->FullName = AllocateZeroPool(StrSize(Node->FullName)); + + NewNode->FileName = AllocateZeroPool(StrSize(Node->FileName)); + NewNode->Info = AllocatePool((UINTN)Node->Info->Size); + if ( NewNode->FullName == NULL + || NewNode->FileName == NULL + || NewNode->Info == NULL + ){ + return(NULL); + } + NewNode->Status = Node->Status; + NewNode->Handle = Node->Handle; + if (!Save) { + Node->Handle = NULL; + } + StrCpy((CHAR16*)NewNode->FullName, Node->FullName); + StrCpy((CHAR16*)NewNode->FileName, Node->FileName); + CopyMem(NewNode->Info, Node->Info, (UINTN)Node->Info->Size); + + return(NewNode); +} + +/** + Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation + failed it will return NULL. + + @param[in] BasePath the Path to prepend onto filename for FullPath + @param[in] Status Status member initial value. + @param[in] FullName FullName member initial value. + @param[in] FileName FileName member initial value. + @param[in] Handle Handle member initial value. + @param[in] Info Info struct to copy. + + @retval NULL An error ocurred. + @return a pointer to the newly allocated structure. +**/ +EFI_SHELL_FILE_INFO * +EFIAPI +CreateAndPopulateShellFileInfo( + IN CONST CHAR16 *BasePath, + IN CONST EFI_STATUS Status, + IN CONST CHAR16 *FullName, + IN CONST CHAR16 *FileName, + IN CONST SHELL_FILE_HANDLE Handle, + IN CONST EFI_FILE_INFO *Info + ) +{ + EFI_SHELL_FILE_INFO *ShellFileListItem; + CHAR16 *TempString; + UINTN Size; + + TempString = NULL; + Size = 0; + + ShellFileListItem = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + if (ShellFileListItem == NULL) { + return (NULL); + } + if (Info != NULL) { + ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size); + if (ShellFileListItem->Info == NULL) { + FreePool(ShellFileListItem); + return (NULL); + } + CopyMem(ShellFileListItem->Info, Info, (UINTN)Info->Size); + } else { + ShellFileListItem->Info = NULL; + } + if (FileName != NULL) { + ASSERT(TempString == NULL); + ShellFileListItem->FileName = StrnCatGrow(&TempString, 0, FileName, 0); + if (ShellFileListItem->FileName == NULL) { + FreePool(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } else { + ShellFileListItem->FileName = NULL; + } + Size = 0; + TempString = NULL; + if (BasePath != NULL) { + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + TempString = StrnCatGrow(&TempString, &Size, BasePath, 0); + if (TempString == NULL) { + FreePool((VOID*)ShellFileListItem->FileName); + FreePool(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } + if (ShellFileListItem->FileName != NULL) { + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + TempString = StrnCatGrow(&TempString, &Size, ShellFileListItem->FileName, 0); + if (TempString == NULL) { + FreePool((VOID*)ShellFileListItem->FileName); + FreePool(ShellFileListItem->Info); + FreePool(ShellFileListItem); + return (NULL); + } + } + + ShellFileListItem->FullName = TempString; + ShellFileListItem->Status = Status; + ShellFileListItem->Handle = Handle; + + return (ShellFileListItem); +} + +/** + Find all files in a specified directory. + + @param FileDirHandle Handle of the directory to search. + @param FileList On return, points to the list of files in the directory + or NULL if there are no files in the directory. + + @retval EFI_SUCCESS File information was returned successfully. + @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_NO_MEDIA The device media is not present. + @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory. + @return An error from FileHandleGetFileName(). +**/ +EFI_STATUS +EFIAPI +EfiShellFindFilesInDir( + IN SHELL_FILE_HANDLE FileDirHandle, + OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_SHELL_FILE_INFO *ShellFileList; + EFI_SHELL_FILE_INFO *ShellFileListItem; + EFI_FILE_INFO *FileInfo; + EFI_STATUS Status; + BOOLEAN NoFile; + CHAR16 *TempString; + CHAR16 *BasePath; + UINTN Size; + CHAR16 *TempSpot; + + Status = FileHandleGetFileName(FileDirHandle, &BasePath); + if (EFI_ERROR(Status)) { + return (Status); + } + + if (ShellFileHandleGetPath(FileDirHandle) != NULL) { + TempString = NULL; + Size = 0; + TempString = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0); + TempSpot = StrStr(TempString, L";"); + + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + + TempString = StrnCatGrow(&TempString, &Size, BasePath, 0); + BasePath = TempString; + } + + NoFile = FALSE; + ShellFileList = NULL; + ShellFileListItem = NULL; + FileInfo = NULL; + Status = EFI_SUCCESS; + + + for ( Status = FileHandleFindFirstFile(FileDirHandle, &FileInfo) + ; !EFI_ERROR(Status) && !NoFile + ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile) + ){ + TempString = NULL; + Size = 0; + // + // allocate a new EFI_SHELL_FILE_INFO and populate it... + // + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + TempString = StrnCatGrow(&TempString, &Size, BasePath, 0); + TempString = StrnCatGrow(&TempString, &Size, FileInfo->FileName, 0); + ShellFileListItem = CreateAndPopulateShellFileInfo( + BasePath, + EFI_SUCCESS, // success since we didnt fail to open it... + TempString, + FileInfo->FileName, + NULL, // no handle since not open + FileInfo); + + if (ShellFileList == NULL) { + ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + ASSERT(ShellFileList != NULL); + InitializeListHead(&ShellFileList->Link); + } + InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link); + } + if (EFI_ERROR(Status)) { + EfiShellFreeFileList(&ShellFileList); + *FileList = NULL; + } else { + *FileList = ShellFileList; + } + SHELL_FREE_NON_NULL(BasePath); + return(Status); +} + +/** + Updates a file name to be preceeded by the mapped drive name + + @param[in] BasePath the Mapped drive name to prepend + @param[in,out] Path pointer to pointer to the file name to update. + + @retval EFI_SUCCESS + @retval EFI_OUT_OF_RESOURCES +**/ +EFI_STATUS +EFIAPI +UpdateFileName( + IN CONST CHAR16 *BasePath, + IN OUT CHAR16 **Path + ) +{ + CHAR16 *Path2; + UINTN Path2Size; + + Path2Size = 0; + Path2 = NULL; + + ASSERT(Path != NULL); + ASSERT(*Path != NULL); + ASSERT(BasePath != NULL); + + // + // convert a local path to an absolute path + // + if (StrStr(*Path, L":") == NULL) { + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, BasePath, 0); + if (Path2 == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, (*Path)[0] == L'\\'?(*Path) + 1 :*Path, 0); + if (Path2 == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + } + + FreePool(*Path); + (*Path) = Path2; + + return (EFI_SUCCESS); +} + +/** + If FileHandle is a directory then the function reads from FileHandle and reads in + each of the FileInfo structures. If one of them matches the Pattern's first + "level" then it opens that handle and calls itself on that handle. + + 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. + + @param[in] FilePattern The FilePattern to check against. + @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure + @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. + + @retval EFI_SUCCESS all files were found and the FileList contains a list. + @retval EFI_NOT_FOUND no files were found + @retval EFI_OUT_OF_RESOURCES a memory allocation failed +**/ +EFI_STATUS +EFIAPI +ShellSearchHandle( + IN CONST CHAR16 *FilePattern, + 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 + ) +{ + EFI_STATUS Status; + CONST CHAR16 *NextFilePatternStart; + CHAR16 *CurrentFilePattern; + EFI_SHELL_FILE_INFO *ShellInfo; + EFI_SHELL_FILE_INFO *ShellInfoNode; + EFI_SHELL_FILE_INFO *NewShellNode; + BOOLEAN Directory; + + if ( FilePattern == NULL + || UnicodeCollation == NULL + || FileList == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + ShellInfo = NULL; + CurrentFilePattern = NULL; + + if (*FilePattern == L'\\') { + FilePattern++; + } + + for( NextFilePatternStart = FilePattern + ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\' + ; NextFilePatternStart++); + + CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16)); + ASSERT(CurrentFilePattern != NULL); + StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern); + + if (CurrentFilePattern[0] == CHAR_NULL + &&NextFilePatternStart[0] == CHAR_NULL + ){ + // + // Add the current parameter FileHandle to the list, then end... + // + if (ParentNode == NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE); + if (NewShellNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + NewShellNode->Handle = NULL; + if (*FileList == NULL) { + *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO)); + InitializeListHead(&((*FileList)->Link)); + } + + // + // Add to the returning to use list + // + InsertTailList(&(*FileList)->Link, &NewShellNode->Link); + + Status = EFI_SUCCESS; + } + } + } else { + Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo); + + if (!EFI_ERROR(Status)){ + if (StrStr(NextFilePatternStart, L"\\") != NULL){ + Directory = TRUE; + } else { + Directory = FALSE; + } + for ( ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ShellInfo->Link) + ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link) + ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link) + ){ + if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){ + if (Directory){ + // + // should be a directory + // + + // + // don't open the . and .. directories + // + if ( (StrCmp(ShellInfoNode->FileName, L".") != 0) + && (StrCmp(ShellInfoNode->FileName, L"..") != 0) + ){ + // + // + // + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + break; + } + // + // Open the directory since we need that handle in the next recursion. + // + ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ); + + // + // recurse with the next part of the pattern + // + Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode); + } + } else { + // + // should be a file + // + + // + // copy the information we need into a new Node + // + NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE); + ASSERT(NewShellNode != NULL); + if (NewShellNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } + if (*FileList == NULL) { + *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO)); + InitializeListHead(&((*FileList)->Link)); + } + + // + // Add to the returning to use list + // + InsertTailList(&(*FileList)->Link, &NewShellNode->Link); + } + } + if (EFI_ERROR(Status)) { + break; + } + } + if (EFI_ERROR(Status)) { + EfiShellFreeFileList(&ShellInfo); + } else { + Status = EfiShellFreeFileList(&ShellInfo); + } + } + } + + FreePool(CurrentFilePattern); + return (Status); +} + +/** + Find files that match a specified pattern. + + This function searches for all files and directories that match the specified + FilePattern. The FilePattern can contain wild-card characters. The resulting file + information is placed in the file list FileList. + + Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. + + The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo + field is set to NULL. + + if *FileList is not NULL then it must be a pre-existing and properly initialized list. + + @param FilePattern Points to a NULL-terminated shell file path, including wildcards. + @param FileList On return, points to the start of a file list containing the names + of all matching files or else points to NULL if no matching files + were found. only on a EFI_SUCCESS return will; this be non-NULL. + + @retval EFI_SUCCESS Files found. FileList is a valid list. + @retval EFI_NOT_FOUND No files found. + @retval EFI_NO_MEDIA The device has no media + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted +**/ +EFI_STATUS +EFIAPI +EfiShellFindFiles( + IN CONST CHAR16 *FilePattern, + OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_STATUS Status; + CHAR16 *PatternCopy; + CHAR16 *PatternCurrentLocation; + EFI_DEVICE_PATH_PROTOCOL *RootDevicePath; + SHELL_FILE_HANDLE RootFileHandle; + CHAR16 *MapName; + UINTN Count; + + if ( FilePattern == NULL + || FileList == NULL + || StrStr(FilePattern, L":") == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + Status = EFI_SUCCESS; + RootDevicePath = NULL; + RootFileHandle = NULL; + MapName = NULL; + PatternCopy = AllocatePool(StrSize(FilePattern)); + if (PatternCopy == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + StrCpy(PatternCopy, FilePattern); + + PatternCopy = CleanPath(PatternCopy); + + Count = StrStr(PatternCopy, L":") - PatternCopy; + Count += 2; + + ASSERT(MapName == NULL); + MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count); + + if (!EFI_ERROR(Status)) { + RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy); + if (RootDevicePath == NULL) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = EfiShellOpenRoot(RootDevicePath, &RootFileHandle); + if (!EFI_ERROR(Status)) { + for ( PatternCurrentLocation = PatternCopy + ; *PatternCurrentLocation != ':' + ; PatternCurrentLocation++); + PatternCurrentLocation++; + Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL); + } + FreePool(RootDevicePath); + } + } + + if (PatternCopy != NULL) { + FreePool(PatternCopy); + } + if (MapName != NULL) { + FreePool(MapName); + } + + return(Status); +} + +/** + Opens the files that match the path specified. + + This function opens all of the files specified by Path. Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each + matching file has an EFI_SHELL_FILE_INFO structure created in a linked list. + + @param Path A pointer to the path string. + @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE. + @param FileList Points to the start of a list of files opened. + + @retval EFI_SUCCESS Create the file list successfully. + @return Others Can't create the file list. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileList( + IN CHAR16 *Path, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **FileList + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *ShellFileListItem; + CHAR16 *Path2; + UINTN Path2Size; + CONST CHAR16 *CurDir; + + ShellCommandCleanPath(Path); + + Path2Size = 0; + Path2 = NULL; + + ASSERT(FileList != NULL); + ASSERT(*FileList != NULL); + + if (*Path == L'.' && *(Path+1) == L'\\') { + Path++; + } + + // + // convert a local path to an absolute path + // + if (StrStr(Path, L":") == NULL) { + CurDir = EfiShellGetCurDir(NULL); + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, CurDir, 0); + if (*Path == L'\\') { + Path++; + } + ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL)); + StrnCatGrow(&Path2, &Path2Size, Path, 0); + } else { + ASSERT(Path2 == NULL); + StrnCatGrow(&Path2, NULL, Path, 0); + } + + CleanPath (Path2); + + // + // do the search + // + Status = EfiShellFindFiles(Path2, FileList); + + FreePool(Path2); + + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // We had no errors so open all the files (that are not already opened...) + // + for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link) + ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link) + ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link) + ){ + if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) { + ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode); + } + } + + return(EFI_SUCCESS); +} + +/** + This function updated with errata. + + Gets either a single or list of environment variables. + + If name is not NULL then this function returns the current value of the specified + environment variable. + + If Name is NULL, then a list of all environment variable names is returned. Each is a + NULL terminated string with a double NULL terminating the list. + + @param Name A pointer to the environment variable name. If + Name is NULL, then the function will return all + of the defined shell environment variables. In + the case where multiple environment variables are + being returned, each variable will be terminated by + a NULL, and the list will be terminated by a double + NULL. + + @return !=NULL A pointer to the returned string. + The returned pointer does not need to be freed by the caller. + + @retval NULL The environment variable doesn't exist or there are + no environment variables. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetEnv( + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + VOID *Buffer; + UINTN Size; + LIST_ENTRY List; + ENV_VAR_LIST *Node; + CHAR16 *CurrentWriteLocation; + + Size = 0; + Buffer = NULL; + + if (Name == NULL) { + // + // Get all our environment variables + // + InitializeListHead(&List); + Status = GetEnvironmentVariableList(&List); + if (EFI_ERROR(Status)){ + return (NULL); + } + + // + // Build the semi-colon delimited list. (2 passes) + // + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List) + ; !IsNull(&List, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link) + ){ + ASSERT(Node->Key != NULL); + Size += StrSize(Node->Key); + } + + Size += 2*sizeof(CHAR16); + + Buffer = AllocateZeroPool(Size); + CurrentWriteLocation = (CHAR16*)Buffer; + + for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List) + ; !IsNull(&List, &Node->Link) + ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link) + ){ + ASSERT(Node->Key != NULL); + StrCpy(CurrentWriteLocation, Node->Key); + CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1; + } + + // + // Free the list... + // + FreeEnvironmentVariableList(&List); + } else { + // + // We are doing a specific environment variable + // + + // + // get the size we need for this EnvVariable + // + Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the space and recall the get function + // + Buffer = AllocateZeroPool(Size); + ASSERT(Buffer != NULL); + Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer); + } + // + // we didnt get it (might not exist) + // free the memory if we allocated any and return NULL + // + if (EFI_ERROR(Status)) { + if (Buffer != NULL) { + FreePool(Buffer); + } + return (NULL); + } + } + + // + // return the buffer + // + return (AddBufferToFreeList(Buffer)); +} + +/** + Internal variable setting function. Allows for setting of the read only variables. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +InternalEfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ) +{ + if (Value == NULL || StrLen(Value) == 0) { + return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name)); + } else { + SHELL_DELETE_ENVIRONMENT_VARIABLE(Name); + if (Volatile) { + return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name, StrSize(Value), Value)); + } else { + return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name, StrSize(Value), Value)); + } + } +} + +/** + Sets the environment variable. + + This function changes the current value of the specified environment variable. If the + environment variable exists and the Value is an empty string, then the environment + variable is deleted. If the environment variable exists and the Value is not an empty + string, then the value of the environment variable is changed. If the environment + variable does not exist and the Value is an empty string, there is no action. If the + environment variable does not exist and the Value is a non-empty string, then the + environment variable is created and assigned the specified value. + + For a description of volatile and non-volatile environment variables, see UEFI Shell + 2.0 specification section 3.6.1. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +EfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ) +{ + if (Name == NULL || *Name == CHAR_NULL) { + return (EFI_INVALID_PARAMETER); + } + // + // Make sure we dont 'set' a predefined read only variable + // + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"cwd") == 0 + ||gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"Lasterror") == 0 + ||gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"profiles") == 0 + ||gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"uefishellsupport") == 0 + ||gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"uefishellversion") == 0 + ||gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Name, + L"uefiversion") == 0 + ){ + return (EFI_INVALID_PARAMETER); + } + return (InternalEfiShellSetEnv(Name, Value, Volatile)); +} + +/** + Returns the current directory on the specified device. + + If FileSystemMapping is NULL, it returns the current working directory. If the + FileSystemMapping is not NULL, it returns the current directory associated with the + FileSystemMapping. In both cases, the returned name includes the file system + mapping (i.e. fs0:\current-dir). + + @param FileSystemMapping A pointer to the file system mapping. If NULL, + then the current working directory is returned. + + @retval !=NULL The current directory. + @retval NULL Current directory does not exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetCurDir( + IN CONST CHAR16 *FileSystemMapping OPTIONAL + ) +{ + CHAR16 *PathToReturn; + UINTN Size; + SHELL_MAP_LIST *MapListItem; + if (!IsListEmpty(&gShellMapList.Link)) { + // + // if parameter is NULL, use current + // + if (FileSystemMapping == NULL) { + return (EfiShellGetEnv(L"cwd")); + } else { + Size = 0; + PathToReturn = NULL; + MapListItem = ShellCommandFindMapItem(FileSystemMapping); + if (MapListItem != NULL) { + ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL)); + PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->MapName, 0); + PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0); + } + } + return (AddBufferToFreeList(PathToReturn)); + } else { + return (NULL); + } +} + +/** + Changes the current directory on the specified device. + + If the FileSystem is NULL, and the directory Dir does not contain a file system's + mapped name, this function changes the current working directory. + + If the FileSystem is NULL and the directory Dir contains a mapped name, then the + current file system and the current directory on that file system are changed. + + If FileSystem is NULL, and Dir is not NULL, then this changes the current working file + system. + + If FileSystem is not NULL and Dir is not NULL, then this function changes the current + directory on the specified file system. + + If the current working directory or the current working file system is changed then the + %cwd% environment variable will be updated + + @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working + directory is changed. + @param Dir Points to the NULL-terminated directory on the device specified by FileSystem. + + @retval EFI_SUCCESS The operation was sucessful + @retval EFI_NOT_FOUND The file system could not be found +**/ +EFI_STATUS +EFIAPI +EfiShellSetCurDir( + IN CONST CHAR16 *FileSystem OPTIONAL, + IN CONST CHAR16 *Dir + ) +{ + CHAR16 *MapName; + SHELL_MAP_LIST *MapListItem; + UINTN Size; + EFI_STATUS Status; + CHAR16 *TempString; + CHAR16 *DirectoryName; + UINTN TempLen; + + Size = 0; + MapName = NULL; + MapListItem = NULL; + TempString = NULL; + DirectoryName = NULL; + + if (FileSystem == NULL && Dir == NULL) { + return (EFI_INVALID_PARAMETER); + } + + if (IsListEmpty(&gShellMapList.Link)){ + return (EFI_NOT_FOUND); + } + + DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0); + ASSERT(DirectoryName != NULL); + + CleanPath(DirectoryName); + + if (FileSystem == NULL) { + // + // determine the file system mapping to use + // + if (StrStr(DirectoryName, L":") != NULL) { + ASSERT(MapName == NULL); + MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1)); + } + // + // find the file system mapping's entry in the list + // or use current + // + if (MapName != NULL) { + MapListItem = ShellCommandFindMapItem(MapName); + + // + // make that the current file system mapping + // + if (MapListItem != NULL) { + gShellCurDir = MapListItem; + } + } else { + MapListItem = gShellCurDir; + } + + if (MapListItem == NULL) { + return (EFI_NOT_FOUND); + } + + // + // now update the MapListItem's current directory + // + if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') { + FreePool(MapListItem->CurrentDirectoryPath); + MapListItem->CurrentDirectoryPath = NULL; + } + if (MapName != NULL) { + TempLen = StrLen(MapName); + if (TempLen != StrLen(DirectoryName)) { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0); + } + } else { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); + } + if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + } + } else { + // + // cant have a mapping in the directory... + // + if (StrStr(DirectoryName, L":") != NULL) { + return (EFI_INVALID_PARAMETER); + } + // + // FileSystem != NULL + // + MapListItem = ShellCommandFindMapItem(FileSystem); + if (MapListItem == NULL) { + return (EFI_INVALID_PARAMETER); + } +// gShellCurDir = MapListItem; + if (DirectoryName != NULL) { + // + // change current dir on that file system + // + + if (MapListItem->CurrentDirectoryPath != NULL) { + FreePool(MapListItem->CurrentDirectoryPath); + DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;); + } +// ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); +// MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0); + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0); + if (MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') { + ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL)); + MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0); + } + } + } + // + // if updated the current directory then update the environment variable + // + if (MapListItem == gShellCurDir) { + Size = 0; + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0); + ASSERT((TempString == NULL && Size == 0) || (TempString != NULL)); + StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0); + Status = InternalEfiShellSetEnv(L"cwd", TempString, TRUE); + FreePool(TempString); + return (Status); + } + return(EFI_SUCCESS); +} + +/** + Return help information about a specific command. + + This function returns the help information for the specified command. The help text + can be internal to the shell or can be from a UEFI Shell manual page. + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param Command Points to the NULL-terminated UEFI Shell command name. + @param Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +EfiShellGetHelpText( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **HelpText + ) +{ + CONST CHAR16 *ManFileName; + + ASSERT(HelpText != NULL); + + ManFileName = ShellCommandGetManFileNameHandler(Command); + + if (ManFileName != NULL) { + return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText)); + } else { + return (ProcessManFile(Command, Command, Sections, NULL, HelpText)); + } +} + +/** + Gets the enable status of the page break output mode. + + User can use this function to determine current page break mode. + + @retval TRUE The page break output mode is enabled. + @retval FALSE The page break output mode is disabled. +**/ +BOOLEAN +EFIAPI +EfiShellGetPageBreak( + VOID + ) +{ + return(ShellInfoObject.PageBreakEnabled); +} + +/** + Judges whether the active shell is the root shell. + + This function makes the user to know that whether the active Shell is the root shell. + + @retval TRUE The active Shell is the root Shell. + @retval FALSE The active Shell is NOT the root Shell. +**/ +BOOLEAN +EFIAPI +EfiShellIsRootShell( + VOID + ) +{ + return(ShellInfoObject.RootShellInstance); +} + +/** + function to return a semi-colon delimeted list of all alias' in the current shell + + up to caller to free the memory. + + @retval NULL No alias' were found + @retval NULL An error ocurred getting alias' + @return !NULL a list of all alias' +**/ +CHAR16 * +EFIAPI +InternalEfiShellGetListAlias( + ) +{ + UINT64 MaxStorSize; + UINT64 RemStorSize; + UINT64 MaxVarSize; + EFI_STATUS Status; + EFI_GUID Guid; + CHAR16 *VariableName; + UINTN NameSize; + CHAR16 *RetVal; + UINTN RetSize; + CHAR16 *Alias; + + Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize); + ASSERT_EFI_ERROR(Status); + + VariableName = AllocateZeroPool((UINTN)MaxVarSize); + RetSize = 0; + RetVal = NULL; + + VariableName[0] = CHAR_NULL; + + while (TRUE) { + NameSize = (UINTN)MaxVarSize; + Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid); + if (Status == EFI_NOT_FOUND){ + break; + } + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + break; + } + if (CompareGuid(&Guid, &gShellAliasGuid)){ + Alias = GetVariable(VariableName, &gShellAliasGuid); + ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL)); + RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0); + RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0); + } // compare guid + } // while + FreePool(VariableName); + + return (RetVal); +} + +/** + This function returns the command associated with a alias or a list of all + alias'. + + @param[in] Alias Points to the NULL-terminated shell alias. + If this parameter is NULL, then all + aliases will be returned in ReturnedData. + @param[out] Volatile upon return of a single command if TRUE indicates + this is stored in a volatile fashion. FALSE otherwise. + + @return If Alias is not NULL, it will return a pointer to + the NULL-terminated command for that alias. + If Alias is NULL, ReturnedData points to a ';' + delimited list of alias (e.g. + ReturnedData = "dir;del;copy;mfp") that is NULL-terminated. + @retval NULL an error ocurred + @retval NULL Alias was not a valid Alias +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetAlias( + IN CONST CHAR16 *Alias, + OUT BOOLEAN *Volatile OPTIONAL + ) +{ + CHAR16 *RetVal; + UINTN RetSize; + UINT32 Attribs; + EFI_STATUS Status; + + if (Alias != NULL) { + if (Volatile == NULL) { + return (AddBufferToFreeList(GetVariable((CHAR16*)Alias, &gShellAliasGuid))); + } + RetSize = 0; + RetVal = NULL; + Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal); + if (Status == EFI_BUFFER_TOO_SMALL) { + RetVal = AllocateZeroPool(RetSize); + Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal); + } + if (EFI_ERROR(Status)) { + if (RetVal != NULL) { + FreePool(RetVal); + } + return (NULL); + } + if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) { + *Volatile = FALSE; + } else { + *Volatile = TRUE; + } + + return (AddBufferToFreeList(RetVal)); + } + return (AddBufferToFreeList(InternalEfiShellGetListAlias())); +} + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + this function does not check for built in alias'. + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found +**/ +EFI_STATUS +EFIAPI +InternalSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias, + IN BOOLEAN Volatile + ) +{ + // + // We must be trying to remove one if Alias is NULL + // + if (Alias == NULL) { + // + // remove an alias (but passed in COMMAND parameter) + // + return (gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL)); + } else { + // + // Add and replace are the same + // + + // We dont check the error return on purpose since the variable may not exist. + gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL); + + return (gRT->SetVariable((CHAR16*)Alias, &gShellAliasGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS|(Volatile?0:EFI_VARIABLE_NON_VOLATILE), StrSize(Command), (VOID*)Command)); + } +} + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If + FALSE and the alias already exists, then the existing alias is unchanged and + EFI_ACCESS_DENIED is returned. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found + @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to + FALSE. +**/ +EFI_STATUS +EFIAPI +EfiShellSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias, + IN BOOLEAN Replace, + IN BOOLEAN Volatile + ) +{ + // + // cant set over a built in alias + // + if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) { + return (EFI_ACCESS_DENIED); + } + if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) { + return (EFI_INVALID_PARAMETER); + } + + if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) { + return (EFI_ACCESS_DENIED); + } + + return (InternalSetAlias(Command, Alias, Volatile)); +} + +// Pure FILE_HANDLE operations are passed to FileHandleLib +// these functions are indicated by the * +EFI_SHELL_PROTOCOL mShellProtocol = { + EfiShellExecute, + EfiShellGetEnv, + EfiShellSetEnv, + EfiShellGetAlias, + EfiShellSetAlias, + EfiShellGetHelpText, + EfiShellGetDevicePathFromMap, + EfiShellGetMapFromDevicePath, + EfiShellGetDevicePathFromFilePath, + EfiShellGetFilePathFromDevicePath, + EfiShellSetMap, + EfiShellGetCurDir, + EfiShellSetCurDir, + EfiShellOpenFileList, + EfiShellFreeFileList, + EfiShellRemoveDupInFileList, + EfiShellBatchIsActive, + EfiShellIsRootShell, + EfiShellEnablePageBreak, + EfiShellDisablePageBreak, + EfiShellGetPageBreak, + EfiShellGetDeviceName, + (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, //* + (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, //* + EfiShellOpenFileByName, + EfiShellClose, + EfiShellCreateFile, + (EFI_SHELL_READ_FILE)FileHandleRead, //* + (EFI_SHELL_WRITE_FILE)FileHandleWrite, //* + (EFI_SHELL_DELETE_FILE)FileHandleDelete, //* + EfiShellDeleteFileByName, + (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, //* + (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, //* + (EFI_SHELL_FLUSH_FILE)FileHandleFlush, //* + EfiShellFindFiles, + EfiShellFindFilesInDir, + (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, //* + EfiShellOpenRoot, + EfiShellOpenRootByHandle, + NULL, + SHELL_MAJOR_VERSION, + SHELL_MINOR_VERSION +}; + +/** + Function to create and install on the current handle. + + Will overwrite any existing ShellProtocols in the system to be sure that + the current shell is in control. + + This must be removed via calling CleanUpShellProtocol(). + + @param[in,out] NewShell The pointer to the pointer to the structure + to install. + + @retval EFI_SUCCESS The operation was successful. + @return An error from LocateHandle, CreateEvent, or other core function. +**/ +EFI_STATUS +EFIAPI +CreatePopulateInstallShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL **NewShell + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HANDLE *Buffer; + UINTN HandleCounter; + SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode; + + 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); + + // + // Get the size of the buffer we need. + // + Status = gBS->LocateHandle(ByProtocol, + &gEfiShellProtocolGuid, + NULL, + &BufferSize, + Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate and recall with buffer of correct size + // + Buffer = AllocateZeroPool(BufferSize); + ASSERT(Buffer != NULL); + Status = gBS->LocateHandle(ByProtocol, + &gEfiShellProtocolGuid, + NULL, + &BufferSize, + Buffer); + ASSERT_EFI_ERROR(Status); + // + // now overwrite each of them, but save the info to restore when we end. + // + for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) { + OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST)); + ASSERT(OldProtocolNode != NULL); + Status = gBS->OpenProtocol(Buffer[HandleCounter], + &gEfiShellProtocolGuid, + (VOID **) &(OldProtocolNode->Interface), + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + // + // reinstall over the old one... + // + OldProtocolNode->Handle = Buffer[HandleCounter]; + Status = gBS->ReinstallProtocolInterface( + OldProtocolNode->Handle, + &gEfiShellProtocolGuid, + OldProtocolNode->Interface, + (VOID*)(*NewShell)); + if (!EFI_ERROR(Status)) { + // + // we reinstalled sucessfully. log this so we can reverse it later. + // + + // + // add to the list for subsequent... + // + InsertTailList(&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link); + } + } + } + FreePool(Buffer); + } else if (Status == EFI_NOT_FOUND) { + ASSERT(IsListEmpty(&ShellInfoObject.OldShellList.Link)); + // + // no one else published yet. just publish it ourselves. + // + Status = gBS->InstallProtocolInterface ( + &gImageHandle, + &gEfiShellProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID*)(*NewShell)); + } + + if (PcdGetBool(PcdShellSupportOldProtocols)){ + ///@todo support ShellEnvironment2 + ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also? + } + + return (Status); +} + +/** + Opposite of CreatePopulateInstallShellProtocol. + + Free all memory and restore the system to the state it was in before calling + CreatePopulateInstallShellProtocol. + + @param[in,out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +CleanUpShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ) +{ + EFI_STATUS Status; + SHELL_PROTOCOL_HANDLE_LIST *Node2; + + // + // if we need to restore old protocols... + // + if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) { + for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link) + ; !IsListEmpty (&ShellInfoObject.OldShellList.Link) + ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link) + ){ + RemoveEntryList(&Node2->Link); + Status = gBS->ReinstallProtocolInterface(Node2->Handle, + &gEfiShellProtocolGuid, + NewShell, + Node2->Interface); + ASSERT_EFI_ERROR(Status); + FreePool(Node2); + } + } else { + // + // no need to restore + // + Status = gBS->UninstallProtocolInterface(gImageHandle, + &gEfiShellProtocolGuid, + NewShell); + ASSERT_EFI_ERROR(Status); + } + Status = gBS->CloseEvent(NewShell->ExecutionBreak); + + return (Status); +} + + diff --git a/ShellPkg/Application/Shell/ShellProtocol.h b/ShellPkg/Application/Shell/ShellProtocol.h new file mode 100644 index 0000000000..d03a382f6d --- /dev/null +++ b/ShellPkg/Application/Shell/ShellProtocol.h @@ -0,0 +1,950 @@ +/** @file + Member functions of EFI_SHELL_PROTOCOL and functions for creation, + manipulation, and initialization of EFI_SHELL_PROTOCOL. + + Copyright (c) 2009 - 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_PROTOCOL_HEADER_ +#define _SHELL_PROTOCOL_HEADER_ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FileHandleWrappers.h" +#include "ShellEnvVar.h" +#include "ShellManParser.h" + +typedef struct { + LIST_ENTRY Link; + EFI_SHELL_PROTOCOL *Interface; + EFI_HANDLE Handle; +} SHELL_PROTOCOL_HANDLE_LIST; + +// flags values... +#define SHELL_MAP_FLAGS_CONSIST BIT1 + +/** + Function to create and install on the current handle. + + Will overwrite any existing ShellProtocols in the system to be sure that + the current shell is in control. + + This must be removed via calling CleanUpShellProtocol(). + + @param[in,out] NewShell The pointer to the pointer to the structure + to install. + + @retval EFI_SUCCESS The operation was successful. + @return An error from LocateHandle, CreateEvent, or other core function. +**/ +EFI_STATUS +EFIAPI +CreatePopulateInstallShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL **NewShell + ); + +/** + Opposite of CreatePopulateInstallShellProtocol. + + Free all memory and restore the system to the state it was in before calling + CreatePopulateInstallShellProtocol. + + @param[in,out] NewShell The pointer to the new shell protocol structure. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +CleanUpShellProtocol ( + IN OUT EFI_SHELL_PROTOCOL *NewShell + ); + +/** + This function creates a mapping for a device path. + + @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping, + then the mapping will be deleted. + @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':' + + @retval EFI_SUCCESS Mapping created or deleted successfully. + @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the + boot service function LocateDevicePath(). + @retval EFI_ACCESS_DENIED The mapping is a built-in alias. + @retval EFI_INVALID_PARAMETER Mapping was NULL + @retval EFI_INVALID_PARAMETER Mapping did not end with a ':' + @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed. + @retval EFI_NOT_FOUND There was no mapping found to delete + @retval EFI_OUT_OF_RESOURCES Memory allocation failed +**/ +EFI_STATUS +EFIAPI +EfiShellSetMap( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, + IN CONST CHAR16 *Mapping + ); + +/** + Gets the device path from the mapping. + + This function gets the device path associated with a mapping. + + @param Mapping A pointer to the mapping + + @retval !=NULL Pointer to the device path that corresponds to the + device mapping. The returned pointer does not need + to be freed. + @retval NULL There is no device path associated with the + specified mapping. +**/ +CONST EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromMap( + IN CONST CHAR16 *Mapping + ); + +/** + Gets the mapping that most closely matches the device path. + + This function gets the mapping which corresponds to the device path *DevicePath. If + there is no exact match, then the mapping which most closely matches *DevicePath + is returned, and *DevicePath is updated to point to the remaining portion of the + device path. If there is an exact match, the mapping is returned and *DevicePath + points to the end-of-device-path node. + + @param DevicePath On entry, points to a device path pointer. On + exit, updates the pointer to point to the + portion of the device path after the mapping. + + @retval NULL No mapping was found. + @return !=NULL Pointer to NULL-terminated mapping. The buffer + is callee allocated and should be freed by the caller. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetMapFromDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +/** + Converts a device path to a file system-style path. + + This function converts a device path to a file system path by replacing part, or all, of + the device path with the file-system mapping. If there are more than one application + file system mappings, the one that most closely matches Path will be used. + + @param Path The pointer to the device path + + @retval NULL the device path could not be found. + @return all The pointer of the NULL-terminated file path. The path + is callee-allocated and should be freed by the caller. +**/ +CHAR16 * +EFIAPI +EfiShellGetFilePathFromDevicePath( + IN CONST EFI_DEVICE_PATH_PROTOCOL *Path + ); + +/** + Converts a file system style name to a device path. + + This function converts a file system style name to a device path, by replacing any + mapping references to the associated device path. + + @param Path the pointer to the path + + @return all The pointer of the file path. The file path is callee + allocated and should be freed by the caller. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +EfiShellGetDevicePathFromFilePath( + IN CONST CHAR16 *Path + ); + +/** + Gets the name of the device specified by the device handle. + + This function gets the user-readable name of the device specified by the device + handle. If no user-readable name could be generated, then *BestDeviceName will be + NULL and EFI_NOT_FOUND will be returned. + + If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the + device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on + DeviceHandle. + + If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the + device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle. + If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and + EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then + EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority. + + @param DeviceHandle The handle of the device. + @param Flags Determines the possible sources of component names. + Valid bits are: + EFI_DEVICE_NAME_USE_COMPONENT_NAME + EFI_DEVICE_NAME_USE_DEVICE_PATH + @param Language A pointer to the language specified for the device + name, in the same format as described in the UEFI + specification, Appendix M + @param BestDeviceName On return, points to the callee-allocated NULL- + terminated name of the device. If no device name + could be found, points to NULL. The name must be + freed by the caller... + + @retval EFI_SUCCESS Get the name successfully. + @retval EFI_NOT_FOUND Fail to get the device name. + @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set. + @retval EFI_INVALID_PARAMETER BestDeviceName was NULL + @retval EFI_INVALID_PARAMETER DeviceHandle was NULL +**/ +EFI_STATUS +EFIAPI +EfiShellGetDeviceName( + IN EFI_HANDLE DeviceHandle, + IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, + IN CHAR8 *Language, + OUT CHAR16 **BestDeviceName + ); + +/** + Opens the root directory of a device on a handle + + This function opens the root directory of a device and returns a file handle to it. + + @param DeviceHandle The handle of the device that contains the volume. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + 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 +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRootByHandle( + IN EFI_HANDLE DeviceHandle, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Opens the root directory of a device. + + This function opens the root directory of a device and returns a file handle to it. + + @param DevicePath Points to the device path corresponding to the device where the + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed. + @param FileHandle On exit, points to the file handle corresponding to the root directory on the + device. + + @retval EFI_SUCCESS Root opened successfully. + @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory + 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 +**/ +EFI_STATUS +EFIAPI +EfiShellOpenRoot( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Returns whether any script files are currently being processed. + + @retval TRUE There is at least one script file active. + @retval FALSE No script files are active now. + +**/ +BOOLEAN +EFIAPI +EfiShellBatchIsActive ( + VOID + ); + +/** + Worker function to open a file based on a device path. this will open the root + of the volume and then traverse down to the file itself. + + @param DevicePath2 Device Path of the file + @param FileHandle Pointer to the file upon a successful return + @param OpenMode mode to open file in. + @param Attributes the File Attributes to use when creating a new file + + @retval EFI_SUCCESS the file is open and FileHandle is valid + @retval EFI_UNSUPPORTED the device path cotained non-path elements + @retval other an error ocurred. +**/ +EFI_STATUS +EFIAPI +InternalOpenFileDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath2, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes OPTIONAL + ); + +/** + Creates a file or directory by name. + + This function creates an empty new file or directory with the specified attributes and + returns the new file's handle. If the file already exists and is read-only, then + EFI_INVALID_PARAMETER will be returned. + + If the file already existed, it is truncated and its attributes updated. If the file is + created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL. + + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + already exists and is non-volatile then EFI_INVALID_PARAMETER is returned. + + @param FileName Pointer to NULL-terminated file path + @param FileAttribs The new file's attrbiutes. the different attributes are + described in EFI_FILE_PROTOCOL.Open(). + @param FileHandle On return, points to the created file handle or directory's handle + + @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED could not open the file path + @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not + file the file system on the device. + @retval EFI_NO_MEDIA the device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the DirName. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +EfiShellCreateFile( + IN CONST CHAR16 *FileName, + IN UINT64 FileAttribs, + OUT SHELL_FILE_HANDLE *FileHandle + ); + +/** + Opens a file or a directory by file name. + + This function opens the specified file in the specified OpenMode and returns a file + handle. + If the file name begins with >v, then the file handle which is returned refers to the + shell environment variable with the specified name. If the shell environment variable + exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then + EFI_INVALID_PARAMETER is returned. + + If the file name is >i, then the file handle which is returned refers to the standard + input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >o, then the file handle which is returned refers to the standard + output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is >e, then the file handle which is returned refers to the standard + error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER + is returned. + + If the file name is NUL, then the file handle that is returned refers to the standard NUL + file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is + returned. + + If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the + FileHandle is NULL. + + @param FileName Points to the NULL-terminated UCS-2 encoded file name. + @param FileHandle On return, points to the file handle. + @param OpenMode File open mode. Either EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE from section 12.4 of the UEFI + Specification. + @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL. + @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL. + @retval EFI_NOT_FOUND The specified file could not be found on the device or the file + system could not be found on the device. FileHandle is NULL. + @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no + longer supported. FileHandle is NULL. + @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according + the FileName. FileHandle is NULL. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL. + @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write + when the media is write-protected. FileHandle is NULL. + @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle + is NULL. + @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileByName( + IN CONST CHAR16 *FileName, + OUT SHELL_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode + ); + +/** + Deletes the file specified by the file name. + + This function deletes a file. + + @param FileName Points to the NULL-terminated file name. + + @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + @sa EfiShellCreateFile + @sa FileHandleDelete +**/ +EFI_STATUS +EFIAPI +EfiShellDeleteFileByName( + IN CONST CHAR16 *FileName + ); + +/** + Disables the page break output mode. +**/ +VOID +EFIAPI +EfiShellDisablePageBreak ( + VOID + ); + +/** + Enables the page break output mode. +**/ +VOID +EFIAPI +EfiShellEnablePageBreak ( + VOID + ); + +/** + internal worker function to run a command via Device Path + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param DevicePath device path of the file to execute + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + 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 StatusCode Points to the status code returned by the command. + + @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. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +EFIAPI +InternalShellExecuteDevicePath( + IN CONST EFI_HANDLE *ParentImageHandle, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST CHAR16 *CommandLine OPTIONAL, + IN CONST CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ); + +/** + Execute the command line. + + This function creates a nested instance of the shell and executes the specified + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + + The CommandLine is executed from the current working directory on the current + device. + + @param ParentImageHandle A handle of the image that is executing the specified + command line. + @param CommandLine Points to the NULL-terminated UCS-2 encoded string + containing the command line. If NULL then the command- + line will be empty. + @param Environment Points to a NULL-terminated array of environment + 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 StatusCode Points to the status code returned by the command. + + @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. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED Nested shell invocations are not allowed. +**/ +EFI_STATUS +EFIAPI +EfiShellExecute( + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL + ); + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +EFIAPI +FreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ); + +/** + Frees the file list. + + This function cleans up the file list and any related data structures. It has no + impact on the files themselves. + + @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is + defined in OpenFileList() + + @retval EFI_SUCCESS Free the file list successfully. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellFreeFileList( + IN EFI_SHELL_FILE_INFO **FileList + ); + +/** + Deletes the duplicate file names files in the given file list. + + This function deletes the reduplicate files in the given file list. + + @param FileList A pointer to the first entry in the file list. + + @retval EFI_SUCCESS Always success. + @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL; +**/ +EFI_STATUS +EFIAPI +EfiShellRemoveDupInFileList( + IN EFI_SHELL_FILE_INFO **FileList + ); + +/** + Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation + failed it will return NULL. + + @param[in] BasePath the Path to prepend onto filename for FullPath + @param[in] Status Status member initial value. + @param[in] FullName FullName member initial value. + @param[in] FileName FileName member initial value. + @param[in] Handle Handle member initial value. + @param[in] Info Info struct to copy. + +**/ +EFI_SHELL_FILE_INFO * +EFIAPI +CreateAndPopulateShellFileInfo( + IN CONST CHAR16 *BasePath, + IN CONST EFI_STATUS Status, + IN CONST CHAR16 *FullName, + IN CONST CHAR16 *FileName, + IN CONST SHELL_FILE_HANDLE Handle, + IN CONST EFI_FILE_INFO *Info + ); + +/** + Find all files in a specified directory. + + @param FileDirHandle Handle of the directory to search. + @param FileList On return, points to the list of files in the directory + or NULL if there are no files in the directory. + + @retval EFI_SUCCESS File information was returned successfully. + @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_NO_MEDIA The device media is not present. + @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory. +**/ +EFI_STATUS +EFIAPI +EfiShellFindFilesInDir( + IN SHELL_FILE_HANDLE FileDirHandle, + OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Find files that match a specified pattern. + + This function searches for all files and directories that match the specified + FilePattern. The FilePattern can contain wild-card characters. The resulting file + information is placed in the file list FileList. + + Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. + + The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo + field is set to NULL. + + if *FileList is not NULL then it must be a pre-existing and properly initialized list. + + @param FilePattern Points to a NULL-terminated shell file path, including wildcards. + @param FileList On return, points to the start of a file list containing the names + of all matching files or else points to NULL if no matching files + were found. only on a EFI_SUCCESS return will; this be non-NULL. + + @retval EFI_SUCCESS Files found. FileList is a valid list. + @retval EFI_NOT_FOUND No files found. + @retval EFI_NO_MEDIA The device has no media + @retval EFI_DEVICE_ERROR The device reported an error + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted +**/ +EFI_STATUS +EFIAPI +EfiShellFindFiles( + IN CONST CHAR16 *FilePattern, + OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Opens the files that match the path specified. + + This function opens all of the files specified by Path. Wildcards are processed + according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each + matching file has an EFI_SHELL_FILE_INFO structure created in a linked list. + + @param Path A pointer to the path string. + @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or + EFI_FILE_MODE_WRITE. + @param FileList Points to the start of a list of files opened. + + @retval EFI_SUCCESS Create the file list successfully. + @return Others Can't create the file list. +**/ +EFI_STATUS +EFIAPI +EfiShellOpenFileList( + IN CHAR16 *Path, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **FileList + ); + +/** + Gets the environment variable. + + This function returns the current value of the specified environment variable. + + @param Name A pointer to the environment variable name + + @return !=NULL The environment variable's value. The returned + pointer does not need to be freed by the caller. + @retval NULL The environment variable doesn't exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetEnv( + IN CONST CHAR16 *Name + ); + +/** + Sets the environment variable. + + This function changes the current value of the specified environment variable. If the + environment variable exists and the Value is an empty string, then the environment + variable is deleted. If the environment variable exists and the Value is not an empty + string, then the value of the environment variable is changed. If the environment + variable does not exist and the Value is an empty string, there is no action. If the + environment variable does not exist and the Value is a non-empty string, then the + environment variable is created and assigned the specified value. + + For a description of volatile and non-volatile environment variables, see UEFI Shell + 2.0 specification section 3.6.1. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +EfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ); + +/** + Returns the current directory on the specified device. + + If FileSystemMapping is NULL, it returns the current working directory. If the + FileSystemMapping is not NULL, it returns the current directory associated with the + FileSystemMapping. In both cases, the returned name includes the file system + mapping (i.e. fs0:\current-dir). + + @param FileSystemMapping A pointer to the file system mapping. If NULL, + then the current working directory is returned. + + @retval !=NULL The current directory. + @retval NULL Current directory does not exist. +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetCurDir( + IN CONST CHAR16 *FileSystemMapping OPTIONAL + ); + +/** + Changes the current directory on the specified device. + + If the FileSystem is NULL, and the directory Dir does not contain a file system's + mapped name, this function changes the current working directory. If FileSystem is + NULL and the directory Dir contains a mapped name, then the current file system and + the current directory on that file system are changed. + + If FileSystem is not NULL, and Dir is NULL, then this changes the current working file + system. + + If FileSystem is not NULL and Dir is not NULL, then this function changes the current + directory on the specified file system. + + If the current working directory or the current working file system is changed then the + %cwd% environment variable will be updated + + @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working + directory is changed. + @param Dir Points to the NULL-terminated directory on the device specified by FileSystem. + + @retval EFI_SUCCESS The operation was sucessful +**/ +EFI_STATUS +EFIAPI +EfiShellSetCurDir( + IN CONST CHAR16 *FileSystem OPTIONAL, + IN CONST CHAR16 *Dir + ); + +/** + Return help information about a specific command. + + This function returns the help information for the specified command. The help text + can be internal to the shell or can be from a UEFI Shell manual page. + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param Command Points to the NULL-terminated UEFI Shell command name. + @param Sections Points to the NULL-terminated comma-delimited + section names to return. If NULL, then all + sections will be returned. + @param HelpText On return, points to a callee-allocated buffer + containing all specified help text. + + @retval EFI_SUCCESS The help text was returned. + @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the + returned help text. + @retval EFI_INVALID_PARAMETER HelpText is NULL + @retval EFI_NOT_FOUND There is no help text available for Command. +**/ +EFI_STATUS +EFIAPI +EfiShellGetHelpText( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Sections OPTIONAL, + OUT CHAR16 **HelpText + ); + +/** + Gets the enable status of the page break output mode. + + User can use this function to determine current page break mode. + + @retval TRUE The page break output mode is enabled + @retval FALSE The page break output mode is disabled +**/ +BOOLEAN +EFIAPI +EfiShellGetPageBreak( + VOID + ); + +/** + Judges whether the active shell is the root shell. + + This function makes the user to know that whether the active Shell is the root shell. + + @retval TRUE The active Shell is the root Shell. + @retval FALSE The active Shell is NOT the root Shell. +**/ +BOOLEAN +EFIAPI +EfiShellIsRootShell( + VOID + ); + +/** + This function returns the command associated with a alias or a list of all + alias'. + + @param[in] Command Points to the NULL-terminated shell alias. + If this parameter is NULL, then all + aliases will be returned in ReturnedData. + @param[out] Volatile upon return of a single command if TRUE indicates + this is stored in a volatile fashion. FALSE otherwise. + @return If Alias is not NULL, it will return a pointer to + the NULL-terminated command for that alias. + If Alias is NULL, ReturnedData points to a ';' + delimited list of alias (e.g. + ReturnedData = "dir;del;copy;mfp") that is NULL-terminated. + @retval NULL an error ocurred + @retval NULL Alias was not a valid Alias +**/ +CONST CHAR16 * +EFIAPI +EfiShellGetAlias( + IN CONST CHAR16 *Command, + OUT BOOLEAN *Volatile OPTIONAL + ); + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + this function does not check for built in alias'. + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found +**/ +EFI_STATUS +EFIAPI +InternalSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias OPTIONAL, + IN BOOLEAN Volatile + ); + +/** + Changes a shell command alias. + + This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias. + + + @param[in] Command Points to the NULL-terminated shell command or existing alias. + @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and + Command refers to an alias, that alias will be deleted. + @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If + FALSE and the alias already exists, then the existing alias is unchanged and + EFI_ACCESS_DENIED is returned. + @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the + Alias being set will be stored in a non-volatile fashion. + + @retval EFI_SUCCESS Alias created or deleted successfully. + @retval EFI_NOT_FOUND the Alias intended to be deleted was not found + @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to + FALSE. +**/ +EFI_STATUS +EFIAPI +EfiShellSetAlias( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias OPTIONAL, + IN BOOLEAN Replace, + IN BOOLEAN Volatile + ); + +/** + Utility cleanup function for EFI_SHELL_FILE_INFO objects. + + 1) frees all pointers (non-NULL) + 2) Closes the SHELL_FILE_HANDLE + + @param FileListNode pointer to the list node to free +**/ +VOID +EFIAPI +InternalFreeShellFileInfoNode( + IN EFI_SHELL_FILE_INFO *FileListNode + ); + +/** + Internal variable setting function. Allows for setting of the read only variables. + + @param Name Points to the NULL-terminated environment variable name. + @param Value Points to the NULL-terminated environment variable value. If the value is an + empty string then the environment variable is deleted. + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS The environment variable was successfully updated. +**/ +EFI_STATUS +EFIAPI +InternalEfiShellSetEnv( + IN CONST CHAR16 *Name, + IN CONST CHAR16 *Value, + IN BOOLEAN Volatile + ); + +#endif //_SHELL_PROTOCOL_HEADER_ + diff --git a/ShellPkg/Application/ShellLibTestApp/sa3.c b/ShellPkg/Application/ShellLibTestApp/sa3.c index e3813c9bbb..6418a6cb0a 100644 --- a/ShellPkg/Application/ShellLibTestApp/sa3.c +++ b/ShellPkg/Application/ShellLibTestApp/sa3.c @@ -52,7 +52,7 @@ UefiMain ( IN EFI_SYSTEM_TABLE *SystemTable ) { - EFI_FILE_HANDLE FileHandle; + SHELL_FILE_HANDLE FileHandle; EFI_STATUS Status; CHAR16 FileName[100]; UINTN BufferSize; diff --git a/ShellPkg/Include/Guid/ShellAliasGuid.h b/ShellPkg/Include/Guid/ShellAliasGuid.h new file mode 100644 index 0000000000..200e358688 --- /dev/null +++ b/ShellPkg/Include/Guid/ShellAliasGuid.h @@ -0,0 +1,25 @@ +/** @file + GUID for Shell Variable for Get/Set via runtime services. + + Copyright (c) 2009 - 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_ALIAS_VARIABLE_GUID_H_ +#define _SHELL_ALIAS_VARIABLE_GUID_H_ + +#define SHELL_ALIAS_VARIABLE_GUID \ +{ \ + 0x0053d9d6, 0x2659, 0x4599, { 0xa2, 0x6b, 0xef, 0x45, 0x36, 0xe6, 0x31, 0xa9 } \ +} + +extern EFI_GUID gShellAliasGuid; + +#endif \ No newline at end of file diff --git a/ShellPkg/Include/Guid/ShellEnvironment2Ext.h b/ShellPkg/Include/Guid/ShellEnvironment2Ext.h index da237479ea..a18d16c0e9 100644 --- a/ShellPkg/Include/Guid/ShellEnvironment2Ext.h +++ b/ShellPkg/Include/Guid/ShellEnvironment2Ext.h @@ -1,5 +1,5 @@ /** @file - GUID for EFI shell Environment2 Extension + GUID for EFI shell Environment2 Extension. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
This program and the accompanying materials @@ -12,8 +12,8 @@ **/ -#ifndef _SHELLPKG_SHELL_ENV2_EXT_GUID_H -#define _SHELLPKG_SHELL_ENV2_EXT_GUID_H +#ifndef _SHELLPKG_SHELL_ENV2_EXT_GUID_H_ +#define _SHELLPKG_SHELL_ENV2_EXT_GUID_H_ #define SHELLPKG_SHELL_ENV2_EXT_GUID \ { \ diff --git a/ShellPkg/Include/Guid/ShellMapGuid.h b/ShellPkg/Include/Guid/ShellMapGuid.h new file mode 100644 index 0000000000..180a41bf53 --- /dev/null +++ b/ShellPkg/Include/Guid/ShellMapGuid.h @@ -0,0 +1,25 @@ +/** @file + GUID for Shell Map for Get/Set via runtime services. + + Copyright (c) 2009 - 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_MAP_GUID_H_ +#define _SHELL_MAP_GUID_H_ + +#define SHELL_MAP_GUID \ +{ \ + 0x51271e13, 0x7de3, 0x43af, { 0x8b, 0xc2, 0x71, 0xad, 0x3b, 0x82, 0x43, 0x25 } \ +} + +extern EFI_GUID gShellMapGuid; + +#endif \ No newline at end of file diff --git a/ShellPkg/Include/Guid/ShellVariableGuid.h b/ShellPkg/Include/Guid/ShellVariableGuid.h new file mode 100644 index 0000000000..b93c94774b --- /dev/null +++ b/ShellPkg/Include/Guid/ShellVariableGuid.h @@ -0,0 +1,25 @@ +/** @file + GUID for Shell Variable for Get/Set via runtime services. + + Copyright (c) 2009 - 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_VARIABLE_GUID_H_ +#define _SHELL_VARIABLE_GUID_H_ + +#define SHELL_VARIABLE_GUID \ +{ \ + 0x158def5a, 0xf656, 0x419c, { 0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2 } \ +} + +extern EFI_GUID gShellVariableGuid; + +#endif \ No newline at end of file diff --git a/ShellPkg/Include/Library/FileHandleLib.h b/ShellPkg/Include/Library/FileHandleLib.h index c0cde036f9..1c191ad64a 100644 --- a/ShellPkg/Include/Library/FileHandleLib.h +++ b/ShellPkg/Include/Library/FileHandleLib.h @@ -12,28 +12,29 @@ **/ -#if !defined (_FILE_HANDLE_LIBRARY_HEADER_) +#ifndef _FILE_HANDLE_LIBRARY_HEADER_ #define _FILE_HANDLE_LIBRARY_HEADER_ -/// Tag for use in identifying UNICODE files. -/// If the file is UNICODE the first 16 bits of the file will equal this value. +#include + +/// The tag for use in identifying UNICODE files. +/// If the file is UNICODE, the first 16 bits of the file will equal this value. enum { UnicodeFileTag = 0xFEFF }; /** - This function will retrieve the information about the file for the handle - specified and store it in allocated pool memory. + This function retrieves information about the file for the handle + specified and stores it in the allocated pool memory. This function allocates a buffer to store the file's information. It is the caller's responsibility to free the buffer. - @param FileHandle The file handle of the file for which information is - being requested. - - @retval NULL information could not be retrieved. + @param[in] FileHandle The file handle of the file for which information is + being requested. - @retval !NULL the information about the file + @retval NULL Information could not be retrieved. + @retval !NULL The information about the file. **/ EFI_FILE_INFO* EFIAPI @@ -42,23 +43,23 @@ FileHandleGetInfo ( ); /** - This function will set the information about the file for the opened handle + This function sets the information about the file for the opened handle specified. - @param FileHandle The file handle of the file for which information + @param[in] FileHandle The file handle of the file for which information is being set. - @param FileInfo The information to set. + @param[in] FileInfo The information to set. @retval EFI_SUCCESS The information was set. - @retval EFI_INVALID_PARAMETER A Parameter was out of range or invalid. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI @@ -83,16 +84,16 @@ FileHandleSetInfo ( are no more directory entries, the read returns a zero-length buffer. EFI_FILE_INFO is the structure returned as the directory entry. - @param FileHandle The opened file handle. - @param BufferSize On input the size of buffer in bytes. On return + @param[in] FileHandle The opened file handle. + @param[in,out] BufferSize On input, the size of buffer in bytes. On return, the number of bytes written. - @param Buffer The buffer to put read data into. + @param[out] Buffer The buffer to put read data into. - @retval EFI_SUCCESS Data was read. + @retval EFI_SUCCESS Data was read. @retval EFI_NO_MEDIA The device has no media. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required + @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required size. **/ @@ -114,19 +115,19 @@ FileHandleRead( The file is automatically grown to hold the data if required. Direct writes to opened directories are not supported. - @param FileHandle The opened file for writing - @param BufferSize On input the number of bytes in Buffer. On output + @param[in] FileHandle The opened file for writing. + @param[in,out] BufferSize On input, the number of bytes in Buffer. On output, the number of bytes written. - @param Buffer The buffer containing data to write is stored. + @param[in] Buffer The buffer containing data to write is stored. - @retval EFI_SUCCESS Data was written. - @retval EFI_UNSUPPORTED Writes to an open directory are not supported. + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to an open directory are not supported. @retval EFI_NO_MEDIA The device has no media. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The device is write-protected. - @retval EFI_ACCESS_DENIED The file was open for read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_WRITE_PROTECTED The device is write-protected. + @retval EFI_ACCESS_DENIED The file was opened for read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI @@ -143,9 +144,9 @@ FileHandleWrite( flushed to the device, and the file is closed. In all cases the handle is closed. - @param FileHandle The file handle to close. + @param[in] FileHandle The file handle to close. - @retval EFI_SUCCESS The file handle was closed sucessfully. + @retval EFI_SUCCESS The file handle was closed successfully. **/ EFI_STATUS EFIAPI @@ -160,11 +161,11 @@ FileHandleClose ( If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is returned, but the handle is still closed. - @param FileHandle The file handle to delete. + @param[in] FileHandle The file handle to delete. - @retval EFI_SUCCESS The file was closed sucessfully. - @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not - deleted + @retval EFI_SUCCESS The file was closed successfully. + @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not + deleted. @retval INVALID_PARAMETER One of the parameters has an invalid value. **/ EFI_STATUS @@ -177,18 +178,18 @@ FileHandleDelete ( Set the current position in a file. This function sets the current file position for the handle to the position - supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only - absolute positioning is supported, and seeking past the end of the file is - allowed (a subsequent write would grow the file). Seeking to position + supplied. With the exception of moving to position 0xFFFFFFFFFFFFFFFF, only + absolute positioning is supported, and moving past the end of the file is + allowed (a subsequent write would grow the file). Moving to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. If FileHandle is a directory, the only position that may be set is zero. This - has the effect of starting the read process of the directory entries over. + has the effect of starting the read process of the directory entries over again. - @param FileHandle The file handle on which the position is being set - @param Position Byte position from begining of file + @param[in] FileHandle The file handle on which the position is being set. + @param[in] Position The byte position from the begining of the file. - @retval EFI_SUCCESS Operation completed sucessfully. - @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_UNSUPPORTED The request for non-zero is not valid on directories. @retval INVALID_PARAMETER One of the parameters has an invalid value. **/ @@ -204,15 +205,15 @@ FileHandleSetPosition ( This function retrieves the current file position for the file handle. For directories, the current file position has no meaning outside of the file - system driver and as such the operation is not supported. An error is returned + system driver. As such, the operation is not supported. An error is returned if FileHandle is a directory. - @param FileHandle The open file handle on which to get the position. - @param Position Byte position from begining of file. + @param[in] FileHandle The open file handle on which to get the position. + @param[out] Position The byte position from begining of file. - @retval EFI_SUCCESS the operation completed sucessfully. + @retval EFI_SUCCESS The operation completed successfully. @retval INVALID_PARAMETER One of the parameters has an invalid value. - @retval EFI_UNSUPPORTED the request is not valid on directories. + @retval EFI_UNSUPPORTED The request is not valid on directories. **/ EFI_STATUS EFIAPI @@ -225,7 +226,7 @@ FileHandleGetPosition ( This function flushes all modified data associated with a file to a device. - @param FileHandle The file handle on which to flush data. + @param[in] FileHandle The file handle on which to flush data. @retval EFI_SUCCESS The data was flushed. @retval EFI_NO_MEDIA The device has no media. @@ -243,16 +244,16 @@ FileHandleFlush ( /** Function to determine if a given handle is a directory handle. - If DirHandle is NULL then ASSERT(). + If DirHandle is NULL, then ASSERT(). - Open the file information on the DirHandle and verify that the Attribute + Open the file information on the DirHandle, and verify that the Attribute includes EFI_FILE_DIRECTORY bit set. - @param DirHandle Handle to open file. + @param[in] DirHandle The handle to open the file. - @retval EFI_SUCCESS DirHandle is a directory - @retval EFI_INVALID_PARAMETER DirHandle did not have EFI_FILE_INFO available - @retval EFI_NOT_FOUND DirHandle is not a directory + @retval EFI_SUCCESS DirHandle is a directory. + @retval EFI_INVALID_PARAMETER DirHandle did not have EFI_FILE_INFO available. + @retval EFI_NOT_FOUND DirHandle is not a directory. **/ EFI_STATUS EFIAPI @@ -263,20 +264,20 @@ FileHandleIsDirectory ( /** Retrieves the first file from a directory. - This function opens a directory and gets the first file's info in the - directory. Caller can use FileHandleFindNextFile() to get other files. When - complete the caller is responsible for calling FreePool() on *Buffer. + This function opens a directory and gets the first file's information in the + directory. The caller the uses FileHandleFindNextFile() to get other files. When + complete, the caller is responsible for calling FreePool() on *Buffer. - @param DirHandle The file handle of the directory to search - @param Buffer Pointer to pointer to buffer for file's information + @param[in] DirHandle The file handle of the directory to search. + @param[out] Buffer The pointer to pointer to buffer for file's information. @retval EFI_SUCCESS Found the first file. @retval EFI_NOT_FOUND Cannot find the directory. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @return Others status of FileHandleGetInfo, FileHandleSetPosition, - or FileHandleRead + @return Others The status of FileHandleGetInfo, FileHandleSetPosition, + or FileHandleRead. **/ EFI_STATUS EFIAPI @@ -294,11 +295,11 @@ FileHandleFindFirstFile ( call of this function has no file to get. *NoFile will be set to TRUE and the Buffer memory will be automatically freed. - @param DirHandle the file handle of the directory - @param Buffer pointer to buffer for file's information - @param NoFile pointer to boolean when last file is found + @param[in] DirHandle The file handle of the directory. + @param[out] Buffer The pointer to buffer for file's information. + @param[out] NoFile The pointer to boolean when last file is found. - @retval EFI_SUCCESS Found the next file, or reached last file + @retval EFI_SUCCESS Found the next file, or reached last file. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @@ -314,17 +315,17 @@ FileHandleFindNextFile( /** Retrieve the size of a file. - If FileHandle is NULL then ASSERT() - If Size is NULL then ASSERT() + If FileHandle is NULL then ASSERT(). + If Size is NULL then ASSERT(). This function extracts the file size info from the FileHandle's EFI_FILE_INFO data. - @param FileHandle The file handle from which size is retrieved. - @param Size pointer to size. + @param[in] FileHandle The file handle from which size is retrieved. + @param[out] Size The pointer to size. - @retval EFI_SUCCESS operation was completed sucessfully - @retval EFI_DEVICE_ERROR cannot access the file + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR Cannot access the file. **/ EFI_STATUS EFIAPI @@ -333,6 +334,27 @@ FileHandleGetSize ( OUT UINT64 *Size ); +/** + Set the size of a file. + + If FileHandle is NULL then ASSERT(). + + This function changes the file size info from the FileHandle's EFI_FILE_INFO + data. + + @param[in] FileHandle The file handle whose size is to be changed. + @param[in] Size The new size. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR Cannot access the file. +**/ +EFI_STATUS +EFIAPI +FileHandleSetSize ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT64 Size + ); + /** Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the directory 'stack'. @@ -341,10 +363,10 @@ FileHandleGetSize ( @param[out] FullFileName Pointer to pointer to generated full file name. It is the responsibility of the caller to free this memory with a call to FreePool(). - @retval EFI_SUCCESS the operation was sucessful and the FullFileName is valid. + @retval EFI_SUCCESS The operation was successful and FullFileName is valid. @retval EFI_INVALID_PARAMETER Handle was NULL. @retval EFI_INVALID_PARAMETER FullFileName was NULL. - @retval EFI_OUT_OF_MEMORY a memory allocation failed. + @retval EFI_OUT_OF_MEMORY A memory allocation failed. **/ EFI_STATUS EFIAPI @@ -359,21 +381,24 @@ FileHandleGetFileName ( If the position upon start is 0, then the Ascii Boolean will be set. This should be maintained and not changed for all operations with the same file. - @param[in] Handle FileHandle to read from - @param[in,out] Buffer pointer to buffer to read into - @param[in,out] Size pointer to number of bytes in buffer - @param[in] Truncate if TRUE then allows for truncation of the line to fit. - if FALSE will reset the position to the begining of the - line if the buffer is not large enough. + @param[in] Handle FileHandle to read from. + @param[in,out] Buffer The pointer to buffer to read into. + @param[in,out] Size The pointer to number of bytes in Buffer. + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + @param[in,out] Ascii Boolean value for indicating whether the file is - Ascii (TRUE) or UCS2 (FALSE); + Ascii (TRUE) or UCS2 (FALSE). - @retval EFI_SUCCESS the operation was sucessful. the line is stored in + @retval EFI_SUCCESS The operation was successful. The line is stored in Buffer. @retval EFI_INVALID_PARAMETER Handle was NULL. @retval EFI_INVALID_PARAMETER Size was NULL. - @retval EFI_BUFFER_TOO_SMALL Size was not enough space to store the line. - Size was updated to minimum space required. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. @sa FileHandleRead **/ EFI_STATUS @@ -394,7 +419,8 @@ FileHandleReadLine( maintained and not changed for all operations with the same file. @param[in] Handle FileHandle to read from. - @param[in,out] Ascii Boolean value for indicating whether the file is Ascii (TRUE) or UCS2 (FALSE); + @param[in,out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). @return The line of text from the file. @@ -412,12 +438,12 @@ FileHandleReturnLine( If Handle is NULL, ASSERT. - @param[in] Handle FileHandle to write to + @param[in] Handle FileHandle to write to. @param[in] Buffer Buffer to write, if NULL the function will take no action and return EFI_SUCCESS. - @retval EFI_SUCCESS the data was written. - @retval other failure. + @retval EFI_SUCCESS The data was written. + @retval other Failure. @sa FileHandleWrite **/ @@ -429,14 +455,14 @@ FileHandleWriteLine( ); /** - function to take a formatted argument and print it to a file. + Function to take a formatted argument and print it to a file. - @param[in] Handle the file handle for the file to write to - @param[in] Format the format argument (see printlib for format specifier) - @param[in] ... the variable arguments for the format + @param[in] Handle The file handle for the file to write to. + @param[in] Format The format argument (see printlib for the format specifier). + @param[in] ... The variable arguments for the format. - @retval EFI_SUCCESS the operation was sucessful - @return other a return value from FileHandleWriteLine + @retval EFI_SUCCESS The operation was successful. + @retval other A return value from FileHandleWriteLine. @sa FileHandleWriteLine **/ @@ -453,12 +479,12 @@ FileHandlePrintLine( This will NOT work on directories. - If Handle is NULL, then ASSERT. + If Handle is NULL, then ASSERT(). - @param[in] Handle the file handle + @param[in] Handle The file handle. - @retval TRUE the position is at the end of the file - @retval FALSE the position is not at the end of the file + @retval TRUE The position is at the end of the file. + @retval FALSE The position is not at the end of the file. **/ BOOLEAN EFIAPI diff --git a/ShellPkg/Include/Library/HandleParsingLib.h b/ShellPkg/Include/Library/HandleParsingLib.h new file mode 100644 index 0000000000..f08768c152 --- /dev/null +++ b/ShellPkg/Include/Library/HandleParsingLib.h @@ -0,0 +1,342 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + 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 __HANDLE_PARSING_LIB__ +#define __HANDLE_PARSING_LIB__ + +#include + +/** + Function to get the name of a protocol or struct from it's GUID. + + If Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + @param[in] Lang The language to use. + + @return The pointer to a string of the name. The caller + is responsible to free this memory. +**/ +CHAR16* +EFIAPI +GetStringNameFromGuid( + IN CONST EFI_GUID *Guid, + IN CONST CHAR8 *Lang OPTIONAL + ); + +/** + Function to get the Guid for a protocol or struct based on it's string name. + + @param[in] Name The pointer to the string name. + @param[in] Lang The pointer to the language code (string). + @param[in] Guid The pointer to the pointer to the Guid. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +GetGuidFromStringName( + IN CONST CHAR16 *Name, + IN CONST CHAR8 *Lang OPTIONAL, + IN EFI_GUID **Guid + ); + +/** + Function to dump protocol information from a handle. + + This function will return a allocated string buffer containing the + information. The caller is responsible for freeing the memory. + + If Guid is NULL, ASSERT(). + If TheHandle is NULL, ASSERT(). + + @param[in] TheHandle The handle to dump information from. + @param[in] Guid The GUID of the protocol to dump. + @param[in] Verbose TRUE for extra info. FALSE otherwise. + + @return The pointer to string. + @retval NULL An error was encountered. +**/ +CHAR16* +EFIAPI +GetProtocolInformationDump( + IN CONST EFI_HANDLE TheHandle, + IN CONST EFI_GUID *Guid, + IN CONST BOOLEAN Verbose + ); + +/** + Function to retrieve the driver name (if possible) from the ComponentName or + ComponentName2 protocol. + + The string returned must be callee freed. + + @param[in] TheHandle The driver handle to get the name of. + @param[in] Language The language to use. + + @retval NULL The name could not be found. + @return A pointer to the string name. Do not de-allocate the memory. +**/ +CONST CHAR16* +EFIAPI +GetStringNameFromHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language + ); + +#define HR_UNKNOWN 0 +#define HR_IMAGE_HANDLE BIT1 +#define HR_DRIVER_BINDING_HANDLE BIT2 // has driver binding +#define HR_DEVICE_DRIVER BIT3 // device driver (hybrid?) +#define HR_BUS_DRIVER BIT4 // a bus driver (hybrid?) +#define HR_DRIVER_CONFIGURATION_HANDLE BIT5 +#define HR_DRIVER_DIAGNOSTICS_HANDLE BIT6 +#define HR_COMPONENT_NAME_HANDLE BIT7 +#define HR_DEVICE_HANDLE BIT8 +#define HR_PARENT_HANDLE BIT9 +#define HR_CONTROLLER_HANDLE BIT10 +#define HR_CHILD_HANDLE BIT11 +#define HR_VALID_MASK (BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7|BIT8|BIT9|BIT10|BIT11) + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function will scan all EFI_HANDLES in the UEFI environment's handle database + and return all the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return, the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] Mask The mask of what relationship(s) is desired. + @param[in] MatchingHandleCount The pointer to UINTN specifying number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. + @sa ParseHandleDatabaseByRelationshipWithType +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationship ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN CONST UINTN Mask, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function scans all EFI_HANDLES in the UEFI environment's handle database + and returns the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] MatchingHandleCount The pointer to UINTN that specifies the number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + @param[out] HandleType An array of type information. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationshipWithType ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN UINTN *HandleCount, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN **HandleType + ); + +/** + Gets handles for any parents of the passed in controller. + + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_PARENTS(ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(NULL, ControllerHandle, HR_PARENT_HANDLE, Count, Buffer) + +/** + Gets handles for any UEFI drivers of the passed in controller. + + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(NULL, ControllerHandle, HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER, Count, Buffer) + +/** + Gets handles for any children of the passed in controller by the passed in driver handle. + + @param[in] DriverHandle The handle of the driver. + @param[in] ControllerHandle The handle of the controller. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_MANAGED_CHILDREN(DriverHandle, ControllerHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(DriverHandle, ControllerHandle, HR_CHILD_HANDLE|HR_DEVICE_HANDLE, Count, Buffer) + +/** + Gets handles for any devices managed by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] Count The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] Buffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +#define PARSE_HANDLE_DATABASE_DEVICES(DriverHandle, Count, Buffer) \ + ParseHandleDatabaseByRelationship(DriverHandle, NULL, HR_CONTROLLER_HANDLE|HR_DEVICE_HANDLE, Count, Buffer) + +/** + Gets handles for any child devices produced by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] MatchingHandleCount The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildDevices( + IN CONST EFI_HANDLE DriverHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + +/** + Gets handles for any child controllers of the passed in controller. + + @param[in] ControllerHandle The handle of the "parent controller". + @param[in] MatchingHandleCount The pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer The buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was successful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildControllers( + IN CONST EFI_HANDLE ControllerHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ); + + +/** + Function to retrieve the human-friendly index of a given handle. If the handle + does not have a index one will be automatically assigned. The index value is valid + until the termination of the shell application. + + @param[in] TheHandle The handle to retrieve an index for. + + @retval 0 A memory allocation failed. + @return The index of the handle. + +**/ +UINTN +EFIAPI +ConvertHandleToHandleIndex( + IN CONST EFI_HANDLE TheHandle + ); + +/** + Function to retrieve the EFI_HANDLE from the human-friendly index. + + @param[in] TheIndex The index to retrieve the EFI_HANDLE for. + + @retval NULL The index was invalid. + @return The EFI_HANDLE that index represents. + +**/ +EFI_HANDLE +EFIAPI +ConvertHandleIndexToHandle( + IN CONST UINTN TheIndex + ); + +/** + Function to get all handles that support a given protocol or all handles. + + @param[in] ProtocolGuid The guid of the protocol to get handles for. If NULL + then the function will return all handles. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByPotocol ( + IN CONST EFI_GUID *ProtocolGuid OPTIONAL + ); + +/** + Function to get all handles that support some protocols. + + @param[in] ProtocolGuids A NULL terminated list of protocol GUIDs. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByPotocolList ( + IN CONST EFI_GUID **ProtocolGuids + ); + +#endif // __HANDLE_PARSING_LIB__ diff --git a/ShellPkg/Include/Library/ShellCEntryLib.h b/ShellPkg/Include/Library/ShellCEntryLib.h index 638dc4b25b..f839372b39 100644 --- a/ShellPkg/Include/Library/ShellCEntryLib.h +++ b/ShellPkg/Include/Library/ShellCEntryLib.h @@ -1,5 +1,5 @@ /** @file - Provides application point extension for "C" style main funciton + Provides application point extension for "C" style main funciton. Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
This program and the accompanying materials @@ -19,8 +19,8 @@ The ShellCEntryLib library instance wrappers the actual UEFI application entry point and calls this ShellAppMain function. - @param ImageHandle The image handle of the UEFI Application. - @param SystemTable A pointer to the EFI System Table. + @param[in] Argc The number of parameters. + @param[in] Argv The array of pointers to parameters. @retval 0 The application exited normally. @retval Other An error occurred. diff --git a/ShellPkg/Include/Library/ShellCommandLib.h b/ShellPkg/Include/Library/ShellCommandLib.h new file mode 100644 index 0000000000..53cc80b4b5 --- /dev/null +++ b/ShellPkg/Include/Library/ShellCommandLib.h @@ -0,0 +1,757 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + This library is for use ONLY by shell commands linked into the shell application. + This library will not funciton if it is used for UEFI Shell 2.0 Applications. + + Copyright (c) 2009 - 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_COMMAND_LIB_ +#define _SHELL_COMMAND_LIB_ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +// +// The extern global protocol poionters. +// +extern EFI_SHELL_PROTOCOL *gEfiShellProtocol; +extern EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol; +extern EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation; +extern EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *gDevPathToText; +extern CONST CHAR16* SupportLevel[]; + +// +// The map list objects. +// +typedef struct { + LIST_ENTRY Link; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *MapName; + CHAR16 *CurrentDirectoryPath; + UINT64 Flags; +} SHELL_MAP_LIST; +/// List of Mappings - DeviceName and Drive Letter(ism). +extern SHELL_MAP_LIST gShellMapList; +/// Pointer to node of current directory in the mMapList. +extern SHELL_MAP_LIST *gShellCurDir; + +/** + Returns the help MAN fileName for a given shell command. + + @retval !NULL The unicode string of the MAN filename. + @retval NULL An error ocurred. + +**/ +typedef +CONST CHAR16 * +(EFIAPI *SHELL_GET_MAN_FILENAME)( + VOID + ); + +/** + Runs a shell command on a given command line. + + The specific operation of a given shell command is specified in the UEFI Shell + Specification 2.0, or in the source of the given command. + + Upon completion of the command run the shell protocol and environment variables + may have been updated due to the operation. + + @param[in] ImageHandle The ImageHandle to the app, or NULL if + the command built into shell. + @param[in] SystemTable The pointer to the system table. + + @retval RETURN_SUCCESS The shell command was sucessful. + @retval RETURN_UNSUPPORTED The command is not supported. +**/ +typedef +SHELL_STATUS +(EFIAPI *SHELL_RUN_COMMAND)( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Registers the handlers of type SHELL_RUN_COMMAND and + SHELL_GET_MAN_FILENAME for each shell command. + + If the ShellSupportLevel is greater than the value of + PcdShellSupportLevel, then return RETURN_UNSUPPORTED. + + Registers the the handlers specified by GetHelpInfoHandler and CommandHandler + with the command specified by CommandString. If the command named by + CommandString has already been registered, then return + RETURN_ALREADY_STARTED. + + If there are not enough resources available to register the handlers, then + RETURN_OUT_OF_RESOURCES is returned. + + If CommandString is NULL, then ASSERT(). + If GetHelpInfoHandler is NULL, then ASSERT(). + If CommandHandler is NULL, then ASSERT(). + If ProfileName is NULL, then ASSERT(). + + @param[in] CommandString The pointer to the command name. This is the + name to look for on the command line in + the shell. + @param[in] CommandHandler The pointer to a function that runs the + specified command. + @param[in] GetManFileName The pointer to a function that provides man + filename. + @param[in] ShellMinSupportLevel The minimum Shell Support Level which has this + function. + @param[in] ProfileName The profile name to require for support of this + function. + @param[in] CanAffectLE Indicates whether this command's return value + can change the LASTERROR environment variable. + @param[in] HiiHandle The handle of this command's HII entry. + @param[in] ManFormatHelp The HII locator for the help text. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. + @retval RETURN_UNSUPPORTED The ShellMinSupportLevel was higher than the + currently allowed support level. + @retval RETURN_ALREADY_STARTED The CommandString represents a command that + is already registered. Only one handler set for + a given command is allowed. + @sa SHELL_GET_MAN_FILENAME + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterCommandName ( + IN CONST CHAR16 *CommandString, + IN SHELL_RUN_COMMAND CommandHandler, + IN SHELL_GET_MAN_FILENAME GetManFileName, + IN UINT32 ShellMinSupportLevel, + IN CONST CHAR16 *ProfileName, + IN CONST BOOLEAN CanAffectLE, + IN CONST EFI_HANDLE HiiHandle, + IN CONST EFI_STRING_ID ManFormatHelp + ); + +/** + Checks if a command string has been registered for CommandString, and if so, it runs + the previously registered handler for that command with the command line. + + If CommandString is NULL, then ASSERT(). + + If Sections is specified, then each section name listed will be compared in a case sensitive + manner to the section names described in Appendix B UEFI Shell 2.0 Specification. If the section exists, + it is appended to the returned help text. If the section does not exist, no + information is returned. If Sections is NULL, then all help text information + available is returned. + + @param[in] CommandString The pointer to the command name. This is the name + found on the command line in the shell. + @param[in,out] RetVal The pointer to the return value from the command handler. + + @param[in,out] CanAffectLE Indicates whether this command's return value + needs to be placed into LASTERROR environment variable. + + @retval RETURN_SUCCESS The handler was run. + @retval RETURN_NOT_FOUND The CommandString did not match a registered + command name. + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRunCommandHandler ( + IN CONST CHAR16 *CommandString, + IN OUT SHELL_STATUS *RetVal, + IN OUT BOOLEAN *CanAffectLE OPTIONAL + ); + +/** + Checks if a command string has been registered for CommandString, and if so, it + returns the MAN filename specified for that command. + + If CommandString is NULL, then ASSERT(). + + @param[in] CommandString The pointer to the command name. This is the name + found on the command line in the shell. + + @retval NULL The CommandString was not a registered command. + @retval other The name of the MAN file. + @sa SHELL_GET_MAN_FILENAME +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameHandler ( + IN CONST CHAR16 *CommandString + ); + + +typedef struct { + LIST_ENTRY Link; + CHAR16 *CommandString; +} COMMAND_LIST; + +/** + Get the list of all available shell internal commands. This is a linked list, + via the LIST_ENTRY structure. Enumerate through it using the BaseLib linked + list functions. Do not modify the values. + + @return A linked list of all available shell commands. +**/ +CONST COMMAND_LIST* +EFIAPI +ShellCommandGetCommandList ( + VOID + ); + +typedef struct { + LIST_ENTRY Link; + CHAR16 *CommandString; + CHAR16 *Alias; +} ALIAS_LIST; + +/** + Registers aliases to be set as part of the initialization of the shell application. + + If Command is NULL, then ASSERT(). + If Alias is NULL, then ASSERT(). + + @param[in] Command The pointer to the Command. + @param[in] Alias The pointer to Alias. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterAlias ( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias + ); + +/** + Get the list of all shell alias commands. This is a linked list, + via LIST_ENTRY structure. Enumerate through it using the BaseLib linked + list functions. Do not modify the values. + + @return A linked list of all requested shell aliases. +**/ +CONST ALIAS_LIST* +EFIAPI +ShellCommandGetInitAliasList ( + VOID + ); + +/** + Determine if a given alias is on the list of built in aliases. + + @param[in] Alias The alias to test for. + + @retval TRUE The alias is a built in alias. + @retval FALSE The alias is not a built in alias. +**/ +BOOLEAN +EFIAPI +ShellCommandIsOnAliasList ( + IN CONST CHAR16 *Alias + ); + +/** + Checks if a command is already on the list. + + @param[in] CommandString The command string to check for on the list. + + @retval TRUE CommandString represents a registered command. + @retval FALSE CommandString does not represent a registered command. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnList ( + IN CONST CHAR16 *CommandString + ); + +/** + Get the help text for a command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return The string of the help text. The caller required to free. +**/ +CHAR16* +EFIAPI +ShellCommandGetCommandHelp ( + IN CONST CHAR16 *CommandString + ); + +/** + Function to make sure that the above pointers are valid. +**/ +EFI_STATUS +EFIAPI +CommandInit ( + VOID + ); + +/** + Function to determine current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + @retval TRUE Echo is currently enabled. + @retval FALSE Echo is currently disabled. +**/ +BOOLEAN +EFIAPI +ShellCommandGetEchoState ( + VOID + ); + +/** + Function to set current state of ECHO. Echo determines if lines from scripts + and ECHO commands are enabled. + + @param[in] State TRUE to enable Echo, FALSE otherwise. +**/ +VOID +EFIAPI +ShellCommandSetEchoState ( + IN BOOLEAN State + ); + + + +/** + Indicate that the current shell or script should exit. + + @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise. +**/ +VOID +EFIAPI +ShellCommandRegisterExit ( + IN BOOLEAN ScriptOnly + ); + +/** + Retrieve the Exit indicator. + + @retval TRUE Exit was indicated. + @retval FALSE Exit was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetExit ( + VOID + ); + +/** + Retrieve the Exit script indicator. + + If ShellCommandGetExit returns FALSE, then the return from this is undefined. + + @retval TRUE ScriptOnly was indicated. + @retval FALSE ScriptOnly was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetScriptExit ( + VOID + ); + +typedef struct { + LIST_ENTRY Link; ///< List enumerator items. + UINTN Line; ///< What line of the script file this was on. + CHAR16 *Cl; ///< The original command line. + VOID *Data; ///< The data structure format dependant upon Command. (not always used) + BOOLEAN Reset; ///< Reset the command (it must be treated like a initial run (but it may have data already)) +} SCRIPT_COMMAND_LIST; + +typedef struct { + CHAR16 *ScriptName; ///< The filename of this script. + CHAR16 **Argv; ///< The parmameters to the script file. + UINTN Argc; ///< The count of parameters. + LIST_ENTRY CommandList; ///< The script converted to a list of commands (SCRIPT_COMMAND_LIST objects). + SCRIPT_COMMAND_LIST *CurrentCommand; ///< The command currently being operated. If !=NULL must be a member of CommandList. + LIST_ENTRY SubstList; ///< A list of current script loop alias' (ALIAS_LIST objects) (Used for the for %-based replacement). +} SCRIPT_FILE; + +/** + Function to return a pointer to the currently running script file object. + + @retval NULL A script file is not currently running. + @return A pointer to the current script file object. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandGetCurrentScriptFile ( + VOID + ); + +/** + Function to set a new script as the currently running one. + + This function will correctly stack and unstack nested scripts. + + @param[in] Script The pointer to new script information structure. If NULL, + it removes and de-allocates the topmost Script structure. + + @return A pointer to the current running script file after this + change. It is NULL if removing the final script. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandSetNewScript ( + IN SCRIPT_FILE *Script OPTIONAL + ); + +/** + Function to get the current Profile string. + + This is used to retrieve what profiles were installed. + + @retval NULL There are no installed profiles. + @return A semicolon-delimited list of profiles. +**/ +CONST CHAR16 * +EFIAPI +ShellCommandGetProfileList ( + VOID + ); + +typedef enum { + MappingTypeFileSystem, + MappingTypeBlockIo, + MappingTypeMax +} SHELL_MAPPING_TYPE; + +/** + Function to generate the next default mapping name. + + If the return value is not NULL then it must be callee freed. + + @param Type What kind of mapping name to make. + + @retval NULL a memory allocation failed. + @return a new map name string +**/ +CHAR16* +EFIAPI +ShellCommandCreateNewMappingName( + IN CONST SHELL_MAPPING_TYPE Type + ); + +/** + Function to initialize the table for creating consistent map names. + + @param[out] Table The pointer to pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was created successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingInitialize ( + EFI_DEVICE_PATH_PROTOCOL ***Table + ); + +/** + Function to uninitialize the table for creating consistent map names. + + The parameter must have been received from ShellCommandConsistMappingInitialize. + + @param[out] Table The pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was deleted successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingUnInitialize ( + EFI_DEVICE_PATH_PROTOCOL **Table + ); + +/** + Create a consistent mapped name for the device specified by DevicePath + based on the Table. + + This must be called after ShellCommandConsistMappingInitialize() and + before ShellCommandConsistMappingUnInitialize() is called. + + @param[in] DeviecPath The pointer to the dev path for the device. + @param[in] Table The Table of mapping information. + + @retval NULL A consistent mapped name could not be created. + @return A pointer to a string allocated from pool with the device name. +**/ +CHAR16* +EFIAPI +ShellCommandConsistMappingGenMappingName ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_DEVICE_PATH_PROTOCOL **Table + ); + +/** + Function to search the list of mappings for the first matching node on the + list based on the MapKey. + + @param[in] MapKey The pointer to the string key to search for in the map. + + @return the node on the list. +**/ +SHELL_MAP_LIST* +EFIAPI +ShellCommandFindMapItem ( + IN CONST CHAR16 *MapKey + ); + +/** + Function to add a map node to the list of map items and update the "path" environment variable (optionally). + + If Path is TRUE (during initialization only), the path environment variable will also be updated to include + default paths on the new map name... + + Path should be FALSE when this function is called from the protocol SetMap function. + + @param[in] Name The human readable mapped name. + @param[in] DevicePath The Device Path for this map. + @param[in] Flags The Flags attribute for this map item. + @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization). + + @retval EFI_SUCCESS The addition was sucessful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +EFIAPI +ShellCommandAddMapItemAndUpdatePath( + IN CONST CHAR16 *Name, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST UINT64 Flags, + IN CONST BOOLEAN Path + ); + +/** + Creates the default map names for each device path in the system with + a protocol depending on the Type. + + Also sets up the default path environment variable if Type is FileSystem. + + @retval EFI_SUCCESS All map names were created sucessfully. + @retval EFI_NOT_FOUND No protocols were found in the system. + @return Error returned from gBS->LocateHandle(). + + @sa LocateHandle +**/ +EFI_STATUS +EFIAPI +ShellCommandCreateInitialMappingsAndPaths( + VOID + ); + +/** + Function to standardize the directory indicators to \ characters. + + @param[in,out] Path The pointer to the path string to fix. + + @retval NULL The operation failed. + @return The Path pointer. +**/ +CHAR16* +EFIAPI +ShellCommandCleanPath ( + IN OUT CHAR16 *Path + ); + +/** + Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*. + + @param[in] Handle The SHELL_FILE_HANDLE to convert. + + @return a EFI_FILE_PROTOCOL* representing the same file. +**/ +EFI_FILE_PROTOCOL* +EFIAPI +ConvertShellHandleToEfiFileProtocol( + IN CONST SHELL_FILE_HANDLE Handle + ); + +/** + Remove a SHELL_FILE_HANDLE frmo the list of SHELL_FILE_HANDLES. + + @param[in] Handle The SHELL_FILE_HANDLE to remove. + + @retval TRUE The item was removed. + @retval FALSE The item was not found. +**/ +BOOLEAN +EFIAPI +ShellFileHandleRemove( + IN CONST SHELL_FILE_HANDLE Handle + ); + +/** + Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE. + + @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert. + @param[in] Path The path to the file for verification. + + @return a SHELL_FILE_HANDLE representing the same file. +**/ +SHELL_FILE_HANDLE +EFIAPI +ConvertEfiFileProtocolToShellHandle( + IN CONST EFI_FILE_PROTOCOL *Handle, + IN CONST CHAR16 *Path + ); + +/** + Find the path that was logged with the specified SHELL_FILE_HANDLE. + + @param[in] Handle The SHELL_FILE_HANDLE to query on. + + @return A pointer to the path for the file. +**/ +CONST CHAR16* +EFIAPI +ShellFileHandleGetPath( + IN CONST SHELL_FILE_HANDLE Handle + ); + + +/** + Function to determine if a SHELL_FILE_HANDLE is at the end of the file. + + This will NOT work on directories. + + If Handle is NULL, then ASSERT. + + @param[in] Handle the file handle + + @retval TRUE the position is at the end of the file + @retval FALSE the position is not at the end of the file +**/ +BOOLEAN +EFIAPI +ShellFileHandleEof( + IN SHELL_FILE_HANDLE Handle + ); + +/** + Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned + buffer. The returned buffer must be callee freed. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in,out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @return The line of text from the file. + + @sa ShellFileHandleReadLine +**/ +CHAR16* +EFIAPI +ShellFileHandleReturnLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT BOOLEAN *Ascii + ); + +/** + Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in,out] Buffer The pointer to buffer to read into. + @param[in,out] Size The pointer to number of bytes in Buffer. + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + + @param[in,out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @retval EFI_SUCCESS The operation was successful. The line is stored in + Buffer. + @retval EFI_INVALID_PARAMETER Handle was NULL. + @retval EFI_INVALID_PARAMETER Size was NULL. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. + @sa ShellFileHandleRead +**/ +EFI_STATUS +EFIAPI +ShellFileHandleReadLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT CHAR16 *Buffer, + IN OUT UINTN *Size, + IN BOOLEAN Truncate, + IN OUT BOOLEAN *Ascii + ); + +typedef struct { + LIST_ENTRY Link; + void *Buffer; +} BUFFER_LIST; + +/** + Frees any BUFFER_LIST defined type. + + @param[in] List The pointer to the list head. +**/ +VOID +EFIAPI +FreeBufferList ( + IN BUFFER_LIST *List + ); + +/** + Chops off last directory or file entry in a path by changing the last '\' to a CHAR_NULL + + @param[in,out] PathToReturn The pointer to the path to modify. + + @retval FALSE No directory was found to chop off. + @retval TRUE A directory was chopped off. +**/ +BOOLEAN +EFIAPI +ChopLastSlash( + IN OUT CHAR16 *PathToReturn + ); + +/** + Function to clean up paths. Removes the following items: + single periods in the path (no need for the current directory tag) + double periods in the path and removes a single parent directory. + + This will be done inline and the resultant string may be be 'too big'. + + @param[in] PathToReturn The pointer to the string containing the path. + + @return PathToReturn is always returned. +**/ +CHAR16* +EFIAPI +CleanPath( + IN CHAR16 *PathToReturn + ); + +#endif //_SHELL_COMMAND_LIB_ diff --git a/ShellPkg/Include/Library/ShellLib.h b/ShellPkg/Include/Library/ShellLib.h index 5c644debfc..7a5d96157b 100644 --- a/ShellPkg/Include/Library/ShellLib.h +++ b/ShellPkg/Include/Library/ShellLib.h @@ -12,7 +12,7 @@ **/ -#if !defined(__SHELL_LIB__) +#ifndef __SHELL_LIB__ #define __SHELL_LIB__ #include @@ -24,6 +24,12 @@ #include #include +// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) +#define MAX_FILE_NAME_LEN 512 + +extern EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol; +extern EFI_SHELL_PROTOCOL *mEfiShellProtocol; + /** This function will retrieve the information about the file for the handle specified and store it in allocated pool memory. @@ -41,31 +47,32 @@ EFI_FILE_INFO* EFIAPI ShellGetFileInfo ( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** - This function will set the information about the file for the opened handle + This function sets the information about the file for the opened handle specified. @param[in] FileHandle The file handle of the file for which information is being set. - @param[in] FileInfo The infotmation to set. + @param[in] FileInfo The information to set. - @retval EFI_SUCCESS The information was set. - @retval EFI_UNSUPPORTED The InformationType is not known. + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. + @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellSetFileInfo ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN EFI_FILE_INFO *FileInfo ); @@ -75,36 +82,36 @@ ShellSetFileInfo ( This function opens a file with the open mode according to the file path. The Attributes is valid only for EFI_FILE_MODE_CREATE. - @param[in] FilePath On input the device path to the file. On output + @param[in,out] FilePath On input, the device path to the file. On output, the remaining device path. - @param[out] DeviceHandle Pointer to the system device handle. - @param[out] FileHandle Pointer to the file handle. - @param[in] OpenMode The mode to open the file with. - @param[in] Attributes The file's file attributes. + @param[out] DeviceHandle Pointer to the system device handle. + @param[out] FileHandle Pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. - @retval EFI_SUCCESS The information was set. + @retval EFI_SUCCESS The information was set. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. - @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_UNSUPPORTED Could not open the file path. @retval EFI_NOT_FOUND The specified file could not be found on the device or the file system could not be found on the device. - @retval EFI_NO_MEDIA The device has no medium. - @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellOpenFileByDevicePath( IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_HANDLE *DeviceHandle, - OUT EFI_FILE_HANDLE *FileHandle, + OUT SHELL_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes ); @@ -113,36 +120,36 @@ ShellOpenFileByDevicePath( This function will open a file or directory referenced by filename. If return is EFI_SUCCESS, the Filehandle is the opened file's handle; - otherwise, the Filehandle is NULL. The Attributes is valid only for + otherwise, the Filehandle is NULL. Attributes is valid only for EFI_FILE_MODE_CREATE. - @param[in] FileName Pointer to file name. - @param[out] FileHandle Pointer to the file handle. - @param[in] OpenMode The mode to open the file with. - @param[in] Attributes The file's file attributes. + @param[in] FilePath The pointer to file name. + @param[out] FileHandle The pointer to the file handle. + @param[in] OpenMode The mode to open the file with. + @param[in] Attributes The file's file attributes. - @retval EFI_SUCCESS The information was set. + @retval EFI_SUCCESS The information was set. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. - @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_UNSUPPORTED Could not open the file path. @retval EFI_NOT_FOUND The specified file could not be found on the device or the file system could not be found on the device. - @retval EFI_NO_MEDIA The device has no medium. - @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellOpenFileByName( IN CONST CHAR16 *FilePath, - OUT EFI_FILE_HANDLE *FileHandle, + OUT SHELL_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes ); @@ -154,31 +161,31 @@ ShellOpenFileByName( otherwise, the Filehandle is NULL. If the directory already existed, this function opens the existing directory. - @param[in] DirectoryName Pointer to Directory name. - @param[out] FileHandle Pointer to the file handle. + @param[in] DirectoryName The pointer to Directory name. + @param[out] FileHandle The pointer to the file handle. - @retval EFI_SUCCESS The information was set. + @retval EFI_SUCCESS The information was set. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. - @retval EFI_UNSUPPORTED Could not open the file path. + @retval EFI_UNSUPPORTED Could not open the file path. @retval EFI_NOT_FOUND The specified file could not be found on the - device or the file system could not be found + device, or the file system could not be found on the device. - @retval EFI_NO_MEDIA The device has no medium. - @retval EFI_MEDIA_CHANGED The device has a different medium in it or the + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellCreateDirectory( IN CONST CHAR16 *DirectoryName, - OUT EFI_FILE_HANDLE *FileHandle + OUT SHELL_FILE_HANDLE *FileHandle ); /** @@ -198,22 +205,22 @@ ShellCreateDirectory( EFI_FILE_INFO is the structure returned as the directory entry. @param[in] FileHandle The opened file handle. - @param[in] ReadSize On input the size of buffer in bytes. On return + @param[in,out] ReadSize On input the size of buffer in bytes. On return the number of bytes written. @param[out] Buffer The buffer to put read data into. - @retval EFI_SUCCESS Data was read. + @retval EFI_SUCCESS Data was read. @retval EFI_NO_MEDIA The device has no media. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required + @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required size. **/ EFI_STATUS EFIAPI ShellReadFile( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *ReadSize, OUT VOID *Buffer ); @@ -230,24 +237,24 @@ ShellReadFile( @param[in] FileHandle The opened file for writing. - @param[in] BufferSize On input the number of bytes in Buffer. On output + @param[in,out] BufferSize On input the number of bytes in Buffer. On output the number of bytes written. @param[in] Buffer The buffer containing data to write is stored. - @retval EFI_SUCCESS Data was written. - @retval EFI_UNSUPPORTED Writes to an open directory are not supported. + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to an open directory are not supported. @retval EFI_NO_MEDIA The device has no media. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The device is write-protected. - @retval EFI_ACCESS_DENIED The file was open for read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write-protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellWriteFile( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *BufferSize, IN VOID *Buffer ); @@ -262,12 +269,12 @@ ShellWriteFile( @param[in] FileHandle The file handle to close. @retval EFI_SUCCESS The file handle was closed sucessfully. - @retval INVALID_PARAMETER One of the parameters has an invalid value. + @retval INVALID_PARAMETER One of the parameters has an invalid value. **/ EFI_STATUS EFIAPI ShellCloseFile ( - IN EFI_FILE_HANDLE *FileHandle + IN SHELL_FILE_HANDLE *FileHandle ); /** @@ -287,7 +294,7 @@ ShellCloseFile ( EFI_STATUS EFIAPI ShellDeleteFile ( - IN EFI_FILE_HANDLE *FileHandle + IN SHELL_FILE_HANDLE *FileHandle ); /** @@ -295,15 +302,15 @@ ShellDeleteFile ( This function sets the current file position for the handle to the position supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only - absolute positioning is supported, and seeking past the end of the file is - allowed (a subsequent write would grow the file). Seeking to position + absolute positioning is supported, and moving past the end of the file is + allowed (a subsequent write would grow the file). Moving to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. If FileHandle is a directory, the only position that may be set is zero. This has the effect of starting the read process of the directory entries over. @param[in] FileHandle The file handle on which the position is being set. - @param[in] Position Byte position from begining of file. + @param[in] Position The byte position from the begining of the file. @retval EFI_SUCCESS Operation completed sucessfully. @retval EFI_UNSUPPORTED The seek request for non-zero is not valid on @@ -313,7 +320,7 @@ ShellDeleteFile ( EFI_STATUS EFIAPI ShellSetFilePosition ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN UINT64 Position ); @@ -326,7 +333,7 @@ ShellSetFilePosition ( if FileHandle is a directory. @param[in] FileHandle The open file handle on which to get the position. - @param[out] Position Byte position from begining of file. + @param[out] Position The byte position from the begining of the file. @retval EFI_SUCCESS The operation completed sucessfully. @retval INVALID_PARAMETER One of the parameters has an invalid value. @@ -335,7 +342,7 @@ ShellSetFilePosition ( EFI_STATUS EFIAPI ShellGetFilePosition ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Position ); @@ -356,7 +363,7 @@ ShellGetFilePosition ( EFI_STATUS EFIAPI ShellFlushFile ( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** @@ -368,20 +375,20 @@ ShellFlushFile ( Caller must use FreePool on *Buffer opon completion of all file searching. - @param[in] DirHandle The file handle of the directory to search - @param[out] Buffer Pointer to pointer to buffer for file's information + @param[in] DirHandle The file handle of the directory to search. + @param[out] Buffer The pointer to the buffer for the file's information. @retval EFI_SUCCESS Found the first file. @retval EFI_NOT_FOUND Cannot find the directory. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @return ShellReadFile + @sa ShellReadFile **/ EFI_STATUS EFIAPI ShellFindFirstFile ( - IN EFI_FILE_HANDLE DirHandle, + IN SHELL_FILE_HANDLE DirHandle, OUT EFI_FILE_INFO **Buffer ); @@ -392,24 +399,25 @@ ShellFindFirstFile ( first file, and then use this function get other files. This function can be called for several times to get each file's information in the directory. If the call of ShellFindNextFile() got the last file in the directory, the next - call of this function has no file to get. *NoFile will be set to TRUE and the + call of this function has no file to get. *NoFile will be set to TRUE, and the data in Buffer is meaningless. @param[in] DirHandle The file handle of the directory. - @param[out] Buffer Pointer to buffer for file's information. - @param[out] NoFile Pointer to boolean when last file is found. + @param[in,out] Buffer The pointer to buffer for file's information. + @param[in,out] NoFile The pointer to boolean when last file is found. @retval EFI_SUCCESS Found the next file. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @sa ShellReadFile **/ EFI_STATUS EFIAPI ShellFindNextFile( - IN EFI_FILE_HANDLE DirHandle, - OUT EFI_FILE_INFO *Buffer, - OUT BOOLEAN *NoFile + IN SHELL_FILE_HANDLE DirHandle, + IN OUT EFI_FILE_INFO *Buffer, + IN OUT BOOLEAN *NoFile ); /** @@ -419,7 +427,7 @@ ShellFindNextFile( data. @param[in] FileHandle The file handle from which size is retrieved. - @param[out] Size Pointer to size. + @param[out] Size The pointer to size. @retval EFI_SUCCESS The operation was completed sucessfully. @retval EFI_DEVICE_ERROR Cannot access the file. @@ -427,7 +435,7 @@ ShellFindNextFile( EFI_STATUS EFIAPI ShellGetFileSize ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Size ); @@ -436,8 +444,8 @@ ShellGetFileSize ( This function is useful to check whether the application is being asked to halt by the shell. - @retval TRUE the execution break is enabled - @retval FALSE the execution break is not enabled + @retval TRUE The execution break is enabled. + @retval FALSE The execution break is not enabled. **/ BOOLEAN EFIAPI @@ -454,7 +462,7 @@ ShellGetExecutionBreakFlag( @param[in] EnvKey The key name of the environment variable. @retval NULL The named environment variable does not exist. - @return != NULL pointer to the value of the environment variable. + @return != NULL The pointer to the value of the environment variable. **/ CONST CHAR16* EFIAPI @@ -479,8 +487,8 @@ ShellGetEnvironmentVariable ( @param[in] EnvVal The Value of the environment variable @param[in] Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). - @retval EFI_SUCCESS the operation was completed sucessfully - @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments + @retval EFI_SUCCESS The operation completed sucessfully + @retval EFI_UNSUPPORTED This operation is not allowed in pre-UEFI 2.0 Shell environments. **/ EFI_STATUS EFIAPI @@ -507,11 +515,11 @@ ShellSetEnvironmentVariable ( ShellExecute() function. The Output parameter has no effect in a UEFI Shell 2.0 environment. - @param[in] ImageHandle Parent image that is starting the operation. - @param[in] CommandLine Pointer to NULL terminated command line. + @param[in] ParentHandle The parent image starting the operation. + @param[in] CommandLine The pointer to a NULL terminated command line. @param[in] Output True to display debug output. False to hide it. @param[in] EnvironmentVariables Optional pointer to array of environment variables - in the form "x=y". If NULL current set is used. + in the form "x=y". If NULL, the current set is used. @param[out] Status The status of the run command line. @retval EFI_SUCCESS The operation completed sucessfully. Status @@ -545,7 +553,7 @@ ShellExecute ( CONST CHAR16* EFIAPI ShellGetCurrentDir ( - IN CHAR16 *DeviceName OPTIONAL + IN CHAR16 * CONST DeviceName OPTIONAL ); /** @@ -575,9 +583,9 @@ ShellSetPageBreakMode ( If you are NOT appending to an existing list *ListHead must be NULL. If *ListHead is NULL then it must be callee freed. - @param[in] Arg Pointer to path string. + @param[in] Arg The pointer to path string. @param[in] OpenMode Mode to open files with. - @param[in] ListHead Head of linked list of results. + @param[in,out] ListHead Head of linked list of results. @retval EFI_SUCCESS The operation was sucessful and the list head contains the list of opened files. @@ -596,7 +604,7 @@ ShellOpenFileMetaArg ( /** Free the linked list returned from ShellOpenFileMetaArg. - @param[in] ListHead The pointer to free. + @param[in,out] ListHead The pointer to free. @retval EFI_SUCCESS The operation was sucessful. @retval EFI_INVALID_PARAMETER A parameter was invalid. @@ -631,12 +639,12 @@ ShellFindFilePath ( in the order provided and return the first one that is successful. If FileName is NULL, then ASSERT. - If FileExtension is NULL, then behavior is identical to ShellFindFilePath. + If FileExtension is NULL, then the behavior is identical to ShellFindFilePath. If the return value is not NULL then the memory must be caller freed. - @param[in] FileName Filename string. - @param[in] FileExtension Semi-colon delimeted list of possible extensions. + @param[in] FileName The filename string. + @param[in] FileExtension Semicolon delimited list of possible extensions. @retval NULL The file was not found. @retval !NULL The path to the file. @@ -656,25 +664,28 @@ typedef enum { TypeDoubleValue, ///< A flag that has 2 space seperated value data following it (IE "-a 1 2"). TypeMaxValue, ///< A flag followed by all the command line data before the next flag. TypeMax, -} ParamType; +} SHELL_PARAM_TYPE; typedef struct { - CHAR16 *Name; - ParamType Type; + CHAR16 *Name; + SHELL_PARAM_TYPE Type; } SHELL_PARAM_ITEM; /// Helper structure for no parameters (besides -? and -b) extern SHELL_PARAM_ITEM EmptyParamList[]; +/// Helper structure for -sfo only (besides -? and -b) +extern SHELL_PARAM_ITEM SfoParamList[]; + /** Checks the command line arguments passed against the list of valid ones. Optionally removes NULL values first. If no initialization is required, then return RETURN_SUCCESS. - @param[in] CheckList Pointer to list of parameters to check. - @param[out] CheckPackage Package of checked values. + @param[in] CheckList The pointer to list of parameters to check. + @param[out] CheckPackage The package of checked values. @param[out] ProblemParam Optional pointer to pointer to unicode string for the paramater that caused failure. @param[in] AutoPageBreak Will automatically set PageBreakEnabled. @@ -683,9 +694,7 @@ extern SHELL_PARAM_ITEM EmptyParamList[]; @retval EFI_SUCCESS The operation completed sucessfully. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @retval EFI_INVALID_PARAMETER A parameter was invalid. - @retval EFI_VOLUME_CORRUPTED The command line was corrupt. An argument was - duplicated. The duplicated command line argument - was returned in ProblemParam if provided. + @retval EFI_VOLUME_CORRUPTED The command line was corrupt. @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One of the command line arguments was returned in ProblemParam if provided. @@ -735,12 +744,12 @@ ShellCommandLineFreeVarList ( @retval TRUE The flag is on the command line. @retval FALSE The flag is not on the command line. - **/ +**/ BOOLEAN EFIAPI ShellCommandLineGetFlag ( - IN CONST LIST_ENTRY *CheckPackage, - IN CHAR16 *KeyString + IN CONST LIST_ENTRY * CONST CheckPackage, + IN CONST CHAR16 * CONST KeyString ); /** @@ -754,8 +763,8 @@ ShellCommandLineGetFlag ( @param[in] KeyString The Key of the command line argument to check for. @retval NULL The flag is not on the command line. - @retval !=NULL Pointer to unicode string of the value. - **/ + @retval !=NULL The pointer to unicode string of the value. +**/ CONST CHAR16* EFIAPI ShellCommandLineGetValue ( @@ -774,13 +783,13 @@ ShellCommandLineGetValue ( @param[in] Position The position of the value. @retval NULL The flag is not on the command line. - @retval !=NULL Pointer to unicode string of the value. - **/ + @retval !=NULL The pointer to unicode string of the value. +**/ CONST CHAR16* EFIAPI ShellCommandLineGetRawValue ( - IN CONST LIST_ENTRY *CheckPackage, - IN UINT32 Position + IN CONST LIST_ENTRY * CONST CheckPackage, + IN UINTN Position ); /** @@ -788,20 +797,22 @@ ShellCommandLineGetRawValue ( This will not include flags. - @retval (UINTN)-1 No parsing has ocurred. - @return The number of value parameters found. + @param[in] CheckPackage The package of parsed command line arguments. + + @retval (UINTN)-1 No parsing has occurred. + @retval other The number of value parameters found. **/ UINTN EFIAPI ShellCommandLineGetCount( - VOID + IN CONST LIST_ENTRY *CheckPackage ); /** - Determins if a parameter is duplicated. + Determines if a parameter is duplicated. - If Param is not NULL then it will point to a callee allocated string buffer - with the parameter value if a duplicate is found. + If Param is not NULL, then it will point to a callee-allocated string buffer + with the parameter value, if a duplicate is found. If CheckPackage is NULL, then ASSERT. @@ -820,7 +831,7 @@ ShellCommandLineCheckDuplicate ( /** This function causes the shell library to initialize itself. If the shell library - is already initialized it will de-initialize all the current protocol poitners and + is already initialized it will de-initialize all the current protocol pointers and re-populate them again. When the library is used with PcdShellLibAutoInitialize set to true this function @@ -828,7 +839,7 @@ ShellCommandLineCheckDuplicate ( This function is intended for internal access for shell commands only. - @retval EFI_SUCCESS the initialization was complete sucessfully + @retval EFI_SUCCESS The initialization was complete sucessfully. **/ EFI_STATUS @@ -858,14 +869,15 @@ ShellInitialize ( Note: The background color is controlled by the shell command cls. - @param[in] Row The row to print at. @param[in] Col The column to print at. + @param[in] Row The row to print at. @param[in] Format The format string. + @param[in] ... The variable argument list. - @return The number of characters printed to the screen. + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. **/ - -UINTN +EFI_STATUS EFIAPI ShellPrintEx( IN INT32 Col OPTIONAL, @@ -895,16 +907,18 @@ ShellPrintEx( Note: The background color is controlled by the shell command cls. - @param[in] Row The row to print at. @param[in] Col The column to print at. + @param[in] Row The row to print at. @param[in] Language The language of the string to retrieve. If this parameter is NULL, then the current platform language is used. @param[in] HiiFormatStringId The format string Id for getting from Hii. @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param[in] ... The variable argument list. - @return the number of characters printed to the screen. + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. **/ -UINTN +EFI_STATUS EFIAPI ShellPrintHiiEx( IN INT32 Col OPTIONAL, @@ -999,7 +1013,7 @@ ShellStrToUintn( given in CurrentSize the string will be grown such that the copy can be performed and CurrentSize will be updated to the new size. - If Source is NULL, there is nothing to append, just return the current buffer in + If Source is NULL, there is nothing to append, so return the current buffer in Destination. If Destination is NULL, then ASSERT(). @@ -1007,14 +1021,14 @@ ShellStrToUintn( CurrentSize, then ASSERT(). @param[in,out] Destination The String to append onto. - @param[in,out] CurrentSize On call the number of bytes in Destination. On - return possibly the new size (still in bytes). If NULL + @param[in,out] CurrentSize On call, the number of bytes in Destination. On + return, possibly the new size (still in bytes). If NULL, then allocate whatever is needed. @param[in] Source The String to append from. - @param[in] Count Maximum number of characters to append. If 0 then + @param[in] Count The maximum number of characters to append. If 0, then all are appended. - @return The Destination after apending the Source. + @return The Destination after appending the Source. **/ CHAR16* EFIAPI @@ -1033,13 +1047,14 @@ StrnCatGrow ( If the string would grow bigger than NewSize it will halt and return error. - @param[in] SourceString String with source buffer. - @param[in,out] NewString String with resultant buffer. - @param[in] NewSize Size in bytes of NewString. - @param[in] FindTarget String to look for. - @param[in] ReplaceWith String to replace FindTarget with. + @param[in] SourceString The string with source buffer. + @param[in,out] NewString The string with resultant buffer. + @param[in] NewSize The size in bytes of NewString. + @param[in] FindTarget The string to look for. + @param[in] ReplaceWith The string to replace FindTarget with. @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^' immediately before it. + @param[in] ParameterReplacing If TRUE will add "" around items with spaces. @retval EFI_INVALID_PARAMETER SourceString was NULL. @retval EFI_INVALID_PARAMETER NewString was NULL. @@ -1049,36 +1064,32 @@ StrnCatGrow ( @retval EFI_INVALID_PARAMETER SourceString had length < 1. @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold the new string (truncation occurred). - @retval EFI_SUCCESS The string was sucessfully copied with replacement. + @retval EFI_SUCCESS The string was successfully copied with replacement. **/ - EFI_STATUS EFIAPI -ShellCopySearchAndReplace2( +ShellCopySearchAndReplace( IN CHAR16 CONST *SourceString, - IN CHAR16 *NewString, + IN OUT CHAR16 *NewString, IN UINTN NewSize, IN CONST CHAR16 *FindTarget, IN CONST CHAR16 *ReplaceWith, - IN CONST BOOLEAN SkipPreCarrot + IN CONST BOOLEAN SkipPreCarrot, + IN CONST BOOLEAN ParameterReplacing ); -/// -/// make upgrades easier from old version -/// -#define ShellLibCopySearchAndReplace(a,b,c,d,e) ShellCopySearchAndReplace2(a,b,c,d,e,FALSE) - /** Check if a Unicode character is a hexadecimal character. This internal function checks if a Unicode character is a - decimal character. The valid hexadecimal character is + numeric character. The valid hexadecimal characters are L'0' to L'9', L'a' to L'f', or L'A' to L'F'. - @param[in] Char The character to check. - @retval TRUE The Char is a hexadecmial character. - @retval FALSE The Char is not a hexadecmial character. + @param Char The character to check against. + + @retval TRUE The Char is a hexadecmial character. + @retval FALSE The Char is not a hexadecmial character. **/ BOOLEAN @@ -1087,31 +1098,51 @@ ShellIsHexaDecimalDigitCharacter ( IN CHAR16 Char ); +/** + Check if a Unicode character is a decimal character. + + This internal function checks if a Unicode character is a + decimal character. The valid characters are + L'0' to L'9'. + + + @param Char The character to check against. + + @retval TRUE The Char is a hexadecmial character. + @retval FALSE The Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsDecimalDigitCharacter ( + IN CHAR16 Char + ); + /// -/// What type of answer is requested +/// What type of answer is requested. /// typedef enum { - SHELL_PROMPT_REQUEST_TYPE_YES_NO, - SHELL_PROMPT_REQUEST_TYPE_YES_NO_CANCEL, - SHELL_PROMPT_REQUEST_TYPE_FREEFORM, - SHELL_PROMPT_REQUEST_TYPE_QUIT_CONTINUE, - SHELL_PROMPT_REQUEST_TYPE_YES_NO_ALL_CANCEL, - SHELL_PROMPT_REQUEST_TYPE_ENTER_TO_COMTINUE, - SHELL_PROMPT_REQUEST_TYPE_ANYKEY_TO_COMTINUE, - SHELL_PROMPT_REQUEST_TYPE_MAX + ShellPromptResponseTypeYesNo, + ShellPromptResponseTypeYesNoCancel, + ShellPromptResponseTypeFreeform, + ShellPromptResponseTypeQuitContinue, + ShellPromptResponseTypeYesNoAllCancel, + ShellPromptResponseTypeEnterContinue, + ShellPromptResponseTypeAnyKeyContinue, + ShellPromptResponseTypeMax } SHELL_PROMPT_REQUEST_TYPE; /// -/// what answer was given +/// What answer was given. /// typedef enum { - SHELL_PROMPT_RESPONSE_YES, - SHELL_PROMPT_RESPONSE_NO, - SHELL_PROMPT_RESPONSE_CANCEL, - SHELL_PROMPT_RESPONSE_QUIT, - SHELL_PROMPT_RESPONSE_CONTINUE, - SHELL_PROMPT_RESPONSE_ALL, - SHELL_PROMPT_RESPONSE_MAX + ShellPromptResponseYes, + ShellPromptResponseNo, + ShellPromptResponseCancel, + ShellPromptResponseQuit, + ShellPromptResponseContinue, + ShellPromptResponseAll, + ShellPromptResponseMax } SHELL_PROMPT_RESPONSE; /** @@ -1120,23 +1151,22 @@ typedef enum { This function will display the requested question on the shell prompt and then wait for an apropriate answer to be input from the console. - if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, SHELL_PROMPT_REQUEST_TYPE_QUIT_CONTINUE + If the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE. - if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_FREEFORM then *Response is of type + If the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type CHAR16*. In either case *Response must be callee freed if Response was not NULL; @param Type What type of question is asked. This is used to filter the input to prevent invalid answers to question. - @param Prompt Pointer to string prompt to use to request input. - @param Response Pointer to Response which will be populated upon return. + @param Prompt The pointer to a string prompt used to request input. + @param Response The pointer to Response, which will be populated upon return. - @retval EFI_SUCCESS The operation was sucessful. + @retval EFI_SUCCESS The operation was successful. @retval EFI_UNSUPPORTED The operation is not supported as requested. @retval EFI_INVALID_PARAMETER A parameter was invalid. - @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @return other The operation failed. **/ EFI_STATUS @@ -1155,11 +1185,12 @@ ShellPromptForResponse ( @param Type What type of question is asked. This is used to filter the input to prevent invalid answers to question. - @param Prompt Pointer to string prompt to use to request input. - @param Response Pointer to Response which will be populated upon return. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param Response The pointer to Response, which will be populated upon return. - @retval EFI_SUCCESS the operation was sucessful. - @return other the operation failed. + @retval EFI_SUCCESS The operation was sucessful. + @return other The operation failed. @sa ShellPromptForResponse **/ @@ -1172,5 +1203,39 @@ ShellPromptForResponseHii ( IN OUT VOID **Response ); +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x or has ForceHex, set TRUE. + + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +EFIAPI +ShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ); + +/** + Function to determine if a given filename exists. + + @param[in] Name Path to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellFileExists( + IN CONST CHAR16 *Name + ); #endif // __SHELL_LIB__ diff --git a/ShellPkg/Include/Library/SortLib.h b/ShellPkg/Include/Library/SortLib.h index c8b68d9381..c8a5ccf0f0 100644 --- a/ShellPkg/Include/Library/SortLib.h +++ b/ShellPkg/Include/Library/SortLib.h @@ -1,7 +1,7 @@ /** @file Library used for sorting and comparison routines. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 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 @@ -12,18 +12,18 @@ **/ -#if !defined(__SORT_LIB_H__) +#ifndef __SORT_LIB_H__ #define __SORT_LIB_H__ /** - Prototype for comparison function for any 2 element types. + Prototype for comparison function for any two element types. - @param[in] Buffer1 Pointer to first buffer. - @param[in] Buffer2 Pointer to second buffer. + @param[in] Buffer1 The pointer to first buffer. + @param[in] Buffer2 The pointer to second buffer. @retval 0 Buffer1 equal to Buffer2. - @return < 0 Buffer1 is less than Buffer2. - @return > 0 Buffer1 is greater than Buffer2. + @return <0 Buffer1 is less than Buffer2. + @return >0 Buffer1 is greater than Buffer2. **/ typedef INTN @@ -40,15 +40,15 @@ INTN If BufferToSort is NULL, then ASSERT. If CompareFunction is NULL, then ASSERT. - If Count is < 2 then perform no action. - If Size is < 1 then perform no action. + If Count is < 2 , then perform no action. + If Size is < 1 , then perform no action. - @param[in,out] BufferToSort On call a Buffer of (possibly sorted) elements - on return a buffer of sorted elements. - @param[in] Count The number of elements in the buffer to sort - @param[in] ElementSize Size of an element in bytes. + @param[in,out] BufferToSort On call, a Buffer of (possibly sorted) elements; + on return, a buffer of sorted elements. + @param[in] Count The number of elements in the buffer to sort. + @param[in] ElementSize The size of an element in bytes. @param[in] CompareFunction The function to call to perform the comparison - of any 2 elements. + of any two elements. **/ VOID EFIAPI @@ -63,8 +63,8 @@ PerformQuickSort ( /** Function to compare 2 device paths for use as CompareFunction. - @param[in] Buffer1 Pointer to Device Path to compare. - @param[in] Buffer2 Pointer to second DevicePath to compare. + @param[in] Buffer1 The pointer to Device Path to compare. + @param[in] Buffer2 The pointer to second DevicePath to compare. @retval 0 Buffer1 equal to Buffer2. @return < 0 Buffer1 is less than Buffer2. @@ -80,8 +80,8 @@ DevicePathCompare ( /** Function to compare 2 strings without regard to case of the characters. - @param[in] Buffer1 Pointer to String to compare (CHAR16**). - @param[in] Buffer2 Pointer to second String to compare (CHAR16**). + @param[in] Buffer1 The pointer to String to compare (CHAR16**). + @param[in] Buffer2 The pointer to second String to compare (CHAR16**). @retval 0 Buffer1 equal to Buffer2. @return < 0 Buffer1 is less than Buffer2. @@ -94,4 +94,21 @@ StringNoCaseCompare ( IN CONST VOID *Buffer2 ); +/** + Function to compare 2 strings. + + @param[in] Buffer1 The pointer to String to compare (CHAR16**). + @param[in] Buffer2 The pointer to second String to compare (CHAR16**). + + @retval 0 Buffer1 equal to Buffer2. + @return < 0 Buffer1 is less than Buffer2. + @return > 0 Buffer1 is greater than Buffer2. +**/ +INTN +EFIAPI +StringCompare ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 + ); + #endif //__SORT_LIB_H__ diff --git a/ShellPkg/Include/Protocol/EfiShell.h b/ShellPkg/Include/Protocol/EfiShell.h index 35a6e0a2f8..ce38e0e439 100644 --- a/ShellPkg/Include/Protocol/EfiShell.h +++ b/ShellPkg/Include/Protocol/EfiShell.h @@ -1,7 +1,7 @@ /** @file EFI Shell protocol as defined in the UEFI Shell 2.0 specification including errata. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 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 @@ -15,7 +15,7 @@ #ifndef __EFI_SHELL_PROTOCOL__ #define __EFI_SHELL_PROTOCOL__ -#include +#include #include #define EFI_SHELL_PROTOCOL_GUID \ @@ -26,12 +26,12 @@ // replaced EFI_LIST_ENTRY with LIST_ENTRY for simplicity. // they are identical outside of the name. typedef struct { - LIST_ENTRY Link; ///< Linked list members. - EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL. - CONST CHAR16 *FullName; ///< Fully qualified filename. - CONST CHAR16 *FileName; ///< name of this file. - EFI_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed. - EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL. + LIST_ENTRY Link; ///< Linked list members. + EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL. + CONST CHAR16 *FullName; ///< Fully qualified filename. + CONST CHAR16 *FileName; ///< name of this file. + SHELL_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed. + EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL. } EFI_SHELL_FILE_INFO; /** @@ -61,7 +61,7 @@ BOOLEAN typedef EFI_STATUS (EFIAPI *EFI_SHELL_CLOSE_FILE)( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** @@ -79,9 +79,9 @@ EFI_STATUS already exists and is non-volatile then EFI_INVALID_PARAMETER is returned. @param[in] FileName Pointer to NULL-terminated file path. - @param[in] FileAttribs The new file's attrbiutes. the different attributes are + @param[in] FileAttribs The new file's attrbiutes. The different attributes are described in EFI_FILE_PROTOCOL.Open(). - @param[out] FileHandle On return, points to the created file handle or directory's handle + @param[out] FileHandle On return, points to the created file handle or directory's handle. @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. @@ -103,9 +103,9 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_CREATE_FILE)( - IN CONST CHAR16 *FileName, - IN UINT64 FileAttribs, - OUT EFI_FILE_HANDLE *FileHandle + IN CONST CHAR16 *FileName, + IN UINT64 FileAttribs, + OUT SHELL_FILE_HANDLE *FileHandle ); /** @@ -123,7 +123,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_DELETE_FILE)( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** @@ -194,10 +194,10 @@ VOID typedef EFI_STATUS (EFIAPI *EFI_SHELL_EXECUTE) ( - IN EFI_HANDLE *ParentImageHandle, - IN CHAR16 *CommandLine OPTIONAL, - IN CHAR16 **Environment OPTIONAL, - OUT EFI_STATUS *StatusCode OPTIONAL + IN EFI_HANDLE *ParentImageHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN CHAR16 **Environment OPTIONAL, + OUT EFI_STATUS *StatusCode OPTIONAL ); /** @@ -224,8 +224,8 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_FIND_FILES)( - IN CONST CHAR16 *FilePattern, - OUT EFI_SHELL_FILE_INFO **FileList + IN CONST CHAR16 *FilePattern, + OUT EFI_SHELL_FILE_INFO **FileList ); /** @@ -243,8 +243,8 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_FIND_FILES_IN_DIR)( -IN EFI_FILE_HANDLE FileDirHandle, -OUT EFI_SHELL_FILE_INFO **FileList +IN SHELL_FILE_HANDLE FileDirHandle, +OUT EFI_SHELL_FILE_INFO **FileList ); /** @@ -265,7 +265,7 @@ OUT EFI_SHELL_FILE_INFO **FileList typedef EFI_STATUS (EFIAPI *EFI_SHELL_FLUSH_FILE)( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** @@ -342,10 +342,10 @@ typedef UINT32 EFI_SHELL_DEVICE_NAME_FLAGS; typedef EFI_STATUS (*EFI_SHELL_GET_DEVICE_NAME) ( - IN EFI_HANDLE DeviceHandle, - IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, - IN CHAR8 *Language, - OUT CHAR16 **BestDeviceName + IN EFI_HANDLE DeviceHandle, + IN EFI_SHELL_DEVICE_NAME_FLAGS Flags, + IN CHAR8 *Language, + OUT CHAR16 **BestDeviceName ); /** @@ -427,7 +427,7 @@ CONST CHAR16 * typedef EFI_FILE_INFO * (EFIAPI *EFI_SHELL_GET_FILE_INFO)( - IN EFI_FILE_HANDLE FileHandle + IN SHELL_FILE_HANDLE FileHandle ); /** @@ -464,7 +464,7 @@ CHAR16 * typedef EFI_STATUS (EFIAPI *EFI_SHELL_GET_FILE_POSITION)( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Position ); @@ -482,7 +482,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_GET_FILE_SIZE)( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Size ); @@ -629,7 +629,7 @@ typedef EFI_STATUS (EFIAPI *EFI_SHELL_OPEN_FILE_BY_NAME) ( IN CONST CHAR16 *FileName, - OUT EFI_FILE_HANDLE *FileHandle, + OUT SHELL_FILE_HANDLE *FileHandle, IN UINT64 OpenMode ); @@ -676,7 +676,7 @@ typedef EFI_STATUS (EFIAPI *EFI_SHELL_OPEN_ROOT)( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, - OUT EFI_FILE_HANDLE *FileHandle + OUT SHELL_FILE_HANDLE *FileHandle ); /** @@ -698,7 +698,7 @@ typedef EFI_STATUS (EFIAPI *EFI_SHELL_OPEN_ROOT_BY_HANDLE)( IN EFI_HANDLE DeviceHandle, - OUT EFI_FILE_HANDLE *FileHandle + OUT SHELL_FILE_HANDLE *FileHandle ); /** @@ -723,7 +723,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_READ_FILE) ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *ReadSize, IN OUT VOID *Buffer ); @@ -873,7 +873,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_SET_FILE_INFO)( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN CONST EFI_FILE_INFO *FileInfo ); @@ -895,7 +895,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_SET_FILE_POSITION)( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN UINT64 Position ); @@ -945,7 +945,7 @@ EFI_STATUS typedef EFI_STATUS (EFIAPI *EFI_SHELL_WRITE_FILE)( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *BufferSize, IN VOID *Buffer ); diff --git a/ShellPkg/Include/Protocol/EfiShellEnvironment2.h b/ShellPkg/Include/Protocol/EfiShellEnvironment2.h index 1c82853027..ad0b551b96 100644 --- a/ShellPkg/Include/Protocol/EfiShellEnvironment2.h +++ b/ShellPkg/Include/Protocol/EfiShellEnvironment2.h @@ -13,7 +13,7 @@ **/ -#if !defined (_SHELL_ENVIRONMENT_2_PROTOCOL_H_) +#ifndef _SHELL_ENVIRONMENT_2_PROTOCOL_H_ #define _SHELL_ENVIRONMENT_2_PROTOCOL_H_ #define DEFAULT_INIT_ROW 1 @@ -24,8 +24,8 @@ to a given location. The location is dependant on the implementation. This is used when programatically adding shell commands. - @param Handle The handle the protocol is on. - @param Interface The interface to the protocol. + @param[in] Handle The handle the protocol is on. + @param[in] Interface The interface to the protocol. **/ typedef @@ -40,11 +40,11 @@ VOID implementation. The specific command depends on the implementation. This is used when programatically adding shell commands. - @param ImageHandle The handle to the binary shell. - @param SystemTable Pointer to the system table. + @param[in] ImageHandle The handle to the binary shell. + @param[in] SystemTable The pointer to the system table. - @retval EFI_SUCCESS The command ran to completion - @retval other An error ocurred. Any error is possible + @retval EFI_SUCCESS The command completed. + @retval other An error occurred. Any error is possible depending on the implementation of the shell command. @@ -61,7 +61,7 @@ EFI_STATUS This is used when programatically adding shell commands. Upon successful return the memory allocated is up to the caller to free. - @param Str Pointer to pointer to string to display for help. + @param[in,out] Str Pointer to pointer to string to display for help. @retval EFI_SUCCESS The help string is in the parameter Str. @@ -111,8 +111,8 @@ GUID for the shell environment2 extension (main GUID above). 0xd2c18636, 0x40e5, 0x4eb5, {0xa3, 0x1b, 0x36, 0x69, 0x5f, 0xd4, 0x2c, 0x87} \ } -#define EFI_SHELL_MAJOR_VER 0x00000001 ///< Major version of the EFI_SHELL_ENVIRONMENT2 -#define EFI_SHELL_MINOR_VER 0x00000000 ///< Minor version of the EFI_SHELL_ENVIRONMENT2 +#define EFI_SHELL_MAJOR_VER 0x00000001 ///< Major version of the EFI_SHELL_ENVIRONMENT2. +#define EFI_SHELL_MINOR_VER 0x00000000 ///< Minor version of the EFI_SHELL_ENVIRONMENT2. /** Execute a command line. @@ -121,13 +121,13 @@ GUID for the shell environment2 extension (main GUID above). parsing any requires scripts, and if DebugOutput is TRUE printing errors encountered directly to the screen. - @param ParentImageHandle Handle of image executing this operation. - @param CommandLine The string command line to execute. - @param DebugOutput TRUE indicates that errors should be printed directly. + @param[in] ParentImageHandle Handle of the image executing this operation. + @param[in] CommandLine The string command line to execute. + @param[in] DebugOutput TRUE indicates that errors should be printed directly. FALSE supresses error messages. @retval EFI_SUCCESS The command line executed and completed. - @retval EFI_ABORTED The operation did not complete due to abort. + @retval EFI_ABORTED The operation aborted. @retval EFI_INVALID_PARAMETER A parameter did not have a valid value. @retval EFI_OUT_OF_RESOURCES A required memory allocation failed. @@ -144,7 +144,7 @@ EFI_STATUS /** This function returns a shell environment variable value. - @param Name Pointer to the string with the shell environment + @param[in] Name The pointer to the string with the shell environment variable name. @retval NULL The shell environment variable's value could not be found. @@ -160,7 +160,7 @@ CHAR16 * /** This function returns a shell environment map value. - @param Name Pointer to the string with the shell environment + @param[in] Name The pointer to the string with the shell environment map name. @retval NULL The shell environment map's value could not be found. @@ -179,9 +179,9 @@ CHAR16 * This will allocate all required memory, put the new command on the command list in the correct location. - @param Handler The handler function to call when the command gets called. - @param Cmd The command name. - @param GetLineHelp Function to call of get help for this command. + @param[in] Handler The handler function to call when the command gets called. + @param[in] Cmd The command name. + @param[in] GetLineHelp The function to call of type "get help" for this command. @retval EFI_SUCCESS The command is now part of the command list. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @@ -203,12 +203,12 @@ EFI_STATUS This will get the current protocol info and add the new info or update existing info and then resave the info. - @param Protocol Pointer to the protocol's GUID. - @param DumpToken The function pointer to dump token function or + @param[in] Protocol The pointer to the protocol's GUID. + @param[in] DumpToken The function pointer to dump token function or NULL. - @param DumpInfo The function pointer to dump infomation function + @param[in] DumpInfo The function pointer to dump infomation function or NULL. - @param IdString The english name of the protocol. + @param[in] IdString The English name of the protocol. **/ typedef VOID @@ -226,11 +226,11 @@ VOID found it will return the name of that protocol. If no name is found and GenId is TRUE it will generate ths string. - @param Protocol The GUID of the protocol to look for. - @param GenId Whether to generate a name string if its not found. + @param[in] Protocol The GUID of the protocol to look for. + @param[in] GenId Whether to generate a name string if it is not found. - @return !NULL The Name of the protocol. - @retval NULL The Name was not found and GenId was not TRUE. + @return !NULL The Name of the protocol. + @retval NULL The Name was not found, and GenId was not TRUE. **/ typedef CHAR16* @@ -246,10 +246,10 @@ CHAR16* If DeviceName is specified, then return the current shell directory on that device. If DeviceName is NULL, then return the current directory on the current device. The caller us responsible to free the returned string when - no londer required. + no longer required. - @param DeviceName The name of the device to get the current - directory on or NULL for current device. + @param[in] DeviceName The name of the device to get the current + directory on, or NULL for current device. @return String array with the current directory on the current or specified device. @@ -270,11 +270,11 @@ CHAR16* The memory allocated by the callee for this list is freed by making a call to SHELLENV_FREE_FILE_LIST. - @param Arg Pointer Path to files to open. - @param ListHead Pointer to allocated and initialized list head - upon which to append all the opened file structures. + @param[in] Arg The pointer Path to files to open. + @param[in,out] ListHead The pointer to the allocated and initialized list head + upon which to append all opened file structures. - @retval EFI_SUCCESS 1 or more files was opened and a struct of each file's + @retval EFI_SUCCESS One or more files was opened and a struct of each file's information was appended to ListHead. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @retval EFI_NOT_FOUND No matching files could be found. @@ -289,9 +289,9 @@ EFI_STATUS /** This frees all of the nodes under the ListHead, but not ListHead itself. - @param ListHead Pointer to list to free all nodes of. + @param[in,out] ListHead Pointer to list to free all nodes of. - @retval EFI_SUCCESS Always returned. + @retval EFI_SUCCESS This function always returns EFI_SUCCESS. **/ typedef EFI_STATUS @@ -307,10 +307,10 @@ EFI_STATUS EFI_SHELL_INTERFACE protocol. It is the caller's responsibility to free the memory. - @param ImageHandle The handle which will use the new ShellInterface + @param[in] ImageHandle The handle which will use the new ShellInterface protocol. - @return the newly allocated shell interface protocol. + @return The newly allocated shell interface protocol. **/ typedef @@ -332,12 +332,12 @@ EFI_SHELL_INTERFACE* typedef BOOLEAN (EFIAPI *SHELLENV_BATCH_IS_ACTIVE) ( - IN VOID + VOID ); /** This is an internal shell function to free any and all allocated resources. - This should be called just closing the shell. + This should be called immediately prior to closing the shell. **/ typedef VOID @@ -349,12 +349,12 @@ VOID This function enables the page break mode. This mode causes the output to pause after each complete screen to enable a - user to more easily read it. If AutoWrap is TRUE then rows with too many - characters will be chopped and divided into 2 rows. If FALSE then rows with + user to more easily read it. If AutoWrap is TRUE, then rows with too many + characters will be chopped and divided into 2 rows. If FALSE, then rows with too many characters may not be fully visible to the user on the screen. - @param StartRow The row number to start this on. - @param AutoWrap Whether to auto wrap rows that are too long. + @param[in] StartRow The row number to start this on. + @param[in] AutoWrap Whether to auto wrap rows that are too long. **/ typedef VOID @@ -366,13 +366,13 @@ VOID /** This function disables the page break mode. - Tisabling this causes the output to print out exactly as coded with no breaks + Disabling this causes the output to print out exactly as coded, with no breaks for readability. **/ typedef VOID (EFIAPI *SHELLENV_DISABLE_PAGE_BREAK) ( - IN VOID + VOID ); /** @@ -384,7 +384,7 @@ VOID typedef BOOLEAN (EFIAPI *SHELLENV_GET_PAGE_BREAK) ( - IN VOID + VOID ); /** @@ -395,7 +395,7 @@ BOOLEAN #define EFI_OUTPUT_PAUSE 0x00000002 #define EFI_EXECUTION_BREAK 0x00000004 - @param KeyFilter The new key filter to use. + @param[in] KeyFilter The new key filter to use. **/ typedef VOID @@ -411,12 +411,12 @@ VOID #define EFI_OUTPUT_PAUSE 0x00000002 #define EFI_EXECUTION_BREAK 0x00000004 - @retval the current filter mask. + @retval The current filter mask. **/ typedef UINT32 (EFIAPI *SHELLENV_GET_KEY_FILTER) ( - IN VOID + VOID ); /** @@ -425,33 +425,33 @@ UINT32 This is used to inform a shell application that a break condition has been initiated. Long loops should check this to prevent delays to the break. - @retval TRUE A break has been signaled. the application + @retval TRUE A break has been signaled. The application should exit with EFI_ABORTED as soon as possible. @retval FALSE Continue as normal. **/ typedef BOOLEAN (EFIAPI *SHELLENV_GET_EXECUTION_BREAK) ( - IN VOID + VOID ); /** - This is an internal-shell function used to increment the shell nesting level. + This is an internal shell function used to increment the shell nesting level. **/ typedef VOID (EFIAPI *SHELLENV_INCREMENT_SHELL_NESTING_LEVEL) ( - IN VOID + VOID ); /** - This is an internal-shell function used to decrement the shell nesting level. + This is an internal shell function used to decrement the shell nesting level. **/ typedef VOID (EFIAPI *SHELLENV_DECREMENT_SHELL_NESTING_LEVEL) ( - IN VOID + VOID ); /** @@ -464,7 +464,7 @@ VOID typedef BOOLEAN (EFIAPI *SHELLENV_IS_ROOT_SHELL) ( - IN VOID + VOID ); /** @@ -473,11 +473,11 @@ BOOLEAN This is an internal shell function to handle shell cascading. It restores the original set of console protocols. - @param ConInHandle The handle of ConIn. - @param ConIn Pointer to the location to return the pointer to + @param[in] ConInHandle The handle of ConIn. + @param[in,out] ConIn The pointer to the location to return the pointer to the original console input. - @param ConOutHandle The handle of ConOut - @param ConOut Pointer to the location to return the pointer to + @param[in] ConOutHandle The handle of ConOut + @param[in,out] ConOut The pointer to the location to return the pointer to the original console output. **/ typedef @@ -507,12 +507,12 @@ VOID This is an internal shell function to enumerate the handle database. This function gets the next handle in the handle database. If no handles are - found EFI_NOT_FOUND is returned. If the previous Handle was the last handle + found, EFI_NOT_FOUND is returned. If the previous Handle was the last handle, it is set to NULL before returning. This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. - @param Handle Pointer to pointer to Handle. Will be set + @param[in,out] Handle The pointer to pointer to Handle. It is set on a sucessful return. @retval EFI_SUCCESS The next handle in the handle database is *Handle. @@ -533,10 +533,10 @@ EFI_STATUS This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. - @param SkipNum how many handles to skip + @param[in] SkipNum How many handles to skip - @retval EFI_SUCCESS the next handle in the handle database is *Handle - @retval EFI_ACCESS_DENIED there are not SkipNum handles left in the database + @retval EFI_SUCCESS The next handle in the handle database is *Handle + @retval EFI_ACCESS_DENIED There are not SkipNum handles left in the database **/ typedef EFI_STATUS @@ -552,9 +552,9 @@ EFI_STATUS This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. - @param EnumIndex Where to start. + @param[in] EnumIndex Where to start. - @return the number of handles either read out or skipped before this reset. + @return The number of handles either read out or skipped before this reset. **/ typedef UINTN @@ -568,7 +568,7 @@ UINTN This must be called after INIT_HANDLE_ENUMERATOR. This function releases all memory and resources associated with the handle database. - Tfter this no other handle enumerator functions except INIT_HANDLE_ENUMERATOR will + After this no other handle enumerator functions except INIT_HANDLE_ENUMERATOR will function properly. **/ typedef @@ -584,7 +584,7 @@ VOID This must be called after INIT_HANDLE_ENUMERATOR and before CLOSE_HANDLE_ENUMERATOR. - @return the number of handles in the handle database. + @return The number of handles in the handle database. **/ typedef UINTN @@ -596,12 +596,12 @@ UINTN Handle Enumerator structure. **/ typedef struct { - INIT_HANDLE_ENUMERATOR Init; ///< Pointer to INIT_HANDLE_ENUMERATOR function. - NEXT_HANDLE Next; ///< Pointer to NEXT_HANDLE function. - SKIP_HANDLE Skip; ///< Pointer to SKIP_HANDLE function. - RESET_HANDLE_ENUMERATOR Reset; ///< Pointer to RESET_HANDLE_ENUMERATOR function. - CLOSE_HANDLE_ENUMERATOR Close; ///< Pointer to CLOSE_HANDLE_ENUMERATOR function. - GET_NUM GetNum; ///< Pointer to GET_NUM function. + INIT_HANDLE_ENUMERATOR Init; ///< The pointer to INIT_HANDLE_ENUMERATOR function. + NEXT_HANDLE Next; ///< The pointer to NEXT_HANDLE function. + SKIP_HANDLE Skip; ///< The pointer to SKIP_HANDLE function. + RESET_HANDLE_ENUMERATOR Reset; ///< The pointer to RESET_HANDLE_ENUMERATOR function. + CLOSE_HANDLE_ENUMERATOR Close; ///< The pointer to CLOSE_HANDLE_ENUMERATOR function. + GET_NUM GetNum; ///< The pointer to GET_NUM function. } HANDLE_ENUMERATOR; /** @@ -614,18 +614,18 @@ typedef struct { **/ typedef struct { UINTN Signature; ///< PROTOCOL_INFO_SIGNATURE. - LIST_ENTRY Link; ///< Standard lined list helper member. + LIST_ENTRY Link; ///< Standard linked list helper member. // // The parsing info for the protocol. // - EFI_GUID ProtocolId; ///< GUID for the protocol. - CHAR16 *IdString; ///< Name of the protocol. - SHELLENV_DUMP_PROTOCOL_INFO DumpToken; ///< Pointer to DumpToken function for the protocol. - SHELLENV_DUMP_PROTOCOL_INFO DumpInfo; ///< Pointer to DumpInfo function for the protocol. + EFI_GUID ProtocolId; ///< The GUID for the protocol. + CHAR16 *IdString; ///< The name of the protocol. + SHELLENV_DUMP_PROTOCOL_INFO DumpToken; ///< The pointer to DumpToken function for the protocol. + SHELLENV_DUMP_PROTOCOL_INFO DumpInfo; ///< The pointer to DumpInfo function for the protocol. // // Patabase info on which handles are supporting this protocol. // - UINTN NoHandles; ///< How many handles produce this protocol. + UINTN NoHandles; ///< The number of handles producing this protocol. EFI_HANDLE *Handles; ///< The array of handles. } PROTOCOL_INFO; @@ -649,14 +649,14 @@ VOID /** This function is an internal shell function for enumeration of protocols. - This functiol will return the next protocol in the list. If this is called - immediately after initialization it will return the first. If this is called - immediately after reset it will return the protocol first again. + This function returns the next protocol on the list. If this is called + immediately after initialization, it will return the first protocol on the list. + If this is called immediately after reset, it will return the first protocol again. This cannot be called after CLOSE_PROTOCOL_INFO_ENUMERATOR, but it must be called after INIT_PROTOCOL_INFO_ENUMERATOR. - @param ProtocolInfo Pointer to pointer to protocol information structure. + @param[in,out] ProtocolInfo The pointer to pointer to protocol information structure. @retval EFI_SUCCESS The next protocol's information was sucessfully returned. @retval NULL There are no more protocols. @@ -675,7 +675,7 @@ EFI_STATUS This function does nothing and always returns EFI_SUCCESS. - @retval EFI_SUCCESS always returned (see above). + @retval EFI_SUCCESS Always returned (see above). **/ typedef EFI_STATUS @@ -718,11 +718,11 @@ VOID Protocol enumerator structure of function pointers. **/ typedef struct { - INIT_PROTOCOL_INFO_ENUMERATOR Init; ///< Pointer to INIT_PROTOCOL_INFO_ENUMERATOR function. - NEXT_PROTOCOL_INFO Next; ///< Pointer to NEXT_PROTOCOL_INFO function. - SKIP_PROTOCOL_INFO Skip; ///< Pointer to SKIP_PROTOCOL_INFO function. - RESET_PROTOCOL_INFO_ENUMERATOR Reset; ///< Pointer to RESET_PROTOCOL_INFO_ENUMERATOR function. - CLOSE_PROTOCOL_INFO_ENUMERATOR Close; ///< Pointer to CLOSE_PROTOCOL_INFO_ENUMERATOR function. + INIT_PROTOCOL_INFO_ENUMERATOR Init; ///< The pointer to INIT_PROTOCOL_INFO_ENUMERATOR function. + NEXT_PROTOCOL_INFO Next; ///< The pointer to NEXT_PROTOCOL_INFO function. + SKIP_PROTOCOL_INFO Skip; ///< The pointer to SKIP_PROTOCOL_INFO function. + RESET_PROTOCOL_INFO_ENUMERATOR Reset; ///< The pointer to RESET_PROTOCOL_INFO_ENUMERATOR function. + CLOSE_PROTOCOL_INFO_ENUMERATOR Close; ///< The pointer to CLOSE_PROTOCOL_INFO_ENUMERATOR function. } PROTOCOL_INFO_ENUMERATOR; /** @@ -742,42 +742,42 @@ typedef struct { whether the handle in question produced either EFI_DRIVER_DIAGNOSTICS_PROTOCOL or EFI_DRIVER_DIAGNOSTICS2_PROTOCOL. - Upon sucessful return the memory for *BestDeviceName is up to the caller to free. + Upon successful return, the memory for *BestDeviceName is up to the caller to free. - @param DeviceHandle The device handle whose name is desired. - @param UseComponentName Whether to use the ComponentName protocol at all. - @param UseDevicePath Whether to use the DevicePath protocol at all. - @param Language Pointer to language string to use. - @param BestDeviceName Pointer to pointer to string allocated with the name. - @param ConfigurationStatus Pointer to status for opening a Configuration protocol. - @param DiagnosticsStatus Pointer to status for opening a Diagnostics protocol. - @param Display Whether to Print this out to default Print location. - @param Indent How many characters to indent the printing. + @param[in] DeviceHandle The device handle whose name is desired. + @param[in] UseComponentName Whether to use the ComponentName protocol at all. + @param[in] UseDevicePath Whether to use the DevicePath protocol at all. + @param[in] Language The pointer to the language string to use. + @param[in,out] BestDeviceName The pointer to pointer to string allocated with the name. + @param[out] ConfigurationStatus The pointer to status for opening a Configuration protocol. + @param[out] DiagnosticsStatus The pointer to status for opening a Diagnostics protocol. + @param[in] Display Whether to Print this out to default Print location. + @param[in] Indent How many characters to indent the printing. @retval EFI_SUCCESS This function always returns EFI_SUCCESS. **/ typedef EFI_STATUS (EFIAPI *GET_DEVICE_NAME) ( - EFI_HANDLE DeviceHandle, - BOOLEAN UseComponentName, - BOOLEAN UseDevicePath, - CHAR8 *Language, - CHAR16 **BestDeviceName, - EFI_STATUS *ConfigurationStatus, - EFI_STATUS *DiagnosticsStatus, - BOOLEAN Display, - UINTN Indent + IN EFI_HANDLE DeviceHandle, + IN BOOLEAN UseComponentName, + IN BOOLEAN UseDevicePath, + IN CHAR8 *Language, + IN OUT CHAR16 **BestDeviceName, + OUT EFI_STATUS *ConfigurationStatus, + OUT EFI_STATUS *DiagnosticsStatus, + IN BOOLEAN Display, + IN UINTN Indent ); -#define EFI_SHELL_COMPATIBLE_MODE_VER L"1.1.1" ///< string for lowest version this shell supports -#define EFI_SHELL_ENHANCED_MODE_VER L"1.1.2" ///< string for highest version this shell supports +#define EFI_SHELL_COMPATIBLE_MODE_VER L"1.1.1" ///< The string for lowest version this shell supports. +#define EFI_SHELL_ENHANCED_MODE_VER L"1.1.2" ///< The string for highest version this shell supports. /** This function gets the shell mode as stored in the shell environment "efishellmode". It will not fail. - @param Mode Returns a string representing one of the + @param[out] Mode Returns a string representing one of the 2 supported modes of the shell. @retval EFI_SUCCESS This function always returns success. @@ -798,6 +798,8 @@ EFI_STATUS If anything prevents the complete conversion free any allocated memory and return NULL. + @param[in] Path The path to convert. + @retval !NULL A pointer to the callee allocated Device Path. @retval NULL The operation could not be completed. **/ @@ -820,9 +822,9 @@ EFI_DEVICE_PATH_PROTOCOL* This function will use the internal lock to prevent changes to the map during the lookup operation. - @param DevPath The device path to search for a name for. - @param ConsistMapping What state to verify map flag VAR_ID_CONSIST. - @param Name On sucessful return the name of that device path. + @param[in] DevPath The device path to search for a name for. + @param[in] ConsistMapping What state to verify map flag VAR_ID_CONSIST. + @param[out] Name On sucessful return the name of that device path. @retval EFI_SUCCESS The DevPath was found and the name returned in Name. @@ -847,11 +849,11 @@ EFI_STATUS The memory allocated by the callee for this list is freed by making a call to SHELLENV_FREE_FILE_LIST. - @param Arg Pointer Path to files to open. - @param ListHead Pointer to allocated and initialized list head + @param[in] Arg The pointer to the path of the files to be opened. + @param[in,out] ListHead The pointer to allocated and initialized list head upon which to append all the opened file structures. - @retval EFI_SUCCESS 1 or more files was opened and a struct of each file's + @retval EFI_SUCCESS One or more files was opened and a struct of each file's information was appended to ListHead. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @retval EFI_NOT_FOUND No matching files could be found. @@ -872,7 +874,7 @@ EFI_STATUS files in the list of returned files. Any file listed twice will have one of its instances removed. - @param ListHead Pointer to linked list head that was returned from + @param[in] ListHead The pointer to linked list head that was returned from SHELLENV_FILE_META_ARG_NO_WILDCARD or SHELLENV_FILE_META_ARG. @@ -888,22 +890,22 @@ EFI_STATUS /** Converts a File System map name to a device path. - if DevPath is NULL, then ASSERT(). + If DevPath is NULL, then ASSERT(). This function looks through the shell environment map for a map whose Name - matches the Name parameter. If one is found the device path pointer is + matches the Name parameter. If one is found, the device path pointer is updated to point to that file systems device path. The caller should not free the memory from that device path. This function will use the internal lock to prevent changes to the map during the lookup operation. - @param Name Pointer to NULL terminated UNICODE string of the + @param[in] Name The pointer to the NULL terminated UNICODE string of the file system name. - @param DevPath Pointer to pointer to DevicePath. only valid on - OUT if sucessful. + @param[out] DevPath The pointer to pointer to DevicePath. Only valid on + successful return. - @retval EFI_SUCCESS The conversion was successful and the device + @retval EFI_SUCCESS The conversion was successful, and the device path was returned. @retval EFI_NOT_FOUND The file system could not be found in the map. **/ diff --git a/ShellPkg/Include/Protocol/EfiShellInterface.h b/ShellPkg/Include/Protocol/EfiShellInterface.h index 4e6e641ff7..6a34c60b07 100644 --- a/ShellPkg/Include/Protocol/EfiShellInterface.h +++ b/ShellPkg/Include/Protocol/EfiShellInterface.h @@ -4,9 +4,7 @@ Shell Interface - additional information (over image_info) provided to an application started by the shell. - ConIo - provides a file style interface to the console. Note that the - ConOut & ConIn interfaces in the system table will work as well, and both - all will be redirected to a file if needed on a command line + ConIo provides a file-style interface to the console. The shell interface's and data (including ConIo) are only valid during the applications Entry Point. Once the application returns from it's @@ -23,16 +21,18 @@ **/ -#if !defined(_SHELLINTERFACE_H_) +#ifndef _SHELLINTERFACE_H_ #define _SHELLINTERFACE_H_ +#include + #define SHELL_INTERFACE_PROTOCOL_GUID \ { \ 0x47c7b223, 0xc42a, 0x11d2, {0x8e, 0x57, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b} \ } /// -/// bit definitions for EFI_SHELL_ARG_INFO +/// Bit definitions for EFI_SHELL_ARG_INFO /// typedef enum { ARG_NO_ATTRIB = 0x0, @@ -43,48 +43,48 @@ typedef enum { } EFI_SHELL_ARG_INFO_TYPES; /// -/// attributes for an argument. +/// Attributes for an argument. /// typedef struct _EFI_SHELL_ARG_INFO { UINT32 Attributes; } EFI_SHELL_ARG_INFO; /// -/// This protocol provides access to additional information about a shell app. +/// This protocol provides access to additional information about a shell application. /// typedef struct { /// - /// Handle back to original image handle & image info + /// Handle back to original image handle & image information. /// EFI_HANDLE ImageHandle; EFI_LOADED_IMAGE_PROTOCOL *Info; /// - /// Parsed arg list converted more C like format + /// Parsed arg list converted more C-like format. /// CHAR16 **Argv; UINTN Argc; /// - /// Storage for file redirection args after parsing + /// Storage for file redirection args after parsing. /// CHAR16 **RedirArgv; UINTN RedirArgc; /// - /// A file style handle for console io + /// A file style handle for console io. /// - EFI_FILE_HANDLE StdIn; - EFI_FILE_HANDLE StdOut; - EFI_FILE_HANDLE StdErr; + EFI_FILE_PROTOCOL *StdIn; + EFI_FILE_PROTOCOL *StdOut; + EFI_FILE_PROTOCOL *StdErr; /// - /// list of attributes for each argument + /// List of attributes for each argument. /// EFI_SHELL_ARG_INFO *ArgInfo; /// - /// whether we are echoing + /// Whether we are echoing. /// BOOLEAN EchoOn; } EFI_SHELL_INTERFACE; diff --git a/ShellPkg/Include/Protocol/EfiShellParameters.h b/ShellPkg/Include/Protocol/EfiShellParameters.h index 32d8379d3b..7082d421be 100644 --- a/ShellPkg/Include/Protocol/EfiShellParameters.h +++ b/ShellPkg/Include/Protocol/EfiShellParameters.h @@ -12,6 +12,8 @@ **/ +#include + #ifndef __EFI_SHELL_PARAMETERS_PROTOCOL__ #define __EFI_SHELL_PARAMETERS_PROTOCOL__ @@ -36,21 +38,21 @@ typedef struct _EFI_SHELL_PARAMETERS_PROTOCOL { /// /// The file handle for the standard input for this executable. This may be different - /// from the ConInHandle in the EFI_SYSTEM_TABLE. + /// from the ConInHandle in EFI_SYSTEM_TABLE. /// - EFI_FILE_HANDLE StdIn; + SHELL_FILE_HANDLE StdIn; /// /// The file handle for the standard output for this executable. This may be different - /// from the ConOutHandle in the EFI_SYSTEM_TABLE. + /// from the ConOutHandle in EFI_SYSTEM_TABLE. /// - EFI_FILE_HANDLE StdOut; + SHELL_FILE_HANDLE StdOut; /// /// The file handle for the standard error output for this executable. This may be - /// different from the StdErrHandle in the EFI_SYSTEM_TABLE. + /// different from the StdErrHandle in EFI_SYSTEM_TABLE. /// - EFI_FILE_HANDLE StdErr; + SHELL_FILE_HANDLE StdErr; } EFI_SHELL_PARAMETERS_PROTOCOL; extern EFI_GUID gEfiShellParametersProtocolGuid; diff --git a/ShellPkg/Include/ShellBase.h b/ShellPkg/Include/ShellBase.h index 3aee67442f..6b88cbc431 100644 --- a/ShellPkg/Include/ShellBase.h +++ b/ShellPkg/Include/ShellBase.h @@ -1,7 +1,7 @@ /** @file Root include file for Shell Package modules that utilize the SHELL_RETURN type - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 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 @@ -12,9 +12,20 @@ **/ -#if !defined(__SHELL_BASE__) +#ifndef __SHELL_BASE__ #define __SHELL_BASE__ +typedef VOID *SHELL_FILE_HANDLE; + +#ifndef SHELL_FREE_NON_NULL +#define SHELL_FREE_NON_NULL(Pointer) \ + do { \ + if (Pointer != NULL) { \ + FreePool(Pointer); \ + } \ + } while(FALSE) +#endif //SHELL_FREE_NON_NULL + typedef enum { /// /// The operation completed successfully. @@ -60,7 +71,7 @@ SHELL_NOT_READY = 6, SHELL_DEVICE_ERROR = 7, /// -/// The device can not be written to. +/// The device cannot be written to. /// SHELL_WRITE_PROTECTED = 8, diff --git a/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.c b/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.c index fd19452cbc..bd3a4a7b52 100644 --- a/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.c +++ b/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.c @@ -1,7 +1,7 @@ /** @file Provides interface to EFI_FILE_HANDLE functionality. - Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2006 - 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 @@ -30,13 +30,13 @@ #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN) /** - This function will retrieve the information about the file for the handle + This function will retrieve the information about the file for the handle specified and store it in allocated pool memory. - This function allocates a buffer to store the file's information. It is the + This function allocates a buffer to store the file's information. It is the caller's responsibility to free the buffer - @param FileHandle The file handle of the file for which information is + @param FileHandle The file handle of the file for which information is being requested. @retval NULL information could not be retrieved. @@ -49,7 +49,7 @@ FileHandleGetInfo ( IN EFI_FILE_HANDLE FileHandle ) { - EFI_FILE_INFO *pFileInfo; + EFI_FILE_INFO *FileInfo; UINTN FileInfoSize; EFI_STATUS Status; @@ -62,51 +62,52 @@ FileHandleGetInfo ( // Get the required size to allocate // FileInfoSize = 0; - pFileInfo = NULL; - Status = FileHandle->GetInfo(FileHandle, - &gEfiFileInfoGuid, - &FileInfoSize, - pFileInfo); + FileInfo = NULL; + Status = FileHandle->GetInfo(FileHandle, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo); // // error is expected. getting size to allocate // ASSERT (Status == EFI_BUFFER_TOO_SMALL); - pFileInfo = AllocateZeroPool(FileInfoSize); - ASSERT (pFileInfo != NULL); + FileInfo = AllocateZeroPool(FileInfoSize); + ASSERT (FileInfo != NULL); // // now get the information // - Status = FileHandle->GetInfo(FileHandle, - &gEfiFileInfoGuid, - &FileInfoSize, - pFileInfo); + Status = FileHandle->GetInfo(FileHandle, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo); // // if we got an error free the memory and return NULL // if (EFI_ERROR(Status)) { - FreePool(pFileInfo); + FreePool(FileInfo); return NULL; } - return (pFileInfo); + return (FileInfo); } /** - This function will set the information about the file for the opened handle + This function sets the information about the file for the opened handle specified. - @param FileHandle The file handle of the file for which information - is being set + @param[in] FileHandle The file handle of the file for which information + is being set. - @param FileInfo The infotmation to set. + @param[in] FileInfo The information to set. - @retval EFI_SUCCESS The information was set. - @retval EFI_UNSUPPORTED The InformationType is not known. - @retval EFI_NO_MEDIA The device has no medium. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. + @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI @@ -115,7 +116,7 @@ FileHandleSetInfo ( IN CONST EFI_FILE_INFO *FileInfo ) { - + // // ASSERT if the FileHandle or FileInfo is NULL // @@ -125,38 +126,38 @@ FileHandleSetInfo ( // // Set the info // - return (FileHandle->SetInfo(FileHandle, + return (FileHandle->SetInfo(FileHandle, &gEfiFileInfoGuid, (UINTN)FileInfo->Size, (EFI_FILE_INFO*)FileInfo)); -} +} /** This function reads information from an opened file. - If FileHandle is not a directory, the function reads the requested number of - bytes from the file at the file's current position and returns them in Buffer. + If FileHandle is not a directory, the function reads the requested number of + bytes from the file at the file's current position and returns them in Buffer. If the read goes beyond the end of the file, the read length is truncated to the - end of the file. The file's current position is increased by the number of bytes - returned. If FileHandle is a directory, the function reads the directory entry - at the file's current position and returns the entry in Buffer. If the Buffer - is not large enough to hold the current directory entry, then - EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. - BufferSize is set to be the size of the buffer needed to read the entry. On - success, the current position is updated to the next directory entry. If there - are no more directory entries, the read returns a zero-length buffer. + end of the file. The file's current position is increased by the number of bytes + returned. If FileHandle is a directory, the function reads the directory entry + at the file's current position and returns the entry in Buffer. If the Buffer + is not large enough to hold the current directory entry, then + EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. + BufferSize is set to be the size of the buffer needed to read the entry. On + success, the current position is updated to the next directory entry. If there + are no more directory entries, the read returns a zero-length buffer. EFI_FILE_INFO is the structure returned as the directory entry. @param FileHandle the opened file handle - @param BufferSize on input the size of buffer in bytes. on return + @param BufferSize on input the size of buffer in bytes. on return the number of bytes written. @param Buffer the buffer to put read data into. - @retval EFI_SUCCESS Data was read. - @retval EFI_NO_MEDIA The device has no media. - @retval EFI_DEVICE_ERROR The device reported an error. - @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required size. **/ @@ -183,11 +184,11 @@ FileHandleRead( /** Write data to a file. - This function writes the specified number of bytes to the file at the current - file position. The current file position is advanced the actual number of bytes - written, which is returned in BufferSize. Partial writes only occur when there - has been a data error during the write attempt (such as "volume space full"). - The file is automatically grown to hold the data if required. Direct writes to + This function writes the specified number of bytes to the file at the current + file position. The current file position is advanced the actual number of bytes + written, which is returned in BufferSize. Partial writes only occur when there + has been a data error during the write attempt (such as "volume space full"). + The file is automatically grown to hold the data if required. Direct writes to opened directories are not supported. @param FileHandle The opened file for writing @@ -222,11 +223,11 @@ FileHandleWrite( return (FileHandle->Write(FileHandle, BufferSize, Buffer)); } -/** +/** Close an open file handle. - This function closes a specified file handle. All "dirty" cached file data is - flushed to the device, and the file is closed. In all cases the handle is + This function closes a specified file handle. All "dirty" cached file data is + flushed to the device, and the file is closed. In all cases the handle is closed. @param FileHandle the file handle to close. @@ -255,13 +256,13 @@ FileHandleClose ( Delete a file and close the handle This function closes and deletes a file. In all cases the file handle is closed. - If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is + If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is returned, but the handle is still closed. @param FileHandle the file handle to delete @retval EFI_SUCCESS the file was closed sucessfully - @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not + @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not deleted @retval INVALID_PARAMETER One of the parameters has an invalid value. **/ @@ -286,19 +287,19 @@ FileHandleDelete ( /** Set the current position in a file. - This function sets the current file position for the handle to the position + This function sets the current file position for the handle to the position supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only - absolute positioning is supported, and seeking past the end of the file is - allowed (a subsequent write would grow the file). Seeking to position + absolute positioning is supported, and seeking past the end of the file is + allowed (a subsequent write would grow the file). Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. - If FileHandle is a directory, the only position that may be set is zero. This + If FileHandle is a directory, the only position that may be set is zero. This has the effect of starting the read process of the directory entries over. @param FileHandle The file handle on which the position is being set @param Position Byte position from begining of file @retval EFI_SUCCESS Operation completed sucessfully. - @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on + @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on directories. @retval INVALID_PARAMETER One of the parameters has an invalid value. **/ @@ -319,11 +320,11 @@ FileHandleSetPosition ( return (FileHandle->SetPosition(FileHandle, Position)); } -/** +/** Gets a file's current position - This function retrieves the current file position for the file handle. For - directories, the current file position has no meaning outside of the file + This function retrieves the current file position for the file handle. For + directories, the current file position has no meaning outside of the file system driver and as such the operation is not supported. An error is returned if FileHandle is a directory. @@ -341,6 +342,9 @@ FileHandleGetPosition ( OUT UINT64 *Position ) { + if (Position == NULL) { + return (EFI_INVALID_PARAMETER); + } // // ASSERT if FileHandle is NULL // @@ -352,7 +356,7 @@ FileHandleGetPosition ( } /** Flushes data on a file - + This function flushes all modified data associated with a file to a device. @param FileHandle The file handle on which to flush data @@ -406,12 +410,12 @@ FileHandleIsDirectory ( // ASSERT if DirHandle is NULL // ASSERT(DirHandle != NULL); - + // // get the file information for DirHandle // DirInfo = FileHandleGetInfo (DirHandle); - + // // Parse DirInfo // @@ -420,7 +424,7 @@ FileHandleIsDirectory ( // We got nothing... // return (EFI_INVALID_PARAMETER); - } + } if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) { // // Attributes say this is not a directory @@ -438,8 +442,8 @@ FileHandleIsDirectory ( /** Retrieves the first file from a directory - This function opens a directory and gets the first file's info in the - directory. Caller can use FileHandleFindNextFile() to get other files. When + This function opens a directory and gets the first file's info in the + directory. Caller can use FileHandleFindNextFile() to get other files. When complete the caller is responsible for calling FreePool() on Buffer. @param DirHandle The file handle of the directory to search @@ -475,15 +479,15 @@ FileHandleFindFirstFile ( Status = FileHandleIsDirectory(DirHandle); if (EFI_ERROR(Status)) { return (Status); - } + } // - // reset to the begining of the directory + // reset to the begining of the directory // Status = FileHandleSetPosition(DirHandle, 0); if (EFI_ERROR(Status)) { return (Status); - } + } // // Allocate a buffer sized to struct size + enough for the string at the end @@ -507,12 +511,12 @@ FileHandleFindFirstFile ( /** Retrieves the next file in a directory. - To use this function, caller must call the FileHandleFindFirstFile() to get the - first file, and then use this function get other files. This function can be - called for several times to get each file's information in the directory. If - the call of FileHandleFindNextFile() got the last file in the directory, the next - call of this function has no file to get. *NoFile will be set to TRUE and the - Buffer memory will be automatically freed. + To use this function, caller must call the FileHandleFindFirstFile() to get the + first file, and then use this function get other files. This function can be + called for several times to get each file's information in the directory. If + the call of FileHandleFindNextFile() got the last file in the directory, the next + call of this function has no file to get. *NoFile will be set to TRUE and the + Buffer memory will be automatically freed. @param DirHandle the file handle of the directory @param Buffer pointer to buffer for file's information @@ -565,13 +569,14 @@ FileHandleFindNextFile( return (EFI_SUCCESS); } + /** Retrieve the size of a file. if FileHandle is NULL then ASSERT() if Size is NULL then ASSERT() - This function extracts the file size info from the FileHandle's EFI_FILE_INFO + This function extracts the file size info from the FileHandle's EFI_FILE_INFO data. @param FileHandle file handle from which size is retrieved @@ -594,7 +599,7 @@ FileHandleGetSize ( // ASSERT (FileHandle != NULL); ASSERT (Size != NULL); - + // // get the FileInfo structure // @@ -607,7 +612,7 @@ FileHandleGetSize ( // Assign the Size pointer to the correct value // *Size = FileInfo->FileSize; - + // // free the FileInfo memory // @@ -616,47 +621,98 @@ FileHandleGetSize ( return (EFI_SUCCESS); } +/** + Set the size of a file. + + If FileHandle is NULL then ASSERT(). + + This function changes the file size info from the FileHandle's EFI_FILE_INFO + data. + + @param FileHandle File handle whose size is to be changed. + @param Size New size. + + @retval EFI_SUCCESS operation was completed sucessfully. + @retval EFI_DEVICE_ERROR cannot access the file. +**/ +EFI_STATUS +EFIAPI +FileHandleSetSize ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT64 Size + ) +{ + EFI_FILE_INFO *FileInfo; + EFI_STATUS Status; + + // + // ASSERT for FileHandle or Size being NULL + // + ASSERT (FileHandle != NULL); + + // + // get the FileInfo structure + // + FileInfo = FileHandleGetInfo(FileHandle); + if (FileInfo == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // Assign the FileSize pointer to the new value + // + FileInfo->FileSize = Size; + + Status = FileHandleSetInfo(FileHandle, FileInfo); + // + // free the FileInfo memory + // + FreePool(FileInfo); + + return (Status); +} /** - Safely append (on the left) with automatic string resizing given length of Destination and + Safely append (on the left) with automatic string resizing given length of Destination and desired length of copy from Source. - append the first D characters of Source to the end of Destination, where D is - the lesser of Count and the StrLen() of Source. If appending those D characters - will fit within Destination (whose Size is given as CurrentSize) and - still leave room for a NULL terminator, then those characters are appended, - starting at the original terminating NULL of Destination, and a new terminating + append the first D characters of Source to the end of Destination, where D is + the lesser of Count and the StrLen() of Source. If appending those D characters + will fit within Destination (whose Size is given as CurrentSize) and + still leave room for a NULL terminator, then those characters are appended, + starting at the original terminating NULL of Destination, and a new terminating NULL is appended. If appending D characters onto Destination will result in a overflow of the size given in CurrentSize the string will be grown such that the copy can be performed and CurrentSize will be updated to the new size. - If Source is NULL, there is nothing to append, just return the current buffer in + If Source is NULL, there is nothing to append, just return the current buffer in Destination. if Destination is NULL, then ASSERT() - if Destination's current length (including NULL terminator) is already more then + if Destination's current length (including NULL terminator) is already more then CurrentSize, then ASSERT() @param[in,out] Destination The String to append onto - @param[in,out] CurrentSize on call the number of bytes in Destination. On + @param[in,out] CurrentSize on call the number of bytes in Destination. On return possibly the new size (still in bytes). if NULL then allocate whatever is needed. @param[in] Source The String to append from - @param[in] Count Maximum number of characters to append. if 0 then + @param[in] Count Maximum number of characters to append. if 0 then all are appended. @return Destination return the resultant string. **/ -CHAR16* +CHAR16* EFIAPI StrnCatGrowLeft ( IN OUT CHAR16 **Destination, IN OUT UINTN *CurrentSize, IN CONST CHAR16 *Source, IN UINTN Count - ){ + ) +{ UINTN DestinationStartSize; UINTN NewSize; UINTN CopySize; @@ -713,13 +769,13 @@ StrnCatGrowLeft ( } /** - Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the + Function to get a full filename given a EFI_FILE_HANDLE somewhere lower on the directory 'stack'. if Handle is NULL, return EFI_INVALID_PARAMETER @param[in] Handle Handle to the Directory or File to create path to. - @param[out] FullFileName pointer to pointer to generated full file name. It + @param[out] FullFileName pointer to pointer to generated full file name. It is the responsibility of the caller to free this memory with a call to FreePool(). @retval EFI_SUCCESS the operation was sucessful and the FullFileName is valid. @@ -732,7 +788,8 @@ EFIAPI FileHandleGetFileName ( IN CONST EFI_FILE_HANDLE Handle, OUT CHAR16 **FullFileName - ){ + ) +{ EFI_STATUS Status; UINTN Size; EFI_FILE_HANDLE CurrentHandle; @@ -749,6 +806,7 @@ FileHandleGetFileName ( } *FullFileName = NULL; + CurrentHandle = NULL; Status = Handle->Open(Handle, &CurrentHandle, L".", EFI_FILE_MODE_READ, 0); if (!EFI_ERROR(Status)) { @@ -766,14 +824,17 @@ FileHandleGetFileName ( // if (StrLen (FileInfo->FileName) == 0) { if (*FullFileName == NULL) { + ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0); } FreePool(FileInfo); break; } else { if (*FullFileName == NULL) { + ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0); } + ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); *FullFileName = StrnCatGrowLeft(FullFileName, &Size, FileInfo->FileName, 0); *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0); FreePool(FileInfo); @@ -790,6 +851,10 @@ FileHandleGetFileName ( FileHandleClose(CurrentHandle); CurrentHandle = NextHigherHandle; } + } else if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + ASSERT((*FullFileName == NULL && Size == 0) || (*FullFileName != NULL)); + *FullFileName = StrnCatGrowLeft(FullFileName, &Size, L"\\", 0); } if (CurrentHandle != NULL) { @@ -804,10 +869,10 @@ FileHandleGetFileName ( } /** - Function to read a single line from a file. The \n is not included in the returned + Function to read a single line from a file. The \n is not included in the returned buffer. The returned buffer must be callee freed. - If the position upon start is 0, then the Ascii Boolean will be set. This should be + If the position upon start is 0, then the Ascii Boolean will be set. This should be maintained and not changed for all operations with the same file. @param[in] Handle FileHandle to read from. @@ -845,24 +910,24 @@ FileHandleReturnLine( } /** - Function to read a single line (up to but not including the \n) from a file. + Function to read a single line (up to but not including the \n) from a EFI_FILE_HANDLE. - If the position upon start is 0, then the Ascii Boolean will be set. This should be + If the position upon start is 0, then the Ascii Boolean will be set. This should be maintained and not changed for all operations with the same file. @param[in] Handle FileHandle to read from @param[in,out] Buffer pointer to buffer to read into @param[in,out] Size pointer to number of bytes in buffer @param[in] Truncate if TRUE then allows for truncation of the line to fit. - if FALSE will reset the position to the begining of the + if FALSE will reset the position to the begining of the line if the buffer is not large enough. @param[in,out] Ascii Boolean value for indicating whether the file is Ascii (TRUE) or UCS2 (FALSE); - @retval EFI_SUCCESS the operation was sucessful. the line is stored in + @retval EFI_SUCCESS the operation was sucessful. the line is stored in Buffer. @retval EFI_INVALID_PARAMETER Handle was NULL. @retval EFI_INVALID_PARAMETER Size was NULL. - @retval EFI_BUFFER_TOO_SMALL Size was not enough space to store the line. + @retval EFI_BUFFER_TOO_SMALL Size was not enough space to store the line. Size was updated to minimum space required. @sa FileHandleRead **/ @@ -874,7 +939,8 @@ FileHandleReadLine( IN OUT UINTN *Size, IN BOOLEAN Truncate, IN OUT BOOLEAN *Ascii - ){ + ) +{ EFI_STATUS Status; CHAR16 CharBuffer; UINTN CharSize; @@ -884,8 +950,13 @@ FileHandleReadLine( if (Handle == NULL ||Size == NULL - ){ - return (EFI_INVALID_PARAMETER); + ){ + return (EFI_INVALID_PARAMETER); + } + if (Buffer == NULL) { + ASSERT(*Size == 0); + } else { + *Buffer = CHAR_NULL; } FileHandleGetPosition(Handle, &OriginalFilePosition); if (OriginalFilePosition == 0) { @@ -908,17 +979,11 @@ FileHandleReadLine( CharSize = sizeof(CHAR16); } Status = FileHandleRead(Handle, &CharSize, &CharBuffer); - if (OriginalFilePosition == 0 && *Ascii == FALSE && CountSoFar == 0) { - // - // we need to skip the unicode tag - // - continue; - } - if ( EFI_ERROR(Status) - || CharSize == 0 - || (CharBuffer == L'\n' && *Ascii == FALSE) - || (CharBuffer == '\n' && *Ascii != FALSE ) - ){ + if ( EFI_ERROR(Status) + || CharSize == 0 + || (CharBuffer == L'\n' && !(*Ascii)) + || (CharBuffer == '\n' && *Ascii) + ){ break; } // @@ -936,7 +1001,7 @@ FileHandleReadLine( // if ((CountSoFar+1)*sizeof(CHAR16) > *Size){ *Size = (CountSoFar+1)*sizeof(CHAR16); - if (Truncate == FALSE) { + if (!Truncate) { FileHandleSetPosition(Handle, OriginalFilePosition); } else { DEBUG((DEBUG_WARN, "The line was truncated in FileHandleReadLine")); @@ -969,7 +1034,8 @@ EFIAPI FileHandleWriteLine( IN EFI_FILE_HANDLE Handle, IN CHAR16 *Buffer - ){ + ) +{ EFI_STATUS Status; UINTN Size; @@ -1031,7 +1097,7 @@ FileHandlePrintLine( Status = FileHandleWriteLine(Handle, Buffer); // - // Cleanup and return + // Cleanup and return // FreePool(Buffer); return (Status); @@ -1063,15 +1129,15 @@ FileHandleEof( // ASSERT if Handle is NULL // ASSERT(Handle != NULL); - + FileHandleGetPosition(Handle, &Pos); Info = FileHandleGetInfo (Handle); ASSERT(Info != NULL); FileHandleSetPosition(Handle, Pos); - + if (Info == NULL) { return (FALSE); - } + } if (Pos == Info->FileSize) { RetVal = TRUE; diff --git a/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf b/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf index ee8cbfee6f..38d9f9cce1 100644 --- a/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf +++ b/ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf @@ -1,7 +1,7 @@ -## @file +## @file # Provides interface to shell functionality for shell commands and applications. # -# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 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 @@ -25,7 +25,7 @@ # VALID_ARCHITECTURES = IA32 X64 IPF EBC # -[Sources] +[Sources.common] BaseFileHandleLib.c [Packages] @@ -46,5 +46,5 @@ [Guids] gEfiFileInfoGuid # ALWAYS_CONSUMED -[Pcd] +[Pcd.common] gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize # ALWAYS_CONSUMED diff --git a/ShellPkg/Library/BaseSortLib/BaseSortLib.c b/ShellPkg/Library/BaseSortLib/BaseSortLib.c index ceedc884c0..2d3f190324 100644 --- a/ShellPkg/Library/BaseSortLib/BaseSortLib.c +++ b/ShellPkg/Library/BaseSortLib/BaseSortLib.c @@ -1,7 +1,7 @@ /** @file Library used for sorting routines. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 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 @@ -62,7 +62,7 @@ QuickSortWorker ( if ( Count < 2 || ElementSize < 1 - ){ + ){ return; } @@ -80,7 +80,7 @@ QuickSortWorker ( for ( LoopCount = 0 ; LoopCount < Count -1 ; LoopCount++ - ){ + ){ // // if the element is less than the pivot // @@ -174,6 +174,9 @@ PerformQuickSort ( /** Not supported in Base version. + @param[in] Buffer1 Ignored. + @param[in] Buffer2 Ignored. + ASSERT and return 0. **/ INTN @@ -209,3 +212,25 @@ StringNoCaseCompare ( } +/** + Function to compare 2 strings. + + @param[in] Buffer1 Pointer to String to compare (CHAR16**). + @param[in] Buffer2 Pointer to second String to compare (CHAR16**). + + @retval 0 Buffer1 equal to Buffer2. + @return < 0 Buffer1 is less than Buffer2. + @return > 0 Buffer1 is greater than Buffer2. +**/ +INTN +EFIAPI +StringCompare ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 + ) +{ + ASSERT(FALSE); + return 0; +} + + diff --git a/ShellPkg/Library/BaseSortLib/BaseSortLib.inf b/ShellPkg/Library/BaseSortLib/BaseSortLib.inf index 167ae451b2..2537245912 100644 --- a/ShellPkg/Library/BaseSortLib/BaseSortLib.inf +++ b/ShellPkg/Library/BaseSortLib/BaseSortLib.inf @@ -1,7 +1,7 @@ -## @file +## @file # Library used for sorting routines. # -# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2009-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 @@ -19,13 +19,13 @@ FILE_GUID = 03F3331B-F12D-494f-BF37-E55A657F2497 MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 - LIBRARY_CLASS = SORTLib|UEFI_APPLICATION UEFI_DRIVER + LIBRARY_CLASS = SortLib|UEFI_APPLICATION UEFI_DRIVER # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # -[Sources] +[Sources.common] BaseSortLib.c [Packages] @@ -42,4 +42,4 @@ [Guids] -[Pcd] +[Pcd.common] diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c new file mode 100644 index 0000000000..c398618bbb --- /dev/null +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c @@ -0,0 +1,1420 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + 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 "UefiHandleParsingLib.h" + + +STATIC CONST EFI_GUID mHandleParsingHiiGuid = \ + { \ + 0xb8969637, 0x81de, 0x43af, { 0xbc, 0x9a, 0x24, 0xd9, 0x89, 0x13, 0xf2, 0xf6 } \ + }; +EFI_HANDLE mHandleParsingHiiHandle; +HANDLE_INDEX_LIST mHandleList = {{{NULL,NULL},0,0},0}; + +/** + Constructor for the library. + + @param[in] ImageHandle Ignored. + @param[in] SystemTable Ignored. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +HandleParsingLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mHandleParsingHiiHandle = HiiAddPackages (&mHandleParsingHiiGuid, gImageHandle, UefiHandleParsingLibStrings, NULL); + if (mHandleParsingHiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param[in] ImageHandle Ignored. + @param[in] SystemTable Ignored. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +HandleParsingLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mHandleParsingHiiHandle != NULL) { + HiiRemovePackages(mHandleParsingHiiHandle); + } + return (EFI_SUCCESS); +} + +/* +CHAR16* +EFIAPI +LoadedImageProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_LOADED_IMAGE_PROTOCOL *Image; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + VOID *Buffer; + UINTN BufferSize; + UINT32 AuthenticationStatus; + EFI_GUID *NameGuid; + EFI_FIRMWARE_VOLUME_PROTOCOL *FV; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FV2; + + FV = NULL; + FV2 = NULL; + Buffer = NULL; + BufferSize = 0; + + Status = HandleProtocol ( + TheHandle, + &gEfiLoadedImageProtocolGuid, + &Image); + ASSERT_EFI_ERROR(Status); + + DevPath = UnpackDevicePath (Image->FilePath); + + if (DevPath == NULL) { + return NULL; + } + + DevPathNode = DevPath; + + while (!IsDevicePathEnd (DevPathNode)) { + // + // Find the Fv File path + // + NameGuid = GetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevPathNode); + if (NameGuid != NULL) { + Status = BS->HandleProtocol ( + Image->DeviceHandle, + &gEfiFirmwareVolumeProtocolGuid, + &FV + ); + if (!EFI_ERROR (Status)) { + Status = FV->ReadSection ( + FV, + NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + &Buffer, + &BufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + break; + } + + Buffer = NULL; + } else { + Status = BS->HandleProtocol ( + Image->DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + &FV2 + ); + if (!EFI_ERROR (Status)) { + Status = FV2->ReadSection ( + FV2, + NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + &Buffer, + &BufferSize, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + break; + } + + Buffer = NULL; + } + } + } + // + // Next device path node + // + DevPathNode = NextDevicePathNode (DevPathNode); + } + + FreePool (DevPath); + return Buffer; +} +*/ + +/** + Function to dump information about SimpleTextOut. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has SimpleTextOut installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +TxtOutProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Dev; + INTN Index; + UINTN Col; + UINTN Row; + EFI_STATUS Status; + CHAR16 *RetVal; + UINTN Size; + CHAR16 *Temp; + UINTN NewSize; + + if (!Verbose) { + return (NULL); + } + + RetVal = NULL; + Size = 0; + + Status = gBS->HandleProtocol( + TheHandle, + &gEfiSimpleTextOutProtocolGuid, + (VOID**)&Dev); + + ASSERT_EFI_ERROR(Status); + ASSERT (Dev != NULL && Dev->Mode != NULL); + + Size = (Dev->Mode->MaxMode + 1) * 80; + RetVal = AllocateZeroPool(Size); + + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_TXT_OUT_DUMP_HEADER), NULL); + UnicodeSPrint(RetVal, Size, Temp, Dev, Dev->Mode->Attribute); + FreePool(Temp); + + // + // Dump TextOut Info + // + Temp = HiiGetString(mHandleParsingHiiHandle, STRING_TOKEN(STR_TXT_OUT_DUMP_LINE), NULL); + for (Index = 0; Index < Dev->Mode->MaxMode; Index++) { + Status = Dev->QueryMode (Dev, Index, &Col, &Row); + NewSize = Size - StrSize(RetVal); + UnicodeSPrint( + RetVal + StrLen(RetVal), + NewSize, + Temp, + Index == Dev->Mode->Mode ? L'*' : L' ', + Index, + !EFI_ERROR(Status)?Col:-1, + !EFI_ERROR(Status)?Row:-1 + ); + } + FreePool(Temp); + return (RetVal); +} + +STATIC CONST UINTN VersionStringSize = 60; + +/** + Function to dump information about EfiDriverSupportedEfiVersion protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +DriverEfiVersionProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL *DriverEfiVersion; + EFI_STATUS Status; + CHAR16 *RetVal; + + Status = gBS->HandleProtocol( + TheHandle, + &gEfiDriverSupportedEfiVersionProtocolGuid, + (VOID**)&DriverEfiVersion); + + ASSERT_EFI_ERROR(Status); + + RetVal = AllocatePool(VersionStringSize); + ASSERT(RetVal != NULL); + UnicodeSPrint(RetVal, VersionStringSize, L"0x%08x", DriverEfiVersion->FirmwareVersion); + return (RetVal); +} + +/** + Function to dump information about DevicePath protocol. + + This will allocate the return buffer from boot services pool. + + @param[in] TheHandle The handle that has the protocol installed. + @param[in] Verbose TRUE for additional information, FALSE otherwise. + + @retval A poitner to a string containing the information. +**/ +CHAR16* +EFIAPI +DevicePathProtocolDumpInformation( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + CHAR16 *Temp; + CHAR16 *Temp2; + EFI_STATUS Status; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + Temp = NULL; + + Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&DevPathToText); + if (!EFI_ERROR(Status)) { + Status = gBS->OpenProtocol(TheHandle, &gEfiDevicePathProtocolGuid, (VOID**)&DevPath, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + // + // I cannot decide whether to allow shortcuts here (the second BOOLEAN on the next line) + // + Temp = DevPathToText->ConvertDevicePathToText(DevPath, TRUE, TRUE); + gBS->CloseProtocol(TheHandle, &gEfiDevicePathProtocolGuid, gImageHandle, NULL); + } + } + if (Verbose && Temp != NULL && StrLen(Temp) > 30) { + Temp2 = NULL; + Temp2 = StrnCatGrow(&Temp2, NULL, Temp+(StrLen(Temp) - 30), 30); + FreePool(Temp); + Temp = Temp2; + } + return (Temp); +} + +// +// Put the information on the NT32 protocol GUIDs here so we are not dependant on the Nt32Pkg +// +#define LOCAL_EFI_WIN_NT_THUNK_PROTOCOL_GUID \ + { \ + 0x58c518b1, 0x76f3, 0x11d4, 0xbc, 0xea, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 \ + } + +#define LOCAL_EFI_WIN_NT_BUS_DRIVER_IO_PROTOCOL_GUID \ + { \ + 0x96eb4ad6, 0xa32a, 0x11d4, 0xbc, 0xfd, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 \ + } + +#define LOCAL_EFI_WIN_NT_SERIAL_PORT_GUID \ + { \ + 0xc95a93d, 0xa006, 0x11d4, 0xbc, 0xfa, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 \ + } +STATIC CONST EFI_GUID WinNtThunkProtocolGuid = LOCAL_EFI_WIN_NT_THUNK_PROTOCOL_GUID; +STATIC CONST EFI_GUID WinNtIoProtocolGuid = LOCAL_EFI_WIN_NT_BUS_DRIVER_IO_PROTOCOL_GUID; +STATIC CONST EFI_GUID WinNtSerialPortGuid = LOCAL_EFI_WIN_NT_SERIAL_PORT_GUID; + +STATIC CONST PROTOCOL_INFO_BLOCK mGuidStringListNT[] = { + {STRING_TOKEN(STR_WINNT_THUNK), (EFI_GUID*)&WinNtThunkProtocolGuid, NULL}, + {STRING_TOKEN(STR_WINNT_DRIVER_IO), (EFI_GUID*)&WinNtIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_WINNT_SERIAL_PORT), (EFI_GUID*)&WinNtSerialPortGuid, NULL}, + {STRING_TOKEN(STR_UNKNOWN_DEVICE), NULL, NULL}, +}; + +STATIC CONST PROTOCOL_INFO_BLOCK mGuidStringList[] = { + {STRING_TOKEN(STR_LOADED_IMAGE), &gEfiLoadedImageProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH), &gEfiDevicePathProtocolGuid, DevicePathProtocolDumpInformation}, + {STRING_TOKEN(STR_IMAGE_PATH), &gEfiLoadedImageDevicePathProtocolGuid, DevicePathProtocolDumpInformation}, + {STRING_TOKEN(STR_DEVICE_PATH_UTIL), &gEfiDevicePathUtilitiesProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_TXT), &gEfiDevicePathToTextProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_FTXT), &gEfiDevicePathFromTextProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_PC), &gEfiPcAnsiGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VT100), &gEfiVT100Guid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VT100P), &gEfiVT100PlusGuid, NULL}, + {STRING_TOKEN(STR_DEVICE_PATH_VTUTF8), &gEfiVTUTF8Guid, NULL}, + {STRING_TOKEN(STR_DRIVER_BINDING), &gEfiDriverBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_PLATFORM_OVERRIDE), &gEfiPlatformDriverOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_BUS_OVERRIDE), &gEfiBusSpecificDriverOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_DIAG), &gEfiDriverDiagnosticsProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_DIAG2), &gEfiDriverDiagnostics2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CN), &gEfiComponentNameProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CN2), &gEfiComponentName2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PLAT_DRV_CFG), &gEfiPlatformToDriverConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_VERSION), &gEfiDriverSupportedEfiVersionProtocolGuid, DriverEfiVersionProtocolDumpInformation}, + {STRING_TOKEN(STR_TXT_IN), &gEfiSimpleTextInProtocolGuid, NULL}, + {STRING_TOKEN(STR_TXT_IN_EX), &gEfiSimpleTextInputExProtocolGuid, NULL}, + {STRING_TOKEN(STR_TXT_OUT), &gEfiSimpleTextOutProtocolGuid, TxtOutProtocolDumpInformation}, + {STRING_TOKEN(STR_SIM_POINTER), &gEfiSimplePointerProtocolGuid, NULL}, + {STRING_TOKEN(STR_ABS_POINTER), &gEfiAbsolutePointerProtocolGuid, NULL}, + {STRING_TOKEN(STR_SERIAL_IO), &gEfiSerialIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_GRAPHICS_OUTPUT), &gEfiGraphicsOutputProtocolGuid, NULL}, + {STRING_TOKEN(STR_EDID_DISCOVERED), &gEfiEdidDiscoveredProtocolGuid, NULL}, + {STRING_TOKEN(STR_EDID_ACTIVE), &gEfiEdidActiveProtocolGuid, NULL}, + {STRING_TOKEN(STR_EDID_OVERRIDE), &gEfiEdidOverrideProtocolGuid, NULL}, + {STRING_TOKEN(STR_CON_IN), &gEfiConsoleInDeviceGuid, NULL}, + {STRING_TOKEN(STR_CON_OUT), &gEfiConsoleOutDeviceGuid, NULL}, + {STRING_TOKEN(STR_STD_ERR), &gEfiStandardErrorDeviceGuid, NULL}, + {STRING_TOKEN(STR_LOAD_FILE), &gEfiLoadFileProtocolGuid, NULL}, + {STRING_TOKEN(STR_LOAD_FILE2), &gEfiLoadFile2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_SIMPLE_FILE_SYS), &gEfiSimpleFileSystemProtocolGuid, NULL}, + {STRING_TOKEN(STR_FILE_INFO), &gEfiFileInfoGuid, NULL}, + {STRING_TOKEN(STR_FILE_SYS_INFO), &gEfiFileSystemInfoGuid, NULL}, + {STRING_TOKEN(STR_TAPE_IO), &gEfiTapeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_DISK_IO), &gEfiDiskIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_BLK_IO), &gEfiBlockIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_UC), &gEfiUnicodeCollationProtocolGuid, NULL}, + {STRING_TOKEN(STR_UC2), &gEfiUnicodeCollation2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCIRB_IO), &gEfiPciRootBridgeIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_PCI_IO), &gEfiPciIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCSI_PT), &gEfiScsiPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCSI_IO), &gEfiScsiIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_SCSI_PT_EXT), &gEfiExtScsiPassThruProtocolGuid, NULL}, + {STRING_TOKEN(STR_ISCSI), &gEfiIScsiInitiatorNameProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_IO), &gEfiUsbIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_HC), &gEfiUsbHcProtocolGuid, NULL}, + {STRING_TOKEN(STR_USB_HC2), &gEfiUsb2HcProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEBUG_SUPPORT), &gEfiDebugSupportProtocolGuid, NULL}, + {STRING_TOKEN(STR_DEBUG_PORT), &gEfiDebugPortProtocolGuid, NULL}, + {STRING_TOKEN(STR_DECOMPRESS), &gEfiDecompressProtocolGuid, NULL}, + {STRING_TOKEN(STR_ACPI_TABLE), &gEfiAcpiTableProtocolGuid, NULL}, + {STRING_TOKEN(STR_EBC_INTERPRETER), &gEfiEbcProtocolGuid, NULL}, + {STRING_TOKEN(STR_SNP), &gEfiSimpleNetworkProtocolGuid, NULL}, + {STRING_TOKEN(STR_NII), &gEfiNetworkInterfaceIdentifierProtocolGuid, NULL}, + {STRING_TOKEN(STR_NII_31), &gEfiNetworkInterfaceIdentifierProtocolGuid_31, NULL}, + {STRING_TOKEN(STR_PXE_BC), &gEfiPxeBaseCodeProtocolGuid, NULL}, + {STRING_TOKEN(STR_PXE_CB), &gEfiPxeBaseCodeCallbackProtocolGuid, NULL}, + {STRING_TOKEN(STR_BIS), &gEfiBisProtocolGuid, NULL}, + {STRING_TOKEN(STR_MNP_SB), &gEfiManagedNetworkServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_MNP), &gEfiManagedNetworkProtocolGuid, NULL}, + {STRING_TOKEN(STR_ARP_SB), &gEfiArpServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_ARP), &gEfiArpProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCPV4_SB), &gEfiDhcp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_DHCPV4), &gEfiDhcp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCPV4_SB), &gEfiTcp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_TCPV4), &gEfiTcp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4_SB), &gEfiIp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4), &gEfiIp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_IPV4_CFG), &gEfiIp4ConfigProtocolGuid, NULL}, + {STRING_TOKEN(STR_SHELL_PARAMETERS), &gEfiShellParametersProtocolGuid, NULL}, + {STRING_TOKEN(STR_SHELL), &gEfiShellProtocolGuid, NULL}, + {STRING_TOKEN(STR_EFI_GLOBAL_VARIABLE), &gEfiGlobalVariableGuid, NULL}, + {STRING_TOKEN(STR_UDPV4_SB), &gEfiUdp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_UDPV4), &gEfiUdp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTPV4_SB), &gEfiMtftp4ServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_MTFTPV4), &gEfiMtftp4ProtocolGuid, NULL}, + {STRING_TOKEN(STR_AUTH_INFO), &gEfiAuthenticationInfoProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH_SB), &gEfiHashServiceBindingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HASH), &gEfiHashProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_FONT), &gEfiHiiFontProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_STRING), &gEfiHiiStringProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_IMAGE), &gEfiHiiImageProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_DATABASE), &gEfiHiiDatabaseProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_CONFIG_ROUT), &gEfiHiiConfigRoutingProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_CONFIG_ACC), &gEfiHiiConfigAccessProtocolGuid, NULL}, + {STRING_TOKEN(STR_HII_FORM_BROWSER2), &gEfiFormBrowser2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_SHELL_INTERFACE), &gEfiShellInterfaceGuid, NULL}, + {STRING_TOKEN(STR_SHELL_ENV2), &gEfiShellEnvironment2Guid, NULL}, + {STRING_TOKEN(STR_SHELL_ENV), &gEfiShellEnvironment2Guid, NULL}, + {STRING_TOKEN(STR_DEVICE_IO), &gEfiDeviceIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_UGA_DRAW), &gEfiUgaDrawProtocolGuid, NULL}, + {STRING_TOKEN(STR_UGA_IO), &gEfiUgaIoProtocolGuid, NULL}, + {STRING_TOKEN(STR_ESP), &gEfiPartTypeSystemPartGuid, NULL}, + {STRING_TOKEN(STR_GPT_NBR), &gEfiPartTypeLegacyMbrGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CONFIG), &gEfiDriverConfigurationProtocolGuid, NULL}, + {STRING_TOKEN(STR_DRIVER_CONFIG2), &gEfiDriverConfiguration2ProtocolGuid, NULL}, + {STRING_TOKEN(STR_UNKNOWN_DEVICE), NULL, NULL}, +}; + +/** + Function to get the node for a protocol or struct from it's GUID. + + if Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + + @return The node. +**/ +CONST PROTOCOL_INFO_BLOCK * +EFIAPI +InternalShellGetNodeFromGuid( + IN CONST EFI_GUID* Guid + ) +{ + CONST PROTOCOL_INFO_BLOCK *ListWalker; + + ASSERT(Guid != NULL); + + if (PcdGetBool(PcdShellIncludeNtGuids)) { + for (ListWalker = mGuidStringListNT ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + if (CompareGuid(ListWalker->GuidId, Guid)) { + return (ListWalker); + } + } + } + for (ListWalker = mGuidStringList ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + if (CompareGuid(ListWalker->GuidId, Guid)) { + return (ListWalker); + } + } + return (ListWalker); +} + +/** + Function to get the name of a protocol or struct from it's GUID. + + if Guid is NULL, then ASSERT. + + @param[in] Guid The GUID to look for the name of. + @param[in] Lang The language to use. + + @return pointer to string of the name. The caller + is responsible to free this memory. +**/ +CHAR16* +EFIAPI +GetStringNameFromGuid( + IN CONST EFI_GUID *Guid, + IN CONST CHAR8 *Lang OPTIONAL + ) +{ + CONST PROTOCOL_INFO_BLOCK *Id; + + Id = InternalShellGetNodeFromGuid(Guid); + return (HiiGetString(mHandleParsingHiiHandle, Id->StringId, Lang)); +} + +/** + Function to dump protocol information from a handle. + + This function will return a allocated string buffer containing the + information. The caller is responsible for freeing the memory. + + If Guid is NULL, ASSERT(). + If TheHandle is NULL, ASSERT(). + + @param[in] TheHandle The handle to dump information from. + @param[in] Guid The GUID of the protocol to dump. + @param[in] Verbose TRUE for extra info. FALSE otherwise. + + @return The pointer to string. + @retval NULL An error was encountered. +**/ +CHAR16* +EFIAPI +GetProtocolInformationDump( + IN CONST EFI_HANDLE TheHandle, + IN CONST EFI_GUID *Guid, + IN CONST BOOLEAN Verbose + ) +{ + CONST PROTOCOL_INFO_BLOCK *Id; + + ASSERT(TheHandle != NULL); + ASSERT(Guid != NULL); + + if (TheHandle == NULL || Guid == NULL) { + return (NULL); + } + + Id = InternalShellGetNodeFromGuid(Guid); + if (Id != NULL && Id->DumpInfo != NULL) { + return (Id->DumpInfo(TheHandle, Verbose)); + } + return (NULL); +} + +/** + Function to get the Guid for a protocol or struct based on it's string name. + + @param[in] Name The pointer to the string name. + @param[in] Lang The pointer to the language code. + @param[in] Guid The pointer to the Guid. + + @retval EFI_SUCCESS The operation was sucessful. +**/ +EFI_STATUS +EFIAPI +GetGuidFromStringName( + IN CONST CHAR16 *Name, + IN CONST CHAR8 *Lang OPTIONAL, + IN EFI_GUID **Guid + ) +{ + CONST PROTOCOL_INFO_BLOCK *ListWalker; + CHAR16 *String; + + ASSERT(Guid != NULL); + if (Guid == NULL) { + return (EFI_INVALID_PARAMETER); + } + *Guid = NULL; + + if (PcdGetBool(PcdShellIncludeNtGuids)) { + for (ListWalker = mGuidStringListNT ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + String = HiiGetString(mHandleParsingHiiHandle, ListWalker->StringId, Lang); + if (Name != NULL && String != NULL && StrCmp(Name, String)==0) { + *Guid = ListWalker->GuidId; + } + SHELL_FREE_NON_NULL(String); + if (*Guid != NULL) { + return (EFI_SUCCESS); + } + } + } + for (ListWalker = mGuidStringList ; ListWalker != NULL && ListWalker->GuidId != NULL ; ListWalker++) { + String = HiiGetString(mHandleParsingHiiHandle, ListWalker->StringId, Lang); + if (Name != NULL && String != NULL && StrCmp(Name, String)==0) { + *Guid = ListWalker->GuidId; + } + SHELL_FREE_NON_NULL(String); + if (*Guid != NULL) { + return (EFI_SUCCESS); + } + } + return (EFI_NOT_FOUND); +} + +/** + Function to retrieve the driver name (if possible) from the ComponentName or + ComponentName2 protocol + + @param[in] TheHandle The driver handle to get the name of. + @param[in] Language The language to use. + + @retval NULL The name could not be found. + @return A pointer to the string name. Do not de-allocate the memory. +**/ +CONST CHAR16* +EFIAPI +GetStringNameFromHandle( + IN CONST EFI_HANDLE TheHandle, + IN CONST CHAR8 *Language + ) +{ + EFI_COMPONENT_NAME2_PROTOCOL *CompNameStruct; + EFI_STATUS Status; + CHAR16 *RetVal; + + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentName2ProtocolGuid, + (VOID**)&CompNameStruct, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + Status = CompNameStruct->GetDriverName(CompNameStruct, (CHAR8*)Language, &RetVal); + if (!EFI_ERROR(Status)) { + return (RetVal); + } + } + Status = gBS->OpenProtocol( + TheHandle, + &gEfiComponentNameProtocolGuid, + (VOID**)&CompNameStruct, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!EFI_ERROR(Status)) { + Status = CompNameStruct->GetDriverName(CompNameStruct, (CHAR8*)Language, &RetVal); + if (!EFI_ERROR(Status)) { + return (RetVal); + } + } + return (NULL); +} + +/** + Function to initialize the file global mHandleList object for use in + vonverting handles to index and index to handle. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +InternalShellInitHandleList( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + HANDLE_LIST *ListWalker; + + if (mHandleList.NextIndex != 0) { + return EFI_SUCCESS; + } + InitializeListHead(&mHandleList.List.Link); + mHandleList.NextIndex = 1; + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return (Status); + } + for (mHandleList.NextIndex = 1 ; mHandleList.NextIndex <= HandleCount ; mHandleList.NextIndex++){ + ListWalker = AllocatePool(sizeof(HANDLE_LIST)); + ASSERT(ListWalker != NULL); + ListWalker->TheHandle = HandleBuffer[mHandleList.NextIndex-1]; + ListWalker->TheIndex = mHandleList.NextIndex; + InsertTailList(&mHandleList.List.Link,&ListWalker->Link); + } + FreePool(HandleBuffer); + return (EFI_SUCCESS); +} + +/** + Function to retrieve the human-friendly index of a given handle. If the handle + does not have a index one will be automatically assigned. The index value is valid + until the termination of the shell application. + + @param[in] TheHandle The handle to retrieve an index for. + + @retval 0 A memory allocation failed. + @return The index of the handle. + +**/ +UINTN +EFIAPI +ConvertHandleToHandleIndex( + IN CONST EFI_HANDLE TheHandle + ) +{ + HANDLE_LIST *ListWalker; + ASSERT(TheHandle!=NULL); + + InternalShellInitHandleList(); + + for (ListWalker = (HANDLE_LIST*)GetFirstNode(&mHandleList.List.Link) + ; !IsNull(&mHandleList.List.Link,&ListWalker->Link) + ; ListWalker = (HANDLE_LIST*)GetNextNode(&mHandleList.List.Link,&ListWalker->Link) + ){ + if (ListWalker->TheHandle == TheHandle) { + return (ListWalker->TheIndex); + } + } + ListWalker = AllocatePool(sizeof(HANDLE_LIST)); + ASSERT(ListWalker != NULL); + ListWalker->TheHandle = TheHandle; + ListWalker->TheIndex = mHandleList.NextIndex++; + InsertTailList(&mHandleList.List.Link,&ListWalker->Link); + return (ListWalker->TheIndex); +} + + + +/** + Function to retrieve the EFI_HANDLE from the human-friendly index. + + @param[in] TheIndex The index to retrieve the EFI_HANDLE for. + + @retval NULL The index was invalid. + @return The EFI_HANDLE that index represents. + +**/ +EFI_HANDLE +EFIAPI +ConvertHandleIndexToHandle( + IN CONST UINTN TheIndex + ) +{ + HANDLE_LIST *ListWalker; + + InternalShellInitHandleList(); + + if (TheIndex >= mHandleList.NextIndex) { + return (NULL); + } + + for (ListWalker = (HANDLE_LIST*)GetFirstNode(&mHandleList.List.Link) + ; !IsNull(&mHandleList.List.Link,&ListWalker->Link) + ; ListWalker = (HANDLE_LIST*)GetNextNode(&mHandleList.List.Link,&ListWalker->Link) + ){ + if (ListWalker->TheIndex == TheIndex) { + return (ListWalker->TheHandle); + } + } + return (NULL); +} + +/** + Gets all the related EFI_HANDLEs based on the mask supplied. + + This function scans all EFI_HANDLES in the UEFI environment's handle database + and returns the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a successful return the memory must be + caller freed. + + @param[in] DriverBindingHandle The handle with Driver Binding protocol on it. + @param[in] ControllerHandle The handle with Device Path protocol on it. + @param[in] MatchingHandleCount The pointer to UINTN that specifies the number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a successful return, a buffer of MatchingHandleCount + EFI_HANDLEs with a terminating NULL EFI_HANDLE. + @param[out] HandleType An array of type information. + + @retval EFI_SUCCESS The operation was successful, and any related handles + are in MatchingHandleBuffer. + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationshipWithType ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN UINTN *HandleCount, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN **HandleType + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + UINTN ChildIndex; + + ASSERT(HandleCount != NULL); + ASSERT(HandleBuffer != NULL); + ASSERT(HandleType != NULL); + ASSERT(DriverBindingHandle != NULL || ControllerHandle != NULL); + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + HandleCount, + HandleBuffer + ); + if (EFI_ERROR (Status)) { + return (Status); + } + + *HandleType = AllocateZeroPool (*HandleCount * sizeof (UINTN)); + ASSERT(*HandleType != NULL); + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + // + // Retrieve the list of all the protocols on each handle + // + Status = gBS->ProtocolsPerHandle ( + (*HandleBuffer)[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + + // + // Set the bit describing what this handle has + // + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_IMAGE_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_DRIVER_BINDING_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfiguration2ProtocolGuid)) { + (*HandleType)[HandleIndex] |= HR_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnostics2ProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid) ) { + (*HandleType)[HandleIndex] |= HR_DEVICE_HANDLE; + } else { + DEBUG_CODE_BEGIN(); + ASSERT((*HandleType)[HandleIndex] == (*HandleType)[HandleIndex]); + DEBUG_CODE_END(); + } + // + // Retrieve the list of agents that have opened each protocol + // + Status = gBS->OpenProtocolInformation ( + (*HandleBuffer)[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (DriverBindingHandle != NULL && OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + (*HandleType)[HandleIndex] |= (HR_DEVICE_HANDLE | HR_CONTROLLER_HANDLE); + } + if (ControllerHandle != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].ControllerHandle) { + (*HandleType)[ChildIndex] |= (HR_DEVICE_HANDLE | HR_CHILD_HANDLE); + } + } + } + } + } + if (DriverBindingHandle == NULL && OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + (*HandleType)[ChildIndex] |= HR_DEVICE_DRIVER; + } + } + } + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + (*HandleType)[HandleIndex] |= HR_PARENT_HANDLE; + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + (*HandleType)[ChildIndex] |= HR_BUS_DRIVER; + } + } + } + } + } + + FreePool (OpenInfo); + } + } + + FreePool (ProtocolGuidArray); + } + } + + if (EFI_ERROR(Status)) { + if (*HandleType != NULL) { + FreePool (*HandleType); + } + if (*HandleBuffer != NULL) { + FreePool (*HandleBuffer); + } + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + } + + return Status; +} + +/** + Gets all the related EFI_HANDLEs based on the single EFI_HANDLE and the mask + supplied. + + This function will scan all EFI_HANDLES in the UEFI environment's handle database + and return all the ones with the specified relationship (Mask) to the specified + controller handle. + + If both DriverBindingHandle and ControllerHandle are NULL, then ASSERT. + If MatchingHandleCount is NULL, then ASSERT. + + If MatchingHandleBuffer is not NULL upon a sucessful return the memory must be + caller freed. + + @param[in] DriverBindingHandle Handle to a object with Driver Binding protocol + on it. + @param[in] ControllerHandle Handle to a device with Device Path protocol on it. + @param[in] Mask Mask of what relationship(s) is desired. + @param[in] MatchingHandleCount Poitner to UINTN specifying number of HANDLES in + MatchingHandleBuffer. + @param[out] MatchingHandleBuffer On a sucessful return a buffer of MatchingHandleCount + EFI_HANDLEs and a terminating NULL EFI_HANDLE. + + @retval EFI_SUCCESS The operation was sucessful and any related handles + are in MatchingHandleBuffer; + @retval EFI_NOT_FOUND No matching handles were found. + @retval EFI_INVALID_PARAMETER A parameter was invalid or out of range. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseByRelationship ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN CONST UINTN Mask, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN *HandleType; + UINTN HandleIndex; + + ASSERT(MatchingHandleCount != NULL); + ASSERT(DriverBindingHandle != NULL || ControllerHandle != NULL); + + if ((Mask & HR_VALID_MASK) != Mask) { + return (EFI_INVALID_PARAMETER); + } + + if ((Mask & HR_CHILD_HANDLE) != 0 && DriverBindingHandle == NULL) { + return (EFI_INVALID_PARAMETER); + } + + *MatchingHandleCount = 0; + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = NULL; + } + + HandleBuffer = NULL; + HandleType = NULL; + + Status = ParseHandleDatabaseByRelationshipWithType ( + DriverBindingHandle, + ControllerHandle, + &HandleCount, + &HandleBuffer, + &HandleType + ); + if (!EFI_ERROR (Status)) { + // + // Count the number of handles that match the attributes in Mask + // + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + if ((HandleType[HandleIndex] & Mask) == Mask) { + (*MatchingHandleCount)++; + } + } + // + // If no handles match the attributes in Mask then return EFI_NOT_FOUND + // + if (*MatchingHandleCount == 0) { + Status = EFI_NOT_FOUND; + } else { + + if (MatchingHandleBuffer == NULL) { + // + // Someone just wanted the count... + // + Status = EFI_SUCCESS; + } else { + // + // Allocate a handle buffer for the number of handles that matched the attributes in Mask + // + *MatchingHandleBuffer = AllocatePool ((*MatchingHandleCount +1)* sizeof (EFI_HANDLE)); + ASSERT(*MatchingHandleBuffer != NULL); + + for (HandleIndex = 0,*MatchingHandleCount = 0 + ; HandleIndex < HandleCount + ; HandleIndex++ + ){ + // + // Fill the allocated buffer with the handles that matched the attributes in Mask + // + if ((HandleType[HandleIndex] & Mask) == Mask) { + (*MatchingHandleBuffer)[(*MatchingHandleCount)++] = HandleBuffer[HandleIndex]; + } + } + + // + // Make the last one NULL + // + (*MatchingHandleBuffer)[*MatchingHandleCount] = NULL; + + Status = EFI_SUCCESS; + } // MacthingHandleBuffer == NULL (ELSE) + } // *MatchingHandleCount == 0 (ELSE) + } // no error on ParseHandleDatabaseByRelationshipWithType + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (HandleType != NULL) { + FreePool (HandleType); + } + + return Status; +} + +/** + Gets handles for any child controllers of the passed in controller. + + @param[in] ControllerHandle The handle of the "parent controller" + @param[in] MatchingHandleCount Pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer Buffer containing handles on a successful + return. + + + @retval EFI_SUCCESS The operation was sucessful. +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildControllers( + IN CONST EFI_HANDLE ControllerHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN DriverBindingHandleCount; + EFI_HANDLE *DriverBindingHandleBuffer; + UINTN DriverBindingHandleIndex; + UINTN ChildControllerHandleCount; + EFI_HANDLE *ChildControllerHandleBuffer; + UINTN ChildControllerHandleIndex; + BOOLEAN Found; + EFI_HANDLE *HandleBufferForReturn; + + ASSERT (MatchingHandleCount != NULL); + + Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS ( + ControllerHandle, + &DriverBindingHandleCount, + &DriverBindingHandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + HandleBufferForReturn = GetHandleListByPotocol(&gEfiDriverBindingProtocolGuid); + if (HandleBufferForReturn == NULL) { + FreePool (DriverBindingHandleBuffer); + return Status; + } + + *MatchingHandleCount = 0; + for (DriverBindingHandleIndex = 0; DriverBindingHandleIndex < DriverBindingHandleCount; DriverBindingHandleIndex++) { + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + DriverBindingHandleBuffer[DriverBindingHandleIndex], + ControllerHandle, + &ChildControllerHandleCount, + &ChildControllerHandleBuffer + ); + if (EFI_ERROR (Status)) { + continue; + } + + for (ChildControllerHandleIndex = 0; + ChildControllerHandleIndex < ChildControllerHandleCount; + ChildControllerHandleIndex++ + ) { + Found = FALSE; + for (HandleIndex = 0; HandleBufferForReturn[HandleIndex] != NULL; HandleIndex++) { + if (HandleBufferForReturn[HandleIndex] == ChildControllerHandleBuffer[ChildControllerHandleIndex]) { + Found = TRUE; + break; + } + } + + if (!Found) { + HandleBufferForReturn[(*MatchingHandleCount)++] = ChildControllerHandleBuffer[ChildControllerHandleIndex]; + } + } + + FreePool (ChildControllerHandleBuffer); + } + + FreePool (DriverBindingHandleBuffer); + + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = HandleBufferForReturn; + } else { + FreePool(HandleBufferForReturn); + } + + return (EFI_SUCCESS); +} + +/** + Appends 1 buffer to another buffer. This will re-allocate the destination buffer + if necessary to fit all of the data. + + If DestinationBuffer is NULL, then ASSERT(). + + @param[in,out] DestinationBuffer The pointer to the pointer to the buffer to append onto. + @param[in,out] DestinationSize The pointer to the size of DestinationBuffer. + @param[in] SourceBuffer The pointer to the buffer to append onto DestinationBuffer. + @param[in] SourceSize The number of bytes of SourceBuffer to append. + + @retval NULL A memory allocation failed. + @retval NULL A parameter was invalid. + @return A pointer to (*DestinationBuffer). +**/ +VOID* +EFIAPI +BuffernCatGrow ( + IN OUT VOID **DestinationBuffer, + IN OUT UINTN *DestinationSize, + IN VOID *SourceBuffer, + IN UINTN SourceSize + ) +{ + UINTN LocalDestinationSize; + UINTN LocalDestinationFinalSize; + + ASSERT(DestinationBuffer != NULL); + + if (SourceSize == 0 || SourceBuffer == NULL) { + return (*DestinationBuffer); + } + + if (DestinationSize == NULL) { + LocalDestinationSize = 0; + } else { + LocalDestinationSize = *DestinationSize; + } + + LocalDestinationFinalSize = LocalDestinationSize + SourceSize; + + if (DestinationSize != NULL) { + *DestinationSize = LocalDestinationSize; + } + + if (LocalDestinationSize == 0) { + // allcoate + *DestinationBuffer = AllocatePool(LocalDestinationFinalSize); + } else { + // reallocate + *DestinationBuffer = ReallocatePool(LocalDestinationSize, LocalDestinationFinalSize, *DestinationBuffer); + } + + ASSERT(*DestinationBuffer != NULL); + + // copy + return (CopyMem(((UINT8*)(*DestinationBuffer)) + LocalDestinationSize, SourceBuffer, SourceSize)); +} + +/** + Gets handles for any child devices produced by the passed in driver. + + @param[in] DriverHandle The handle of the driver. + @param[in] MatchingHandleCount Pointer to the number of handles in + MatchingHandleBuffer on return. + @param[out] MatchingHandleBuffer Buffer containing handles on a successful + return. + @retval EFI_SUCCESS The operation was sucessful. + @sa ParseHandleDatabaseByRelationship +**/ +EFI_STATUS +EFIAPI +ParseHandleDatabaseForChildDevices( + IN CONST EFI_HANDLE DriverHandle, + IN UINTN *MatchingHandleCount, + OUT EFI_HANDLE **MatchingHandleBuffer OPTIONAL + ) +{ + EFI_HANDLE *Buffer; + EFI_HANDLE *Buffer2; + UINTN Count1; + UINTN Count2; + UINTN HandleIndex; + EFI_STATUS Status; + UINTN HandleBufferSize; + + ASSERT(MatchingHandleCount != NULL); + + HandleBufferSize = 0; + Buffer = NULL; + Buffer2 = NULL; + *MatchingHandleCount = 0; + + Status = PARSE_HANDLE_DATABASE_DEVICES ( + DriverHandle, + &Count1, + &Buffer + ); + if (!EFI_ERROR (Status)) { + for (HandleIndex = 0; HandleIndex < Count1; HandleIndex++) { + // + // now find the children + // + Status = PARSE_HANDLE_DATABASE_MANAGED_CHILDREN ( + DriverHandle, + Buffer[HandleIndex], + &Count2, + &Buffer2 + ); + if (EFI_ERROR(Status)) { + break; + } + // + // save out required and optional data elements + // + *MatchingHandleCount += Count2; + if (MatchingHandleBuffer != NULL) { + *MatchingHandleBuffer = BuffernCatGrow((VOID**)MatchingHandleBuffer, &HandleBufferSize, Buffer2, Count2 * sizeof(Buffer2[0])); + } + + // + // free the memory + // + if (Buffer2 != NULL) { + FreePool(Buffer2); + } + } + } + + if (Buffer != NULL) { + FreePool(Buffer); + } + return (Status); +} + +/** + Function to get all handles that support a given protocol or all handles. + + @param[in] ProtocolGuid The guid of the protocol to get handles for. If NULL + then the function will return all handles. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByPotocol ( + IN CONST EFI_GUID *ProtocolGuid OPTIONAL + ) +{ + EFI_HANDLE *HandleList; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + HandleList = NULL; + + // + // We cannot use LocateHandleBuffer since we need that NULL item on the ends of the list! + // + if (ProtocolGuid == NULL) { + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocatePool(Size + sizeof(EFI_HANDLE)); + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } else { + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocatePool(Size + sizeof(EFI_HANDLE)); + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } + if (EFI_ERROR(Status)) { + if (HandleList != NULL) { + FreePool(HandleList); + } + return (NULL); + } + return (HandleList); +} + +/** + Function to get all handles that support some protocols. + + @param[in] ProtocolGuids A NULL terminated list of protocol GUIDs. + + @retval NULL A memory allocation failed. + @return A NULL terminated list of handles. +**/ +EFI_HANDLE* +EFIAPI +GetHandleListByPotocolList ( + IN CONST EFI_GUID **ProtocolGuids + ) +{ + EFI_HANDLE *HandleList; + UINTN Size; + UINTN TotalSize; + EFI_STATUS Status; + CONST EFI_GUID **GuidWalker; + EFI_HANDLE *HandleWalker1; + EFI_HANDLE *HandleWalker2; + + Size = 0; + HandleList = NULL; + TotalSize = sizeof(EFI_HANDLE); + + for (GuidWalker = ProtocolGuids ; GuidWalker != NULL && *GuidWalker != NULL ; GuidWalker++,Size = 0){ + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)(*GuidWalker), NULL, &Size, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + TotalSize += Size; + } + } + HandleList = AllocatePool(TotalSize); + ASSERT(HandleList != NULL); + if (HandleList == NULL) { + return (NULL); + } + + Size = 0; + for (GuidWalker = ProtocolGuids ; GuidWalker != NULL && *GuidWalker != NULL ; GuidWalker++){ + Size = TotalSize - Size; + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)(*GuidWalker), NULL, &Size, HandleList+((TotalSize - Size)/sizeof(EFI_HANDLE))); + ASSERT_EFI_ERROR(Status); + } + HandleList[(TotalSize/sizeof(EFI_HANDLE))-1] = NULL; + + for (HandleWalker1 = HandleList ; HandleWalker1 != NULL && *HandleWalker1 != NULL ; HandleWalker1++) { + for (HandleWalker2 = HandleWalker1 + 1; HandleWalker2 != NULL && *HandleWalker2 != NULL ; HandleWalker2++) { + if (*HandleWalker1 == *HandleWalker2) { + // + // copy memory back 1 handle width. + // + CopyMem(HandleWalker2, HandleWalker2 + 1, TotalSize - ((HandleWalker2-HandleList+1)*sizeof(EFI_HANDLE))); + } + } + } + + return (HandleList); +} + + + + + + + + + + diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h new file mode 100644 index 0000000000..479c12d351 --- /dev/null +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.h @@ -0,0 +1,142 @@ +/** @file + Provides interface to advanced shell functionality for parsing both handle and protocol database. + + 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + LIST_ENTRY Link; + EFI_HANDLE TheHandle; + UINTN TheIndex; +}HANDLE_LIST; + +typedef struct { + HANDLE_LIST List; + UINTN NextIndex; +} HANDLE_INDEX_LIST; + +typedef +CHAR16 * +(EFIAPI *DUMP_PROTOCOL_INFO)( + IN CONST EFI_HANDLE TheHandle, + IN CONST BOOLEAN Verbose + ); + + +typedef struct { + EFI_STRING_ID StringId; + EFI_GUID *GuidId; + DUMP_PROTOCOL_INFO DumpInfo; +} PROTOCOL_INFO_BLOCK; + diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf new file mode 100644 index 0000000000..a0c2c16533 --- /dev/null +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf @@ -0,0 +1,158 @@ +## @file +# Provides interface to advanced shell functionality for parsing both handle and protocol database. +# 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. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiHandleParsingLib + FILE_GUID = 3CDC7177-CC2A-4678-BA8F-1A936A093FA4 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = HandleParsingLib|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = HandleParsingLibConstructor + DESTRUCTOR = HandleParsingLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + UefiHandleParsingLib.c + UefiHandleParsingLib.h + UefiHandleParsingLib.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + DevicePathLib + BaseLib + BaseMemoryLib + DebugLib + FileHandleLib + PrintLib + UefiLib + HiiLib + +[Protocols] + gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED + + # shell 2.0 + gEfiShellProtocolGuid # SOMETIMES_CONSUMED + gEfiShellParametersProtocolGuid # SOMETIMES_CONSUMED + + # 'old' shell + gEfiShellEnvironment2Guid # SOMETIMES_CONSUMED + gEfiShellInterfaceGuid # SOMETIMES_CONSUMED + + gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED + gEfiBusSpecificDriverOverrideProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathUtilitiesProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathFromTextProtocolGuid # ALWAYS_CONSUMED + gEfiPlatformDriverOverrideProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextInProtocolGuid # ALWAYS_CONSUMED + gEfiPlatformToDriverConfigurationProtocolGuid # ALWAYS_CONSUMED + gEfiDriverSupportedEfiVersionProtocolGuid # ALWAYS_CONSUMED + gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathProtocolGuid # ALWAYS_CONSUMED + gEfiLoadedImageDevicePathProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleTextOutProtocolGuid + gEfiSimplePointerProtocolGuid + gEfiAbsolutePointerProtocolGuid + gEfiSerialIoProtocolGuid + gEfiEdidDiscoveredProtocolGuid + gEfiEdidActiveProtocolGuid + gEfiEdidOverrideProtocolGuid + gEfiLoadFileProtocolGuid + gEfiLoadFile2ProtocolGuid + gEfiTapeIoProtocolGuid + gEfiDiskIoProtocolGuid + gEfiBlockIoProtocolGuid + gEfiUnicodeCollationProtocolGuid + gEfiUnicodeCollation2ProtocolGuid + gEfiPciRootBridgeIoProtocolGuid + gEfiPciIoProtocolGuid + gEfiScsiPassThruProtocolGuid + gEfiScsiIoProtocolGuid + gEfiExtScsiPassThruProtocolGuid + gEfiIScsiInitiatorNameProtocolGuid + gEfiUsbIoProtocolGuid + gEfiUsbHcProtocolGuid + gEfiUsb2HcProtocolGuid + gEfiDebugSupportProtocolGuid + gEfiDebugPortProtocolGuid + gEfiDecompressProtocolGuid + gEfiAcpiTableProtocolGuid + gEfiEbcProtocolGuid + gEfiSimpleNetworkProtocolGuid + gEfiNetworkInterfaceIdentifierProtocolGuid + gEfiNetworkInterfaceIdentifierProtocolGuid_31 + gEfiPxeBaseCodeProtocolGuid + gEfiPxeBaseCodeCallbackProtocolGuid + gEfiBisProtocolGuid + gEfiManagedNetworkServiceBindingProtocolGuid + gEfiManagedNetworkProtocolGuid + gEfiArpServiceBindingProtocolGuid + gEfiArpProtocolGuid + gEfiDhcp4ServiceBindingProtocolGuid + gEfiDhcp4ProtocolGuid + gEfiTcp4ServiceBindingProtocolGuid + gEfiTcp4ProtocolGuid + gEfiIp4ServiceBindingProtocolGuid + gEfiIp4ProtocolGuid + gEfiIp4ConfigProtocolGuid + gEfiUdp4ServiceBindingProtocolGuid + gEfiUdp4ProtocolGuid + gEfiMtftp4ServiceBindingProtocolGuid + gEfiMtftp4ProtocolGuid + gEfiAuthenticationInfoProtocolGuid + gEfiHashServiceBindingProtocolGuid + gEfiHashProtocolGuid + gEfiHiiFontProtocolGuid + gEfiHiiStringProtocolGuid + gEfiHiiImageProtocolGuid + gEfiHiiConfigRoutingProtocolGuid + gEfiHiiConfigAccessProtocolGuid + gEfiFormBrowser2ProtocolGuid + gEfiDeviceIoProtocolGuid + gEfiUgaDrawProtocolGuid + gEfiUgaIoProtocolGuid + gEfiDriverConfigurationProtocolGuid + gEfiDriverConfiguration2ProtocolGuid + gEfiSimpleTextInputExProtocolGuid + +[Guids] + gEfiFileInfoGuid # ALWAYS_CONSUMED + gEfiShellEnvironment2ExtGuid # ALWAYS_CONSUMED + gEfiPcAnsiGuid + gEfiVT100Guid + gEfiVT100PlusGuid + gEfiVTUTF8Guid + gEfiStandardErrorDeviceGuid + gEfiConsoleInDeviceGuid + gEfiConsoleOutDeviceGuid + gEfiFileSystemInfoGuid + gEfiGlobalVariableGuid + gEfiPartTypeSystemPartGuid + gEfiPartTypeLegacyMbrGuid + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellIncludeNtGuids # ALWAYS_CONSUMED \ No newline at end of file diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni new file mode 100644 index 0000000000..1ac84d8a3c Binary files /dev/null and b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.uni differ diff --git a/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c b/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c index 53e50ca7de..60b15fe8a0 100644 --- a/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c +++ b/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c @@ -59,7 +59,7 @@ ShellCEntryLib ( ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + ); if (!EFI_ERROR(Status)) { // // use shell 2.0 interface @@ -67,7 +67,7 @@ ShellCEntryLib ( ReturnFromMain = ShellAppMain ( EfiShellParametersProtocol->Argc, EfiShellParametersProtocol->Argv - ); + ); } else { // // try to get shell 1.0 interface instead. @@ -78,7 +78,7 @@ ShellCEntryLib ( ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + ); if (!EFI_ERROR(Status)) { // // use shell 1.0 interface @@ -86,7 +86,7 @@ ShellCEntryLib ( ReturnFromMain = ShellAppMain ( EfiShellInterface->Argc, EfiShellInterface->Argv - ); + ); } else { ASSERT(FALSE); } diff --git a/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf b/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf index b55264dc27..7c06525bb8 100644 --- a/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf +++ b/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf @@ -1,7 +1,7 @@ -## @file +## @file # Provides interface to shell functionality for shell commands and applications. # -# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 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 @@ -19,13 +19,13 @@ FILE_GUID = 0e205c8a-8586-4dec-9f5c-4f9e394aefe8 MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 - LIBRARY_CLASS = ShellCEntryLib|UEFI_APPLICATION + LIBRARY_CLASS = ShellCEntryLib|UEFI_APPLICATION UEFI_DRIVER # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # -[Sources] +[Sources.common] UefiShellCEntryLib.c [Packages] @@ -43,5 +43,5 @@ [Guids] -[Pcd] +[Pcd.common] diff --git a/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c b/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c new file mode 100644 index 0000000000..3425e9e912 --- /dev/null +++ b/ShellPkg/Library/UefiShellCommandLib/ConsistMapping.c @@ -0,0 +1,1310 @@ +/** @file + Main file for support of shell consist mapping. + + Copyright (c) 2005 - 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 "UefiShellCommandLib.h" +#include +#include + +typedef enum { + MTDTypeUnknown, + MTDTypeFloppy, + MTDTypeHardDisk, + MTDTypeCDRom, + MTDTypeEnd +} MTD_TYPE; + +typedef struct { + CHAR16 *Str; + UINTN Len; +} POOL_PRINT; + +typedef struct { + UINTN HI; + MTD_TYPE MTD; + POOL_PRINT CSD; + BOOLEAN Digital; +} DEVICE_CONSIST_MAPPING_INFO; + +typedef struct { + MTD_TYPE MTDType; + CHAR16 *Name; +} MTD_NAME; + +typedef struct { + UINT8 Type; + UINT8 SubType; + VOID (*SerialFun) (EFI_DEVICE_PATH_PROTOCOL *, DEVICE_CONSIST_MAPPING_INFO *); + INTN (*CompareFun) (EFI_DEVICE_PATH_PROTOCOL *, EFI_DEVICE_PATH_PROTOCOL *); +} DEV_PATH_CONSIST_MAPPING_TABLE; + + +/** + Concatenates a formatted unicode string to allocated pool. + The caller must free the resulting buffer. + + @param Str Tracks the allocated pool, size in use, and amount of pool allocated. + @param Fmt The format string + @param ... The data will be printed. + + @return Allocated buffer with the formatted string printed in it. + The caller must free the allocated buffer. + The buffer allocation is not packed. + +**/ +CHAR16 * +EFIAPI +CatPrint ( + IN OUT POOL_PRINT *Str, + IN CHAR16 *Fmt, + ... + ) +{ + UINT16 *AppendStr; + VA_LIST Args; + UINTN StringSize; + + AppendStr = AllocateZeroPool (0x1000); + if (AppendStr == NULL) { + ASSERT(FALSE); + return Str->Str; + } + + VA_START (Args, Fmt); + UnicodeVSPrint (AppendStr, 0x1000, Fmt, Args); + VA_END (Args); + if (NULL == Str->Str) { + StringSize = StrSize (AppendStr); + Str->Str = AllocateZeroPool (StringSize); + ASSERT (Str->Str != NULL); + } else { + StringSize = StrSize (AppendStr); + StringSize += (StrSize (Str->Str) - sizeof (UINT16)); + + Str->Str = ReallocatePool ( + StrSize (Str->Str), + StringSize, + Str->Str + ); + ASSERT (Str->Str != NULL); + } + + StrCat (Str->Str, AppendStr); + Str->Len = StringSize; + + FreePool (AppendStr); + return Str->Str; +} + +MTD_NAME mMTDName[] = { + { + MTDTypeUnknown, + L"F" + }, + { + MTDTypeFloppy, + L"FP" + }, + { + MTDTypeHardDisk, + L"HD" + }, + { + MTDTypeCDRom, + L"CD" + }, + { + MTDTypeEnd, + NULL + } +}; + +VOID +AppendCSDNum2 ( + IN OUT POOL_PRINT *Str, + IN UINT64 Num + ) +{ + UINT64 Result; + UINT32 Rem; + + ASSERT(Str != NULL); + + Result = DivU64x32Remainder (Num, 25, &Rem); + if (Result > 0) { + AppendCSDNum2 (Str, Result); + } + + CatPrint (Str, L"%c", Rem + 'a'); +} + +VOID +AppendCSDNum ( + DEVICE_CONSIST_MAPPING_INFO *MappingItem, + UINT64 Num + ) +{ + ASSERT(MappingItem != NULL); + + if (MappingItem->Digital) { + CatPrint (&MappingItem->CSD, L"%ld", Num); + } else { + AppendCSDNum2 (&MappingItem->CSD, Num); + } + + MappingItem->Digital = (BOOLEAN)!(MappingItem->Digital); +} + +VOID +AppendCSDStr ( + DEVICE_CONSIST_MAPPING_INFO *MappingItem, + CHAR16 *Str + ) +{ + CHAR16 *Index; + + ASSERT(Str != NULL); + ASSERT(MappingItem != NULL); + + if (MappingItem->Digital) { + // + // To aVOID mult-meaning, the mapping is: + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + // 0 16 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // + for (Index = Str; *Index != 0; Index++) { + switch (*Index) { + case '0': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + CatPrint (&MappingItem->CSD, L"%c", *Index); + break; + + case '1': + CatPrint (&MappingItem->CSD, L"16"); + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + CatPrint (&MappingItem->CSD, L"1%c", *Index - 'a' + '0'); + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + CatPrint (&MappingItem->CSD, L"1%c", *Index - 'A' + '0'); + break; + } + } + } else { + for (Index = Str; *Index != 0; Index++) { + // + // The mapping is: + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + // a b c d e f g h i j k l m n o p + // + if (*Index >= '0' && *Index <= '9') { + CatPrint (&MappingItem->CSD, L"%c", *Index - '0' + 'a'); + } else if (*Index >= 'a' && *Index <= 'f') { + CatPrint (&MappingItem->CSD, L"%c", *Index - 'a' + 'k'); + } else if (*Index >= 'A' && *Index <= 'F') { + CatPrint (&MappingItem->CSD, L"%c", *Index - 'A' + 'k'); + } + } + } + + MappingItem->Digital = (BOOLEAN)!(MappingItem->Digital); +} + +VOID +AppendCSDGuid ( + DEVICE_CONSIST_MAPPING_INFO *MappingItem, + EFI_GUID *Guid + ) +{ + CHAR16 Buffer[64]; + ASSERT(Guid != NULL); + ASSERT(MappingItem != NULL); + + UnicodeSPrint ( + Buffer, + 0, + L"%g", + Guid + ); +// StrLwr (Buffer); + AppendCSDStr (MappingItem, Buffer); +} + +INTN +_DevPathCompareAcpi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + ACPI_HID_DEVICE_PATH *Acpi1; + ACPI_HID_DEVICE_PATH *Acpi2; + + ASSERT(DevicePath1 != NULL); + ASSERT(DevicePath2 != NULL); + + Acpi1 = (ACPI_HID_DEVICE_PATH *) DevicePath1; + Acpi2 = (ACPI_HID_DEVICE_PATH *) DevicePath2; + if (Acpi1->HID > Acpi2->HID || (Acpi1->HID == Acpi2->HID && Acpi1->UID > Acpi2->UID)) { + return 1; + } + + if (Acpi1->HID == Acpi2->HID && Acpi1->UID == Acpi2->UID) { + return 0; + } + + return -1; +} + +INTN +_DevPathComparePci ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + PCI_DEVICE_PATH *Pci1; + PCI_DEVICE_PATH *Pci2; + + ASSERT(DevicePath1 != NULL); + ASSERT(DevicePath2 != NULL); + + Pci1 = (PCI_DEVICE_PATH *) DevicePath1; + Pci2 = (PCI_DEVICE_PATH *) DevicePath2; + if (Pci1->Device > Pci2->Device || (Pci1->Device == Pci2->Device && Pci1->Function > Pci2->Function)) { + return 1; + } + + if (Pci1->Device == Pci2->Device && Pci1->Function == Pci2->Function) { + return 0; + } + + return -1; +} + +/** + Do a comparison on 2 device paths. + + @param[in] DevicePath1 The first device path. + @param[in] DevicePath2 The second device path. + + @retval 0 The 2 device paths are the same. + @retval <0 DevicePath2 is greater than DevicePath1. + @retval >0 DevicePath1 is greater than DevicePath2. +**/ +INTN +EFIAPI +DevPathCompareDefault ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + UINTN DevPathSize1; + UINTN DevPathSize2; + + ASSERT(DevicePath1 != NULL); + ASSERT(DevicePath2 != NULL); + + DevPathSize1 = DevicePathNodeLength (DevicePath1); + DevPathSize2 = DevicePathNodeLength (DevicePath2); + if (DevPathSize1 > DevPathSize2) { + return 1; + } else if (DevPathSize1 < DevPathSize2) { + return -1; + } else { + return CompareMem (DevicePath1, DevicePath2, DevPathSize1); + } +} + +/** + DevicePathNode must be SerialHDD Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialHardDrive ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + HARDDRIVE_DEVICE_PATH *Hd; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Hd = (HARDDRIVE_DEVICE_PATH *) DevicePathNode; + if (MappingItem->MTD == MTDTypeUnknown) { + MappingItem->MTD = MTDTypeHardDisk; + } + + AppendCSDNum (MappingItem, Hd->PartitionNumber); +} + +/** + DevicePathNode must be SerialAtapi Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialAtapi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + ATAPI_DEVICE_PATH *Atapi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Atapi = (ATAPI_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, (Atapi->PrimarySecondary * 2 + Atapi->SlaveMaster)); +} + +/** + DevicePathNode must be SerialCDROM Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialCdRom ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + CDROM_DEVICE_PATH *Cd; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Cd = (CDROM_DEVICE_PATH *) DevicePathNode; + MappingItem->MTD = MTDTypeCDRom; + AppendCSDNum (MappingItem, Cd->BootEntry); +} + +/** + DevicePathNode must be SerialFibre Channel type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialFibre ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + FIBRECHANNEL_DEVICE_PATH *Fibre; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Fibre = (FIBRECHANNEL_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Fibre->WWN); + AppendCSDNum (MappingItem, Fibre->Lun); +} + +/** + DevicePathNode must be SerialUart type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialUart ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + UART_DEVICE_PATH *Uart; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Uart = (UART_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Uart->BaudRate); + AppendCSDNum (MappingItem, Uart->DataBits); + AppendCSDNum (MappingItem, Uart->Parity); + AppendCSDNum (MappingItem, Uart->StopBits); +} + +/** + DevicePathNode must be SerialUSB type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialUsb ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + USB_DEVICE_PATH *Usb; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Usb = (USB_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Usb->ParentPortNumber); + AppendCSDNum (MappingItem, Usb->InterfaceNumber); +} + +/** + DevicePathNode must be SerialVendor type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialVendor ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + VENDOR_DEVICE_PATH *Vendor; + SAS_DEVICE_PATH *Sas; + EFI_GUID SasVendorGuid = DEVICE_PATH_MESSAGING_SAS; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Vendor = (VENDOR_DEVICE_PATH *) DevicePathNode; + AppendCSDGuid (MappingItem, &Vendor->Guid); + + if (CompareGuid (&SasVendorGuid, &Vendor->Guid) == 0) { + Sas = (SAS_DEVICE_PATH *) Vendor; + AppendCSDNum (MappingItem, Sas->SasAddress); + AppendCSDNum (MappingItem, Sas->Lun); + AppendCSDNum (MappingItem, Sas->DeviceTopology); + AppendCSDNum (MappingItem, Sas->RelativeTargetPort); + } +} + +/** + DevicePathNode must be SerialLun type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialLun ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + DEVICE_LOGICAL_UNIT_DEVICE_PATH *Lun; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Lun = (DEVICE_LOGICAL_UNIT_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Lun->Lun); +} + +/** + DevicePathNode must be SerialSata type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialSata ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + SATA_DEVICE_PATH *Sata; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Sata = (SATA_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Sata->HBAPortNumber); + AppendCSDNum (MappingItem, Sata->PortMultiplierPortNumber); + AppendCSDNum (MappingItem, Sata->Lun); +} + +/** + DevicePathNode must be SerialSCSI type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialIScsi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ +///@todo make this a PCD +// +// As CSD of ISCSI node is quite long, we comment +// the code below to keep the consistent mapping +// short. Uncomment if you really need it. +// +/* + ISCSI_DEVICE_PATH *IScsi; + UINT8 *IScsiTargetName; + CHAR16 *TargetName; + UINTN TargetNameLength; + UINTN Index; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + IScsi = (ISCSI_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, IScsi->NetworkProtocol); + AppendCSDNum (MappingItem, IScsi->LoginOption); + AppendCSDNum (MappingItem, IScsi->Lun); + AppendCSDNum (MappingItem, IScsi->TargetPortalGroupTag); + TargetNameLength = DevicePathNodeLength (DevicePathNode) - sizeof (ISCSI_DEVICE_PATH); + if (TargetNameLength > 0) { + TargetName = AllocateZeroPool ((TargetNameLength + 1) * sizeof (CHAR16)); + if (TargetName != NULL) { + IScsiTargetName = (UINT8 *) (IScsi + 1); + for (Index = 0; Index < TargetNameLength; Index++) { + TargetName[Index] = (CHAR16) IScsiTargetName[Index]; + } + AppendCSDStr (MappingItem, TargetName); + FreePool (TargetName); + } + } + */ +} + +/** + DevicePathNode must be SerialI20 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialI2O ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + I2O_DEVICE_PATH *I2O; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + I2O = (I2O_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, I2O->Tid); +} + +/** + DevicePathNode must be Mac Address type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialMacAddr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + MAC_ADDR_DEVICE_PATH *Mac; + UINTN HwAddressSize; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Mac = (MAC_ADDR_DEVICE_PATH *) DevicePathNode; + + HwAddressSize = sizeof (EFI_MAC_ADDRESS); + if (Mac->IfType == 0x01 || Mac->IfType == 0x00) { + HwAddressSize = 6; + } + + for (Index = 0, PBuffer = Buffer; Index < HwAddressSize; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Mac->MacAddress.Addr[Index]); + } + + AppendCSDStr (MappingItem, Buffer); +} + +/** + DevicePathNode must be InfiniBand type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialInfiniBand ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + INFINIBAND_DEVICE_PATH *InfiniBand; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + InfiniBand = (INFINIBAND_DEVICE_PATH *) DevicePathNode; + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) InfiniBand->PortGid[Index]); + } + + AppendCSDStr (MappingItem, Buffer); + AppendCSDNum (MappingItem, InfiniBand->ServiceId); + AppendCSDNum (MappingItem, InfiniBand->TargetPortId); + AppendCSDNum (MappingItem, InfiniBand->DeviceId); +} + +/** + DevicePathNode must be IPv4 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialIPv4 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + IPv4_DEVICE_PATH *Ip; + CHAR16 Buffer[10]; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Ip = (IPv4_DEVICE_PATH *) DevicePathNode; + UnicodeSPrint ( + Buffer, + 0, + L"%02x%02x%02x%02x", + (UINTN) Ip->LocalIpAddress.Addr[0], + (UINTN) Ip->LocalIpAddress.Addr[1], + (UINTN) Ip->LocalIpAddress.Addr[2], + (UINTN) Ip->LocalIpAddress.Addr[3] + ); + AppendCSDStr (MappingItem, Buffer); + AppendCSDNum (MappingItem, Ip->LocalPort); + UnicodeSPrint ( + Buffer, + 0, + L"%02x%02x%02x%02x", + (UINTN) Ip->RemoteIpAddress.Addr[0], + (UINTN) Ip->RemoteIpAddress.Addr[1], + (UINTN) Ip->RemoteIpAddress.Addr[2], + (UINTN) Ip->RemoteIpAddress.Addr[3] + ); + AppendCSDStr (MappingItem, Buffer); + AppendCSDNum (MappingItem, Ip->RemotePort); +} + +/** + DevicePathNode must be IPv6 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialIPv6 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + IPv6_DEVICE_PATH *Ip; + UINTN Index; + CHAR16 Buffer[64]; + CHAR16 *PBuffer; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Ip = (IPv6_DEVICE_PATH *) DevicePathNode; + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->LocalIpAddress.Addr[Index]); + } + + AppendCSDStr (MappingItem, Buffer); + AppendCSDNum (MappingItem, Ip->LocalPort); + for (Index = 0, PBuffer = Buffer; Index < 16; Index++, PBuffer += 2) { + UnicodeSPrint (PBuffer, 0, L"%02x", (UINTN) Ip->RemoteIpAddress.Addr[Index]); + } + + AppendCSDStr (MappingItem, Buffer); + AppendCSDNum (MappingItem, Ip->RemotePort); +} + +/** + DevicePathNode must be SCSI type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialScsi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + SCSI_DEVICE_PATH *Scsi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Scsi = (SCSI_DEVICE_PATH *) DevicePathNode; + AppendCSDNum (MappingItem, Scsi->Pun); + AppendCSDNum (MappingItem, Scsi->Lun); +} + +/** + DevicePathNode must be 1394 type and this will populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerial1394 ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + F1394_DEVICE_PATH *F1394; + CHAR16 Buffer[20]; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + F1394 = (F1394_DEVICE_PATH *) DevicePathNode; + UnicodeSPrint (Buffer, 0, L"%lx", F1394->Guid); + AppendCSDStr (MappingItem, Buffer); +} + +/** + If the node is floppy type then populate the MappingItem. + + @param[in] DevicePathNode The node to get info on. + @param[in] MappingItem The info item to populate. +**/ +VOID +EFIAPI +DevPathSerialAcpi ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + ASSERT(DevicePathNode != NULL); + ASSERT(MappingItem != NULL); + + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; + if ((Acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { + if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { + MappingItem->MTD = MTDTypeFloppy; + AppendCSDNum (MappingItem, Acpi->UID); + } + } +} + +/** + Empty function used for unknown devices. + + Does nothing. +**/ +VOID +EFIAPI +DevPathSerialDefault ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode, + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem + ) +{ +} + +DEV_PATH_CONSIST_MAPPING_TABLE DevPathConsistMappingTable[] = { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + DevPathSerialDefault, + _DevPathComparePci, + ACPI_DEVICE_PATH, + ACPI_DP, + DevPathSerialAcpi, + _DevPathCompareAcpi, + MESSAGING_DEVICE_PATH, + MSG_ATAPI_DP, + DevPathSerialAtapi, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_SCSI_DP, + DevPathSerialScsi, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_FIBRECHANNEL_DP, + DevPathSerialFibre, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_1394_DP, + DevPathSerial1394, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_USB_DP, + DevPathSerialUsb, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_I2O_DP, + DevPathSerialI2O, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_MAC_ADDR_DP, + DevPathSerialMacAddr, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_IPv4_DP, + DevPathSerialIPv4, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_IPv6_DP, + DevPathSerialIPv6, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_INFINIBAND_DP, + DevPathSerialInfiniBand, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_UART_DP, + DevPathSerialUart, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_VENDOR_DP, + DevPathSerialVendor, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_DEVICE_LOGICAL_UNIT_DP, + DevPathSerialLun, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_SATA_DP, + DevPathSerialSata, + DevPathCompareDefault, + MESSAGING_DEVICE_PATH, + MSG_ISCSI_DP, + DevPathSerialIScsi, + DevPathCompareDefault, + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP, + DevPathSerialHardDrive, + DevPathCompareDefault, + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP, + DevPathSerialCdRom, + DevPathCompareDefault, + MEDIA_DEVICE_PATH, + MEDIA_VENDOR_DP, + DevPathSerialVendor, + DevPathCompareDefault, + 0, + 0, + NULL, + NULL +}; + +/** + Function to determine if a device path node is Hi or not. + + @param[in] DevicePathNode The node to check. + + @retval TRUE The node is HI. + @retval FALSE The node is not HI. +**/ +BOOLEAN +EFIAPI +IsHIDevicePathNode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + ASSERT(DevicePathNode != NULL); + + if (DevicePathNode->Type == HARDWARE_DEVICE_PATH) { + return TRUE; + } + + if (DevicePathNode->Type == ACPI_DEVICE_PATH) { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePathNode; + switch (EISA_ID_TO_NUM (Acpi->HID)) { + case 0x0301: + case 0x0401: + case 0x0501: + case 0x0604: + return FALSE; + } + + return TRUE; + } + + return FALSE; +} + +/** + Function to convert a standard device path structure into a HI version. + + @param[in] DevicePath The device path to convert. + + @return the device path portion that is HI. +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +GetHIDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + UINTN NonHIDevicePathNodeCount; + UINTN Index; + EFI_DEV_PATH Node; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + ASSERT(DevicePath != NULL); + + NonHIDevicePathNodeCount = 0; + + HIDevicePath = AllocatePool (sizeof (EFI_DEVICE_PATH_PROTOCOL)); + SetDevicePathEndNode (HIDevicePath); + + Node.DevPath.Type = END_DEVICE_PATH_TYPE; + Node.DevPath.SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; + Node.DevPath.Length[0] = (UINT8)sizeof (EFI_DEVICE_PATH_PROTOCOL); + Node.DevPath.Length[1] = 0; + + while (!IsDevicePathEnd (DevicePath)) { + if (IsHIDevicePathNode (DevicePath)) { + for (Index = 0; Index < NonHIDevicePathNodeCount; Index++) { + TempDevicePath = AppendDevicePathNode (HIDevicePath, &Node.DevPath); + FreePool (HIDevicePath); + HIDevicePath = TempDevicePath; + } + + TempDevicePath = AppendDevicePathNode (HIDevicePath, DevicePath); + FreePool (HIDevicePath); + HIDevicePath = TempDevicePath; + } else { + NonHIDevicePathNodeCount++; + } + // + // Next device path node + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); + } + + return HIDevicePath; +} + +/** + Function to walk the device path looking for a dumpable node. + + @param[in] MappingItem The Item to fill with data. + @param[in] DevicePath The path of the item to get data on. + + @return EFI_SUCCESS Always returns success. +**/ +EFI_STATUS +EFIAPI +GetDeviceConsistMappingInfo ( + IN DEVICE_CONSIST_MAPPING_INFO *MappingItem, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + VOID (*SerialFun) (EFI_DEVICE_PATH_PROTOCOL *, DEVICE_CONSIST_MAPPING_INFO *); + + UINTN Index; + + ASSERT(DevicePath != NULL); + ASSERT(MappingItem != NULL); + + SetMem (&MappingItem->CSD, sizeof (POOL_PRINT), 0); + + while (!IsDevicePathEnd (DevicePath)) { + // + // Find the handler to dump this device path node + // + SerialFun = NULL; + for (Index = 0; DevPathConsistMappingTable[Index].SerialFun != NULL; Index += 1) { + + if (DevicePathType (DevicePath) == DevPathConsistMappingTable[Index].Type && + DevicePathSubType (DevicePath) == DevPathConsistMappingTable[Index].SubType + ) { + SerialFun = DevPathConsistMappingTable[Index].SerialFun; + break; + } + } + // + // If not found, use a generic function + // + if (!SerialFun) { + SerialFun = DevPathSerialDefault; + } + + SerialFun (DevicePath, MappingItem); + + // + // Next device path node + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) NextDevicePathNode (DevicePath); + } + + return EFI_SUCCESS; +} + +/** + Function to initialize the table for creating consistent map names. + + @param[out] Table The pointer to pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was created successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingInitialize ( + OUT EFI_DEVICE_PATH_PROTOCOL ***Table + ) +{ + EFI_HANDLE *HandleBuffer; + UINTN HandleNum; + UINTN HandleLoop; + EFI_DEVICE_PATH_PROTOCOL **TempTable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + UINTN Index; + EFI_STATUS Status; + + HandleBuffer = NULL; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleNum, + &HandleBuffer + ); + ASSERT_EFI_ERROR(Status); + + TempTable = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_DEVICE_PATH_PROTOCOL *)); + if (TempTable == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (HandleLoop = 0 ; HandleLoop < HandleNum ; HandleLoop++) { + DevicePath = DevicePathFromHandle (HandleBuffer[HandleLoop]); + if (DevicePath == NULL) { + continue; + } + + HIDevicePath = GetHIDevicePath (DevicePath); + if (HIDevicePath == NULL) { + continue; + } + + for (Index = 0; TempTable[Index] != NULL; Index++) { + if (DevicePathCompare (&TempTable[Index], &HIDevicePath) == 0) { + FreePool (HIDevicePath); + break; + } + } + + if (TempTable[Index] == NULL) { + TempTable[Index] = HIDevicePath; + } + } + + for (Index = 0; TempTable[Index] != NULL; Index++); + PerformQuickSort(TempTable, Index, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + *Table = TempTable; + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + Function to uninitialize the table for creating consistent map names. + + The parameter must have been received from ShellCommandConsistMappingInitialize. + + @param[out] Table The pointer to pointer to DevicePathProtocol object. + + @retval EFI_SUCCESS The table was deleted successfully. +**/ +EFI_STATUS +EFIAPI +ShellCommandConsistMappingUnInitialize ( + EFI_DEVICE_PATH_PROTOCOL **Table + ) +{ + UINTN Index; + + ASSERT(Table != NULL); + + for (Index = 0; Table[Index] != NULL; Index++) { + FreePool (Table[Index]); + } + + FreePool (Table); + return EFI_SUCCESS; +} + +/** + Create a consistent mapped name for the device specified by DevicePath + based on the Table. + + This must be called after ShellCommandConsistMappingInitialize() and + before ShellCommandConsistMappingUnInitialize() is called. + + @param[in] DeviecPath The pointer to the dev path for the device. + @param[in] Table The Table of mapping information. + + @retval NULL A consistent mapped name could not be created. + @return A pointer to a string allocated from pool with the device name. +**/ +CHAR16 * +EFIAPI +ShellCommandConsistMappingGenMappingName ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath, + EFI_DEVICE_PATH_PROTOCOL **Table + ) +{ + POOL_PRINT Str; + DEVICE_CONSIST_MAPPING_INFO MappingInfo; + EFI_DEVICE_PATH_PROTOCOL *HIDevicePath; + UINTN Index; + UINTN NewSize; + + ASSERT(DevicePath != NULL); + ASSERT(Table != NULL); + + HIDevicePath = GetHIDevicePath (DevicePath); + if (HIDevicePath == NULL) { + return NULL; + } + + for (Index = 0; Table[Index] != NULL; Index++) { + if (DevicePathCompare (&Table[Index], &HIDevicePath) == 0) { + break; + } + } + + FreePool (HIDevicePath); + if (Table[Index] == NULL) { + return NULL; + } + + MappingInfo.HI = Index; + MappingInfo.MTD = MTDTypeUnknown; + MappingInfo.Digital = FALSE; + + GetDeviceConsistMappingInfo (&MappingInfo, DevicePath); + + SetMem (&Str, sizeof (Str), 0); + for (Index = 0; mMTDName[Index].MTDType != MTDTypeEnd; Index++) { + if (MappingInfo.MTD == mMTDName[Index].MTDType) { + break; + } + } + + if (mMTDName[Index].MTDType != MTDTypeEnd) { + CatPrint (&Str, L"%s", mMTDName[Index].Name); + } + + CatPrint (&Str, L"%d", (UINTN) MappingInfo.HI); + if (MappingInfo.CSD.Str != NULL) { + CatPrint (&Str, L"%s", MappingInfo.CSD.Str); + FreePool (MappingInfo.CSD.Str); + } + + if (Str.Str != NULL) { + CatPrint (&Str, L":"); + } + + NewSize = (Str.Len + 1) * sizeof (CHAR16); + Str.Str = ReallocatePool (Str.Len, NewSize, Str.Str); + Str.Str[Str.Len] = CHAR_NULL; + return Str.Str; +} + +/** + Function to search the list of mappings for the node on the list based on the key. + + @param[in] MapKey String Key to search for on the map + + @return the node on the list. +**/ +SHELL_MAP_LIST * +EFIAPI +ShellCommandFindMapItem ( + IN CONST CHAR16 *MapKey + ) +{ + SHELL_MAP_LIST *MapListItem; + + for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsNull(&gShellMapList.Link, &MapListItem->Link) + ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link) + ){ + if (gUnicodeCollation->StriColl(gUnicodeCollation,MapListItem->MapName,(CHAR16*)MapKey) == 0) { + return (MapListItem); + } + } + return (NULL); +} + + diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c new file mode 100644 index 0000000000..5a3739ff91 --- /dev/null +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -0,0 +1,1511 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + Copyright (c) 2009 - 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 "UefiShellCommandLib.h" + +/// The tag for use in identifying UNICODE files. +/// If the file is UNICODE, the first 16 bits of the file will equal this value. +enum { + UnicodeFileTag = 0xFEFF +}; + +// STATIC local variables +STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList; +STATIC SCRIPT_FILE_LIST mScriptList; +STATIC ALIAS_LIST mAliasList; +STATIC BOOLEAN mEchoState; +STATIC BOOLEAN mExitRequested; +STATIC BOOLEAN mExitScript; +STATIC CHAR16 *mProfileList; +STATIC UINTN mProfileListSize; +STATIC UINTN mFsMaxCount = 0; +STATIC UINTN mBlkMaxCount = 0; +STATIC BUFFER_LIST mFileHandleList; + +// global variables required by library class. +EFI_SHELL_PROTOCOL *gEfiShellProtocol = NULL; +EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol = NULL; +EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL; +EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *gDevPathToText = NULL; +SHELL_MAP_LIST gShellMapList; +SHELL_MAP_LIST *gShellCurDir = NULL; + +CONST CHAR16* SupportLevel[] = { + L"Minimal", + L"Scripting", + L"Basic", + L"Interactive" +}; + +/** + Function to make sure that the global protocol pointers are valid. + must be called after constructor before accessing the pointers. +**/ +EFI_STATUS +EFIAPI +CommandInit( + VOID + ) +{ + EFI_STATUS Status; + if (gEfiShellParametersProtocol == NULL) { + Status = gBS->OpenProtocol(gImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **)&gEfiShellParametersProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + return (EFI_DEVICE_ERROR); + } + } + if (gEfiShellProtocol == NULL) { + Status = gBS->LocateProtocol(&gEfiShellProtocolGuid, NULL, (VOID**)&gEfiShellProtocol); + if (EFI_ERROR(Status)) { + return (EFI_DEVICE_ERROR); + } + } + if (gUnicodeCollation == NULL) { + Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation); + if (EFI_ERROR(Status)) { + return (EFI_DEVICE_ERROR); + } + } + if (gDevPathToText == NULL) { + Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDevPathToText); + if (EFI_ERROR(Status)) { + return (EFI_DEVICE_ERROR); + } + } + return (EFI_SUCCESS); +} + +/** + Constructor for the Shell Command library. + + Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the initialization was complete sucessfully +**/ +RETURN_STATUS +EFIAPI +ShellCommandLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + InitializeListHead(&gShellMapList.Link); + InitializeListHead(&mCommandList.Link); + InitializeListHead(&mAliasList.Link); + InitializeListHead(&mScriptList.Link); + InitializeListHead(&mFileHandleList.Link); + mEchoState = TRUE; + + mExitRequested = FALSE; + mExitScript = FALSE; + mProfileListSize = 0; + mProfileList = NULL; + + if (gUnicodeCollation == NULL) { + Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation); + if (EFI_ERROR(Status)) { + return (EFI_DEVICE_ERROR); + } + } + + return (RETURN_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval RETURN_SUCCESS this function always returns success +**/ +RETURN_STATUS +EFIAPI +ShellCommandLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + COMMAND_LIST *Node2; + SCRIPT_FILE_LIST *Node3; + SHELL_MAP_LIST *MapNode; + // + // enumerate throught the list and free all the memory + // + while (!IsListEmpty (&mCommandList.Link)) { + Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link); + RemoveEntryList(&Node->Link); + SHELL_FREE_NON_NULL(Node->CommandString); + FreePool(Node); + DEBUG_CODE(Node = NULL;); + } + + // + // enumerate through the init command list and free all memory + // + while (!IsListEmpty (&mAliasList.Link)) { + Node2 = (COMMAND_LIST *)GetFirstNode(&mAliasList.Link); + RemoveEntryList(&Node2->Link); + SHELL_FREE_NON_NULL(Node2->CommandString); + FreePool(Node2); + DEBUG_CODE(Node2 = NULL;); + } + + // + // enumerate throught the list and free all the memory + // + while (!IsListEmpty (&mScriptList.Link)) { + Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link); + RemoveEntryList(&Node3->Link); + DeleteScriptFileStruct(Node3->Data); + FreePool(Node3); + } + + // + // enumerate throught the mappings list and free all the memory + // + if (!IsListEmpty(&gShellMapList.Link)) { + for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsListEmpty (&gShellMapList.Link) + ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ){ + ASSERT(MapNode != NULL); + RemoveEntryList(&MapNode->Link); + SHELL_FREE_NON_NULL(MapNode->DevicePath); + SHELL_FREE_NON_NULL(MapNode->MapName); + SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath); + FreePool(MapNode); + } + } + if (!IsListEmpty(&mFileHandleList.Link)){ + FreeBufferList(&mFileHandleList); + } + + if (mProfileList != NULL) { + FreePool(mProfileList); + } + + return (RETURN_SUCCESS); +} + +/** + Checks if a command is already on the list. + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnList ( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameter + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (TRUE); + } + } + return (FALSE); +} + +/** + Get the help text for a command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return String of help text. Caller reuiqred to free. +**/ +CHAR16* +EFIAPI +ShellCommandGetCommandHelp ( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameter + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL)); + } + } + return (NULL); +} + +/** + Registers handlers of type SHELL_RUN_COMMAND and + SHELL_GET_MAN_FILENAME for each shell command. + + If the ShellSupportLevel is greater than the value of the + PcdShellSupportLevel then return RETURN_UNSUPPORTED. + + Registers the handlers specified by GetHelpInfoHandler and CommandHandler + with the command specified by CommandString. If the command named by + CommandString has already been registered, then return + RETURN_ALREADY_STARTED. + + If there are not enough resources available to register the handlers then + RETURN_OUT_OF_RESOURCES is returned. + + If CommandString is NULL, then ASSERT(). + If GetHelpInfoHandler is NULL, then ASSERT(). + If CommandHandler is NULL, then ASSERT(). + If ProfileName is NULL, then ASSERT(). + + @param[in] CommandString Pointer to the command name. This is the + name to look for on the command line in + the shell. + @param[in] CommandHandler Pointer to a function that runs the + specified command. + @param[in] GetManFileName Pointer to a function that provides man + filename. + @param[in] ShellMinSupportLevel minimum Shell Support Level which has this + function. + @param[in] ProfileName profile name to require for support of this + function. + @param[in] CanAffectLE indicates whether this command's return value + can change the LASTERROR environment variable. + @param[in] HiiHandle Handle of this command's HII entry. + @param[in] ManFormatHelp HII locator for the help text. + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. + @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the + currently allowed support level. + @retval RETURN_ALREADY_STARTED The CommandString represents a command that + is already registered. Only 1 handler set for + a given command is allowed. + @sa SHELL_GET_MAN_FILENAME + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterCommandName ( + IN CONST CHAR16 *CommandString, + IN SHELL_RUN_COMMAND CommandHandler, + IN SHELL_GET_MAN_FILENAME GetManFileName, + IN UINT32 ShellMinSupportLevel, + IN CONST CHAR16 *ProfileName, + IN CONST BOOLEAN CanAffectLE, + IN CONST EFI_HANDLE HiiHandle, + IN CONST EFI_STRING_ID ManFormatHelp + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // ASSERTs for NULL parameters + // + ASSERT(CommandString != NULL); + ASSERT(GetManFileName != NULL); + ASSERT(CommandHandler != NULL); + ASSERT(ProfileName != NULL); + + // + // check for shell support level + // + if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) { + return (RETURN_UNSUPPORTED); + } + + // + // check for already on the list + // + if (ShellCommandIsCommandOnList(CommandString)) { + return (RETURN_ALREADY_STARTED); + } + + // + // allocate memory for new struct + // + Node = AllocatePool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY)); + ASSERT(Node != NULL); + Node->CommandString = AllocatePool(StrSize(CommandString)); + ASSERT(Node->CommandString != NULL); + + // + // populate the new struct + // + StrCpy(Node->CommandString, CommandString); + + Node->GetManFileName = GetManFileName; + Node->CommandHandler = CommandHandler; + Node->LastError = CanAffectLE; + Node->HiiHandle = HiiHandle; + Node->ManFormatHelp = ManFormatHelp; + + if ( StrLen(ProfileName)>0 + && ((mProfileList != NULL + && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL) + ){ + ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL)); + if (mProfileList == NULL) { + // + // If this is the first make a leading ';' + // + StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0); + } + StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0); + StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0); + } + + // + // add the new struct to the list + // + InsertTailList (&mCommandList.Link, &Node->Link); + + return (RETURN_SUCCESS); +} + +/** + Function to get the current Profile string. + + @retval NULL There are no installed profiles. + @return A semi-colon delimited list of profiles. +**/ +CONST CHAR16 * +EFIAPI +ShellCommandGetProfileList ( + VOID + ) +{ + return (mProfileList); +} + +/** + Checks if a command string has been registered for CommandString and if so it runs + the previously registered handler for that command with the command line. + + If CommandString is NULL, then ASSERT(). + + If Sections is specified, then each section name listed will be compared in a casesensitive + manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists, + it will be appended to the returned help text. If the section does not exist, no + information will be returned. If Sections is NULL, then all help text information + available will be returned. + + @param Sections pointer to string representing which section to get help on. + + @param[in] CommandString Pointer to the command name. This is the name + found on the command line in the shell. + @param[in,out] RetVal Pointer to the return vaule from the command handler. + + @param[in,out] CanAffectLE indicates whether this command's return value + needs to be placed into LASTERROR environment variable. + + @retval RETURN_SUCCESS The handler was run. + @retval RETURN_NOT_FOUND The CommandString did not match a registered + command name. + @sa SHELL_RUN_COMMAND +**/ +RETURN_STATUS +EFIAPI +ShellCommandRunCommandHandler ( + IN CONST CHAR16 *CommandString, + IN OUT SHELL_STATUS *RetVal, + IN OUT BOOLEAN *CanAffectLE OPTIONAL + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameters + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + if (CanAffectLE != NULL) { + *CanAffectLE = Node->LastError; + } + if (RetVal != NULL) { + *RetVal = Node->CommandHandler(NULL, gST); + } else { + Node->CommandHandler(NULL, gST); + } + return (RETURN_SUCCESS); + } + } + return (RETURN_NOT_FOUND); +} + +/** + Checks if a command string has been registered for CommandString and if so it + returns the MAN filename specified for that command. + + If CommandString is NULL, then ASSERT(). + + @param[in] CommandString Pointer to the command name. This is the name + found on the command line in the shell.\ + + @retval NULL the commandString was not a registered command. + @return other the name of the MAN file. + @sa SHELL_GET_MAN_FILENAME +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameHandler ( + IN CONST CHAR16 *CommandString + ) +{ + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + + // + // assert for NULL parameters + // + ASSERT(CommandString != NULL); + + // + // check for the command + // + for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link) + ; !IsNull(&mCommandList.Link, &Node->Link) + ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + Node->CommandString) == 0 + ){ + return (Node->GetManFileName()); + } + } + return (NULL); +} + +/** + Get the list of all available shell internal commands. This is a linked list + (via LIST_ENTRY structure). enumerate through it using the BaseLib linked + list functions. do not modify the values. + + @return a Linked list of all available shell commands. +**/ +CONST COMMAND_LIST* +EFIAPI +ShellCommandGetCommandList ( + ) +{ + return ((COMMAND_LIST*)(&mCommandList)); +} + +/** + Registers aliases to be set as part of the initialization of the shell application. + + If Command is NULL, then ASSERT(). + If Alias is NULL, then ASSERT(). + + @param[in] Command Pointer to the Command + @param[in] Alias Pointer to Alias + + @retval RETURN_SUCCESS The handlers were registered. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to + register the shell command. +**/ +RETURN_STATUS +EFIAPI +ShellCommandRegisterAlias ( + IN CONST CHAR16 *Command, + IN CONST CHAR16 *Alias + ) +{ + ALIAS_LIST *Node; + + // + // Asserts for NULL + // + ASSERT(Command != NULL); + ASSERT(Alias != NULL); + + // + // allocate memory for new struct + // + Node = AllocatePool(sizeof(ALIAS_LIST)); + ASSERT(Node != NULL); + Node->CommandString = AllocatePool(StrSize(Command)); + Node->Alias = AllocatePool(StrSize(Alias)); + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + + // + // populate the new struct + // + StrCpy(Node->CommandString, Command); + StrCpy(Node->Alias , Alias ); + + // + // add the new struct to the list + // + InsertTailList (&mAliasList.Link, &Node->Link); + + return (RETURN_SUCCESS); +} + +/** + Get the list of all shell alias commands. This is a linked list + (via LIST_ENTRY structure). enumerate through it using the BaseLib linked + list functions. do not modify the values. + + @return a Linked list of all requested shell alias'. +**/ +CONST ALIAS_LIST* +EFIAPI +ShellCommandGetInitAliasList ( + VOID + ) +{ + return (&mAliasList); +} + +/** + Determine if a given alias is on the list of built in alias' + + @param[in] Alias The alias to test for + + @retval TRUE The alias is a built in alias + @retval FALSE The alias is not a built in alias +**/ +BOOLEAN +EFIAPI +ShellCommandIsOnAliasList( + IN CONST CHAR16 *Alias + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link) + ; !IsNull(&mAliasList.Link, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Alias, + Node->CommandString) == 0 + ){ + return (TRUE); + } + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Alias, + Node->Alias) == 0 + ){ + return (TRUE); + } + } + return (FALSE); +} + +/** + Function to determine current state of ECHO. Echo determins if lines from scripts + and ECHO commands are enabled. + + @retval TRUE Echo is currently enabled + @retval FALSE Echo is currently disabled +**/ +BOOLEAN +EFIAPI +ShellCommandGetEchoState( + VOID + ) +{ + return (mEchoState); +} + +/** + Function to set current state of ECHO. Echo determins if lines from scripts + and ECHO commands are enabled. + + If State is TRUE, Echo will be enabled. + If State is FALSE, Echo will be disabled. +**/ +VOID +EFIAPI +ShellCommandSetEchoState( + IN BOOLEAN State + ) +{ + mEchoState = State; +} + +/** + Indicate that the current shell or script should exit. + + @param[in] ScriptOnly TRUE if only exiting a script, FALSE othrwise. +**/ +VOID +EFIAPI +ShellCommandRegisterExit ( + IN BOOLEAN ScriptOnly + ) +{ + mExitRequested = (BOOLEAN)(!mExitRequested); + if (mExitRequested) { + mExitScript = ScriptOnly; + } else { + mExitScript = FALSE; + } +} + +/** + Retrieve the Exit indicator. + + @retval TRUE Exit was indicated. + @retval FALSE Exis was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetExit ( + VOID + ) +{ + return (mExitRequested); +} + +/** + Retrieve the Exit script indicator. + + If ShellCommandGetExit returns FALSE than the return from this is undefined. + + @retval TRUE ScriptOnly was indicated. + @retval FALSE ScriptOnly was not indicated. +**/ +BOOLEAN +EFIAPI +ShellCommandGetScriptExit ( + VOID + ) +{ + return (mExitScript); +} + +/** + Function to cleanup all memory from a SCRIPT_FILE structure. + + @param[in] Script The pointer to the structure to cleanup. +**/ +VOID +EFIAPI +DeleteScriptFileStruct ( + IN SCRIPT_FILE *Script + ) +{ + UINT8 LoopVar; + ASSERT(Script != NULL); + ASSERT(Script->ScriptName != NULL); + for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) { + FreePool(Script->Argv[LoopVar]); + } + if (Script->Argv != NULL) { + FreePool(Script->Argv); + } + Script->CurrentCommand = NULL; + while (!IsListEmpty (&Script->CommandList)) { + Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList); + if (Script->CurrentCommand != NULL) { + RemoveEntryList(&Script->CurrentCommand->Link); + if (Script->CurrentCommand->Cl != NULL) { + FreePool(Script->CurrentCommand->Cl); + } + if (Script->CurrentCommand->Data != NULL) { + FreePool(Script->CurrentCommand->Data); + } + FreePool(Script->CurrentCommand); + } + } + FreePool(Script->ScriptName); + FreePool(Script); +} + +/** + Function to return a pointer to the currently running script file object. + + @retval NULL A script file is not currently running. + @return A pointer to the current script file object. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandGetCurrentScriptFile ( + VOID + ) +{ + SCRIPT_FILE_LIST *List; + if (IsListEmpty (&mScriptList.Link)) { + return (NULL); + } + List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link)); + return (List->Data); +} + +/** + Function to set a new script as the currently running one. + + This function will correctly stack and unstack nested scripts. + + @param[in] Script Pointer to new script information structure. if NULL + will remove and de-allocate the top-most Script structure. + + @return A pointer to the current running script file after this + change. NULL if removing the final script. +**/ +SCRIPT_FILE* +EFIAPI +ShellCommandSetNewScript ( + IN SCRIPT_FILE *Script OPTIONAL + ) +{ + SCRIPT_FILE_LIST *Node; + if (Script == NULL) { + if (IsListEmpty (&mScriptList.Link)) { + ASSERT(FALSE); + return (NULL); + } + Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link); + RemoveEntryList(&Node->Link); + DeleteScriptFileStruct(Node->Data); + FreePool(Node); + } else { + Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST)); + Node->Data = Script; + InsertHeadList(&mScriptList.Link, &Node->Link); + } + return (ShellCommandGetCurrentScriptFile()); +} + +/** + Function to generate the next default mapping name. + + If the return value is not NULL then it must be callee freed. + + @param Type What kind of mapping name to make. + + @retval NULL a memory allocation failed. + @return a new map name string +**/ +CHAR16* +EFIAPI +ShellCommandCreateNewMappingName( + IN CONST SHELL_MAPPING_TYPE Type + ) +{ + CHAR16 *String; + ASSERT(Type < MappingTypeMax); + + String = NULL; + + String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0])); + UnicodeSPrint( + String, + PcdGet8(PcdShellMapNameLength) * sizeof(String[0]), + Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:", + Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++); + + return (String); +} + +/** + Function to add a map node to the list of map items and update the "path" environment variable (optionally). + + If Path is TRUE (during initialization only), the path environment variable will also be updated to include + default paths on the new map name... + + Path should be FALSE when this function is called from the protocol SetMap function. + + @param[in] Name The human readable mapped name. + @param[in] DevicePath The Device Path for this map. + @param[in] Flags The Flags attribute for this map item. + @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization). + + @retval EFI_SUCCESS The addition was sucessful. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. +**/ +EFI_STATUS +EFIAPI +ShellCommandAddMapItemAndUpdatePath( + IN CONST CHAR16 *Name, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CONST UINT64 Flags, + IN CONST BOOLEAN Path + ) +{ + EFI_STATUS Status; + SHELL_MAP_LIST *MapListNode; + CONST CHAR16 *OriginalPath; + CHAR16 *NewPath; + UINTN NewPathSize; + + NewPathSize = 0; + NewPath = NULL; + OriginalPath = NULL; + Status = EFI_SUCCESS; + + MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST)); + if (MapListNode == NULL) { + Status = EFI_OUT_OF_RESOURCES; + } else { + MapListNode->Flags = Flags; + MapListNode->MapName = AllocateZeroPool(StrSize(Name)); + MapListNode->DevicePath = DuplicateDevicePath(DevicePath); + if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){ + Status = EFI_OUT_OF_RESOURCES; + } else { + StrCpy(MapListNode->MapName, Name); + InsertTailList(&gShellMapList.Link, &MapListNode->Link); + } + } + if (EFI_ERROR(Status)) { + if (MapListNode != NULL) { + if (MapListNode->DevicePath != NULL) { + FreePool(MapListNode->DevicePath); + } + if (MapListNode->MapName != NULL) { + FreePool(MapListNode->MapName); + } + FreePool(MapListNode); + } + } else if (Path) { + // + // Since there was no error and Path was TRUE + // Now add the correct path for that mapping + // + OriginalPath = gEfiShellProtocol->GetEnv(L"path"); + ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL)); + if (OriginalPath != NULL) { + StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0); + } else { + StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0); + } + StrnCatGrow(&NewPath, &NewPathSize, L";", 0); + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0); + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0); + StrnCatGrow(&NewPath, &NewPathSize, Name, 0); + StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0); + + Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE); + ASSERT_EFI_ERROR(Status); + FreePool(NewPath); + } + return (Status); +} + +/** + Creates the default map names for each device path in the system with + a protocol depending on the Type. + + Creates the consistent map names for each device path in the system with + a protocol depending on the Type. + + Note: This will reset all mappings in the system("map -r"). + + Also sets up the default path environment variable if Type is FileSystem. + + @retval EFI_SUCCESS All map names were created sucessfully. + @retval EFI_NOT_FOUND No protocols were found in the system. + @return Error returned from gBS->LocateHandle(). + + @sa LocateHandle +**/ +EFI_STATUS +EFIAPI +ShellCommandCreateInitialMappingsAndPaths( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleList; + UINTN Count; + EFI_DEVICE_PATH_PROTOCOL **DevicePathList; + CHAR16 *NewDefaultName; + CHAR16 *NewConsistName; + EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable; + SHELL_MAP_LIST *MapListNode; + + HandleList = NULL; + + // + // Reset the static members back to zero + // + mFsMaxCount = 0; + mBlkMaxCount = 0; + + gEfiShellProtocol->SetEnv(L"path", L"", TRUE); + + // + // First empty out the existing list. + // + if (!IsListEmpty(&gShellMapList.Link)) { + for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ; !IsListEmpty(&gShellMapList.Link) + ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) + ){ + RemoveEntryList(&MapListNode->Link); + FreePool(MapListNode); + } // for loop + } + + // + // Find each handle with Simple File System + // + HandleList = GetHandleListByPotocol(&gEfiSimpleFileSystemProtocolGuid); + if (HandleList != NULL) { + // + // Do a count of the handles + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocatePool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + ASSERT(DevicePathList != NULL); + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + ShellCommandConsistMappingInitialize(&ConsistMappingTable); + // + // Assign new Mappings to all... + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + // + // Get default name first + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem); + ASSERT(NewDefaultName != NULL); + Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE); + ASSERT_EFI_ERROR(Status); + FreePool(NewDefaultName); + + // + // Now do consistent name + // + NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable); + if (NewConsistName != NULL) { + Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE); + ASSERT_EFI_ERROR(Status); + FreePool(NewConsistName); + } + } + + ShellCommandConsistMappingUnInitialize(ConsistMappingTable); + + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + + HandleList = NULL; + } else { + Count = (UINTN)-1; + } + + // + // Find each handle with Block Io + // + HandleList = GetHandleListByPotocol(&gEfiBlockIoProtocolGuid); + if (HandleList != NULL) { + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocatePool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + ASSERT(DevicePathList != NULL); + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + // + // Assign new Mappings to all... + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + // + // Get default name first + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo); + ASSERT(NewDefaultName != NULL); + Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE); + ASSERT_EFI_ERROR(Status); + FreePool(NewDefaultName); + } + + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + } else if (Count == (UINTN)-1) { + return (EFI_NOT_FOUND); + } + + return (EFI_SUCCESS); +} + +CHAR16* +EFIAPI +ShellCommandCleanPath ( + IN OUT CHAR16 *Path + ) +{ + CHAR16 *Path2; + + for (Path2 = Path ; Path2 != NULL && *Path2 != CHAR_NULL ; Path2++) { + if (*Path2 == L'/') { + *Path2 = L'\\'; + } + } + + return (Path); +} + +/** + Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*. + + @param[in] Handle The SHELL_FILE_HANDLE to convert. + + @return a EFI_FILE_PROTOCOL* representing the same file. +**/ +EFI_FILE_PROTOCOL* +EFIAPI +ConvertShellHandleToEfiFileProtocol( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + return ((EFI_FILE_PROTOCOL*)(Handle)); +} + +/** + Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE. + + @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert. + @param[in] Path The path to the file for verification. + + @return a SHELL_FILE_HANDLE representing the same file. +**/ +SHELL_FILE_HANDLE +EFIAPI +ConvertEfiFileProtocolToShellHandle( + IN CONST EFI_FILE_PROTOCOL *Handle, + IN CONST CHAR16 *Path + ) +{ + SHELL_COMMAND_FILE_HANDLE *Buffer; + BUFFER_LIST *NewNode; + + if (Path != NULL) { + Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE)); + ASSERT(Buffer != NULL); + NewNode = AllocatePool(sizeof(BUFFER_LIST)); + ASSERT(NewNode != NULL); + Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle; + Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0); + NewNode->Buffer = Buffer; + + InsertHeadList(&mFileHandleList.Link, &NewNode->Link); + } + return ((SHELL_FILE_HANDLE)(Handle)); +} + +/** + Find the path that was logged with the specified SHELL_FILE_HANDLE. + + @param[in] Handle The SHELL_FILE_HANDLE to query on. + + @return A pointer to the path for the file. +**/ +CONST CHAR16* +EFIAPI +ShellFileHandleGetPath( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + BUFFER_LIST *Node; + + for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link) + ; !IsNull(&mFileHandleList.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link) + ){ + if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){ + return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path); + } + } + return (NULL); +} + +/** + Remove a SHELL_FILE_HANDLE frmo the list of SHELL_FILE_HANDLES. + + @param[in] Handle The SHELL_FILE_HANDLE to remove. + + @retval TRUE The item was removed. + @retval FALSE The item was not found. +**/ +BOOLEAN +EFIAPI +ShellFileHandleRemove( + IN CONST SHELL_FILE_HANDLE Handle + ) +{ + BUFFER_LIST *Node; + + for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link) + ; !IsNull(&mFileHandleList.Link, &Node->Link) + ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link) + ){ + if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){ + SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path); + RemoveEntryList(&Node->Link); + return (TRUE); + } + } + return (FALSE); +} + +/** + Function to determine if a SHELL_FILE_HANDLE is at the end of the file. + + This will NOT work on directories. + + If Handle is NULL, then ASSERT. + + @param[in] Handle the file handle + + @retval TRUE the position is at the end of the file + @retval FALSE the position is not at the end of the file +**/ +BOOLEAN +EFIAPI +ShellFileHandleEof( + IN SHELL_FILE_HANDLE Handle + ) +{ + EFI_FILE_INFO *Info; + UINT64 Pos; + BOOLEAN RetVal; + + // + // ASSERT if Handle is NULL + // + ASSERT(Handle != NULL); + + gEfiShellProtocol->GetFilePosition(Handle, &Pos); + Info = gEfiShellProtocol->GetFileInfo (Handle); + ASSERT(Info != NULL); + gEfiShellProtocol->SetFilePosition(Handle, Pos); + + if (Info == NULL) { + return (FALSE); + } + + if (Pos == Info->FileSize) { + RetVal = TRUE; + } else { + RetVal = FALSE; + } + + FreePool (Info); + + return (RetVal); +} + +/** + Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned + buffer. The returned buffer must be callee freed. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in,out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @return The line of text from the file. + + @sa ShellFileHandleReadLine +**/ +CHAR16* +EFIAPI +ShellFileHandleReturnLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT BOOLEAN *Ascii + ) +{ + CHAR16 *RetVal; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + RetVal = NULL; + + Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii); + if (Status == EFI_BUFFER_TOO_SMALL) { + RetVal = AllocatePool(Size); + Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii); + } + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status) && (RetVal != NULL)) { + FreePool(RetVal); + RetVal = NULL; + } + return (RetVal); +} + +/** + Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in,out] Buffer The pointer to buffer to read into. + @param[in,out] Size The pointer to number of bytes in Buffer. + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + + @param[in,out] Ascii Boolean value for indicating whether the file is + Ascii (TRUE) or UCS2 (FALSE). + + @retval EFI_SUCCESS The operation was successful. The line is stored in + Buffer. + @retval EFI_INVALID_PARAMETER Handle was NULL. + @retval EFI_INVALID_PARAMETER Size was NULL. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. + @sa ShellFileHandleRead +**/ +EFI_STATUS +EFIAPI +ShellFileHandleReadLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT CHAR16 *Buffer, + IN OUT UINTN *Size, + IN BOOLEAN Truncate, + IN OUT BOOLEAN *Ascii + ) +{ + EFI_STATUS Status; + CHAR16 CharBuffer; + UINTN CharSize; + UINTN CountSoFar; + UINT64 OriginalFilePosition; + + + if (Handle == NULL + ||Size == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + if (Buffer == NULL) { + ASSERT(*Size == 0); + } else { + *Buffer = CHAR_NULL; + } + gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition); + if (OriginalFilePosition == 0) { + CharSize = sizeof(CHAR16); + Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer); + ASSERT_EFI_ERROR(Status); + if (CharBuffer == UnicodeFileTag) { + *Ascii = FALSE; + } else { + *Ascii = TRUE; + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + } + } + + for (CountSoFar = 0;;CountSoFar++){ + CharBuffer = 0; + if (*Ascii) { + CharSize = sizeof(CHAR8); + } else { + CharSize = sizeof(CHAR16); + } + Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer); + if ( EFI_ERROR(Status) + || CharSize == 0 + || (CharBuffer == L'\n' && !(*Ascii)) + || (CharBuffer == '\n' && *Ascii) + ){ + break; + } + // + // if we have space save it... + // + if ((CountSoFar+1)*sizeof(CHAR16) < *Size){ + ASSERT(Buffer != NULL); + ((CHAR16*)Buffer)[CountSoFar] = CharBuffer; + ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL; + } + } + + // + // if we ran out of space tell when... + // + if ((CountSoFar+1)*sizeof(CHAR16) > *Size){ + *Size = (CountSoFar+1)*sizeof(CHAR16); + if (!Truncate) { + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + } else { + DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine")); + } + return (EFI_BUFFER_TOO_SMALL); + } + while(Buffer[StrLen(Buffer)-1] == L'\r') { + Buffer[StrLen(Buffer)-1] = CHAR_NULL; + } + + return (Status); +} +/** + Frees any BUFFER_LIST defined type. +**/ +VOID +EFIAPI +FreeBufferList ( + IN BUFFER_LIST *List + ) +{ + BUFFER_LIST *BufferListEntry; + + if (List == NULL){ + return; + } + // + // enumerate through the buffer list and free all memory + // + for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link) + ; !IsListEmpty (&List->Link) + ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link) + ){ + RemoveEntryList(&BufferListEntry->Link); + ASSERT(BufferListEntry->Buffer != NULL); + if (BufferListEntry->Buffer != NULL) { + FreePool(BufferListEntry->Buffer); + } + FreePool(BufferListEntry); + } +} + +/** + Chops off last directory or file entry in a path leaving the trailing slash + + @param[in,out] Path + + @retval FALSE No directory was found to chop off. + @retval TRUE A directory was chopped off. +**/ +BOOLEAN +EFIAPI +ChopLastSlash( + IN OUT CHAR16 *PathToReturn + ) +{ + CHAR16 *Walker; + CHAR16 *LastSlash = NULL; + // + // get directory name from path... ('chop' off extra) + // + for ( Walker = PathToReturn + ; Walker != NULL && *Walker != CHAR_NULL + ; Walker++ + ){ + if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) { + LastSlash = Walker+1; + } + } + if (LastSlash != NULL) { + *LastSlash = CHAR_NULL; + return (TRUE); + } + return (FALSE); +} + diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h new file mode 100644 index 0000000000..431eb53f9d --- /dev/null +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.h @@ -0,0 +1,79 @@ +/** @file + Provides interface to shell internal functions for shell commands. + + Copyright (c) 2006 - 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 _UEFI_COMMAND_LIB_INTERNAL_HEADER_ +#define _UEFI_COMMAND_LIB_INTERNAL_HEADER_ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct{ + LIST_ENTRY Link; + CHAR16 *CommandString; + SHELL_GET_MAN_FILENAME GetManFileName; + SHELL_RUN_COMMAND CommandHandler; + BOOLEAN LastError; + EFI_HANDLE HiiHandle; + EFI_STRING_ID ManFormatHelp; +} SHELL_COMMAND_INTERNAL_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + SCRIPT_FILE *Data; +} SCRIPT_FILE_LIST; + +/** + Function to cleanup all memory from a SCRIPT_FILE structure. + + @param[in] Script The pointer to the structure to cleanup. +**/ +VOID +EFIAPI +DeleteScriptFileStruct ( + IN SCRIPT_FILE *Script + ); + +typedef struct { + EFI_FILE_PROTOCOL *FileHandle; + CHAR16 *Path; +} SHELL_COMMAND_FILE_HANDLE; + + +#endif //_UEFI_COMMAND_LIB_INTERNAL_HEADER_ + diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf new file mode 100644 index 0000000000..3c3573ffc5 --- /dev/null +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf @@ -0,0 +1,61 @@ +## @file +# Provides interface to shell internal functions for shell commands. +# +# Copyright (c) 2006 - 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. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellCommandLib + FILE_GUID = 5C12F31F-EBAC-466e-A400-FCA8C9EA3A05 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = ShellCommandLib|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellCommandLibConstructor + DESTRUCTOR = ShellCommandLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + UefiShellCommandLib.c + UefiShellCommandLib.h + ConsistMapping.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + PrintLib + UefiBootServicesTableLib + ShellLib + HiiLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED + gEfiShellProtocolGuid # ALWAYS_CONSUMED + gEfiShellParametersProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED + +[Guids] + + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel ## ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellMapNameLength ## ALWAYS_CONSUMED diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.uni b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.uni new file mode 100644 index 0000000000..4b65ec7dc3 Binary files /dev/null and b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.uni differ diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c b/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c new file mode 100644 index 0000000000..55bdf21efe --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c @@ -0,0 +1,273 @@ +/** @file + Main file for connect shell Driver1 function. + + 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 "UefiShellDriver1CommandsLib.h" +#include +#include +#include + +EFI_STATUS +EFIAPI +ConnectControllers ( + IN CONST EFI_HANDLE ControllerHandle, + IN CONST EFI_HANDLE DriverHandle, + IN CONST BOOLEAN Recursive, + IN CONST BOOLEAN Output + ){ + EFI_STATUS Status; + EFI_HANDLE *ControllerHandleList; + EFI_HANDLE *DriverHandleList; + EFI_HANDLE *HandleWalker; + + ControllerHandleList = NULL; + Status = EFI_NOT_FOUND; + + // + // If we have a single handle to connect make that a 'list' + // + if (DriverHandle == NULL) { + DriverHandleList = NULL; + } else { + DriverHandleList = AllocatePool(2*sizeof(EFI_HANDLE)); + DriverHandleList[0] = DriverHandle; + DriverHandleList[1] = NULL; + } + + // + // do we connect all controllers (with a loop) or a single one... + // This is where we call the gBS->ConnectController function. + // + if (ControllerHandle == NULL) { + ControllerHandleList = GetHandleListByPotocol(&gEfiDevicePathProtocolGuid); + for (HandleWalker = ControllerHandleList + ; HandleWalker != NULL && *HandleWalker != NULL + ; HandleWalker++ + ){ + Status = gBS->ConnectController(*HandleWalker, DriverHandleList, NULL, Recursive); + if (Output) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_CON_RESULT), gShellDriver1HiiHandle, *HandleWalker, Status); + } + } + } else { + Status = gBS->ConnectController(ControllerHandle, DriverHandleList, NULL, Recursive); + ASSERT(Output == FALSE); + } + + // + // Free any memory we allocated. + // + if (ControllerHandleList != NULL) { + FreePool(ControllerHandleList); + } + if (DriverHandleList != NULL) { + FreePool(DriverHandleList); + } + return (Status); +} + +EFI_STATUS +EFIAPI +ConnectFromDevPaths ( + IN CONST CHAR16 *Key + ){ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathWalker; + UINTN Length; + EFI_HANDLE Handle; + EFI_STATUS Status; + + DevPath = NULL; + Length = 0; + + // + // Get the DevicePath buffer from the variable... + // + Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath); + if (Status == EFI_BUFFER_TOO_SMALL) { + DevPath = AllocatePool(Length); + Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath); + } + + // + // walk the list of devices and connect them + // + for (DevPathWalker = DevPath + ; DevPathWalker < (DevPath + Length) && !EFI_ERROR(Status) && DevPath != NULL + ; DevPathWalker += GetDevicePathSize(DevPathWalker) + ){ + // + // get the correct handle from a given device path + // + if (StrCmp(Key, L"ConInDev") == 0) { + Status = gBS->LocateDevicePath((EFI_GUID*)&gEfiConsoleInDeviceGuid, &DevPathWalker, &Handle); + } else if (StrCmp(Key, L"ConOutDev") == 0) { + Status = gBS->LocateDevicePath((EFI_GUID*)&gEfiConsoleOutDeviceGuid, &DevPathWalker, &Handle); + } else { + Handle = NULL; + Status = EFI_INVALID_PARAMETER; + ASSERT(FALSE); + } + if (!EFI_ERROR(Status)) { + Status = ConnectControllers(Handle, NULL, FALSE, FALSE); + } + } + + if (DevPath != NULL) { + FreePool(DevPath); + } + return (Status); +} + +EFI_STATUS +EFIAPI +ConvertAndConnectControllers ( + IN CONST CHAR16 *StringHandle1, + IN CONST CHAR16 *StringHandle2 OPTIONAL, + IN CONST BOOLEAN Recursive, + IN CONST BOOLEAN Output + ){ + EFI_HANDLE Handle1; + EFI_HANDLE Handle2; + + // + // Convert the command line parameters to HANDLES. They must be in HEX according to spec. + // + if (StringHandle1 != NULL) { + Handle1 = (EFI_HANDLE)StrHexToUintn(StringHandle1); + } else { + Handle1 = NULL; + } + if (StringHandle2 != NULL) { + Handle2 = (EFI_HANDLE)StrHexToUintn(StringHandle2); + } else { + Handle2 = NULL; + } + + // + // if only one is NULL verify it's the proper one... + // + if ( (Handle1 == NULL && Handle2 != NULL) + || (Handle1 != NULL && Handle2 == NULL) + ){ + // + // Figure out which one should be NULL and move the handle to the right place. + // If Handle1 is NULL then test Handle2 and vise versa. + // The one that DOES has driver binding must be Handle2 + // + if (Handle1 == NULL) { + if (EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + // swap + Handle1 = Handle2; + Handle2 = NULL; + } else { + // We're all good... + } + } else { + if (EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) { + // We're all good... + } else { + // swap + Handle2 = Handle1; + Handle1 = NULL; + } + } + } + + return (ConnectControllers(Handle1, Handle2, Recursive, Output)); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-c", TypeFlag}, + {L"-r", TypeFlag}, + {NULL, TypeMax} + }; + +SHELL_STATUS +EFIAPI +ShellCommandRunConnect ( + VOID *RESERVED + ) { + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if EFI_ERROR(Status) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters + // + if ((ShellCommandLineGetCount() > 3) + ||((ShellCommandLineGetFlag(Package, L"-r") != FALSE || ShellCommandLineGetFlag(Package, L"-c") != FALSE) && ShellCommandLineGetCount()!=0) + ){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-c") != FALSE) { + // + // do the conin and conout from EFI variables + // if the first fails dont 'loose' the error + // + Status = ConnectFromDevPaths(L"ConInDev"); + if (EFI_ERROR(Status)) { + ConnectFromDevPaths(L"ConOutDev"); + } else { + Status = ConnectFromDevPaths(L"ConOutDev"); + } + ShellStatus = Status & (~MAX_BIT); + } else { + // + // 0, 1, or 2 specific handles and possibly recursive + // + if (ShellCommandLineGetRawValue(Package, 1) != NULL && CommandLibGetHandleValue(StrHexToUintn(ShellCommandLineGetRawValue(Package, 1))) == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL && CommandLibGetHandleValue(StrHexToUintn(ShellCommandLineGetRawValue(Package, 2))) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, ShellCommandLineGetRawValue(Package, 2)); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ConvertAndConnectControllers(ShellCommandLineGetRawValue(Package, 1), ShellCommandLineGetRawValue(Package, 2), ShellCommandLineGetFlag(Package, L"-r"), (BOOLEAN)(ShellCommandLineGetCount()!=0)); + ShellStatus = Status & (~MAX_BIT); + } + } + + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c b/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c new file mode 100644 index 0000000000..485458f25c --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/Devices.c @@ -0,0 +1,164 @@ +/** @file + Main file for devices shell Driver1 function. + + 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 "UefiShellDriver1CommandsLib.h" + +EFI_STATUS +EFIAPI +GetDeviceHandleInfo ( + IN EFI_HANDLE TheHandle, + IN CHAR16 *Type, + IN BOOLEAN *Cfg, + IN BOOLEAN *Diag, + IN UINT8 *Parents, + IN UINT8 *Devices, + IN UINT8 *Children, + OUT CHAR16 **Name, + IN CONST CHAR8 *Language + ){ + *Name = NULL; + + gEfiShellProtocol->GetDeviceName(TheHandle, EFI_DEVICE_NAME_USE_COMPONENT_NAME|EFI_DEVICE_NAME_USE_DEVICE_PATH, (CHAR8*)Language, Name); + + + + + + + + + + + + + + return (EFI_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-l", TypeValue}, + {NULL, TypeMax} + }; + +SHELL_STATUS +EFIAPI +ShellCommandRunDevices ( + VOID *RESERVED + ) { + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR8 *Language; + EFI_HANDLE *HandleList; + EFI_HANDLE *HandleListWalker; + CHAR16 Type; + BOOLEAN Cfg; + BOOLEAN Diag; + UINT8 Parents; + UINT8 Devices; + UINT8 Children; + CHAR16 *Name; + + ShellStatus = SHELL_SUCCESS; + Language = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if EFI_ERROR(Status) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // if more than 0 'value' parameters we have too many parameters + // + if (ShellCommandLineGetRawValue(Package, 1) != NULL){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get the language if necessary + // + if (ShellCommandLineGetFlag(Package, L"-l") != FALSE) { + Language = AllocateZeroPool(StrSize(ShellCommandLineGetValue(Package, L"-l"))); + AsciiSPrint(Language, StrSize(ShellCommandLineGetValue(Package, L"-l")), "%S", ShellCommandLineGetValue(Package, L"-l")); + } + + // + // Print Header + // + ShellPrintHiiEx(-1, -1, Language, STRING_TOKEN (STR_DEVICES_HEADER_LINES), gShellDriver1HiiHandle); + + // + // loop through each handle + // + HandleList = GetHandleListByPotocol(NULL); + ASSERT(HandleList != NULL); + for (HandleListWalker = HandleList + ; HandleListWalker != NULL && *HandleListWalker != NULL && !EFI_ERROR(Status) + ; HandleListWalker++ + ){ + // + // get all the info on each handle + // + Status = GetDeviceHandleInfo(*HandleListWalker, &Type, &Cfg, &Diag, &Parents, &Devices, &Children, &Name, Language); + if (Parents != 0 || Devices != 0 || Children != 0) { + ShellPrintHiiEx( + -1, + -1, + Language, + STRING_TOKEN (STR_DEVICES_ITEM_LINE), + gShellDriver1HiiHandle, + *HandleListWalker, + Type, + Cfg!=FALSE?L'X':L'-', + Diag!=FALSE?L'X':L'-', + Parents, + Devices, + Children, + Name); + } + if (Name != NULL) { + FreePool(Name); + } + } + + if (HandleList != NULL) { + FreePool(HandleList); + } + } + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c b/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c new file mode 100644 index 0000000000..80683b5abe --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/OpenInfo.c @@ -0,0 +1,243 @@ +/** @file + Main file for OpenInfo shell Driver1 function. + + 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 "UefiShellDriver1CommandsLib.h" + +EFI_STATUS +EFIAPI +TraverseHandleDatabase ( + IN CONST EFI_HANDLE DriverBindingHandle OPTIONAL, + IN CONST EFI_HANDLE ControllerHandle OPTIONAL, + IN UINTN *HandleCount, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN **HandleType + ){ + EFI_STATUS Status; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + UINTN ChildIndex; + + ASSERT(HandleCount != NULL); + ASSERT(HandleBuffer != NULL); + ASSERT(HandleType != NULL); + ASSERT(DriverBindingHandle != NULL || ControllerHandle != NULL); + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + + // + // Retrieve the list of all handles from the handle database + // + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + HandleCount, + HandleBuffer + ); + if (EFI_ERROR (Status)) { + return (Status); + } + + *HandleType = AllocateZeroPool (*HandleCount * sizeof (UINTN)); + ASSERT(*HandleType != NULL); + + for (HandleIndex = 0; HandleIndex < *HandleCount; HandleIndex++) { + // + // Retrieve the list of all the protocols on each handle + // + Status = gBS->ProtocolsPerHandle ( + (*HandleBuffer)[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + + // + // Set the bit describing what this handle has + // + if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiLoadedImageProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_IMAGE_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverBindingProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DRIVER_BINDING_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfiguration2ProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverConfigurationProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DRIVER_CONFIGURATION_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnostics2ProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDriverDiagnosticsProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DRIVER_DIAGNOSTICS_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentName2ProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiComponentNameProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_COMPONENT_NAME_HANDLE; + } else if (CompareGuid (ProtocolGuidArray[ProtocolIndex], &gEfiDevicePathProtocolGuid) != FALSE) { + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_DEVICE_HANDLE; + } else { + DEBUG_CODE_BEGIN(); + ASSERT((*HandleType)[HandleIndex] == (*HandleType)[HandleIndex]); + DEBUG_CODE_END(); + } + // + // Retrieve the list of agents that have opened each protocol + // + Status = gBS->OpenProtocolInformation ( + (*HandleBuffer)[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (DriverBindingHandle != NULL && OpenInfo[OpenInfoIndex].AgentHandle == DriverBindingHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + // + // Mark the device handle as being managed by the driver specified by DriverBindingHandle + // + (*HandleType)[HandleIndex] |= (HANDLE_RELATIONSHIP_DEVICE_HANDLE | HANDLE_RELATIONSHIP_CONTROLLER_HANDLE); + } + if (ControllerHandle != NULL && (*HandleBuffer)[HandleIndex] == ControllerHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].ControllerHandle) { + (*HandleType)[ChildIndex] |= (HANDLE_RELATIONSHIP_DEVICE_HANDLE | HANDLE_RELATIONSHIP_CHILD_HANDLE); + } + } + } + } + } else if (DriverBindingHandle == NULL && OpenInfo[OpenInfoIndex].ControllerHandle == ControllerHandle) { + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) { + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + // + // mark the handle who opened this as a device driver + // + (*HandleType)[ChildIndex] |= HANDLE_RELATIONSHIP_DEVICE_DRIVER; + } + } + } + if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { + // + // this handle has people opening by child so it must be a parent + // + (*HandleType)[HandleIndex] |= HANDLE_RELATIONSHIP_PARENT_HANDLE; + for (ChildIndex = 0; ChildIndex < *HandleCount; ChildIndex++) { + if ((*HandleBuffer)[ChildIndex] == OpenInfo[OpenInfoIndex].AgentHandle) { + (*HandleType)[ChildIndex] |= HANDLE_RELATIONSHIP_BUS_DRIVER; + } + } + } + } + } + + FreePool (OpenInfo); + } + } + + FreePool (ProtocolGuidArray); + } + } + + if (EFI_ERROR(Status)) { + if (*HandleType != NULL) { + FreePool (*HandleType); + } + if (*HandleBuffer != NULL) { + FreePool (*HandleBuffer); + } + + *HandleCount = 0; + *HandleBuffer = NULL; + *HandleType = NULL; + } + + return Status; +} + + +SHELL_STATUS +EFIAPI +ShellCommandRunOpenInfo ( + VOID *RESERVED + ) { + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + EFI_HANDLE theHandle; + EFI_HANDLE *HandleList; + UINTN Count; + UINTN *Type; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if EFI_ERROR(Status) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount() > 2){ + // + // error for too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount() == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDriver1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetRawValue(Package, 1) != NULL && CommandLibGetHandleValue(StrHexToUintn(ShellCommandLineGetRawValue(Package, 1))) == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + theHandle = CommandLibGetHandleValue(StrHexToUintn(ShellCommandLineGetRawValue(Package, 1))); + ASSERT(theHandle != NULL); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_OPENINFO_HEADER_LINE), gShellDriver1HiiHandle, StrHexToUintn(ShellCommandLineGetRawValue(Package, 1)), theHandle); + Status = TraverseHandleDatabase (NULL, theHandle, &Count, &HandleList, &Type); + if (EFI_ERROR(Status) == FALSE && Count > 0) { + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } + } + } + } + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c new file mode 100644 index 0000000000..67a074f11b --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.c @@ -0,0 +1,137 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + 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 "UefiShellDriver1CommandsLib.h" + +STATIC CONST CHAR16 mFileName[] = L"Driver1Commands"; +EFI_HANDLE gShellDriver1HiiHandle = NULL; +CONST EFI_GUID gShellDriver1HiiGuid = \ + { \ + 0xaf0b742, 0x63ec, 0x45bd, {0x8d, 0xb6, 0x71, 0xad, 0x7f, 0x2f, 0xe8, 0xe8} \ + }; + + +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameDriver1 ( + VOID + ){ + return (mFileName); +} + +/** + Constructor for the Shell Driver1 Commands library. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +UefiShellDriver1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) { + // + // check or bit of the profiles mask + // + if (PcdGet8(PcdShellProfileMask) && BIT0 == 0) { + return (EFI_UNSUPPORTED); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"connect", ShellCommandRunConnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"devices", ShellCommandRunDevices , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"openinfo", ShellCommandRunOpenInfo , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); +/* + ShellCommandRegisterCommandName(L"devtree", ShellCommandRunDevTree , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"dh", ShellCommandRunDH , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"disconnect", ShellCommandRunDisconnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"drivers", ShellCommandRunDrivers , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"drvcfg", ShellCommandRunDrvCfg , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"drvdiag", ShellCommandRunDrvDiag , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"reconnect", ShellCommandRunReconnect , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); + ShellCommandRegisterCommandName(L"unload", ShellCommandRunUnload , ShellCommandGetManFileNameDriver1, 0, L"Driver1", TRUE); +*/ + + // + // install the HII stuff. + // + gShellDriver1HiiHandle = HiiAddPackages (&gShellDriver1HiiGuid, gImageHandle, UefiShellDriver1CommandsLibStrings, NULL); + if (gShellDriver1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + return (EFI_SUCCESS); +} + +/** + Destructory for the library. free any resources. +**/ +EFI_STATUS +EFIAPI +UefiShellDriver1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellDriver1HiiHandle != NULL) { + HiiRemovePackages(gShellDriver1HiiHandle); + } + return (EFI_SUCCESS); +} + +EFI_HANDLE* +EFIAPI +GetHandleListByPotocol ( + IN CONST EFI_GUID *ProtocolGuid + ){ + EFI_HANDLE *HandleList; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + HandleList = NULL; + + // + // We cannot use LocateHandleBuffer since we need that NULL item on the ends of the list! + // + if (ProtocolGuid == NULL) { + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocatePool(Size + sizeof(EFI_HANDLE)); + Status = gBS->LocateHandle(AllHandles, NULL, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } else { + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleList = AllocatePool(Size + sizeof(EFI_HANDLE)); + Status = gBS->LocateHandle(ByProtocol, (EFI_GUID*)ProtocolGuid, NULL, &Size, HandleList); + HandleList[Size/sizeof(EFI_HANDLE)] = NULL; + } + } + if (EFI_ERROR(Status)) { + if (HandleList != NULL) { + FreePool(HandleList); + } + return (NULL); + } + return (HandleList); +} + diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h new file mode 100644 index 0000000000..4d3935e31a --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.h @@ -0,0 +1,71 @@ +/** @file + Main file for NULL named library for Profile1 shell command functions. + + 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern EFI_HANDLE gShellDriver1HiiHandle; +extern CONST EFI_GUID gShellDriver1HiiGuid; + +EFI_HANDLE* +EFIAPI +GetHandleListByPotocol ( + IN CONST EFI_GUID *ProtocolGuid + ); + +SHELL_STATUS +EFIAPI +ShellCommandRunConnect ( + VOID *RESERVED + ); + +SHELL_STATUS +EFIAPI +ShellCommandRunDevices ( + VOID *RESERVED + ); + +SHELL_STATUS +EFIAPI +ShellCommandRunOpenInfo ( + VOID *RESERVED + ); + + + + diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf new file mode 100644 index 0000000000..07840eca6f --- /dev/null +++ b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf @@ -0,0 +1,57 @@ +#/** @file +# Provides shell driver1 profile functions +# +# 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. +# +# +#**/ +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellDriver1CommandsLib + FILE_GUID = 313D3674-3ED4-48fd-BF97-7DB35D4190D1 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = UefiShellDriver1CommandsLibConstructor + DESTRUCTOR = UefiShellDriver1CommandsLibDestructor + +[Sources] + Connect.c + Devices.c + OpenInfo.c + UefiShellDriver1CommandsLib.c + UefiShellDriver1CommandsLib.h + UefiShellDriver1CommandsLib.uni + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask # ALWAYS_CONSUMED + +[Guids] + gEfiGlobalVariableGuid + gEfiConsoleInDeviceGuid + gEfiConsoleOutDeviceGuid diff --git a/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni new file mode 100644 index 0000000000..1de8b6d4aa Binary files /dev/null and b/ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.uni differ diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c new file mode 100644 index 0000000000..2f2a5bf565 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/Exit.c @@ -0,0 +1,81 @@ +/** @file + Main file for exit shell level 1 function. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"/b", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'exit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + + // + // If we are in a batch file and /b then pass TRUE otherwise false... + // + ShellCommandRegisterExit((BOOLEAN)(gEfiShellProtocol->BatchIsActive() && ShellCommandLineGetFlag(Package, L"/b"))); + + // + // return the specified error code + // + if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellStatus = (SHELL_STATUS)(ShellStrToUintn(ShellCommandLineGetRawValue(Package, 1))); + } + + ShellCommandLineFreeVarList (Package); + } + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c new file mode 100644 index 0000000000..0e68119b8d --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/For.c @@ -0,0 +1,581 @@ +/** @file + Main file for endfor and for shell level 1 functions. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" +#include + +BOOLEAN +EFIAPI +ShellIsValidForNumber ( + IN CONST CHAR16 *Number + ) +{ + if (Number == NULL || *Number == CHAR_NULL) { + return (FALSE); + } + + if (*Number == L'-') { + Number++; + } + + if (StrLen(Number) == 0) { + return (FALSE); + } + + if (StrLen(Number) >= 7) { + if (StrStr(Number, L" ") != NULL && (StrStr(Number, L" ") - Number) >= 7) { + return (FALSE); + } + } + + if (!ShellIsDecimalDigitCharacter(*Number)) { + return (FALSE); + } + + return (TRUE); +} + +/** + Function for 'endfor' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + BOOLEAN Found; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"EndFor"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + Found = MoveToTag(GetPreviousNode, L"for", L"endfor", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE); + + if (!Found) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"For", L"EndFor", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_NOT_FOUND); + } + return (SHELL_SUCCESS); +} + +typedef struct { + UINT32 Signature; + INTN Current; + INTN End; + INTN Step; + CHAR16 *ReplacementName; + CHAR16 *CurrentValue; + BOOLEAN RemoveSubstAlias; + CHAR16 Set[1]; + } SHELL_FOR_INFO; +#define SIZE_OF_SHELL_FOR_INFO OFFSET_OF (SHELL_FOR_INFO, Set) +#define SHELL_FOR_INFO_SIGNATURE SIGNATURE_32 ('S', 'F', 'I', 's') + +/** + Update the value of a given alias on the list. If the alias is not there then add it. + + @param[in] Alias The alias to test for. + @param[in] CommandString The updated command string. + @param[in,out] List The list to search. +**/ +VOID +EFIAPI +InternalUpdateAliasOnList( + IN CONST CHAR16 *Alias, + IN CONST CHAR16 *CommandString, + IN OUT LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + BOOLEAN Found; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List), Found = FALSE + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + FreePool(Node->CommandString); + Node->CommandString = NULL; + Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0); + Found = TRUE; + break; + } + } + if (!Found) { + Node = AllocateZeroPool(sizeof(ALIAS_LIST)); + ASSERT(Node->Alias == NULL); + Node->Alias = StrnCatGrow(&Node->Alias, NULL, Alias, 0); + ASSERT(Node->CommandString == NULL); + Node->CommandString = StrnCatGrow(&Node->CommandString, NULL, CommandString, 0); + InsertTailList(List, &Node->Link); + } +} + +/** + Find out if an alias is on the given list. + + @param[in] Alias The alias to test for. + @param[in] List The list to search. + + @retval TRUE The alias is on the list. + @retval FALSE The alias is not on the list. +**/ +BOOLEAN +EFIAPI +InternalIsAliasOnList( + IN CONST CHAR16 *Alias, + IN CONST LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List) + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + return (TRUE); + } + } + return (FALSE); +} + +/** + Remove an alias from the given list. + + @param[in] Alias The alias to remove. + @param[in,out] List The list to search. +**/ +BOOLEAN +EFIAPI +InternalRemoveAliasFromList( + IN CONST CHAR16 *Alias, + IN OUT LIST_ENTRY *List + ) +{ + ALIAS_LIST *Node; + + // + // assert for NULL parameter + // + ASSERT(Alias != NULL); + + // + // check for the Alias + // + for ( Node = (ALIAS_LIST *)GetFirstNode(List) + ; !IsNull(List, &Node->Link) + ; Node = (ALIAS_LIST *)GetNextNode(List, &Node->Link) + ){ + ASSERT(Node->CommandString != NULL); + ASSERT(Node->Alias != NULL); + if (StrCmp(Node->Alias, Alias)==0) { + RemoveEntryList(&Node->Link); + FreePool(Node->Alias); + FreePool(Node->CommandString); + FreePool(Node); + return (TRUE); + } + } + return (FALSE); +} + +/** + Function for 'for' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + SCRIPT_FILE *CurrentScriptFile; + CHAR16 *ArgSet; + CHAR16 *ArgSetWalker; + UINTN ArgSize; + UINTN LoopVar; + SHELL_FOR_INFO *Info; + CHAR16 *TempString; + CHAR16 *TempSpot; + BOOLEAN FirstPass; + EFI_SHELL_FILE_INFO *Node; + EFI_SHELL_FILE_INFO *FileList; + UINTN NewSize; + + ArgSet = NULL; + ArgSize = 0; + ShellStatus = SHELL_SUCCESS; + ArgSetWalker = NULL; + TempString = NULL; + FirstPass = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"For"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc < 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ASSERT(CurrentScriptFile != NULL); + + if (CurrentScriptFile->CurrentCommand->Data == NULL) { + FirstPass = TRUE; + + // + // Make sure that an End exists. + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + // + // Process the line. + // + if (gEfiShellParametersProtocol->Argv[1][0] != L'%' || gEfiShellParametersProtocol->Argv[1][2] != CHAR_NULL + ||!((gEfiShellParametersProtocol->Argv[1][1] >= L'a' && gEfiShellParametersProtocol->Argv[1][1] <= L'z') + ||(gEfiShellParametersProtocol->Argv[1][1] >= L'A' && gEfiShellParametersProtocol->Argv[1][1] <= L'Z')) + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_VAR), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[2]); + return (SHELL_INVALID_PARAMETER); + } + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + L"in", + gEfiShellParametersProtocol->Argv[2]) == 0) { + for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL)); + if (ArgSet == NULL) { + // ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } else { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0); + } + if (StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"*") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"?") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"[") != NULL + ||StrStr(gEfiShellParametersProtocol->Argv[LoopVar], L"]") != NULL) { + FileList = NULL; + Status = ShellOpenFileMetaArg ((CHAR16*)gEfiShellParametersProtocol->Argv[LoopVar], EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0); + } else { + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" \"", 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, Node->FullName, 0); + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } + ShellCloseFileMetaArg(&FileList); + } + } else { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0); + } + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } + // + // set up for an 'in' for loop + // + NewSize = StrSize(ArgSet); + NewSize += sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1]); + Info = AllocateZeroPool(NewSize); + ASSERT(Info != NULL); + Info->Signature = SHELL_FOR_INFO_SIGNATURE; + CopyMem(Info->Set, ArgSet, StrSize(ArgSet)); + NewSize = StrSize(gEfiShellParametersProtocol->Argv[1]); + CopyMem(Info->Set+(StrSize(ArgSet)/sizeof(Info->Set[0])), gEfiShellParametersProtocol->Argv[1], NewSize); + Info->ReplacementName = Info->Set+StrSize(ArgSet)/sizeof(Info->Set[0]); + Info->CurrentValue = (CHAR16*)Info->Set; + Info->Step = 0; + Info->Current = 0; + Info->End = 0; + + if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) { + Info->RemoveSubstAlias = FALSE; + } else { + Info->RemoveSubstAlias = TRUE; + } + CurrentScriptFile->CurrentCommand->Data = Info; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + L"run", + gEfiShellParametersProtocol->Argv[2]) == 0) { + for (LoopVar = 0x3 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) { + ASSERT((ArgSet == NULL && ArgSize == 0) || (ArgSet != NULL)); + if (ArgSet == NULL) { +// ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L"\"", 0); + } else { + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0); + } + ArgSet = StrnCatGrow(&ArgSet, &ArgSize, gEfiShellParametersProtocol->Argv[LoopVar], 0); +// ArgSet = StrnCatGrow(&ArgSet, &ArgSize, L" ", 0); + } + // + // set up for a 'run' for loop + // + Info = AllocateZeroPool(sizeof(SHELL_FOR_INFO)+StrSize(gEfiShellParametersProtocol->Argv[1])); + ASSERT(Info != NULL); + CopyMem(Info->Set, gEfiShellParametersProtocol->Argv[1], StrSize(gEfiShellParametersProtocol->Argv[1])); + Info->ReplacementName = Info->Set; + Info->CurrentValue = NULL; + ArgSetWalker = ArgSet; + if (ArgSetWalker[0] != L'(') { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ArgSetWalker++; + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (!ShellIsValidForNumber(ArgSetWalker)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ArgSetWalker[0] == L'-') { + Info->Current = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1); + } else { + Info->Current = (INTN)ShellStrToUintn(ArgSetWalker); + } + ArgSetWalker = StrStr(ArgSetWalker, L" "); + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ArgSetWalker[0] == L'-') { + Info->End = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1); + } else { + Info->End = (INTN)ShellStrToUintn(ArgSetWalker); + } + if (Info->Current < Info->End) { + Info->Step = 1; + } else { + Info->Step = -1; + } + + ArgSetWalker = StrStr(ArgSetWalker, L" "); + while (ArgSetWalker != NULL && ArgSetWalker[0] == L' ') { + ArgSetWalker++; + } + if (ArgSetWalker != NULL && *ArgSetWalker != CHAR_NULL) { + TempSpot = StrStr(ArgSetWalker, L")"); + if (TempSpot == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + *TempSpot = CHAR_NULL; + if (ArgSetWalker == NULL || *ArgSetWalker == CHAR_NULL || !ShellIsValidForNumber(ArgSetWalker)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (*ArgSetWalker == L')') { + ASSERT(Info->Step == 1 || Info->Step == -1); + } else { + if (ArgSetWalker[0] == L'-') { + Info->Step = 0 - (INTN)ShellStrToUintn(ArgSetWalker+1); + } else { + Info->Step = (INTN)ShellStrToUintn(ArgSetWalker); + } + } + } + } + } + } + } + } + if (ShellStatus == SHELL_SUCCESS) { + if (InternalIsAliasOnList(Info->ReplacementName, &CurrentScriptFile->SubstList)) { + Info->RemoveSubstAlias = FALSE; + } else { + Info->RemoveSubstAlias = TRUE; + } + } + CurrentScriptFile->CurrentCommand->Data = Info; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_SCRIPT), gShellLevel1HiiHandle, ArgSet, ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // These need to be NULL since they are used to determine if this is the first pass later on... + // + ASSERT(ArgSetWalker == NULL); + ASSERT(ArgSet == NULL); + } + + Info = (SHELL_FOR_INFO*)CurrentScriptFile->CurrentCommand->Data; + if (CurrentScriptFile->CurrentCommand->Reset) { + Info->CurrentValue = (CHAR16*)Info->Set; + FirstPass = TRUE; + CurrentScriptFile->CurrentCommand->Reset = FALSE; + } + if (ShellStatus == SHELL_SUCCESS) { + ASSERT(Info != NULL); + if (Info->Step != 0) { + // + // only advance if not the first pass + // + if (!FirstPass) { + // + // sequence version of for loop... + // + Info->Current += Info->Step; + } + + TempString = AllocateZeroPool(50*sizeof(CHAR16)); + UnicodeSPrint(TempString, 50*sizeof(CHAR16), L"%d", Info->Current); + InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList); + FreePool(TempString); + + if ((Info->Step > 0 && Info->Current > Info->End) || (Info->Step < 0 && Info->Current < Info->End)) { + CurrentScriptFile->CurrentCommand->Data = NULL; + // + // find the matching endfor (we're done with the loop) + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_DEVICE_ERROR; + } + if (Info->RemoveSubstAlias) { + // + // remove item from list + // + InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList); + } + FreePool(Info); + } + } else { + // + // Must be in 'in' version of for loop... + // + ASSERT(Info->Set != NULL); + if (Info->CurrentValue != NULL && *Info->CurrentValue != CHAR_NULL) { + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + while (Info->CurrentValue[0] == L' ') { + Info->CurrentValue++; + } + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + // + // do the next one of the set + // + ASSERT(TempString == NULL); + TempString = StrnCatGrow(&TempString, NULL, Info->CurrentValue, 0); + TempSpot = StrStr(TempString, L"\" \""); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + while (TempString[StrLen(TempString)-1] == L'\"') { + TempString[StrLen(TempString)-1] = CHAR_NULL; + } + InternalUpdateAliasOnList(Info->ReplacementName, TempString, &CurrentScriptFile->SubstList); + Info->CurrentValue += StrLen(TempString); + + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + while (Info->CurrentValue[0] == L' ') { + Info->CurrentValue++; + } + if (Info->CurrentValue[0] == L'\"') { + Info->CurrentValue++; + } + FreePool(TempString); + + } else { + CurrentScriptFile->CurrentCommand->Data = NULL; + // + // find the matching endfor (we're done with the loop) + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", NULL, CurrentScriptFile, TRUE, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndFor", L"For", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_DEVICE_ERROR; + } + if (Info->RemoveSubstAlias) { + // + // remove item from list + // + InternalRemoveAliasFromList(Info->ReplacementName, &CurrentScriptFile->SubstList); + } + FreePool(Info); + } + } + } + if (ArgSet != NULL) { + FreePool(ArgSet); + } + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c new file mode 100644 index 0000000000..8213fae7ac --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/Goto.c @@ -0,0 +1,92 @@ +/** @file + Main file for goto shell level 1 function. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" + +/** + Function for 'goto' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGoto ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR16 *CompareString; + UINTN Size; + + ShellStatus = SHELL_SUCCESS; + CompareString = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Goto"); + return (SHELL_UNSUPPORTED); + } + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel1HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Size = 0; + ASSERT((CompareString == NULL && Size == 0) || (CompareString != NULL)); + CompareString = StrnCatGrow(&CompareString, &Size, L":", 0); + CompareString = StrnCatGrow(&CompareString, &Size, ShellCommandLineGetRawValue(Package, 1), 0); + // + // Check forwards and then backwards for a label... + // + if (!MoveToTag(GetNextNode, L"endfor", L"for", CompareString, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, TRUE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, CompareString, L"Goto", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_NOT_FOUND; + } + FreePool(CompareString); + } + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c new file mode 100644 index 0000000000..3376329622 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/If.c @@ -0,0 +1,962 @@ +/** @file + Main file for If and else shell level 1 function. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" +#include + + + + +typedef enum { + END_TAG_OR, + END_TAG_AND, + END_TAG_THEN, + END_TAG_MAX +} END_TAG_TYPE; + +typedef enum { + OPERATOR_GT, + OPERATOR_LT, + OPERATOR_EQ, + OPERATOR_NE, + OPERATOR_GE, + OPERATOR_LE, + OPERATOR_UGT, + OPERATOR_ULT, + OPERATOR_UGE, + OPERATOR_ULE, + OPERATOR_MAX +} BIN_OPERATOR_TYPE; + +BOOLEAN +EFIAPI +IsNextFragment ( + IN CONST CHAR16 **Statement, + IN CONST CHAR16 *Fragment + ) +{ + CHAR16 *Tester; + + Tester = NULL; + + Tester = StrnCatGrow(&Tester, NULL, *Statement, StrLen(Fragment)); + ASSERT(Tester != NULL); + Tester[StrLen(Fragment)] = CHAR_NULL; + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)Fragment, + Tester) == 0) { + // + // increment the string pointer to the end of what we found and then chop off spaces... + // + *Statement+=StrLen(Fragment); + while (*Statement[0] == L' ') { + *Statement++; + } + FreePool(Tester); + return (TRUE); + } + FreePool(Tester); + return (FALSE); +} + +BOOLEAN +EFIAPI +IsValidProfile ( + IN CONST CHAR16 *String + ) +{ + CONST CHAR16 *ProfilesString; + CONST CHAR16 *TempLocation; + + ProfilesString = ShellGetEnvironmentVariable(L"profiles"); + TempLocation = StrStr(ProfilesString, String); + if ((TempLocation != NULL) && (*(TempLocation-1) == L';') && (*(TempLocation+StrLen(String)) == L';')) { + return (TRUE); + } + return (FALSE); +} + +BOOLEAN +EFIAPI +TestOperation ( + IN CONST CHAR16 *Compare1, + IN CONST CHAR16 *Compare2, + IN CONST BIN_OPERATOR_TYPE BinOp, + IN CONST BOOLEAN CaseInsensitive, + IN CONST BOOLEAN ForceStringCompare + ) +{ + INTN Cmp1; + INTN Cmp2; + + // + // "Compare1 BinOp Compare2" + // + switch (BinOp) { + case OPERATOR_UGT: + case OPERATOR_GT: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) > 0) || (StringCompare(&Compare1, &Compare2) > 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)StrDecimalToUintn(Compare1+1); + } else { + Cmp1 = (INTN)StrDecimalToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)StrDecimalToUintn(Compare2+1); + } else { + Cmp2 = (INTN)StrDecimalToUintn(Compare2); + } + if (BinOp == OPERATOR_GT) { + if (Cmp1 > Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 > (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + break; + case OPERATOR_ULT: + case OPERATOR_LT: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) < 0) || (StringCompare(&Compare1, &Compare2) < 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)StrDecimalToUintn(Compare1+1); + } else { + Cmp1 = (INTN)StrDecimalToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)StrDecimalToUintn(Compare2+1); + } else { + Cmp2 = (INTN)StrDecimalToUintn(Compare2); + } + if (BinOp == OPERATOR_LT) { + if (Cmp1 < Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 < (UINTN)Cmp2) { + return (TRUE); + } + } + + } + return (FALSE); + break; + case OPERATOR_EQ: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) == 0) || (StringCompare(&Compare1, &Compare2) == 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)ShellStrToUintn(Compare1+1); + } else { + Cmp1 = (INTN)ShellStrToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)ShellStrToUintn(Compare2+1); + } else { + Cmp2 = (INTN)ShellStrToUintn(Compare2); + } + if (Cmp1 == Cmp2) { + return (TRUE); + } + } + return (FALSE); + break; + case OPERATOR_NE: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) != 0) || (StringCompare(&Compare1, &Compare2) != 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)StrDecimalToUintn(Compare1+1); + } else { + Cmp1 = (INTN)StrDecimalToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)StrDecimalToUintn(Compare2+1); + } else { + Cmp2 = (INTN)StrDecimalToUintn(Compare2); + } + if (Cmp1 != Cmp2) { + return (TRUE); + } + } + return (FALSE); + break; + case OPERATOR_UGE: + case OPERATOR_GE: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) >= 0) || (StringCompare(&Compare1, &Compare2) >= 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)StrDecimalToUintn(Compare1+1); + } else { + Cmp1 = (INTN)StrDecimalToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)StrDecimalToUintn(Compare2+1); + } else { + Cmp2 = (INTN)StrDecimalToUintn(Compare2); + } + if (BinOp == OPERATOR_GE) { + if (Cmp1 >= Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 >= (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + break; + case OPERATOR_LE: + case OPERATOR_ULE: + if (ForceStringCompare || !ShellIsHexOrDecimalNumber(Compare1, FALSE, FALSE) || !ShellIsHexOrDecimalNumber(Compare2, FALSE, FALSE)) { + // + // string compare + // + if ((CaseInsensitive && StringNoCaseCompare(&Compare1, &Compare2) <= 0) || (StringCompare(&Compare1, &Compare2) <= 0)) { + return (TRUE); + } + } else { + // + // numeric compare + // + if (Compare1[0] == L'-') { + Cmp1 = 0 - (INTN)StrDecimalToUintn(Compare1+1); + } else { + Cmp1 = (INTN)StrDecimalToUintn(Compare1); + } + if (Compare2[0] == L'-') { + Cmp2 = 0 - (INTN)StrDecimalToUintn(Compare2+1); + } else { + Cmp2 = (INTN)StrDecimalToUintn(Compare2); + } + if (BinOp == OPERATOR_LE) { + if (Cmp1 <= Cmp2) { + return (TRUE); + } + } else { + if ((UINTN)Cmp1 <= (UINTN)Cmp2) { + return (TRUE); + } + } + } + return (FALSE); + break; + } + ASSERT(FALSE); + return (FALSE); +} + +EFI_STATUS +EFIAPI +ProcessStatement ( + IN OUT BOOLEAN *PassingState, + IN UINTN StartParameterNumber, + IN UINTN EndParameterNumber, + IN CONST END_TAG_TYPE OperatorToUse, + IN CONST BOOLEAN CaseInsensitive, + IN CONST BOOLEAN ForceStringCompare + ) +{ + EFI_STATUS Status; + BOOLEAN OperationResult; + BOOLEAN NotPresent; + CHAR16 *StatementWalker; + BIN_OPERATOR_TYPE BinOp; + CHAR16 *Compare1; + CHAR16 *Compare2; + CHAR16 HexString[20]; + CHAR16 *TempSpot; + + ASSERT((END_TAG_TYPE)OperatorToUse != END_TAG_THEN); + + Status = EFI_SUCCESS; + BinOp = OPERATOR_MAX; + OperationResult = FALSE; + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber]; + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"not")) { + NotPresent = TRUE; + StatementWalker = gEfiShellParametersProtocol->Argv[++StartParameterNumber]; + } else { + NotPresent = FALSE; + } + + // + // now check for 'boolfunc' operators + // + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"isint")) { + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + OperationResult = ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE); + } else { + Status = EFI_INVALID_PARAMETER; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"isint"); + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exists") || IsNextFragment((CONST CHAR16**)(&StatementWalker), L"exist")) { + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + // + // is what remains a file in CWD??? + // + OperationResult = (BOOLEAN)(ShellFileExists(StatementWalker)==EFI_SUCCESS); + } else if (StatementWalker[0] == CHAR_NULL && StartParameterNumber+1 == EndParameterNumber) { + OperationResult = (BOOLEAN)(ShellFileExists(gEfiShellParametersProtocol->Argv[++StartParameterNumber])==EFI_SUCCESS); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"exist(s)"); + Status = EFI_INVALID_PARAMETER; + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"available")) { + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && StatementWalker[StrLen(StatementWalker)-1] == L')') { + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + // + // is what remains a file in the CWD or path??? + // + OperationResult = (BOOLEAN)(ShellIsFileInPath(StatementWalker)==EFI_SUCCESS); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"available"); + Status = EFI_INVALID_PARAMETER; + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"profile")) { + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && StatementWalker[StrLen(StatementWalker)-1] == L')') { + // + // Chop off that ')' + // + StatementWalker[StrLen(StatementWalker)-1] = CHAR_NULL; + OperationResult = IsValidProfile(StatementWalker); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"profile"); + Status = EFI_INVALID_PARAMETER; + } + } else if (StartParameterNumber+1 >= EndParameterNumber) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber]); + Status = EFI_INVALID_PARAMETER; + } else { + // + // must be 'item binop item' style + // + Compare1 = NULL; + Compare2 = NULL; + BinOp = OPERATOR_MAX; + + // + // get the first item + // + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber]; + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + *TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + *TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2)); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"oemerror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1)); + ASSERT(Compare1 == NULL); + Compare1 = StrnCatGrow(&Compare1, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ASSERT(Compare1 == NULL); + if (EndParameterNumber - StartParameterNumber > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[StartParameterNumber+2]); + Status = EFI_INVALID_PARAMETER; + } else { + // + // must be a raw string + // + Compare1 = StrnCatGrow(&Compare1, NULL, StatementWalker, 0); + } + } + + // + // get the operator + // + ASSERT(StartParameterNumber+1Argv[StartParameterNumber+1]; + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"gt")) { + BinOp = OPERATOR_GT; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"lt")) { + BinOp = OPERATOR_LT; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"eq")) { + BinOp = OPERATOR_EQ; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ne")) { + BinOp = OPERATOR_NE; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ge")) { + BinOp = OPERATOR_GE; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"le")) { + BinOp = OPERATOR_LE; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"==")) { + BinOp = OPERATOR_EQ; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ugt")) { + BinOp = OPERATOR_UGT; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ult")) { + BinOp = OPERATOR_ULT; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"uge")) { + BinOp = OPERATOR_UGE; + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"ule")) { + BinOp = OPERATOR_ULE; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_INVALID_BINOP), gShellLevel1HiiHandle, StatementWalker); + Status = EFI_INVALID_PARAMETER; + } + + // + // get the second item + // + ASSERT(StartParameterNumber+2<=EndParameterNumber); + StatementWalker = gEfiShellParametersProtocol->Argv[StartParameterNumber+2]; + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"efierror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"efierror"); + Status = EFI_INVALID_PARAMETER; + } + // + // can this be collapsed into the above? + // + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"pierror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>2)); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"pierror"); + Status = EFI_INVALID_PARAMETER; + } + } else if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"oemerror")) { + TempSpot = StrStr(StatementWalker, L")"); + if (IsNextFragment((CONST CHAR16**)(&StatementWalker), L"(") && TempSpot != NULL) { + TempSpot = CHAR_NULL; + if (ShellIsHexOrDecimalNumber(StatementWalker, FALSE, FALSE)) { + UnicodeSPrint(HexString, sizeof(HexString), L"0x%x", ShellStrToUintn(StatementWalker)|MAX_BIT|(MAX_BIT>>1)); + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, HexString, 0); + StatementWalker += StrLen(StatementWalker) + 1; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_IN), gShellLevel1HiiHandle, L"oemerror"); + Status = EFI_INVALID_PARAMETER; + } + } else { + // + // must be a raw string + // + ASSERT(Compare2 == NULL); + Compare2 = StrnCatGrow(&Compare2, NULL, StatementWalker, 0); + } + + if (Compare1 != NULL && Compare2 != NULL && BinOp != OPERATOR_MAX) { + OperationResult = TestOperation(Compare1, Compare2, BinOp, CaseInsensitive, ForceStringCompare); + } + + SHELL_FREE_NON_NULL(Compare1); + SHELL_FREE_NON_NULL(Compare2); + } + + // + // done processing do result... + // + + if (!EFI_ERROR(Status)) { + if (NotPresent) { + OperationResult = (BOOLEAN)(!OperationResult); + } + switch(OperatorToUse) { + case END_TAG_OR: + *PassingState = (BOOLEAN)(*PassingState || OperationResult); + break; + case END_TAG_AND: + *PassingState = (BOOLEAN)(*PassingState && OperationResult); + break; + case END_TAG_MAX: + *PassingState = (BOOLEAN)(OperationResult); + break; + default: + ASSERT(FALSE); + } + } + return (Status); +} + +BOOLEAN +EFIAPI +BuildNextStatement ( + IN UINTN ParameterNumber, + OUT UINTN *EndParameter, + OUT END_TAG_TYPE *EndTag + ) +{ + CHAR16 *Buffer; + UINTN BufferSize; + + *EndTag = END_TAG_MAX; + + for(Buffer = NULL, BufferSize = 0 + ; ParameterNumber < gEfiShellParametersProtocol->Argc + ; ParameterNumber++ + ) { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"or") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = END_TAG_OR; + break; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"and") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = END_TAG_AND; + break; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[ParameterNumber], + L"then") == 0) { + *EndParameter = ParameterNumber - 1; + *EndTag = END_TAG_THEN; + break; + } + } + if (*EndTag == END_TAG_MAX) { + return (FALSE); + } + return (TRUE); +} + +BOOLEAN +EFIAPI +MoveToTagSpecial ( + IN SCRIPT_FILE *ScriptFile + ) +{ + SCRIPT_COMMAND_LIST *CommandNode; + BOOLEAN Found; + UINTN TargetCount; + CHAR16 *CommandName; + CHAR16 *CommandWalker; + CHAR16 *TempLocation; + + TargetCount = 1; + Found = FALSE; + + if (ScriptFile == NULL) { + return FALSE; + } + + for (CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE + ; !IsNull(&ScriptFile->CommandList, &CommandNode->Link) && !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link) + ){ + + // + // get just the first part of the command line... + // + CommandName = NULL; + CommandName = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0); + CommandWalker = CommandName; + while (CommandWalker[0] == L' ') { + CommandWalker++; + } + TempLocation = StrStr(CommandWalker, L" "); + + if (TempLocation != NULL) { + *TempLocation = CHAR_NULL; + } + + // + // did we find a nested item ? + // + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + L"If") == 0) { + TargetCount++; + } else if (TargetCount == 1 && gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + (CHAR16*)L"else") == 0) { + // + // else can only decrement the last part... not an nested if + // hence the TargetCount compare added + // + TargetCount--; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandWalker, + (CHAR16*)L"endif") == 0) { + TargetCount--; + } + if (TargetCount == 0) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&ScriptFile->CommandList, &CommandNode->Link); + Found = TRUE; + } + + // + // Free the memory for this loop... + // + SHELL_FREE_NON_NULL(CommandName); + } + return (Found); +} + +EFI_STATUS +EFIAPI +PerformResultOperation ( + IN CONST BOOLEAN Result + ) +{ + if (Result || MoveToTagSpecial(ShellCommandGetCurrentScriptFile())) { + return (EFI_SUCCESS); + } + return (EFI_NOT_FOUND); +} + +/** + Function for 'if' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + BOOLEAN CaseInsensitive; + BOOLEAN ForceString; + UINTN CurrentParameter; + UINTN EndParameter; + BOOLEAN CurrentValue; + END_TAG_TYPE Ending; + END_TAG_TYPE PreviousEnding; + + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"If"); + return (SHELL_UNSUPPORTED); + } + + if (gEfiShellParametersProtocol->Argc < 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + // + // Make sure that an End exists. + // + if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, ShellCommandGetCurrentScriptFile(), TRUE, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EnfIf", L"If", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + CurrentParameter = 1; + EndParameter = 0; + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[1], + L"/i") == 0 || + gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[2], + L"/i") == 0 || + (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[3], + L"/i") == 0)) { + CaseInsensitive = TRUE; + CurrentParameter++; + } else { + CaseInsensitive = FALSE; + } + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[1], + L"/s") == 0 || + gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[2], + L"/s") == 0 || + (gEfiShellParametersProtocol->Argc > 3 && gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[3], + L"/s") == 0)) { + ForceString = TRUE; + CurrentParameter++; + } else { + ForceString = FALSE; + } + + for ( ShellStatus = SHELL_SUCCESS, CurrentValue = FALSE, Ending = END_TAG_MAX + ; CurrentParameter < gEfiShellParametersProtocol->Argc && ShellStatus == SHELL_SUCCESS + ; CurrentParameter++) { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + gEfiShellParametersProtocol->Argv[CurrentParameter], + L"then") == 0) { + // + // we are at the then + // + if (CurrentParameter+1 != gEfiShellParametersProtocol->Argc) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TEXT_AFTER_THEN), gShellLevel1HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = PerformResultOperation(CurrentValue); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else { + PreviousEnding = Ending; + // + // build up the next statement for analysis + // + if (!BuildNextStatement(CurrentParameter, &EndParameter, &Ending)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"Then", L"If", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Analyze the statement + // + Status = ProcessStatement(&CurrentValue, CurrentParameter, EndParameter, PreviousEnding, CaseInsensitive, ForceString); + if (EFI_ERROR(Status)) { +// ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_STARTING), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Optomize to get out of the loop early... + // + if ((Ending == END_TAG_OR && CurrentValue) || (Ending == END_TAG_AND && !CurrentValue)) { + Status = PerformResultOperation(CurrentValue); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_AFTER_BAD), gShellLevel1HiiHandle, gEfiShellParametersProtocol->Argv[CurrentParameter]); + ShellStatus = SHELL_INVALID_PARAMETER; + } + break; + } + } + } + if (ShellStatus == SHELL_SUCCESS){ + CurrentParameter = EndParameter; + // + // Skip over the or or and parameter. + // + if (Ending == END_TAG_OR || Ending == END_TAG_AND) { + CurrentParameter++; + } + } + } + } + return (ShellStatus); +} + +/** + Function for 'else' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunElse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + ASSERT_EFI_ERROR(CommandInit()); + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Else"); + return (SHELL_UNSUPPORTED); + } + + + if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, ShellCommandGetCurrentScriptFile(), FALSE, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"If", L"Else", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + if (!MoveToTag(GetPreviousNode, L"if", L"else", NULL, ShellCommandGetCurrentScriptFile(), FALSE, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"If", L"Else", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + if (!MoveToTag(GetNextNode, L"endif", L"if", NULL, ShellCommandGetCurrentScriptFile(), FALSE, FALSE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"EndIf", "Else", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + return (SHELL_SUCCESS); +} + +/** + Function for 'endif' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + ASSERT_EFI_ERROR(CommandInit()); + + if (gEfiShellParametersProtocol->Argc > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel1HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Endif"); + return (SHELL_UNSUPPORTED); + } + + if (!MoveToTag(GetPreviousNode, L"if", L"endif", NULL, ShellCommandGetCurrentScriptFile(), FALSE, TRUE, FALSE)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SYNTAX_NO_MATCHING), gShellLevel1HiiHandle, L"If", L"EndIf", ShellCommandGetCurrentScriptFile()->CurrentCommand->Line); + return (SHELL_DEVICE_ERROR); + } + + return (SHELL_SUCCESS); +} diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/NoOpScriptCommand.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/NoOpScriptCommand.c new file mode 100644 index 0000000000..85fe582579 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/NoOpScriptCommand.c @@ -0,0 +1,40 @@ +/** @file + Main file for else and endif shell level 1 functions. Does nothing really... + + Copyright (c) 2009-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 "UefiShellLevel1CommandsLib.h" + +SHELL_STATUS +EFIAPI +ShellCommandRunNoOpScriptCommand ( + VOID *RESERVED + ) +{ + EFI_STATUS Status; + // + // ASSERT that we can init... + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // We best be in a script... + // + ASSERT(gEfiShellProtocol->BatchIsActive()); + + // + // Do nothing... + // + return (SHELL_SUCCESS); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c new file mode 100644 index 0000000000..9abb4c31b1 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/Shift.c @@ -0,0 +1,63 @@ +/** @file + Main file for Shift shell level 1 function. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" + +/** + Function for 'shift' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunShift ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SCRIPT_FILE *CurrentScriptFile; + UINTN LoopVar; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_NO_SCRIPT), gShellLevel1HiiHandle, L"Shift"); + return (SHELL_UNSUPPORTED); + } + + CurrentScriptFile = ShellCommandGetCurrentScriptFile(); + ASSERT(CurrentScriptFile != NULL); + + if (CurrentScriptFile->Argc < 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel1HiiHandle); + return (SHELL_UNSUPPORTED); + } + + for (LoopVar = 0 ; LoopVar < CurrentScriptFile->Argc ; LoopVar++) { + if (LoopVar == 0) { + SHELL_FREE_NON_NULL(CurrentScriptFile->Argv[LoopVar]); + } + if (LoopVar < CurrentScriptFile->Argc -1) { + CurrentScriptFile->Argv[LoopVar] = CurrentScriptFile->Argv[LoopVar+1]; + } else { + CurrentScriptFile->Argv[LoopVar] = NULL; + } + } + CurrentScriptFile->Argc--; + return (SHELL_SUCCESS); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c new file mode 100644 index 0000000000..47b6f92864 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.c @@ -0,0 +1,251 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + Copyright (c) 2009 - 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 "UefiShellLevel1CommandsLib.h" + +STATIC CONST CHAR16 mFileName[] = L"ShellCommands"; +EFI_HANDLE gShellLevel1HiiHandle = NULL; +CONST EFI_GUID gShellLevel1HiiGuid = \ + { \ + 0xdec5daa4, 0x6781, 0x4820, { 0x9c, 0x63, 0xa7, 0xb0, 0xe4, 0xf1, 0xdb, 0x31 } + }; + + +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel1 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Level 1 Commands library. + + Install the handlers for level 1 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel1CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // if shell level is less than 2 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 1) { + return (EFI_UNSUPPORTED); + } + + gShellLevel1HiiHandle = HiiAddPackages (&gShellLevel1HiiGuid, gImageHandle, UefiShellLevel1CommandsLibStrings, NULL); + if (gShellLevel1HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"for", ShellCommandRunFor , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_FOR) )); + ShellCommandRegisterCommandName(L"goto", ShellCommandRunGoto , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_GOTO) )); + ShellCommandRegisterCommandName(L"if", ShellCommandRunIf , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_IF) )); + ShellCommandRegisterCommandName(L"shift", ShellCommandRunShift , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_SHIFT) )); + ShellCommandRegisterCommandName(L"exit", ShellCommandRunExit , ShellCommandGetManFileNameLevel1, 1, L"", TRUE , gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_EXIT) )); + ShellCommandRegisterCommandName(L"else", ShellCommandRunElse , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ELSE) )); + ShellCommandRegisterCommandName(L"endif", ShellCommandRunEndIf , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ENDIF) )); + ShellCommandRegisterCommandName(L"endfor", ShellCommandRunEndFor , ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8(PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN(STR_GET_HELP_ENDFOR))); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. +**/ +EFI_STATUS +EFIAPI +ShellLevel1CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel1HiiHandle != NULL) { + HiiRemovePackages(gShellLevel1HiiHandle); + } + return (EFI_SUCCESS); +} + +BOOLEAN +EFIAPI +TestNodeForMove ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST SCRIPT_COMMAND_LIST *CommandNode, + IN UINTN *TargetCount + ) +{ + BOOLEAN Found; + CHAR16 *CommandName; + CHAR16 *CommandNameWalker; + CHAR16 *TempLocation; + + Found = FALSE; + + // + // get just the first part of the command line... + // + CommandName = NULL; + CommandName = StrnCatGrow(&CommandName, NULL, CommandNode->Cl, 0); + CommandNameWalker = CommandName; + while(CommandNameWalker[0] == L' ') { + CommandNameWalker++; + } + TempLocation = StrStr(CommandNameWalker, L" "); + + if (TempLocation != NULL) { + *TempLocation = CHAR_NULL; + } + + // + // did we find a nested item ? + // + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)IncrementerTag) == 0) { + (*TargetCount)++; + } else if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)DecrementerTag) == 0) { + if (*TargetCount > 0) { + (*TargetCount)--; + } + } + + // + // did we find the matching one... + // + if (Label == NULL) { + if (*TargetCount == 0) { + Found = TRUE; + if (!FindOnly) { + if (MovePast) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); + } else { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; + } + } + } + } else { + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandNameWalker, + (CHAR16*)Label) == 0 + && (*TargetCount) == 0) { + Found = TRUE; + if (!FindOnly) { + // + // we found the target label without loops + // + if (MovePast) { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); + } else { + ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; + } + } + } + } + + // + // Free the memory for this loop... + // + FreePool(CommandName); + return (Found); +} + +BOOLEAN +EFIAPI +MoveToTag ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST BOOLEAN WrapAroundScript + ) +{ + SCRIPT_COMMAND_LIST *CommandNode; + BOOLEAN Found; + UINTN TargetCount; + + if (Label == NULL) { + TargetCount = 1; + } else { + TargetCount = 0; + } + + if (ScriptFile == NULL) { + return FALSE; + } + + for (CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE + ; !IsNull(&ScriptFile->CommandList, &CommandNode->Link)&& !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) + ){ + Found = TestNodeForMove( + Function, + DecrementerTag, + IncrementerTag, + Label, + ScriptFile, + MovePast, + FindOnly, + CommandNode, + &TargetCount); + } + + if (WrapAroundScript && !Found) { + for (CommandNode = (SCRIPT_COMMAND_LIST *)GetFirstNode(&ScriptFile->CommandList), Found = FALSE + ; CommandNode != ScriptFile->CurrentCommand && !Found + ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) + ){ + Found = TestNodeForMove( + Function, + DecrementerTag, + IncrementerTag, + Label, + ScriptFile, + MovePast, + FindOnly, + CommandNode, + &TargetCount); + } + } + return (Found); +} + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h new file mode 100644 index 0000000000..b0aa51bc1b --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.h @@ -0,0 +1,182 @@ +/** @file + Main file for NULL named library for level 1 shell command functions. + + Copyright (c) 2009 - 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HANDLE gShellLevel1HiiHandle; +extern CONST EFI_GUID gShellLevel1HiiGuid; + +/** + Function for 'exit' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'endif' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'for' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'endfor' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEndFor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'if' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIf ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'goto' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGoto ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'shift' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunShift ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +/** + Function for 'else' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunElse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/// +/// Function prototype for BOTH GetNextNode and GetPreviousNode... +/// This is used to control the MoveToTag function direction... +/// +typedef +LIST_ENTRY * +(EFIAPI *LIST_MANIP_FUNC)( + IN CONST LIST_ENTRY *List, + IN CONST LIST_ENTRY *Node + ); + +/** + Function to move to a spacified tag in a script file structure. + + @param[in] Function The pointer to the function to move with. + @param[in] DecrementerTag The pointer to a string to decrement upon finding. + @param[in] IncrementerTag The pointer to a string to increment upon finding. + @param[in] Label A Label to look for. + @param[in] ScriptFile The script file structure to look in. + @param[in] MovePast TRUE to go to the element just after the found one. FALSE otherwise. + @param[in] FindOnly FALSE to change the execution point in the script file structure. TRUE otherwise. + @param[in] WrapAroundScript TRUE to go to begining when end is hit, or vise versa. FALSE otherwise. +**/ +BOOLEAN +EFIAPI +MoveToTag ( + IN CONST LIST_MANIP_FUNC Function, + IN CONST CHAR16 *DecrementerTag, + IN CONST CHAR16 *IncrementerTag, + IN CONST CHAR16 *Label OPTIONAL, + IN SCRIPT_FILE *ScriptFile, + IN CONST BOOLEAN MovePast, + IN CONST BOOLEAN FindOnly, + IN CONST BOOLEAN WrapAroundScript + ); + diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf new file mode 100644 index 0000000000..b4697f3908 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf @@ -0,0 +1,54 @@ +## @file +# Provides shell level 1 functions +# +# Copyright (c) 2009-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. +# +# +## +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel1CommandsLib + FILE_GUID = 50cb6037-1102-47af-b2dd-9944b6eb1abe + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel1CommandsLibConstructor + DESTRUCTOR = ShellLevel1CommandsLibDestructor + +[Sources.common] + UefiShellLevel1CommandsLib.c + UefiShellLevel1CommandsLib.h + UefiShellLevel1CommandsLib.uni + Exit.c + Goto.c + If.c + For.c + Shift.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SortLib + PrintLib + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel # ALWAYS_CONSUMED diff --git a/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni new file mode 100644 index 0000000000..7043b48ad5 Binary files /dev/null and b/ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.uni differ diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c new file mode 100644 index 0000000000..c891ca6afa --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Attrib.c @@ -0,0 +1,271 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +STATIC CONST CHAR16 AllFiles[] = L"*"; + +STATIC CONST SHELL_PARAM_ITEM AttribParamList[] = { + {L"-a", TypeFlag}, + {L"+a", TypeFlag}, + {L"-s", TypeFlag}, + {L"+s", TypeFlag}, + {L"-h", TypeFlag}, + {L"+h", TypeFlag}, + {L"-r", TypeFlag}, + {L"+r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'attrib' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAttrib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT64 FileAttributesToAdd; + UINT64 FileAttributesToRemove; + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamNumberCount; + CONST CHAR16 *FileName; + EFI_SHELL_FILE_INFO *ListOfFiles; + EFI_SHELL_FILE_INFO *FileNode; + EFI_FILE_INFO *FileInfo; + + ListOfFiles = NULL; + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (AttribParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else { + FileAttributesToAdd = 0; + FileAttributesToRemove = 0; + + // + // apply or remove each flag + // + if (ShellCommandLineGetFlag(Package, L"+a")) { + FileAttributesToAdd |= EFI_FILE_ARCHIVE; + } + if (ShellCommandLineGetFlag(Package, L"-a")) { + FileAttributesToRemove |= EFI_FILE_ARCHIVE; + } + if (ShellCommandLineGetFlag(Package, L"+s")) { + FileAttributesToAdd |= EFI_FILE_SYSTEM; + } + if (ShellCommandLineGetFlag(Package, L"-s")) { + FileAttributesToRemove |= EFI_FILE_SYSTEM; + } + if (ShellCommandLineGetFlag(Package, L"+h")) { + FileAttributesToAdd |= EFI_FILE_HIDDEN; + } + if (ShellCommandLineGetFlag(Package, L"-h")) { + FileAttributesToRemove |= EFI_FILE_HIDDEN; + } + if (ShellCommandLineGetFlag(Package, L"+r")) { + FileAttributesToAdd |= EFI_FILE_READ_ONLY; + } + if (ShellCommandLineGetFlag(Package, L"-r")) { + FileAttributesToRemove |= EFI_FILE_READ_ONLY; + } + + if (FileAttributesToRemove == 0 && FileAttributesToAdd == 0) { + // + // Do display as we have no attributes to change + // + for ( ParamNumberCount = 1 + ; + ; ParamNumberCount++ + ){ + FileName = ShellCommandLineGetRawValue(Package, ParamNumberCount); + // if we dont have anything left, move on... + if (FileName == NULL && ParamNumberCount == 1) { + FileName = (CHAR16*)AllFiles; + } else if (FileName == NULL) { + break; + } + ASSERT(ListOfFiles == NULL); + Status = ShellOpenFileMetaArg((CHAR16*)FileName, EFI_FILE_MODE_READ, &ListOfFiles); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (FileNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ListOfFiles->Link) + ; !IsNull(&ListOfFiles->Link, &FileNode->Link) + ; FileNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ListOfFiles->Link, &FileNode->Link) + ){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_ATTRIB_OUTPUT_LINE), + gShellLevel2HiiHandle, + FileNode->Info->Attribute&EFI_FILE_DIRECTORY? L'D':L' ', + FileNode->Info->Attribute&EFI_FILE_ARCHIVE? L'A':L' ', + FileNode->Info->Attribute&EFI_FILE_SYSTEM? L'S':L' ', + FileNode->Info->Attribute&EFI_FILE_HIDDEN? L'H':L' ', + FileNode->Info->Attribute&EFI_FILE_READ_ONLY? L'R':L' ', + FileNode->FileName + ); + } + Status = ShellCloseFileMetaArg(&ListOfFiles); + ListOfFiles = NULL; + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_CLOSE_FAIL), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for handling wildcard filenames + } // for loop for printing out the info + } else if ((FileAttributesToRemove & FileAttributesToAdd) != 0) { + // + // fail as we have conflcting params. + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // enumerate through all the files/directories and apply the attributes + // + for ( ParamNumberCount = 1 + ; + ; ParamNumberCount++ + ){ + FileName = ShellCommandLineGetRawValue(Package, ParamNumberCount); + // if we dont have anything left, move on... + if (FileName == NULL) { + // + // make sure we are not failing on the first one we do... if yes that's an error... + // + if (ParamNumberCount == 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } + break; + } + + // + // OpenFileByName / GetFileInfo / Change attributes / SetFileInfo / CloseFile / free memory + // for each file or directory on the line. + // + + // + // Open the file(s) + // + ASSERT(ListOfFiles == NULL); + Status = ShellOpenFileMetaArg((CHAR16*)FileName, EFI_FILE_MODE_READ, &ListOfFiles); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (FileNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ListOfFiles->Link) + ; !IsNull(&ListOfFiles->Link, &FileNode->Link) + ; FileNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ListOfFiles->Link, &FileNode->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(FileNode->FileName, L".") == 0 || StrCmp(FileNode->FileName, L"..") == 0) { + continue; + } + + FileInfo = gEfiShellProtocol->GetFileInfo(FileNode->Handle); + + // + // if we are removing Read-Only we need to do that alone + // + if ((FileAttributesToRemove & EFI_FILE_READ_ONLY) == EFI_FILE_READ_ONLY) { + FileInfo->Attribute &= ~EFI_FILE_READ_ONLY; + // + // SetFileInfo + // + Status = ShellSetFileInfo(FileNode->Handle, FileInfo); + if (EFI_ERROR(Status)) {; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_ACCESS_DENIED; + } + } + + // + // change the attribute + // + FileInfo->Attribute &= ~FileAttributesToRemove; + FileInfo->Attribute |= FileAttributesToAdd; + + // + // SetFileInfo + // + Status = ShellSetFileInfo(FileNode->Handle, FileInfo); + if (EFI_ERROR(Status)) {; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_ACCESS_DENIED; + } + + SHELL_FREE_NON_NULL(FileInfo); + } + Status = ShellCloseFileMetaArg(&ListOfFiles); + ListOfFiles = NULL; + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_CLOSE_FAIL), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamNumberCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for handling wildcard filenames + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c new file mode 100644 index 0000000000..78403c2274 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c @@ -0,0 +1,218 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +/** + Function for 'cd' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *Directory; + CHAR16 *Path; + CHAR16 *Drive; + UINTN DriveSize; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + SHELL_FILE_HANDLE Handle; + CONST CHAR16 *Param1; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + Drive = NULL; + DriveSize = 0; + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } + + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // remember that param 0 is the command name + // If there are 0 value parameters, then print the current directory + // else If there are 2 value parameters, then print the error message + // else If there is 1 value paramerer , then change the directory + // + Param1 = ShellCommandLineGetRawValue(Package, 1); + if (Param1 == NULL) { + // + // display the current directory + // + Directory = ShellGetCurrentDir(NULL); + if (Directory != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_PRINT), gShellLevel2HiiHandle, Directory); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } + } else { + if (StrCmp(Param1, L".") == 0) { + // + // nothing to do... change to current directory + // + } else if (StrCmp(Param1, L"..") == 0) { + // + // Change up one directory... + // + Directory = ShellGetCurrentDir(NULL); + if (Directory == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } else { + Drive = GetFullyQualifiedPath(Directory); + ChopLastSlash(Drive); + } + if (ShellStatus == SHELL_SUCCESS && Drive != NULL) { + // + // change directory on current drive letter + // + Status = gEfiShellProtocol->SetCurDir(NULL, Drive); + if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } + } + } else if (StrCmp(Param1, L"\\") == 0) { + // + // Move to root of current drive + // + Directory = ShellGetCurrentDir(NULL); + if (Directory == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } else { + Drive = GetFullyQualifiedPath(Directory); + while (ChopLastSlash(Drive)) ; + } + if (ShellStatus == SHELL_SUCCESS && Drive != NULL) { + // + // change directory on current drive letter + // + Status = gEfiShellProtocol->SetCurDir(NULL, Drive); + if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } + } + } else if (StrStr(Param1, L":") == NULL) { + if (ShellGetCurrentDir(NULL) == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } else { + ASSERT((Drive == NULL && DriveSize == 0) || (Drive != NULL)); + Drive = StrnCatGrow(&Drive, &DriveSize, ShellGetCurrentDir(NULL), 0); + if (*Param1 == L'\\') { + while (ChopLastSlash(Drive)) ; + Drive = StrnCatGrow(&Drive, &DriveSize, Param1+1, 0); + } else { + Drive = StrnCatGrow(&Drive, &DriveSize, Param1, 0); + } + // + // Verify that this is a valid directory + // + Status = gEfiShellProtocol->OpenFileByName(Drive, &Handle, EFI_FILE_MODE_READ); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, Drive); + ShellStatus = SHELL_NOT_FOUND; + } else if (EFI_ERROR(FileHandleIsDirectory(Handle))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, Drive); + ShellStatus = SHELL_NOT_FOUND; + } + if (ShellStatus == SHELL_SUCCESS && Drive != NULL) { + // + // change directory on current drive letter + // + Status = gEfiShellProtocol->SetCurDir(NULL, Drive); + if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle); + ShellStatus = SHELL_NOT_FOUND; + } + } + if (Handle != NULL) { + gEfiShellProtocol->CloseFile(Handle); + DEBUG_CODE(Handle = NULL;); + } + } + } else { + // + // change directory on other drive letter + // + Drive = AllocateZeroPool(StrSize(Param1)); + Drive = StrCpy(Drive, Param1); + Path = StrStr(Drive, L":"); + *(++Path) = CHAR_NULL; + Status = gEfiShellProtocol->SetCurDir(Drive, ++Path); + + if (Status == EFI_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle); + Status = SHELL_NOT_FOUND; + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, Param1); + Status = SHELL_NOT_FOUND; + } + } + } + } + + if (Drive != NULL) { + FreePool(Drive); + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c new file mode 100644 index 0000000000..e35bf18824 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c @@ -0,0 +1,599 @@ +/** @file + Main file for cp shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +// this is later in the file. +SHELL_STATUS +EFIAPI +ValidateAndCopyFiles( + IN CONST EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode, + IN VOID **Resp + ); + +/** + Function to Copy one file to another location + + If the destination exists the user will be prompted and the result put into *resp + + @param[in] Source pointer to source file name + @param[in] Dest pointer to destination file name + @param[out] Resp pointer to response from question. Pass back on looped calling + @param[in] SilentMode whether to run in quiet mode or not + + @retval SHELL_SUCCESS The source file was copied to the destination +**/ +SHELL_STATUS +EFIAPI +CopySingleFile( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Dest, + OUT VOID **Resp, + IN BOOLEAN SilentMode + ) +{ + VOID *Response; + UINTN ReadSize; + SHELL_FILE_HANDLE SourceHandle; + SHELL_FILE_HANDLE DestHandle; + EFI_STATUS Status; + VOID *Buffer; + CHAR16 *TempName; + UINTN Size; + EFI_SHELL_FILE_INFO *List; + SHELL_STATUS ShellStatus; + + + ASSERT(Resp != NULL); + + SourceHandle = NULL; + DestHandle = NULL; + Response = *Resp; + List = NULL; + + ReadSize = PcdGet16(PcdShellFileOperationSize); + // Why bother copying a file to itself + if (StrCmp(Source, Dest) == 0) { + return (SHELL_SUCCESS); + } + + // + // Open destination file without create + // + Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); + + // + // close file + // + if (DestHandle != NULL) { + ShellCloseFile(&DestHandle); + DestHandle = NULL; + } + + // + // if the destination file existed check response and possibly prompt user + // + if (!EFI_ERROR(Status)) { + if (Response == NULL && !SilentMode) { + Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_CP_PROMPT), gShellLevel2HiiHandle, &Response); + } + // + // possibly return based on response + // + if (!SilentMode) { + switch (*(SHELL_PROMPT_RESPONSE*)Response) { + case ShellPromptResponseNo: + // + // return success here so we dont stop the process + // + return (SHELL_SUCCESS); + case ShellPromptResponseCancel: + *Resp = Response; + // + // indicate to stop everything + // + return (SHELL_ABORTED); + case ShellPromptResponseAll: + *Resp = Response; + case ShellPromptResponseYes: + break; + } + } + } + + if (ShellIsDirectory(Source) == EFI_SUCCESS) { + Status = ShellCreateDirectory(Dest, &DestHandle); + if (EFI_ERROR(Status)) { + return (SHELL_ACCESS_DENIED); + } + + // + // Now copy all the files under the directory... + // + TempName = NULL; + Size = 0; + StrnCatGrow(&TempName, &Size, Source, 0); + StrnCatGrow(&TempName, &Size, L"\\*", 0); + ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List); + TempName = NULL; + StrnCatGrow(&TempName, &Size, Dest, 0); + StrnCatGrow(&TempName, &Size, L"\\", 0); + ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp); + ShellCloseFileMetaArg(&List); + FreePool(TempName); + Size = 0; + } else { + // + // open file with create enabled + // + Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); + if (EFI_ERROR(Status)) { + return (SHELL_ACCESS_DENIED); + } + + // + // open source file + // + Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0); + ASSERT_EFI_ERROR(Status); + + // + // copy data between files + // + Buffer = AllocateZeroPool(ReadSize); + ASSERT(Buffer != NULL); + while (ReadSize == PcdGet16(PcdShellFileOperationSize) && !EFI_ERROR(Status)) { + Status = ShellReadFile(SourceHandle, &ReadSize, Buffer); + ASSERT_EFI_ERROR(Status); + Status = ShellWriteFile(DestHandle, &ReadSize, Buffer); + } + } + + // + // close files + // + if (DestHandle != NULL) { + ShellCloseFile(&DestHandle); + DestHandle = NULL; + } + if (SourceHandle != NULL) { + ShellCloseFile(&SourceHandle); + SourceHandle = NULL; + } + + // + // return + // + return (SHELL_SUCCESS); +} + +/** + function to take a list of files to copy and a destination location and do + the verification and copying of those files to that location. This function + will report any errors to the user and halt. + + The key is to have this function called ONLY once. this allows for the parameter + verification to happen correctly. + + @param[in] FileList A LIST_ENTRY* based list of files to move + @param[in] DestDir the destination location + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_SECURITY_VIOLATION a security violation ocurred + @retval SHELL_WRITE_PROTECTED the destination was write protected + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +SHELL_STATUS +EFIAPI +ValidateAndCopyFiles( + IN CONST EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode, + IN VOID **Resp + ) +{ + CHAR16 *HiiOutput; + CHAR16 *HiiResultOk; + CONST EFI_SHELL_FILE_INFO *Node; + SHELL_STATUS ShellStatus; + CHAR16 *DestPath; + VOID *Response; + UINTN PathLen; + CONST CHAR16 *Cwd; + CONST CHAR16 *TempLocation; + UINTN NewSize; + + if (Resp == NULL) { + Response = NULL; + } else { + Response = *Resp; + } + + DestPath = NULL; + ShellStatus = SHELL_SUCCESS; + PathLen = 0; + Cwd = ShellGetCurrentDir(NULL); + + ASSERT(FileList != NULL); + ASSERT(DestDir != NULL); + + // + // If we are trying to copy multiple files... make sure we got a directory for the target... + // + if (EFI_ERROR(ShellIsDirectory(DestDir)) && FileList->Link.ForwardLink != FileList->Link.BackLink) { + // + // Error for destination not a directory + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir); + return (SHELL_INVALID_PARAMETER); + } + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + NewSize = StrSize(DestDir); + NewSize += StrSize(Node->FileName); + NewSize += StrSize(Cwd); + if (NewSize > PathLen) { + PathLen = NewSize; + } + + // + // Make sure got -r if required + // + if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + // + // make sure got dest as dir if needed + // + if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(DestDir))) { + // + // Error for destination not a directory + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir); + return (SHELL_INVALID_PARAMETER); + } + } + + HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL); + HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); + DestPath = AllocatePool(PathLen); + + // + // Go through the list of files to copy... + // + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag()) { + break; + } + ASSERT(Node->FileName != NULL); + ASSERT(Node->FullName != NULL); + + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item + && EFI_ERROR(ShellIsDirectory(DestDir)) // not an existing directory + ) { + ASSERT(StrStr(DestDir, L":") == NULL); + // + // simple copy of a single file + // + StrCpy(DestPath, Cwd); + if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') { + StrCat(DestPath, L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCat(DestPath, DestDir); + } else { + // + // we have multiple files or a directory in the DestDir + // + if (StrStr(DestDir, L":") == NULL) { + StrCpy(DestPath, Cwd); + if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') { + StrCat(DestPath, L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCat(DestPath, DestDir); + if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') { + StrCat(DestPath, L"\\"); + } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCat(DestPath, Node->FileName); + + } else { + StrCpy(DestPath, DestDir); + if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') { + StrCat(DestPath, L"\\"); + } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') { + ((CHAR16*)DestDir)[StrLen(DestDir)-1] = CHAR_NULL; + } + StrCat(DestPath, Node->FileName); + } + } + + // + // Make sure the path exists + // + if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle); + ShellStatus = SHELL_DEVICE_ERROR; + break; + } + + if ( !EFI_ERROR(ShellIsDirectory(Node->FullName)) + && !EFI_ERROR(ShellIsDirectory(DestPath)) + && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + if ((TempLocation = StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName))) == 0 + && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\') + ) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + CleanPath(DestPath); + + ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath); + + // + // copy single file... + // + ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode); + if (ShellStatus != SHELL_SUCCESS) { + break; + } + } + if (ShellStatus == SHELL_SUCCESS && Resp == NULL) { + ShellPrintEx(-1, -1, L"%s", HiiResultOk); + } + + SHELL_FREE_NON_NULL(DestPath); + SHELL_FREE_NON_NULL(HiiOutput); + SHELL_FREE_NON_NULL(HiiResultOk); + if (Resp != NULL) { + SHELL_FREE_NON_NULL(Response); + } + + return (ShellStatus); +} + +SHELL_STATUS +EFIAPI +ProcessValidateAndCopyFiles( + IN EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir, + IN BOOLEAN SilentMode, + IN BOOLEAN RecursiveMode + ) +{ + SHELL_STATUS ShellStatus; + EFI_SHELL_FILE_INFO *List; + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + + List = NULL; + + Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List); + if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir); + ShellStatus = SHELL_INVALID_PARAMETER; + ShellCloseFileMetaArg(&List); + } else if (List != NULL) { + ASSERT(List != NULL); + ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL); + ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL); + FileInfo = NULL; + FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle); + ASSERT(FileInfo != NULL); + if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) { + ShellStatus = ValidateAndCopyFiles(FileList, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, SilentMode, RecursiveMode, NULL); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle); + ShellStatus = SHELL_ACCESS_DENIED; + } + SHELL_FREE_NON_NULL(FileInfo); + ShellCloseFileMetaArg(&List); + } else { + ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL); + } + + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'cp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + UINTN LoopCounter; + EFI_SHELL_FILE_INFO *FileList; + BOOLEAN SilentMode; + BOOLEAN RecursiveMode; + CONST CHAR16 *Cwd; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + // + // Initialize SilentMode and RecursiveMode + // + if (gEfiShellProtocol->BatchIsActive()) { + SilentMode = TRUE; + } else { + SilentMode = ShellCommandLineGetFlag(Package, L"-q"); + } + RecursiveMode = ShellCommandLineGetFlag(Package, L"-r"); + + switch (ParamCount = ShellCommandLineGetCount(Package)) { + case 0: + case 1: + // + // we have insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + case 2: + // + // must have valid CWD for single parameter... + // + Cwd = ShellGetCurrentDir(NULL); + if (Cwd == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } else { + ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode); + } + } + + break; + default: + // + // Make a big list of all the files... + // + for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) { + if (ShellGetExecutionBreakFlag()) { + break; + } + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } + } + // + // now copy them all... + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + ShellStatus = ProcessValidateAndCopyFiles(FileList, ShellCommandCleanPath((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode); + Status = ShellCloseFileMetaArg(&FileList); + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT); + ShellStatus = SHELL_ACCESS_DENIED; + } + } + + break; + } // switch on parameter count + + if (FileList != NULL) { + ShellCloseFileMetaArg(&FileList); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c new file mode 100644 index 0000000000..1e29ad62e1 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Load.c @@ -0,0 +1,282 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +// This function was from from the BdsLib implementation in +// IntelFrameworkModulePkg\Library\GenericBdsLib\BdsConnect.c +// function name: BdsLibConnectAllEfi +/** + This function will connect all current system handles recursively. The + connection will finish until every handle's child handle created if it have. + + @retval EFI_SUCCESS All handles and it's child handle have been + connected + @retval EFI_STATUS Return the status of gBS->LocateHandleBuffer(). + +**/ +EFI_STATUS +EFIAPI +ConnectAllEfi ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + Status = gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + +/** + function to load a .EFI driver into memory and possible connect the driver. + + if FileName is NULL then ASSERT. + + @param[in] FileName FileName of the driver to load + @param[in] Connect Whether to connect or not + + @retval EFI_SUCCESS the driver was loaded and if Connect was + true then connect was attempted. Connection may + have failed. + @retval EFI_OUT_OF_RESOURCES there was insufficient memory +**/ +EFI_STATUS +EFIAPI +LoadDriver( + IN CONST CHAR16 *FileName, + IN CONST BOOLEAN Connect + ) +{ + EFI_HANDLE LoadedDriverHandle; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *Node; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_LOADED_IMAGE_PROTOCOL *LoadedDriverImage; + + LoadedDriverImage = NULL; + FilePath = NULL; + Node = NULL; + LoadedDriverHandle = NULL; + Status = EFI_SUCCESS; + + ASSERT (FileName != NULL); + + // + // Fix local copies of the protocol pointers + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // Convert to DEVICE_PATH + // + FilePath = gEfiShellProtocol->GetDevicePathFromFilePath(FileName); + + if (FilePath == NULL) { + ASSERT(FALSE); + return (EFI_INVALID_PARAMETER); + } + + // + // Use LoadImage to get it into memory + // + Status = gBS->LoadImage( + FALSE, + gImageHandle, + FilePath, + NULL, + 0, + &LoadedDriverHandle); + + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_IMAGE), gShellLevel2HiiHandle, FileName, Status); + } else { + // + // Make sure it is a driver image + // + Status = gBS->HandleProtocol (LoadedDriverHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &LoadedDriverImage); + + ASSERT (LoadedDriverImage != NULL); + + if ( EFI_ERROR(Status) + || ( LoadedDriverImage->ImageCodeType != EfiBootServicesCode + && LoadedDriverImage->ImageCodeType != EfiRuntimeServicesCode) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_DRIVER), gShellLevel2HiiHandle, FileName); + + // + // Exit and unload the non-driver image + // + gBS->Exit(LoadedDriverHandle, EFI_INVALID_PARAMETER, 0, NULL); + Status = EFI_INVALID_PARAMETER; + } + } + + if (!EFI_ERROR(Status)) { + // + // Start the image + // + Status = gBS->StartImage(LoadedDriverHandle, NULL, NULL); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_ERROR), gShellLevel2HiiHandle, FileName, Status); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_LOADED), gShellLevel2HiiHandle, FileName, LoadedDriverImage->ImageBase, Status); + } + } + + if (!EFI_ERROR(Status) && Connect) { + // + // Connect it... + // + Status = ConnectAllEfi(); + } + + // + // clean up memory... + // + if (FilePath != NULL) { + FreePool(FilePath); + } + + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM LoadParamList[] = { + {L"-nc", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'load' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoad ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *ListHead; + EFI_SHELL_FILE_INFO *Node; + + ListHead = NULL; + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (LoadParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we didnt get a single file to load parameter + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + for ( ParamCount = 1 + ; ShellCommandLineGetRawValue(Package, ParamCount) != NULL + ; ParamCount++ + ){ + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount), EFI_FILE_MODE_READ, &ListHead); + if (!EFI_ERROR(Status)) { + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + // + // once we have an error preserve that value, but finish the loop. + // + if (EFI_ERROR(Status)) { + LoadDriver(Node->FullName, ShellCommandLineGetFlag(Package, L"-nc")); + } else { + Status = LoadDriver(Node->FullName, ShellCommandLineGetFlag(Package, L"-nc")); + } + } // for loop for multi-open + if (EFI_ERROR(Status)) { + ShellCloseFileMetaArg(&ListHead); + } else { + Status = ShellCloseFileMetaArg(&ListHead);; + } + } else { + // + // no files found. + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, (CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)); + ShellStatus = SHELL_NOT_FOUND; + } + } // for loop for params + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_DEVICE_ERROR; + } + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c new file mode 100644 index 0000000000..61d48977f1 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c @@ -0,0 +1,564 @@ +/** @file + Main file for ls shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" +#include + +/** + print out the list of files and directories from the LS command + + @param[in] Rec TRUE to automatically recurse into each found directory + FALSE to only list the specified directory. + @param[in] Attribs List of required Attribute for display. + If 0 then all non-system and non-hidden files will be printed. + @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise + @param[in] Path String with starting path. + @param[in] First TRUE for the original and FALSE for any recursion spawned instances. + @param[in] Count The count of bits enabled in Attribs. + @param[in] TimeZone The current time zone offset. + + @retval SHELL_SUCCESS the printing was sucessful. +**/ +SHELL_STATUS +EFIAPI +PrintLsOutput( + IN CONST BOOLEAN Rec, + IN CONST UINT64 Attribs, + IN CONST BOOLEAN Sfo, + IN CONST CHAR16 *Path, + IN CONST BOOLEAN First, + IN CONST UINTN Count, + IN CONST INT16 TimeZone + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *ListHead; + EFI_SHELL_FILE_INFO *Node; + SHELL_STATUS ShellStatus; + UINT64 FileCount; + UINT64 DirCount; + UINT64 FileSize; + CHAR16 *DirectoryName; + UINTN LongestPath; + EFI_FILE_SYSTEM_INFO *SysInfo; + UINTN SysInfoSize; + SHELL_FILE_HANDLE ShellFileHandle; + CHAR16 *CorrectedPath; + EFI_FILE_PROTOCOL *EfiFpHandle; + + FileCount = 0; + DirCount = 0; + FileSize = 0; + ListHead = NULL; + ShellStatus = SHELL_SUCCESS; + LongestPath = 0; + CorrectedPath = NULL; + + CorrectedPath = StrnCatGrow(&CorrectedPath, NULL, Path, 0); + ASSERT(CorrectedPath != NULL); + ShellCommandCleanPath(CorrectedPath); + + Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + if (ListHead == NULL || IsListEmpty(&ListHead->Link)) { + // + // On the first one only we expect to find something... + // do we find the . and .. directories otherwise? + // + if (First) { + return (SHELL_NOT_FOUND); + } + return (SHELL_SUCCESS); + } + + if (Sfo && First) { + // + // Get the first valid handle (directories) + // + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) && Node->Handle == NULL + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ); + + if (Node->Handle == NULL) { + DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link))->FullName); + + // + // We need to open something up to get system information + // + Status = gEfiShellProtocol->OpenFileByName( + DirectoryName, + &ShellFileHandle, + EFI_FILE_MODE_READ); + + ASSERT_EFI_ERROR(Status); + FreePool(DirectoryName); + + // + // Get the Volume Info from ShellFileHandle + // + SysInfo = NULL; + SysInfoSize = 0; + EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + } + + ASSERT_EFI_ERROR(Status); + + gEfiShellProtocol->CloseFile(ShellFileHandle); + } else { + // + // Get the Volume Info from Node->Handle + // + SysInfo = NULL; + SysInfoSize = 0; + EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + + if (Status == EFI_BUFFER_TOO_SMALL) { + SysInfo = AllocateZeroPool(SysInfoSize); + Status = EfiFpHandle->GetInfo( + EfiFpHandle, + &gEfiFileSystemInfoGuid, + &SysInfoSize, + SysInfo); + } + + ASSERT_EFI_ERROR(Status); + } + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_GEN_SFO_HEADER), + gShellLevel2HiiHandle, + L"ls"); + // + // print VolumeInfo table + // + ASSERT(SysInfo != NULL); + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_SFO_VOLINFO), + gShellLevel2HiiHandle, + SysInfo->VolumeLabel, + SysInfo->VolumeSize, + SysInfo->ReadOnly?L"TRUE":L"FALSE", + SysInfo->FreeSpace, + SysInfo->BlockSize + ); + if (SysInfo != NULL) { + FreePool(SysInfo); + } + } + + if (!Sfo) { + // + // get directory name from path... + // + DirectoryName = GetFullyQualifiedPath(CorrectedPath); + + // + // print header + // + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_HEADER_LINE1), + gShellLevel2HiiHandle, + DirectoryName + ); + FreePool(DirectoryName); + } + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + ASSERT(Node != NULL); + if (LongestPath < StrSize(Node->FullName)) { + LongestPath = StrSize(Node->FullName); + } + ASSERT(Node->Info != NULL); + ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute); + if (Attribs == 0) { + // + // NOT system & NOT hidden + // + if ( (Node->Info->Attribute & EFI_FILE_SYSTEM) + || (Node->Info->Attribute & EFI_FILE_HIDDEN) + ){ + continue; + } + } else if (Attribs != EFI_FILE_VALID_ATTR) { + if (Count == 1) { + // + // the bit must match + // + if ( (Node->Info->Attribute & Attribs) != Attribs) { + continue; + } + } else { + // + // exact match on all bits + // + if ( Node->Info->Attribute != Attribs) { + continue; + } + } + } + + if (Sfo) { + // + // Print the FileInfo Table + // + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_LS_SFO_FILEINFO), + gShellLevel2HiiHandle, + Node->FullName, + Node->Info->FileSize, + Node->Info->PhysicalSize, + (Node->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"", + (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"", + (Node->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"", + (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"", + (Node->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"", + Node->Info->CreateTime.Hour, + Node->Info->CreateTime.Minute, + Node->Info->CreateTime.Second, + Node->Info->CreateTime.Day, + Node->Info->CreateTime.Month, + Node->Info->CreateTime.Year, + Node->Info->LastAccessTime.Hour, + Node->Info->LastAccessTime.Minute, + Node->Info->LastAccessTime.Second, + Node->Info->LastAccessTime.Day, + Node->Info->LastAccessTime.Month, + Node->Info->LastAccessTime.Year, + Node->Info->ModificationTime.Hour, + Node->Info->ModificationTime.Minute, + Node->Info->ModificationTime.Second, + Node->Info->ModificationTime.Day, + Node->Info->ModificationTime.Month, + Node->Info->ModificationTime.Year + ); + } else { + // + // print this one out... + // first print the universal start, next print the type specific name format, last print the CRLF + // + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_START_ALL), + gShellLevel2HiiHandle, + &Node->Info->ModificationTime, + (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"":L"", + (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ', + Node->Info->FileSize + ); + if (Node->Info->Attribute & EFI_FILE_DIRECTORY) { + DirCount++; + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_DIR), + gShellLevel2HiiHandle, + Node->FileName + ); + } else { + FileCount++; + FileSize += Node->Info->FileSize; + if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0) + || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0) + ){ + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_EXE), + gShellLevel2HiiHandle, + Node->FileName + ); + } else { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_LINE_END_FILE), + gShellLevel2HiiHandle, + Node->FileName + ); + } + } + } + } + + if (!Sfo) { + // + // print footer + // + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_LS_FOOTER_LINE), + gShellLevel2HiiHandle, + FileCount, + FileSize, + DirCount + ); + } + + if (Rec){ + DirectoryName = AllocatePool(LongestPath + 2*sizeof(CHAR16)); + for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link) + ; !IsNull(&ListHead->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link) + ){ + // + // recurse on any directory except the traversing ones... + // + if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) + && StrCmp(Node->FileName, L".") != 0 + && StrCmp(Node->FileName, L"..") != 0 + ){ + StrCpy(DirectoryName, Node->FullName); + StrCat(DirectoryName, L"\\*"); + PrintLsOutput( + Rec, + Attribs, + Sfo, + DirectoryName, + FALSE, + Count, + TimeZone); + } + } + FreePool(DirectoryName); + } + + FreePool(CorrectedPath); + ShellCloseFileMetaArg(&ListHead); + FreePool(ListHead); + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM LsParamList[] = { + {L"-r", TypeFlag}, + {L"-a", TypeStart}, + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'ls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLs ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Attribs; + SHELL_STATUS ShellStatus; + UINT64 RequiredAttributes; + CONST CHAR16 *PathName; + CONST CHAR16 *CurDir; + UINTN Count; + CHAR16 *FullPath; + UINTN Size; + EFI_TIME theTime; + BOOLEAN SfoMode; + + Size = 0; + FullPath = NULL; + ProblemParam = NULL; + Attribs = NULL; + ShellStatus = SHELL_SUCCESS; + RequiredAttributes = 0; + PathName = NULL; + CurDir = NULL; + Count = 0; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Fix local copies of the protocol pointers + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // check for -a + // + if (ShellCommandLineGetFlag(Package, L"-a")) { + for ( Attribs = ShellCommandLineGetValue(Package, L"-a") + ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS + ; Attribs++ + ){ + switch (*Attribs) { + case L'a': + case L'A': + RequiredAttributes |= EFI_FILE_ARCHIVE; + Count++; + continue; + case L's': + case L'S': + RequiredAttributes |= EFI_FILE_SYSTEM; + Count++; + continue; + case L'h': + case L'H': + RequiredAttributes |= EFI_FILE_HIDDEN; + Count++; + continue; + case L'r': + case L'R': + RequiredAttributes |= EFI_FILE_READ_ONLY; + Count++; + continue; + case L'd': + case L'D': + RequiredAttributes |= EFI_FILE_DIRECTORY; + Count++; + continue; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, ShellCommandLineGetValue(Package, L"-a")); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } // switch + } // for loop + // + // if nothing is specified all are specified + // + if (RequiredAttributes == 0) { + RequiredAttributes = EFI_FILE_VALID_ATTR; + } + } // if -a present + if (ShellStatus == SHELL_SUCCESS) { + PathName = ShellCommandLineGetRawValue(Package, 1); + if (PathName == NULL) { + CurDir = gEfiShellProtocol->GetCurDir(NULL); + if (CurDir == NULL) { + ShellStatus = SHELL_NOT_FOUND; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + } + } + if (PathName != NULL) { + ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL)); + StrnCatGrow(&FullPath, &Size, PathName, 0); + if (ShellIsDirectory(PathName) == EFI_SUCCESS) { + StrnCatGrow(&FullPath, &Size, L"\\*", 0); + } + } else { + ASSERT(FullPath == NULL); + StrnCatGrow(&FullPath, NULL, L"*", 0); + } + Status = gRT->GetTime(&theTime, NULL); + ASSERT_EFI_ERROR(Status); + SfoMode = ShellCommandLineGetFlag(Package, L"-sfo"); + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PrintLsOutput( + ShellCommandLineGetFlag(Package, L"-r"), + RequiredAttributes, + SfoMode, + FullPath, + TRUE, + Count, + (INT16)(theTime.TimeZone==2047?0:theTime.TimeZone) + ); + if (ShellStatus == SHELL_NOT_FOUND) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_FILES), gShellLevel2HiiHandle); + } else if (ShellStatus == SHELL_INVALID_PARAMETER) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle); + } else if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle); + } + } + } + } + } + + if (FullPath != NULL) { + FreePool(FullPath); + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c new file mode 100644 index 0000000000..5d6a200c19 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Map.c @@ -0,0 +1,1116 @@ +/** @file + Main file for map shell level 2 command. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" +#include +#include +#include +#include +#include + +BOOLEAN +EFIAPI +SearchList( + IN CONST CHAR16 *List, + IN CONST CHAR16 *MetaTarget, + OUT CHAR16 **FullName OPTIONAL, + IN CONST BOOLEAN Meta, + IN CONST BOOLEAN SkipTrailingNumbers, + IN CONST CHAR16 *Target + + ) +{ + CHAR16 *TempList; + CONST CHAR16 *ListWalker; + BOOLEAN Result; + CHAR16 *TempSpot; + + for (ListWalker = List , TempList = NULL + ; ListWalker != NULL && *ListWalker != CHAR_NULL + ; + ) { + TempList = StrnCatGrow(&TempList, NULL, ListWalker, 0); + ASSERT(TempList != NULL); + TempSpot = StrStr(TempList, Target); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + + while (SkipTrailingNumbers && (ShellIsDecimalDigitCharacter(TempList[StrLen(TempList)-1]) || TempList[StrLen(TempList)-1] == L':')) { + TempList[StrLen(TempList)-1] = CHAR_NULL; + } + + ListWalker = StrStr(ListWalker, Target); + while(ListWalker != NULL && *ListWalker == *Target) { + ListWalker++; + } + if (Meta) { + Result = gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)TempList, (CHAR16*)MetaTarget); + } else { + Result = (BOOLEAN)(StrCmp(TempList, MetaTarget)==0); + } + if (Result) { + if (FullName != NULL) { + *FullName = TempList; + } else { + FreePool(TempList); + } + return (TRUE); + } + FreePool(TempList); + TempList = NULL; + } + + return (FALSE); +} + +EFI_STATUS +EFIAPI +UpdateMapping ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleList; + UINTN Count; + EFI_DEVICE_PATH_PROTOCOL **DevicePathList; + CHAR16 *NewDefaultName; + CHAR16 *NewConsistName; + EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable; + + HandleList = NULL; + Status = EFI_SUCCESS; + + // + // remove mappings that represent removed devices. + // + + // + // Find each handle with Simple File System + // + HandleList = GetHandleListByPotocol(&gEfiSimpleFileSystemProtocolGuid); + if (HandleList != NULL) { + // + // Do a count of the handles + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocatePool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + ASSERT(DevicePathList != NULL); + + for (Count = 0 ; HandleList[Count] != NULL ; Count++) { + DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]); + } + + // + // Sort all DevicePaths + // + PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare); + + ShellCommandConsistMappingInitialize(&ConsistMappingTable); + + // + // Assign new Mappings to remainders + // + for (Count = 0 ; HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) { + // + // Skip ones that already have + // + if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) { + continue; + } + // + // Get default name + // + NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem); + ASSERT(NewDefaultName != NULL); + + // + // Call shell protocol SetMap function now... + // + Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName); + + if (!EFI_ERROR(Status)) { + // + // Now do consistent name + // + NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable); + if (NewConsistName != NULL) { + Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName); + FreePool(NewConsistName); + } + } + + FreePool(NewDefaultName); + } + ShellCommandConsistMappingUnInitialize(ConsistMappingTable); + SHELL_FREE_NON_NULL(HandleList); + SHELL_FREE_NON_NULL(DevicePathList); + + HandleList = NULL; + } else { + Count = (UINTN)-1; + } + // + // Do it all over again for gEfiBlockIoProtocolGuid + // + + return (Status); +} + +CHAR16* +EFIAPI +GetDeviceMediaType ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ACPI_HID_DEVICE_PATH *Acpi; + + // + // Parse the device path: + // Devicepath sub type mediatype + // MEDIA_HANRDDRIVE_DP -> Hard Disk + // MEDIA_CDROM_DP -> CD Rom + // Acpi.HID = 0X0604 -> Floppy + // + if (NULL == DevicePath) { + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); + } + + for (;!IsDevicePathEndType (DevicePath) ;DevicePath = NextDevicePathNode (DevicePath)) { + if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) { + switch (DevicePathSubType (DevicePath)) { + case MEDIA_HARDDRIVE_DP: + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_HARDDISK), NULL); + case MEDIA_CDROM_DP: + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_CDROM), NULL); + } + } else if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH) { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; + if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_FLOPPY), NULL); + } + } + } + + return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); +} + +/** + Function to detemine if a handle has removable storage. + + @param[in] DevicePath DevicePath to test. + + @retval TRUE The handle has removable storage. + @retval FALSE The handle does not have removable storage. +**/ +BOOLEAN +EFIAPI +IsRemoveableDevice ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + if (NULL == DevicePath) { + return FALSE; + } + + while (!IsDevicePathEndType (DevicePath)) { + if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) { + switch (DevicePathSubType (DevicePath)) { + case MSG_USB_DP: + case MSG_SCSI_DP: + return TRUE; + default: + return FALSE; + } + } + DevicePath = NextDevicePathNode (DevicePath); + } + return FALSE; +} + +/** + Function to detemine if a something on the map list matches. + + @param[in] MapList The pointer to the list to test. + @param[in] Specific The pointer to a specific name to test for. + @param[in] TypeString The pointer to the list of types. + @param[in] Normal Always show normal mappings. + @param[in] Consist Always show consistent mappings. + + @retval TRUE The map should be displayed. + @retval FALSE The map should not be displayed. +**/ +BOOLEAN +EFIAPI +MappingListHasType( + IN CONST CHAR16 *MapList, + IN CONST CHAR16 *Specific, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN Normal, + IN CONST BOOLEAN Consist + ) +{ + // + // specific has priority + // + if ( Specific != NULL + && SearchList(MapList, Specific, NULL, TRUE, FALSE, L";")) { + return (TRUE); + } + + if ( Consist + && (SearchList(MapList, L"HD*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"CD*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"F*", NULL, TRUE, TRUE, L";") + ||SearchList(MapList, L"FP*", NULL, TRUE, TRUE, L";"))){ + return (TRUE); + } + + if ( Normal + && (SearchList(MapList, L"FS", NULL, FALSE, TRUE, L";") + ||SearchList(MapList, L"BLK", NULL, FALSE, TRUE, L";"))){ + return (TRUE); + } + + if (TypeString != NULL && SearchList(MapList, TypeString, NULL, TRUE, TRUE, L";")) { + return (TRUE); + } + return (FALSE); +} + + +VOID +EFIAPI +PerformSingleMappingDisplay( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL, + IN CONST EFI_HANDLE Handle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; + CONST CHAR16 *MapList; + CHAR16 *CurrentName; + CHAR16 *MediaType; + CHAR16 *DevPathString; + CHAR16 *TempSpot; + UINTN TempLen; + BOOLEAN Removable; + CONST CHAR16 *TempSpot2; + + DevPath = DevicePathFromHandle(Handle); + DevPathCopy = DevPath; + MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); + if (MapList == NULL) { + return; + } + + if (!MappingListHasType(MapList, Specific, TypeString, Normal, Consist)){ + return; + } + + CurrentName = NULL; + CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0); + TempSpot = StrStr(CurrentName, L";"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + DevPathString = gDevPathToText->ConvertDevicePathToText(DevPath, TRUE, FALSE); + if (!SFO) { + TempLen = StrLen(CurrentName); + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_ENTRY), + gShellLevel2HiiHandle, + CurrentName, + TempLen < StrLen(MapList)?MapList + TempLen+1:L"", + DevPathString + ); + if (Verbose) { + // + // also print handle, media type, removable (y/n), and current directory + // + MediaType = GetDeviceMediaType(DevPath); + if ((TypeString != NULL &&MediaType != NULL && StrStr(TypeString, MediaType) != NULL) || TypeString == NULL) { + Removable = IsRemoveableDevice(DevPath); + TempSpot2 = ShellGetCurrentDir(CurrentName); + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_ENTRY_VERBOSE), + gShellLevel2HiiHandle, + ConvertHandleToHandleIndex(Handle), + MediaType, + Removable?L"Yes":L"No", + TempSpot2 + ); + } + FreePool(MediaType); + } + } else { + TempLen = StrLen(CurrentName); + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_MAP_SFO_MAPPINGS), + gShellLevel2HiiHandle, + CurrentName, + DevPathString, + TempLen < StrLen(MapList)?MapList + TempLen+1:L"" + ); + } + FreePool(DevPathString); + FreePool(CurrentName); + return; +} + +EFI_STATUS +EFIAPI +PerformSingleMappingDelete( + IN CONST CHAR16 *Specific, + IN CONST EFI_HANDLE Handle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; + CONST CHAR16 *MapList; + CHAR16 *CurrentName; + + DevPath = DevicePathFromHandle(Handle); + DevPathCopy = DevPath; + MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); + CurrentName = NULL; + + if (MapList == NULL) { + return (EFI_NOT_FOUND); + } + // + // if there is a specific and its not on the list... + // + if (!SearchList(MapList, Specific, &CurrentName, TRUE, FALSE, L";")) { + return (EFI_NOT_FOUND); + } + return (gEfiShellProtocol->SetMap(NULL, CurrentName)); +} + +/** + Function to display mapping information to the user. + + if Specific is specified then Consist and Normal will be ignored since information will + be printed for the specific item only. + + @param[in] Verbose TRUE to display (extra) verbose information + @param[in] Consist TRUE to display consistent mappings + @param[in] Normal TRUE to display normal (not consist) mappings + @param[in] TypeString pointer to string of filter types + @param[in] SFO TRUE to display output in Standard Output Format + @param[in] Specific pointer to string for specific map to display + + @retval SHELL_SUCCESS the display was printed + @retval SHELL_INVALID_PARAMETER one of Consist or Normal must be TRUE if no Specific + +**/ +CONST CHAR16 Cd[] = L"cd*"; +CONST CHAR16 Hd[] = L"hd*"; +CONST CHAR16 Fp[] = L"fp*"; +CONST CHAR16 F[] = L"F*"; +SHELL_STATUS +EFIAPI +PerformMappingDisplay( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL, + IN CONST BOOLEAN Header + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN BufferSize; + UINTN LoopVar; + CHAR16 *Test; + + if (!Consist && !Normal && Specific == NULL && TypeString == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + return (SHELL_INVALID_PARAMETER); + } + + if (TypeString != NULL) { + Test = (CHAR16*)Cd; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + Test = (CHAR16*)Hd; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + Test = (CHAR16*)Fp; + if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, TypeString); + return (SHELL_INVALID_PARAMETER); + } + } else if (Test == NULL) { + Test = (CHAR16*)F; + } + } + } else { + Test = NULL; + } + + if (Header) { + // + // Print the header + // + if (!SFO) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_HEADER), gShellLevel2HiiHandle); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"map"); + } + } + + BufferSize = 0; + HandleBuffer = NULL; + + // + // Look up all SimpleFileSystems in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocatePool(BufferSize); + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + ASSERT_EFI_ERROR(Status); + ASSERT(HandleBuffer != NULL); + + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < (BufferSize / sizeof(EFI_HANDLE)) + ; LoopVar ++ + ){ + PerformSingleMappingDisplay( + Verbose, + Consist, + Normal, + Test, + SFO, + Specific, + HandleBuffer[LoopVar]); + } + + // + // Look up all BlockIo in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool(HandleBuffer); + HandleBuffer = AllocatePool(BufferSize); + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + ASSERT_EFI_ERROR(Status); + + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + // + // Skip any that were already done... + // + if (gBS->OpenProtocol( + HandleBuffer[LoopVar], + &gEfiDevicePathProtocolGuid, + NULL, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { + continue; + } + PerformSingleMappingDisplay( + Verbose, + Consist, + Normal, + Test, + SFO, + Specific, + HandleBuffer[LoopVar]); + } + FreePool(HandleBuffer); + return (SHELL_SUCCESS); +} + +SHELL_STATUS +EFIAPI +PerformMappingDisplay2( + IN CONST BOOLEAN Verbose, + IN CONST BOOLEAN Consist, + IN CONST BOOLEAN Normal, + IN CONST CHAR16 *TypeString, + IN CONST BOOLEAN SFO, + IN CONST CHAR16 *Specific OPTIONAL + ) +{ + CONST CHAR16 *TypeWalker; + SHELL_STATUS ShellStatus; + CHAR16 *Comma; + + + if (TypeString == NULL) { + return (PerformMappingDisplay(Verbose, Consist, Normal, NULL, SFO, Specific, TRUE)); + } + ShellStatus = SHELL_SUCCESS; + for (TypeWalker = TypeString ; TypeWalker != NULL && *TypeWalker != CHAR_NULL ;) { + Comma = StrStr(TypeWalker, L","); + if (Comma == NULL) { + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } else { + PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } + break; + } else { + *Comma = CHAR_NULL; + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } else { + PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); + } + *Comma = L','; + TypeWalker = Comma + 1; + } + } + + return (ShellStatus); +} + +EFI_STATUS +EFIAPI +PerformMappingDelete( + IN CONST CHAR16 *Specific + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN BufferSize; + UINTN LoopVar; + BOOLEAN Deleted; + + if (Specific == NULL) { + return (EFI_INVALID_PARAMETER); + } + + BufferSize = 0; + HandleBuffer = NULL; + Deleted = FALSE; + + // + // Look up all SimpleFileSystems in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + HandleBuffer = AllocatePool(BufferSize); + Status = gBS->LocateHandle( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + ASSERT_EFI_ERROR(Status); + ASSERT(HandleBuffer != NULL); + + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { + Deleted = TRUE; + } + } + + // + // Look up all BlockIo in the platform + // + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool(HandleBuffer); + HandleBuffer = AllocatePool(BufferSize); + Status = gBS->LocateHandle( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &BufferSize, + HandleBuffer); + } + ASSERT_EFI_ERROR(Status); + + // + // Get the map name(s) for each one. + // + for ( LoopVar = 0 + ; LoopVar < BufferSize / sizeof(EFI_HANDLE) + ; LoopVar ++ + ){ + // + // Skip any that were already done... + // + if (gBS->OpenProtocol( + HandleBuffer[LoopVar], + &gEfiDevicePathProtocolGuid, + NULL, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { + continue; + } + if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { + Deleted = TRUE; + } + } + FreePool(HandleBuffer); + if (!Deleted) { + return (EFI_NOT_FOUND); + } + return (EFI_SUCCESS); +} + +/** + function to add a mapping from mapping. + + This function will get the device path associated with the mapping and call SetMap. + + @param[in] Map The Map to add a mapping for + @param[in] SName The name of the new mapping + + @retval SHELL_SUCCESS the mapping was added + @retval SHELL_INVALID_PARAMETER the device path for Map could not be retrieved. + @return Shell version of a return value from EfiShellProtocol->SetMap + +**/ +SHELL_STATUS +EFIAPI +AddMappingFromMapping( + IN CONST CHAR16 *Map, + IN CONST CHAR16 *SName + ) +{ + CONST EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_STATUS Status; + + if (StrStr(SName, L"*") != NULL + ||StrStr(SName, L"?") != NULL + ||StrStr(SName, L"[") != NULL + ||StrStr(SName, L"]") != NULL) { + return (SHELL_INVALID_PARAMETER); + } + + DevPath = gEfiShellProtocol->GetDevicePathFromMap(Map); + if (DevPath == NULL) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gEfiShellProtocol->SetMap(DevPath, SName); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + return (SHELL_SUCCESS); +} + +/** + function to determine if a string has only numbers and letters + + This is useful for such things as Map names which can only be letters and numbers + + @param[in] String pointer to the string to analyze + + @retval TRUE String has only numbers and letters + @retval FALSE String has at least one other character. +**/ +BOOLEAN +EFIAPI +IsNumberLetterOnly( + IN CONST CHAR16 *String + ) +{ + while(String != NULL && *String != CHAR_NULL) { + if (! ( *String >= L'a' && *String <= L'z' + || *String >= L'A' && *String <= L'Z' + || *String >= L'0' && *String <= L'9') + ){ + return (FALSE); + } + String++; + } + return (TRUE); +} + +/** + function to add a mapping from an EFI_HANDLE. + + This function will get the device path associated with the Handle and call SetMap. + + @param[in] Handle The handle to add a mapping for + @param[in] SName The name of the new mapping + + @retval SHELL_SUCCESS the mapping was added + @retval SHELL_INVALID_PARAMETER SName was not valid for a map name. + @return Shell version of a return value from either + gBS->OpenProtocol or EfiShellProtocol->SetMap + +**/ +SHELL_STATUS +EFIAPI +AddMappingFromHandle( + IN CONST EFI_HANDLE Handle, + IN CONST CHAR16 *SName + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPath; + EFI_STATUS Status; + + if (!IsNumberLetterOnly(SName)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gBS->OpenProtocol( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID**)&DevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + Status = gEfiShellProtocol->SetMap(DevPath, SName); + if (EFI_ERROR(Status)) { + return (SHELL_DEVICE_ERROR); + } + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM MapParamList[] = { + {L"-d", TypeValue}, + {L"-r", TypeFlag}, + {L"-v", TypeFlag}, + {L"-c", TypeFlag}, + {L"-f", TypeFlag}, + {L"-u", TypeFlag}, + {L"-t", TypeValue}, + {L"-sfo", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'map' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *SName; + CONST CHAR16 *Mapping; + EFI_HANDLE MappingAsHandle; + CONST EFI_DEVICE_PATH_PROTOCOL *DevPath; + SHELL_STATUS ShellStatus; + BOOLEAN SfoMode; + BOOLEAN ConstMode; + BOOLEAN NormlMode; + CONST CHAR16 *Param1; + CONST CHAR16 *TypeString; + + ProblemParam = NULL; + Mapping = NULL; + SName = NULL; + DevPath = NULL; + ShellStatus = SHELL_SUCCESS; + MappingAsHandle = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (MapParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + SfoMode = ShellCommandLineGetFlag(Package, L"-sfo"); + ConstMode = ShellCommandLineGetFlag(Package, L"-c"); + NormlMode = ShellCommandLineGetFlag(Package, L"-f"); + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 3) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Deleting a map name... + // + if (ShellCommandLineGetFlag(Package, L"-d")) { + if ( ShellCommandLineGetFlag(Package, L"-r") + || ShellCommandLineGetFlag(Package, L"-v") + || ConstMode + || NormlMode + || ShellCommandLineGetFlag(Package, L"-u") + || ShellCommandLineGetFlag(Package, L"-t") + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + SName = ShellCommandLineGetValue(Package, L"-d"); + if (SName != NULL) { + Status = PerformMappingDelete(SName); + if (EFI_ERROR(Status)) { + switch (Status) { + case EFI_ACCESS_DENIED: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle); + ShellStatus = SHELL_ACCESS_DENIED; + break; + case EFI_NOT_FOUND: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, SName); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } else if ( ShellCommandLineGetFlag(Package, L"-r") +// || ShellCommandLineGetFlag(Package, L"-v") + || ConstMode + || NormlMode + || ShellCommandLineGetFlag(Package, L"-u") + || ShellCommandLineGetFlag(Package, L"-t") + ){ + if ( ShellCommandLineGetFlag(Package, L"-r")) { + // + // Do the reset + // + Status = ShellCommandCreateInitialMappingsAndPaths(); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + if ( ShellStatus == SHELL_SUCCESS && ShellCommandLineGetFlag(Package, L"-u")) { + // + // Do the Update + // + Status = UpdateMapping(); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status); + ShellStatus = SHELL_UNSUPPORTED; + } + } + if (ShellStatus == SHELL_SUCCESS) { + Param1 = ShellCommandLineGetRawValue(Package, 1); + TypeString = ShellCommandLineGetValue(Package, L"-t"); + if (!ConstMode + &&!NormlMode + &&TypeString == NULL + ) { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay( + ShellCommandLineGetFlag(Package, L"-v"), + TRUE, + TRUE, + NULL, + SfoMode, + Param1, + TRUE + ); + } else { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay2( + ShellCommandLineGetFlag(Package, L"-v"), + ConstMode, + NormlMode, + TypeString, + SfoMode, + Param1 + ); + } + } + } else { + // + // adding or displaying (there were no flags) + // + SName = ShellCommandLineGetRawValue(Package, 1); + Mapping = ShellCommandLineGetRawValue(Package, 2); + if ( SName == NULL + && Mapping == NULL + ){ + // + // display only since no flags + // + ShellStatus = PerformMappingDisplay( + ShellCommandLineGetFlag(Package, L"-v"), + TRUE, + TRUE, + NULL, + SfoMode, + NULL, + TRUE + ); + } else if ( SName == NULL + || Mapping == NULL + ){ + // + // Display only the one specified + // + ShellStatus = PerformMappingDisplay( + FALSE, + FALSE, + FALSE, + NULL, + SfoMode, + SName, // note the variable here... + TRUE + ); + } else { + if (ShellIsHexOrDecimalNumber(Mapping, TRUE, FALSE)) { + MappingAsHandle = ConvertHandleIndexToHandle(StrHexToUintn(Mapping)); + } else { + MappingAsHandle = NULL; + } + if (MappingAsHandle == NULL && Mapping[StrLen(Mapping)-1] != L':') { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, Mapping); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (MappingAsHandle != NULL) { + ShellStatus = AddMappingFromHandle(MappingAsHandle, SName); + } else { + ShellStatus = AddMappingFromMapping(Mapping, SName); + } + if (ShellStatus != SHELL_SUCCESS) { + switch (ShellStatus) { + case SHELL_ACCESS_DENIED: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle); + break; + case SHELL_INVALID_PARAMETER: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle); + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, ShellStatus|MAX_BIT); + } + } else { + // + // now do the display... + // + ShellStatus = PerformMappingDisplay( + FALSE, + FALSE, + FALSE, + NULL, + SfoMode, + SName, + TRUE + ); + } // we were sucessful so do an output + } // got a valid map target + } // got 2 variables + } // we are adding a mapping + } // got valid parameters + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c new file mode 100644 index 0000000000..421bd55d6f --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/MkDir.c @@ -0,0 +1,128 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +/** + Function for 'mkdir' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMkDir ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + CONST CHAR16 *NewDirName; + UINTN DirCreateCount; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_FILE_HANDLE FileHandle; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + // + // create a set of directories + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we didnt get a single parameter + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + for ( DirCreateCount = 1 + ; + ; DirCreateCount++ + ){ + // + // loop through each directory specified + // + + NewDirName = ShellCommandLineGetRawValue(Package, DirCreateCount); + if (NewDirName == NULL) { + break; + } + // + // check if that already exists... if yes fail + // + FileHandle = NULL; + Status = ShellOpenFileByName(NewDirName, + &FileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, + EFI_FILE_DIRECTORY + ); + if (!EFI_ERROR(Status)) { + ShellCloseFile(&FileHandle); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MKDIR_ALREADY), gShellLevel2HiiHandle, NewDirName); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } else { + ASSERT(FileHandle == NULL); + // + // create the directory named NewDirName + // + Status = ShellCreateDirectory(NewDirName, &FileHandle); + if (FileHandle != NULL) { + gEfiShellProtocol->CloseFile(FileHandle); + } + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MKDIR_CREATEFAIL), gShellLevel2HiiHandle, NewDirName); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c new file mode 100644 index 0000000000..adb6f99759 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c @@ -0,0 +1,478 @@ +/** @file + Main file for mv shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +/** + Function to validate that moving a specific file (FileName) to a specific + location (DestPath) is valid. + + This function will verify that the destination is not a subdirectory of + FullName, that the Current working Directory is not being moved, and that + the directory is not read only. + + if the move is invalid this function will report the error to StdOut. + + @param FullName [in] The name of the file to move. + @param Cwd [in] The current working directory + @param DestPath [in] The target location to move to + @param Attribute[in] The Attribute of the file + + @retval TRUE The move is valid + @retval FALSE The move is not +**/ +BOOLEAN +EFIAPI +IsValidMove( + IN CONST CHAR16 *FullName, + IN CONST CHAR16 *Cwd, + IN CONST CHAR16 *DestPath, + IN CONST UINT64 Attribute + ) +{ + CHAR16 *Test; + CHAR16 *Test1; + CHAR16 *TestWalker; + UINTN Result; + UINTN TempLen; + if (Cwd != NULL && StrCmp(FullName, Cwd) == 0) { + // + // Invalid move + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle); + return (FALSE); + } + Test = NULL; + Test = StrnCatGrow(&Test, NULL, DestPath, 0); + TestWalker = Test; + ASSERT(TestWalker != NULL); + while(*TestWalker == L'\\') { + TestWalker++; + } + while(TestWalker != NULL && TestWalker[StrLen(TestWalker)-1] == L'\\') { + TestWalker[StrLen(TestWalker)-1] = CHAR_NULL; + } + ASSERT(TestWalker != NULL); + ASSERT(FullName != NULL); + if (StrStr(FullName, TestWalker) != 0) { + TempLen = StrLen(FullName); + if (StrStr(FullName, TestWalker) != FullName // not the first items... (could below it) + && TempLen <= (StrLen(TestWalker) + 1) + && StrStr(FullName+StrLen(TestWalker) + 1, L"\\") == NULL) { + // + // Invalid move + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle); + FreePool(Test); + return (FALSE); + } + } + FreePool(Test); + if (StrStr(DestPath, FullName) != 0 && StrStr(DestPath, FullName) != DestPath) { + // + // Invalid move + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle); + return (FALSE); + } + if ((Attribute & EFI_FILE_READ_ONLY) != 0) { + // + // invalid to move read only + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle); + return (FALSE); + } + Test = StrStr(FullName, L":"); + Test1 = StrStr(DestPath, L":"); + if (Test1 != NULL && Test != NULL) { + *Test = CHAR_NULL; + *Test1 = CHAR_NULL; + Result = StringNoCaseCompare(&FullName, &DestPath); + *Test = L':'; + *Test1 = L':'; + if (Result != 0) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_FS), gShellLevel2HiiHandle); + return (FALSE); + } + } + return (TRUE); +} + +/** + Function to take a destination path that might contain wildcards and verify + that there is only a single possible target (IE we cant have wildcards that + have 2 possible destination). + + if the result is sucessful the caller must free *DestPathPointer. + + @param[in] DestDir The original path to the destination + @param[in,out] DestPathPointer a pointer to the callee allocated final path. + + @retval EFI_INVALID_PARAMETR the DestDir could not be resolved to a location + @retval EFI_INVALID_PARAMETR the DestDir could be resolved to more than 1 location + @retval EFI_SUCCESS the operation was sucessful +**/ +SHELL_STATUS +EFIAPI +GetDestinationLocation( + IN CONST CHAR16 *DestDir, + IN OUT CHAR16 **DestPathPointer, + IN CONST CHAR16 *Cwd + ) +{ + EFI_SHELL_FILE_INFO *DestList; + EFI_SHELL_FILE_INFO *Node; + EFI_STATUS Status; + CHAR16 *DestPath; + CHAR16 *TempLocation; + UINTN NewSize; + + DestList = NULL; + DestPath = NULL; + // + // get the destination path + // + Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList); + if (DestList == NULL || IsListEmpty(&DestList->Link)) { + // + // Not existing... must be renaming + // + if ((TempLocation = StrStr(DestDir, L":")) == NULL) { + NewSize = StrSize(Cwd); + NewSize += StrSize(DestDir); + DestPath = AllocateZeroPool(NewSize); + StrCpy(DestPath, Cwd); + if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') { + StrCat(DestPath, L"\\"); + } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') { + ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; + } + StrCat(DestPath, DestDir); + } else { + ASSERT(DestPath == NULL); + DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0); + } + } else { + Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link); + // + // Make sure there is only 1 node in the list. + // + if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) { + ShellCloseFileMetaArg(&DestList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir); + return (SHELL_INVALID_PARAMETER); + } + if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) { + DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16)); + StrCpy(DestPath, Node->FullName); + StrCat(DestPath, L"\\"); + } else { + // + // cant move onto another file. + // + ShellCloseFileMetaArg(&DestList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir); + return (SHELL_INVALID_PARAMETER); + } + } + + *DestPathPointer = DestPath; + ShellCloseFileMetaArg(&DestList); + + return (SHELL_SUCCESS); +} + +/** + function to take a list of files to move and a destination location and do + the verification and moving of those files to that location. This function + will report any errors to the user and continue to move the rest of the files. + + @param[in] FileList A LIST_ENTRY* based list of files to move + @param[in] DestDir the destination location + + @retval SHELL_SUCCESS the files were all moved. + @retval SHELL_INVALID_PARAMETER a parameter was invalid + @retval SHELL_SECURITY_VIOLATION a security violation ocurred + @retval SHELL_WRITE_PROTECTED the destination was write protected + @retval SHELL_OUT_OF_RESOURCES a memory allocation failed +**/ +SHELL_STATUS +EFIAPI +ValidateAndMoveFiles( + IN CONST EFI_SHELL_FILE_INFO *FileList, + IN CONST CHAR16 *DestDir + ) +{ + EFI_STATUS Status; + CHAR16 *HiiOutput; + CHAR16 *HiiResultOk; + CHAR16 *DestPath; + CONST CHAR16 *Cwd; + SHELL_STATUS ShellStatus; + CONST EFI_SHELL_FILE_INFO *Node; + EFI_FILE_INFO *NewFileInfo; + CHAR16 *TempLocation; + UINTN NewSize; + + ASSERT(FileList != NULL); + ASSERT(DestDir != NULL); + + DestPath = NULL; + Cwd = ShellGetCurrentDir(NULL); + + // + // Get and validate the destination location + // + ShellStatus = GetDestinationLocation(DestDir, &DestPath, Cwd); + if (ShellStatus != SHELL_SUCCESS) { + return (ShellStatus); + } + + HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL); + HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); + ASSERT (DestPath != NULL); + ASSERT (HiiResultOk != NULL); + ASSERT (HiiOutput != NULL); +// ASSERT (Cwd != NULL); + + // + // Go through the list of files and directories to move... + // + for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) + ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) + ){ + if (ShellGetExecutionBreakFlag()) { + break; + } + ASSERT(Node->FileName != NULL); + ASSERT(Node->FullName != NULL); + + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + // + // Validate that the move is valid + // + if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute)) { + ShellStatus = SHELL_INVALID_PARAMETER; + continue; + } + + // + // Chop off map info from "DestPath" + // + if ((TempLocation = StrStr(DestPath, L":")) != NULL) { + CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1)); + } + + // + // construct the new file info block + // + NewSize = StrSize(DestPath); + NewSize += StrSize(Node->FileName) + sizeof(EFI_FILE_INFO) + sizeof(CHAR16); + NewFileInfo = AllocateZeroPool(NewSize); + ASSERT(NewFileInfo != NULL); + CopyMem(NewFileInfo, Node->Info, sizeof(EFI_FILE_INFO)); + if (DestPath[0] != L'\\') { + StrCpy(NewFileInfo->FileName, L"\\"); + StrCat(NewFileInfo->FileName, DestPath); + } else { + StrCpy(NewFileInfo->FileName, DestPath); + } + if (NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] == L'\\') { + if (Node->FileName[0] == L'\\') { + // + // Don't allow for double slashes. Eliminate one of them. + // + NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] = CHAR_NULL; + } + StrCat(NewFileInfo->FileName, Node->FileName); + } + NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFileInfo->FileName); + + ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName); + + // + // Perform the move operation + // + Status = ShellSetFileInfo(Node->Handle, NewFileInfo); + + // + // Free the info object we used... + // + ASSERT (NewFileInfo != NULL); + FreePool(NewFileInfo); + + // + // Check our result + // + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status); + // + // move failed + // + switch(Status){ + default: + ShellStatus = SHELL_INVALID_PARAMETER; + case EFI_SECURITY_VIOLATION: + ShellStatus = SHELL_SECURITY_VIOLATION; + case EFI_WRITE_PROTECTED: + ShellStatus = SHELL_WRITE_PROTECTED; + case EFI_OUT_OF_RESOURCES: + ShellStatus = SHELL_OUT_OF_RESOURCES; + case EFI_DEVICE_ERROR: + ShellStatus = SHELL_DEVICE_ERROR; + case EFI_ACCESS_DENIED: + ShellStatus = SHELL_ACCESS_DENIED; + } // switch + } else { + ShellPrintEx(-1, -1, L"%s", HiiResultOk); + } + } // for loop + + FreePool(DestPath); + FreePool(HiiOutput); + FreePool(HiiResultOk); + return (ShellStatus); +} + +SHELL_STATUS +EFIAPI +ShellCommandRunMv ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + UINTN LoopCounter; + EFI_SHELL_FILE_INFO *FileList; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + + switch (ParamCount = ShellCommandLineGetCount(Package)) { + case 0: + case 1: + // + // we have insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + case 2: + // + // must have valid CWD for single parameter... + // + if (ShellGetCurrentDir(NULL) == NULL){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } else { + // + // ValidateAndMoveFiles will report errors to the screen itself + // + ShellStatus = ValidateAndMoveFiles(FileList, ShellGetCurrentDir(NULL)); + } + } + + break; + default: + ///@todo make sure this works with error half way through and continues... + for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) { + if (ShellGetExecutionBreakFlag()) { + break; + } + Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_NOT_FOUND; + } else { + // + // ValidateAndMoveFiles will report errors to the screen itself + // Only change ShellStatus if it's sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount)); + } else { + ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount)); + } + } + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { + ShellStatus = SHELL_ACCESS_DENIED; + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT); + } + } + } + break; + } // switch on parameter count + + if (FileList != NULL) { + ShellCloseFileMetaArg(&FileList); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c new file mode 100644 index 0000000000..927c8d9729 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c @@ -0,0 +1,190 @@ +/** @file + Main file for Parse shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +SHELL_STATUS +EFIAPI +PerformParsing( + IN CONST CHAR16 *FileName, + IN CONST CHAR16 *TableName, + IN CONST UINTN ColumnIndex, + IN CONST UINTN TableNameInstance, + IN CONST UINTN ShellCommandInstance + ) +{ + SHELL_FILE_HANDLE FileHandle; + EFI_STATUS Status; + BOOLEAN Ascii; + UINTN LoopVariable; + UINTN ColumnLoop; + CHAR16 *TempLine; + CHAR16 *ColumnPointer; + SHELL_STATUS ShellStatus; + CHAR16 *TempSpot; + + ASSERT(FileName != NULL); + ASSERT(TableName != NULL); + + ShellStatus = SHELL_SUCCESS; + + Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, FileName); + ShellStatus = SHELL_NOT_FOUND; + } else { + for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) { + TempLine = ShellFileHandleReturnLine(FileHandle, &Ascii); + if (TempLine == NULL) { + break; + } + if (StrStr(TempLine, L"ShellCommand, \"") == TempLine) { + LoopVariable++; + } + SHELL_FREE_NON_NULL(TempLine); + } + if (LoopVariable == ShellCommandInstance) { + LoopVariable = 0; + while(1) { + TempLine = ShellFileHandleReturnLine(FileHandle, &Ascii); + if ( TempLine == NULL + || *TempLine == CHAR_NULL + || StrStr(TempLine, L"ShellCommand, \"") == TempLine + ){ + SHELL_FREE_NON_NULL(TempLine); + break; + } + if (StrStr(TempLine, TableName) == TempLine) { + LoopVariable++; + } + if ( LoopVariable == TableNameInstance + || (TableNameInstance == (UINTN)-1 && StrStr(TempLine, TableName) == TempLine) + ){ + for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) { + ColumnPointer = StrStr(ColumnPointer, L","); + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){ + ColumnPointer++; + } + } + if (ColumnLoop == ColumnIndex) { + ASSERT(ColumnPointer != NULL); + TempSpot = StrStr(ColumnPointer, L","); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){ + ColumnPointer++; + } + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){ + ColumnPointer++; + } + if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen(ColumnPointer)-1] == L'\"'){ + ColumnPointer[StrLen(ColumnPointer)-1] = CHAR_NULL; + } + + ShellPrintEx(-1, -1, L"%s\r\n", ColumnPointer); + } + } + SHELL_FREE_NON_NULL(TempLine); + } + } + } + return (ShellStatus); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-i", TypeValue}, + {L"-s", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'parse' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunParse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *FileName; + CONST CHAR16 *TableName; + CONST CHAR16 *ColumnString; + SHELL_STATUS ShellStatus; + UINTN ShellCommandInstance; + UINTN TableNameInstance; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + if (ShellCommandLineGetCount(Package) < 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetCount(Package) > 4) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + FileName = ShellCommandLineGetRawValue(Package, 1); + TableName = ShellCommandLineGetRawValue(Package, 2); + ColumnString = ShellCommandLineGetRawValue(Package, 3); + + if (ShellCommandLineGetValue(Package, L"-i") == NULL) { + TableNameInstance = (UINTN)-1; + } else { + TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i")); + } + if (ShellCommandLineGetValue(Package, L"-s") == NULL) { + ShellCommandInstance = 1; + } else { + ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s")); + } + + ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance); + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c new file mode 100644 index 0000000000..d0eea8d033 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Reset.c @@ -0,0 +1,131 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ResetParamList[] = { + {L"-w", TypeValue}, + {L"-s", TypeValue}, + {L"-c", TypeValue}, + {NULL, TypeMax} + }; + +/** + Function for 'reset' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *String; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ResetParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + return (SHELL_INVALID_PARAMETER); + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // check for cold reset flag, then shutdown reset flag, then warm (default) reset flag + // + if (ShellCommandLineGetFlag(Package, L"-c")) { + if (ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-w")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + String = ShellCommandLineGetValue(Package, L"-c"); + if (String != NULL) { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } + } + } else if (ShellCommandLineGetFlag(Package, L"-s")) { + if (ShellCommandLineGetFlag(Package, L"-w")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + String = ShellCommandLineGetValue(Package, L"-s"); + DEBUG_CODE(ShellPrintEx(-1,-1,L"Reset with %s (%d bytes)", String, String!=NULL?StrSize(String):0);); + if (String != NULL) { + gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } + } else { + // + // this is default so dont worry about flag... + // + String = ShellCommandLineGetValue(Package, L"-w"); + if (String != NULL) { + gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, StrSize(String), (VOID*)String); + } else { + gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + } + } + + // + // we should never get here... so the free and return are for formality more than use + // as the ResetSystem function should not return... + // + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c new file mode 100644 index 0000000000..bde710faf0 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c @@ -0,0 +1,296 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +BOOLEAN +EFIAPI +IsDirectoryEmpty ( + IN EFI_HANDLE FileHandle + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + BOOLEAN NoFile; + BOOLEAN RetVal; + + RetVal = TRUE; + NoFile = FALSE; + + for (Status = FileHandleFindFirstFile(FileHandle, &FileInfo) + ; !NoFile + ; Status = FileHandleFindNextFile(FileHandle, FileInfo, &NoFile) + ){ + if (StrStr(FileInfo->FileName, L".") != FileInfo->FileName + &&StrStr(FileInfo->FileName, L"..") != FileInfo->FileName) { + RetVal = FALSE; + } + } + return (RetVal); +} + +SHELL_STATUS +EFIAPI +CascadeDelete( + IN EFI_SHELL_FILE_INFO *Node, + IN CONST BOOLEAN Quiet + ) +{ + SHELL_STATUS ShellStatus; + EFI_SHELL_FILE_INFO *List; + EFI_SHELL_FILE_INFO *Node2; + EFI_STATUS Status; + SHELL_PROMPT_RESPONSE *Resp; + + Resp = NULL; + ShellStatus = SHELL_SUCCESS; + List = NULL; + Status = EFI_SUCCESS; + + if ((Node->Info->Attribute & EFI_FILE_READ_ONLY) == EFI_FILE_READ_ONLY) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DETELE_RO), gShellLevel2HiiHandle, Node->FullName); + return (SHELL_ACCESS_DENIED); + } + + if ((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + if (!IsDirectoryEmpty(Node->Handle)) { + if (!Quiet) { + Status = ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_RM_LOG_DELETE_CONF), gShellLevel2HiiHandle, Node->FullName); + Status = ShellPromptForResponse(ShellPromptResponseTypeYesNo, NULL, (VOID**)&Resp); + ASSERT_EFI_ERROR(Status); + ASSERT(Resp != NULL); + if (EFI_ERROR(Status) || *Resp != ShellPromptResponseYes) { + SHELL_FREE_NON_NULL(Resp); + return (SHELL_ABORTED); + } + SHELL_FREE_NON_NULL(Resp); + } + // + // empty out the directory + // + Status = gEfiShellProtocol->FindFilesInDir(Node->Handle, &List); + if (EFI_ERROR(Status)) { + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + return (SHELL_DEVICE_ERROR); + } + for (Node2 = (EFI_SHELL_FILE_INFO *)GetFirstNode(&List->Link) + ; !IsNull(&List->Link, &Node2->Link) + ; Node2 = (EFI_SHELL_FILE_INFO *)GetNextNode(&List->Link, &Node2->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node2->FileName, L".") == 0 || StrCmp(Node2->FileName, L"..") == 0) { + continue; + } + Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE); + ShellStatus = CascadeDelete(Node2, Quiet); + if (ShellStatus != SHELL_SUCCESS) { + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + return (ShellStatus); + } + } + if (List!=NULL) { + gEfiShellProtocol->FreeFileList(&List); + } + } + } + + if (!(StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0)) { + // + // now delete the current node... + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE), gShellLevel2HiiHandle, Node->FullName); + Status = gEfiShellProtocol->DeleteFile(Node->Handle); + Node->Handle = NULL; + } + + // + // We cant allow for the warning here! + // + if (Status != EFI_SUCCESS){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR), gShellLevel2HiiHandle, Status); + return (SHELL_ACCESS_DENIED); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_COMP), gShellLevel2HiiHandle); + return (SHELL_SUCCESS); + } +} + +BOOLEAN +EFIAPI +IsValidDeleteTarget( + IN CONST EFI_SHELL_FILE_INFO *List, + IN CONST EFI_SHELL_FILE_INFO *Node, + IN CONST LIST_ENTRY *Package + ) +{ + CONST CHAR16 *TempLocation; + CHAR16 *Temp2; + UINTN Size; + + TempLocation = StrStr(Node->FullName, L":"); + if (StrLen(TempLocation) == 2) { + // + // Deleting the root directory is invalid. + // + return (FALSE); + } + TempLocation = ShellGetCurrentDir(NULL); + Size = 0; + Temp2 = NULL; + StrnCatGrow(&Temp2, &Size, TempLocation, 0); + if (StrStr(Temp2, Node->FullName) != NULL) { + FreePool(Temp2); + return (FALSE); + } + FreePool(Temp2); + + return (TRUE); +} + +/** + Function for 'rm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunRm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, (CHAR16*)Param); + ShellStatus = SHELL_NOT_FOUND; + break; + } + } + + if (ShellStatus == SHELL_SUCCESS){ + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // skip the directory traversing stuff... + // + if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { + continue; + } + + // + // do the deleting of nodes + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR2), gShellLevel2HiiHandle, Node->Status); + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + if (!IsValidDeleteTarget(FileList, Node, Package)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR3), gShellLevel2HiiHandle, Node->FullName); + ShellStatus = SHELL_INVALID_PARAMETER; + break; + } + + ShellStatus = CascadeDelete(Node, ShellCommandLineGetFlag(Package, L"-q")); + } + } + // + // Free the fileList + // + if (FileList != NULL) { + Status = ShellCloseFileMetaArg(&FileList); + } + FileList = NULL; + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c new file mode 100644 index 0000000000..a3452f0b62 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Set.c @@ -0,0 +1,169 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +/** + Print out each environment variable registered with the Shell 2.0 GUID. + + If you spawn a pre 2.0 shell from the Shell 2.0 the environment variable may not carry through. + + @retval STATUS_SUCCESS the printout was sucessful + @return any return code from GetNextVariableName except EFI_NOT_FOUND +**/ +SHELL_STATUS +EFIAPI +PrintAllShellEnvVars( + VOID + ) +{ + CONST CHAR16 *Value; + CONST CHAR16 *ConstEnvNameList; + + ConstEnvNameList = gEfiShellProtocol->GetEnv(NULL); + if (ConstEnvNameList == NULL) { + return (SHELL_SUCCESS); + } + while (*ConstEnvNameList != CHAR_NULL){ + Value = gEfiShellProtocol->GetEnv(ConstEnvNameList); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_DISP), gShellLevel2HiiHandle, ConstEnvNameList, Value); + ConstEnvNameList += StrLen(ConstEnvNameList)+1; + } + + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM SetParamList[] = { + {L"-d", TypeValue}, + {L"-v", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'set' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSet ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CONST CHAR16 *KeyName; + CONST CHAR16 *Value; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // Make sure globals are good... + // + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (SetParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + return (SHELL_INVALID_PARAMETER); + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 3) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL && ShellCommandLineGetFlag(Package, L"-d")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-d")) { + // + // delete a environment variable + // + KeyName = ShellCommandLineGetValue(Package, L"-d"); + if (KeyName == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + Status = ShellSetEnvironmentVariable(KeyName, L"", ShellCommandLineGetFlag(Package, L"-v")); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_ND), gShellLevel2HiiHandle, KeyName, Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // print out all current environment variables + // + return(PrintAllShellEnvVars()); + } else { + // + // we are either printing one or assigning one + // + KeyName = ShellCommandLineGetRawValue(Package, 1); + Value = ShellCommandLineGetRawValue(Package, 2); + if (KeyName != NULL && Value != NULL) { + // + // assigning one + // + Status = ShellSetEnvironmentVariable(KeyName, Value, ShellCommandLineGetFlag(Package, L"-v")); + } else { + if (KeyName != NULL) { + // + // print out value for this one only. + // + Value = ShellGetEnvironmentVariable(KeyName); + if (Value == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_NF), gShellLevel2HiiHandle, KeyName); + ShellStatus = SHELL_SUCCESS; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SET_DISP), gShellLevel2HiiHandle, KeyName, Value); + ShellStatus = SHELL_SUCCESS; + } + } else { + ASSERT(FALSE); + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c new file mode 100644 index 0000000000..c8de9cf066 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/TimeDate.c @@ -0,0 +1,772 @@ +/** @file + Main file for time, timezone, and date shell level 2 and shell level 3 functions. + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +INT16 +EFIAPI +AbsVal( + INT16 v + ) +{ + if (v>0) { + return (v); + } + return ((INT16)(-v)); +} + +BOOLEAN +EFIAPI +InternalIsTimeLikeString ( + IN CONST CHAR16 *String, + IN CONST CHAR16 Char, + IN CONST UINTN Min, + IN CONST UINTN Max, + IN CONST BOOLEAN MinusOk + ) +{ + UINTN Count; + Count = 0; + + if (MinusOk) { + // + // A single minus is ok. + // + if (*String == L'-') { + String++; + } + } + + // + // the first char must be numeric. + // + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + // + // loop through the characters and use the lib function + // + for ( ; String != NULL && *String != CHAR_NULL ; String++){ + if (*String == Char) { + Count++; + if (Count > Max) { + return (FALSE); + } + continue; + } + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + } + if (Count < Min) { + return (FALSE); + } + return (TRUE); +} + +SHELL_STATUS +EFIAPI +CheckAndSetDate ( + IN CONST CHAR16 *DateString + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CONST CHAR16 *Walker; + + if (!InternalIsTimeLikeString(DateString, L'/', 2, 2, FALSE)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + + Walker = DateString; + + TheTime.Month = 0xFF; + TheTime.Day = 0xFF; + TheTime.Year = 0xFFFF; + + TheTime.Month = (UINT8)StrDecimalToUintn (Walker); + Walker = StrStr(Walker, L"/"); + if (Walker != NULL && *Walker == L'/') { + Walker = Walker + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Day = (UINT8)StrDecimalToUintn (Walker); + Walker = StrStr(Walker, L"/"); + if (Walker != NULL && *Walker == L'/') { + Walker = Walker + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Year = (UINT16)StrDecimalToUintn (Walker); + } + } + + if (TheTime.Year < 100) { + if (TheTime.Year >= 98) { + TheTime.Year = (UINT16)(1900 + TheTime.Year); + } else { + TheTime.Year = (UINT16)(2000 + TheTime.Year); + } + } + + Status = gRT->SetTime(&TheTime); + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + return (SHELL_INVALID_PARAMETER); +} + +/** + Function for 'date' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDate ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + EFI_TIME TheTime; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (SfoParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // If there are 0 value parameters, then print the current date + // else If there are any value paramerers, then print error + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // get the current date + // + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + + // + // ShellPrintEx the date in SFO or regular format + // + if (ShellCommandLineGetFlag(Package, L"-sfo")) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DATE_SFO_FORMAT), gShellLevel2HiiHandle, TheTime.Month, TheTime.Day, TheTime.Year); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DATE_FORMAT), gShellLevel2HiiHandle, TheTime.Month, TheTime.Day, TheTime.Year); + } + } else { + if (PcdGet8(PcdShellSupportLevel) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // perform level 3 operation here. + // + ShellStatus = CheckAndSetDate(ShellCommandLineGetRawValue(Package, 1)); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + +// +// Note "-tz" is invalid for this (non-interactive) version of 'time'. +// +STATIC CONST SHELL_PARAM_ITEM TimeParamList2[] = { + {L"-d", TypeValue}, + {NULL, TypeMax} + }; + +STATIC CONST SHELL_PARAM_ITEM TimeParamList3[] = { + {L"-d", TypeValue}, + {L"-tz", TypeValue}, + {NULL, TypeMax} + }; + +SHELL_STATUS +EFIAPI +CheckAndSetTime ( + IN CONST CHAR16 *TimeString, + IN CONST INT16 Tz, + IN CONST UINT8 Daylight + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CONST CHAR16 *Walker; + + if (TimeString != NULL && !InternalIsTimeLikeString(TimeString, L':', 1, 2, FALSE)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + + if (TimeString != NULL) { + Walker = TimeString; + TheTime.Hour = 0xFF; + TheTime.Minute = 0xFF; + + TheTime.Hour = (UINT8)StrDecimalToUintn (Walker); + Walker = StrStr(Walker, L":"); + if (Walker != NULL && *Walker == L':') { + Walker = Walker + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Minute = (UINT8)StrDecimalToUintn (Walker); + Walker = StrStr(Walker, L":"); + if (Walker != NULL && *Walker == L':') { + Walker = Walker + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + TheTime.Second = (UINT8)StrDecimalToUintn (Walker); + } + } + } + + if ((Tz >= -1440 && Tz <= 1440)||(Tz == 2047)) { + TheTime.TimeZone = Tz; + } + if (Daylight <= 3 && Daylight != 2) { + TheTime.Daylight = Daylight; + } + Status = gRT->SetTime(&TheTime); + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + + return (SHELL_INVALID_PARAMETER); +} + +/** + Function for 'time' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTime ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *Message; + EFI_TIME TheTime; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + INT16 Tz; + UINT8 Daylight; + CONST CHAR16 *TempLocation; + UINTN TzMinutes; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // Initialize variables + // + Message = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + if (PcdGet8(PcdShellSupportLevel) == 2) { + Status = ShellCommandLineParseEx (TimeParamList2, &Package, &ProblemParam, TRUE, TRUE); + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + Status = ShellCommandLineParseEx (TimeParamList3, &Package, &ProblemParam, TRUE, TRUE); + } + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // If there are no parameters, then print the current time + // + if (ShellCommandLineGetRawValue(Package, 1) == NULL + && !ShellCommandLineGetFlag(Package, L"-d") + && !ShellCommandLineGetFlag(Package, L"-tz")) { + // + // ShellPrintEx the current time + // + if (TheTime.TimeZone == 2047) { + TzMinutes = 0; + } else { + TzMinutes = AbsVal(TheTime.TimeZone) % 60; + } + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second, + TheTime.TimeZone==2047?L" ":(TheTime.TimeZone > 0?L"-":L"+"), + TheTime.TimeZone==2047?0:AbsVal(TheTime.TimeZone) / 60, + TzMinutes + ); + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), gShellLevel2HiiHandle); + } else if (ShellCommandLineGetFlag(Package, L"-d") && ShellCommandLineGetValue(Package, L"-d") == NULL) { + if (TheTime.TimeZone == 2047) { + TzMinutes = 0; + } else { + TzMinutes = AbsVal(TheTime.TimeZone) % 60; + } + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_TIME_FORMAT), + gShellLevel2HiiHandle, + TheTime.Hour, + TheTime.Minute, + TheTime.Second, + TheTime.TimeZone==2047?L" ":(TheTime.TimeZone > 0?L"-":L"+"), + TheTime.TimeZone==2047?0:AbsVal(TheTime.TimeZone) / 60, + TzMinutes + ); + switch (TheTime.Daylight) { + case 0: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DSTNA), gShellLevel2HiiHandle); + break; + case EFI_TIME_ADJUST_DAYLIGHT: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DSTST), gShellLevel2HiiHandle); + break; + case EFI_TIME_IN_DAYLIGHT: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DSTDT), gShellLevel2HiiHandle); + break; + default: + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_ERROR), gShellLevel2HiiHandle, L"gRT->GetTime", L"TheTime.Daylight", TheTime.Daylight); + } + } else { + if (PcdGet8(PcdShellSupportLevel) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // perform level 3 operation here. + // + if ((TempLocation = ShellCommandLineGetValue(Package, L"-tz")) != NULL) { + if (TempLocation[0] == L'-') { + Tz = (INT16)(0 - StrDecimalToUintn(++TempLocation)); + } else { + Tz = (INT16)StrDecimalToUintn(TempLocation); + } + if (!(Tz >= -1440 && Tz <= 1440) && Tz != 2047) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // intentionally out of bounds value will prevent changing it... + // + Tz = 1441; + } + TempLocation = ShellCommandLineGetValue(Package, L"-d"); + if (TempLocation != NULL) { + Daylight = (UINT8)StrDecimalToUintn(TempLocation); + if (Daylight != 0 && Daylight != 1 && Daylight != 3) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"-d"); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } else { + // + // invalid = will not use + // + Daylight = 0xFF; + } + if (ShellStatus == SHELL_SUCCESS) { + ShellStatus = CheckAndSetTime(ShellCommandLineGetRawValue(Package, 1), Tz, Daylight); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1)); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + +typedef struct { + INT16 TimeZone; + EFI_STRING_ID StringId; +} TIME_ZONE_ITEM; + +STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList2[] = { + {L"-l", TypeFlag}, + {L"-f", TypeFlag}, + {NULL, TypeMax} + }; +STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList3[] = { + {L"-l", TypeFlag}, + {L"-f", TypeFlag}, + {L"-s", TypeValue}, + {NULL, TypeMax} + }; + + STATIC CONST TIME_ZONE_ITEM TimeZoneList[] = { + {720, STRING_TOKEN (STR_TIMEZONE_M12)}, + {660, STRING_TOKEN (STR_TIMEZONE_M11)}, + {600, STRING_TOKEN (STR_TIMEZONE_M10)}, + {540, STRING_TOKEN (STR_TIMEZONE_M9)}, + {480, STRING_TOKEN (STR_TIMEZONE_M8)}, + {420, STRING_TOKEN (STR_TIMEZONE_M7)}, + {360, STRING_TOKEN (STR_TIMEZONE_M6)}, + {300, STRING_TOKEN (STR_TIMEZONE_M5)}, + {270, STRING_TOKEN (STR_TIMEZONE_M430)}, + {240, STRING_TOKEN (STR_TIMEZONE_M4)}, + {210, STRING_TOKEN (STR_TIMEZONE_M330)}, + {180, STRING_TOKEN (STR_TIMEZONE_M3)}, + {120, STRING_TOKEN (STR_TIMEZONE_M2)}, + {60 , STRING_TOKEN (STR_TIMEZONE_M1)}, + {0 , STRING_TOKEN (STR_TIMEZONE_0)}, + {-60 , STRING_TOKEN (STR_TIMEZONE_P1)}, + {-120 , STRING_TOKEN (STR_TIMEZONE_P2)}, + {-180 , STRING_TOKEN (STR_TIMEZONE_P3)}, + {-210 , STRING_TOKEN (STR_TIMEZONE_P330)}, + {-240 , STRING_TOKEN (STR_TIMEZONE_P4)}, + {-270 , STRING_TOKEN (STR_TIMEZONE_P430)}, + {-300 , STRING_TOKEN (STR_TIMEZONE_P5)}, + {-330 , STRING_TOKEN (STR_TIMEZONE_P530)}, + {-345 , STRING_TOKEN (STR_TIMEZONE_P545)}, + {-360 , STRING_TOKEN (STR_TIMEZONE_P6)}, + {-390 , STRING_TOKEN (STR_TIMEZONE_P630)}, + {-420 , STRING_TOKEN (STR_TIMEZONE_P7)}, + {-480 , STRING_TOKEN (STR_TIMEZONE_P8)}, + {-540 , STRING_TOKEN (STR_TIMEZONE_P9)}, + {-570 , STRING_TOKEN (STR_TIMEZONE_P930)}, + {-600 , STRING_TOKEN (STR_TIMEZONE_P10)}, + {-660 , STRING_TOKEN (STR_TIMEZONE_P11)}, + {-720 , STRING_TOKEN (STR_TIMEZONE_P12)}, + {-780 , STRING_TOKEN (STR_TIMEZONE_P13)}, + {-840 , STRING_TOKEN (STR_TIMEZONE_P14)} + }; + +SHELL_STATUS +EFIAPI +CheckAndSetTimeZone ( + IN CONST CHAR16 *TimeZoneString + ) +{ + EFI_TIME TheTime; + EFI_STATUS Status; + CONST CHAR16 *Walker; + UINTN LoopVar; + + if (TimeZoneString == NULL) { + return (SHELL_INVALID_PARAMETER); + } + + if (TimeZoneString != NULL && !InternalIsTimeLikeString(TimeZoneString, L':', 1, 1, TRUE)) { + return (SHELL_INVALID_PARAMETER); + } + + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + + Walker = TimeZoneString; + if (*Walker == L'-') { + TheTime.TimeZone = (INT16)((StrDecimalToUintn (++Walker)) * 60); + } else { + TheTime.TimeZone = (INT16)((StrDecimalToUintn (Walker)) * -60); + } + Walker = StrStr(Walker, L":"); + if (Walker != NULL && *Walker == L':') { + Walker = Walker + 1; + } + if (Walker != NULL && Walker[0] != CHAR_NULL) { + if (TheTime.TimeZone < 0) { + TheTime.TimeZone = (INT16)(TheTime.TimeZone - (UINT8)StrDecimalToUintn (Walker)); + } else { + TheTime.TimeZone = (INT16)(TheTime.TimeZone + (UINT8)StrDecimalToUintn (Walker)); + } + } + + Status = EFI_INVALID_PARAMETER; + + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) { + Status = gRT->SetTime(&TheTime); + break; + } + } + + if (!EFI_ERROR(Status)){ + return (SHELL_SUCCESS); + } + return (SHELL_INVALID_PARAMETER); +} + + +/** + Function for 'timezone' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTimeZone ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // non interactive + // + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT8 LoopVar; + EFI_TIME TheTime; + BOOLEAN Found; + UINTN TzMinutes; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + if (PcdGet8(PcdShellSupportLevel) == 2) { + Status = ShellCommandLineParse (TimeZoneParamList2, &Package, &ProblemParam, FALSE); + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + Status = ShellCommandLineParseEx (TimeZoneParamList3, &Package, &ProblemParam, FALSE, TRUE); + } + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetCount(Package) > 1) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetFlag(Package, L"-s")) { + if ((ShellCommandLineGetFlag(Package, L"-l")) || (ShellCommandLineGetFlag(Package, L"-f"))) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"-l or -f"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(PcdGet8(PcdShellSupportLevel) == 3); + if (ShellCommandLineGetValue(Package, L"-s") == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"-s"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Set the time zone + // + ShellStatus = CheckAndSetTimeZone(ShellCommandLineGetValue(Package, L"-s")); + if (ShellStatus != SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ShellCommandLineGetValue(Package, L"-s")); + ShellStatus = SHELL_INVALID_PARAMETER; + } + } + } + } else if (ShellCommandLineGetFlag(Package, L"-l")) { + // + // Print a list of all time zones + // + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle); + } + } else { + // + // Get Current Time Zone Info + // + Status = gRT->GetTime(&TheTime, NULL); + ASSERT_EFI_ERROR(Status); + + if (TheTime.TimeZone != 2047) { + Found = FALSE; + for ( LoopVar = 0 + ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0]) + ; LoopVar++ + ){ + if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) { + if (ShellCommandLineGetFlag(Package, L"-f")) { + // + // Print all info about current time zone + // + ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle); + } else { + // + // Print basic info only + // + if (TheTime.TimeZone == 2047) { + TzMinutes = 0; + } else { + TzMinutes = AbsVal(TheTime.TimeZone) % 60; + } + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN(STR_TIMEZONE_SIMPLE), + gShellLevel2HiiHandle, + TheTime.TimeZone==2047?0:(TheTime.TimeZone > 0?L"-":L"+"), + TheTime.TimeZone==2047?0:AbsVal(TheTime.TimeZone) / 60, + TzMinutes); + } + Found = TRUE; + break; + } + } + if (!Found) { + // + // Print basic info only + // + if (TheTime.TimeZone == 2047) { + TzMinutes = 0; + } else { + TzMinutes = AbsVal(TheTime.TimeZone) % 60; + } + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN(STR_TIMEZONE_SIMPLE), + gShellLevel2HiiHandle, + TheTime.TimeZone==2047?0:(TheTime.TimeZone > 0?L"-":L"+"), + TheTime.TimeZone==2047?0:AbsVal(TheTime.TimeZone) / 60, + TzMinutes); + if (ShellCommandLineGetFlag(Package, L"-f")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_TIMEZONE_NI), gShellLevel2HiiHandle); + } + } + } else { + // + // TimeZone was 2047 (unknown) from GetTime() + // + } + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c new file mode 100644 index 0000000000..7fe5a1102c --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.c @@ -0,0 +1,329 @@ +/** @file + Main file for NULL named library for level 2 shell command functions. + + these functions are: + attrib, + cd, + cp, + date*, + time*, + load, + ls, + map, + mkdir, + mv, + parse, + rm, + reset, + set, + timezone* + + * functions are non-interactive only + + + Copyright (c) 2009 - 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 "UefiShellLevel2CommandsLib.h" + +CONST CHAR16 mFileName[] = L"ShellCommands"; +EFI_HANDLE gShellLevel2HiiHandle = NULL; +CONST EFI_GUID gShellLevel2HiiGuid = \ + { \ + 0xf95a7ccc, 0x4c55, 0x4426, { 0xa7, 0xb4, 0xdc, 0x89, 0x61, 0x95, 0xb, 0xae } \ + }; + +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel2 ( + VOID + ) +{ + return (mFileName); +} + +/** + Constructor for the Shell Level 2 Commands library. + + Install the handlers for level 2 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel2CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // if shell level is less than 2 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 2) { + return (EFI_UNSUPPORTED); + } + + gShellLevel2HiiHandle = HiiAddPackages (&gShellLevel2HiiGuid, gImageHandle, UefiShellLevel2CommandsLibStrings, NULL); + if (gShellLevel2HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // install our shell command handlers that are always installed + // + ShellCommandRegisterCommandName(L"attrib", ShellCommandRunAttrib , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_ATTRIB) ); + ShellCommandRegisterCommandName(L"cd", ShellCommandRunCd , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CD) ); + ShellCommandRegisterCommandName(L"cp", ShellCommandRunCp , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CP) ); + ShellCommandRegisterCommandName(L"load", ShellCommandRunLoad , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD) ); + ShellCommandRegisterCommandName(L"map", ShellCommandRunMap , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MAP) ); + ShellCommandRegisterCommandName(L"mkdir", ShellCommandRunMkDir , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MKDIR) ); + ShellCommandRegisterCommandName(L"mv", ShellCommandRunMv , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MV) ); + ShellCommandRegisterCommandName(L"parse", ShellCommandRunParse , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_PARSE) ); + ShellCommandRegisterCommandName(L"reset", ShellCommandRunReset , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RESET) ); + ShellCommandRegisterCommandName(L"set", ShellCommandRunSet , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_SET) ); + ShellCommandRegisterCommandName(L"ls", ShellCommandRunLs , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LS) ); + ShellCommandRegisterCommandName(L"rm", ShellCommandRunRm , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RM) ); + + // + // support for permenant (built in) aliases + // + ShellCommandRegisterAlias(L"rm", L"del"); + ShellCommandRegisterAlias(L"ls", L"dir"); + ShellCommandRegisterAlias(L"cp", L"copy"); + ShellCommandRegisterAlias(L"mkdir", L"md"); + ShellCommandRegisterAlias(L"cd ..", L"cd.."); + ShellCommandRegisterAlias(L"cd \\", L"cd\\"); + // + // These are installed in level 2 or 3... + // + if (PcdGet8(PcdShellSupportLevel) == 2 || PcdGet8(PcdShellSupportLevel) == 3) { + ShellCommandRegisterCommandName(L"date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); + ShellCommandRegisterCommandName(L"time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); + ShellCommandRegisterCommandName(L"timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); + } else { + DEBUG_CODE_BEGIN(); + // + // we want to be able to test these so install them under a different name in debug mode... + // + ShellCommandRegisterCommandName(L"l2date", ShellCommandRunDate , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE) ); + ShellCommandRegisterCommandName(L"l2time", ShellCommandRunTime , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME) ); + ShellCommandRegisterCommandName(L"l2timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE)); + DEBUG_CODE_END(); + } + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS Always returned. +**/ +EFI_STATUS +EFIAPI +ShellLevel2CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel2HiiHandle != NULL) { + HiiRemovePackages(gShellLevel2HiiHandle); + } + return (EFI_SUCCESS); +} + +/** + Function to clean up paths. Removes the following items: + single periods in the path (no need for the current directory tag) + double periods in the path and removes a single parent directory. + + This will be done inline and the resultant string may be be 'too big'. + + @param[in] PathToReturn The pointer to the string containing the path. + + @return PathToReturn is always returned. +**/ +CHAR16* +EFIAPI +CleanPath( + IN CHAR16 *PathToReturn + ) +{ + CHAR16 *TempString; + UINTN TempSize; + if (PathToReturn==NULL) { + return(NULL); + } + // + // Fix up the directory name + // + while ((TempString = StrStr(PathToReturn, L"\\..\\")) != NULL) { + *TempString = CHAR_NULL; + TempString += 4; + ChopLastSlash(PathToReturn); + TempSize = StrSize(TempString); + CopyMem(PathToReturn+StrLen(PathToReturn), TempString, TempSize); + } + if ((TempString = StrStr(PathToReturn, L"\\..")) != NULL && *(TempString + 3) == CHAR_NULL) { + *TempString = CHAR_NULL; + ChopLastSlash(PathToReturn); + } + while ((TempString = StrStr(PathToReturn, L"\\.\\")) != NULL) { + *TempString = CHAR_NULL; + TempString += 2; + TempSize = StrSize(TempString); + CopyMem(PathToReturn+StrLen(PathToReturn), TempString, TempSize); + } + if ((TempString = StrStr(PathToReturn, L"\\.")) != NULL && *(TempString + 2) == CHAR_NULL) { + *TempString = CHAR_NULL; + } + return (PathToReturn); +} + +/** + returns a fully qualified directory (contains a map drive at the begining) + path from a unknown directory path. + + If Path is already fully qualified this will return a duplicat otherwise this + will use get the current directory and use that to build the fully qualified + version. + + if the return value is not NULL it must be caller freed. + + @param[in] Path The unknown Path Value + + @retval NULL A memory allocation failed + @retval NULL a fully qualified path could not be discovered. + @retval other pointer to a fuly qualified path. +**/ +CHAR16* +EFIAPI +GetFullyQualifiedPath( + IN CONST CHAR16* Path + ) +{ + CHAR16 *PathToReturn; + UINTN Size; + CONST CHAR16 *CurDir; + + PathToReturn = NULL; + Size = 0; + + ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL)); + // + // convert a local path to an absolute path + // + if (StrStr(Path, L":") == NULL) { + CurDir = gEfiShellProtocol->GetCurDir(NULL); + StrnCatGrow(&PathToReturn, &Size, CurDir, 0); + if (*Path == L'\\') { + Path++; + } + } + StrnCatGrow(&PathToReturn, &Size, Path, 0); + + CleanPath(PathToReturn); + + while (PathToReturn[StrLen(PathToReturn)-1] == L'*') { + PathToReturn[StrLen(PathToReturn)-1] = CHAR_NULL; + } + + return (PathToReturn); +} + +/** + Function to verify all intermediate directories in the path. + + @param[in] Path The pointer to the path to fix. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +VerifyIntermediateDirectories ( + IN CONST CHAR16 *Path + ) +{ + EFI_STATUS Status; + CHAR16 *PathCopy; + CHAR16 *TempSpot; + SHELL_FILE_HANDLE FileHandle; + + ASSERT(Path != NULL); + + Status = EFI_SUCCESS; + PathCopy = NULL; + PathCopy = StrnCatGrow(&PathCopy, NULL, Path, 0); + FileHandle = NULL; + + for (TempSpot = &PathCopy[StrLen(PathCopy)-1] ; *TempSpot != CHAR_NULL && *TempSpot != L'\\' ; TempSpot = &PathCopy[StrLen(PathCopy)-1]){ + *TempSpot = CHAR_NULL; + } + if (*TempSpot == L'\\') { + *TempSpot = CHAR_NULL; + } + + if (PathCopy != NULL && *PathCopy != CHAR_NULL) { + Status = VerifyIntermediateDirectories(PathCopy); + + if (PathCopy[StrLen(PathCopy)-1] != L':') { + if (!EFI_ERROR(Status)) { + Status = ShellOpenFileByName(PathCopy, &FileHandle, EFI_FILE_MODE_READ, 0); + if (FileHandle != NULL) { + ShellCloseFile(&FileHandle); + } + } + } + } + + SHELL_FREE_NON_NULL(PathCopy); + + return (Status); +} + +// be lazy and borrow from baselib. +CHAR16 +EFIAPI +InternalCharToUpper ( + IN CONST CHAR16 Char + ); + +CONST CHAR16* +EFIAPI +StrniCmp( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Target, + IN CONST UINTN Count + ) +{ + UINTN LoopCount; + CHAR16 Char1; + CHAR16 Char2; + + ASSERT(Source != NULL); + ASSERT(Target != NULL); + + for (LoopCount = 0 ; LoopCount < Count ; LoopCount++) { + Char1 = InternalCharToUpper(Source[LoopCount]); + Char2 = InternalCharToUpper(Target[LoopCount]); + if (Char1 != Char2) { + return (&Source[LoopCount]); + } + } + return (NULL); +} + diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h new file mode 100644 index 0000000000..c04acccf05 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.h @@ -0,0 +1,297 @@ +/** @file + Main file for NULL named library for level 2 shell command functions. + + these functions are: + attrib, cd, cp, date*, time*, rm, reset, + load, ls, map, mkdir, mv, parse, set, timezone* + + + * functions are non-interactive only + + + Copyright (c) 2009 - 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern CONST CHAR16 mFileName[]; +extern EFI_HANDLE gShellLevel2HiiHandle; +extern CONST EFI_GUID gShellLevel2HiiGuid; + +/** + Function for 'attrib' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAttrib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'date' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunDate ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'time' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTime ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'load' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLoad ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunLs ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'map' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMap ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'reset' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunReset ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'timezone' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTimeZone ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'set' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunSet ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mkdir' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMkDir ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cd' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCd ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cp' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'parse' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunParse ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'rm' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunRm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'mv' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunMv ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + returns a fully qualified directory (contains a map drive at the begining) + path from a unknown directory path. + + If Path is already fully qualified this will return a duplicat otherwise this + will use get the current directory and use that to build the fully qualified + version. + + if the return value is not NULL it must be caller freed. + + @param[in] Path The unknown Path Value + + @retval NULL A memory allocation failed + @retval NULL a fully qualified path could not be discovered. + @retval other pointer to a fuly qualified path. +**/ +CHAR16* +EFIAPI +GetFullyQualifiedPath( + IN CONST CHAR16* Path + ); + +/** + Function to verify all intermediate directories in the path. + + @param[in] Path The pointer to the path to fix. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +VerifyIntermediateDirectories ( + IN CONST CHAR16 *Path + ); + +/** + CaseInsensitive length limited string comparison. + + @param[in] Source Pointer to first string. + @param[in] Target Pointer to second string. + @param[in] Count Number of characters to compare. + + @retval 0 The strings are the same. + @return non-zero if the strings are different. +**/ +CONST CHAR16* +EFIAPI +StrniCmp( + IN CONST CHAR16 *Source, + IN CONST CHAR16 *Target, + IN CONST UINTN Count + ); diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf new file mode 100644 index 0000000000..9280ad5cbd --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf @@ -0,0 +1,82 @@ +## @file +# Provides shell level 2 functions +# +# Copyright (c) 2009, 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. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel2CommandsLib + FILE_GUID = CBF3931C-A2DF-40e5-B77E-CCA9555E9755 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel2CommandsLibConstructor + DESTRUCTOR = ShellLevel2CommandsLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + UefiShellLevel2CommandsLib.c + UefiShellLevel2CommandsLib.h + UefiShellLevel2CommandsLib.uni + TimeDate.c + Load.c + Ls.c + Map.c + Reset.c + Set.c + MkDir.c + Cd.c + Cp.c + Parse.c + Rm.c + Mv.c + Attrib.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + HandleParsingLib + +[Protocols] + gEfiUnicodeCollation2ProtocolGuid # ALWAYS_CONSUMED + gEfiShellProtocolGuid # ALWAYS_CONSUMED + gEfiShellParametersProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathProtocolGuid # ALWAYS_CONSUMED + gEfiLoadedImageProtocolGuid # ALWAYS_CONSUMED + gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED + gEfiDevicePathToTextProtocolGuid # ALWAYS_CONSUMED + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel # ALWAYS_CONSUMED + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize # ALWAYS_CONSUMED + +[Guids] + gEfiFileSystemInfoGuid + gEfiFileInfoGuid diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni new file mode 100644 index 0000000000..27b1053354 Binary files /dev/null and b/ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.uni differ diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c new file mode 100644 index 0000000000..da53af4c5c --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Alias.c @@ -0,0 +1,162 @@ +/** @file + Main file for Alias shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +/** + Print out each alias registered with the Shell. + + @retval STATUS_SUCCESS the printout was sucessful + @return any return code from GetNextVariableName except EFI_NOT_FOUND +**/ +SHELL_STATUS +EFIAPI +PrintAllShellAlias( + VOID + ) +{ + CONST CHAR16 *ConstAllAliasList; + CHAR16 *Alias; + CONST CHAR16 *Command; + CHAR16 *Walker; + BOOLEAN Volatile; + + Volatile = FALSE; + + ConstAllAliasList = gEfiShellProtocol->GetAlias(NULL, NULL); + if (ConstAllAliasList == NULL) { + return (SHELL_SUCCESS); + } + Alias = AllocateZeroPool(StrSize(ConstAllAliasList)); + Walker = (CHAR16*)ConstAllAliasList; + + do { + CopyMem(Alias, Walker, StrSize(Walker)); + Walker = StrStr(Alias, L";"); + if (Walker != NULL) { + Walker[0] = CHAR_NULL; + Walker = Walker + 1; + } + Command = gEfiShellProtocol->GetAlias(Alias, &Volatile); + if (ShellCommandIsOnAliasList(Alias)) { + Volatile = FALSE; + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ALIAS_OUTPUT), gShellLevel3HiiHandle, !Volatile?L' ':L'*', Alias, Command); + } while (Walker != NULL && Walker[0] != CHAR_NULL); + + FreePool(Alias); + + return (SHELL_SUCCESS); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-v", TypeFlag}, + {L"-d", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'alias' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAlias ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + CONST CHAR16 *Param2; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + Param1 = ShellCommandLineGetRawValue(Package, 1); + Param2 = ShellCommandLineGetRawValue(Package, 2); + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetCount(Package) == 1) { + // + // print out alias' + // + Status = PrintAllShellAlias(); + } else if (ShellCommandLineGetFlag(Package, L"-d")) { + // + // delete an alias + // + Status = gEfiShellProtocol->SetAlias(Param1, NULL, TRUE, FALSE); + } else if (ShellCommandLineGetCount(Package) == 3) { + // + // must be adding an alias + // + Status = gEfiShellProtocol->SetAlias(Param2, Param1, FALSE, ShellCommandLineGetFlag(Package, L"-v")); + if (EFI_ERROR(Status)) { + if (Status == EFI_ACCESS_DENIED) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel3HiiHandle); + ShellStatus = SHELL_ACCESS_DENIED; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel3HiiHandle, Status); + ShellStatus = SHELL_DEVICE_ERROR; + } + } + } else if (ShellCommandLineGetCount(Package) == 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c new file mode 100644 index 0000000000..019aaf7231 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Cls.c @@ -0,0 +1,135 @@ +/** @file + Main file for attrib shell level 2 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +/** + Function for 'cls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCls ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *Message; + UINTN Background; + UINTN ForeColor; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CONST CHAR16 *Param1; + + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + Background = 0; + + // + // Initialize variables + // + Message = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else { + // + // If there are 0 value parameters, clear sceen + // + Param1 = ShellCommandLineGetRawValue(Package, 1); + if (Param1 == NULL) { + // + // clear screen + // + gST->ConOut->ClearScreen (gST->ConOut); + } else if (ShellCommandLineGetCount(Package) > 2) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (StrDecimalToUintn(Param1) > 7 || StrLen(Param1) > 1 || !ShellIsDecimalDigitCharacter(*Param1)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, Param1); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + switch (StrDecimalToUintn(Param1)) { + case 0: + Background = EFI_BACKGROUND_BLACK; + break; + case 1: + Background = EFI_BACKGROUND_BLUE; + break; + case 2: + Background = EFI_BACKGROUND_GREEN; + break; + case 3: + Background = EFI_BACKGROUND_CYAN; + break; + case 4: + Background = EFI_BACKGROUND_RED; + break; + case 5: + Background = EFI_BACKGROUND_MAGENTA; + break; + case 6: + Background = EFI_BACKGROUND_BROWN; + break; + case 7: + Background = EFI_BACKGROUND_LIGHTGRAY; + break; + } + ForeColor = (~StrDecimalToUintn(Param1)) & 0xF; + Status = gST->ConOut->SetAttribute (gST->ConOut, ForeColor | Background); + ASSERT_EFI_ERROR(Status); + Status = gST->ConOut->ClearScreen (gST->ConOut); + ASSERT_EFI_ERROR(Status); + } + } + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + + // + // return the status + // + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c new file mode 100644 index 0000000000..dc6bca0b8a --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c @@ -0,0 +1,116 @@ +/** @file + Main file for Echo shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-on", TypeFlag}, + {L"-off", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'echo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEcho ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; +// CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + +// ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParseEx (ParamList, &Package, NULL, TRUE, TRUE); +// if (EFI_ERROR(Status)) { +// if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { +// ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); +// FreePool(ProblemParam); +// ShellStatus = SHELL_INVALID_PARAMETER; +// } else { +// ASSERT(FALSE); +// } +// } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetFlag(Package, L"-on")) { + // + // Turn it on + // + ShellCommandSetEchoState(TRUE); + } else if (ShellCommandLineGetFlag(Package, L"-off")) { + // + // turn it off + // + ShellCommandSetEchoState(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // output its current state + // + if (ShellCommandGetEchoState()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_ON), gShellLevel3HiiHandle); + } else { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_OFF), gShellLevel3HiiHandle); + } + } else { + // + // print the line + // + for ( ParamCount = 1 + ; ShellCommandLineGetRawValue(Package, ParamCount) != NULL + ; ParamCount++ + ) { + if (ShellCommandLineGetRawValue(Package, ParamCount+1) != NULL) { + ShellPrintEx(-1, -1, L"%s ", ShellCommandLineGetRawValue(Package, ParamCount)); + } else { + ShellPrintEx(-1, -1, L"%s", ShellCommandLineGetRawValue(Package, ParamCount)); + } + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), gShellLevel3HiiHandle); + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); +// } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c new file mode 100644 index 0000000000..ce1eb1fcf0 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/GetMtc.c @@ -0,0 +1,101 @@ +/** @file + Main file for GetMtc shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +/** + Function for 'getmtc' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGetMtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT64 Mtc; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Get the monotonic counter count + // + Status = gBS->GetNextMonotonicCount(&Mtc); + switch(Status) { + case EFI_DEVICE_ERROR: + ShellStatus = SHELL_DEVICE_ERROR; + break; + case EFI_SECURITY_VIOLATION: + ShellStatus = SHELL_SECURITY_VIOLATION; + break; + default: + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_DEVICE_ERROR; + } + } + + // + // print it... + // + if (ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GET_MTC_OUTPUT), gShellLevel3HiiHandle, Mtc); + } + } + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c new file mode 100644 index 0000000000..04e3d31dba --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Help.c @@ -0,0 +1,183 @@ +/** @file + Main file for Help shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-usage", TypeFlag}, + {L"-section", TypeValue}, + {L"-verbose", TypeFlag}, + {L"-v", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'help' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHelp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + CHAR16 *OutText; + CONST COMMAND_LIST *CommandList; + CONST COMMAND_LIST *Node; + CHAR16 *CommandToGetHelpOn; + CHAR16 *SectionToGetHelpOn; + CHAR16 *HiiString; + BOOLEAN Found; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + OutText = NULL; + CommandToGetHelpOn = NULL; + SectionToGetHelpOn = NULL; + Found = FALSE; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // Check for conflicting parameters. + // + if (ShellCommandLineGetFlag(Package, L"-usage") + &&ShellCommandLineGetFlag(Package, L"-section") + &&(ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) + ){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // Get the command name we are getting help on + // + ASSERT(CommandToGetHelpOn == NULL); + StrnCatGrow(&CommandToGetHelpOn, NULL, ShellCommandLineGetRawValue(Package, 1), 0); + if (CommandToGetHelpOn == NULL && ShellCommandLineGetFlag(Package, L"-?")) { + // + // If we dont have a command and we got a simple -? + // we are looking for help on help command. + // + StrnCatGrow(&CommandToGetHelpOn, NULL, L"help", 0); + } + + if (CommandToGetHelpOn == NULL) { + StrnCatGrow(&CommandToGetHelpOn, NULL, L"*", 0); + ASSERT(SectionToGetHelpOn == NULL); + StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME", 0); + } else { + ASSERT(SectionToGetHelpOn == NULL); + // + // Get the section name for the given command name + // + if (ShellCommandLineGetFlag(Package, L"-section")) { + StrnCatGrow(&SectionToGetHelpOn, NULL, ShellCommandLineGetValue(Package, L"-section"), 0); + } else if (ShellCommandLineGetFlag(Package, L"-usage")) { + StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME,SYNOPSIS", 0); + } else if (ShellCommandLineGetFlag(Package, L"-verbose") || ShellCommandLineGetFlag(Package, L"-v")) { + } else { + StrnCatGrow(&SectionToGetHelpOn, NULL, L"NAME", 0); + } + } + + if (gUnicodeCollation->StriColl(gUnicodeCollation, CommandToGetHelpOn, L"special") == 0) { + // + // we need info on the special characters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_SC_HEADER), gShellLevel3HiiHandle); + HiiString = HiiGetString(gShellLevel3HiiHandle, STRING_TOKEN(STR_HELP_SC_DATA), NULL); + ShellPrintEx(-1, -1, L"%s", HiiString); + FreePool(HiiString); + Found = TRUE; + } else { + CommandList = ShellCommandGetCommandList(); + ASSERT(CommandList != NULL); + for ( Node = (COMMAND_LIST*)GetFirstNode(&CommandList->Link) + ; CommandList != NULL && !IsListEmpty(&CommandList->Link) && !IsNull(&CommandList->Link, &Node->Link) + ; Node = (COMMAND_LIST*)GetNextNode(&CommandList->Link, &Node->Link) + ){ + if (gUnicodeCollation->MetaiMatch(gUnicodeCollation, Node->CommandString, CommandToGetHelpOn)) { + // + // We have a command to look for help on. + // + Status = gEfiShellProtocol->GetHelpText(Node->CommandString, SectionToGetHelpOn, &OutText); + if (EFI_ERROR(Status) || OutText == NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, Node->CommandString); + ShellStatus = SHELL_NOT_FOUND; + } else { + while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') { + OutText[StrLen(OutText)-1] = CHAR_NULL; + } + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_COMMAND), gShellLevel3HiiHandle, Node->CommandString, OutText); + FreePool(OutText); + OutText = NULL; + Found = TRUE; + } + } + } + } + + if (!Found && ShellStatus == SHELL_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_HELP_NF), gShellLevel3HiiHandle, CommandToGetHelpOn); + ShellStatus = SHELL_NOT_FOUND; + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + } + if (CommandToGetHelpOn != NULL) { + FreePool(CommandToGetHelpOn); + } + if (SectionToGetHelpOn != NULL) { + FreePool(SectionToGetHelpOn); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c new file mode 100644 index 0000000000..facacaac7d --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Pause.c @@ -0,0 +1,106 @@ +/** @file + Main file for Pause shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-q", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'pause' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPause ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + SHELL_PROMPT_RESPONSE *Resp; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + if (!gEfiShellProtocol->BatchIsActive()) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_SCRIPT_ONLY), gShellLevel3HiiHandle); + return (SHELL_UNSUPPORTED); + } + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } else if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (!ShellCommandLineGetFlag(Package, L"-q")) { + Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN (STR_PAUSE_PROMPT), gShellLevel3HiiHandle, (VOID**)&Resp); + } else { + Status = ShellPromptForResponse(ShellPromptResponseTypeQuitContinue, NULL, (VOID**)&Resp); + } + ASSERT_EFI_ERROR(Status); + + if (Resp == NULL || *Resp == ShellPromptResponseQuit) { + ShellCommandRegisterExit(TRUE); + ShellStatus = SHELL_ABORTED; + } + + if (Resp != NULL) { + FreePool(Resp); + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c new file mode 100644 index 0000000000..0252f7748d --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Touch.c @@ -0,0 +1,265 @@ +/** @file + Main file for Touch shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +EFI_STATUS +EFIAPI +TouchFileByHandle ( + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + + FileInfo = gEfiShellProtocol->GetFileInfo(Handle); + if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) != 0){ + return (EFI_ACCESS_DENIED); + } + Status = gRT->GetTime(&FileInfo->ModificationTime, NULL); + ASSERT_EFI_ERROR(Status); + CopyMem(&FileInfo->LastAccessTime, &FileInfo->ModificationTime, sizeof(EFI_TIME)); + + Status = gEfiShellProtocol->SetFileInfo(Handle, FileInfo); + + FreePool(FileInfo); + + return (Status); +} + +EFI_STATUS +EFIAPI +DoTouchByHandle ( + IN CONST CHAR16 *Name, + IN CHAR16 *FS, + IN SHELL_FILE_HANDLE Handle, + IN BOOLEAN Rec + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Walker; + CHAR16 *TempSpot; + + Status = EFI_SUCCESS; + FileList = NULL; + Walker = NULL; + + if (FS == NULL) { + FS = StrnCatGrow(&FS, NULL, Name, 0); + TempSpot = StrStr(FS, L"\\"); + if (TempSpot != NULL) { + *TempSpot = CHAR_NULL; + } + } + + // + // do it + // + Status = TouchFileByHandle(Handle); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NO_OPEN), gShellLevel3HiiHandle, Name, Status); + return (Status); + } + + // + // if it's a directory recurse... + // + if (FileHandleIsDirectory(Handle) == EFI_SUCCESS && Rec) { + // + // get each file under this directory + // + if (EFI_ERROR(gEfiShellProtocol->FindFilesInDir(Handle, &FileList))) { + Status = EFI_INVALID_PARAMETER; + } + + // + // recurse on each + // + for (Walker = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) + ; FileList != NULL && !IsNull(&FileList->Link, &Walker->Link) && !EFI_ERROR(Status) + ; Walker = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Walker->Link) + ){ + if ( (StrCmp(Walker->FileName, L".") != 0) + && (StrCmp(Walker->FileName, L"..") != 0) + ){ + // + // Open the file since we need that handle. + // + Status = gEfiShellProtocol->OpenFileByName (Walker->FullName, &Walker->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NO_OPEN), gShellLevel3HiiHandle, Walker->FullName, Status); + Status = EFI_ACCESS_DENIED; + } else { + Status = DoTouchByHandle(Walker->FullName, FS, Walker->Handle, TRUE); + gEfiShellProtocol->CloseFile(Walker->Handle); + Walker->Handle = NULL; + } + } + } + + // + // free stuff + // + if (FileList != NULL && EFI_ERROR(gEfiShellProtocol->FreeFileList(&FileList))) { + Status = EFI_INVALID_PARAMETER; + } + } + + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-r", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'touch' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTouch ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, &FileList); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, (CHAR16*)Param); + ShellStatus = SHELL_NOT_FOUND; + break; + } + // + // make sure we completed the param parsing sucessfully... + // Also make sure that any previous action was sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + // + // check that we have at least 1 file + // + if (FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel3HiiHandle, Param); + continue; + } else { + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // make sure the file opened ok + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NO_OPEN), gShellLevel3HiiHandle, Node->FileName, Node->Status); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + Status = DoTouchByHandle(Node->FullName, NULL, Node->Handle, ShellCommandLineGetFlag(Package, L"-r")); + if (EFI_ERROR(Status) && Status != EFI_ACCESS_DENIED) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NO_OPEN), gShellLevel3HiiHandle, Node->FileName, Status); + ShellStatus = SHELL_NOT_FOUND; + } + } + } + } + // + // Free the fileList + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + ASSERT_EFI_ERROR(Status); + } + FileList = NULL; + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c new file mode 100644 index 0000000000..05f13f0756 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Type.c @@ -0,0 +1,239 @@ +/** @file + Main file for Type shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +EFI_STATUS +EFIAPI +TypeFileByHandle ( + IN EFI_HANDLE Handle, + BOOLEAN Ascii, + BOOLEAN UCS2 + ) +{ + UINTN ReadSize; + VOID *Buffer; + EFI_STATUS Status; + UINTN LoopVar; + CHAR16 AsciiChar; + + ReadSize = PcdGet16(PcdShellFileOperationSize); + Buffer = AllocatePool(ReadSize); + if (Buffer == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + Status = ShellSetFilePosition(Handle, 0); + ASSERT_EFI_ERROR(Status); + + while (ReadSize == ((UINTN)PcdGet16(PcdShellFileOperationSize))){ + ZeroMem(Buffer, ReadSize); + Status = ShellReadFile(Handle, &ReadSize, Buffer); + if (EFI_ERROR(Status)){ + break; + } + + if (!(Ascii|UCS2)){ + if (*(UINT16*)Buffer == UnicodeFileTag) { + UCS2 = TRUE; + Buffer = ((UINT16*)Buffer) + 1; + } else { + Ascii = TRUE; + } + } + + // + // We want to use plain Print function here! (no color support for files) + // + if (Ascii){ + for (LoopVar = 0 ; LoopVar < ReadSize ; LoopVar++) { + AsciiChar = CHAR_NULL; + AsciiChar = ((CHAR8*)Buffer)[LoopVar]; + if (AsciiChar == CHAR_NULL) { + AsciiChar = '.'; + } + Print(L"%c", AsciiChar); + } + } else { + Print(L"%s", Buffer); + } + } + Status = Print(L"\r\n", Buffer); + return (Status); +} + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-a", TypeFlag}, + {L"-u", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'type' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunType ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + CONST CHAR16 *Param; + SHELL_STATUS ShellStatus; + UINTN ParamCount; + EFI_SHELL_FILE_INFO *FileList; + EFI_SHELL_FILE_INFO *Node; + BOOLEAN AsciiMode; + BOOLEAN UnicodeMode; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ParamCount = 0; + FileList = NULL; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + AsciiMode = ShellCommandLineGetFlag(Package, L"-a"); + UnicodeMode = ShellCommandLineGetFlag(Package, L"-u"); + + if (AsciiMode && UnicodeMode) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"-a & -u"); + ShellStatus = SHELL_INVALID_PARAMETER; + } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) { + // + // we insufficient parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + // + // get a list with each file specified by parameters + // if parameter is a directory then add all the files below it to the list + // + for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ; Param != NULL + ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount) + ){ + Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_READ, &FileList); + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_NOT_FOUND; + break; + } + // + // make sure we completed the param parsing sucessfully... + // Also make sure that any previous action was sucessful + // + if (ShellStatus == SHELL_SUCCESS) { + // + // check that we have at least 1 file + // + if (FileList == NULL || IsListEmpty(&FileList->Link)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel3HiiHandle, Param); + continue; + } else { + // + // loop through the list and make sure we are not aborting... + // + for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link) + ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag() + ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link) + ){ + // + // make sure the file opened ok + // + if (EFI_ERROR(Node->Status)){ + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NO_OPEN), gShellLevel3HiiHandle, Node->FileName, Node->Status); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + // + // make sure its not a directory + // + if (FileHandleIsDirectory(Node->Handle) == EFI_SUCCESS) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_IS_DIR), gShellLevel3HiiHandle, Node->FileName); + ShellStatus = SHELL_NOT_FOUND; + continue; + } + + // + // do it + // + Status = TypeFileByHandle(Node->Handle, AsciiMode, UnicodeMode); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TYP_ERROR), gShellLevel3HiiHandle, Node->FileName, Status); + ShellStatus = SHELL_INVALID_PARAMETER; + } + ASSERT(ShellStatus == SHELL_SUCCESS); + } + } + } + // + // Free the fileList + // + if (FileList != NULL && !IsListEmpty(&FileList->Link)) { + Status = ShellCloseFileMetaArg(&FileList); + } + ASSERT_EFI_ERROR(Status); + FileList = NULL; + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + if (ShellGetExecutionBreakFlag()) { + return (SHELL_ABORTED); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c new file mode 100644 index 0000000000..3ce39d7ea2 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.c @@ -0,0 +1,94 @@ +/** @file + Main file for NULL named library for level 3 shell command functions. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +CONST CHAR16 gShellLevel3FileName[] = L"ShellCommands"; +EFI_HANDLE gShellLevel3HiiHandle = NULL; +STATIC CONST EFI_GUID gShellLevel3HiiGuid = \ + { \ + 0x4344558d, 0x4ef9, 0x4725, { 0xb1, 0xe4, 0x33, 0x76, 0xe8, 0xd6, 0x97, 0x4f } \ + }; + +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameLevel3 ( + VOID + ) +{ + return (gShellLevel3FileName); +} + +/** + Constructor for the Shell Level 3 Commands library. + + Install the handlers for level 3 UEFI Shell 2.0 commands. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the shell command handlers were installed sucessfully + @retval EFI_UNSUPPORTED the shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellLevel3CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellLevel3HiiHandle = NULL; + // + // if shell level is less than 3 do nothing + // + if (PcdGet8(PcdShellSupportLevel) < 3) { + return (EFI_UNSUPPORTED); + } + + gShellLevel3HiiHandle = HiiAddPackages (&gShellLevel3HiiGuid, gImageHandle, UefiShellLevel3CommandsLibStrings, NULL); + if (gShellLevel3HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers that are always installed + // + // Note: that Time, Timezone, and Date are part of level 2 library + // + ShellCommandRegisterCommandName(L"type", ShellCommandRunType , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_TYPE)); + ShellCommandRegisterCommandName(L"touch", ShellCommandRunTouch , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_TOUCH)); + ShellCommandRegisterCommandName(L"ver", ShellCommandRunVer , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_VER)); + ShellCommandRegisterCommandName(L"alias", ShellCommandRunAlias , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_ALIAS)); + ShellCommandRegisterCommandName(L"cls", ShellCommandRunCls , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_CLS)); + ShellCommandRegisterCommandName(L"echo", ShellCommandRunEcho , ShellCommandGetManFileNameLevel3, 3, L"", FALSE, gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_ECHO)); + ShellCommandRegisterCommandName(L"pause", ShellCommandRunPause , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_PAUSE)); + ShellCommandRegisterCommandName(L"getmtc", ShellCommandRunGetMtc , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_GETMTC)); + ShellCommandRegisterCommandName(L"help", ShellCommandRunHelp , ShellCommandGetManFileNameLevel3, 3, L"", TRUE , gShellLevel3HiiHandle, STRING_TOKEN(STR_GET_HELP_HELP)); + + return (EFI_SUCCESS); +} + +/** + Destructor for the library. free any resources. +**/ +EFI_STATUS +EFIAPI +ShellLevel3CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellLevel3HiiHandle != NULL) { + HiiRemovePackages(gShellLevel3HiiHandle); + } + return (EFI_SUCCESS); +} diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h new file mode 100644 index 0000000000..b6ac99658d --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.h @@ -0,0 +1,156 @@ +/** @file + header file for NULL named library for level 3 shell command functions. + + Copyright (c) 2009 - 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HANDLE gShellLevel3HiiHandle; + +/** + Function for 'type' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunType ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'touch' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunTouch ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ver' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'alias' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunAlias ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'cls' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunCls ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'echo' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunEcho ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'pause' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPause ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'getmtc' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunGetMtc ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'help' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunHelp ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf new file mode 100644 index 0000000000..16c6f7a2b3 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf @@ -0,0 +1,68 @@ +## @file +# Provides shell level 3 functions +# Note that the interactive versions of the time, date, and timezone functions are handled in the level 2 library. +# +# Copyright (c) 2009-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. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellLevel3CommandsLib + FILE_GUID = 71374B42-85D7-4753-AD17-AA84C3A0EB93 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLevel3CommandsLibConstructor + DESTRUCTOR = ShellLevel3CommandsLibDestructor + +[Sources.common] +# note that time, timezone, and date are part of the level 2 library + Type.c + Touch.c + Ver.c + UefiShellLevel3CommandsLib.uni + UefiShellLevel3CommandsLib.c + UefiShellLevel3CommandsLib.h + Cls.c + Alias.c + Echo.c + Pause.c + GetMtc.c + Help.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + +[Guids] + gEfiFileInfoGuid + +[Pcd.common] + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize + diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni new file mode 100644 index 0000000000..3e4a57ac7d Binary files /dev/null and b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.uni differ diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c b/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c new file mode 100644 index 0000000000..e00f4c90f5 --- /dev/null +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Ver.c @@ -0,0 +1,145 @@ +/** @file + Main file for Ver shell level 3 function. + + Copyright (c) 2009 - 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 "UefiShellLevel3CommandsLib.h" + +#include + +STATIC CONST SHELL_PARAM_ITEM ParamList[] = { + {L"-s", TypeFlag}, + {L"-terse", TypeFlag}, + {L"-t", TypeFlag}, + {L"-_pa", TypeFlag}, + {NULL, TypeMax} + }; + +/** + Function for 'ver' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunVer ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Package; + CHAR16 *ProblemParam; + SHELL_STATUS ShellStatus; + UINT8 Level; + + Level = PcdGet8(PcdShellSupportLevel); + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + // + // initialize the shell lib (we must be in non-auto-init...) + // + Status = ShellInitialize(); + ASSERT_EFI_ERROR(Status); + + Status = CommandInit(); + ASSERT_EFI_ERROR(Status); + + // + // parse the command line + // + Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + if (EFI_ERROR(Status)) { + if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, ProblemParam); + FreePool(ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + ASSERT(FALSE); + } + } else { + // + // check for "-?" + // + if (ShellCommandLineGetFlag(Package, L"-?")) { + ASSERT(FALSE); + } + if (ShellCommandLineGetRawValue(Package, 1) != NULL) { + // + // we have too many parameters + // + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel3HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + } else { + if (ShellCommandLineGetFlag(Package, L"-s")) { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_SIMPLE), + gShellLevel3HiiHandle, + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion + ); + } else { + ShellPrintHiiEx ( + 0, + gST->ConOut->Mode->CursorRow, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_SHELL), + gShellLevel3HiiHandle, + SupportLevel[Level], + gEfiShellProtocol->MajorVersion, + gEfiShellProtocol->MinorVersion + ); + if (!ShellCommandLineGetFlag(Package, L"-terse") && !ShellCommandLineGetFlag(Package, L"-t")){ + ShellPrintHiiEx( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_EXTRA_STRING), + gShellLevel3HiiHandle + ); + + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_VER_OUTPUT_UEFI), + gShellLevel3HiiHandle, + (gST->Hdr.Revision&0xffff0000)>>16, + (gST->Hdr.Revision&0x0000ffff), + gST->FirmwareVendor, + gST->FirmwareRevision + ); + } + } + // + // implementation specific support for displaying processor architecture + // + if (ShellCommandLineGetFlag(Package, L"-_pa")) { + ShellPrintEx(-1, -1, L"%d\r\n", sizeof(UINTN)==sizeof(UINT64)?64:32); + } + } + + // + // free the command line package + // + ShellCommandLineFreeVarList (Package); + } + + return (ShellStatus); +} + diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.c b/ShellPkg/Library/UefiShellLib/UefiShellLib.c index d3cc59e9be..1694f46378 100644 --- a/ShellPkg/Library/UefiShellLib/UefiShellLib.c +++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.c @@ -13,38 +13,36 @@ **/ #include "UefiShellLib.h" +#include -#define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN) // -// This is not static since it's extern in the .h file +// globals... // SHELL_PARAM_ITEM EmptyParamList[] = { {NULL, TypeMax} }; - -// -// Static file globals for the shell library -// -STATIC EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; -STATIC EFI_SHELL_INTERFACE *mEfiShellInterface; -STATIC EFI_SHELL_PROTOCOL *mEfiShellProtocol; -STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol; -STATIC EFI_HANDLE mEfiShellEnvironment2Handle; -STATIC FILE_HANDLE_FUNCTION_MAP FileFunctionMap; -STATIC UINTN mTotalParameterCount; -STATIC CHAR16 *mPostReplaceFormat; -STATIC CHAR16 *mPostReplaceFormat2; +SHELL_PARAM_ITEM SfoParamList[] = { + {L"-sfo", TypeFlag}, + {NULL, TypeMax} + }; +EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; +EFI_SHELL_INTERFACE *mEfiShellInterface; +EFI_SHELL_PROTOCOL *mEfiShellProtocol; +EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol; +EFI_HANDLE mEfiShellEnvironment2Handle; +FILE_HANDLE_FUNCTION_MAP FileFunctionMap; +CHAR16 *mPostReplaceFormat; +CHAR16 *mPostReplaceFormat2; /** Check if a Unicode character is a hexadecimal character. This internal function checks if a Unicode character is a - decimal character. The valid hexadecimal character is + numeric character. The valid hexadecimal characters are L'0' to L'9', L'a' to L'f', or L'A' to L'F'. - @param Char The character to check against. @retval TRUE If the Char is a hexadecmial character. @@ -55,18 +53,45 @@ BOOLEAN EFIAPI ShellIsHexaDecimalDigitCharacter ( IN CHAR16 Char - ) { + ) +{ return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f')); } /** - helper function to find ShellEnvironment2 for constructor + Check if a Unicode character is a decimal character. + + This internal function checks if a Unicode character is a + decimal character. The valid characters are + L'0' to L'9'. + + + @param Char The character to check against. + + @retval TRUE If the Char is a hexadecmial character. + @retval FALSE If the Char is not a hexadecmial character. + +**/ +BOOLEAN +EFIAPI +ShellIsDecimalDigitCharacter ( + IN CHAR16 Char + ) +{ + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + +/** + Helper function to find ShellEnvironment2 for constructor. + + @param[in] ImageHandle A copy of the calling image's handle. **/ EFI_STATUS EFIAPI ShellFindSE2 ( IN EFI_HANDLE ImageHandle - ) { + ) +{ EFI_STATUS Status; EFI_HANDLE *Buffer; UINTN BufferSize; @@ -80,11 +105,11 @@ ShellFindSE2 ( ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + ); // // look for the mEfiShellEnvironment2 protocol at a higher level // - if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE)){ + if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))){ // // figure out how big of a buffer we need. // @@ -93,7 +118,7 @@ ShellFindSE2 ( NULL, // ignored for ByProtocol &BufferSize, Buffer - ); + ); // // maybe it's not there??? // @@ -105,7 +130,7 @@ ShellFindSE2 ( NULL, // ignored for ByProtocol &BufferSize, Buffer - ); + ); } if (!EFI_ERROR (Status) && Buffer != NULL) { // @@ -119,8 +144,8 @@ ShellFindSE2 ( ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); - if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE) { + ); + if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) { mEfiShellEnvironment2Handle = Buffer[HandleIndex]; Status = EFI_SUCCESS; break; @@ -134,44 +159,58 @@ ShellFindSE2 ( return (Status); } +/*/ + Function to do most of the work of the constructor. Allows for calling + multiple times without complete re-initialization. + + @param[in] ImageHandle A copy of the ImageHandle. + @param[in] SystemTable A pointer to the SystemTable for the application. +**/ EFI_STATUS EFIAPI ShellLibConstructorWorker ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable - ) { - EFI_STATUS Status; - + ) +{ + EFI_STATUS Status; mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); ASSERT (mPostReplaceFormat != NULL); mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize)); ASSERT (mPostReplaceFormat2 != NULL); - // - // Set the parameter count to an invalid number - // - mTotalParameterCount = (UINTN)(-1); - // // UEFI 2.0 shell interfaces (used preferentially) // - Status = gBS->OpenProtocol(ImageHandle, - &gEfiShellProtocolGuid, - (VOID **)&mEfiShellProtocol, - ImageHandle, - NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + Status = gBS->OpenProtocol( + ImageHandle, + &gEfiShellProtocolGuid, + (VOID **)&mEfiShellProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); if (EFI_ERROR(Status)) { - mEfiShellProtocol = NULL; + // + // Search for the shell protocol + // + Status = gBS->LocateProtocol( + &gEfiShellProtocolGuid, + NULL, + (VOID **)&mEfiShellProtocol + ); + if (EFI_ERROR(Status)) { + mEfiShellProtocol = NULL; + } } - Status = gBS->OpenProtocol(ImageHandle, - &gEfiShellParametersProtocolGuid, - (VOID **)&mEfiShellParametersProtocol, - ImageHandle, - NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + Status = gBS->OpenProtocol( + ImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **)&mEfiShellParametersProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); if (EFI_ERROR(Status)) { mEfiShellParametersProtocol = NULL; } @@ -192,7 +231,7 @@ ShellLibConstructorWorker ( ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL - ); + ); if (EFI_ERROR(Status)) { mEfiShellInterface = NULL; } @@ -202,7 +241,7 @@ ShellLibConstructorWorker ( // only success getting 2 of either the old or new, but no 1/2 and 1/2 // if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) || - (mEfiShellProtocol != NULL && mEfiShellParametersProtocol != NULL) ) { + (mEfiShellProtocol != NULL && mEfiShellParametersProtocol != NULL) ) { if (mEfiShellProtocol != NULL) { FileFunctionMap.GetFileInfo = mEfiShellProtocol->GetFileInfo; FileFunctionMap.SetFileInfo = mEfiShellProtocol->SetFileInfo; @@ -215,16 +254,16 @@ ShellLibConstructorWorker ( FileFunctionMap.FlushFile = mEfiShellProtocol->FlushFile; FileFunctionMap.GetFileSize = mEfiShellProtocol->GetFileSize; } else { - FileFunctionMap.GetFileInfo = FileHandleGetInfo; - FileFunctionMap.SetFileInfo = FileHandleSetInfo; - FileFunctionMap.ReadFile = FileHandleRead; - FileFunctionMap.WriteFile = FileHandleWrite; - FileFunctionMap.CloseFile = FileHandleClose; - FileFunctionMap.DeleteFile = FileHandleDelete; - FileFunctionMap.GetFilePosition = FileHandleGetPosition; - FileFunctionMap.SetFilePosition = FileHandleSetPosition; - FileFunctionMap.FlushFile = FileHandleFlush; - FileFunctionMap.GetFileSize = FileHandleGetSize; + FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo; + FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo; + FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead; + FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite; + FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose; + FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete; + FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition; + FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition; + FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush; + FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize; } return (EFI_SUCCESS); } @@ -246,8 +285,8 @@ EFIAPI ShellLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable - ) { - + ) +{ mEfiShellEnvironment2 = NULL; mEfiShellProtocol = NULL; mEfiShellParametersProtocol = NULL; @@ -267,14 +306,21 @@ ShellLibConstructor ( } /** - Destructory for the library. free any resources. + Destructor for the library. free any resources. + + @param[in] ImageHandle A copy of the ImageHandle. + @param[in] SystemTable A pointer to the SystemTable for the application. + + @retval EFI_SUCCESS The operation was successful. + @return An error from the CloseProtocol function. **/ EFI_STATUS EFIAPI ShellLibDestructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable - ) { + ) +{ if (mEfiShellEnvironment2 != NULL) { gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle, &gEfiShellEnvironment2Guid, @@ -333,7 +379,8 @@ ShellLibDestructor ( EFI_STATUS EFIAPI ShellInitialize ( - ) { + ) +{ // // if auto initialize is not false then skip // @@ -369,35 +416,38 @@ ShellInitialize ( EFI_FILE_INFO* EFIAPI ShellGetFileInfo ( - IN EFI_FILE_HANDLE FileHandle - ) { + IN SHELL_FILE_HANDLE FileHandle + ) +{ return (FileFunctionMap.GetFileInfo(FileHandle)); } /** - This function will set the information about the file for the opened handle + This function sets the information about the file for the opened handle specified. - @param FileHandle The file handle of the file for which information - is being set + @param[in] FileHandle The file handle of the file for which information + is being set. - @param FileInfo The infotmation to set. + @param[in] FileInfo The information to set. - @retval EFI_SUCCESS The information was set. - @retval EFI_UNSUPPORTED The InformationType is not known. - @retval EFI_NO_MEDIA The device has no medium. - @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_SUCCESS The information was set. + @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid. + @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo. + @retval EFI_NO_MEDIA The device has no medium. + @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. - @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. - @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_WRITE_PROTECTED The file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI ShellSetFileInfo ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN EFI_FILE_INFO *FileInfo - ) { + ) +{ return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo)); } @@ -426,7 +476,7 @@ ShellSetFileInfo ( @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The file or medium is write protected. - @retval EFI_ACCESS_DENIED The file was opened read only. + @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. @retval EFI_VOLUME_FULL The volume is full. @@ -436,14 +486,16 @@ EFIAPI ShellOpenFileByDevicePath( IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_HANDLE *DeviceHandle, - OUT EFI_FILE_HANDLE *FileHandle, + OUT SHELL_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes - ) { - CHAR16 *FileName; - EFI_STATUS Status; + ) +{ + CHAR16 *FileName; + EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; - EFI_FILE_HANDLE LastHandle; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; // // ASERT for FileHandle, FilePath, and DeviceHandle being NULL @@ -486,7 +538,7 @@ ShellOpenFileByDevicePath( if (EFI_ERROR (Status)) { return Status; } - Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle); + Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); if (EFI_ERROR (Status)) { FileHandle = NULL; return Status; @@ -501,43 +553,43 @@ ShellOpenFileByDevicePath( // if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP - ) { + ) { FileHandle = NULL; return (EFI_INVALID_PARAMETER); } // // Open this file path node // - LastHandle = *FileHandle; - *FileHandle = NULL; + Handle2 = Handle1; + Handle1 = NULL; // // Try to test opening an existing file // - Status = LastHandle->Open ( - LastHandle, - FileHandle, + Status = Handle2->Open ( + Handle2, + &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode &~EFI_FILE_MODE_CREATE, 0 - ); + ); // // see if the error was that it needs to be created // if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { - Status = LastHandle->Open ( - LastHandle, - FileHandle, + Status = Handle2->Open ( + Handle2, + &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode, Attributes - ); + ); } // // Close the last node // - LastHandle->Close (LastHandle); + Handle2->Close (Handle2); if (EFI_ERROR(Status)) { return (Status); @@ -548,6 +600,11 @@ ShellOpenFileByDevicePath( // *FilePath = NextDevicePathNode (*FilePath); } + + // + // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! + // + *FileHandle = (VOID*)Handle1; return (EFI_SUCCESS); } @@ -586,10 +643,11 @@ EFI_STATUS EFIAPI ShellOpenFileByName( IN CONST CHAR16 *FileName, - OUT EFI_FILE_HANDLE *FileHandle, + OUT SHELL_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes - ) { + ) +{ EFI_HANDLE DeviceHandle; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_STATUS Status; @@ -600,14 +658,21 @@ ShellOpenFileByName( // ASSERT(FileName != NULL); + if (FileName == NULL) { + return (EFI_INVALID_PARAMETER); + } + if (mEfiShellProtocol != NULL) { + if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE && (Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) { + return ShellCreateDirectory(FileName, FileHandle); + } // // Use UEFI Shell 2.0 method // Status = mEfiShellProtocol->OpenFileByName(FileName, FileHandle, OpenMode); - if (!EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){ + if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){ FileInfo = FileFunctionMap.GetFileInfo(*FileHandle); ASSERT(FileInfo != NULL); FileInfo->Attribute = Attributes; @@ -628,7 +693,7 @@ ShellOpenFileByName( &DeviceHandle, FileHandle, OpenMode, - Attributes )); + Attributes)); } return (EFI_DEVICE_ERROR); } @@ -664,8 +729,9 @@ EFI_STATUS EFIAPI ShellCreateDirectory( IN CONST CHAR16 *DirectoryName, - OUT EFI_FILE_HANDLE *FileHandle - ) { + OUT SHELL_FILE_HANDLE *FileHandle + ) +{ if (mEfiShellProtocol != NULL) { // // Use UEFI Shell 2.0 method @@ -673,13 +739,13 @@ ShellCreateDirectory( return (mEfiShellProtocol->CreateFile(DirectoryName, EFI_FILE_DIRECTORY, FileHandle - )); + )); } else { return (ShellOpenFileByName(DirectoryName, FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY - )); + )); } } @@ -715,10 +781,11 @@ ShellCreateDirectory( EFI_STATUS EFIAPI ShellReadFile( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *BufferSize, OUT VOID *Buffer - ) { + ) +{ return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer)); } @@ -750,10 +817,11 @@ ShellReadFile( EFI_STATUS EFIAPI ShellWriteFile( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN OUT UINTN *BufferSize, IN VOID *Buffer - ) { + ) +{ return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer)); } @@ -771,8 +839,9 @@ ShellWriteFile( EFI_STATUS EFIAPI ShellCloseFile ( - IN EFI_FILE_HANDLE *FileHandle - ) { + IN SHELL_FILE_HANDLE *FileHandle + ) +{ return (FileFunctionMap.CloseFile(*FileHandle)); } @@ -793,8 +862,9 @@ ShellCloseFile ( EFI_STATUS EFIAPI ShellDeleteFile ( - IN EFI_FILE_HANDLE *FileHandle - ) { + IN SHELL_FILE_HANDLE *FileHandle + ) +{ return (FileFunctionMap.DeleteFile(*FileHandle)); } @@ -820,9 +890,10 @@ ShellDeleteFile ( EFI_STATUS EFIAPI ShellSetFilePosition ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, IN UINT64 Position - ) { + ) +{ return (FileFunctionMap.SetFilePosition(FileHandle, Position)); } @@ -844,9 +915,10 @@ ShellSetFilePosition ( EFI_STATUS EFIAPI ShellGetFilePosition ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Position - ) { + ) +{ return (FileFunctionMap.GetFilePosition(FileHandle, Position)); } /** @@ -866,8 +938,9 @@ ShellGetFilePosition ( EFI_STATUS EFIAPI ShellFlushFile ( - IN EFI_FILE_HANDLE FileHandle - ) { + IN SHELL_FILE_HANDLE FileHandle + ) +{ return (FileFunctionMap.FlushFile(FileHandle)); } @@ -892,9 +965,10 @@ ShellFlushFile ( EFI_STATUS EFIAPI ShellFindFirstFile ( - IN EFI_FILE_HANDLE DirHandle, + IN SHELL_FILE_HANDLE DirHandle, OUT EFI_FILE_INFO **Buffer - ) { + ) +{ // // pass to file handle lib // @@ -903,7 +977,7 @@ ShellFindFirstFile ( /** Retrieves the next file in a directory. - To use this function, caller must call the LibFindFirstFile() to get the + To use this function, caller must call the ShellFindFirstFile() to get the first file, and then use this function get other files. This function can be called for several times to get each file's information in the directory. If the call of ShellFindNextFile() got the last file in the directory, the next @@ -922,10 +996,11 @@ ShellFindFirstFile ( EFI_STATUS EFIAPI ShellFindNextFile( - IN EFI_FILE_HANDLE DirHandle, + IN SHELL_FILE_HANDLE DirHandle, OUT EFI_FILE_INFO *Buffer, OUT BOOLEAN *NoFile - ) { + ) +{ // // pass to file handle lib // @@ -949,9 +1024,10 @@ ShellFindNextFile( EFI_STATUS EFIAPI ShellGetFileSize ( - IN EFI_FILE_HANDLE FileHandle, + IN SHELL_FILE_HANDLE FileHandle, OUT UINT64 *Size - ) { + ) +{ return (FileFunctionMap.GetFileSize(FileHandle, Size)); } /** @@ -1062,34 +1138,38 @@ ShellSetEnvironmentVariable ( // return (EFI_UNSUPPORTED); } + /** - cause the shell to parse and execute a command line. + Cause the shell to parse and execute a command line. This function creates a nested instance of the shell and executes the specified -command (CommandLine) with the specified environment (Environment). Upon return, -the status code returned by the specified command is placed in StatusCode. -If Environment is NULL, then the current environment is used and all changes made -by the commands executed will be reflected in the current environment. If the -Environment is non-NULL, then the changes made will be discarded. -The CommandLine is executed from the current working directory on the current -device. - -EnvironmentVariables and Status are only supported for UEFI Shell 2.0. -Output is only supported for pre-UEFI Shell 2.0 - - @param ImageHandle Parent image that is starting the operation - @param CommandLine pointer to NULL terminated command line. - @param Output true to display debug output. false to hide it. - @param EnvironmentVariables optional pointer to array of environment variables - in the form "x=y". if NULL current set is used. - @param Status the status of the run command line. - - @retval EFI_SUCCESS the operation completed sucessfully. Status - contains the status code returned. - @retval EFI_INVALID_PARAMETER a parameter contains an invalid value - @retval EFI_OUT_OF_RESOURCES out of resources - @retval EFI_UNSUPPORTED the operation is not allowed. + command (CommandLine) with the specified environment (Environment). Upon return, + the status code returned by the specified command is placed in StatusCode. + If Environment is NULL, then the current environment is used and all changes made + by the commands executed will be reflected in the current environment. If the + Environment is non-NULL, then the changes made will be discarded. + The CommandLine is executed from the current working directory on the current + device. + + The EnvironmentVariables and Status parameters are ignored in a pre-UEFI Shell 2.0 + environment. The values pointed to by the parameters will be unchanged by the + ShellExecute() function. The Output parameter has no effect in a + UEFI Shell 2.0 environment. + + @param[in] ParentHandle The parent image starting the operation. + @param[in] CommandLine The pointer to a NULL terminated command line. + @param[in] Output True to display debug output. False to hide it. + @param[in] EnvironmentVariables Optional pointer to array of environment variables + in the form "x=y". If NULL, the current set is used. + @param[out] Status The status of the run command line. + + @retval EFI_SUCCESS The operation completed sucessfully. Status + contains the status code returned. + @retval EFI_INVALID_PARAMETER A parameter contains an invalid value. + @retval EFI_OUT_OF_RESOURCES Out of resources. + @retval EFI_UNSUPPORTED The operation is not allowed. **/ + EFI_STATUS EFIAPI ShellExecute ( @@ -1139,7 +1219,7 @@ ShellExecute ( CONST CHAR16* EFIAPI ShellGetCurrentDir ( - IN CHAR16 *DeviceName OPTIONAL + IN CHAR16 * CONST DeviceName OPTIONAL ) { // @@ -1225,7 +1305,7 @@ typedef struct { EFI_STATUS Status; CHAR16 *FullName; CHAR16 *FileName; - EFI_FILE_HANDLE Handle; + SHELL_FILE_HANDLE Handle; EFI_FILE_INFO *Info; } EFI_SHELL_FILE_INFO_NO_CONST; @@ -1238,7 +1318,7 @@ typedef struct { EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via the ShellCloseFileMetaArg function. - @param[in] FileList the EFI shell list type + @param[in] FileList the EFI shell list type @param[in,out] ListHead the list to add to @retval the resultant head of the double linked new format list; @@ -1265,11 +1345,18 @@ InternalShellConvertFileListType ( // for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) { OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE); + ASSERT(OldInfo != NULL); + + // + // Skip ones that failed to open... + // + if (OldInfo->Status != EFI_SUCCESS) { + continue; + } // // make sure the old list was valid // - ASSERT(OldInfo != NULL); ASSERT(OldInfo->Info != NULL); ASSERT(OldInfo->FullName != NULL); ASSERT(OldInfo->FileName != NULL); @@ -1339,8 +1426,6 @@ InternalShellConvertFileListType ( @retval EFI_SUCCESS the operation was sucessful and the list head contains the list of opened files - #retval EFI_UNSUPPORTED a previous ShellOpenFileMetaArg must be closed first. - *ListHead is set to NULL. @return != EFI_SUCCESS the operation failed @sa InternalShellConvertFileListType @@ -1381,6 +1466,11 @@ ShellOpenFileMetaArg ( } else { Status = mEfiShellProtocol->RemoveDupInFileList(ListHead); } + if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) { + FreePool(*ListHead); + *ListHead = NULL; + return (EFI_NOT_FOUND); + } return (Status); } @@ -1408,6 +1498,7 @@ ShellOpenFileMetaArg ( if (*ListHead == NULL) { return (EFI_OUT_OF_RESOURCES); } + InitializeListHead(&((*ListHead)->Link)); } // @@ -1420,16 +1511,22 @@ ShellOpenFileMetaArg ( // mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList); + if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) { + FreePool(*ListHead); + *ListHead = NULL; + Status = EFI_NOT_FOUND; + } + return (Status); } /** - Free the linked list returned from ShellOpenFileMetaArg + Free the linked list returned from ShellOpenFileMetaArg. - if ListHead is NULL then ASSERT() + if ListHead is NULL then ASSERT(). - @param ListHead the pointer to free + @param ListHead the pointer to free. - @retval EFI_SUCCESS the operation was sucessful + @retval EFI_SUCCESS the operation was sucessful. **/ EFI_STATUS EFIAPI @@ -1455,10 +1552,10 @@ ShellCloseFileMetaArg ( // of the list // for ( Node = GetFirstNode(&(*ListHead)->Link) - ; IsListEmpty(&(*ListHead)->Link) == FALSE + ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link) ; Node = GetFirstNode(&(*ListHead)->Link)) { RemoveEntryList(Node); - ((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle); + ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle); FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName); FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName); FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info); @@ -1487,7 +1584,7 @@ ShellFindFilePath ( ) { CONST CHAR16 *Path; - EFI_FILE_HANDLE Handle; + SHELL_FILE_HANDLE Handle; EFI_STATUS Status; CHAR16 *RetVal; CHAR16 *TestPath; @@ -1497,6 +1594,21 @@ ShellFindFilePath ( RetVal = NULL; + // + // First make sure its not an absolute path. + // + Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0); + if (!EFI_ERROR(Status)){ + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0); + ShellCloseFile(&Handle); + return (RetVal); + } else { + ShellCloseFile(&Handle); + } + } + Path = ShellGetEnvironmentVariable(L"cwd"); if (Path != NULL) { Size = StrSize(Path); @@ -1510,22 +1622,23 @@ ShellFindFilePath ( StrCat(TestPath, FileName); Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0); if (!EFI_ERROR(Status)){ - RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); - ShellCloseFile(&Handle); - FreePool(TestPath); - return (RetVal); + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); + ShellCloseFile(&Handle); + FreePool(TestPath); + return (RetVal); + } else { + ShellCloseFile(&Handle); + } } FreePool(TestPath); } Path = ShellGetEnvironmentVariable(L"path"); if (Path != NULL) { - Size = StrSize(Path); + Size = StrSize(Path)+sizeof(CHAR16); Size += StrSize(FileName); TestPath = AllocateZeroPool(Size); - ASSERT(TestPath != NULL); - if (TestPath == NULL) { - return (NULL); - } Walker = (CHAR16*)Path; do { CopyMem(TestPath, Walker, StrSize(Walker)); @@ -1533,6 +1646,9 @@ ShellFindFilePath ( if (TempChar != NULL) { *TempChar = CHAR_NULL; } + if (TestPath[StrLen(TestPath)-1] != L'\\') { + StrCat(TestPath, L"\\"); + } StrCat(TestPath, FileName); if (StrStr(Walker, L";") != NULL) { Walker = StrStr(Walker, L";") + 1; @@ -1541,9 +1657,14 @@ ShellFindFilePath ( } Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0); if (!EFI_ERROR(Status)){ - RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); - ShellCloseFile(&Handle); - break; + if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) { + ASSERT(RetVal == NULL); + RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0); + ShellCloseFile(&Handle); + break; + } else { + ShellCloseFile(&Handle); + } } } while (Walker != NULL && Walker[0] != CHAR_NULL); FreePool(TestPath); @@ -1596,9 +1717,11 @@ ShellFindFilePathEx ( if (TestPath == NULL) { return (NULL); } - for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1 ){ + for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){ StrCpy(TestPath, FileName); - StrCat(TestPath, ExtensionWalker); + if (ExtensionWalker != NULL) { + StrCat(TestPath, ExtensionWalker); + } TempChar = StrStr(TestPath, L";"); if (TempChar != NULL) { *TempChar = CHAR_NULL; @@ -1607,6 +1730,7 @@ ShellFindFilePathEx ( if (RetVal != NULL) { break; } + ASSERT(ExtensionWalker != NULL); TempChar2 = StrStr(ExtensionWalker, L";"); } FreePool(TestPath); @@ -1616,7 +1740,7 @@ ShellFindFilePathEx ( typedef struct { LIST_ENTRY Link; CHAR16 *Name; - ParamType Type; + SHELL_PARAM_TYPE Type; CHAR16 *Value; UINTN OriginalPosition; } SHELL_PARAM_PACKAGE; @@ -1629,9 +1753,9 @@ typedef struct { if Name is NULL then ASSERT(); if Type is NULL then ASSERT(); - @param Type pointer to type of parameter if it was found @param Name pointer to Name of parameter found @param CheckList List to check against + @param Type pointer to type of parameter if it was found @retval TRUE the Parameter was found. Type is valid. @retval FALSE the Parameter was not found. Type is not valid. @@ -1641,8 +1765,9 @@ EFIAPI InternalIsOnCheckList ( IN CONST CHAR16 *Name, IN CONST SHELL_PARAM_ITEM *CheckList, - OUT ParamType *Type - ) { + OUT SHELL_PARAM_TYPE *Type + ) +{ SHELL_PARAM_ITEM *TempListItem; // @@ -1657,7 +1782,7 @@ InternalIsOnCheckList ( // if ((StrCmp(Name, L"-?") == 0) || (StrCmp(Name, L"-b") == 0) - ) { + ) { return (TRUE); } @@ -1683,10 +1808,11 @@ InternalIsOnCheckList ( /** Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+' - @param Name pointer to Name of parameter found + @param[in] Name pointer to Name of parameter found + @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not. @retval TRUE the Parameter is a flag. - @retval FALSE the Parameter not a flag + @retval FALSE the Parameter not a flag. **/ BOOLEAN EFIAPI @@ -1703,17 +1829,17 @@ InternalIsFlag ( // // If we accept numbers then dont return TRUE. (they will be values) // - if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers != FALSE) { + if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers) { return (FALSE); } // - // If the Name has a / or - as the first character return TRUE + // If the Name has a /, +, or - as the first character return TRUE // if ((Name[0] == L'/') || (Name[0] == L'-') || (Name[0] == L'+') - ) { + ) { return (TRUE); } return (FALSE); @@ -1724,14 +1850,15 @@ InternalIsFlag ( If no initialization is required, then return RETURN_SUCCESS. - @param CheckList pointer to list of parameters to check - @param CheckPackage pointer to pointer to list checked values - @param ProblemParam optional pointer to pointer to unicode string for + @param[in] CheckList pointer to list of parameters to check + @param[out] CheckPackage pointer to pointer to list checked values + @param[out] ProblemParam optional pointer to pointer to unicode string for the paramater that caused failure. If used then the caller is responsible for freeing the memory. - @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter - @param Argc Count of parameters in Argv - @param Argv pointer to array of parameters + @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter + @param[in] Argv pointer to array of parameters + @param[in] Argc Count of parameters in Argv + @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise. @retval EFI_SUCCESS The operation completed sucessfully. @retval EFI_OUT_OF_RESOURCES A memory allocation failed @@ -1743,7 +1870,6 @@ InternalIsFlag ( the invalid command line argument was returned in ProblemParam if provided. **/ -STATIC EFI_STATUS EFIAPI InternalCommandLineParse ( @@ -1754,22 +1880,24 @@ InternalCommandLineParse ( IN CONST CHAR16 **Argv, IN UINTN Argc, IN BOOLEAN AlwaysAllowNumbers - ) { + ) +{ UINTN LoopCounter; - ParamType CurrentItemType; + SHELL_PARAM_TYPE CurrentItemType; SHELL_PARAM_PACKAGE *CurrentItemPackage; UINTN GetItemValue; UINTN ValueSize; + UINTN Count; CurrentItemPackage = NULL; - mTotalParameterCount = 0; GetItemValue = 0; ValueSize = 0; + Count = 0; // // If there is only 1 item we dont need to do anything // - if (Argc <= 1) { + if (Argc < 1) { *CheckPackage = NULL; return (EFI_SUCCESS); } @@ -1794,7 +1922,7 @@ InternalCommandLineParse ( // // do nothing for NULL argv // - } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) != FALSE) { + } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) { // // We might have leftover if last parameter didnt have optional value // @@ -1841,7 +1969,7 @@ InternalCommandLineParse ( ASSERT(GetItemValue == 0); break; } - } else if (GetItemValue != 0 && InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) { + } else if (GetItemValue != 0 && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers)) { ASSERT(CurrentItemPackage != NULL); // // get the item VALUE for a previous flag @@ -1859,7 +1987,7 @@ InternalCommandLineParse ( if (GetItemValue == 0) { InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); } - } else if (InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) { + } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) ){ //|| ProblemParam == NULL) { // // add this one as a non-flag // @@ -1870,9 +1998,9 @@ InternalCommandLineParse ( CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter])); ASSERT(CurrentItemPackage->Value != NULL); StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]); - CurrentItemPackage->OriginalPosition = mTotalParameterCount++; + CurrentItemPackage->OriginalPosition = Count++; InsertHeadList(*CheckPackage, &CurrentItemPackage->Link); - } else if (ProblemParam) { + } else if (ProblemParam != NULL) { // // this was a non-recognised flag... error! // @@ -1883,9 +2011,7 @@ InternalCommandLineParse ( *CheckPackage = NULL; return (EFI_VOLUME_CORRUPTED); } else { - ShellCommandLineFreeVarList(*CheckPackage); - *CheckPackage = NULL; - return (EFI_VOLUME_CORRUPTED); + //ASSERT(FALSE); } } if (GetItemValue != 0) { @@ -1907,23 +2033,22 @@ InternalCommandLineParse ( If no initialization is required, then return RETURN_SUCCESS. - @param CheckList pointer to list of parameters to check - @param CheckPackage pointer to pointer to list checked values - @param ProblemParam optional pointer to pointer to unicode string for + @param[in] CheckList The pointer to list of parameters to check. + @param[out] CheckPackage The package of checked values. + @param[out] ProblemParam Optional pointer to pointer to unicode string for the paramater that caused failure. - @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter + @param[in] AutoPageBreak Will automatically set PageBreakEnabled. + @param[in] AlwaysAllowNumbers Will never fail for number based flags. @retval EFI_SUCCESS The operation completed sucessfully. - @retval EFI_OUT_OF_RESOURCES A memory allocation failed - @retval EFI_INVALID_PARAMETER A parameter was invalid - @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was - duplicated. the duplicated command line argument - was returned in ProblemParam if provided. - @retval EFI_DEVICE_ERROR the commands contained 2 opposing arguments. one + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_VOLUME_CORRUPTED The command line was corrupt. + @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One of the command line arguments was returned in ProblemParam if provided. - @retval EFI_NOT_FOUND a argument required a value that was missing. - the invalid command line argument was returned in + @retval EFI_NOT_FOUND A argument required a value that was missing. + The invalid command line argument was returned in ProblemParam if provided. **/ EFI_STATUS @@ -1934,7 +2059,8 @@ ShellCommandLineParseEx ( OUT CHAR16 **ProblemParam OPTIONAL, IN BOOLEAN AutoPageBreak, IN BOOLEAN AlwaysAllowNumbers - ) { + ) +{ // // ASSERT that CheckList and CheckPackage aren't NULL // @@ -1983,7 +2109,8 @@ VOID EFIAPI ShellCommandLineFreeVarList ( IN LIST_ENTRY *CheckPackage - ) { + ) +{ LIST_ENTRY *Node; // @@ -1997,9 +2124,9 @@ ShellCommandLineFreeVarList ( // for each node in the list // for ( Node = GetFirstNode(CheckPackage) - ; IsListEmpty(CheckPackage) == FALSE + ; !IsListEmpty(CheckPackage) ; Node = GetFirstNode(CheckPackage) - ){ + ){ // // Remove it from the list // @@ -2046,9 +2173,10 @@ ShellCommandLineFreeVarList ( BOOLEAN EFIAPI ShellCommandLineGetFlag ( - IN CONST LIST_ENTRY *CheckPackage, - IN CHAR16 *KeyString - ) { + IN CONST LIST_ENTRY * CONST CheckPackage, + IN CONST CHAR16 * CONST KeyString + ) +{ LIST_ENTRY *Node; // @@ -2069,7 +2197,7 @@ ShellCommandLineGetFlag ( for ( Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) - ){ + ){ // // If the Name matches, return TRUE (and there may be NULL name) // @@ -2079,7 +2207,7 @@ ShellCommandLineGetFlag ( // if ( ((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0 - ){ + ){ return (TRUE); } else if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { return (TRUE); @@ -2089,24 +2217,25 @@ ShellCommandLineGetFlag ( return (FALSE); } /** - returns value from command line argument + Returns value from command line argument. - value parameters are in the form of "- value" or "/ value" + Value parameters are in the form of "- value" or "/ value". - if CheckPackage is NULL, then return NULL; + If CheckPackage is NULL, then return NULL. - @param CheckPackage The package of parsed command line arguments - @param KeyString the Key of the command line argument to check for + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] KeyString The Key of the command line argument to check for. - @retval NULL the flag is not on the command line - @return !=NULL pointer to unicode string of the value - **/ + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. +**/ CONST CHAR16* EFIAPI ShellCommandLineGetValue ( IN CONST LIST_ENTRY *CheckPackage, IN CHAR16 *KeyString - ) { + ) +{ LIST_ENTRY *Node; // @@ -2122,7 +2251,7 @@ ShellCommandLineGetValue ( for ( Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) - ){ + ){ // // If the Name matches, return the value (name can be NULL) // @@ -2132,7 +2261,7 @@ ShellCommandLineGetValue ( // if ( ((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart && StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0 - ){ + ){ // // return the string part after the flag // @@ -2147,25 +2276,27 @@ ShellCommandLineGetValue ( } return (NULL); } + /** - returns raw value from command line argument + Returns raw value from command line argument. - raw value parameters are in the form of "value" in a specific position in the list + Raw value parameters are in the form of "value" in a specific position in the list. - if CheckPackage is NULL, then return NULL; + If CheckPackage is NULL, then return NULL. - @param CheckPackage The package of parsed command line arguments - @param Position the position of the value + @param[in] CheckPackage The package of parsed command line arguments. + @param[in] Position The position of the value. - @retval NULL the flag is not on the command line - @return !=NULL pointer to unicode string of the value + @retval NULL The flag is not on the command line. + @retval !=NULL The pointer to unicode string of the value. **/ CONST CHAR16* EFIAPI ShellCommandLineGetRawValue ( - IN CONST LIST_ENTRY *CheckPackage, - IN UINT32 Position - ) { + IN CONST LIST_ENTRY * CONST CheckPackage, + IN UINTN Position + ) +{ LIST_ENTRY *Node; // @@ -2181,7 +2312,7 @@ ShellCommandLineGetRawValue ( for ( Node = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node) ; Node = GetNextNode(CheckPackage, Node) - ){ + ){ // // If the position matches, return the value // @@ -2197,16 +2328,32 @@ ShellCommandLineGetRawValue ( this will not include flags. + @param[in] CheckPackage The package of parsed command line arguments. + @retval (UINTN)-1 No parsing has ocurred @return other The number of value parameters found **/ UINTN EFIAPI ShellCommandLineGetCount( - VOID + IN CONST LIST_ENTRY *CheckPackage ) { - return (mTotalParameterCount); + LIST_ENTRY *Node1; + UINTN Count; + + if (CheckPackage == NULL) { + return (0); + } + for ( Node1 = GetFirstNode(CheckPackage), Count = 0 + ; !IsNull (CheckPackage, Node1) + ; Node1 = GetNextNode(CheckPackage, Node1) + ){ + if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) { + Count++; + } + } + return (Count); } /** @@ -2238,12 +2385,12 @@ ShellCommandLineCheckDuplicate ( for ( Node1 = GetFirstNode(CheckPackage) ; !IsNull (CheckPackage, Node1) ; Node1 = GetNextNode(CheckPackage, Node1) - ){ + ){ for ( Node2 = GetNextNode(CheckPackage, Node1) ; !IsNull (CheckPackage, Node2) ; Node2 = GetNextNode(CheckPackage, Node2) - ){ - if (StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) { + ){ + if ((((SHELL_PARAM_PACKAGE*)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE*)Node2)->Name != NULL) && StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) { if (Param != NULL) { *Param = NULL; *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0); @@ -2263,13 +2410,14 @@ ShellCommandLineCheckDuplicate ( If the string would grow bigger than NewSize it will halt and return error. - @param[in] SourceString String with source buffer - @param[in,out] NewString String with resultant buffer - @param[in] NewSize Size in bytes of NewString - @param[in] FindTarget String to look for - @param[in[ ReplaceWith String to replace FindTarget with + @param[in] SourceString The string with source buffer. + @param[in,out] NewString The string with resultant buffer. + @param[in] NewSize The size in bytes of NewString. + @param[in] FindTarget The string to look for. + @param[in] ReplaceWith The string to replace FindTarget with. @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^' immediately before it. + @param[in] ParameterReplacing If TRUE will add "" around items with spaces. @retval EFI_INVALID_PARAMETER SourceString was NULL. @retval EFI_INVALID_PARAMETER NewString was NULL. @@ -2279,54 +2427,66 @@ ShellCommandLineCheckDuplicate ( @retval EFI_INVALID_PARAMETER SourceString had length < 1. @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold the new string (truncation occurred). - @retval EFI_SUCCESS the string was sucessfully copied with replacement. + @retval EFI_SUCCESS The string was successfully copied with replacement. **/ - EFI_STATUS EFIAPI -ShellCopySearchAndReplace2( +ShellCopySearchAndReplace( IN CHAR16 CONST *SourceString, - IN CHAR16 *NewString, + IN OUT CHAR16 *NewString, IN UINTN NewSize, IN CONST CHAR16 *FindTarget, IN CONST CHAR16 *ReplaceWith, - IN CONST BOOLEAN SkipPreCarrot + IN CONST BOOLEAN SkipPreCarrot, + IN CONST BOOLEAN ParameterReplacing ) { UINTN Size; + CHAR16 *Replace; + if ( (SourceString == NULL) || (NewString == NULL) || (FindTarget == NULL) || (ReplaceWith == NULL) || (StrLen(FindTarget) < 1) || (StrLen(SourceString) < 1) - ){ + ){ return (EFI_INVALID_PARAMETER); } + Replace = NULL; + if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) { + Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0); + } else { + Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16)); + UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith); + } NewString = SetMem16(NewString, NewSize, CHAR_NULL); while (*SourceString != CHAR_NULL) { // - // if we find the FindTarget and either Skip == FALSE or Skip == TRUE and we + // if we find the FindTarget and either Skip == FALSE or Skip and we // dont have a carrot do a replace... // if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0 - && ((SkipPreCarrot && *(SourceString-1) != L'^') || SkipPreCarrot == FALSE) - ){ + && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot) + ){ SourceString += StrLen(FindTarget); Size = StrSize(NewString); - if ((Size + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) { + if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) { + FreePool(Replace); return (EFI_BUFFER_TOO_SMALL); } - StrCat(NewString, ReplaceWith); + StrCat(NewString, Replace); } else { Size = StrSize(NewString); if (Size + sizeof(CHAR16) > NewSize) { + FreePool(Replace); return (EFI_BUFFER_TOO_SMALL); } StrnCat(NewString, SourceString, 1); SourceString++; } } + FreePool(Replace); return (EFI_SUCCESS); } @@ -2348,15 +2508,18 @@ InternalPrintTo ( { UINTN Size; Size = StrSize(String) - sizeof(CHAR16); + if (Size == 0) { + return (EFI_SUCCESS); + } if (mEfiShellParametersProtocol != NULL) { - return (mEfiShellParametersProtocol->StdOut->Write(mEfiShellParametersProtocol->StdOut, &Size, (VOID*)String)); + return (mEfiShellProtocol->WriteFile(mEfiShellParametersProtocol->StdOut, &Size, (VOID*)String)); } if (mEfiShellInterface != NULL) { // // Divide in half for old shell. Must be string length not size. // Size /= 2; - return ( mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String)); + return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String)); } ASSERT(FALSE); return (EFI_UNSUPPORTED); @@ -2388,10 +2551,10 @@ InternalPrintTo ( @param[in] Format the format string @param[in] Marker the marker for the variable argument list - @return the number of characters printed to the screen + @return EFI_SUCCESS The operation was successful. + @return EFI_DEVICE_ERROR The console device reported an error. **/ - -UINTN +EFI_STATUS EFIAPI InternalShellPrintWorker( IN INT32 Col OPTIONAL, @@ -2400,37 +2563,38 @@ InternalShellPrintWorker( VA_LIST Marker ) { - UINTN Return; EFI_STATUS Status; - UINTN NormalAttribute; CHAR16 *ResumeLocation; CHAR16 *FormatWalker; + UINTN OriginalAttribute; + + Status = EFI_SUCCESS; + OriginalAttribute = gST->ConOut->Mode->Attribute; // // Back and forth each time fixing up 1 of our flags... // - Status = ShellLibCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N"); + Status = ShellCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE); ASSERT_EFI_ERROR(Status); - Status = ShellLibCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E"); + Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE); ASSERT_EFI_ERROR(Status); - Status = ShellLibCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H"); + Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE); ASSERT_EFI_ERROR(Status); - Status = ShellLibCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B"); + Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE); ASSERT_EFI_ERROR(Status); - Status = ShellLibCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V"); + Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE); ASSERT_EFI_ERROR(Status); // // Use the last buffer from replacing to print from... // - Return = UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker); + UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker); if (Col != -1 && Row != -1) { Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row); ASSERT_EFI_ERROR(Status); } - NormalAttribute = gST->ConOut->Mode->Attribute; FormatWalker = mPostReplaceFormat2; while (*FormatWalker != CHAR_NULL) { // @@ -2443,34 +2607,41 @@ InternalShellPrintWorker( // // print the current FormatWalker string // - Status = InternalPrintTo(FormatWalker); - ASSERT_EFI_ERROR(Status); + if (StrLen(FormatWalker)>0) { + Status = InternalPrintTo(FormatWalker); + if (EFI_ERROR(Status)) { + break; + } + } + // // update the attribute // if (ResumeLocation != NULL) { switch (*(ResumeLocation+1)) { case (L'N'): - gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute); + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); break; case (L'E'): - gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); break; case (L'H'): - gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); break; case (L'B'): - gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); break; case (L'V'): - gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((NormalAttribute&(BIT4|BIT5|BIT6))>>4))); + gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))); break; default: // // Print a simple '%' symbol // Status = InternalPrintTo(L"%"); - ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + break; + } ResumeLocation = ResumeLocation - 1; break; } @@ -2478,7 +2649,6 @@ InternalShellPrintWorker( // // reset to normal now... // - gST->ConOut->SetAttribute(gST->ConOut, NormalAttribute); break; } @@ -2488,7 +2658,8 @@ InternalShellPrintWorker( FormatWalker = ResumeLocation + 2; } - return (Return); + gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute); + return (Status); } /** @@ -2512,14 +2683,15 @@ InternalShellPrintWorker( Note: The background color is controlled by the shell command cls. - @param[in] Row the row to print at @param[in] Col the column to print at + @param[in] Row the row to print at @param[in] Format the format string + @param[in] ... The variable argument list. - @return the number of characters printed to the screen + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. **/ - -UINTN +EFI_STATUS EFIAPI ShellPrintEx( IN INT32 Col OPTIONAL, @@ -2529,11 +2701,11 @@ ShellPrintEx( ) { VA_LIST Marker; - EFI_STATUS Status; + EFI_STATUS RetVal; VA_START (Marker, Format); - Status = InternalShellPrintWorker(Col, Row, Format, Marker); + RetVal = InternalShellPrintWorker(Col, Row, Format, Marker); VA_END(Marker); - return(Status); + return(RetVal); } /** @@ -2557,16 +2729,18 @@ ShellPrintEx( Note: The background color is controlled by the shell command cls. - @param[in] Row The row to print at. @param[in] Col The column to print at. + @param[in] Row The row to print at. @param[in] Language The language of the string to retrieve. If this parameter is NULL, then the current platform language is used. @param[in] HiiFormatStringId The format string Id for getting from Hii. @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param[in] ... The variable argument list. - @return the number of characters printed to the screen. + @return EFI_SUCCESS The printing was successful. + @return EFI_DEVICE_ERROR The console device reported an error. **/ -UINTN +EFI_STATUS EFIAPI ShellPrintHiiEx( IN INT32 Col OPTIONAL, @@ -2579,7 +2753,7 @@ ShellPrintHiiEx( { VA_LIST Marker; CHAR16 *HiiFormatString; - UINTN RetVal; + EFI_STATUS RetVal; VA_START (Marker, HiiFormatHandle); HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language); @@ -2587,7 +2761,7 @@ ShellPrintHiiEx( RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker); - FreePool(HiiFormatString); + SHELL_FREE_NON_NULL(HiiFormatString); VA_END(Marker); return (RetVal); @@ -2609,14 +2783,38 @@ ShellIsDirectory( ) { EFI_STATUS Status; - EFI_FILE_HANDLE Handle; + SHELL_FILE_HANDLE Handle; + CHAR16 *TempLocation; ASSERT(DirName != NULL); - Handle = NULL; + Handle = NULL; + TempLocation = NULL; Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { + // + // try good logic first. + // + if (mEfiShellProtocol != NULL) { + TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0); + if (StrStr(TempLocation, L":") != NULL && StrLen(StrStr(TempLocation, L":")) == 2) { + *(StrStr(TempLocation, L":")+1) = CHAR_NULL; + } + if (mEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) { + FreePool(TempLocation); + return (EFI_SUCCESS); + } + FreePool(TempLocation); + } else { + // + // probably a map name?!?!!? + // + TempLocation = StrStr(DirName, L"\\"); + if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) { + return (EFI_SUCCESS); + } + } return (Status); } @@ -2644,7 +2842,7 @@ ShellIsFile( ) { EFI_STATUS Status; - EFI_FILE_HANDLE Handle; + SHELL_FILE_HANDLE Handle; ASSERT(Name != NULL); @@ -2680,12 +2878,13 @@ EFI_STATUS EFIAPI ShellIsFileInPath( IN CONST CHAR16 *Name - ) { + ) +{ CHAR16 *NewName; EFI_STATUS Status; if (!EFI_ERROR(ShellIsFile(Name))) { - return (TRUE); + return (EFI_SUCCESS); } NewName = ShellFindFilePath(Name); @@ -2836,10 +3035,10 @@ StrnCatGrow ( This function will display the requested question on the shell prompt and then wait for an apropriate answer to be input from the console. - if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, SHELL_PROMPT_REQUEST_TYPE_QUIT_CONTINUE + if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE. - if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_FREEFORM then *Response is of type + if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type CHAR16*. In either case *Response must be callee freed if Response was not NULL; @@ -2852,7 +3051,6 @@ StrnCatGrow ( @retval EFI_SUCCESS The operation was sucessful. @retval EFI_UNSUPPORTED The operation is not supported as requested. @retval EFI_INVALID_PARAMETER A parameter was invalid. - @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @return other The operation failed. **/ EFI_STATUS @@ -2867,15 +3065,19 @@ ShellPromptForResponse ( EFI_INPUT_KEY Key; UINTN EventIndex; SHELL_PROMPT_RESPONSE *Resp; + UINTN Size; + CHAR16 *Buffer; - Status = EFI_SUCCESS; - Resp = (SHELL_PROMPT_RESPONSE*)AllocatePool(sizeof(SHELL_PROMPT_RESPONSE)); - if (Resp == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_UNSUPPORTED; + Resp = NULL; + Buffer = NULL; + Size = 0; + if (Type != ShellPromptResponseTypeFreeform) { + Resp = (SHELL_PROMPT_RESPONSE*)AllocatePool(sizeof(SHELL_PROMPT_RESPONSE)); } switch(Type) { - case SHELL_PROMPT_REQUEST_TYPE_QUIT_CONTINUE: + case ShellPromptResponseTypeQuitContinue: if (Prompt != NULL) { ShellPrintEx(-1, -1, L"%s", Prompt); } @@ -2887,20 +3089,20 @@ ShellPromptForResponse ( ASSERT_EFI_ERROR(Status); ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') { - *Resp = SHELL_PROMPT_RESPONSE_QUIT; + *Resp = ShellPromptResponseQuit; } else { - *Resp = SHELL_PROMPT_RESPONSE_CONTINUE; + *Resp = ShellPromptResponseContinue; } break; - case SHELL_PROMPT_REQUEST_TYPE_YES_NO_ALL_CANCEL: + case ShellPromptResponseTypeYesNoCancel: if (Prompt != NULL) { ShellPrintEx(-1, -1, L"%s", Prompt); } // // wait for valid response // - *Resp = SHELL_PROMPT_RESPONSE_MAX; - while (*Resp == SHELL_PROMPT_RESPONSE_MAX) { + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); ASSERT_EFI_ERROR(Status); @@ -2908,60 +3110,143 @@ ShellPromptForResponse ( switch (Key.UnicodeChar) { case L'Y': case L'y': - *Resp = SHELL_PROMPT_RESPONSE_YES; + *Resp = ShellPromptResponseYes; break; case L'N': case L'n': - *Resp = SHELL_PROMPT_RESPONSE_NO; + *Resp = ShellPromptResponseNo; + break; + case L'C': + case L'c': + *Resp = ShellPromptResponseCancel; + break; + } + } + break; case ShellPromptResponseTypeYesNoAllCancel: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + ASSERT_EFI_ERROR(Status); + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + switch (Key.UnicodeChar) { + case L'Y': + case L'y': + *Resp = ShellPromptResponseYes; + break; + case L'N': + case L'n': + *Resp = ShellPromptResponseNo; break; case L'A': case L'a': - *Resp = SHELL_PROMPT_RESPONSE_ALL; + *Resp = ShellPromptResponseAll; break; case L'C': case L'c': - *Resp = SHELL_PROMPT_RESPONSE_CANCEL; + *Resp = ShellPromptResponseCancel; break; } } break; - case SHELL_PROMPT_REQUEST_TYPE_ENTER_TO_COMTINUE: - case SHELL_PROMPT_REQUEST_TYPE_ANYKEY_TO_COMTINUE: + case ShellPromptResponseTypeEnterContinue: + case ShellPromptResponseTypeAnyKeyContinue: if (Prompt != NULL) { ShellPrintEx(-1, -1, L"%s", Prompt); } // // wait for valid response // - *Resp = SHELL_PROMPT_RESPONSE_MAX; - while (*Resp == SHELL_PROMPT_RESPONSE_MAX) { + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); - if (Type == SHELL_PROMPT_REQUEST_TYPE_ENTER_TO_COMTINUE) { + if (Type == ShellPromptResponseTypeEnterContinue) { Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); ASSERT_EFI_ERROR(Status); ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { - *Resp = SHELL_PROMPT_RESPONSE_CONTINUE; + *Resp = ShellPromptResponseContinue; break; } } - if (Type == SHELL_PROMPT_REQUEST_TYPE_ANYKEY_TO_COMTINUE) { - *Resp = SHELL_PROMPT_RESPONSE_CONTINUE; + if (Type == ShellPromptResponseTypeAnyKeyContinue) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + ASSERT_EFI_ERROR(Status); + *Resp = ShellPromptResponseContinue; + break; + } + } + break; + case ShellPromptResponseTypeYesNo: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + // + // wait for valid response + // + *Resp = ShellPromptResponseMax; + while (*Resp == ShellPromptResponseMax) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + ASSERT_EFI_ERROR(Status); + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + switch (Key.UnicodeChar) { + case L'Y': + case L'y': + *Resp = ShellPromptResponseYes; + break; + case L'N': + case L'n': + *Resp = ShellPromptResponseNo; + break; + } + } + break; + case ShellPromptResponseTypeFreeform: + if (Prompt != NULL) { + ShellPrintEx(-1, -1, L"%s", Prompt); + } + while(1) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + ASSERT_EFI_ERROR(Status); + ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar); + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { break; } + ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL)); + StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1); } break; - ///@todo add more request types here! + // + // This is the location to add new prompt types. + // default: - Status = EFI_UNSUPPORTED; + ASSERT(FALSE); } if (Response != NULL) { - *Response = Resp; + if (Resp != NULL) { + *Response = Resp; + } else if (Buffer != NULL) { + *Response = Buffer; + } } else { - FreePool(Resp); + if (Resp != NULL) { + FreePool(Resp); + } + if (Buffer != NULL) { + FreePool(Buffer); + } } + ShellPrintEx(-1, -1, L"\r\n"); return (Status); } @@ -2973,8 +3258,9 @@ ShellPromptForResponse ( @param Type What type of question is asked. This is used to filter the input to prevent invalid answers to question. - @param Prompt Pointer to string prompt to use to request input. - @param Response Pointer to Response which will be populated upon return. + @param[in] HiiFormatStringId The format string Id for getting from Hii. + @param[in] HiiFormatHandle The format string Handle for getting from Hii. + @param Response Pointer to Response which will be populated upon return. @retval EFI_SUCCESS the operation was sucessful. @return other the operation failed. @@ -2999,4 +3285,107 @@ ShellPromptForResponseHii ( return (Status); } +/** + Function to determin if an entire string is a valid number. + + If Hex it must be preceeded with a 0x or has ForceHex, set TRUE. + @param[in] String The string to evaluate. + @param[in] ForceHex TRUE - always assume hex. + @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going. + + @retval TRUE It is all numeric (dec/hex) characters. + @retval FALSE There is a non-numeric character. +**/ +BOOLEAN +EFIAPI +ShellIsHexOrDecimalNumber ( + IN CONST CHAR16 *String, + IN CONST BOOLEAN ForceHex, + IN CONST BOOLEAN StopAtSpace + ) +{ + BOOLEAN Hex; + + // + // chop off a single negative sign + // + if (String != NULL && *String == L'-') { + String++; + } + + if (String == NULL) { + return (FALSE); + } + + // + // chop leading zeroes + // + while(String != NULL && *String == L'0'){ + String++; + } + // + // allow '0x' or '0X', but not 'x' or 'X' + // + if (String != NULL && (*String == L'x' || *String == L'X')) { + if (*(String-1) != L'0') { + // + // we got an x without a preceeding 0 + // + return (FALSE); + } + String++; + Hex = TRUE; + } else if (ForceHex) { + Hex = TRUE; + } else { + Hex = FALSE; + } + + // + // loop through the remaining characters and use the lib function + // + for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){ + if (Hex) { + if (!ShellIsHexaDecimalDigitCharacter(*String)) { + return (FALSE); + } + } else { + if (!ShellIsDecimalDigitCharacter(*String)) { + return (FALSE); + } + } + } + return (TRUE); +} + +/** + Function to determine if a given filename exists. + + @param[in] Name Path to test. + + @retval EFI_SUCCESS The Path represents a file. + @retval EFI_NOT_FOUND The Path does not represent a file. + @retval other The path failed to open. +**/ +EFI_STATUS +EFIAPI +ShellFileExists( + IN CONST CHAR16 *Name + ) +{ + EFI_STATUS Status; + EFI_SHELL_FILE_INFO *List; + + ASSERT(Name != NULL); + + List = NULL; + Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List); + if (EFI_ERROR(Status)) { + return (Status); + } + + ShellCloseFileMetaArg(&List); + + return (EFI_SUCCESS); +} diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.inf b/ShellPkg/Library/UefiShellLib/UefiShellLib.inf index b35555bb67..bcbf9bdd7a 100644 --- a/ShellPkg/Library/UefiShellLib/UefiShellLib.inf +++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.inf @@ -1,7 +1,7 @@ -## @file +## @file # Provides interface to shell functionality for shell commands and applications. # -# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2006 - 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 @@ -27,7 +27,7 @@ # VALID_ARCHITECTURES = IA32 X64 IPF EBC # -[Sources] +[Sources.common] UefiShellLib.c UefiShellLib.h @@ -63,6 +63,6 @@ gEfiFileInfoGuid # ALWAYS_CONSUMED gEfiShellEnvironment2ExtGuid # ALWAYS_CONSUMED -[Pcd] +[Pcd.common] gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize # ALWAYS_CONSUMED gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize # ALWAYS_CONSUMED diff --git a/ShellPkg/Library/UefiSortLib/UefiSortLib.c b/ShellPkg/Library/UefiSortLib/UefiSortLib.c index 28313b3bbe..efeaad8c76 100644 --- a/ShellPkg/Library/UefiSortLib/UefiSortLib.c +++ b/ShellPkg/Library/UefiSortLib/UefiSortLib.c @@ -1,7 +1,7 @@ /** @file Library used for sorting routines. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 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 @@ -71,7 +71,7 @@ QuickSortWorker ( if ( Count < 2 || ElementSize < 1 - ){ + ){ return; } @@ -89,7 +89,7 @@ QuickSortWorker ( for ( LoopCount = 0 ; LoopCount < Count -1 ; LoopCount++ - ){ + ){ // // if the element is less than the pivot // @@ -291,3 +291,24 @@ StringNoCaseCompare ( } +/** + Function to compare 2 strings. + + @param[in] Buffer1 Pointer to String to compare (CHAR16**). + @param[in] Buffer2 Pointer to second String to compare (CHAR16**). + + @retval 0 Buffer1 equal to Buffer2. + @return < 0 Buffer1 is less than Buffer2. + @return > 0 Buffer1 is greater than Buffer2. +**/ +INTN +EFIAPI +StringCompare ( + IN CONST VOID *Buffer1, + IN CONST VOID *Buffer2 + ) +{ + return (StrCmp( + *(CHAR16**)Buffer1, + *(CHAR16**)Buffer2)); +} diff --git a/ShellPkg/Library/UefiSortLib/UefiSortLib.inf b/ShellPkg/Library/UefiSortLib/UefiSortLib.inf index f329693436..a6dcb27516 100644 --- a/ShellPkg/Library/UefiSortLib/UefiSortLib.inf +++ b/ShellPkg/Library/UefiSortLib/UefiSortLib.inf @@ -1,7 +1,7 @@ -## @file +## @file # Library used for sorting routines. # -# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2009, 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 @@ -19,13 +19,13 @@ FILE_GUID = 4264A823-45A3-42db-B92C-AA078555CBD3 MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 - LIBRARY_CLASS = SORTLib|UEFI_APPLICATION UEFI_DRIVER + LIBRARY_CLASS = SortLib|UEFI_APPLICATION UEFI_DRIVER UEFI_DRIVER # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # -[Sources] +[Sources.common] UefiSortLib.c [Packages] @@ -46,4 +46,4 @@ [Guids] -[Pcd] +[Pcd.common] diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec index 385bc343a7..3cadc74a42 100644 --- a/ShellPkg/ShellPkg.dec +++ b/ShellPkg/ShellPkg.dec @@ -1,9 +1,10 @@ -## @file ShellPkg.dec +## @file ShellPkg.dec # # This Package provides all definitions for EFI and UEFI Shell # -# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2009, 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 @@ -19,37 +20,40 @@ DEC_SPECIFICATION = 0x00010005 PACKAGE_NAME = ShellPkg PACKAGE_GUID = 9FB7587C-93F7-40a7-9C04-FD7BA94EE646 - PACKAGE_VERSION = 0.2 + PACKAGE_VERSION = 0.40 -[Includes] +[Includes.common] Include -[LibraryClasses] - ## @libraryclass Provides most Shell APIs. - # Only available for Shell applications - ## +[LibraryClasses.common] + ## @libraryclass Provides most Shell APIs. Only available for Shell applications ShellLib|Include/Library/ShellLib.h - ## @libraryclass provides EFI_FILE_HANDLE services - ## used by Shell and ShellLib - ## + ## @libraryclass Provides shell internal support Only available for shell internal commands + ShellCommandLib|Include/Library/ShellCommandLib.h + + ## @libraryclass provides EFI_FILE_HANDLE services used by Shell and ShellLib FileHandleLib|Include/Library/FileHandleLib.h - + ## @libraryclass Allows for a shell application to have a C style entry point - ## ShellCEntryLib|Include/Library/ShellCEntryLib.h ## @libraryclass Provides sorting functions - ## - SortLib|Include/Library/Sortlib.h + SortLib|Include/Library/SortLib.h + ## @libraryclass Provides advanced parsing functions + HandleParsingLib|Include/Library/HandleParsingLib.h -[Guids] +[Guids.common] gEfiShellEnvironment2ExtGuid = {0xd2c18636, 0x40e5, 0x4eb5, {0xa3, 0x1b, 0x36, 0x69, 0x5f, 0xd4, 0x2c, 0x87}} - gEfiShellPkgTokenSpaceGuid = {0x171e9188, 0x31d3, 0x40f5, {0xb1, 0x0c, 0x53, 0x9b, 0x2d, 0xb9, 0x40, 0xcd}} + gEfiShellPkgTokenSpaceGuid = {0x171e9188, 0x31d3, 0x40f5, {0xb1, 0x0c, 0x53, 0x9b, 0x2d, 0xb9, 0x40, 0xcd}} + gShellVariableGuid = {0x158def5a, 0xf656, 0x419c, {0xb0, 0x27, 0x7a, 0x31, 0x92, 0xc0, 0x79, 0xd2}} + gShellMapGuid = {0x51271e13, 0x7de3, 0x43af, {0x8b, 0xc2, 0x71, 0xad, 0x3b, 0x82, 0x43, 0x25}} + gShellAliasGuid = {0x0053d9d6, 0x2659, 0x4599, {0xa2, 0x6b, 0xef, 0x45, 0x36, 0xe6, 0x31, 0xa9}} + -[Protocols] +[Protocols.common] gEfiShellProtocolGuid = {0x6302d008, 0x7f9b, 0x4f30, {0x87, 0xac, 0x60, 0xc9, 0xfe, 0xf5, 0xda, 0x4e}} gEfiShellParametersProtocolGuid = {0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca}} gEfiShellEnvironment2Guid = {0x47c7b221, 0xc42a, 0x11d2, {0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} @@ -57,10 +61,54 @@ [PcdsFixedAtBuild] ## This flag is used to control initialization of the shell library - ## This should be FALSE for compiling the shell application itself only. + # This should be FALSE for compiling the shell application itself only. gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|TRUE|BOOLEAN|0x00000005 - ## This is the max buffer for ShellLib printings. - gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize|8000|UINT16|0x0000000C + ## This is the max buffer for ShellLib, FileHandleLib, and internal Shell printings. + gEfiShellPkgTokenSpaceGuid.PcdShellPrintBufferSize|16000|UINT16|0x0000000C + + ## This flag is used to control the commands available in the shell + gEfiShellPkgTokenSpaceGuid.PcdShellSupportLevel|3|UINT8|0x00000001 + + ## This flag is used to control the profiles available in the shell + # don't forget to update the text file if you change this. + # bit 0 = Drivers1 + # bit 1 = Debug1 + # bit 2 = Install1 + # bit 3 = Network1 + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask|0xFF|UINT8|0x0000000D + + ## This is the character count for allocation for consistent mappings + gEfiShellPkgTokenSpaceGuid.PcdShellMapNameLength|50|UINT8|0x00000009 + + ## This determins how many bytes are read out of files at a time for file operations (type, copy, etc...) + gEfiShellPkgTokenSpaceGuid.PcdShellFileOperationSize|1000|UINT16|0x0000000A + +[PcdsFeatureFlag] + ## This flag is used to control whether the shell includes NT32 platform Guids + # and thereby prevents dependancy on that Pkg + gEfiShellPkgTokenSpaceGuid.PcdShellIncludeNtGuids|TRUE|BOOLEAN|0x0000000E + + ## This flag is used to control HII required by the shell + gEfiShellPkgTokenSpaceGuid.PcdShellRequireHiiPlatform|TRUE|BOOLEAN|0x00000003 + + ## This flag is used to control HII required by the shell + gEfiShellPkgTokenSpaceGuid.PcdShellSupportFrameworkHii|FALSE|BOOLEAN|0x00000004 + + ## This flag forces the shell to present a user console. Allows for earlier debugging of platforms. + gEfiShellPkgTokenSpaceGuid.PcdShellForceConsole|FALSE|BOOLEAN|0x0000000F + +[PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic] + ## This flag is used to control the protocols produced by the shell + # If TRUE the shell will produce EFI_SHELL_ENVIRONMENT2 and EFI_SHELL_INTERFACE + gEfiShellPkgTokenSpaceGuid.PcdShellSupportOldProtocols|FALSE|BOOLEAN|0x00000002 + + ## this flag determins whether Page Break (-b) defaults to on or off in the shell + gEfiShellPkgTokenSpaceGuid.PcdShellPageBreakDefault|FALSE|BOOLEAN|0x00000006 + ## this flag determins whether insert mode for typing is default (FALSE means typeover) + gEfiShellPkgTokenSpaceGuid.PcdShellInsertModeDefault|TRUE|BOOLEAN|0x00000007 + ## this flag determins the default number of screens kept for history log. + # the spec defines 3 as the minimum + gEfiShellPkgTokenSpaceGuid.PcdShellScreenLogCount|3|UINT8|0x00000008 \ No newline at end of file diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index 1f9bec645e..54f9f4d132 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -1,9 +1,9 @@ -## @file +## @file # Shell Package # -# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2010, Intel Corporation # -# This program and the accompanying materials +# 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 @@ -16,14 +16,14 @@ [Defines] PLATFORM_NAME = Shell PLATFORM_GUID = E1DC9BF8-7013-4c99-9437-795DAA45F3BD - PLATFORM_VERSION = 0.2 + PLATFORM_VERSION = 0.40 DSC_SPECIFICATION = 0x00010006 OUTPUT_DIRECTORY = Build/Shell SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC BUILD_TARGETS = DEBUG|RELEASE SKUID_IDENTIFIER = DEFAULT -[LibraryClasses] +[LibraryClasses.common] UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf @@ -33,24 +33,56 @@ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf - PrintLib|MdeModulePkg/Library/DxePrintLibPrint2Protocol/DxePrintLibPrint2Protocol.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf - + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf FileHandleLib|ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf SortLib|ShellPkg/Library/BaseSortLib/BaseSortLib.inf + HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf -[PcdsFixedAtBuild] +[PcdsFixedAtBuild.common] -[Components] - ShellPkg/Application/ShellExecTestApp/SA.inf - ShellPkg/Application/ShellLibTestApp/SA3.inf +[Components.common] ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf ShellPkg/Library/UefiShellLib/UefiShellLib.inf - ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf - ShellPkg/Library/BaseSortLib/BaseSortLib.inf - ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf - ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf \ No newline at end of file + ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + + ShellPkg/Application/Shell/Shell.inf { + + DebugLib|MdePkg\Library\UefiDebugLibConOut\UefiDebugLibConOut.inf + ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf + NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf + HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf + FileHandleLib|ShellPkg/Library/BaseFileHandleLib/BaseFileHandleLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + SortLib|ShellPkg/Library/UefiSortLib/UefiSortLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + + + gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF + gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE + gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|16000 + + *_*_*_CC_FLAGS = /Od + } + + + ShellPkg/Application/ShellLibTestApp/SA3.inf + ShellPkg/Application/ShellCTestApp/ShellCTestApp.inf { + + ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + } + ShellPkg/Application/ShellSortTestApp/ShellSortTestApp.inf { + + ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + } + ShellPkg/Application/ShellExecTestApp/SA.inf diff --git a/ShellPkg/UDK2010.UP2.Shell.txt b/ShellPkg/UDK2010.UP2.Shell.txt new file mode 100644 index 0000000000..f39bd75ac5 --- /dev/null +++ b/ShellPkg/UDK2010.UP2.Shell.txt @@ -0,0 +1,89 @@ +============================================================================ +UEFI Shell 2.0 implementation release notes. +September 13, 2010 +============================================================================ +============================================================================ +                                   DISCLAIMER +============================================================================ +This release note as well as the software described in it is furnished under +license and may only be used or copied in accordance with the terms of the +license. The information in this manual is furnished for informational use +only, is subject to change without notice, and should not be construed as a +commitment by Intel Corporation. + +Intel Corporation assumes no responsibility or liability for any errors or +inaccuracies that may appear in this document or any software that may be +provided in association with this document. + +Except as permitted by such license, no part of this document may be +reproduced, stored in a retrieval system, or transmitted in any form or by +any means without the express written consent of Intel Corporation. + +============================================================================ +                              ADDITIONAL DISCLAIMER +============================================================================ +This code is based upon the EDK II code base as found on the UEFI Open +Source Community Website at http://www.tianocore.org. + +============================================================================ +                                  CONTENTS +============================================================================ +* Overview +* How to build shell +* Known limitations +* Incorporation + +============================================================================ +                                  OVERVIEW +============================================================================ +The UEFI 2.0 shell provides a standard pre-boot command line processor.  +It is similar to the EDK EFI Shell or a *nix command line parser. + +============================================================================ +                               HOW TO BUILD SHELL +============================================================================ +1. Tools preparation +  1). *Visual Studio 2005* or Intel(r) Compiler 9.1 +      + +2. Source preparation +  1). Extract .zip (or later) to root of EDK II workspace + +3. Build steps +  1) run edksetup script +  2) run build -p ShellPlg\ShellPkg.dsc + +============================================================================ +                            KNOWN LIMITATIONS +============================================================================ +1. Redirecting StdErr is not completely functional. + +2. This uses errata approved by the USHT/USWG, but not yet published by UEFI. + +3. Online help may be incomplete and examples may be slightly out of date. + +4. CTRL-C is not functional. + +============================================================================ +         HOW TO INCORPORATE THIS SHELL INTO NT32 +============================================================================ +The instructions below are included as a sample and template on how a +developer may integrate this code into An existing platform: + +1. Add this shell build to the NT32 build: +Add the shell.inf to the [components] section as it is in the ShellPkg.dsc. + +1) Update system PCDs to support this new module +Update the PCD as follows using the Shell's PCD: + + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile|{ 0x83, 0xA5, 0x04, 0x7C, 0x3E, 0x9E, 0x1C, 0x4F, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 } + +2) Remove the old shell from the NT32 Firmware list +Remove the FILE APPLICATION section for the old shell. + +3) Add this shell to the NT32 firmware list +Add the Shell.INF to the end of the list of DXE modules. + +4) Build NT32 (per instructions provided with EDK II/UDK2010) + +============================================================================ -- cgit v1.2.3