/** @file\r
Provides interface to shell internal functions for shell commands.\r
\r
- Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "UefiShellCommandLib.h"\r
\r
-/// The tag for use in identifying UNICODE files.\r
-/// If the file is UNICODE, the first 16 bits of the file will equal this value.\r
-enum {\r
- gUnicodeFileTag = 0xFEFF\r
-};\r
-\r
// STATIC local variables\r
STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;\r
STATIC SCRIPT_FILE_LIST mScriptList;\r
STATIC UINTN mBlkMaxCount = 0;\r
STATIC BUFFER_LIST mFileHandleList;\r
\r
+STATIC CONST CHAR8 Hex[] = {\r
+ '0',\r
+ '1',\r
+ '2',\r
+ '3',\r
+ '4',\r
+ '5',\r
+ '6',\r
+ '7',\r
+ '8',\r
+ '9',\r
+ 'A',\r
+ 'B',\r
+ 'C',\r
+ 'D',\r
+ 'E',\r
+ 'F'\r
+};\r
+\r
// global variables required by library class.\r
EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;\r
-EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *gDevPathToText = NULL;\r
SHELL_MAP_LIST gShellMapList;\r
-SHELL_MAP_LIST *gShellCurDir = NULL;\r
+SHELL_MAP_LIST *gShellCurMapping = NULL;\r
\r
CONST CHAR16* SupportLevel[] = {\r
L"Minimal",\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
+ UINTN NumHandles;\r
+ EFI_HANDLE *Handles;\r
+ EFI_UNICODE_COLLATION_PROTOCOL *Uc;\r
+ CHAR8 *BestLanguage;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ CHAR8 *PlatformLang;\r
+\r
if (gUnicodeCollation == NULL) {\r
- Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
- if (EFI_ERROR(Status)) {\r
- return (EFI_DEVICE_ERROR);\r
+\r
+ GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME, (VOID**)&PlatformLang, NULL);\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiUnicodeCollation2ProtocolGuid,\r
+ NULL,\r
+ &NumHandles,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ NumHandles = 0;\r
+ Handles = NULL;\r
}\r
- }\r
- if (gDevPathToText == NULL) {\r
- Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDevPathToText);\r
- if (EFI_ERROR(Status)) {\r
- return (EFI_DEVICE_ERROR);\r
+ for (Index = 0; Index < NumHandles; Index++) {\r
+ //\r
+ // Open Unicode Collation Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Handles[Index],\r
+ &gEfiUnicodeCollation2ProtocolGuid,\r
+ (VOID **) &Uc,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Without clue provided use the first Unicode Collation2 protocol.\r
+ //\r
+ if (PlatformLang == NULL) {\r
+ gUnicodeCollation = Uc;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Find the best matching matching language from the supported languages\r
+ // of Unicode Collation2 protocol.\r
+ //\r
+ BestLanguage = GetBestLanguage (\r
+ Uc->SupportedLanguages,\r
+ FALSE,\r
+ PlatformLang,\r
+ NULL\r
+ );\r
+ if (BestLanguage != NULL) {\r
+ FreePool (BestLanguage);\r
+ gUnicodeCollation = Uc;\r
+ break;\r
+ }\r
+ }\r
+ if (Handles != NULL) {\r
+ FreePool (Handles);\r
+ }\r
+ if (PlatformLang != NULL) {\r
+ FreePool (PlatformLang);\r
}\r
}\r
- return (EFI_SUCCESS);\r
+\r
+ return (gUnicodeCollation == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;\r
}\r
\r
/**\r
mProfileListSize = 0;\r
mProfileList = NULL;\r
\r
- if (gUnicodeCollation == NULL) {\r
- Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
- if (EFI_ERROR(Status)) {\r
- return (EFI_DEVICE_ERROR);\r
- }\r
+ Status = CommandInit ();\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
return (RETURN_SUCCESS);\r
}\r
\r
+/**\r
+ Frees list of file handles.\r
+\r
+ @param[in] List The list to free.\r
+**/\r
+VOID\r
+FreeFileHandleList (\r
+ IN BUFFER_LIST *List\r
+ )\r
+{\r
+ BUFFER_LIST *BufferListEntry;\r
+\r
+ if (List == NULL){\r
+ return;\r
+ }\r
+ //\r
+ // enumerate through the buffer list and free all memory\r
+ //\r
+ for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
+ ; !IsListEmpty (&List->Link)\r
+ ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
+ ){\r
+ RemoveEntryList(&BufferListEntry->Link);\r
+ ASSERT(BufferListEntry->Buffer != NULL);\r
+ SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);\r
+ SHELL_FREE_NON_NULL(BufferListEntry->Buffer);\r
+ SHELL_FREE_NON_NULL(BufferListEntry);\r
+ }\r
+}\r
+\r
/**\r
Destructor for the library. free any resources.\r
\r
)\r
{\r
SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
- COMMAND_LIST *Node2;\r
+ ALIAS_LIST *Node2;\r
SCRIPT_FILE_LIST *Node3;\r
SHELL_MAP_LIST *MapNode;\r
//\r
}\r
\r
//\r
- // enumerate through the init command list and free all memory\r
+ // enumerate through the alias list and free all memory\r
//\r
while (!IsListEmpty (&mAliasList.Link)) {\r
- Node2 = (COMMAND_LIST *)GetFirstNode(&mAliasList.Link);\r
+ Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);\r
RemoveEntryList(&Node2->Link);\r
SHELL_FREE_NON_NULL(Node2->CommandString);\r
- FreePool(Node2);\r
+ SHELL_FREE_NON_NULL(Node2->Alias);\r
+ SHELL_FREE_NON_NULL(Node2);\r
DEBUG_CODE(Node2 = NULL;);\r
}\r
\r
}\r
}\r
if (!IsListEmpty(&mFileHandleList.Link)){\r
- FreeBufferList(&mFileHandleList);\r
+ FreeFileHandleList(&mFileHandleList);\r
}\r
\r
if (mProfileList != NULL) {\r
}\r
\r
gUnicodeCollation = NULL;\r
- gDevPathToText = NULL;\r
- gShellCurDir = NULL;\r
+ gShellCurMapping = NULL;\r
\r
return (RETURN_SUCCESS);\r
}\r
\r
/**\r
- Checks if a command is already on the list.\r
+ Find a dynamic command protocol instance given a command name string.\r
+\r
+ @param CommandString the command name string\r
+\r
+ @return instance the command protocol instance, if dynamic command instance found\r
+ @retval NULL no dynamic command protocol instance found for name\r
+**/\r
+CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *\r
+ShellCommandFindDynamicCommand (\r
+ IN CONST CHAR16 *CommandString\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *CommandHandleList;\r
+ EFI_HANDLE *NextCommand;\r
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
+\r
+ CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);\r
+ if (CommandHandleList == NULL) {\r
+ //\r
+ // not found or out of resources\r
+ //\r
+ return NULL;\r
+ }\r
+\r
+ for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {\r
+ Status = gBS->HandleProtocol(\r
+ *NextCommand,\r
+ &gEfiShellDynamicCommandProtocolGuid,\r
+ (VOID **)&DynamicCommand\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)CommandString,\r
+ (CHAR16*)DynamicCommand->CommandName) == 0\r
+ ){\r
+ FreePool(CommandHandleList);\r
+ return (DynamicCommand);\r
+ }\r
+ }\r
+\r
+ FreePool(CommandHandleList);\r
+ return (NULL);\r
+}\r
+\r
+/**\r
+ Checks if a command exists as a dynamic command protocol instance\r
\r
@param[in] CommandString The command string to check for on the list.\r
**/\r
BOOLEAN\r
-EFIAPI\r
-ShellCommandIsCommandOnList (\r
- IN CONST CHAR16 *CommandString\r
+ShellCommandDynamicCommandExists (\r
+ IN CONST CHAR16 *CommandString\r
+ )\r
+{\r
+ return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));\r
+}\r
+\r
+/**\r
+ Checks if a command is already on the internal command list.\r
+\r
+ @param[in] CommandString The command string to check for on the list.\r
+**/\r
+BOOLEAN\r
+ShellCommandIsCommandOnInternalList(\r
+ IN CONST CHAR16 *CommandString\r
)\r
{\r
SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
}\r
\r
/**\r
- Get the help text for a command.\r
+ Checks if a command exists, either internally or through the dynamic command protocol.\r
+\r
+ @param[in] CommandString The command string to check for on the list.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ShellCommandIsCommandOnList(\r
+ IN CONST CHAR16 *CommandString\r
+ )\r
+{\r
+ if (ShellCommandIsCommandOnInternalList(CommandString)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return ShellCommandDynamicCommandExists(CommandString);\r
+}\r
+\r
+/**\r
+ Get the help text for a dynamic command.\r
+\r
+ @param[in] CommandString The command name.\r
+\r
+ @retval NULL No help text was found.\r
+ @return String of help text. Caller required to free.\r
+**/\r
+CHAR16*\r
+ShellCommandGetDynamicCommandHelp(\r
+ IN CONST CHAR16 *CommandString\r
+ )\r
+{\r
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
+\r
+ DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
+ if (DynamicCommand == NULL) {\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // TODO: how to get proper language?\r
+ //\r
+ return DynamicCommand->GetHelp(DynamicCommand, "en");\r
+}\r
+\r
+/**\r
+ Get the help text for an internal command.\r
\r
@param[in] CommandString The command name.\r
\r
@return String of help text. Caller reuiqred to free.\r
**/\r
CHAR16*\r
-EFIAPI\r
-ShellCommandGetCommandHelp (\r
+ShellCommandGetInternalCommandHelp(\r
IN CONST CHAR16 *CommandString\r
)\r
{\r
return (NULL);\r
}\r
\r
+/**\r
+ Get the help text for a command.\r
+\r
+ @param[in] CommandString The command name.\r
+\r
+ @retval NULL No help text was found.\r
+ @return String of help text.Caller reuiqred to free.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+ShellCommandGetCommandHelp (\r
+ IN CONST CHAR16 *CommandString\r
+ )\r
+{\r
+ CHAR16 *HelpStr;\r
+ HelpStr = ShellCommandGetInternalCommandHelp(CommandString);\r
+\r
+ if (HelpStr == NULL) {\r
+ HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);\r
+ }\r
+\r
+ return HelpStr;\r
+}\r
+\r
+\r
/**\r
Registers handlers of type SHELL_RUN_COMMAND and\r
SHELL_GET_MAN_FILENAME for each shell command.\r
IN UINT32 ShellMinSupportLevel,\r
IN CONST CHAR16 *ProfileName,\r
IN CONST BOOLEAN CanAffectLE,\r
- IN CONST EFI_HANDLE HiiHandle,\r
+ IN CONST EFI_HII_HANDLE HiiHandle,\r
IN CONST EFI_STRING_ID ManFormatHelp\r
)\r
{\r
SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
+ SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;\r
+ SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;\r
+ INTN LexicalMatchValue;\r
+\r
+ //\r
+ // Initialize local variables.\r
+ //\r
+ Command = NULL;\r
+ PrevCommand = NULL;\r
+ LexicalMatchValue = 0;\r
\r
//\r
// ASSERTs for NULL parameters\r
// allocate memory for new struct\r
//\r
Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));\r
- ASSERT(Node != NULL);\r
- Node->CommandString = AllocateZeroPool(StrSize(CommandString));\r
- ASSERT(Node->CommandString != NULL);\r
-\r
- //\r
- // populate the new struct\r
- //\r
- StrCpy(Node->CommandString, CommandString);\r
+ if (Node == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);\r
+ if (Node->CommandString == NULL) {\r
+ FreePool (Node);\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
\r
Node->GetManFileName = GetManFileName;\r
Node->CommandHandler = CommandHandler;\r
}\r
\r
//\r
- // add the new struct to the list\r
+ // Insert a new entry on top of the list\r
+ //\r
+ InsertHeadList (&mCommandList.Link, &Node->Link);\r
+\r
//\r
- InsertTailList (&mCommandList.Link, &Node->Link);\r
+ // Move a new registered command to its sorted ordered location in the list\r
+ //\r
+ for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),\r
+ PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)\r
+ ; !IsNull (&mCommandList.Link, &Command->Link)\r
+ ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {\r
+\r
+ //\r
+ // Get Lexical Comparison Value between PrevCommand and Command list entry\r
+ //\r
+ LexicalMatchValue = gUnicodeCollation->StriColl (\r
+ gUnicodeCollation,\r
+ PrevCommand->CommandString,\r
+ Command->CommandString\r
+ );\r
+\r
+ //\r
+ // Swap PrevCommand and Command list entry if PrevCommand list entry\r
+ // is alphabetically greater than Command list entry\r
+ //\r
+ if (LexicalMatchValue > 0){\r
+ Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);\r
+ } else if (LexicalMatchValue < 0) {\r
+ //\r
+ // PrevCommand entry is lexically lower than Command entry\r
+ //\r
+ break;\r
+ }\r
+ }\r
\r
return (RETURN_SUCCESS);\r
}\r
IN OUT BOOLEAN *CanAffectLE OPTIONAL\r
)\r
{\r
- SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
+ SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
\r
//\r
// assert for NULL parameters\r
gUnicodeCollation,\r
(CHAR16*)CommandString,\r
Node->CommandString) == 0\r
- ){\r
+ ){\r
if (CanAffectLE != NULL) {\r
*CanAffectLE = Node->LastError;\r
}\r
return (RETURN_SUCCESS);\r
}\r
}\r
+\r
+ //\r
+ // An internal command was not found, try to find a dynamic command\r
+ //\r
+ DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
+ if (DynamicCommand != NULL) {\r
+ if (RetVal != NULL) {\r
+ *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
+ } else {\r
+ DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
+ }\r
+ return (RETURN_SUCCESS);\r
+ }\r
+\r
return (RETURN_NOT_FOUND);\r
}\r
\r
)\r
{\r
ALIAS_LIST *Node;\r
+ ALIAS_LIST *CommandAlias;\r
+ ALIAS_LIST *PrevCommandAlias;\r
+ INTN LexicalMatchValue;\r
\r
//\r
// Asserts for NULL\r
// allocate memory for new struct\r
//\r
Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
- ASSERT(Node != NULL);\r
- Node->CommandString = AllocateZeroPool(StrSize(Command));\r
- Node->Alias = AllocateZeroPool(StrSize(Alias));\r
- ASSERT(Node->CommandString != NULL);\r
- ASSERT(Node->Alias != NULL);\r
+ if (Node == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ Node->CommandString = AllocateCopyPool(StrSize(Command), Command);\r
+ if (Node->CommandString == NULL) {\r
+ FreePool (Node);\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+ Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);\r
+ if (Node->Alias == NULL) {\r
+ FreePool (Node->CommandString);\r
+ FreePool (Node);\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
\r
- //\r
- // populate the new struct\r
- //\r
- StrCpy(Node->CommandString, Command);\r
- StrCpy(Node->Alias , Alias );\r
+ InsertHeadList (&mAliasList.Link, &Node->Link);\r
\r
//\r
- // add the new struct to the list\r
+ // Move a new pre-defined registered alias to its sorted ordered location in the list\r
//\r
- InsertTailList (&mAliasList.Link, &Node->Link);\r
+ for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),\r
+ PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)\r
+ ; !IsNull (&mAliasList.Link, &CommandAlias->Link)\r
+ ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {\r
+ //\r
+ // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry\r
+ //\r
+ LexicalMatchValue = gUnicodeCollation->StriColl (\r
+ gUnicodeCollation,\r
+ PrevCommandAlias->Alias,\r
+ CommandAlias->Alias\r
+ );\r
+\r
+ //\r
+ // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry\r
+ // is alphabetically greater than CommandAlias list entry\r
+ //\r
+ if (LexicalMatchValue > 0) {\r
+ CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);\r
+ } else if (LexicalMatchValue < 0) {\r
+ //\r
+ // PrevCommandAlias entry is lexically lower than CommandAlias entry\r
+ //\r
+ break;\r
+ }\r
+ }\r
\r
return (RETURN_SUCCESS);\r
}\r
}\r
\r
/**\r
- Function to determine current state of ECHO. Echo determins if lines from scripts\r
+ Function to determine current state of ECHO. Echo determines if lines from scripts\r
and ECHO commands are enabled.\r
\r
@retval TRUE Echo is currently enabled\r
}\r
\r
/**\r
- Function to set current state of ECHO. Echo determins if lines from scripts\r
+ Function to set current state of ECHO. Echo determines if lines from scripts\r
and ECHO commands are enabled.\r
\r
If State is TRUE, Echo will be enabled.\r
Status = EFI_OUT_OF_RESOURCES;\r
} else {\r
MapListNode->Flags = Flags;\r
- MapListNode->MapName = AllocateZeroPool(StrSize(Name));\r
+ MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);\r
MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
Status = EFI_OUT_OF_RESOURCES;\r
} else {\r
- StrCpy(MapListNode->MapName, Name);\r
InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
}\r
}\r
ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
if (OriginalPath != NULL) {\r
StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
- } else {\r
- StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);\r
+ StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
}\r
- StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
CHAR16 *NewConsistName;\r
EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
SHELL_MAP_LIST *MapListNode;\r
-\r
+ CONST CHAR16 *CurDir;\r
+ CHAR16 *SplitCurDir;\r
+ CHAR16 *MapName;\r
+ SHELL_MAP_LIST *MapListItem;\r
+\r
+ SplitCurDir = NULL;\r
+ MapName = NULL;\r
+ MapListItem = NULL;\r
HandleList = NULL;\r
\r
//\r
; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
){\r
RemoveEntryList(&MapListNode->Link);\r
+ SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
+ SHELL_FREE_NON_NULL(MapListNode->MapName);\r
+ SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
FreePool(MapListNode);\r
} // for loop\r
}\r
// Get all Device Paths\r
//\r
DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
- ASSERT(DevicePathList != NULL);\r
+ if (DevicePathList == NULL) {\r
+ SHELL_FREE_NON_NULL (HandleList);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
\r
for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
SHELL_FREE_NON_NULL(DevicePathList);\r
\r
HandleList = NULL;\r
+\r
+ //\r
+ //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,\r
+ //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,\r
+ //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.\r
+ //\r
+ if (gShellCurMapping != NULL) {\r
+ gShellCurMapping = NULL;\r
+ CurDir = gEfiShellProtocol->GetEnv(L"cwd");\r
+ if (CurDir != NULL) {\r
+ MapName = AllocateCopyPool (StrSize(CurDir), CurDir);\r
+ if (MapName == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ SplitCurDir = StrStr (MapName, L":");\r
+ if (SplitCurDir == NULL) {\r
+ SHELL_FREE_NON_NULL (MapName);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ *(SplitCurDir + 1) = CHAR_NULL;\r
+ MapListItem = ShellCommandFindMapItem (MapName);\r
+ if (MapListItem != NULL) {\r
+ gShellCurMapping = MapListItem;\r
+ }\r
+ SHELL_FREE_NON_NULL (MapName);\r
+ }\r
+ }\r
} else {\r
Count = (UINTN)-1;\r
}\r
// Get all Device Paths\r
//\r
DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
- ASSERT(DevicePathList != NULL);\r
+ if (DevicePathList == NULL) {\r
+ SHELL_FREE_NON_NULL (HandleList);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
\r
for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
return (EFI_SUCCESS);\r
}\r
\r
+/**\r
+ Add mappings for any devices without one. Do not change any existing maps.\r
+\r
+ @retval EFI_SUCCESS The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellCommandUpdateMapping (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleList;\r
+ UINTN Count;\r
+ EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
+ CHAR16 *NewDefaultName;\r
+ CHAR16 *NewConsistName;\r
+ EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
+\r
+ HandleList = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // remove mappings that represent removed devices.\r
+ //\r
+\r
+ //\r
+ // Find each handle with Simple File System\r
+ //\r
+ HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
+ if (HandleList != NULL) {\r
+ //\r
+ // Do a count of the handles\r
+ //\r
+ for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
+\r
+ //\r
+ // Get all Device Paths\r
+ //\r
+ DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
+ if (DevicePathList == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+\r
+ for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
+ DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
+ }\r
+\r
+ //\r
+ // Sort all DevicePaths\r
+ //\r
+ PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
+\r
+ ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
+\r
+ //\r
+ // Assign new Mappings to remainders\r
+ //\r
+ for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {\r
+ //\r
+ // Skip ones that already have\r
+ //\r
+ if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {\r
+ continue;\r
+ }\r
+ //\r
+ // Get default name\r
+ //\r
+ NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
+ if (NewDefaultName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Call shell protocol SetMap function now...\r
+ //\r
+ Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // Now do consistent name\r
+ //\r
+ NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
+ if (NewConsistName != NULL) {\r
+ Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);\r
+ FreePool(NewConsistName);\r
+ }\r
+ }\r
+\r
+ FreePool(NewDefaultName);\r
+ }\r
+ ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
+ SHELL_FREE_NON_NULL(HandleList);\r
+ SHELL_FREE_NON_NULL(DevicePathList);\r
+\r
+ HandleList = NULL;\r
+ } else {\r
+ Count = (UINTN)-1;\r
+ }\r
+ //\r
+ // Do it all over again for gEfiBlockIoProtocolGuid\r
+ //\r
+\r
+ return (Status);\r
+}\r
+\r
/**\r
Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
\r
}\r
NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));\r
if (NewNode == NULL) {\r
+ SHELL_FREE_NON_NULL(Buffer);\r
return (NULL);\r
}\r
Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;\r
Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
if (Buffer->Path == NULL) {\r
+ SHELL_FREE_NON_NULL(NewNode);\r
+ SHELL_FREE_NON_NULL(Buffer);\r
return (NULL);\r
}\r
NewNode->Buffer = Buffer;\r
\r
gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
Info = gEfiShellProtocol->GetFileInfo (Handle);\r
- ASSERT(Info != NULL);\r
gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
\r
if (Info == NULL) {\r
; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
){\r
RemoveEntryList(&BufferListEntry->Link);\r
- ASSERT(BufferListEntry->Buffer != NULL);\r
if (BufferListEntry->Buffer != NULL) {\r
FreePool(BufferListEntry->Buffer);\r
}\r
}\r
}\r
\r
+/**\r
+ Dump some hexadecimal data to the screen.\r
+\r
+ @param[in] Indent How many spaces to indent the output.\r
+ @param[in] Offset The offset of the printing.\r
+ @param[in] DataSize The size in bytes of UserData.\r
+ @param[in] UserData The data to print out.\r
+**/\r
+VOID\r
+EFIAPI\r
+DumpHex (\r
+ IN UINTN Indent,\r
+ IN UINTN Offset,\r
+ IN UINTN DataSize,\r
+ IN VOID *UserData\r
+ )\r
+{\r
+ UINT8 *Data;\r
+\r
+ CHAR8 Val[50];\r
+\r
+ CHAR8 Str[20];\r
+\r
+ UINT8 TempByte;\r
+ UINTN Size;\r
+ UINTN Index;\r
+\r
+ Data = UserData;\r
+ while (DataSize != 0) {\r
+ Size = 16;\r
+ if (Size > DataSize) {\r
+ Size = DataSize;\r
+ }\r
+\r
+ for (Index = 0; Index < Size; Index += 1) {\r
+ TempByte = Data[Index];\r
+ Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
+ Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > '~') ? '.' : TempByte);\r
+ }\r
+\r
+ Val[Index * 3] = 0;\r
+ Str[Index] = 0;\r
+ ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
+\r
+ Data += Size;\r
+ Offset += Size;\r
+ DataSize -= Size;\r
+ }\r
+}\r
+\r
+/**\r
+ Dump HEX data into buffer.\r
+\r
+ @param[in] Buffer HEX data to be dumped in Buffer.\r
+ @param[in] Indent How many spaces to indent the output.\r
+ @param[in] Offset The offset of the printing.\r
+ @param[in] DataSize The size in bytes of UserData.\r
+ @param[in] UserData The data to print out.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+CatSDumpHex (\r
+ IN CHAR16 *Buffer,\r
+ IN UINTN Indent,\r
+ IN UINTN Offset,\r
+ IN UINTN DataSize,\r
+ IN VOID *UserData\r
+ )\r
+{\r
+ UINT8 *Data;\r
+ UINT8 TempByte;\r
+ UINTN Size;\r
+ UINTN Index;\r
+ CHAR8 Val[50];\r
+ CHAR8 Str[20];\r
+ CHAR16 *RetVal;\r
+ CHAR16 *TempRetVal;\r
+\r
+ Data = UserData;\r
+ RetVal = Buffer;\r
+ while (DataSize != 0) {\r
+ Size = 16;\r
+ if (Size > DataSize) {\r
+ Size = DataSize;\r
+ }\r
+\r
+ for (Index = 0; Index < Size; Index += 1) {\r
+ TempByte = Data[Index];\r
+ Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
+ Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
+ }\r
+\r
+ Val[Index * 3] = 0;\r
+ Str[Index] = 0;\r
+ TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
+ SHELL_FREE_NON_NULL (RetVal);\r
+ RetVal = TempRetVal;\r
+\r
+ Data += Size;\r
+ Offset += Size;\r
+ DataSize -= Size;\r
+ }\r
+\r
+ return RetVal;\r
+}\r