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