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;
+ }
+}