/** @file | |
Provides interface to shell internal functions for shell commands. | |
Copyright (c) 2013-2014, Hewlett-Packard Development Company, L.P.<BR> | |
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> | |
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" | |
// 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 UINT64 mExitCode; | |
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_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = 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 (gUnicodeCollation == NULL) { | |
Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation); | |
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); | |
} | |
/** | |
Frees list of file handles. | |
@param[in] List The list to free. | |
**/ | |
VOID | |
EFIAPI | |
FreeFileHandleList ( | |
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); | |
SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path); | |
SHELL_FREE_NON_NULL(BufferListEntry->Buffer); | |
SHELL_FREE_NON_NULL(BufferListEntry); | |
} | |
} | |
/** | |
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; | |
ALIAS_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 alias list and free all memory | |
// | |
while (!IsListEmpty (&mAliasList.Link)) { | |
Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link); | |
RemoveEntryList(&Node2->Link); | |
SHELL_FREE_NON_NULL(Node2->CommandString); | |
SHELL_FREE_NON_NULL(Node2->Alias); | |
SHELL_FREE_NON_NULL(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)){ | |
FreeFileHandleList(&mFileHandleList); | |
} | |
if (mProfileList != NULL) { | |
FreePool(mProfileList); | |
} | |
gUnicodeCollation = NULL; | |
gShellCurDir = NULL; | |
return (RETURN_SUCCESS); | |
} | |
/** | |
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 | |
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; | |
// | |
// 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); | |
} | |
/** | |
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. | |
@retval NULL No help text was found. | |
@return String of help text. Caller reuiqred to free. | |
**/ | |
CHAR16* | |
EFIAPI | |
ShellCommandGetInternalCommandHelp( | |
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); | |
} | |
/** | |
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. | |
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; | |
SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command; | |
SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand; | |
INTN LexicalMatchValue; | |
// | |
// Initialize local variables. | |
// | |
Command = NULL; | |
PrevCommand = NULL; | |
LexicalMatchValue = 0; | |
// | |
// 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 = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY)); | |
ASSERT(Node != NULL); | |
Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString); | |
ASSERT(Node->CommandString != NULL); | |
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); | |
} | |
// | |
// Insert a new entry on top of the list | |
// | |
InsertHeadList (&mCommandList.Link, &Node->Link); | |
// | |
// Move a new registered command to its sorted ordered location in the list | |
// | |
for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link), | |
PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link) | |
; !IsNull (&mCommandList.Link, &Command->Link) | |
; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) { | |
// | |
// Get Lexical Comparison Value between PrevCommand and Command list entry | |
// | |
LexicalMatchValue = gUnicodeCollation->StriColl ( | |
gUnicodeCollation, | |
PrevCommand->CommandString, | |
Command->CommandString | |
); | |
// | |
// Swap PrevCommand and Command list entry if PrevCommand list entry | |
// is alphabetically greater than Command list entry | |
// | |
if (LexicalMatchValue > 0){ | |
Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link); | |
} else if (LexicalMatchValue < 0) { | |
// | |
// PrevCommand entry is lexically lower than Command entry | |
// | |
break; | |
} | |
} | |
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[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; | |
EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand; | |
// | |
// 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); | |
} | |
} | |
// | |
// 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); | |
} | |
/** | |
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. | |
@param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise. | |
@return a Linked list of all available shell commands. | |
**/ | |
CONST COMMAND_LIST* | |
EFIAPI | |
ShellCommandGetCommandList ( | |
IN CONST BOOLEAN Sort | |
) | |
{ | |
// if (!Sort) { | |
// return ((COMMAND_LIST*)(&mCommandList)); | |
// } | |
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; | |
ALIAS_LIST *CommandAlias; | |
ALIAS_LIST *PrevCommandAlias; | |
INTN LexicalMatchValue; | |
// | |
// Asserts for NULL | |
// | |
ASSERT(Command != NULL); | |
ASSERT(Alias != NULL); | |
// | |
// allocate memory for new struct | |
// | |
Node = AllocateZeroPool(sizeof(ALIAS_LIST)); | |
ASSERT(Node != NULL); | |
Node->CommandString = AllocateCopyPool(StrSize(Command), Command); | |
Node->Alias = AllocateCopyPool(StrSize(Alias), Alias); | |
ASSERT(Node->CommandString != NULL); | |
ASSERT(Node->Alias != NULL); | |
InsertHeadList (&mAliasList.Link, &Node->Link); | |
// | |
// Move a new pre-defined registered alias to its sorted ordered location in the list | |
// | |
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); | |
} | |
/** | |
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. | |
@param[in] State How to set echo. | |
**/ | |
VOID | |
EFIAPI | |
ShellCommandSetEchoState( | |
IN BOOLEAN State | |
) | |
{ | |
mEchoState = State; | |
} | |
/** | |
Indicate that the current shell or script should exit. | |
@param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise. | |
@param[in] ErrorCode The 64 bit error code to return. | |
**/ | |
VOID | |
EFIAPI | |
ShellCommandRegisterExit ( | |
IN BOOLEAN ScriptOnly, | |
IN CONST UINT64 ErrorCode | |
) | |
{ | |
mExitRequested = (BOOLEAN)(!mExitRequested); | |
if (mExitRequested) { | |
mExitScript = ScriptOnly; | |
} else { | |
mExitScript = FALSE; | |
} | |
mExitCode = ErrorCode; | |
} | |
/** | |
Retrieve the Exit indicator. | |
@retval TRUE Exit was indicated. | |
@retval FALSE Exis was not indicated. | |
**/ | |
BOOLEAN | |
EFIAPI | |
ShellCommandGetExit ( | |
VOID | |
) | |
{ | |
return (mExitRequested); | |
} | |
/** | |
Retrieve the Exit code. | |
If ShellCommandGetExit returns FALSE than the return from this is undefined. | |
@return the value passed into RegisterExit. | |
**/ | |
UINT64 | |
EFIAPI | |
ShellCommandGetExitCode ( | |
VOID | |
) | |
{ | |
return (mExitCode); | |
} | |
/** | |
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; | |
if (Script == NULL) { | |
return; | |
} | |
for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) { | |
SHELL_FREE_NON_NULL(Script->Argv[LoopVar]); | |
} | |
if (Script->Argv != NULL) { | |
SHELL_FREE_NON_NULL(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) { | |
SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl); | |
} | |
if (Script->CurrentCommand->Data != NULL) { | |
SHELL_FREE_NON_NULL(Script->CurrentCommand->Data); | |
} | |
SHELL_FREE_NON_NULL(Script->CurrentCommand); | |
} | |
} | |
SHELL_FREE_NON_NULL(Script->ScriptName); | |
SHELL_FREE_NON_NULL(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)) { | |
return (NULL); | |
} | |
Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link); | |
RemoveEntryList(&Node->Link); | |
DeleteScriptFileStruct(Node->Data); | |
FreePool(Node); | |
} else { | |
Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST)); | |
if (Node == NULL) { | |
return (NULL); | |
} | |
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 = AllocateCopyPool(StrSize(Name), Name); | |
MapListNode->DevicePath = DuplicateDevicePath(DevicePath); | |
if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){ | |
Status = EFI_OUT_OF_RESOURCES; | |
} else { | |
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 = 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 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 = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid); | |
if (HandleList != NULL) { | |
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); | |
// | |
// 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); | |
} | |
/** | |
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. | |
**/ | |
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. | |
@retval NULL There was not enough memory. | |
**/ | |
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)); | |
if (Buffer == NULL) { | |
return (NULL); | |
} | |
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; | |
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 from 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)){ | |
RemoveEntryList(&Node->Link); | |
SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path); | |
SHELL_FREE_NON_NULL(Node->Buffer); | |
SHELL_FREE_NON_NULL(Node); | |
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); | |
} | |
/** | |
Frees any BUFFER_LIST defined type. | |
@param[in] List The BUFFER_LIST object to free. | |
**/ | |
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); | |
if (BufferListEntry->Buffer != NULL) { | |
FreePool(BufferListEntry->Buffer); | |
} | |
FreePool(BufferListEntry); | |
} | |
} | |