]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg/ConsistMapping.c: Handle memory allocation failure
[mirror_edk2.git] / ShellPkg / Library / UefiShellCommandLib / UefiShellCommandLib.c
1 /** @file
2 Provides interface to shell internal functions for shell commands.
3
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
7
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "UefiShellCommandLib.h"
19
20 // STATIC local variables
21 STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;
22 STATIC SCRIPT_FILE_LIST mScriptList;
23 STATIC ALIAS_LIST mAliasList;
24 STATIC BOOLEAN mEchoState;
25 STATIC BOOLEAN mExitRequested;
26 STATIC UINT64 mExitCode;
27 STATIC BOOLEAN mExitScript;
28 STATIC CHAR16 *mProfileList;
29 STATIC UINTN mProfileListSize;
30 STATIC UINTN mFsMaxCount = 0;
31 STATIC UINTN mBlkMaxCount = 0;
32 STATIC BUFFER_LIST mFileHandleList;
33
34 STATIC CONST CHAR8 Hex[] = {
35 '0',
36 '1',
37 '2',
38 '3',
39 '4',
40 '5',
41 '6',
42 '7',
43 '8',
44 '9',
45 'A',
46 'B',
47 'C',
48 'D',
49 'E',
50 'F'
51 };
52
53 // global variables required by library class.
54 EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;
55 SHELL_MAP_LIST gShellMapList;
56 SHELL_MAP_LIST *gShellCurDir = NULL;
57
58 CONST CHAR16* SupportLevel[] = {
59 L"Minimal",
60 L"Scripting",
61 L"Basic",
62 L"Interactive"
63 };
64
65 /**
66 Function to make sure that the global protocol pointers are valid.
67 must be called after constructor before accessing the pointers.
68 **/
69 EFI_STATUS
70 EFIAPI
71 CommandInit(
72 VOID
73 )
74 {
75 EFI_STATUS Status;
76 if (gUnicodeCollation == NULL) {
77 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
78 if (EFI_ERROR(Status)) {
79 return (EFI_DEVICE_ERROR);
80 }
81 }
82 return (EFI_SUCCESS);
83 }
84
85 /**
86 Constructor for the Shell Command library.
87
88 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
89
90 @param ImageHandle the image handle of the process
91 @param SystemTable the EFI System Table pointer
92
93 @retval EFI_SUCCESS the initialization was complete sucessfully
94 **/
95 RETURN_STATUS
96 EFIAPI
97 ShellCommandLibConstructor (
98 IN EFI_HANDLE ImageHandle,
99 IN EFI_SYSTEM_TABLE *SystemTable
100 )
101 {
102 EFI_STATUS Status;
103 InitializeListHead(&gShellMapList.Link);
104 InitializeListHead(&mCommandList.Link);
105 InitializeListHead(&mAliasList.Link);
106 InitializeListHead(&mScriptList.Link);
107 InitializeListHead(&mFileHandleList.Link);
108 mEchoState = TRUE;
109
110 mExitRequested = FALSE;
111 mExitScript = FALSE;
112 mProfileListSize = 0;
113 mProfileList = NULL;
114
115 if (gUnicodeCollation == NULL) {
116 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
117 if (EFI_ERROR(Status)) {
118 return (EFI_DEVICE_ERROR);
119 }
120 }
121
122 return (RETURN_SUCCESS);
123 }
124
125 /**
126 Frees list of file handles.
127
128 @param[in] List The list to free.
129 **/
130 VOID
131 EFIAPI
132 FreeFileHandleList (
133 IN BUFFER_LIST *List
134 )
135 {
136 BUFFER_LIST *BufferListEntry;
137
138 if (List == NULL){
139 return;
140 }
141 //
142 // enumerate through the buffer list and free all memory
143 //
144 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
145 ; !IsListEmpty (&List->Link)
146 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
147 ){
148 RemoveEntryList(&BufferListEntry->Link);
149 ASSERT(BufferListEntry->Buffer != NULL);
150 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);
151 SHELL_FREE_NON_NULL(BufferListEntry->Buffer);
152 SHELL_FREE_NON_NULL(BufferListEntry);
153 }
154 }
155
156 /**
157 Destructor for the library. free any resources.
158
159 @param ImageHandle the image handle of the process
160 @param SystemTable the EFI System Table pointer
161
162 @retval RETURN_SUCCESS this function always returns success
163 **/
164 RETURN_STATUS
165 EFIAPI
166 ShellCommandLibDestructor (
167 IN EFI_HANDLE ImageHandle,
168 IN EFI_SYSTEM_TABLE *SystemTable
169 )
170 {
171 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
172 ALIAS_LIST *Node2;
173 SCRIPT_FILE_LIST *Node3;
174 SHELL_MAP_LIST *MapNode;
175 //
176 // enumerate throught the list and free all the memory
177 //
178 while (!IsListEmpty (&mCommandList.Link)) {
179 Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);
180 RemoveEntryList(&Node->Link);
181 SHELL_FREE_NON_NULL(Node->CommandString);
182 FreePool(Node);
183 DEBUG_CODE(Node = NULL;);
184 }
185
186 //
187 // enumerate through the alias list and free all memory
188 //
189 while (!IsListEmpty (&mAliasList.Link)) {
190 Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);
191 RemoveEntryList(&Node2->Link);
192 SHELL_FREE_NON_NULL(Node2->CommandString);
193 SHELL_FREE_NON_NULL(Node2->Alias);
194 SHELL_FREE_NON_NULL(Node2);
195 DEBUG_CODE(Node2 = NULL;);
196 }
197
198 //
199 // enumerate throught the list and free all the memory
200 //
201 while (!IsListEmpty (&mScriptList.Link)) {
202 Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
203 RemoveEntryList(&Node3->Link);
204 DeleteScriptFileStruct(Node3->Data);
205 FreePool(Node3);
206 }
207
208 //
209 // enumerate throught the mappings list and free all the memory
210 //
211 if (!IsListEmpty(&gShellMapList.Link)) {
212 for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
213 ; !IsListEmpty (&gShellMapList.Link)
214 ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
215 ){
216 ASSERT(MapNode != NULL);
217 RemoveEntryList(&MapNode->Link);
218 SHELL_FREE_NON_NULL(MapNode->DevicePath);
219 SHELL_FREE_NON_NULL(MapNode->MapName);
220 SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);
221 FreePool(MapNode);
222 }
223 }
224 if (!IsListEmpty(&mFileHandleList.Link)){
225 FreeFileHandleList(&mFileHandleList);
226 }
227
228 if (mProfileList != NULL) {
229 FreePool(mProfileList);
230 }
231
232 gUnicodeCollation = NULL;
233 gShellCurDir = NULL;
234
235 return (RETURN_SUCCESS);
236 }
237
238 /**
239 Find a dynamic command protocol instance given a command name string.
240
241 @param CommandString the command name string
242
243 @return instance the command protocol instance, if dynamic command instance found
244 @retval NULL no dynamic command protocol instance found for name
245 **/
246 CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *
247 EFIAPI
248 ShellCommandFindDynamicCommand (
249 IN CONST CHAR16 *CommandString
250 )
251 {
252 EFI_STATUS Status;
253 EFI_HANDLE *CommandHandleList;
254 EFI_HANDLE *NextCommand;
255 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
256
257 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);
258 if (CommandHandleList == NULL) {
259 //
260 // not found or out of resources
261 //
262 return NULL;
263 }
264
265 for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {
266 Status = gBS->HandleProtocol(
267 *NextCommand,
268 &gEfiShellDynamicCommandProtocolGuid,
269 (VOID **)&DynamicCommand
270 );
271
272 if (EFI_ERROR(Status)) {
273 continue;
274 }
275
276 if (gUnicodeCollation->StriColl(
277 gUnicodeCollation,
278 (CHAR16*)CommandString,
279 (CHAR16*)DynamicCommand->CommandName) == 0
280 ){
281 FreePool(CommandHandleList);
282 return (DynamicCommand);
283 }
284 }
285
286 FreePool(CommandHandleList);
287 return (NULL);
288 }
289
290 /**
291 Checks if a command exists as a dynamic command protocol instance
292
293 @param[in] CommandString The command string to check for on the list.
294 **/
295 BOOLEAN
296 EFIAPI
297 ShellCommandDynamicCommandExists (
298 IN CONST CHAR16 *CommandString
299 )
300 {
301 return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));
302 }
303
304 /**
305 Checks if a command is already on the internal command list.
306
307 @param[in] CommandString The command string to check for on the list.
308 **/
309 BOOLEAN
310 EFIAPI
311 ShellCommandIsCommandOnInternalList(
312 IN CONST CHAR16 *CommandString
313 )
314 {
315 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
316
317 //
318 // assert for NULL parameter
319 //
320 ASSERT(CommandString != NULL);
321
322 //
323 // check for the command
324 //
325 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
326 ; !IsNull(&mCommandList.Link, &Node->Link)
327 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
328 ){
329 ASSERT(Node->CommandString != NULL);
330 if (gUnicodeCollation->StriColl(
331 gUnicodeCollation,
332 (CHAR16*)CommandString,
333 Node->CommandString) == 0
334 ){
335 return (TRUE);
336 }
337 }
338 return (FALSE);
339 }
340
341 /**
342 Checks if a command exists, either internally or through the dynamic command protocol.
343
344 @param[in] CommandString The command string to check for on the list.
345 **/
346 BOOLEAN
347 EFIAPI
348 ShellCommandIsCommandOnList(
349 IN CONST CHAR16 *CommandString
350 )
351 {
352 if (ShellCommandIsCommandOnInternalList(CommandString)) {
353 return TRUE;
354 }
355
356 return ShellCommandDynamicCommandExists(CommandString);
357 }
358
359 /**
360 Get the help text for a dynamic command.
361
362 @param[in] CommandString The command name.
363
364 @retval NULL No help text was found.
365 @return String of help text. Caller required to free.
366 **/
367 CHAR16*
368 EFIAPI
369 ShellCommandGetDynamicCommandHelp(
370 IN CONST CHAR16 *CommandString
371 )
372 {
373 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
374
375 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);
376 if (DynamicCommand == NULL) {
377 return (NULL);
378 }
379
380 //
381 // TODO: how to get proper language?
382 //
383 return DynamicCommand->GetHelp(DynamicCommand, "en");
384 }
385
386 /**
387 Get the help text for an internal command.
388
389 @param[in] CommandString The command name.
390
391 @retval NULL No help text was found.
392 @return String of help text. Caller reuiqred to free.
393 **/
394 CHAR16*
395 EFIAPI
396 ShellCommandGetInternalCommandHelp(
397 IN CONST CHAR16 *CommandString
398 )
399 {
400 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
401
402 //
403 // assert for NULL parameter
404 //
405 ASSERT(CommandString != NULL);
406
407 //
408 // check for the command
409 //
410 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
411 ; !IsNull(&mCommandList.Link, &Node->Link)
412 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
413 ){
414 ASSERT(Node->CommandString != NULL);
415 if (gUnicodeCollation->StriColl(
416 gUnicodeCollation,
417 (CHAR16*)CommandString,
418 Node->CommandString) == 0
419 ){
420 return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));
421 }
422 }
423 return (NULL);
424 }
425
426 /**
427 Get the help text for a command.
428
429 @param[in] CommandString The command name.
430
431 @retval NULL No help text was found.
432 @return String of help text.Caller reuiqred to free.
433 **/
434 CHAR16*
435 EFIAPI
436 ShellCommandGetCommandHelp (
437 IN CONST CHAR16 *CommandString
438 )
439 {
440 CHAR16 *HelpStr;
441 HelpStr = ShellCommandGetInternalCommandHelp(CommandString);
442
443 if (HelpStr == NULL) {
444 HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);
445 }
446
447 return HelpStr;
448 }
449
450
451 /**
452 Registers handlers of type SHELL_RUN_COMMAND and
453 SHELL_GET_MAN_FILENAME for each shell command.
454
455 If the ShellSupportLevel is greater than the value of the
456 PcdShellSupportLevel then return RETURN_UNSUPPORTED.
457
458 Registers the handlers specified by GetHelpInfoHandler and CommandHandler
459 with the command specified by CommandString. If the command named by
460 CommandString has already been registered, then return
461 RETURN_ALREADY_STARTED.
462
463 If there are not enough resources available to register the handlers then
464 RETURN_OUT_OF_RESOURCES is returned.
465
466 If CommandString is NULL, then ASSERT().
467 If GetHelpInfoHandler is NULL, then ASSERT().
468 If CommandHandler is NULL, then ASSERT().
469 If ProfileName is NULL, then ASSERT().
470
471 @param[in] CommandString Pointer to the command name. This is the
472 name to look for on the command line in
473 the shell.
474 @param[in] CommandHandler Pointer to a function that runs the
475 specified command.
476 @param[in] GetManFileName Pointer to a function that provides man
477 filename.
478 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
479 function.
480 @param[in] ProfileName profile name to require for support of this
481 function.
482 @param[in] CanAffectLE indicates whether this command's return value
483 can change the LASTERROR environment variable.
484 @param[in] HiiHandle Handle of this command's HII entry.
485 @param[in] ManFormatHelp HII locator for the help text.
486
487 @retval RETURN_SUCCESS The handlers were registered.
488 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
489 register the shell command.
490 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
491 currently allowed support level.
492 @retval RETURN_ALREADY_STARTED The CommandString represents a command that
493 is already registered. Only 1 handler set for
494 a given command is allowed.
495 @sa SHELL_GET_MAN_FILENAME
496 @sa SHELL_RUN_COMMAND
497 **/
498 RETURN_STATUS
499 EFIAPI
500 ShellCommandRegisterCommandName (
501 IN CONST CHAR16 *CommandString,
502 IN SHELL_RUN_COMMAND CommandHandler,
503 IN SHELL_GET_MAN_FILENAME GetManFileName,
504 IN UINT32 ShellMinSupportLevel,
505 IN CONST CHAR16 *ProfileName,
506 IN CONST BOOLEAN CanAffectLE,
507 IN CONST EFI_HANDLE HiiHandle,
508 IN CONST EFI_STRING_ID ManFormatHelp
509 )
510 {
511 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
512 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;
513 SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;
514 INTN LexicalMatchValue;
515
516 //
517 // Initialize local variables.
518 //
519 Command = NULL;
520 PrevCommand = NULL;
521 LexicalMatchValue = 0;
522
523 //
524 // ASSERTs for NULL parameters
525 //
526 ASSERT(CommandString != NULL);
527 ASSERT(GetManFileName != NULL);
528 ASSERT(CommandHandler != NULL);
529 ASSERT(ProfileName != NULL);
530
531 //
532 // check for shell support level
533 //
534 if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {
535 return (RETURN_UNSUPPORTED);
536 }
537
538 //
539 // check for already on the list
540 //
541 if (ShellCommandIsCommandOnList(CommandString)) {
542 return (RETURN_ALREADY_STARTED);
543 }
544
545 //
546 // allocate memory for new struct
547 //
548 Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));
549 ASSERT(Node != NULL);
550 Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);
551 ASSERT(Node->CommandString != NULL);
552
553 Node->GetManFileName = GetManFileName;
554 Node->CommandHandler = CommandHandler;
555 Node->LastError = CanAffectLE;
556 Node->HiiHandle = HiiHandle;
557 Node->ManFormatHelp = ManFormatHelp;
558
559 if ( StrLen(ProfileName)>0
560 && ((mProfileList != NULL
561 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)
562 ){
563 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));
564 if (mProfileList == NULL) {
565 //
566 // If this is the first make a leading ';'
567 //
568 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
569 }
570 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);
571 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
572 }
573
574 //
575 // Insert a new entry on top of the list
576 //
577 InsertHeadList (&mCommandList.Link, &Node->Link);
578
579 //
580 // Move a new registered command to its sorted ordered location in the list
581 //
582 for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),
583 PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
584 ; !IsNull (&mCommandList.Link, &Command->Link)
585 ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {
586
587 //
588 // Get Lexical Comparison Value between PrevCommand and Command list entry
589 //
590 LexicalMatchValue = gUnicodeCollation->StriColl (
591 gUnicodeCollation,
592 PrevCommand->CommandString,
593 Command->CommandString
594 );
595
596 //
597 // Swap PrevCommand and Command list entry if PrevCommand list entry
598 // is alphabetically greater than Command list entry
599 //
600 if (LexicalMatchValue > 0){
601 Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);
602 } else if (LexicalMatchValue < 0) {
603 //
604 // PrevCommand entry is lexically lower than Command entry
605 //
606 break;
607 }
608 }
609
610 return (RETURN_SUCCESS);
611 }
612
613 /**
614 Function to get the current Profile string.
615
616 @retval NULL There are no installed profiles.
617 @return A semi-colon delimited list of profiles.
618 **/
619 CONST CHAR16 *
620 EFIAPI
621 ShellCommandGetProfileList (
622 VOID
623 )
624 {
625 return (mProfileList);
626 }
627
628 /**
629 Checks if a command string has been registered for CommandString and if so it runs
630 the previously registered handler for that command with the command line.
631
632 If CommandString is NULL, then ASSERT().
633
634 If Sections is specified, then each section name listed will be compared in a casesensitive
635 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
636 it will be appended to the returned help text. If the section does not exist, no
637 information will be returned. If Sections is NULL, then all help text information
638 available will be returned.
639
640 @param[in] CommandString Pointer to the command name. This is the name
641 found on the command line in the shell.
642 @param[in, out] RetVal Pointer to the return vaule from the command handler.
643
644 @param[in, out] CanAffectLE indicates whether this command's return value
645 needs to be placed into LASTERROR environment variable.
646
647 @retval RETURN_SUCCESS The handler was run.
648 @retval RETURN_NOT_FOUND The CommandString did not match a registered
649 command name.
650 @sa SHELL_RUN_COMMAND
651 **/
652 RETURN_STATUS
653 EFIAPI
654 ShellCommandRunCommandHandler (
655 IN CONST CHAR16 *CommandString,
656 IN OUT SHELL_STATUS *RetVal,
657 IN OUT BOOLEAN *CanAffectLE OPTIONAL
658 )
659 {
660 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
661 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
662
663 //
664 // assert for NULL parameters
665 //
666 ASSERT(CommandString != NULL);
667
668 //
669 // check for the command
670 //
671 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
672 ; !IsNull(&mCommandList.Link, &Node->Link)
673 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
674 ){
675 ASSERT(Node->CommandString != NULL);
676 if (gUnicodeCollation->StriColl(
677 gUnicodeCollation,
678 (CHAR16*)CommandString,
679 Node->CommandString) == 0
680 ){
681 if (CanAffectLE != NULL) {
682 *CanAffectLE = Node->LastError;
683 }
684 if (RetVal != NULL) {
685 *RetVal = Node->CommandHandler(NULL, gST);
686 } else {
687 Node->CommandHandler(NULL, gST);
688 }
689 return (RETURN_SUCCESS);
690 }
691 }
692
693 //
694 // An internal command was not found, try to find a dynamic command
695 //
696 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);
697 if (DynamicCommand != NULL) {
698 if (RetVal != NULL) {
699 *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
700 } else {
701 DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
702 }
703 return (RETURN_SUCCESS);
704 }
705
706 return (RETURN_NOT_FOUND);
707 }
708
709 /**
710 Checks if a command string has been registered for CommandString and if so it
711 returns the MAN filename specified for that command.
712
713 If CommandString is NULL, then ASSERT().
714
715 @param[in] CommandString Pointer to the command name. This is the name
716 found on the command line in the shell.\
717
718 @retval NULL the commandString was not a registered command.
719 @return other the name of the MAN file.
720 @sa SHELL_GET_MAN_FILENAME
721 **/
722 CONST CHAR16*
723 EFIAPI
724 ShellCommandGetManFileNameHandler (
725 IN CONST CHAR16 *CommandString
726 )
727 {
728 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
729
730 //
731 // assert for NULL parameters
732 //
733 ASSERT(CommandString != NULL);
734
735 //
736 // check for the command
737 //
738 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
739 ; !IsNull(&mCommandList.Link, &Node->Link)
740 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
741 ){
742 ASSERT(Node->CommandString != NULL);
743 if (gUnicodeCollation->StriColl(
744 gUnicodeCollation,
745 (CHAR16*)CommandString,
746 Node->CommandString) == 0
747 ){
748 return (Node->GetManFileName());
749 }
750 }
751 return (NULL);
752 }
753
754 /**
755 Get the list of all available shell internal commands. This is a linked list
756 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
757 list functions. do not modify the values.
758
759 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
760
761 @return a Linked list of all available shell commands.
762 **/
763 CONST COMMAND_LIST*
764 EFIAPI
765 ShellCommandGetCommandList (
766 IN CONST BOOLEAN Sort
767 )
768 {
769 // if (!Sort) {
770 // return ((COMMAND_LIST*)(&mCommandList));
771 // }
772 return ((COMMAND_LIST*)(&mCommandList));
773 }
774
775 /**
776 Registers aliases to be set as part of the initialization of the shell application.
777
778 If Command is NULL, then ASSERT().
779 If Alias is NULL, then ASSERT().
780
781 @param[in] Command Pointer to the Command
782 @param[in] Alias Pointer to Alias
783
784 @retval RETURN_SUCCESS The handlers were registered.
785 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
786 register the shell command.
787 **/
788 RETURN_STATUS
789 EFIAPI
790 ShellCommandRegisterAlias (
791 IN CONST CHAR16 *Command,
792 IN CONST CHAR16 *Alias
793 )
794 {
795 ALIAS_LIST *Node;
796 ALIAS_LIST *CommandAlias;
797 ALIAS_LIST *PrevCommandAlias;
798 INTN LexicalMatchValue;
799
800 //
801 // Asserts for NULL
802 //
803 ASSERT(Command != NULL);
804 ASSERT(Alias != NULL);
805
806 //
807 // allocate memory for new struct
808 //
809 Node = AllocateZeroPool(sizeof(ALIAS_LIST));
810 ASSERT(Node != NULL);
811 Node->CommandString = AllocateCopyPool(StrSize(Command), Command);
812 Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);
813 ASSERT(Node->CommandString != NULL);
814 ASSERT(Node->Alias != NULL);
815
816 InsertHeadList (&mAliasList.Link, &Node->Link);
817
818 //
819 // Move a new pre-defined registered alias to its sorted ordered location in the list
820 //
821 for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),
822 PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)
823 ; !IsNull (&mAliasList.Link, &CommandAlias->Link)
824 ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {
825 //
826 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
827 //
828 LexicalMatchValue = gUnicodeCollation->StriColl (
829 gUnicodeCollation,
830 PrevCommandAlias->Alias,
831 CommandAlias->Alias
832 );
833
834 //
835 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
836 // is alphabetically greater than CommandAlias list entry
837 //
838 if (LexicalMatchValue > 0) {
839 CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);
840 } else if (LexicalMatchValue < 0) {
841 //
842 // PrevCommandAlias entry is lexically lower than CommandAlias entry
843 //
844 break;
845 }
846 }
847
848 return (RETURN_SUCCESS);
849 }
850
851 /**
852 Get the list of all shell alias commands. This is a linked list
853 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
854 list functions. do not modify the values.
855
856 @return a Linked list of all requested shell alias'.
857 **/
858 CONST ALIAS_LIST*
859 EFIAPI
860 ShellCommandGetInitAliasList (
861 VOID
862 )
863 {
864 return (&mAliasList);
865 }
866
867 /**
868 Determine if a given alias is on the list of built in alias'.
869
870 @param[in] Alias The alias to test for
871
872 @retval TRUE The alias is a built in alias
873 @retval FALSE The alias is not a built in alias
874 **/
875 BOOLEAN
876 EFIAPI
877 ShellCommandIsOnAliasList(
878 IN CONST CHAR16 *Alias
879 )
880 {
881 ALIAS_LIST *Node;
882
883 //
884 // assert for NULL parameter
885 //
886 ASSERT(Alias != NULL);
887
888 //
889 // check for the Alias
890 //
891 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)
892 ; !IsNull(&mAliasList.Link, &Node->Link)
893 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)
894 ){
895 ASSERT(Node->CommandString != NULL);
896 ASSERT(Node->Alias != NULL);
897 if (gUnicodeCollation->StriColl(
898 gUnicodeCollation,
899 (CHAR16*)Alias,
900 Node->CommandString) == 0
901 ){
902 return (TRUE);
903 }
904 if (gUnicodeCollation->StriColl(
905 gUnicodeCollation,
906 (CHAR16*)Alias,
907 Node->Alias) == 0
908 ){
909 return (TRUE);
910 }
911 }
912 return (FALSE);
913 }
914
915 /**
916 Function to determine current state of ECHO. Echo determines if lines from scripts
917 and ECHO commands are enabled.
918
919 @retval TRUE Echo is currently enabled
920 @retval FALSE Echo is currently disabled
921 **/
922 BOOLEAN
923 EFIAPI
924 ShellCommandGetEchoState(
925 VOID
926 )
927 {
928 return (mEchoState);
929 }
930
931 /**
932 Function to set current state of ECHO. Echo determines if lines from scripts
933 and ECHO commands are enabled.
934
935 If State is TRUE, Echo will be enabled.
936 If State is FALSE, Echo will be disabled.
937
938 @param[in] State How to set echo.
939 **/
940 VOID
941 EFIAPI
942 ShellCommandSetEchoState(
943 IN BOOLEAN State
944 )
945 {
946 mEchoState = State;
947 }
948
949 /**
950 Indicate that the current shell or script should exit.
951
952 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
953 @param[in] ErrorCode The 64 bit error code to return.
954 **/
955 VOID
956 EFIAPI
957 ShellCommandRegisterExit (
958 IN BOOLEAN ScriptOnly,
959 IN CONST UINT64 ErrorCode
960 )
961 {
962 mExitRequested = (BOOLEAN)(!mExitRequested);
963 if (mExitRequested) {
964 mExitScript = ScriptOnly;
965 } else {
966 mExitScript = FALSE;
967 }
968 mExitCode = ErrorCode;
969 }
970
971 /**
972 Retrieve the Exit indicator.
973
974 @retval TRUE Exit was indicated.
975 @retval FALSE Exis was not indicated.
976 **/
977 BOOLEAN
978 EFIAPI
979 ShellCommandGetExit (
980 VOID
981 )
982 {
983 return (mExitRequested);
984 }
985
986 /**
987 Retrieve the Exit code.
988
989 If ShellCommandGetExit returns FALSE than the return from this is undefined.
990
991 @return the value passed into RegisterExit.
992 **/
993 UINT64
994 EFIAPI
995 ShellCommandGetExitCode (
996 VOID
997 )
998 {
999 return (mExitCode);
1000 }
1001 /**
1002 Retrieve the Exit script indicator.
1003
1004 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1005
1006 @retval TRUE ScriptOnly was indicated.
1007 @retval FALSE ScriptOnly was not indicated.
1008 **/
1009 BOOLEAN
1010 EFIAPI
1011 ShellCommandGetScriptExit (
1012 VOID
1013 )
1014 {
1015 return (mExitScript);
1016 }
1017
1018 /**
1019 Function to cleanup all memory from a SCRIPT_FILE structure.
1020
1021 @param[in] Script The pointer to the structure to cleanup.
1022 **/
1023 VOID
1024 EFIAPI
1025 DeleteScriptFileStruct (
1026 IN SCRIPT_FILE *Script
1027 )
1028 {
1029 UINT8 LoopVar;
1030
1031 if (Script == NULL) {
1032 return;
1033 }
1034
1035 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {
1036 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);
1037 }
1038 if (Script->Argv != NULL) {
1039 SHELL_FREE_NON_NULL(Script->Argv);
1040 }
1041 Script->CurrentCommand = NULL;
1042 while (!IsListEmpty (&Script->CommandList)) {
1043 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);
1044 if (Script->CurrentCommand != NULL) {
1045 RemoveEntryList(&Script->CurrentCommand->Link);
1046 if (Script->CurrentCommand->Cl != NULL) {
1047 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);
1048 }
1049 if (Script->CurrentCommand->Data != NULL) {
1050 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);
1051 }
1052 SHELL_FREE_NON_NULL(Script->CurrentCommand);
1053 }
1054 }
1055 SHELL_FREE_NON_NULL(Script->ScriptName);
1056 SHELL_FREE_NON_NULL(Script);
1057 }
1058
1059 /**
1060 Function to return a pointer to the currently running script file object.
1061
1062 @retval NULL A script file is not currently running.
1063 @return A pointer to the current script file object.
1064 **/
1065 SCRIPT_FILE*
1066 EFIAPI
1067 ShellCommandGetCurrentScriptFile (
1068 VOID
1069 )
1070 {
1071 SCRIPT_FILE_LIST *List;
1072 if (IsListEmpty (&mScriptList.Link)) {
1073 return (NULL);
1074 }
1075 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));
1076 return (List->Data);
1077 }
1078
1079 /**
1080 Function to set a new script as the currently running one.
1081
1082 This function will correctly stack and unstack nested scripts.
1083
1084 @param[in] Script Pointer to new script information structure. if NULL
1085 will remove and de-allocate the top-most Script structure.
1086
1087 @return A pointer to the current running script file after this
1088 change. NULL if removing the final script.
1089 **/
1090 SCRIPT_FILE*
1091 EFIAPI
1092 ShellCommandSetNewScript (
1093 IN SCRIPT_FILE *Script OPTIONAL
1094 )
1095 {
1096 SCRIPT_FILE_LIST *Node;
1097 if (Script == NULL) {
1098 if (IsListEmpty (&mScriptList.Link)) {
1099 return (NULL);
1100 }
1101 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
1102 RemoveEntryList(&Node->Link);
1103 DeleteScriptFileStruct(Node->Data);
1104 FreePool(Node);
1105 } else {
1106 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));
1107 if (Node == NULL) {
1108 return (NULL);
1109 }
1110 Node->Data = Script;
1111 InsertHeadList(&mScriptList.Link, &Node->Link);
1112 }
1113 return (ShellCommandGetCurrentScriptFile());
1114 }
1115
1116 /**
1117 Function to generate the next default mapping name.
1118
1119 If the return value is not NULL then it must be callee freed.
1120
1121 @param Type What kind of mapping name to make.
1122
1123 @retval NULL a memory allocation failed.
1124 @return a new map name string
1125 **/
1126 CHAR16*
1127 EFIAPI
1128 ShellCommandCreateNewMappingName(
1129 IN CONST SHELL_MAPPING_TYPE Type
1130 )
1131 {
1132 CHAR16 *String;
1133 ASSERT(Type < MappingTypeMax);
1134
1135 String = NULL;
1136
1137 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));
1138 UnicodeSPrint(
1139 String,
1140 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),
1141 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",
1142 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);
1143
1144 return (String);
1145 }
1146
1147 /**
1148 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
1149
1150 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
1151 default paths on the new map name...
1152
1153 Path should be FALSE when this function is called from the protocol SetMap function.
1154
1155 @param[in] Name The human readable mapped name.
1156 @param[in] DevicePath The Device Path for this map.
1157 @param[in] Flags The Flags attribute for this map item.
1158 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
1159
1160 @retval EFI_SUCCESS The addition was sucessful.
1161 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1162 @retval EFI_INVALID_PARAMETER A parameter was invalid.
1163 **/
1164 EFI_STATUS
1165 EFIAPI
1166 ShellCommandAddMapItemAndUpdatePath(
1167 IN CONST CHAR16 *Name,
1168 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1169 IN CONST UINT64 Flags,
1170 IN CONST BOOLEAN Path
1171 )
1172 {
1173 EFI_STATUS Status;
1174 SHELL_MAP_LIST *MapListNode;
1175 CONST CHAR16 *OriginalPath;
1176 CHAR16 *NewPath;
1177 UINTN NewPathSize;
1178
1179 NewPathSize = 0;
1180 NewPath = NULL;
1181 OriginalPath = NULL;
1182 Status = EFI_SUCCESS;
1183
1184 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));
1185 if (MapListNode == NULL) {
1186 Status = EFI_OUT_OF_RESOURCES;
1187 } else {
1188 MapListNode->Flags = Flags;
1189 MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);
1190 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);
1191 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){
1192 Status = EFI_OUT_OF_RESOURCES;
1193 } else {
1194 InsertTailList(&gShellMapList.Link, &MapListNode->Link);
1195 }
1196 }
1197 if (EFI_ERROR(Status)) {
1198 if (MapListNode != NULL) {
1199 if (MapListNode->DevicePath != NULL) {
1200 FreePool(MapListNode->DevicePath);
1201 }
1202 if (MapListNode->MapName != NULL) {
1203 FreePool(MapListNode->MapName);
1204 }
1205 FreePool(MapListNode);
1206 }
1207 } else if (Path) {
1208 //
1209 // Since there was no error and Path was TRUE
1210 // Now add the correct path for that mapping
1211 //
1212 OriginalPath = gEfiShellProtocol->GetEnv(L"path");
1213 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));
1214 if (OriginalPath != NULL) {
1215 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);
1216 } else {
1217 StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);
1218 }
1219 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);
1220 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1221 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
1222 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1223 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
1224 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1225 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);
1226
1227 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);
1228 ASSERT_EFI_ERROR(Status);
1229 FreePool(NewPath);
1230 }
1231 return (Status);
1232 }
1233
1234 /**
1235 Creates the default map names for each device path in the system with
1236 a protocol depending on the Type.
1237
1238 Creates the consistent map names for each device path in the system with
1239 a protocol depending on the Type.
1240
1241 Note: This will reset all mappings in the system("map -r").
1242
1243 Also sets up the default path environment variable if Type is FileSystem.
1244
1245 @retval EFI_SUCCESS All map names were created sucessfully.
1246 @retval EFI_NOT_FOUND No protocols were found in the system.
1247 @return Error returned from gBS->LocateHandle().
1248
1249 @sa LocateHandle
1250 **/
1251 EFI_STATUS
1252 EFIAPI
1253 ShellCommandCreateInitialMappingsAndPaths(
1254 VOID
1255 )
1256 {
1257 EFI_STATUS Status;
1258 EFI_HANDLE *HandleList;
1259 UINTN Count;
1260 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1261 CHAR16 *NewDefaultName;
1262 CHAR16 *NewConsistName;
1263 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1264 SHELL_MAP_LIST *MapListNode;
1265
1266 HandleList = NULL;
1267
1268 //
1269 // Reset the static members back to zero
1270 //
1271 mFsMaxCount = 0;
1272 mBlkMaxCount = 0;
1273
1274 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);
1275
1276 //
1277 // First empty out the existing list.
1278 //
1279 if (!IsListEmpty(&gShellMapList.Link)) {
1280 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1281 ; !IsListEmpty(&gShellMapList.Link)
1282 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1283 ){
1284 RemoveEntryList(&MapListNode->Link);
1285 SHELL_FREE_NON_NULL(MapListNode->DevicePath);
1286 SHELL_FREE_NON_NULL(MapListNode->MapName);
1287 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);
1288 FreePool(MapListNode);
1289 } // for loop
1290 }
1291
1292 //
1293 // Find each handle with Simple File System
1294 //
1295 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1296 if (HandleList != NULL) {
1297 //
1298 // Do a count of the handles
1299 //
1300 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1301
1302 //
1303 // Get all Device Paths
1304 //
1305 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1306 ASSERT(DevicePathList != NULL);
1307
1308 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1309 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1310 }
1311
1312 //
1313 // Sort all DevicePaths
1314 //
1315 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1316
1317 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1318 //
1319 // Assign new Mappings to all...
1320 //
1321 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1322 //
1323 // Get default name first
1324 //
1325 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1326 ASSERT(NewDefaultName != NULL);
1327 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);
1328 ASSERT_EFI_ERROR(Status);
1329 FreePool(NewDefaultName);
1330
1331 //
1332 // Now do consistent name
1333 //
1334 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1335 if (NewConsistName != NULL) {
1336 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);
1337 ASSERT_EFI_ERROR(Status);
1338 FreePool(NewConsistName);
1339 }
1340 }
1341
1342 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1343
1344 SHELL_FREE_NON_NULL(HandleList);
1345 SHELL_FREE_NON_NULL(DevicePathList);
1346
1347 HandleList = NULL;
1348 } else {
1349 Count = (UINTN)-1;
1350 }
1351
1352 //
1353 // Find each handle with Block Io
1354 //
1355 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);
1356 if (HandleList != NULL) {
1357 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1358
1359 //
1360 // Get all Device Paths
1361 //
1362 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1363 ASSERT(DevicePathList != NULL);
1364
1365 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1366 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1367 }
1368
1369 //
1370 // Sort all DevicePaths
1371 //
1372 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1373
1374 //
1375 // Assign new Mappings to all...
1376 //
1377 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1378 //
1379 // Get default name first
1380 //
1381 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);
1382 ASSERT(NewDefaultName != NULL);
1383 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);
1384 ASSERT_EFI_ERROR(Status);
1385 FreePool(NewDefaultName);
1386 }
1387
1388 SHELL_FREE_NON_NULL(HandleList);
1389 SHELL_FREE_NON_NULL(DevicePathList);
1390 } else if (Count == (UINTN)-1) {
1391 return (EFI_NOT_FOUND);
1392 }
1393
1394 return (EFI_SUCCESS);
1395 }
1396
1397 /**
1398 Add mappings for any devices without one. Do not change any existing maps.
1399
1400 @retval EFI_SUCCESS The operation was successful.
1401 **/
1402 EFI_STATUS
1403 EFIAPI
1404 ShellCommandUpdateMapping (
1405 VOID
1406 )
1407 {
1408 EFI_STATUS Status;
1409 EFI_HANDLE *HandleList;
1410 UINTN Count;
1411 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1412 CHAR16 *NewDefaultName;
1413 CHAR16 *NewConsistName;
1414 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1415
1416 HandleList = NULL;
1417 Status = EFI_SUCCESS;
1418
1419 //
1420 // remove mappings that represent removed devices.
1421 //
1422
1423 //
1424 // Find each handle with Simple File System
1425 //
1426 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1427 if (HandleList != NULL) {
1428 //
1429 // Do a count of the handles
1430 //
1431 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1432
1433 //
1434 // Get all Device Paths
1435 //
1436 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1437 if (DevicePathList == NULL) {
1438 return (EFI_OUT_OF_RESOURCES);
1439 }
1440
1441 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1442 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1443 }
1444
1445 //
1446 // Sort all DevicePaths
1447 //
1448 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1449
1450 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1451
1452 //
1453 // Assign new Mappings to remainders
1454 //
1455 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {
1456 //
1457 // Skip ones that already have
1458 //
1459 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {
1460 continue;
1461 }
1462 //
1463 // Get default name
1464 //
1465 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1466 if (NewDefaultName == NULL) {
1467 Status = EFI_OUT_OF_RESOURCES;
1468 break;
1469 }
1470
1471 //
1472 // Call shell protocol SetMap function now...
1473 //
1474 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);
1475
1476 if (!EFI_ERROR(Status)) {
1477 //
1478 // Now do consistent name
1479 //
1480 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1481 if (NewConsistName != NULL) {
1482 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);
1483 FreePool(NewConsistName);
1484 }
1485 }
1486
1487 FreePool(NewDefaultName);
1488 }
1489 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1490 SHELL_FREE_NON_NULL(HandleList);
1491 SHELL_FREE_NON_NULL(DevicePathList);
1492
1493 HandleList = NULL;
1494 } else {
1495 Count = (UINTN)-1;
1496 }
1497 //
1498 // Do it all over again for gEfiBlockIoProtocolGuid
1499 //
1500
1501 return (Status);
1502 }
1503
1504 /**
1505 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1506
1507 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1508
1509 @return a EFI_FILE_PROTOCOL* representing the same file.
1510 **/
1511 EFI_FILE_PROTOCOL*
1512 EFIAPI
1513 ConvertShellHandleToEfiFileProtocol(
1514 IN CONST SHELL_FILE_HANDLE Handle
1515 )
1516 {
1517 return ((EFI_FILE_PROTOCOL*)(Handle));
1518 }
1519
1520 /**
1521 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1522
1523 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1524 @param[in] Path The path to the file for verification.
1525
1526 @return A SHELL_FILE_HANDLE representing the same file.
1527 @retval NULL There was not enough memory.
1528 **/
1529 SHELL_FILE_HANDLE
1530 EFIAPI
1531 ConvertEfiFileProtocolToShellHandle(
1532 IN CONST EFI_FILE_PROTOCOL *Handle,
1533 IN CONST CHAR16 *Path
1534 )
1535 {
1536 SHELL_COMMAND_FILE_HANDLE *Buffer;
1537 BUFFER_LIST *NewNode;
1538
1539 if (Path != NULL) {
1540 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));
1541 if (Buffer == NULL) {
1542 return (NULL);
1543 }
1544 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));
1545 if (NewNode == NULL) {
1546 SHELL_FREE_NON_NULL(Buffer);
1547 return (NULL);
1548 }
1549 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;
1550 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);
1551 if (Buffer->Path == NULL) {
1552 SHELL_FREE_NON_NULL(NewNode);
1553 SHELL_FREE_NON_NULL(Buffer);
1554 return (NULL);
1555 }
1556 NewNode->Buffer = Buffer;
1557
1558 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);
1559 }
1560 return ((SHELL_FILE_HANDLE)(Handle));
1561 }
1562
1563 /**
1564 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1565
1566 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1567
1568 @return A pointer to the path for the file.
1569 **/
1570 CONST CHAR16*
1571 EFIAPI
1572 ShellFileHandleGetPath(
1573 IN CONST SHELL_FILE_HANDLE Handle
1574 )
1575 {
1576 BUFFER_LIST *Node;
1577
1578 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1579 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1580 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1581 ){
1582 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1583 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1584 }
1585 }
1586 return (NULL);
1587 }
1588
1589 /**
1590 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1591
1592 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1593
1594 @retval TRUE The item was removed.
1595 @retval FALSE The item was not found.
1596 **/
1597 BOOLEAN
1598 EFIAPI
1599 ShellFileHandleRemove(
1600 IN CONST SHELL_FILE_HANDLE Handle
1601 )
1602 {
1603 BUFFER_LIST *Node;
1604
1605 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1606 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1607 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1608 ){
1609 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1610 RemoveEntryList(&Node->Link);
1611 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1612 SHELL_FREE_NON_NULL(Node->Buffer);
1613 SHELL_FREE_NON_NULL(Node);
1614 return (TRUE);
1615 }
1616 }
1617 return (FALSE);
1618 }
1619
1620 /**
1621 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1622
1623 This will NOT work on directories.
1624
1625 If Handle is NULL, then ASSERT.
1626
1627 @param[in] Handle the file handle
1628
1629 @retval TRUE the position is at the end of the file
1630 @retval FALSE the position is not at the end of the file
1631 **/
1632 BOOLEAN
1633 EFIAPI
1634 ShellFileHandleEof(
1635 IN SHELL_FILE_HANDLE Handle
1636 )
1637 {
1638 EFI_FILE_INFO *Info;
1639 UINT64 Pos;
1640 BOOLEAN RetVal;
1641
1642 //
1643 // ASSERT if Handle is NULL
1644 //
1645 ASSERT(Handle != NULL);
1646
1647 gEfiShellProtocol->GetFilePosition(Handle, &Pos);
1648 Info = gEfiShellProtocol->GetFileInfo (Handle);
1649 gEfiShellProtocol->SetFilePosition(Handle, Pos);
1650
1651 if (Info == NULL) {
1652 return (FALSE);
1653 }
1654
1655 if (Pos == Info->FileSize) {
1656 RetVal = TRUE;
1657 } else {
1658 RetVal = FALSE;
1659 }
1660
1661 FreePool (Info);
1662
1663 return (RetVal);
1664 }
1665
1666 /**
1667 Frees any BUFFER_LIST defined type.
1668
1669 @param[in] List The BUFFER_LIST object to free.
1670 **/
1671 VOID
1672 EFIAPI
1673 FreeBufferList (
1674 IN BUFFER_LIST *List
1675 )
1676 {
1677 BUFFER_LIST *BufferListEntry;
1678
1679 if (List == NULL){
1680 return;
1681 }
1682 //
1683 // enumerate through the buffer list and free all memory
1684 //
1685 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
1686 ; !IsListEmpty (&List->Link)
1687 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
1688 ){
1689 RemoveEntryList(&BufferListEntry->Link);
1690 if (BufferListEntry->Buffer != NULL) {
1691 FreePool(BufferListEntry->Buffer);
1692 }
1693 FreePool(BufferListEntry);
1694 }
1695 }
1696
1697 /**
1698 Dump some hexadecimal data to the screen.
1699
1700 @param[in] Indent How many spaces to indent the output.
1701 @param[in] Offset The offset of the printing.
1702 @param[in] DataSize The size in bytes of UserData.
1703 @param[in] UserData The data to print out.
1704 **/
1705 VOID
1706 DumpHex (
1707 IN UINTN Indent,
1708 IN UINTN Offset,
1709 IN UINTN DataSize,
1710 IN VOID *UserData
1711 )
1712 {
1713 UINT8 *Data;
1714
1715 CHAR8 Val[50];
1716
1717 CHAR8 Str[20];
1718
1719 UINT8 TempByte;
1720 UINTN Size;
1721 UINTN Index;
1722
1723 Data = UserData;
1724 while (DataSize != 0) {
1725 Size = 16;
1726 if (Size > DataSize) {
1727 Size = DataSize;
1728 }
1729
1730 for (Index = 0; Index < Size; Index += 1) {
1731 TempByte = Data[Index];
1732 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1733 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1734 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1735 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1736 }
1737
1738 Val[Index * 3] = 0;
1739 Str[Index] = 0;
1740 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1741
1742 Data += Size;
1743 Offset += Size;
1744 DataSize -= Size;
1745 }
1746 }
1747
1748 /**
1749 Dump HEX data into buffer.
1750
1751 @param[in] Buffer HEX data to be dumped in Buffer.
1752 @param[in] Indent How many spaces to indent the output.
1753 @param[in] Offset The offset of the printing.
1754 @param[in] DataSize The size in bytes of UserData.
1755 @param[in] UserData The data to print out.
1756 **/
1757 CHAR16*
1758 CatSDumpHex (
1759 IN CHAR16 *Buffer,
1760 IN UINTN Indent,
1761 IN UINTN Offset,
1762 IN UINTN DataSize,
1763 IN VOID *UserData
1764 )
1765 {
1766 UINT8 *Data;
1767 UINT8 TempByte;
1768 UINTN Size;
1769 UINTN Index;
1770 CHAR8 Val[50];
1771 CHAR8 Str[20];
1772 CHAR16 *RetVal;
1773 CHAR16 *TempRetVal;
1774
1775 Data = UserData;
1776 RetVal = Buffer;
1777 while (DataSize != 0) {
1778 Size = 16;
1779 if (Size > DataSize) {
1780 Size = DataSize;
1781 }
1782
1783 for (Index = 0; Index < Size; Index += 1) {
1784 TempByte = Data[Index];
1785 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1786 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1787 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1788 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1789 }
1790
1791 Val[Index * 3] = 0;
1792 Str[Index] = 0;
1793 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1794 SHELL_FREE_NON_NULL (RetVal);
1795 RetVal = TempRetVal;
1796
1797 Data += Size;
1798 Offset += Size;
1799 DataSize -= Size;
1800 }
1801
1802 return RetVal;
1803 }