X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ShellPkg%2FLibrary%2FUefiShellCommandLib%2FUefiShellCommandLib.c;h=92a88d18a065b95b98631e91061418792fe13c0c;hb=3bd89603625eb451b166ee64676c2b31818d1a1f;hp=18ae9f33844c5dcfa81141624f93c85875aae6e1;hpb=e71cb45263cd3e03887d24de81653f3b4b02d510;p=mirror_edk2.git diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c index 18ae9f3384..92a88d18a0 100644 --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -1,7 +1,7 @@ /** @file Provides interface to shell internal functions for shell commands. - (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P. + (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2014, 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 @@ -29,6 +29,25 @@ STATIC UINTN mFsMaxCount = 0; STATIC UINTN mBlkMaxCount = 0; STATIC BUFFER_LIST mFileHandleList; +STATIC CONST CHAR8 Hex[] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F' +}; + // global variables required by library class. EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL; SHELL_MAP_LIST gShellMapList; @@ -215,14 +234,80 @@ ShellCommandLibDestructor ( } /** - Checks if a command is already on the list. + Find a dynamic command protocol instance given a command name string. + + @param CommandString the command name string + + @return instance the command protocol instance, if dynamic command instance found + @retval NULL no dynamic command protocol instance found for name +**/ +CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL * +EFIAPI +ShellCommandFindDynamicCommand ( + IN CONST CHAR16 *CommandString + ) +{ + EFI_STATUS Status; + EFI_HANDLE *CommandHandleList; + EFI_HANDLE *NextCommand; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid); + if (CommandHandleList == NULL) { + // + // not found or out of resources + // + return NULL; + } + + for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) { + Status = gBS->HandleProtocol( + *NextCommand, + &gEfiShellDynamicCommandProtocolGuid, + (VOID **)&DynamicCommand + ); + + if (EFI_ERROR(Status)) { + continue; + } + + if (gUnicodeCollation->StriColl( + gUnicodeCollation, + (CHAR16*)CommandString, + (CHAR16*)DynamicCommand->CommandName) == 0 + ){ + FreePool(CommandHandleList); + return (DynamicCommand); + } + } + + FreePool(CommandHandleList); + return (NULL); +} + +/** + Checks if a command exists as a dynamic command protocol instance @param[in] CommandString The command string to check for on the list. **/ BOOLEAN EFIAPI -ShellCommandIsCommandOnList ( - IN CONST CHAR16 *CommandString +ShellCommandDynamicCommandExists ( + IN CONST CHAR16 *CommandString + ) +{ + return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL)); +} + +/** + Checks if a command is already on the internal command list. + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnInternalList( + IN CONST CHAR16 *CommandString ) { SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; @@ -252,7 +337,52 @@ ShellCommandIsCommandOnList ( } /** - Get the help text for a command. + Checks if a command exists, either internally or through the dynamic command protocol. + + @param[in] CommandString The command string to check for on the list. +**/ +BOOLEAN +EFIAPI +ShellCommandIsCommandOnList( + IN CONST CHAR16 *CommandString + ) +{ + if (ShellCommandIsCommandOnInternalList(CommandString)) { + return TRUE; + } + + return ShellCommandDynamicCommandExists(CommandString); +} + +/** + Get the help text for a dynamic command. + + @param[in] CommandString The command name. + + @retval NULL No help text was found. + @return String of help text. Caller required to free. +**/ +CHAR16* +EFIAPI +ShellCommandGetDynamicCommandHelp( + IN CONST CHAR16 *CommandString + ) +{ + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; + + DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString); + if (DynamicCommand == NULL) { + return (NULL); + } + + // + // TODO: how to get proper language? + // + return DynamicCommand->GetHelp(DynamicCommand, "en"); +} + +/** + Get the help text for an internal command. @param[in] CommandString The command name. @@ -261,7 +391,7 @@ ShellCommandIsCommandOnList ( **/ CHAR16* EFIAPI -ShellCommandGetCommandHelp ( +ShellCommandGetInternalCommandHelp( IN CONST CHAR16 *CommandString ) { @@ -291,6 +421,31 @@ ShellCommandGetCommandHelp ( return (NULL); } +/** + 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 + ) +{ + CHAR16 *HelpStr; + HelpStr = ShellCommandGetInternalCommandHelp(CommandString); + + if (HelpStr == NULL) { + HelpStr = ShellCommandGetDynamicCommandHelp(CommandString); + } + + return HelpStr; +} + + /** Registers handlers of type SHELL_RUN_COMMAND and SHELL_GET_MAN_FILENAME for each shell command. @@ -390,14 +545,9 @@ ShellCommandRegisterCommandName ( // Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY)); ASSERT(Node != NULL); - Node->CommandString = AllocateZeroPool(StrSize(CommandString)); + Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString); ASSERT(Node->CommandString != NULL); - // - // populate the new struct - // - StrCpy(Node->CommandString, CommandString); - Node->GetManFileName = GetManFileName; Node->CommandHandler = CommandHandler; Node->LastError = CanAffectLE; @@ -505,7 +655,8 @@ ShellCommandRunCommandHandler ( IN OUT BOOLEAN *CanAffectLE OPTIONAL ) { - SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node; + EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; // // assert for NULL parameters @@ -524,7 +675,7 @@ ShellCommandRunCommandHandler ( gUnicodeCollation, (CHAR16*)CommandString, Node->CommandString) == 0 - ){ + ){ if (CanAffectLE != NULL) { *CanAffectLE = Node->LastError; } @@ -536,6 +687,20 @@ ShellCommandRunCommandHandler ( return (RETURN_SUCCESS); } } + + // + // An internal command was not found, try to find a dynamic command + // + DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString); + if (DynamicCommand != NULL) { + if (RetVal != NULL) { + *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol); + } else { + DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol); + } + return (RETURN_SUCCESS); + } + return (RETURN_NOT_FOUND); } @@ -626,6 +791,9 @@ ShellCommandRegisterAlias ( ) { ALIAS_LIST *Node; + ALIAS_LIST *CommandAlias; + ALIAS_LIST *PrevCommandAlias; + INTN LexicalMatchValue; // // Asserts for NULL @@ -638,21 +806,42 @@ ShellCommandRegisterAlias ( // Node = AllocateZeroPool(sizeof(ALIAS_LIST)); ASSERT(Node != NULL); - Node->CommandString = AllocateZeroPool(StrSize(Command)); - Node->Alias = AllocateZeroPool(StrSize(Alias)); + Node->CommandString = AllocateCopyPool(StrSize(Command), Command); + Node->Alias = AllocateCopyPool(StrSize(Alias), Alias); ASSERT(Node->CommandString != NULL); ASSERT(Node->Alias != NULL); - // - // populate the new struct - // - StrCpy(Node->CommandString, Command); - StrCpy(Node->Alias , Alias ); + InsertHeadList (&mAliasList.Link, &Node->Link); // - // add the new struct to the list + // Move a new pre-defined registered alias to its sorted ordered location in the list // - InsertTailList (&mAliasList.Link, &Node->Link); + for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link), + PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link) + ; !IsNull (&mAliasList.Link, &CommandAlias->Link) + ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) { + // + // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry + // + LexicalMatchValue = gUnicodeCollation->StriColl ( + gUnicodeCollation, + PrevCommandAlias->Alias, + CommandAlias->Alias + ); + + // + // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry + // is alphabetically greater than CommandAlias list entry + // + if (LexicalMatchValue > 0) { + CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link); + } else if (LexicalMatchValue < 0) { + // + // PrevCommandAlias entry is lexically lower than CommandAlias entry + // + break; + } + } return (RETURN_SUCCESS); } @@ -722,7 +911,7 @@ ShellCommandIsOnAliasList( } /** - Function to determine current state of ECHO. Echo determins if lines from scripts + Function to determine current state of ECHO. Echo determines if lines from scripts and ECHO commands are enabled. @retval TRUE Echo is currently enabled @@ -738,7 +927,7 @@ ShellCommandGetEchoState( } /** - Function to set current state of ECHO. Echo determins if lines from scripts + Function to set current state of ECHO. Echo determines if lines from scripts and ECHO commands are enabled. If State is TRUE, Echo will be enabled. @@ -995,12 +1184,11 @@ ShellCommandAddMapItemAndUpdatePath( Status = EFI_OUT_OF_RESOURCES; } else { MapListNode->Flags = Flags; - MapListNode->MapName = AllocateZeroPool(StrSize(Name)); + MapListNode->MapName = AllocateCopyPool(StrSize(Name), 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); } } @@ -1092,6 +1280,9 @@ ShellCommandCreateInitialMappingsAndPaths( ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link) ){ RemoveEntryList(&MapListNode->Link); + SHELL_FREE_NON_NULL(MapListNode->DevicePath); + SHELL_FREE_NON_NULL(MapListNode->MapName); + SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath); FreePool(MapListNode); } // for loop } @@ -1199,114 +1390,119 @@ ShellCommandCreateInitialMappingsAndPaths( } return (EFI_SUCCESS); -} - -/** - Add mappings for any devices without one. Do not change any existing maps. - - @retval EFI_SUCCESS The operation was successful. -**/ -EFI_STATUS -EFIAPI -ShellCommandUpdateMapping ( - 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 = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid); - if (HandleList != NULL) { - // - // Do a count of the handles - // - for (Count = 0 ; HandleList[Count] != NULL ; Count++); - - // - // Get all Device Paths - // - DevicePathList = AllocateZeroPool(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); -} - -/** - Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*. - - @param[in] Handle The SHELL_FILE_HANDLE to convert. +} + +/** + Add mappings for any devices without one. Do not change any existing maps. + + @retval EFI_SUCCESS The operation was successful. +**/ +EFI_STATUS +EFIAPI +ShellCommandUpdateMapping ( + 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 = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid); + if (HandleList != NULL) { + // + // Do a count of the handles + // + for (Count = 0 ; HandleList[Count] != NULL ; Count++); + + // + // Get all Device Paths + // + DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count); + if (DevicePathList == NULL) { + return (EFI_OUT_OF_RESOURCES); + } + + 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 ; !EFI_ERROR(Status) && 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); + if (NewDefaultName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + // + // 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); +} + +/** + 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. **/ @@ -1345,11 +1541,14 @@ ConvertEfiFileProtocolToShellHandle( } NewNode = AllocateZeroPool(sizeof(BUFFER_LIST)); if (NewNode == NULL) { + SHELL_FREE_NON_NULL(Buffer); return (NULL); } Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle; Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0); if (Buffer->Path == NULL) { + SHELL_FREE_NON_NULL(NewNode); + SHELL_FREE_NON_NULL(Buffer); return (NULL); } NewNode->Buffer = Buffer; @@ -1445,7 +1644,6 @@ ShellFileHandleEof( gEfiShellProtocol->GetFilePosition(Handle, &Pos); Info = gEfiShellProtocol->GetFileInfo (Handle); - ASSERT(Info != NULL); gEfiShellProtocol->SetFilePosition(Handle, Pos); if (Info == NULL) { @@ -1487,7 +1685,6 @@ FreeBufferList ( ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link) ){ RemoveEntryList(&BufferListEntry->Link); - ASSERT(BufferListEntry->Buffer != NULL); if (BufferListEntry->Buffer != NULL) { FreePool(BufferListEntry->Buffer); } @@ -1495,3 +1692,53 @@ FreeBufferList ( } } +/** + Dump some hexadecimal data to the screen. + + @param[in] Indent How many spaces to indent the output. + @param[in] Offset The offset of the printing. + @param[in] DataSize The size in bytes of UserData. + @param[in] UserData The data to print out. +**/ +VOID +DumpHex ( + IN UINTN Indent, + IN UINTN Offset, + IN UINTN DataSize, + IN VOID *UserData + ) +{ + UINT8 *Data; + + CHAR8 Val[50]; + + CHAR8 Str[20]; + + UINT8 TempByte; + UINTN Size; + UINTN Index; + + Data = UserData; + while (DataSize != 0) { + Size = 16; + if (Size > DataSize) { + Size = DataSize; + } + + for (Index = 0; Index < Size; Index += 1) { + TempByte = Data[Index]; + Val[Index * 3 + 0] = Hex[TempByte >> 4]; + Val[Index * 3 + 1] = Hex[TempByte & 0xF]; + Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' '); + Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte); + } + + Val[Index * 3] = 0; + Str[Index] = 0; + ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str); + + Data += Size; + Offset += Size; + DataSize -= Size; + } +}