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