]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg/UefiShellCommandLib.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 - 2016, 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 } else {
1231 StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);
1232 }
1233 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);
1234 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1235 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
1236 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1237 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
1238 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
1239 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);
1240
1241 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);
1242 ASSERT_EFI_ERROR(Status);
1243 FreePool(NewPath);
1244 }
1245 return (Status);
1246 }
1247
1248 /**
1249 Creates the default map names for each device path in the system with
1250 a protocol depending on the Type.
1251
1252 Creates the consistent map names for each device path in the system with
1253 a protocol depending on the Type.
1254
1255 Note: This will reset all mappings in the system("map -r").
1256
1257 Also sets up the default path environment variable if Type is FileSystem.
1258
1259 @retval EFI_SUCCESS All map names were created sucessfully.
1260 @retval EFI_NOT_FOUND No protocols were found in the system.
1261 @return Error returned from gBS->LocateHandle().
1262
1263 @sa LocateHandle
1264 **/
1265 EFI_STATUS
1266 EFIAPI
1267 ShellCommandCreateInitialMappingsAndPaths(
1268 VOID
1269 )
1270 {
1271 EFI_STATUS Status;
1272 EFI_HANDLE *HandleList;
1273 UINTN Count;
1274 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1275 CHAR16 *NewDefaultName;
1276 CHAR16 *NewConsistName;
1277 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1278 SHELL_MAP_LIST *MapListNode;
1279
1280 HandleList = NULL;
1281
1282 //
1283 // Reset the static members back to zero
1284 //
1285 mFsMaxCount = 0;
1286 mBlkMaxCount = 0;
1287
1288 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);
1289
1290 //
1291 // First empty out the existing list.
1292 //
1293 if (!IsListEmpty(&gShellMapList.Link)) {
1294 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1295 ; !IsListEmpty(&gShellMapList.Link)
1296 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
1297 ){
1298 RemoveEntryList(&MapListNode->Link);
1299 SHELL_FREE_NON_NULL(MapListNode->DevicePath);
1300 SHELL_FREE_NON_NULL(MapListNode->MapName);
1301 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);
1302 FreePool(MapListNode);
1303 } // for loop
1304 }
1305
1306 //
1307 // Find each handle with Simple File System
1308 //
1309 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1310 if (HandleList != NULL) {
1311 //
1312 // Do a count of the handles
1313 //
1314 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1315
1316 //
1317 // Get all Device Paths
1318 //
1319 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1320 if (DevicePathList == NULL) {
1321 SHELL_FREE_NON_NULL (HandleList);
1322 return EFI_OUT_OF_RESOURCES;
1323 }
1324
1325 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1326 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1327 }
1328
1329 //
1330 // Sort all DevicePaths
1331 //
1332 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1333
1334 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1335 //
1336 // Assign new Mappings to all...
1337 //
1338 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1339 //
1340 // Get default name first
1341 //
1342 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1343 ASSERT(NewDefaultName != NULL);
1344 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);
1345 ASSERT_EFI_ERROR(Status);
1346 FreePool(NewDefaultName);
1347
1348 //
1349 // Now do consistent name
1350 //
1351 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1352 if (NewConsistName != NULL) {
1353 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);
1354 ASSERT_EFI_ERROR(Status);
1355 FreePool(NewConsistName);
1356 }
1357 }
1358
1359 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1360
1361 SHELL_FREE_NON_NULL(HandleList);
1362 SHELL_FREE_NON_NULL(DevicePathList);
1363
1364 HandleList = NULL;
1365 } else {
1366 Count = (UINTN)-1;
1367 }
1368
1369 //
1370 // Find each handle with Block Io
1371 //
1372 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);
1373 if (HandleList != NULL) {
1374 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1375
1376 //
1377 // Get all Device Paths
1378 //
1379 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1380 if (DevicePathList == NULL) {
1381 SHELL_FREE_NON_NULL (HandleList);
1382 return EFI_OUT_OF_RESOURCES;
1383 }
1384
1385 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1386 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1387 }
1388
1389 //
1390 // Sort all DevicePaths
1391 //
1392 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1393
1394 //
1395 // Assign new Mappings to all...
1396 //
1397 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1398 //
1399 // Get default name first
1400 //
1401 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);
1402 ASSERT(NewDefaultName != NULL);
1403 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);
1404 ASSERT_EFI_ERROR(Status);
1405 FreePool(NewDefaultName);
1406 }
1407
1408 SHELL_FREE_NON_NULL(HandleList);
1409 SHELL_FREE_NON_NULL(DevicePathList);
1410 } else if (Count == (UINTN)-1) {
1411 return (EFI_NOT_FOUND);
1412 }
1413
1414 return (EFI_SUCCESS);
1415 }
1416
1417 /**
1418 Add mappings for any devices without one. Do not change any existing maps.
1419
1420 @retval EFI_SUCCESS The operation was successful.
1421 **/
1422 EFI_STATUS
1423 EFIAPI
1424 ShellCommandUpdateMapping (
1425 VOID
1426 )
1427 {
1428 EFI_STATUS Status;
1429 EFI_HANDLE *HandleList;
1430 UINTN Count;
1431 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
1432 CHAR16 *NewDefaultName;
1433 CHAR16 *NewConsistName;
1434 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
1435
1436 HandleList = NULL;
1437 Status = EFI_SUCCESS;
1438
1439 //
1440 // remove mappings that represent removed devices.
1441 //
1442
1443 //
1444 // Find each handle with Simple File System
1445 //
1446 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);
1447 if (HandleList != NULL) {
1448 //
1449 // Do a count of the handles
1450 //
1451 for (Count = 0 ; HandleList[Count] != NULL ; Count++);
1452
1453 //
1454 // Get all Device Paths
1455 //
1456 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
1457 if (DevicePathList == NULL) {
1458 return (EFI_OUT_OF_RESOURCES);
1459 }
1460
1461 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
1462 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
1463 }
1464
1465 //
1466 // Sort all DevicePaths
1467 //
1468 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
1469
1470 ShellCommandConsistMappingInitialize(&ConsistMappingTable);
1471
1472 //
1473 // Assign new Mappings to remainders
1474 //
1475 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {
1476 //
1477 // Skip ones that already have
1478 //
1479 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {
1480 continue;
1481 }
1482 //
1483 // Get default name
1484 //
1485 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
1486 if (NewDefaultName == NULL) {
1487 Status = EFI_OUT_OF_RESOURCES;
1488 break;
1489 }
1490
1491 //
1492 // Call shell protocol SetMap function now...
1493 //
1494 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);
1495
1496 if (!EFI_ERROR(Status)) {
1497 //
1498 // Now do consistent name
1499 //
1500 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
1501 if (NewConsistName != NULL) {
1502 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);
1503 FreePool(NewConsistName);
1504 }
1505 }
1506
1507 FreePool(NewDefaultName);
1508 }
1509 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
1510 SHELL_FREE_NON_NULL(HandleList);
1511 SHELL_FREE_NON_NULL(DevicePathList);
1512
1513 HandleList = NULL;
1514 } else {
1515 Count = (UINTN)-1;
1516 }
1517 //
1518 // Do it all over again for gEfiBlockIoProtocolGuid
1519 //
1520
1521 return (Status);
1522 }
1523
1524 /**
1525 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1526
1527 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1528
1529 @return a EFI_FILE_PROTOCOL* representing the same file.
1530 **/
1531 EFI_FILE_PROTOCOL*
1532 EFIAPI
1533 ConvertShellHandleToEfiFileProtocol(
1534 IN CONST SHELL_FILE_HANDLE Handle
1535 )
1536 {
1537 return ((EFI_FILE_PROTOCOL*)(Handle));
1538 }
1539
1540 /**
1541 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1542
1543 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1544 @param[in] Path The path to the file for verification.
1545
1546 @return A SHELL_FILE_HANDLE representing the same file.
1547 @retval NULL There was not enough memory.
1548 **/
1549 SHELL_FILE_HANDLE
1550 EFIAPI
1551 ConvertEfiFileProtocolToShellHandle(
1552 IN CONST EFI_FILE_PROTOCOL *Handle,
1553 IN CONST CHAR16 *Path
1554 )
1555 {
1556 SHELL_COMMAND_FILE_HANDLE *Buffer;
1557 BUFFER_LIST *NewNode;
1558
1559 if (Path != NULL) {
1560 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));
1561 if (Buffer == NULL) {
1562 return (NULL);
1563 }
1564 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));
1565 if (NewNode == NULL) {
1566 SHELL_FREE_NON_NULL(Buffer);
1567 return (NULL);
1568 }
1569 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;
1570 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);
1571 if (Buffer->Path == NULL) {
1572 SHELL_FREE_NON_NULL(NewNode);
1573 SHELL_FREE_NON_NULL(Buffer);
1574 return (NULL);
1575 }
1576 NewNode->Buffer = Buffer;
1577
1578 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);
1579 }
1580 return ((SHELL_FILE_HANDLE)(Handle));
1581 }
1582
1583 /**
1584 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1585
1586 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1587
1588 @return A pointer to the path for the file.
1589 **/
1590 CONST CHAR16*
1591 EFIAPI
1592 ShellFileHandleGetPath(
1593 IN CONST SHELL_FILE_HANDLE Handle
1594 )
1595 {
1596 BUFFER_LIST *Node;
1597
1598 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1599 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1600 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1601 ){
1602 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1603 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1604 }
1605 }
1606 return (NULL);
1607 }
1608
1609 /**
1610 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1611
1612 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1613
1614 @retval TRUE The item was removed.
1615 @retval FALSE The item was not found.
1616 **/
1617 BOOLEAN
1618 EFIAPI
1619 ShellFileHandleRemove(
1620 IN CONST SHELL_FILE_HANDLE Handle
1621 )
1622 {
1623 BUFFER_LIST *Node;
1624
1625 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
1626 ; !IsNull(&mFileHandleList.Link, &Node->Link)
1627 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
1628 ){
1629 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
1630 RemoveEntryList(&Node->Link);
1631 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
1632 SHELL_FREE_NON_NULL(Node->Buffer);
1633 SHELL_FREE_NON_NULL(Node);
1634 return (TRUE);
1635 }
1636 }
1637 return (FALSE);
1638 }
1639
1640 /**
1641 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1642
1643 This will NOT work on directories.
1644
1645 If Handle is NULL, then ASSERT.
1646
1647 @param[in] Handle the file handle
1648
1649 @retval TRUE the position is at the end of the file
1650 @retval FALSE the position is not at the end of the file
1651 **/
1652 BOOLEAN
1653 EFIAPI
1654 ShellFileHandleEof(
1655 IN SHELL_FILE_HANDLE Handle
1656 )
1657 {
1658 EFI_FILE_INFO *Info;
1659 UINT64 Pos;
1660 BOOLEAN RetVal;
1661
1662 //
1663 // ASSERT if Handle is NULL
1664 //
1665 ASSERT(Handle != NULL);
1666
1667 gEfiShellProtocol->GetFilePosition(Handle, &Pos);
1668 Info = gEfiShellProtocol->GetFileInfo (Handle);
1669 gEfiShellProtocol->SetFilePosition(Handle, Pos);
1670
1671 if (Info == NULL) {
1672 return (FALSE);
1673 }
1674
1675 if (Pos == Info->FileSize) {
1676 RetVal = TRUE;
1677 } else {
1678 RetVal = FALSE;
1679 }
1680
1681 FreePool (Info);
1682
1683 return (RetVal);
1684 }
1685
1686 /**
1687 Frees any BUFFER_LIST defined type.
1688
1689 @param[in] List The BUFFER_LIST object to free.
1690 **/
1691 VOID
1692 EFIAPI
1693 FreeBufferList (
1694 IN BUFFER_LIST *List
1695 )
1696 {
1697 BUFFER_LIST *BufferListEntry;
1698
1699 if (List == NULL){
1700 return;
1701 }
1702 //
1703 // enumerate through the buffer list and free all memory
1704 //
1705 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
1706 ; !IsListEmpty (&List->Link)
1707 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
1708 ){
1709 RemoveEntryList(&BufferListEntry->Link);
1710 if (BufferListEntry->Buffer != NULL) {
1711 FreePool(BufferListEntry->Buffer);
1712 }
1713 FreePool(BufferListEntry);
1714 }
1715 }
1716
1717 /**
1718 Dump some hexadecimal data to the screen.
1719
1720 @param[in] Indent How many spaces to indent the output.
1721 @param[in] Offset The offset of the printing.
1722 @param[in] DataSize The size in bytes of UserData.
1723 @param[in] UserData The data to print out.
1724 **/
1725 VOID
1726 DumpHex (
1727 IN UINTN Indent,
1728 IN UINTN Offset,
1729 IN UINTN DataSize,
1730 IN VOID *UserData
1731 )
1732 {
1733 UINT8 *Data;
1734
1735 CHAR8 Val[50];
1736
1737 CHAR8 Str[20];
1738
1739 UINT8 TempByte;
1740 UINTN Size;
1741 UINTN Index;
1742
1743 Data = UserData;
1744 while (DataSize != 0) {
1745 Size = 16;
1746 if (Size > DataSize) {
1747 Size = DataSize;
1748 }
1749
1750 for (Index = 0; Index < Size; Index += 1) {
1751 TempByte = Data[Index];
1752 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1753 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1754 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1755 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1756 }
1757
1758 Val[Index * 3] = 0;
1759 Str[Index] = 0;
1760 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1761
1762 Data += Size;
1763 Offset += Size;
1764 DataSize -= Size;
1765 }
1766 }
1767
1768 /**
1769 Dump HEX data into buffer.
1770
1771 @param[in] Buffer HEX data to be dumped in Buffer.
1772 @param[in] Indent How many spaces to indent the output.
1773 @param[in] Offset The offset of the printing.
1774 @param[in] DataSize The size in bytes of UserData.
1775 @param[in] UserData The data to print out.
1776 **/
1777 CHAR16*
1778 CatSDumpHex (
1779 IN CHAR16 *Buffer,
1780 IN UINTN Indent,
1781 IN UINTN Offset,
1782 IN UINTN DataSize,
1783 IN VOID *UserData
1784 )
1785 {
1786 UINT8 *Data;
1787 UINT8 TempByte;
1788 UINTN Size;
1789 UINTN Index;
1790 CHAR8 Val[50];
1791 CHAR8 Str[20];
1792 CHAR16 *RetVal;
1793 CHAR16 *TempRetVal;
1794
1795 Data = UserData;
1796 RetVal = Buffer;
1797 while (DataSize != 0) {
1798 Size = 16;
1799 if (Size > DataSize) {
1800 Size = DataSize;
1801 }
1802
1803 for (Index = 0; Index < Size; Index += 1) {
1804 TempByte = Data[Index];
1805 Val[Index * 3 + 0] = Hex[TempByte >> 4];
1806 Val[Index * 3 + 1] = Hex[TempByte & 0xF];
1807 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
1808 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
1809 }
1810
1811 Val[Index * 3] = 0;
1812 Str[Index] = 0;
1813 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
1814 SHELL_FREE_NON_NULL (RetVal);
1815 RetVal = TempRetVal;
1816
1817 Data += Size;
1818 Offset += Size;
1819 DataSize -= Size;
1820 }
1821
1822 return RetVal;
1823 }