]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg/UefiShellLevel1CommandsLib: Remove unnecessary EFIAPI
[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 if (Node == NULL) {
550 return RETURN_OUT_OF_RESOURCES;
551 }
552 Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);
553 if (Node->CommandString == NULL) {
554 FreePool (Node);
555 return RETURN_OUT_OF_RESOURCES;
556 }
557
558 Node->GetManFileName = GetManFileName;
559 Node->CommandHandler = CommandHandler;
560 Node->LastError = CanAffectLE;
561 Node->HiiHandle = HiiHandle;
562 Node->ManFormatHelp = ManFormatHelp;
563
564 if ( StrLen(ProfileName)>0
565 && ((mProfileList != NULL
566 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)
567 ){
568 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));
569 if (mProfileList == NULL) {
570 //
571 // If this is the first make a leading ';'
572 //
573 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
574 }
575 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);
576 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
577 }
578
579 //
580 // Insert a new entry on top of the list
581 //
582 InsertHeadList (&mCommandList.Link, &Node->Link);
583
584 //
585 // Move a new registered command to its sorted ordered location in the list
586 //
587 for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),
588 PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
589 ; !IsNull (&mCommandList.Link, &Command->Link)
590 ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {
591
592 //
593 // Get Lexical Comparison Value between PrevCommand and Command list entry
594 //
595 LexicalMatchValue = gUnicodeCollation->StriColl (
596 gUnicodeCollation,
597 PrevCommand->CommandString,
598 Command->CommandString
599 );
600
601 //
602 // Swap PrevCommand and Command list entry if PrevCommand list entry
603 // is alphabetically greater than Command list entry
604 //
605 if (LexicalMatchValue > 0){
606 Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);
607 } else if (LexicalMatchValue < 0) {
608 //
609 // PrevCommand entry is lexically lower than Command entry
610 //
611 break;
612 }
613 }
614
615 return (RETURN_SUCCESS);
616 }
617
618 /**
619 Function to get the current Profile string.
620
621 @retval NULL There are no installed profiles.
622 @return A semi-colon delimited list of profiles.
623 **/
624 CONST CHAR16 *
625 EFIAPI
626 ShellCommandGetProfileList (
627 VOID
628 )
629 {
630 return (mProfileList);
631 }
632
633 /**
634 Checks if a command string has been registered for CommandString and if so it runs
635 the previously registered handler for that command with the command line.
636
637 If CommandString is NULL, then ASSERT().
638
639 If Sections is specified, then each section name listed will be compared in a casesensitive
640 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
641 it will be appended to the returned help text. If the section does not exist, no
642 information will be returned. If Sections is NULL, then all help text information
643 available will be returned.
644
645 @param[in] CommandString Pointer to the command name. This is the name
646 found on the command line in the shell.
647 @param[in, out] RetVal Pointer to the return vaule from the command handler.
648
649 @param[in, out] CanAffectLE indicates whether this command's return value
650 needs to be placed into LASTERROR environment variable.
651
652 @retval RETURN_SUCCESS The handler was run.
653 @retval RETURN_NOT_FOUND The CommandString did not match a registered
654 command name.
655 @sa SHELL_RUN_COMMAND
656 **/
657 RETURN_STATUS
658 EFIAPI
659 ShellCommandRunCommandHandler (
660 IN CONST CHAR16 *CommandString,
661 IN OUT SHELL_STATUS *RetVal,
662 IN OUT BOOLEAN *CanAffectLE OPTIONAL
663 )
664 {
665 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
666 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
667
668 //
669 // assert for NULL parameters
670 //
671 ASSERT(CommandString != NULL);
672
673 //
674 // check for the command
675 //
676 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
677 ; !IsNull(&mCommandList.Link, &Node->Link)
678 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
679 ){
680 ASSERT(Node->CommandString != NULL);
681 if (gUnicodeCollation->StriColl(
682 gUnicodeCollation,
683 (CHAR16*)CommandString,
684 Node->CommandString) == 0
685 ){
686 if (CanAffectLE != NULL) {
687 *CanAffectLE = Node->LastError;
688 }
689 if (RetVal != NULL) {
690 *RetVal = Node->CommandHandler(NULL, gST);
691 } else {
692 Node->CommandHandler(NULL, gST);
693 }
694 return (RETURN_SUCCESS);
695 }
696 }
697
698 //
699 // An internal command was not found, try to find a dynamic command
700 //
701 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);
702 if (DynamicCommand != NULL) {
703 if (RetVal != NULL) {
704 *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
705 } else {
706 DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
707 }
708 return (RETURN_SUCCESS);
709 }
710
711 return (RETURN_NOT_FOUND);
712 }
713
714 /**
715 Checks if a command string has been registered for CommandString and if so it
716 returns the MAN filename specified for that command.
717
718 If CommandString is NULL, then ASSERT().
719
720 @param[in] CommandString Pointer to the command name. This is the name
721 found on the command line in the shell.\
722
723 @retval NULL the commandString was not a registered command.
724 @return other the name of the MAN file.
725 @sa SHELL_GET_MAN_FILENAME
726 **/
727 CONST CHAR16*
728 EFIAPI
729 ShellCommandGetManFileNameHandler (
730 IN CONST CHAR16 *CommandString
731 )
732 {
733 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
734
735 //
736 // assert for NULL parameters
737 //
738 ASSERT(CommandString != NULL);
739
740 //
741 // check for the command
742 //
743 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
744 ; !IsNull(&mCommandList.Link, &Node->Link)
745 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
746 ){
747 ASSERT(Node->CommandString != NULL);
748 if (gUnicodeCollation->StriColl(
749 gUnicodeCollation,
750 (CHAR16*)CommandString,
751 Node->CommandString) == 0
752 ){
753 return (Node->GetManFileName());
754 }
755 }
756 return (NULL);
757 }
758
759 /**
760 Get the list of all available shell internal commands. This is a linked list
761 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
762 list functions. do not modify the values.
763
764 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
765
766 @return a Linked list of all available shell commands.
767 **/
768 CONST COMMAND_LIST*
769 EFIAPI
770 ShellCommandGetCommandList (
771 IN CONST BOOLEAN Sort
772 )
773 {
774 // if (!Sort) {
775 // return ((COMMAND_LIST*)(&mCommandList));
776 // }
777 return ((COMMAND_LIST*)(&mCommandList));
778 }
779
780 /**
781 Registers aliases to be set as part of the initialization of the shell application.
782
783 If Command is NULL, then ASSERT().
784 If Alias is NULL, then ASSERT().
785
786 @param[in] Command Pointer to the Command
787 @param[in] Alias Pointer to Alias
788
789 @retval RETURN_SUCCESS The handlers were registered.
790 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
791 register the shell command.
792 **/
793 RETURN_STATUS
794 EFIAPI
795 ShellCommandRegisterAlias (
796 IN CONST CHAR16 *Command,
797 IN CONST CHAR16 *Alias
798 )
799 {
800 ALIAS_LIST *Node;
801 ALIAS_LIST *CommandAlias;
802 ALIAS_LIST *PrevCommandAlias;
803 INTN LexicalMatchValue;
804
805 //
806 // Asserts for NULL
807 //
808 ASSERT(Command != NULL);
809 ASSERT(Alias != NULL);
810
811 //
812 // allocate memory for new struct
813 //
814 Node = AllocateZeroPool(sizeof(ALIAS_LIST));
815 if (Node == NULL) {
816 return RETURN_OUT_OF_RESOURCES;
817 }
818 Node->CommandString = AllocateCopyPool(StrSize(Command), Command);
819 if (Node->CommandString == NULL) {
820 FreePool (Node);
821 return RETURN_OUT_OF_RESOURCES;
822 }
823 Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);
824 if (Node->Alias == NULL) {
825 FreePool (Node->CommandString);
826 FreePool (Node);
827 return RETURN_OUT_OF_RESOURCES;
828 }
829
830 InsertHeadList (&mAliasList.Link, &Node->Link);
831
832 //
833 // Move a new pre-defined registered alias to its sorted ordered location in the list
834 //
835 for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),
836 PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)
837 ; !IsNull (&mAliasList.Link, &CommandAlias->Link)
838 ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {
839 //
840 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
841 //
842 LexicalMatchValue = gUnicodeCollation->StriColl (
843 gUnicodeCollation,
844 PrevCommandAlias->Alias,
845 CommandAlias->Alias
846 );
847
848 //
849 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
850 // is alphabetically greater than CommandAlias list entry
851 //
852 if (LexicalMatchValue > 0) {
853 CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);
854 } else if (LexicalMatchValue < 0) {
855 //
856 // PrevCommandAlias entry is lexically lower than CommandAlias entry
857 //
858 break;
859 }
860 }
861
862 return (RETURN_SUCCESS);
863 }
864
865 /**
866 Get the list of all shell alias commands. This is a linked list
867 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
868 list functions. do not modify the values.
869
870 @return a Linked list of all requested shell alias'.
871 **/
872 CONST ALIAS_LIST*
873 EFIAPI
874 ShellCommandGetInitAliasList (
875 VOID
876 )
877 {
878 return (&mAliasList);
879 }
880
881 /**
882 Determine if a given alias is on the list of built in alias'.
883
884 @param[in] Alias The alias to test for
885
886 @retval TRUE The alias is a built in alias
887 @retval FALSE The alias is not a built in alias
888 **/
889 BOOLEAN
890 EFIAPI
891 ShellCommandIsOnAliasList(
892 IN CONST CHAR16 *Alias
893 )
894 {
895 ALIAS_LIST *Node;
896
897 //
898 // assert for NULL parameter
899 //
900 ASSERT(Alias != NULL);
901
902 //
903 // check for the Alias
904 //
905 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)
906 ; !IsNull(&mAliasList.Link, &Node->Link)
907 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)
908 ){
909 ASSERT(Node->CommandString != NULL);
910 ASSERT(Node->Alias != NULL);
911 if (gUnicodeCollation->StriColl(
912 gUnicodeCollation,
913 (CHAR16*)Alias,
914 Node->CommandString) == 0
915 ){
916 return (TRUE);
917 }
918 if (gUnicodeCollation->StriColl(
919 gUnicodeCollation,
920 (CHAR16*)Alias,
921 Node->Alias) == 0
922 ){
923 return (TRUE);
924 }
925 }
926 return (FALSE);
927 }
928
929 /**
930 Function to determine current state of ECHO. Echo determines if lines from scripts
931 and ECHO commands are enabled.
932
933 @retval TRUE Echo is currently enabled
934 @retval FALSE Echo is currently disabled
935 **/
936 BOOLEAN
937 EFIAPI
938 ShellCommandGetEchoState(
939 VOID
940 )
941 {
942 return (mEchoState);
943 }
944
945 /**
946 Function to set current state of ECHO. Echo determines if lines from scripts
947 and ECHO commands are enabled.
948
949 If State is TRUE, Echo will be enabled.
950 If State is FALSE, Echo will be disabled.
951
952 @param[in] State How to set echo.
953 **/
954 VOID
955 EFIAPI
956 ShellCommandSetEchoState(
957 IN BOOLEAN State
958 )
959 {
960 mEchoState = State;
961 }
962
963 /**
964 Indicate that the current shell or script should exit.
965
966 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
967 @param[in] ErrorCode The 64 bit error code to return.
968 **/
969 VOID
970 EFIAPI
971 ShellCommandRegisterExit (
972 IN BOOLEAN ScriptOnly,
973 IN CONST UINT64 ErrorCode
974 )
975 {
976 mExitRequested = (BOOLEAN)(!mExitRequested);
977 if (mExitRequested) {
978 mExitScript = ScriptOnly;
979 } else {
980 mExitScript = FALSE;
981 }
982 mExitCode = ErrorCode;
983 }
984
985 /**
986 Retrieve the Exit indicator.
987
988 @retval TRUE Exit was indicated.
989 @retval FALSE Exis was not indicated.
990 **/
991 BOOLEAN
992 EFIAPI
993 ShellCommandGetExit (
994 VOID
995 )
996 {
997 return (mExitRequested);
998 }
999
1000 /**
1001 Retrieve the Exit code.
1002
1003 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1004
1005 @return the value passed into RegisterExit.
1006 **/
1007 UINT64
1008 EFIAPI
1009 ShellCommandGetExitCode (
1010 VOID
1011 )
1012 {
1013 return (mExitCode);
1014 }
1015 /**
1016 Retrieve the Exit script indicator.
1017
1018 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1019
1020 @retval TRUE ScriptOnly was indicated.
1021 @retval FALSE ScriptOnly was not indicated.
1022 **/
1023 BOOLEAN
1024 EFIAPI
1025 ShellCommandGetScriptExit (
1026 VOID
1027 )
1028 {
1029 return (mExitScript);
1030 }
1031
1032 /**
1033 Function to cleanup all memory from a SCRIPT_FILE structure.
1034
1035 @param[in] Script The pointer to the structure to cleanup.
1036 **/
1037 VOID
1038 EFIAPI
1039 DeleteScriptFileStruct (
1040 IN SCRIPT_FILE *Script
1041 )
1042 {
1043 UINT8 LoopVar;
1044
1045 if (Script == NULL) {
1046 return;
1047 }
1048
1049 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {
1050 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);
1051 }
1052 if (Script->Argv != NULL) {
1053 SHELL_FREE_NON_NULL(Script->Argv);
1054 }
1055 Script->CurrentCommand = NULL;
1056 while (!IsListEmpty (&Script->CommandList)) {
1057 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);
1058 if (Script->CurrentCommand != NULL) {
1059 RemoveEntryList(&Script->CurrentCommand->Link);
1060 if (Script->CurrentCommand->Cl != NULL) {
1061 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);
1062 }
1063 if (Script->CurrentCommand->Data != NULL) {
1064 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);
1065 }
1066 SHELL_FREE_NON_NULL(Script->CurrentCommand);
1067 }
1068 }
1069 SHELL_FREE_NON_NULL(Script->ScriptName);
1070 SHELL_FREE_NON_NULL(Script);
1071 }
1072
1073 /**
1074 Function to return a pointer to the currently running script file object.
1075
1076 @retval NULL A script file is not currently running.
1077 @return A pointer to the current script file object.
1078 **/
1079 SCRIPT_FILE*
1080 EFIAPI
1081 ShellCommandGetCurrentScriptFile (
1082 VOID
1083 )
1084 {
1085 SCRIPT_FILE_LIST *List;
1086 if (IsListEmpty (&mScriptList.Link)) {
1087 return (NULL);
1088 }
1089 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));
1090 return (List->Data);
1091 }
1092
1093 /**
1094 Function to set a new script as the currently running one.
1095
1096 This function will correctly stack and unstack nested scripts.
1097
1098 @param[in] Script Pointer to new script information structure. if NULL
1099 will remove and de-allocate the top-most Script structure.
1100
1101 @return A pointer to the current running script file after this
1102 change. NULL if removing the final script.
1103 **/
1104 SCRIPT_FILE*
1105 EFIAPI
1106 ShellCommandSetNewScript (
1107 IN SCRIPT_FILE *Script OPTIONAL
1108 )
1109 {
1110 SCRIPT_FILE_LIST *Node;
1111 if (Script == NULL) {
1112 if (IsListEmpty (&mScriptList.Link)) {
1113 return (NULL);
1114 }
1115 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
1116 RemoveEntryList(&Node->Link);
1117 DeleteScriptFileStruct(Node->Data);
1118 FreePool(Node);
1119 } else {
1120 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));
1121 if (Node == NULL) {
1122 return (NULL);
1123 }
1124 Node->Data = Script;
1125 InsertHeadList(&mScriptList.Link, &Node->Link);
1126 }
1127 return (ShellCommandGetCurrentScriptFile());
1128 }
1129
1130 /**
1131 Function to generate the next default mapping name.
1132
1133 If the return value is not NULL then it must be callee freed.
1134
1135 @param Type What kind of mapping name to make.
1136
1137 @retval NULL a memory allocation failed.
1138 @return a new map name string
1139 **/
1140 CHAR16*
1141 EFIAPI
1142 ShellCommandCreateNewMappingName(
1143 IN CONST SHELL_MAPPING_TYPE Type
1144 )
1145 {
1146 CHAR16 *String;
1147 ASSERT(Type < MappingTypeMax);
1148
1149 String = NULL;
1150
1151 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));
1152 UnicodeSPrint(
1153 String,
1154 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),
1155 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",
1156 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);
1157
1158 return (String);
1159 }
1160
1161 /**
1162 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
1163
1164 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
1165 default paths on the new map name...
1166
1167 Path should be FALSE when this function is called from the protocol SetMap function.
1168
1169 @param[in] Name The human readable mapped name.
1170 @param[in] DevicePath The Device Path for this map.
1171 @param[in] Flags The Flags attribute for this map item.
1172 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
1173
1174 @retval EFI_SUCCESS The addition was sucessful.
1175 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1176 @retval EFI_INVALID_PARAMETER A parameter was invalid.
1177 **/
1178 EFI_STATUS
1179 EFIAPI
1180 ShellCommandAddMapItemAndUpdatePath(
1181 IN CONST CHAR16 *Name,
1182 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1183 IN CONST UINT64 Flags,
1184 IN CONST BOOLEAN Path
1185 )
1186 {
1187 EFI_STATUS Status;
1188 SHELL_MAP_LIST *MapListNode;
1189 CONST CHAR16 *OriginalPath;
1190 CHAR16 *NewPath;
1191 UINTN NewPathSize;
1192
1193 NewPathSize = 0;
1194 NewPath = NULL;
1195 OriginalPath = NULL;
1196 Status = EFI_SUCCESS;
1197
1198 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));
1199 if (MapListNode == NULL) {
1200 Status = EFI_OUT_OF_RESOURCES;
1201 } else {
1202 MapListNode->Flags = Flags;
1203 MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);
1204 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);
1205 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){
1206 Status = EFI_OUT_OF_RESOURCES;
1207 } else {
1208 InsertTailList(&gShellMapList.Link, &MapListNode->Link);
1209 }
1210 }
1211 if (EFI_ERROR(Status)) {
1212 if (MapListNode != NULL) {
1213 if (MapListNode->DevicePath != NULL) {
1214 FreePool(MapListNode->DevicePath);
1215 }
1216 if (MapListNode->MapName != NULL) {
1217 FreePool(MapListNode->MapName);
1218 }
1219 FreePool(MapListNode);
1220 }
1221 } else if (Path) {
1222 //
1223 // Since there was no error and Path was TRUE
1224 // Now add the correct path for that mapping
1225 //
1226 OriginalPath = gEfiShellProtocol->GetEnv(L"path");
1227 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));
1228 if (OriginalPath != NULL) {
1229 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);
1230 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);
1231 }
1232 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1233 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
1234 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1235 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
1236 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1237 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);
1238
1239 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);
1240 ASSERT_EFI_ERROR(Status);
1241 FreePool(NewPath);
1242 }
1243 return (Status);
1244 }
1245
1246 /**
1247 Creates the default map names for each device path in the system with
1248 a protocol depending on the Type.
1249
1250 Creates the consistent map names for each device path in the system with
1251 a protocol depending on the Type.
1252
1253 Note: This will reset all mappings in the system("map -r").
1254
1255 Also sets up the default path environment variable if Type is FileSystem.
1256
1257 @retval EFI_SUCCESS All map names were created sucessfully.
1258 @retval EFI_NOT_FOUND No protocols were found in the system.
1259 @return Error returned from gBS->LocateHandle().
1260
1261 @sa LocateHandle
1262 **/
1263 EFI_STATUS
1264 EFIAPI
1265 ShellCommandCreateInitialMappingsAndPaths(
1266 VOID
1267 )
1268 {
1269 EFI_STATUS Status;
1270 EFI_HANDLE *HandleList;
1271 UINTN Count;
1272 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1273 CHAR16 *NewDefaultName;
1274 CHAR16 *NewConsistName;
1275 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1276 SHELL_MAP_LIST *MapListNode;
1277
1278 HandleList = NULL;
1279
1280 //
1281 // Reset the static members back to zero
1282 //
1283 mFsMaxCount = 0;
1284 mBlkMaxCount = 0;
1285
1286 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);
1287
1288 //
1289 // First empty out the existing list.
1290 //
1291 if (!IsListEmpty(&gShellMapList.Link)) {
1292 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1293 ; !IsListEmpty(&gShellMapList.Link)
1294 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1295 ){
1296 RemoveEntryList(&MapListNode->Link);
1297 SHELL_FREE_NON_NULL(MapListNode->DevicePath);
1298 SHELL_FREE_NON_NULL(MapListNode->MapName);
1299 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);
1300 FreePool(MapListNode);
1301 } // for loop
1302 }
1303
1304 //
1305 // Find each handle with Simple File System
1306 //
1307 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1308 if (HandleList != NULL) {
1309 //
1310 // Do a count of the handles
1311 //
1312 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1313
1314 //
1315 // Get all Device Paths
1316 //
1317 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1318 if (DevicePathList == NULL) {
1319 SHELL_FREE_NON_NULL (HandleList);
1320 return EFI_OUT_OF_RESOURCES;
1321 }
1322
1323 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1324 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1325 }
1326
1327 //
1328 // Sort all DevicePaths
1329 //
1330 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1331
1332 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1333 //
1334 // Assign new Mappings to all...
1335 //
1336 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1337 //
1338 // Get default name first
1339 //
1340 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1341 ASSERT(NewDefaultName != NULL);
1342 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);
1343 ASSERT_EFI_ERROR(Status);
1344 FreePool(NewDefaultName);
1345
1346 //
1347 // Now do consistent name
1348 //
1349 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1350 if (NewConsistName != NULL) {
1351 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);
1352 ASSERT_EFI_ERROR(Status);
1353 FreePool(NewConsistName);
1354 }
1355 }
1356
1357 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1358
1359 SHELL_FREE_NON_NULL(HandleList);
1360 SHELL_FREE_NON_NULL(DevicePathList);
1361
1362 HandleList = NULL;
1363 } else {
1364 Count = (UINTN)-1;
1365 }
1366
1367 //
1368 // Find each handle with Block Io
1369 //
1370 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);
1371 if (HandleList != NULL) {
1372 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1373
1374 //
1375 // Get all Device Paths
1376 //
1377 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1378 if (DevicePathList == NULL) {
1379 SHELL_FREE_NON_NULL (HandleList);
1380 return EFI_OUT_OF_RESOURCES;
1381 }
1382
1383 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1384 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1385 }
1386
1387 //
1388 // Sort all DevicePaths
1389 //
1390 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1391
1392 //
1393 // Assign new Mappings to all...
1394 //
1395 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1396 //
1397 // Get default name first
1398 //
1399 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);
1400 ASSERT(NewDefaultName != NULL);
1401 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);
1402 ASSERT_EFI_ERROR(Status);
1403 FreePool(NewDefaultName);
1404 }
1405
1406 SHELL_FREE_NON_NULL(HandleList);
1407 SHELL_FREE_NON_NULL(DevicePathList);
1408 } else if (Count == (UINTN)-1) {
1409 return (EFI_NOT_FOUND);
1410 }
1411
1412 return (EFI_SUCCESS);
1413 }
1414
1415 /**
1416 Add mappings for any devices without one. Do not change any existing maps.
1417
1418 @retval EFI_SUCCESS The operation was successful.
1419 **/
1420 EFI_STATUS
1421 EFIAPI
1422 ShellCommandUpdateMapping (
1423 VOID
1424 )
1425 {
1426 EFI_STATUS Status;
1427 EFI_HANDLE *HandleList;
1428 UINTN Count;
1429 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1430 CHAR16 *NewDefaultName;
1431 CHAR16 *NewConsistName;
1432 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1433
1434 HandleList = NULL;
1435 Status = EFI_SUCCESS;
1436
1437 //
1438 // remove mappings that represent removed devices.
1439 //
1440
1441 //
1442 // Find each handle with Simple File System
1443 //
1444 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1445 if (HandleList != NULL) {
1446 //
1447 // Do a count of the handles
1448 //
1449 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1450
1451 //
1452 // Get all Device Paths
1453 //
1454 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1455 if (DevicePathList == NULL) {
1456 return (EFI_OUT_OF_RESOURCES);
1457 }
1458
1459 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1460 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1461 }
1462
1463 //
1464 // Sort all DevicePaths
1465 //
1466 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1467
1468 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1469
1470 //
1471 // Assign new Mappings to remainders
1472 //
1473 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {
1474 //
1475 // Skip ones that already have
1476 //
1477 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {
1478 continue;
1479 }
1480 //
1481 // Get default name
1482 //
1483 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1484 if (NewDefaultName == NULL) {
1485 Status = EFI_OUT_OF_RESOURCES;
1486 break;
1487 }
1488
1489 //
1490 // Call shell protocol SetMap function now...
1491 //
1492 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);
1493
1494 if (!EFI_ERROR(Status)) {
1495 //
1496 // Now do consistent name
1497 //
1498 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1499 if (NewConsistName != NULL) {
1500 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);
1501 FreePool(NewConsistName);
1502 }
1503 }
1504
1505 FreePool(NewDefaultName);
1506 }
1507 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1508 SHELL_FREE_NON_NULL(HandleList);
1509 SHELL_FREE_NON_NULL(DevicePathList);
1510
1511 HandleList = NULL;
1512 } else {
1513 Count = (UINTN)-1;
1514 }
1515 //
1516 // Do it all over again for gEfiBlockIoProtocolGuid
1517 //
1518
1519 return (Status);
1520 }
1521
1522 /**
1523 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1524
1525 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1526
1527 @return a EFI_FILE_PROTOCOL* representing the same file.
1528 **/
1529 EFI_FILE_PROTOCOL*
1530 EFIAPI
1531 ConvertShellHandleToEfiFileProtocol(
1532 IN CONST SHELL_FILE_HANDLE Handle
1533 )
1534 {
1535 return ((EFI_FILE_PROTOCOL*)(Handle));
1536 }
1537
1538 /**
1539 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1540
1541 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1542 @param[in] Path The path to the file for verification.
1543
1544 @return A SHELL_FILE_HANDLE representing the same file.
1545 @retval NULL There was not enough memory.
1546 **/
1547 SHELL_FILE_HANDLE
1548 EFIAPI
1549 ConvertEfiFileProtocolToShellHandle(
1550 IN CONST EFI_FILE_PROTOCOL *Handle,
1551 IN CONST CHAR16 *Path
1552 )
1553 {
1554 SHELL_COMMAND_FILE_HANDLE *Buffer;
1555 BUFFER_LIST *NewNode;
1556
1557 if (Path != NULL) {
1558 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));
1559 if (Buffer == NULL) {
1560 return (NULL);
1561 }
1562 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));
1563 if (NewNode == NULL) {
1564 SHELL_FREE_NON_NULL(Buffer);
1565 return (NULL);
1566 }
1567 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;
1568 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);
1569 if (Buffer->Path == NULL) {
1570 SHELL_FREE_NON_NULL(NewNode);
1571 SHELL_FREE_NON_NULL(Buffer);
1572 return (NULL);
1573 }
1574 NewNode->Buffer = Buffer;
1575
1576 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);
1577 }
1578 return ((SHELL_FILE_HANDLE)(Handle));
1579 }
1580
1581 /**
1582 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1583
1584 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1585
1586 @return A pointer to the path for the file.
1587 **/
1588 CONST CHAR16*
1589 EFIAPI
1590 ShellFileHandleGetPath(
1591 IN CONST SHELL_FILE_HANDLE Handle
1592 )
1593 {
1594 BUFFER_LIST *Node;
1595
1596 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1597 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1598 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1599 ){
1600 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1601 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1602 }
1603 }
1604 return (NULL);
1605 }
1606
1607 /**
1608 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1609
1610 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1611
1612 @retval TRUE The item was removed.
1613 @retval FALSE The item was not found.
1614 **/
1615 BOOLEAN
1616 EFIAPI
1617 ShellFileHandleRemove(
1618 IN CONST SHELL_FILE_HANDLE Handle
1619 )
1620 {
1621 BUFFER_LIST *Node;
1622
1623 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1624 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1625 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1626 ){
1627 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1628 RemoveEntryList(&Node->Link);
1629 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1630 SHELL_FREE_NON_NULL(Node->Buffer);
1631 SHELL_FREE_NON_NULL(Node);
1632 return (TRUE);
1633 }
1634 }
1635 return (FALSE);
1636 }
1637
1638 /**
1639 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1640
1641 This will NOT work on directories.
1642
1643 If Handle is NULL, then ASSERT.
1644
1645 @param[in] Handle the file handle
1646
1647 @retval TRUE the position is at the end of the file
1648 @retval FALSE the position is not at the end of the file
1649 **/
1650 BOOLEAN
1651 EFIAPI
1652 ShellFileHandleEof(
1653 IN SHELL_FILE_HANDLE Handle
1654 )
1655 {
1656 EFI_FILE_INFO *Info;
1657 UINT64 Pos;
1658 BOOLEAN RetVal;
1659
1660 //
1661 // ASSERT if Handle is NULL
1662 //
1663 ASSERT(Handle != NULL);
1664
1665 gEfiShellProtocol->GetFilePosition(Handle, &Pos);
1666 Info = gEfiShellProtocol->GetFileInfo (Handle);
1667 gEfiShellProtocol->SetFilePosition(Handle, Pos);
1668
1669 if (Info == NULL) {
1670 return (FALSE);
1671 }
1672
1673 if (Pos == Info->FileSize) {
1674 RetVal = TRUE;
1675 } else {
1676 RetVal = FALSE;
1677 }
1678
1679 FreePool (Info);
1680
1681 return (RetVal);
1682 }
1683
1684 /**
1685 Frees any BUFFER_LIST defined type.
1686
1687 @param[in] List The BUFFER_LIST object to free.
1688 **/
1689 VOID
1690 EFIAPI
1691 FreeBufferList (
1692 IN BUFFER_LIST *List
1693 )
1694 {
1695 BUFFER_LIST *BufferListEntry;
1696
1697 if (List == NULL){
1698 return;
1699 }
1700 //
1701 // enumerate through the buffer list and free all memory
1702 //
1703 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
1704 ; !IsListEmpty (&List->Link)
1705 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
1706 ){
1707 RemoveEntryList(&BufferListEntry->Link);
1708 if (BufferListEntry->Buffer != NULL) {
1709 FreePool(BufferListEntry->Buffer);
1710 }
1711 FreePool(BufferListEntry);
1712 }
1713 }
1714
1715 /**
1716 Dump some hexadecimal data to the screen.
1717
1718 @param[in] Indent How many spaces to indent the output.
1719 @param[in] Offset The offset of the printing.
1720 @param[in] DataSize The size in bytes of UserData.
1721 @param[in] UserData The data to print out.
1722 **/
1723 VOID
1724 DumpHex (
1725 IN UINTN Indent,
1726 IN UINTN Offset,
1727 IN UINTN DataSize,
1728 IN VOID *UserData
1729 )
1730 {
1731 UINT8 *Data;
1732
1733 CHAR8 Val[50];
1734
1735 CHAR8 Str[20];
1736
1737 UINT8 TempByte;
1738 UINTN Size;
1739 UINTN Index;
1740
1741 Data = UserData;
1742 while (DataSize != 0) {
1743 Size = 16;
1744 if (Size > DataSize) {
1745 Size = DataSize;
1746 }
1747
1748 for (Index = 0; Index < Size; Index += 1) {
1749 TempByte = Data[Index];
1750 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1751 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1752 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1753 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1754 }
1755
1756 Val[Index * 3] = 0;
1757 Str[Index] = 0;
1758 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1759
1760 Data += Size;
1761 Offset += Size;
1762 DataSize -= Size;
1763 }
1764 }
1765
1766 /**
1767 Dump HEX data into buffer.
1768
1769 @param[in] Buffer HEX data to be dumped in Buffer.
1770 @param[in] Indent How many spaces to indent the output.
1771 @param[in] Offset The offset of the printing.
1772 @param[in] DataSize The size in bytes of UserData.
1773 @param[in] UserData The data to print out.
1774 **/
1775 CHAR16*
1776 CatSDumpHex (
1777 IN CHAR16 *Buffer,
1778 IN UINTN Indent,
1779 IN UINTN Offset,
1780 IN UINTN DataSize,
1781 IN VOID *UserData
1782 )
1783 {
1784 UINT8 *Data;
1785 UINT8 TempByte;
1786 UINTN Size;
1787 UINTN Index;
1788 CHAR8 Val[50];
1789 CHAR8 Str[20];
1790 CHAR16 *RetVal;
1791 CHAR16 *TempRetVal;
1792
1793 Data = UserData;
1794 RetVal = Buffer;
1795 while (DataSize != 0) {
1796 Size = 16;
1797 if (Size > DataSize) {
1798 Size = DataSize;
1799 }
1800
1801 for (Index = 0; Index < Size; Index += 1) {
1802 TempByte = Data[Index];
1803 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1804 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1805 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1806 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1807 }
1808
1809 Val[Index * 3] = 0;
1810 Str[Index] = 0;
1811 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1812 SHELL_FREE_NON_NULL (RetVal);
1813 RetVal = TempRetVal;
1814
1815 Data += Size;
1816 Offset += Size;
1817 DataSize -= Size;
1818 }
1819
1820 return RetVal;
1821 }