2 Provides interface to shell internal functions for shell commands.
4 (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.
5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UefiShellCommandLib.h"
18 // STATIC local variables
19 STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList
;
20 STATIC SCRIPT_FILE_LIST mScriptList
;
21 STATIC ALIAS_LIST mAliasList
;
22 STATIC BOOLEAN mEchoState
;
23 STATIC BOOLEAN mExitRequested
;
24 STATIC UINT64 mExitCode
;
25 STATIC BOOLEAN mExitScript
;
26 STATIC CHAR16
*mProfileList
;
27 STATIC UINTN mProfileListSize
;
28 STATIC UINTN mFsMaxCount
= 0;
29 STATIC UINTN mBlkMaxCount
= 0;
30 STATIC BUFFER_LIST mFileHandleList
;
32 // global variables required by library class.
33 EFI_UNICODE_COLLATION_PROTOCOL
*gUnicodeCollation
= NULL
;
34 SHELL_MAP_LIST gShellMapList
;
35 SHELL_MAP_LIST
*gShellCurDir
= NULL
;
37 CONST CHAR16
* SupportLevel
[] = {
45 Function to make sure that the global protocol pointers are valid.
46 must be called after constructor before accessing the pointers.
55 if (gUnicodeCollation
== NULL
) {
56 Status
= gBS
->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid
, NULL
, (VOID
**)&gUnicodeCollation
);
57 if (EFI_ERROR(Status
)) {
58 return (EFI_DEVICE_ERROR
);
65 Constructor for the Shell Command library.
67 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
69 @param ImageHandle the image handle of the process
70 @param SystemTable the EFI System Table pointer
72 @retval EFI_SUCCESS the initialization was complete sucessfully
76 ShellCommandLibConstructor (
77 IN EFI_HANDLE ImageHandle
,
78 IN EFI_SYSTEM_TABLE
*SystemTable
82 InitializeListHead(&gShellMapList
.Link
);
83 InitializeListHead(&mCommandList
.Link
);
84 InitializeListHead(&mAliasList
.Link
);
85 InitializeListHead(&mScriptList
.Link
);
86 InitializeListHead(&mFileHandleList
.Link
);
89 mExitRequested
= FALSE
;
94 if (gUnicodeCollation
== NULL
) {
95 Status
= gBS
->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid
, NULL
, (VOID
**)&gUnicodeCollation
);
96 if (EFI_ERROR(Status
)) {
97 return (EFI_DEVICE_ERROR
);
101 return (RETURN_SUCCESS
);
105 Frees list of file handles.
107 @param[in] List The list to free.
115 BUFFER_LIST
*BufferListEntry
;
121 // enumerate through the buffer list and free all memory
123 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
124 ; !IsListEmpty (&List
->Link
)
125 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
127 RemoveEntryList(&BufferListEntry
->Link
);
128 ASSERT(BufferListEntry
->Buffer
!= NULL
);
129 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)(BufferListEntry
->Buffer
))->Path
);
130 SHELL_FREE_NON_NULL(BufferListEntry
->Buffer
);
131 SHELL_FREE_NON_NULL(BufferListEntry
);
136 Destructor for the library. free any resources.
138 @param ImageHandle the image handle of the process
139 @param SystemTable the EFI System Table pointer
141 @retval RETURN_SUCCESS this function always returns success
145 ShellCommandLibDestructor (
146 IN EFI_HANDLE ImageHandle
,
147 IN EFI_SYSTEM_TABLE
*SystemTable
150 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
152 SCRIPT_FILE_LIST
*Node3
;
153 SHELL_MAP_LIST
*MapNode
;
155 // enumerate throught the list and free all the memory
157 while (!IsListEmpty (&mCommandList
.Link
)) {
158 Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
);
159 RemoveEntryList(&Node
->Link
);
160 SHELL_FREE_NON_NULL(Node
->CommandString
);
162 DEBUG_CODE(Node
= NULL
;);
166 // enumerate through the alias list and free all memory
168 while (!IsListEmpty (&mAliasList
.Link
)) {
169 Node2
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
);
170 RemoveEntryList(&Node2
->Link
);
171 SHELL_FREE_NON_NULL(Node2
->CommandString
);
172 SHELL_FREE_NON_NULL(Node2
->Alias
);
173 SHELL_FREE_NON_NULL(Node2
);
174 DEBUG_CODE(Node2
= NULL
;);
178 // enumerate throught the list and free all the memory
180 while (!IsListEmpty (&mScriptList
.Link
)) {
181 Node3
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
182 RemoveEntryList(&Node3
->Link
);
183 DeleteScriptFileStruct(Node3
->Data
);
188 // enumerate throught the mappings list and free all the memory
190 if (!IsListEmpty(&gShellMapList
.Link
)) {
191 for (MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
192 ; !IsListEmpty (&gShellMapList
.Link
)
193 ; MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
195 ASSERT(MapNode
!= NULL
);
196 RemoveEntryList(&MapNode
->Link
);
197 SHELL_FREE_NON_NULL(MapNode
->DevicePath
);
198 SHELL_FREE_NON_NULL(MapNode
->MapName
);
199 SHELL_FREE_NON_NULL(MapNode
->CurrentDirectoryPath
);
203 if (!IsListEmpty(&mFileHandleList
.Link
)){
204 FreeFileHandleList(&mFileHandleList
);
207 if (mProfileList
!= NULL
) {
208 FreePool(mProfileList
);
211 gUnicodeCollation
= NULL
;
214 return (RETURN_SUCCESS
);
218 Checks if a command is already on the list.
220 @param[in] CommandString The command string to check for on the list.
224 ShellCommandIsCommandOnList (
225 IN CONST CHAR16
*CommandString
228 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
231 // assert for NULL parameter
233 ASSERT(CommandString
!= NULL
);
236 // check for the command
238 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
239 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
240 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
242 ASSERT(Node
->CommandString
!= NULL
);
243 if (gUnicodeCollation
->StriColl(
245 (CHAR16
*)CommandString
,
246 Node
->CommandString
) == 0
255 Get the help text for a command.
257 @param[in] CommandString The command name.
259 @retval NULL No help text was found.
260 @return String of help text. Caller reuiqred to free.
264 ShellCommandGetCommandHelp (
265 IN CONST CHAR16
*CommandString
268 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
271 // assert for NULL parameter
273 ASSERT(CommandString
!= NULL
);
276 // check for the command
278 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
279 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
280 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
282 ASSERT(Node
->CommandString
!= NULL
);
283 if (gUnicodeCollation
->StriColl(
285 (CHAR16
*)CommandString
,
286 Node
->CommandString
) == 0
288 return (HiiGetString(Node
->HiiHandle
, Node
->ManFormatHelp
, NULL
));
295 Registers handlers of type SHELL_RUN_COMMAND and
296 SHELL_GET_MAN_FILENAME for each shell command.
298 If the ShellSupportLevel is greater than the value of the
299 PcdShellSupportLevel then return RETURN_UNSUPPORTED.
301 Registers the handlers specified by GetHelpInfoHandler and CommandHandler
302 with the command specified by CommandString. If the command named by
303 CommandString has already been registered, then return
304 RETURN_ALREADY_STARTED.
306 If there are not enough resources available to register the handlers then
307 RETURN_OUT_OF_RESOURCES is returned.
309 If CommandString is NULL, then ASSERT().
310 If GetHelpInfoHandler is NULL, then ASSERT().
311 If CommandHandler is NULL, then ASSERT().
312 If ProfileName is NULL, then ASSERT().
314 @param[in] CommandString Pointer to the command name. This is the
315 name to look for on the command line in
317 @param[in] CommandHandler Pointer to a function that runs the
319 @param[in] GetManFileName Pointer to a function that provides man
321 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
323 @param[in] ProfileName profile name to require for support of this
325 @param[in] CanAffectLE indicates whether this command's return value
326 can change the LASTERROR environment variable.
327 @param[in] HiiHandle Handle of this command's HII entry.
328 @param[in] ManFormatHelp HII locator for the help text.
330 @retval RETURN_SUCCESS The handlers were registered.
331 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
332 register the shell command.
333 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
334 currently allowed support level.
335 @retval RETURN_ALREADY_STARTED The CommandString represents a command that
336 is already registered. Only 1 handler set for
337 a given command is allowed.
338 @sa SHELL_GET_MAN_FILENAME
339 @sa SHELL_RUN_COMMAND
343 ShellCommandRegisterCommandName (
344 IN CONST CHAR16
*CommandString
,
345 IN SHELL_RUN_COMMAND CommandHandler
,
346 IN SHELL_GET_MAN_FILENAME GetManFileName
,
347 IN UINT32 ShellMinSupportLevel
,
348 IN CONST CHAR16
*ProfileName
,
349 IN CONST BOOLEAN CanAffectLE
,
350 IN CONST EFI_HANDLE HiiHandle
,
351 IN CONST EFI_STRING_ID ManFormatHelp
354 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
355 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Command
;
356 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*PrevCommand
;
357 INTN LexicalMatchValue
;
360 // Initialize local variables.
364 LexicalMatchValue
= 0;
367 // ASSERTs for NULL parameters
369 ASSERT(CommandString
!= NULL
);
370 ASSERT(GetManFileName
!= NULL
);
371 ASSERT(CommandHandler
!= NULL
);
372 ASSERT(ProfileName
!= NULL
);
375 // check for shell support level
377 if (PcdGet8(PcdShellSupportLevel
) < ShellMinSupportLevel
) {
378 return (RETURN_UNSUPPORTED
);
382 // check for already on the list
384 if (ShellCommandIsCommandOnList(CommandString
)) {
385 return (RETURN_ALREADY_STARTED
);
389 // allocate memory for new struct
391 Node
= AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY
));
392 ASSERT(Node
!= NULL
);
393 Node
->CommandString
= AllocateZeroPool(StrSize(CommandString
));
394 ASSERT(Node
->CommandString
!= NULL
);
397 // populate the new struct
399 StrCpy(Node
->CommandString
, CommandString
);
401 Node
->GetManFileName
= GetManFileName
;
402 Node
->CommandHandler
= CommandHandler
;
403 Node
->LastError
= CanAffectLE
;
404 Node
->HiiHandle
= HiiHandle
;
405 Node
->ManFormatHelp
= ManFormatHelp
;
407 if ( StrLen(ProfileName
)>0
408 && ((mProfileList
!= NULL
409 && StrStr(mProfileList
, ProfileName
) == NULL
) || mProfileList
== NULL
)
411 ASSERT((mProfileList
== NULL
&& mProfileListSize
== 0) || (mProfileList
!= NULL
));
412 if (mProfileList
== NULL
) {
414 // If this is the first make a leading ';'
416 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
418 StrnCatGrow(&mProfileList
, &mProfileListSize
, ProfileName
, 0);
419 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
423 // Insert a new entry on top of the list
425 InsertHeadList (&mCommandList
.Link
, &Node
->Link
);
428 // Move a new registered command to its sorted ordered location in the list
430 for (Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
),
431 PrevCommand
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
)
432 ; !IsNull (&mCommandList
.Link
, &Command
->Link
)
433 ; Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode (&mCommandList
.Link
, &Command
->Link
)) {
436 // Get Lexical Comparison Value between PrevCommand and Command list entry
438 LexicalMatchValue
= gUnicodeCollation
->StriColl (
440 PrevCommand
->CommandString
,
441 Command
->CommandString
445 // Swap PrevCommand and Command list entry if PrevCommand list entry
446 // is alphabetically greater than Command list entry
448 if (LexicalMatchValue
> 0){
449 Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*) SwapListEntries (&PrevCommand
->Link
, &Command
->Link
);
450 } else if (LexicalMatchValue
< 0) {
452 // PrevCommand entry is lexically lower than Command entry
458 return (RETURN_SUCCESS
);
462 Function to get the current Profile string.
464 @retval NULL There are no installed profiles.
465 @return A semi-colon delimited list of profiles.
469 ShellCommandGetProfileList (
473 return (mProfileList
);
477 Checks if a command string has been registered for CommandString and if so it runs
478 the previously registered handler for that command with the command line.
480 If CommandString is NULL, then ASSERT().
482 If Sections is specified, then each section name listed will be compared in a casesensitive
483 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
484 it will be appended to the returned help text. If the section does not exist, no
485 information will be returned. If Sections is NULL, then all help text information
486 available will be returned.
488 @param[in] CommandString Pointer to the command name. This is the name
489 found on the command line in the shell.
490 @param[in, out] RetVal Pointer to the return vaule from the command handler.
492 @param[in, out] CanAffectLE indicates whether this command's return value
493 needs to be placed into LASTERROR environment variable.
495 @retval RETURN_SUCCESS The handler was run.
496 @retval RETURN_NOT_FOUND The CommandString did not match a registered
498 @sa SHELL_RUN_COMMAND
502 ShellCommandRunCommandHandler (
503 IN CONST CHAR16
*CommandString
,
504 IN OUT SHELL_STATUS
*RetVal
,
505 IN OUT BOOLEAN
*CanAffectLE OPTIONAL
508 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
511 // assert for NULL parameters
513 ASSERT(CommandString
!= NULL
);
516 // check for the command
518 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
519 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
520 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
522 ASSERT(Node
->CommandString
!= NULL
);
523 if (gUnicodeCollation
->StriColl(
525 (CHAR16
*)CommandString
,
526 Node
->CommandString
) == 0
528 if (CanAffectLE
!= NULL
) {
529 *CanAffectLE
= Node
->LastError
;
531 if (RetVal
!= NULL
) {
532 *RetVal
= Node
->CommandHandler(NULL
, gST
);
534 Node
->CommandHandler(NULL
, gST
);
536 return (RETURN_SUCCESS
);
539 return (RETURN_NOT_FOUND
);
543 Checks if a command string has been registered for CommandString and if so it
544 returns the MAN filename specified for that command.
546 If CommandString is NULL, then ASSERT().
548 @param[in] CommandString Pointer to the command name. This is the name
549 found on the command line in the shell.\
551 @retval NULL the commandString was not a registered command.
552 @return other the name of the MAN file.
553 @sa SHELL_GET_MAN_FILENAME
557 ShellCommandGetManFileNameHandler (
558 IN CONST CHAR16
*CommandString
561 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
564 // assert for NULL parameters
566 ASSERT(CommandString
!= NULL
);
569 // check for the command
571 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
572 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
573 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
575 ASSERT(Node
->CommandString
!= NULL
);
576 if (gUnicodeCollation
->StriColl(
578 (CHAR16
*)CommandString
,
579 Node
->CommandString
) == 0
581 return (Node
->GetManFileName());
588 Get the list of all available shell internal commands. This is a linked list
589 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
590 list functions. do not modify the values.
592 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
594 @return a Linked list of all available shell commands.
598 ShellCommandGetCommandList (
599 IN CONST BOOLEAN Sort
603 // return ((COMMAND_LIST*)(&mCommandList));
605 return ((COMMAND_LIST
*)(&mCommandList
));
609 Registers aliases to be set as part of the initialization of the shell application.
611 If Command is NULL, then ASSERT().
612 If Alias is NULL, then ASSERT().
614 @param[in] Command Pointer to the Command
615 @param[in] Alias Pointer to Alias
617 @retval RETURN_SUCCESS The handlers were registered.
618 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
619 register the shell command.
623 ShellCommandRegisterAlias (
624 IN CONST CHAR16
*Command
,
625 IN CONST CHAR16
*Alias
633 ASSERT(Command
!= NULL
);
634 ASSERT(Alias
!= NULL
);
637 // allocate memory for new struct
639 Node
= AllocateZeroPool(sizeof(ALIAS_LIST
));
640 ASSERT(Node
!= NULL
);
641 Node
->CommandString
= AllocateZeroPool(StrSize(Command
));
642 Node
->Alias
= AllocateZeroPool(StrSize(Alias
));
643 ASSERT(Node
->CommandString
!= NULL
);
644 ASSERT(Node
->Alias
!= NULL
);
647 // populate the new struct
649 StrCpy(Node
->CommandString
, Command
);
650 StrCpy(Node
->Alias
, Alias
);
653 // add the new struct to the list
655 InsertTailList (&mAliasList
.Link
, &Node
->Link
);
657 return (RETURN_SUCCESS
);
661 Get the list of all shell alias commands. This is a linked list
662 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
663 list functions. do not modify the values.
665 @return a Linked list of all requested shell alias'.
669 ShellCommandGetInitAliasList (
673 return (&mAliasList
);
677 Determine if a given alias is on the list of built in alias'.
679 @param[in] Alias The alias to test for
681 @retval TRUE The alias is a built in alias
682 @retval FALSE The alias is not a built in alias
686 ShellCommandIsOnAliasList(
687 IN CONST CHAR16
*Alias
693 // assert for NULL parameter
695 ASSERT(Alias
!= NULL
);
698 // check for the Alias
700 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
)
701 ; !IsNull(&mAliasList
.Link
, &Node
->Link
)
702 ; Node
= (ALIAS_LIST
*)GetNextNode(&mAliasList
.Link
, &Node
->Link
)
704 ASSERT(Node
->CommandString
!= NULL
);
705 ASSERT(Node
->Alias
!= NULL
);
706 if (gUnicodeCollation
->StriColl(
709 Node
->CommandString
) == 0
713 if (gUnicodeCollation
->StriColl(
725 Function to determine current state of ECHO. Echo determins if lines from scripts
726 and ECHO commands are enabled.
728 @retval TRUE Echo is currently enabled
729 @retval FALSE Echo is currently disabled
733 ShellCommandGetEchoState(
741 Function to set current state of ECHO. Echo determins if lines from scripts
742 and ECHO commands are enabled.
744 If State is TRUE, Echo will be enabled.
745 If State is FALSE, Echo will be disabled.
747 @param[in] State How to set echo.
751 ShellCommandSetEchoState(
759 Indicate that the current shell or script should exit.
761 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
762 @param[in] ErrorCode The 64 bit error code to return.
766 ShellCommandRegisterExit (
767 IN BOOLEAN ScriptOnly
,
768 IN CONST UINT64 ErrorCode
771 mExitRequested
= (BOOLEAN
)(!mExitRequested
);
772 if (mExitRequested
) {
773 mExitScript
= ScriptOnly
;
777 mExitCode
= ErrorCode
;
781 Retrieve the Exit indicator.
783 @retval TRUE Exit was indicated.
784 @retval FALSE Exis was not indicated.
788 ShellCommandGetExit (
792 return (mExitRequested
);
796 Retrieve the Exit code.
798 If ShellCommandGetExit returns FALSE than the return from this is undefined.
800 @return the value passed into RegisterExit.
804 ShellCommandGetExitCode (
811 Retrieve the Exit script indicator.
813 If ShellCommandGetExit returns FALSE than the return from this is undefined.
815 @retval TRUE ScriptOnly was indicated.
816 @retval FALSE ScriptOnly was not indicated.
820 ShellCommandGetScriptExit (
824 return (mExitScript
);
828 Function to cleanup all memory from a SCRIPT_FILE structure.
830 @param[in] Script The pointer to the structure to cleanup.
834 DeleteScriptFileStruct (
835 IN SCRIPT_FILE
*Script
840 if (Script
== NULL
) {
844 for (LoopVar
= 0 ; LoopVar
< Script
->Argc
; LoopVar
++) {
845 SHELL_FREE_NON_NULL(Script
->Argv
[LoopVar
]);
847 if (Script
->Argv
!= NULL
) {
848 SHELL_FREE_NON_NULL(Script
->Argv
);
850 Script
->CurrentCommand
= NULL
;
851 while (!IsListEmpty (&Script
->CommandList
)) {
852 Script
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&Script
->CommandList
);
853 if (Script
->CurrentCommand
!= NULL
) {
854 RemoveEntryList(&Script
->CurrentCommand
->Link
);
855 if (Script
->CurrentCommand
->Cl
!= NULL
) {
856 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Cl
);
858 if (Script
->CurrentCommand
->Data
!= NULL
) {
859 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Data
);
861 SHELL_FREE_NON_NULL(Script
->CurrentCommand
);
864 SHELL_FREE_NON_NULL(Script
->ScriptName
);
865 SHELL_FREE_NON_NULL(Script
);
869 Function to return a pointer to the currently running script file object.
871 @retval NULL A script file is not currently running.
872 @return A pointer to the current script file object.
876 ShellCommandGetCurrentScriptFile (
880 SCRIPT_FILE_LIST
*List
;
881 if (IsListEmpty (&mScriptList
.Link
)) {
884 List
= ((SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
));
889 Function to set a new script as the currently running one.
891 This function will correctly stack and unstack nested scripts.
893 @param[in] Script Pointer to new script information structure. if NULL
894 will remove and de-allocate the top-most Script structure.
896 @return A pointer to the current running script file after this
897 change. NULL if removing the final script.
901 ShellCommandSetNewScript (
902 IN SCRIPT_FILE
*Script OPTIONAL
905 SCRIPT_FILE_LIST
*Node
;
906 if (Script
== NULL
) {
907 if (IsListEmpty (&mScriptList
.Link
)) {
910 Node
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
911 RemoveEntryList(&Node
->Link
);
912 DeleteScriptFileStruct(Node
->Data
);
915 Node
= AllocateZeroPool(sizeof(SCRIPT_FILE_LIST
));
920 InsertHeadList(&mScriptList
.Link
, &Node
->Link
);
922 return (ShellCommandGetCurrentScriptFile());
926 Function to generate the next default mapping name.
928 If the return value is not NULL then it must be callee freed.
930 @param Type What kind of mapping name to make.
932 @retval NULL a memory allocation failed.
933 @return a new map name string
937 ShellCommandCreateNewMappingName(
938 IN CONST SHELL_MAPPING_TYPE Type
942 ASSERT(Type
< MappingTypeMax
);
946 String
= AllocateZeroPool(PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]));
949 PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]),
950 Type
== MappingTypeFileSystem
?L
"FS%d:":L
"BLK%d:",
951 Type
== MappingTypeFileSystem
?mFsMaxCount
++:mBlkMaxCount
++);
957 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
959 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
960 default paths on the new map name...
962 Path should be FALSE when this function is called from the protocol SetMap function.
964 @param[in] Name The human readable mapped name.
965 @param[in] DevicePath The Device Path for this map.
966 @param[in] Flags The Flags attribute for this map item.
967 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
969 @retval EFI_SUCCESS The addition was sucessful.
970 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
971 @retval EFI_INVALID_PARAMETER A parameter was invalid.
975 ShellCommandAddMapItemAndUpdatePath(
976 IN CONST CHAR16
*Name
,
977 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
978 IN CONST UINT64 Flags
,
979 IN CONST BOOLEAN Path
983 SHELL_MAP_LIST
*MapListNode
;
984 CONST CHAR16
*OriginalPath
;
991 Status
= EFI_SUCCESS
;
993 MapListNode
= AllocateZeroPool(sizeof(SHELL_MAP_LIST
));
994 if (MapListNode
== NULL
) {
995 Status
= EFI_OUT_OF_RESOURCES
;
997 MapListNode
->Flags
= Flags
;
998 MapListNode
->MapName
= AllocateZeroPool(StrSize(Name
));
999 MapListNode
->DevicePath
= DuplicateDevicePath(DevicePath
);
1000 if ((MapListNode
->MapName
== NULL
) || (MapListNode
->DevicePath
== NULL
)){
1001 Status
= EFI_OUT_OF_RESOURCES
;
1003 StrCpy(MapListNode
->MapName
, Name
);
1004 InsertTailList(&gShellMapList
.Link
, &MapListNode
->Link
);
1007 if (EFI_ERROR(Status
)) {
1008 if (MapListNode
!= NULL
) {
1009 if (MapListNode
->DevicePath
!= NULL
) {
1010 FreePool(MapListNode
->DevicePath
);
1012 if (MapListNode
->MapName
!= NULL
) {
1013 FreePool(MapListNode
->MapName
);
1015 FreePool(MapListNode
);
1019 // Since there was no error and Path was TRUE
1020 // Now add the correct path for that mapping
1022 OriginalPath
= gEfiShellProtocol
->GetEnv(L
"path");
1023 ASSERT((NewPath
== NULL
&& NewPathSize
== 0) || (NewPath
!= NULL
));
1024 if (OriginalPath
!= NULL
) {
1025 StrnCatGrow(&NewPath
, &NewPathSize
, OriginalPath
, 0);
1027 StrnCatGrow(&NewPath
, &NewPathSize
, L
".\\", 0);
1029 StrnCatGrow(&NewPath
, &NewPathSize
, L
";", 0);
1030 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1031 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\tools\\;", 0);
1032 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1033 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\boot\\;", 0);
1034 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1035 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\", 0);
1037 Status
= gEfiShellProtocol
->SetEnv(L
"path", NewPath
, TRUE
);
1038 ASSERT_EFI_ERROR(Status
);
1045 Creates the default map names for each device path in the system with
1046 a protocol depending on the Type.
1048 Creates the consistent map names for each device path in the system with
1049 a protocol depending on the Type.
1051 Note: This will reset all mappings in the system("map -r").
1053 Also sets up the default path environment variable if Type is FileSystem.
1055 @retval EFI_SUCCESS All map names were created sucessfully.
1056 @retval EFI_NOT_FOUND No protocols were found in the system.
1057 @return Error returned from gBS->LocateHandle().
1063 ShellCommandCreateInitialMappingsAndPaths(
1068 EFI_HANDLE
*HandleList
;
1070 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1071 CHAR16
*NewDefaultName
;
1072 CHAR16
*NewConsistName
;
1073 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1074 SHELL_MAP_LIST
*MapListNode
;
1079 // Reset the static members back to zero
1084 gEfiShellProtocol
->SetEnv(L
"path", L
"", TRUE
);
1087 // First empty out the existing list.
1089 if (!IsListEmpty(&gShellMapList
.Link
)) {
1090 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1091 ; !IsListEmpty(&gShellMapList
.Link
)
1092 ; MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1094 RemoveEntryList(&MapListNode
->Link
);
1095 FreePool(MapListNode
);
1100 // Find each handle with Simple File System
1102 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1103 if (HandleList
!= NULL
) {
1105 // Do a count of the handles
1107 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1110 // Get all Device Paths
1112 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1113 ASSERT(DevicePathList
!= NULL
);
1115 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1116 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1120 // Sort all DevicePaths
1122 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1124 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1126 // Assign new Mappings to all...
1128 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1130 // Get default name first
1132 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1133 ASSERT(NewDefaultName
!= NULL
);
1134 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, TRUE
);
1135 ASSERT_EFI_ERROR(Status
);
1136 FreePool(NewDefaultName
);
1139 // Now do consistent name
1141 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1142 if (NewConsistName
!= NULL
) {
1143 Status
= ShellCommandAddMapItemAndUpdatePath(NewConsistName
, DevicePathList
[Count
], 0, FALSE
);
1144 ASSERT_EFI_ERROR(Status
);
1145 FreePool(NewConsistName
);
1149 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1151 SHELL_FREE_NON_NULL(HandleList
);
1152 SHELL_FREE_NON_NULL(DevicePathList
);
1160 // Find each handle with Block Io
1162 HandleList
= GetHandleListByProtocol(&gEfiBlockIoProtocolGuid
);
1163 if (HandleList
!= NULL
) {
1164 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1167 // Get all Device Paths
1169 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1170 ASSERT(DevicePathList
!= NULL
);
1172 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1173 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1177 // Sort all DevicePaths
1179 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1182 // Assign new Mappings to all...
1184 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1186 // Get default name first
1188 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeBlockIo
);
1189 ASSERT(NewDefaultName
!= NULL
);
1190 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, FALSE
);
1191 ASSERT_EFI_ERROR(Status
);
1192 FreePool(NewDefaultName
);
1195 SHELL_FREE_NON_NULL(HandleList
);
1196 SHELL_FREE_NON_NULL(DevicePathList
);
1197 } else if (Count
== (UINTN
)-1) {
1198 return (EFI_NOT_FOUND
);
1201 return (EFI_SUCCESS
);
1205 Add mappings for any devices without one. Do not change any existing maps.
1207 @retval EFI_SUCCESS The operation was successful.
1211 ShellCommandUpdateMapping (
1216 EFI_HANDLE
*HandleList
;
1218 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1219 CHAR16
*NewDefaultName
;
1220 CHAR16
*NewConsistName
;
1221 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1224 Status
= EFI_SUCCESS
;
1227 // remove mappings that represent removed devices.
1231 // Find each handle with Simple File System
1233 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1234 if (HandleList
!= NULL
) {
1236 // Do a count of the handles
1238 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1241 // Get all Device Paths
1243 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1244 ASSERT(DevicePathList
!= NULL
);
1246 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1247 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1251 // Sort all DevicePaths
1253 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1255 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1258 // Assign new Mappings to remainders
1260 for (Count
= 0 ; HandleList
[Count
] != NULL
&& !EFI_ERROR(Status
); Count
++) {
1262 // Skip ones that already have
1264 if (gEfiShellProtocol
->GetMapFromDevicePath(&DevicePathList
[Count
]) != NULL
) {
1270 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1271 ASSERT(NewDefaultName
!= NULL
);
1274 // Call shell protocol SetMap function now...
1276 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewDefaultName
);
1278 if (!EFI_ERROR(Status
)) {
1280 // Now do consistent name
1282 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1283 if (NewConsistName
!= NULL
) {
1284 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewConsistName
);
1285 FreePool(NewConsistName
);
1289 FreePool(NewDefaultName
);
1291 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1292 SHELL_FREE_NON_NULL(HandleList
);
1293 SHELL_FREE_NON_NULL(DevicePathList
);
1300 // Do it all over again for gEfiBlockIoProtocolGuid
1307 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1309 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1311 @return a EFI_FILE_PROTOCOL* representing the same file.
1315 ConvertShellHandleToEfiFileProtocol(
1316 IN CONST SHELL_FILE_HANDLE Handle
1319 return ((EFI_FILE_PROTOCOL
*)(Handle
));
1323 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1325 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1326 @param[in] Path The path to the file for verification.
1328 @return A SHELL_FILE_HANDLE representing the same file.
1329 @retval NULL There was not enough memory.
1333 ConvertEfiFileProtocolToShellHandle(
1334 IN CONST EFI_FILE_PROTOCOL
*Handle
,
1335 IN CONST CHAR16
*Path
1338 SHELL_COMMAND_FILE_HANDLE
*Buffer
;
1339 BUFFER_LIST
*NewNode
;
1342 Buffer
= AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE
));
1343 if (Buffer
== NULL
) {
1346 NewNode
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1347 if (NewNode
== NULL
) {
1350 Buffer
->FileHandle
= (EFI_FILE_PROTOCOL
*)Handle
;
1351 Buffer
->Path
= StrnCatGrow(&Buffer
->Path
, NULL
, Path
, 0);
1352 if (Buffer
->Path
== NULL
) {
1355 NewNode
->Buffer
= Buffer
;
1357 InsertHeadList(&mFileHandleList
.Link
, &NewNode
->Link
);
1359 return ((SHELL_FILE_HANDLE
)(Handle
));
1363 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1365 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1367 @return A pointer to the path for the file.
1371 ShellFileHandleGetPath(
1372 IN CONST SHELL_FILE_HANDLE Handle
1377 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1378 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1379 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1381 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1382 return (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1389 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1391 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1393 @retval TRUE The item was removed.
1394 @retval FALSE The item was not found.
1398 ShellFileHandleRemove(
1399 IN CONST SHELL_FILE_HANDLE Handle
1404 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1405 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1406 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1408 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1409 RemoveEntryList(&Node
->Link
);
1410 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1411 SHELL_FREE_NON_NULL(Node
->Buffer
);
1412 SHELL_FREE_NON_NULL(Node
);
1420 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1422 This will NOT work on directories.
1424 If Handle is NULL, then ASSERT.
1426 @param[in] Handle the file handle
1428 @retval TRUE the position is at the end of the file
1429 @retval FALSE the position is not at the end of the file
1434 IN SHELL_FILE_HANDLE Handle
1437 EFI_FILE_INFO
*Info
;
1442 // ASSERT if Handle is NULL
1444 ASSERT(Handle
!= NULL
);
1446 gEfiShellProtocol
->GetFilePosition(Handle
, &Pos
);
1447 Info
= gEfiShellProtocol
->GetFileInfo (Handle
);
1448 ASSERT(Info
!= NULL
);
1449 gEfiShellProtocol
->SetFilePosition(Handle
, Pos
);
1455 if (Pos
== Info
->FileSize
) {
1467 Frees any BUFFER_LIST defined type.
1469 @param[in] List The BUFFER_LIST object to free.
1474 IN BUFFER_LIST
*List
1477 BUFFER_LIST
*BufferListEntry
;
1483 // enumerate through the buffer list and free all memory
1485 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1486 ; !IsListEmpty (&List
->Link
)
1487 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1489 RemoveEntryList(&BufferListEntry
->Link
);
1490 ASSERT(BufferListEntry
->Buffer
!= NULL
);
1491 if (BufferListEntry
->Buffer
!= NULL
) {
1492 FreePool(BufferListEntry
->Buffer
);
1494 FreePool(BufferListEntry
);