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 | if (gUnicodeCollation == NULL) {
|
---|
78 | GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME, (VOID **)&PlatformLang, NULL);
|
---|
79 |
|
---|
80 | Status = gBS->LocateHandleBuffer (
|
---|
81 | ByProtocol,
|
---|
82 | &gEfiUnicodeCollation2ProtocolGuid,
|
---|
83 | NULL,
|
---|
84 | &NumHandles,
|
---|
85 | &Handles
|
---|
86 | );
|
---|
87 | if (EFI_ERROR (Status)) {
|
---|
88 | NumHandles = 0;
|
---|
89 | Handles = NULL;
|
---|
90 | }
|
---|
91 |
|
---|
92 | for (Index = 0; Index < NumHandles; Index++) {
|
---|
93 | //
|
---|
94 | // Open Unicode Collation Protocol
|
---|
95 | //
|
---|
96 | Status = gBS->OpenProtocol (
|
---|
97 | Handles[Index],
|
---|
98 | &gEfiUnicodeCollation2ProtocolGuid,
|
---|
99 | (VOID **)&Uc,
|
---|
100 | gImageHandle,
|
---|
101 | NULL,
|
---|
102 | EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
---|
103 | );
|
---|
104 | if (EFI_ERROR (Status)) {
|
---|
105 | continue;
|
---|
106 | }
|
---|
107 |
|
---|
108 | //
|
---|
109 | // Without clue provided use the first Unicode Collation2 protocol.
|
---|
110 | // This may happen when PlatformLang is NULL or when no installed Unicode
|
---|
111 | // Collation2 protocol instance supports PlatformLang.
|
---|
112 | //
|
---|
113 | if (gUnicodeCollation == NULL) {
|
---|
114 | gUnicodeCollation = Uc;
|
---|
115 | }
|
---|
116 |
|
---|
117 | if (PlatformLang == NULL) {
|
---|
118 | break;
|
---|
119 | }
|
---|
120 |
|
---|
121 | //
|
---|
122 | // Find the best matching matching language from the supported languages
|
---|
123 | // of Unicode Collation2 protocol.
|
---|
124 | //
|
---|
125 | BestLanguage = GetBestLanguage (
|
---|
126 | Uc->SupportedLanguages,
|
---|
127 | FALSE,
|
---|
128 | PlatformLang,
|
---|
129 | NULL
|
---|
130 | );
|
---|
131 | if (BestLanguage != NULL) {
|
---|
132 | FreePool (BestLanguage);
|
---|
133 | gUnicodeCollation = Uc;
|
---|
134 | break;
|
---|
135 | }
|
---|
136 | }
|
---|
137 |
|
---|
138 | if (Handles != NULL) {
|
---|
139 | FreePool (Handles);
|
---|
140 | }
|
---|
141 |
|
---|
142 | if (PlatformLang != NULL) {
|
---|
143 | FreePool (PlatformLang);
|
---|
144 | }
|
---|
145 | }
|
---|
146 |
|
---|
147 | return (gUnicodeCollation == NULL) ? EFI_UNSUPPORTED : EFI_SUCCESS;
|
---|
148 | }
|
---|
149 |
|
---|
150 | /**
|
---|
151 | Constructor for the Shell Command library.
|
---|
152 |
|
---|
153 | Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
|
---|
154 |
|
---|
155 | @param ImageHandle the image handle of the process
|
---|
156 | @param SystemTable the EFI System Table pointer
|
---|
157 |
|
---|
158 | @retval EFI_SUCCESS the initialization was complete successfully
|
---|
159 | **/
|
---|
160 | RETURN_STATUS
|
---|
161 | EFIAPI
|
---|
162 | ShellCommandLibConstructor (
|
---|
163 | IN EFI_HANDLE ImageHandle,
|
---|
164 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
165 | )
|
---|
166 | {
|
---|
167 | EFI_STATUS Status;
|
---|
168 |
|
---|
169 | InitializeListHead (&gShellMapList.Link);
|
---|
170 | InitializeListHead (&mCommandList.Link);
|
---|
171 | InitializeListHead (&mAliasList.Link);
|
---|
172 | InitializeListHead (&mScriptList.Link);
|
---|
173 | InitializeListHead (&mFileHandleList.Link);
|
---|
174 | mEchoState = TRUE;
|
---|
175 |
|
---|
176 | mExitRequested = FALSE;
|
---|
177 | mExitScript = FALSE;
|
---|
178 | mProfileListSize = 0;
|
---|
179 | mProfileList = NULL;
|
---|
180 |
|
---|
181 | Status = CommandInit ();
|
---|
182 | if (EFI_ERROR (Status)) {
|
---|
183 | return EFI_DEVICE_ERROR;
|
---|
184 | }
|
---|
185 |
|
---|
186 | return (RETURN_SUCCESS);
|
---|
187 | }
|
---|
188 |
|
---|
189 | /**
|
---|
190 | Frees list of file handles.
|
---|
191 |
|
---|
192 | @param[in] List The list to free.
|
---|
193 | **/
|
---|
194 | VOID
|
---|
195 | FreeFileHandleList (
|
---|
196 | IN BUFFER_LIST *List
|
---|
197 | )
|
---|
198 | {
|
---|
199 | BUFFER_LIST *BufferListEntry;
|
---|
200 |
|
---|
201 | if (List == NULL) {
|
---|
202 | return;
|
---|
203 | }
|
---|
204 |
|
---|
205 | //
|
---|
206 | // enumerate through the buffer list and free all memory
|
---|
207 | //
|
---|
208 | for ( BufferListEntry = (BUFFER_LIST *)GetFirstNode (&List->Link)
|
---|
209 | ; !IsListEmpty (&List->Link)
|
---|
210 | ; BufferListEntry = (BUFFER_LIST *)GetFirstNode (&List->Link)
|
---|
211 | )
|
---|
212 | {
|
---|
213 | RemoveEntryList (&BufferListEntry->Link);
|
---|
214 | ASSERT (BufferListEntry->Buffer != NULL);
|
---|
215 | SHELL_FREE_NON_NULL (((SHELL_COMMAND_FILE_HANDLE *)(BufferListEntry->Buffer))->Path);
|
---|
216 | SHELL_FREE_NON_NULL (BufferListEntry->Buffer);
|
---|
217 | SHELL_FREE_NON_NULL (BufferListEntry);
|
---|
218 | }
|
---|
219 | }
|
---|
220 |
|
---|
221 | /**
|
---|
222 | Destructor for the library. free any resources.
|
---|
223 |
|
---|
224 | @param ImageHandle the image handle of the process
|
---|
225 | @param SystemTable the EFI System Table pointer
|
---|
226 |
|
---|
227 | @retval RETURN_SUCCESS this function always returns success
|
---|
228 | **/
|
---|
229 | RETURN_STATUS
|
---|
230 | EFIAPI
|
---|
231 | ShellCommandLibDestructor (
|
---|
232 | IN EFI_HANDLE ImageHandle,
|
---|
233 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
234 | )
|
---|
235 | {
|
---|
236 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
237 | ALIAS_LIST *Node2;
|
---|
238 | SCRIPT_FILE_LIST *Node3;
|
---|
239 | SHELL_MAP_LIST *MapNode;
|
---|
240 |
|
---|
241 | //
|
---|
242 | // enumerate throught the list and free all the memory
|
---|
243 | //
|
---|
244 | while (!IsListEmpty (&mCommandList.Link)) {
|
---|
245 | Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link);
|
---|
246 | RemoveEntryList (&Node->Link);
|
---|
247 | SHELL_FREE_NON_NULL (Node->CommandString);
|
---|
248 | FreePool (Node);
|
---|
249 | DEBUG_CODE (
|
---|
250 | Node = NULL;
|
---|
251 | );
|
---|
252 | }
|
---|
253 |
|
---|
254 | //
|
---|
255 | // enumerate through the alias list and free all memory
|
---|
256 | //
|
---|
257 | while (!IsListEmpty (&mAliasList.Link)) {
|
---|
258 | Node2 = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link);
|
---|
259 | RemoveEntryList (&Node2->Link);
|
---|
260 | SHELL_FREE_NON_NULL (Node2->CommandString);
|
---|
261 | SHELL_FREE_NON_NULL (Node2->Alias);
|
---|
262 | SHELL_FREE_NON_NULL (Node2);
|
---|
263 | DEBUG_CODE (
|
---|
264 | Node2 = NULL;
|
---|
265 | );
|
---|
266 | }
|
---|
267 |
|
---|
268 | //
|
---|
269 | // enumerate throught the list and free all the memory
|
---|
270 | //
|
---|
271 | while (!IsListEmpty (&mScriptList.Link)) {
|
---|
272 | Node3 = (SCRIPT_FILE_LIST *)GetFirstNode (&mScriptList.Link);
|
---|
273 | RemoveEntryList (&Node3->Link);
|
---|
274 | DeleteScriptFileStruct (Node3->Data);
|
---|
275 | FreePool (Node3);
|
---|
276 | }
|
---|
277 |
|
---|
278 | //
|
---|
279 | // enumerate throught the mappings list and free all the memory
|
---|
280 | //
|
---|
281 | if (!IsListEmpty (&gShellMapList.Link)) {
|
---|
282 | for (MapNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)
|
---|
283 | ; !IsListEmpty (&gShellMapList.Link)
|
---|
284 | ; MapNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)
|
---|
285 | )
|
---|
286 | {
|
---|
287 | ASSERT (MapNode != NULL);
|
---|
288 | RemoveEntryList (&MapNode->Link);
|
---|
289 | SHELL_FREE_NON_NULL (MapNode->DevicePath);
|
---|
290 | SHELL_FREE_NON_NULL (MapNode->MapName);
|
---|
291 | SHELL_FREE_NON_NULL (MapNode->CurrentDirectoryPath);
|
---|
292 | FreePool (MapNode);
|
---|
293 | }
|
---|
294 | }
|
---|
295 |
|
---|
296 | if (!IsListEmpty (&mFileHandleList.Link)) {
|
---|
297 | FreeFileHandleList (&mFileHandleList);
|
---|
298 | }
|
---|
299 |
|
---|
300 | if (mProfileList != NULL) {
|
---|
301 | FreePool (mProfileList);
|
---|
302 | }
|
---|
303 |
|
---|
304 | gUnicodeCollation = NULL;
|
---|
305 | gShellCurMapping = NULL;
|
---|
306 |
|
---|
307 | return (RETURN_SUCCESS);
|
---|
308 | }
|
---|
309 |
|
---|
310 | /**
|
---|
311 | Find a dynamic command protocol instance given a command name string.
|
---|
312 |
|
---|
313 | @param CommandString the command name string
|
---|
314 |
|
---|
315 | @return instance the command protocol instance, if dynamic command instance found
|
---|
316 | @retval NULL no dynamic command protocol instance found for name
|
---|
317 | **/
|
---|
318 | CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *
|
---|
319 | ShellCommandFindDynamicCommand (
|
---|
320 | IN CONST CHAR16 *CommandString
|
---|
321 | )
|
---|
322 | {
|
---|
323 | EFI_STATUS Status;
|
---|
324 | EFI_HANDLE *CommandHandleList;
|
---|
325 | EFI_HANDLE *NextCommand;
|
---|
326 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
---|
327 |
|
---|
328 | CommandHandleList = GetHandleListByProtocol (&gEfiShellDynamicCommandProtocolGuid);
|
---|
329 | if (CommandHandleList == NULL) {
|
---|
330 | //
|
---|
331 | // not found or out of resources
|
---|
332 | //
|
---|
333 | return NULL;
|
---|
334 | }
|
---|
335 |
|
---|
336 | for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {
|
---|
337 | Status = gBS->HandleProtocol (
|
---|
338 | *NextCommand,
|
---|
339 | &gEfiShellDynamicCommandProtocolGuid,
|
---|
340 | (VOID **)&DynamicCommand
|
---|
341 | );
|
---|
342 |
|
---|
343 | if (EFI_ERROR (Status)) {
|
---|
344 | continue;
|
---|
345 | }
|
---|
346 |
|
---|
347 | if (gUnicodeCollation->StriColl (
|
---|
348 | gUnicodeCollation,
|
---|
349 | (CHAR16 *)CommandString,
|
---|
350 | (CHAR16 *)DynamicCommand->CommandName
|
---|
351 | ) == 0
|
---|
352 | )
|
---|
353 | {
|
---|
354 | FreePool (CommandHandleList);
|
---|
355 | return (DynamicCommand);
|
---|
356 | }
|
---|
357 | }
|
---|
358 |
|
---|
359 | FreePool (CommandHandleList);
|
---|
360 | return (NULL);
|
---|
361 | }
|
---|
362 |
|
---|
363 | /**
|
---|
364 | Checks if a command exists as a dynamic command protocol instance
|
---|
365 |
|
---|
366 | @param[in] CommandString The command string to check for on the list.
|
---|
367 | **/
|
---|
368 | BOOLEAN
|
---|
369 | ShellCommandDynamicCommandExists (
|
---|
370 | IN CONST CHAR16 *CommandString
|
---|
371 | )
|
---|
372 | {
|
---|
373 | return (BOOLEAN)((ShellCommandFindDynamicCommand (CommandString) != NULL));
|
---|
374 | }
|
---|
375 |
|
---|
376 | /**
|
---|
377 | Checks if a command is already on the internal command list.
|
---|
378 |
|
---|
379 | @param[in] CommandString The command string to check for on the list.
|
---|
380 | **/
|
---|
381 | BOOLEAN
|
---|
382 | ShellCommandIsCommandOnInternalList (
|
---|
383 | IN CONST CHAR16 *CommandString
|
---|
384 | )
|
---|
385 | {
|
---|
386 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
387 |
|
---|
388 | //
|
---|
389 | // assert for NULL parameter
|
---|
390 | //
|
---|
391 | ASSERT (CommandString != NULL);
|
---|
392 |
|
---|
393 | //
|
---|
394 | // check for the command
|
---|
395 | //
|
---|
396 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
---|
397 | ; !IsNull (&mCommandList.Link, &Node->Link)
|
---|
398 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Node->Link)
|
---|
399 | )
|
---|
400 | {
|
---|
401 | ASSERT (Node->CommandString != NULL);
|
---|
402 | if (gUnicodeCollation->StriColl (
|
---|
403 | gUnicodeCollation,
|
---|
404 | (CHAR16 *)CommandString,
|
---|
405 | Node->CommandString
|
---|
406 | ) == 0
|
---|
407 | )
|
---|
408 | {
|
---|
409 | return (TRUE);
|
---|
410 | }
|
---|
411 | }
|
---|
412 |
|
---|
413 | return (FALSE);
|
---|
414 | }
|
---|
415 |
|
---|
416 | /**
|
---|
417 | Checks if a command exists, either internally or through the dynamic command protocol.
|
---|
418 |
|
---|
419 | @param[in] CommandString The command string to check for on the list.
|
---|
420 | **/
|
---|
421 | BOOLEAN
|
---|
422 | EFIAPI
|
---|
423 | ShellCommandIsCommandOnList (
|
---|
424 | IN CONST CHAR16 *CommandString
|
---|
425 | )
|
---|
426 | {
|
---|
427 | if (ShellCommandIsCommandOnInternalList (CommandString)) {
|
---|
428 | return TRUE;
|
---|
429 | }
|
---|
430 |
|
---|
431 | return ShellCommandDynamicCommandExists (CommandString);
|
---|
432 | }
|
---|
433 |
|
---|
434 | /**
|
---|
435 | Get the help text for a dynamic command.
|
---|
436 |
|
---|
437 | @param[in] CommandString The command name.
|
---|
438 |
|
---|
439 | @retval NULL No help text was found.
|
---|
440 | @return String of help text. Caller required to free.
|
---|
441 | **/
|
---|
442 | CHAR16 *
|
---|
443 | ShellCommandGetDynamicCommandHelp (
|
---|
444 | IN CONST CHAR16 *CommandString
|
---|
445 | )
|
---|
446 | {
|
---|
447 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
---|
448 |
|
---|
449 | DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand (CommandString);
|
---|
450 | if (DynamicCommand == NULL) {
|
---|
451 | return (NULL);
|
---|
452 | }
|
---|
453 |
|
---|
454 | //
|
---|
455 | // TODO: how to get proper language?
|
---|
456 | //
|
---|
457 | return DynamicCommand->GetHelp (DynamicCommand, "en");
|
---|
458 | }
|
---|
459 |
|
---|
460 | /**
|
---|
461 | Get the help text for an internal command.
|
---|
462 |
|
---|
463 | @param[in] CommandString The command name.
|
---|
464 |
|
---|
465 | @retval NULL No help text was found.
|
---|
466 | @return String of help text. Caller reuiqred to free.
|
---|
467 | **/
|
---|
468 | CHAR16 *
|
---|
469 | ShellCommandGetInternalCommandHelp (
|
---|
470 | IN CONST CHAR16 *CommandString
|
---|
471 | )
|
---|
472 | {
|
---|
473 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
474 |
|
---|
475 | //
|
---|
476 | // assert for NULL parameter
|
---|
477 | //
|
---|
478 | ASSERT (CommandString != NULL);
|
---|
479 |
|
---|
480 | //
|
---|
481 | // check for the command
|
---|
482 | //
|
---|
483 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
---|
484 | ; !IsNull (&mCommandList.Link, &Node->Link)
|
---|
485 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Node->Link)
|
---|
486 | )
|
---|
487 | {
|
---|
488 | ASSERT (Node->CommandString != NULL);
|
---|
489 | if (gUnicodeCollation->StriColl (
|
---|
490 | gUnicodeCollation,
|
---|
491 | (CHAR16 *)CommandString,
|
---|
492 | Node->CommandString
|
---|
493 | ) == 0
|
---|
494 | )
|
---|
495 | {
|
---|
496 | return (HiiGetString (Node->HiiHandle, Node->ManFormatHelp, NULL));
|
---|
497 | }
|
---|
498 | }
|
---|
499 |
|
---|
500 | return (NULL);
|
---|
501 | }
|
---|
502 |
|
---|
503 | /**
|
---|
504 | Get the help text for a command.
|
---|
505 |
|
---|
506 | @param[in] CommandString The command name.
|
---|
507 |
|
---|
508 | @retval NULL No help text was found.
|
---|
509 | @return String of help text.Caller reuiqred to free.
|
---|
510 | **/
|
---|
511 | CHAR16 *
|
---|
512 | EFIAPI
|
---|
513 | ShellCommandGetCommandHelp (
|
---|
514 | IN CONST CHAR16 *CommandString
|
---|
515 | )
|
---|
516 | {
|
---|
517 | CHAR16 *HelpStr;
|
---|
518 |
|
---|
519 | HelpStr = ShellCommandGetInternalCommandHelp (CommandString);
|
---|
520 |
|
---|
521 | if (HelpStr == NULL) {
|
---|
522 | HelpStr = ShellCommandGetDynamicCommandHelp (CommandString);
|
---|
523 | }
|
---|
524 |
|
---|
525 | return HelpStr;
|
---|
526 | }
|
---|
527 |
|
---|
528 | /**
|
---|
529 | Registers handlers of type SHELL_RUN_COMMAND and
|
---|
530 | SHELL_GET_MAN_FILENAME for each shell command.
|
---|
531 |
|
---|
532 | If the ShellSupportLevel is greater than the value of the
|
---|
533 | PcdShellSupportLevel then return RETURN_UNSUPPORTED.
|
---|
534 |
|
---|
535 | Registers the handlers specified by GetHelpInfoHandler and CommandHandler
|
---|
536 | with the command specified by CommandString. If the command named by
|
---|
537 | CommandString has already been registered, then return
|
---|
538 | RETURN_ALREADY_STARTED.
|
---|
539 |
|
---|
540 | If there are not enough resources available to register the handlers then
|
---|
541 | RETURN_OUT_OF_RESOURCES is returned.
|
---|
542 |
|
---|
543 | If CommandString is NULL, then ASSERT().
|
---|
544 | If GetHelpInfoHandler is NULL, then ASSERT().
|
---|
545 | If CommandHandler is NULL, then ASSERT().
|
---|
546 | If ProfileName is NULL, then ASSERT().
|
---|
547 |
|
---|
548 | @param[in] CommandString Pointer to the command name. This is the
|
---|
549 | name to look for on the command line in
|
---|
550 | the shell.
|
---|
551 | @param[in] CommandHandler Pointer to a function that runs the
|
---|
552 | specified command.
|
---|
553 | @param[in] GetManFileName Pointer to a function that provides man
|
---|
554 | filename.
|
---|
555 | @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
|
---|
556 | function.
|
---|
557 | @param[in] ProfileName profile name to require for support of this
|
---|
558 | function.
|
---|
559 | @param[in] CanAffectLE indicates whether this command's return value
|
---|
560 | can change the LASTERROR environment variable.
|
---|
561 | @param[in] HiiHandle Handle of this command's HII entry.
|
---|
562 | @param[in] ManFormatHelp HII locator for the help text.
|
---|
563 |
|
---|
564 | @retval RETURN_SUCCESS The handlers were registered.
|
---|
565 | @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
|
---|
566 | register the shell command.
|
---|
567 | @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
|
---|
568 | currently allowed support level.
|
---|
569 | @retval RETURN_ALREADY_STARTED The CommandString represents a command that
|
---|
570 | is already registered. Only 1 handler set for
|
---|
571 | a given command is allowed.
|
---|
572 | @sa SHELL_GET_MAN_FILENAME
|
---|
573 | @sa SHELL_RUN_COMMAND
|
---|
574 | **/
|
---|
575 | RETURN_STATUS
|
---|
576 | EFIAPI
|
---|
577 | ShellCommandRegisterCommandName (
|
---|
578 | IN CONST CHAR16 *CommandString,
|
---|
579 | IN SHELL_RUN_COMMAND CommandHandler,
|
---|
580 | IN SHELL_GET_MAN_FILENAME GetManFileName,
|
---|
581 | IN UINT32 ShellMinSupportLevel,
|
---|
582 | IN CONST CHAR16 *ProfileName,
|
---|
583 | IN CONST BOOLEAN CanAffectLE,
|
---|
584 | IN CONST EFI_HII_HANDLE HiiHandle,
|
---|
585 | IN CONST EFI_STRING_ID ManFormatHelp
|
---|
586 | )
|
---|
587 | {
|
---|
588 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
589 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;
|
---|
590 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;
|
---|
591 | INTN LexicalMatchValue;
|
---|
592 |
|
---|
593 | //
|
---|
594 | // Initialize local variables.
|
---|
595 | //
|
---|
596 | Command = NULL;
|
---|
597 | PrevCommand = NULL;
|
---|
598 | LexicalMatchValue = 0;
|
---|
599 |
|
---|
600 | //
|
---|
601 | // ASSERTs for NULL parameters
|
---|
602 | //
|
---|
603 | ASSERT (CommandString != NULL);
|
---|
604 | ASSERT (GetManFileName != NULL);
|
---|
605 | ASSERT (CommandHandler != NULL);
|
---|
606 | ASSERT (ProfileName != NULL);
|
---|
607 |
|
---|
608 | //
|
---|
609 | // check for shell support level
|
---|
610 | //
|
---|
611 | if (PcdGet8 (PcdShellSupportLevel) < ShellMinSupportLevel) {
|
---|
612 | return (RETURN_UNSUPPORTED);
|
---|
613 | }
|
---|
614 |
|
---|
615 | //
|
---|
616 | // check for already on the list
|
---|
617 | //
|
---|
618 | if (ShellCommandIsCommandOnList (CommandString)) {
|
---|
619 | return (RETURN_ALREADY_STARTED);
|
---|
620 | }
|
---|
621 |
|
---|
622 | //
|
---|
623 | // allocate memory for new struct
|
---|
624 | //
|
---|
625 | Node = AllocateZeroPool (sizeof (SHELL_COMMAND_INTERNAL_LIST_ENTRY));
|
---|
626 | if (Node == NULL) {
|
---|
627 | return RETURN_OUT_OF_RESOURCES;
|
---|
628 | }
|
---|
629 |
|
---|
630 | Node->CommandString = AllocateCopyPool (StrSize (CommandString), CommandString);
|
---|
631 | if (Node->CommandString == NULL) {
|
---|
632 | FreePool (Node);
|
---|
633 | return RETURN_OUT_OF_RESOURCES;
|
---|
634 | }
|
---|
635 |
|
---|
636 | Node->GetManFileName = GetManFileName;
|
---|
637 | Node->CommandHandler = CommandHandler;
|
---|
638 | Node->LastError = CanAffectLE;
|
---|
639 | Node->HiiHandle = HiiHandle;
|
---|
640 | Node->ManFormatHelp = ManFormatHelp;
|
---|
641 |
|
---|
642 | if ( (StrLen (ProfileName) > 0)
|
---|
643 | && (( (mProfileList != NULL)
|
---|
644 | && (StrStr (mProfileList, ProfileName) == NULL)) || (mProfileList == NULL))
|
---|
645 | )
|
---|
646 | {
|
---|
647 | ASSERT ((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));
|
---|
648 | if (mProfileList == NULL) {
|
---|
649 | //
|
---|
650 | // If this is the first make a leading ';'
|
---|
651 | //
|
---|
652 | StrnCatGrow (&mProfileList, &mProfileListSize, L";", 0);
|
---|
653 | }
|
---|
654 |
|
---|
655 | StrnCatGrow (&mProfileList, &mProfileListSize, ProfileName, 0);
|
---|
656 | StrnCatGrow (&mProfileList, &mProfileListSize, L";", 0);
|
---|
657 | }
|
---|
658 |
|
---|
659 | //
|
---|
660 | // Insert a new entry on top of the list
|
---|
661 | //
|
---|
662 | InsertHeadList (&mCommandList.Link, &Node->Link);
|
---|
663 |
|
---|
664 | //
|
---|
665 | // Move a new registered command to its sorted ordered location in the list
|
---|
666 | //
|
---|
667 | for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),
|
---|
668 | PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
---|
669 | ; !IsNull (&mCommandList.Link, &Command->Link)
|
---|
670 | ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link))
|
---|
671 | {
|
---|
672 | //
|
---|
673 | // Get Lexical Comparison Value between PrevCommand and Command list entry
|
---|
674 | //
|
---|
675 | LexicalMatchValue = gUnicodeCollation->StriColl (
|
---|
676 | gUnicodeCollation,
|
---|
677 | PrevCommand->CommandString,
|
---|
678 | Command->CommandString
|
---|
679 | );
|
---|
680 |
|
---|
681 | //
|
---|
682 | // Swap PrevCommand and Command list entry if PrevCommand list entry
|
---|
683 | // is alphabetically greater than Command list entry
|
---|
684 | //
|
---|
685 | if (LexicalMatchValue > 0) {
|
---|
686 | Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)SwapListEntries (&PrevCommand->Link, &Command->Link);
|
---|
687 | } else if (LexicalMatchValue < 0) {
|
---|
688 | //
|
---|
689 | // PrevCommand entry is lexically lower than Command entry
|
---|
690 | //
|
---|
691 | break;
|
---|
692 | }
|
---|
693 | }
|
---|
694 |
|
---|
695 | return (RETURN_SUCCESS);
|
---|
696 | }
|
---|
697 |
|
---|
698 | /**
|
---|
699 | Function to get the current Profile string.
|
---|
700 |
|
---|
701 | @retval NULL There are no installed profiles.
|
---|
702 | @return A semi-colon delimited list of profiles.
|
---|
703 | **/
|
---|
704 | CONST CHAR16 *
|
---|
705 | EFIAPI
|
---|
706 | ShellCommandGetProfileList (
|
---|
707 | VOID
|
---|
708 | )
|
---|
709 | {
|
---|
710 | return (mProfileList);
|
---|
711 | }
|
---|
712 |
|
---|
713 | /**
|
---|
714 | Checks if a command string has been registered for CommandString and if so it runs
|
---|
715 | the previously registered handler for that command with the command line.
|
---|
716 |
|
---|
717 | If CommandString is NULL, then ASSERT().
|
---|
718 |
|
---|
719 | If Sections is specified, then each section name listed will be compared in a casesensitive
|
---|
720 | manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
|
---|
721 | it will be appended to the returned help text. If the section does not exist, no
|
---|
722 | information will be returned. If Sections is NULL, then all help text information
|
---|
723 | available will be returned.
|
---|
724 |
|
---|
725 | @param[in] CommandString Pointer to the command name. This is the name
|
---|
726 | found on the command line in the shell.
|
---|
727 | @param[in, out] RetVal Pointer to the return vaule from the command handler.
|
---|
728 |
|
---|
729 | @param[in, out] CanAffectLE indicates whether this command's return value
|
---|
730 | needs to be placed into LASTERROR environment variable.
|
---|
731 |
|
---|
732 | @retval RETURN_SUCCESS The handler was run.
|
---|
733 | @retval RETURN_NOT_FOUND The CommandString did not match a registered
|
---|
734 | command name.
|
---|
735 | @sa SHELL_RUN_COMMAND
|
---|
736 | **/
|
---|
737 | RETURN_STATUS
|
---|
738 | EFIAPI
|
---|
739 | ShellCommandRunCommandHandler (
|
---|
740 | IN CONST CHAR16 *CommandString,
|
---|
741 | IN OUT SHELL_STATUS *RetVal,
|
---|
742 | IN OUT BOOLEAN *CanAffectLE OPTIONAL
|
---|
743 | )
|
---|
744 | {
|
---|
745 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
746 | EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;
|
---|
747 |
|
---|
748 | //
|
---|
749 | // assert for NULL parameters
|
---|
750 | //
|
---|
751 | ASSERT (CommandString != NULL);
|
---|
752 |
|
---|
753 | //
|
---|
754 | // check for the command
|
---|
755 | //
|
---|
756 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
---|
757 | ; !IsNull (&mCommandList.Link, &Node->Link)
|
---|
758 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Node->Link)
|
---|
759 | )
|
---|
760 | {
|
---|
761 | ASSERT (Node->CommandString != NULL);
|
---|
762 | if (gUnicodeCollation->StriColl (
|
---|
763 | gUnicodeCollation,
|
---|
764 | (CHAR16 *)CommandString,
|
---|
765 | Node->CommandString
|
---|
766 | ) == 0
|
---|
767 | )
|
---|
768 | {
|
---|
769 | if (CanAffectLE != NULL) {
|
---|
770 | *CanAffectLE = Node->LastError;
|
---|
771 | }
|
---|
772 |
|
---|
773 | if (RetVal != NULL) {
|
---|
774 | *RetVal = Node->CommandHandler (NULL, gST);
|
---|
775 | } else {
|
---|
776 | Node->CommandHandler (NULL, gST);
|
---|
777 | }
|
---|
778 |
|
---|
779 | return (RETURN_SUCCESS);
|
---|
780 | }
|
---|
781 | }
|
---|
782 |
|
---|
783 | //
|
---|
784 | // An internal command was not found, try to find a dynamic command
|
---|
785 | //
|
---|
786 | DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand (CommandString);
|
---|
787 | if (DynamicCommand != NULL) {
|
---|
788 | if (RetVal != NULL) {
|
---|
789 | *RetVal = DynamicCommand->Handler (DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
|
---|
790 | } else {
|
---|
791 | DynamicCommand->Handler (DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);
|
---|
792 | }
|
---|
793 |
|
---|
794 | return (RETURN_SUCCESS);
|
---|
795 | }
|
---|
796 |
|
---|
797 | return (RETURN_NOT_FOUND);
|
---|
798 | }
|
---|
799 |
|
---|
800 | /**
|
---|
801 | Checks if a command string has been registered for CommandString and if so it
|
---|
802 | returns the MAN filename specified for that command.
|
---|
803 |
|
---|
804 | If CommandString is NULL, then ASSERT().
|
---|
805 |
|
---|
806 | @param[in] CommandString Pointer to the command name. This is the name
|
---|
807 | found on the command line in the shell.\
|
---|
808 |
|
---|
809 | @retval NULL the commandString was not a registered command.
|
---|
810 | @return other the name of the MAN file.
|
---|
811 | @sa SHELL_GET_MAN_FILENAME
|
---|
812 | **/
|
---|
813 | CONST CHAR16 *
|
---|
814 | EFIAPI
|
---|
815 | ShellCommandGetManFileNameHandler (
|
---|
816 | IN CONST CHAR16 *CommandString
|
---|
817 | )
|
---|
818 | {
|
---|
819 | SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
|
---|
820 |
|
---|
821 | //
|
---|
822 | // assert for NULL parameters
|
---|
823 | //
|
---|
824 | ASSERT (CommandString != NULL);
|
---|
825 |
|
---|
826 | //
|
---|
827 | // check for the command
|
---|
828 | //
|
---|
829 | for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)
|
---|
830 | ; !IsNull (&mCommandList.Link, &Node->Link)
|
---|
831 | ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Node->Link)
|
---|
832 | )
|
---|
833 | {
|
---|
834 | ASSERT (Node->CommandString != NULL);
|
---|
835 | if (gUnicodeCollation->StriColl (
|
---|
836 | gUnicodeCollation,
|
---|
837 | (CHAR16 *)CommandString,
|
---|
838 | Node->CommandString
|
---|
839 | ) == 0
|
---|
840 | )
|
---|
841 | {
|
---|
842 | return (Node->GetManFileName ());
|
---|
843 | }
|
---|
844 | }
|
---|
845 |
|
---|
846 | return (NULL);
|
---|
847 | }
|
---|
848 |
|
---|
849 | /**
|
---|
850 | Get the list of all available shell internal commands. This is a linked list
|
---|
851 | (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
|
---|
852 | list functions. do not modify the values.
|
---|
853 |
|
---|
854 | @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
|
---|
855 |
|
---|
856 | @return a Linked list of all available shell commands.
|
---|
857 | **/
|
---|
858 | CONST COMMAND_LIST *
|
---|
859 | EFIAPI
|
---|
860 | ShellCommandGetCommandList (
|
---|
861 | IN CONST BOOLEAN Sort
|
---|
862 | )
|
---|
863 | {
|
---|
864 | // if (!Sort) {
|
---|
865 | // return ((COMMAND_LIST*)(&mCommandList));
|
---|
866 | // }
|
---|
867 | return ((COMMAND_LIST *)(&mCommandList));
|
---|
868 | }
|
---|
869 |
|
---|
870 | /**
|
---|
871 | Registers aliases to be set as part of the initialization of the shell application.
|
---|
872 |
|
---|
873 | If Command is NULL, then ASSERT().
|
---|
874 | If Alias is NULL, then ASSERT().
|
---|
875 |
|
---|
876 | @param[in] Command Pointer to the Command
|
---|
877 | @param[in] Alias Pointer to Alias
|
---|
878 |
|
---|
879 | @retval RETURN_SUCCESS The handlers were registered.
|
---|
880 | @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
|
---|
881 | register the shell command.
|
---|
882 | **/
|
---|
883 | RETURN_STATUS
|
---|
884 | EFIAPI
|
---|
885 | ShellCommandRegisterAlias (
|
---|
886 | IN CONST CHAR16 *Command,
|
---|
887 | IN CONST CHAR16 *Alias
|
---|
888 | )
|
---|
889 | {
|
---|
890 | ALIAS_LIST *Node;
|
---|
891 | ALIAS_LIST *CommandAlias;
|
---|
892 | ALIAS_LIST *PrevCommandAlias;
|
---|
893 | INTN LexicalMatchValue;
|
---|
894 |
|
---|
895 | //
|
---|
896 | // Asserts for NULL
|
---|
897 | //
|
---|
898 | ASSERT (Command != NULL);
|
---|
899 | ASSERT (Alias != NULL);
|
---|
900 |
|
---|
901 | //
|
---|
902 | // allocate memory for new struct
|
---|
903 | //
|
---|
904 | Node = AllocateZeroPool (sizeof (ALIAS_LIST));
|
---|
905 | if (Node == NULL) {
|
---|
906 | return RETURN_OUT_OF_RESOURCES;
|
---|
907 | }
|
---|
908 |
|
---|
909 | Node->CommandString = AllocateCopyPool (StrSize (Command), Command);
|
---|
910 | if (Node->CommandString == NULL) {
|
---|
911 | FreePool (Node);
|
---|
912 | return RETURN_OUT_OF_RESOURCES;
|
---|
913 | }
|
---|
914 |
|
---|
915 | Node->Alias = AllocateCopyPool (StrSize (Alias), Alias);
|
---|
916 | if (Node->Alias == NULL) {
|
---|
917 | FreePool (Node->CommandString);
|
---|
918 | FreePool (Node);
|
---|
919 | return RETURN_OUT_OF_RESOURCES;
|
---|
920 | }
|
---|
921 |
|
---|
922 | InsertHeadList (&mAliasList.Link, &Node->Link);
|
---|
923 |
|
---|
924 | //
|
---|
925 | // Move a new pre-defined registered alias to its sorted ordered location in the list
|
---|
926 | //
|
---|
927 | for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),
|
---|
928 | PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)
|
---|
929 | ; !IsNull (&mAliasList.Link, &CommandAlias->Link)
|
---|
930 | ; CommandAlias = (ALIAS_LIST *)GetNextNode (&mAliasList.Link, &CommandAlias->Link))
|
---|
931 | {
|
---|
932 | //
|
---|
933 | // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
|
---|
934 | //
|
---|
935 | LexicalMatchValue = gUnicodeCollation->StriColl (
|
---|
936 | gUnicodeCollation,
|
---|
937 | PrevCommandAlias->Alias,
|
---|
938 | CommandAlias->Alias
|
---|
939 | );
|
---|
940 |
|
---|
941 | //
|
---|
942 | // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
|
---|
943 | // is alphabetically greater than CommandAlias list entry
|
---|
944 | //
|
---|
945 | if (LexicalMatchValue > 0) {
|
---|
946 | CommandAlias = (ALIAS_LIST *)SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);
|
---|
947 | } else if (LexicalMatchValue < 0) {
|
---|
948 | //
|
---|
949 | // PrevCommandAlias entry is lexically lower than CommandAlias entry
|
---|
950 | //
|
---|
951 | break;
|
---|
952 | }
|
---|
953 | }
|
---|
954 |
|
---|
955 | return (RETURN_SUCCESS);
|
---|
956 | }
|
---|
957 |
|
---|
958 | /**
|
---|
959 | Get the list of all shell alias commands. This is a linked list
|
---|
960 | (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
|
---|
961 | list functions. do not modify the values.
|
---|
962 |
|
---|
963 | @return a Linked list of all requested shell alias'.
|
---|
964 | **/
|
---|
965 | CONST ALIAS_LIST *
|
---|
966 | EFIAPI
|
---|
967 | ShellCommandGetInitAliasList (
|
---|
968 | VOID
|
---|
969 | )
|
---|
970 | {
|
---|
971 | return (&mAliasList);
|
---|
972 | }
|
---|
973 |
|
---|
974 | /**
|
---|
975 | Determine if a given alias is on the list of built in alias'.
|
---|
976 |
|
---|
977 | @param[in] Alias The alias to test for
|
---|
978 |
|
---|
979 | @retval TRUE The alias is a built in alias
|
---|
980 | @retval FALSE The alias is not a built in alias
|
---|
981 | **/
|
---|
982 | BOOLEAN
|
---|
983 | EFIAPI
|
---|
984 | ShellCommandIsOnAliasList (
|
---|
985 | IN CONST CHAR16 *Alias
|
---|
986 | )
|
---|
987 | {
|
---|
988 | ALIAS_LIST *Node;
|
---|
989 |
|
---|
990 | //
|
---|
991 | // assert for NULL parameter
|
---|
992 | //
|
---|
993 | ASSERT (Alias != NULL);
|
---|
994 |
|
---|
995 | //
|
---|
996 | // check for the Alias
|
---|
997 | //
|
---|
998 | for ( Node = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)
|
---|
999 | ; !IsNull (&mAliasList.Link, &Node->Link)
|
---|
1000 | ; Node = (ALIAS_LIST *)GetNextNode (&mAliasList.Link, &Node->Link)
|
---|
1001 | )
|
---|
1002 | {
|
---|
1003 | ASSERT (Node->CommandString != NULL);
|
---|
1004 | ASSERT (Node->Alias != NULL);
|
---|
1005 | if (gUnicodeCollation->StriColl (
|
---|
1006 | gUnicodeCollation,
|
---|
1007 | (CHAR16 *)Alias,
|
---|
1008 | Node->CommandString
|
---|
1009 | ) == 0
|
---|
1010 | )
|
---|
1011 | {
|
---|
1012 | return (TRUE);
|
---|
1013 | }
|
---|
1014 |
|
---|
1015 | if (gUnicodeCollation->StriColl (
|
---|
1016 | gUnicodeCollation,
|
---|
1017 | (CHAR16 *)Alias,
|
---|
1018 | Node->Alias
|
---|
1019 | ) == 0
|
---|
1020 | )
|
---|
1021 | {
|
---|
1022 | return (TRUE);
|
---|
1023 | }
|
---|
1024 | }
|
---|
1025 |
|
---|
1026 | return (FALSE);
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | /**
|
---|
1030 | Function to determine current state of ECHO. Echo determines if lines from scripts
|
---|
1031 | and ECHO commands are enabled.
|
---|
1032 |
|
---|
1033 | @retval TRUE Echo is currently enabled
|
---|
1034 | @retval FALSE Echo is currently disabled
|
---|
1035 | **/
|
---|
1036 | BOOLEAN
|
---|
1037 | EFIAPI
|
---|
1038 | ShellCommandGetEchoState (
|
---|
1039 | VOID
|
---|
1040 | )
|
---|
1041 | {
|
---|
1042 | return (mEchoState);
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | /**
|
---|
1046 | Function to set current state of ECHO. Echo determines if lines from scripts
|
---|
1047 | and ECHO commands are enabled.
|
---|
1048 |
|
---|
1049 | If State is TRUE, Echo will be enabled.
|
---|
1050 | If State is FALSE, Echo will be disabled.
|
---|
1051 |
|
---|
1052 | @param[in] State How to set echo.
|
---|
1053 | **/
|
---|
1054 | VOID
|
---|
1055 | EFIAPI
|
---|
1056 | ShellCommandSetEchoState (
|
---|
1057 | IN BOOLEAN State
|
---|
1058 | )
|
---|
1059 | {
|
---|
1060 | mEchoState = State;
|
---|
1061 | }
|
---|
1062 |
|
---|
1063 | /**
|
---|
1064 | Indicate that the current shell or script should exit.
|
---|
1065 |
|
---|
1066 | @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
|
---|
1067 | @param[in] ErrorCode The 64 bit error code to return.
|
---|
1068 | **/
|
---|
1069 | VOID
|
---|
1070 | EFIAPI
|
---|
1071 | ShellCommandRegisterExit (
|
---|
1072 | IN BOOLEAN ScriptOnly,
|
---|
1073 | IN CONST UINT64 ErrorCode
|
---|
1074 | )
|
---|
1075 | {
|
---|
1076 | mExitRequested = (BOOLEAN)(!mExitRequested);
|
---|
1077 | if (mExitRequested) {
|
---|
1078 | mExitScript = ScriptOnly;
|
---|
1079 | } else {
|
---|
1080 | mExitScript = FALSE;
|
---|
1081 | }
|
---|
1082 |
|
---|
1083 | mExitCode = ErrorCode;
|
---|
1084 | }
|
---|
1085 |
|
---|
1086 | /**
|
---|
1087 | Retrieve the Exit indicator.
|
---|
1088 |
|
---|
1089 | @retval TRUE Exit was indicated.
|
---|
1090 | @retval FALSE Exis was not indicated.
|
---|
1091 | **/
|
---|
1092 | BOOLEAN
|
---|
1093 | EFIAPI
|
---|
1094 | ShellCommandGetExit (
|
---|
1095 | VOID
|
---|
1096 | )
|
---|
1097 | {
|
---|
1098 | return (mExitRequested);
|
---|
1099 | }
|
---|
1100 |
|
---|
1101 | /**
|
---|
1102 | Retrieve the Exit code.
|
---|
1103 |
|
---|
1104 | If ShellCommandGetExit returns FALSE than the return from this is undefined.
|
---|
1105 |
|
---|
1106 | @return the value passed into RegisterExit.
|
---|
1107 | **/
|
---|
1108 | UINT64
|
---|
1109 | EFIAPI
|
---|
1110 | ShellCommandGetExitCode (
|
---|
1111 | VOID
|
---|
1112 | )
|
---|
1113 | {
|
---|
1114 | return (mExitCode);
|
---|
1115 | }
|
---|
1116 |
|
---|
1117 | /**
|
---|
1118 | Retrieve the Exit script indicator.
|
---|
1119 |
|
---|
1120 | If ShellCommandGetExit returns FALSE than the return from this is undefined.
|
---|
1121 |
|
---|
1122 | @retval TRUE ScriptOnly was indicated.
|
---|
1123 | @retval FALSE ScriptOnly was not indicated.
|
---|
1124 | **/
|
---|
1125 | BOOLEAN
|
---|
1126 | EFIAPI
|
---|
1127 | ShellCommandGetScriptExit (
|
---|
1128 | VOID
|
---|
1129 | )
|
---|
1130 | {
|
---|
1131 | return (mExitScript);
|
---|
1132 | }
|
---|
1133 |
|
---|
1134 | /**
|
---|
1135 | Function to cleanup all memory from a SCRIPT_FILE structure.
|
---|
1136 |
|
---|
1137 | @param[in] Script The pointer to the structure to cleanup.
|
---|
1138 | **/
|
---|
1139 | VOID
|
---|
1140 | EFIAPI
|
---|
1141 | DeleteScriptFileStruct (
|
---|
1142 | IN SCRIPT_FILE *Script
|
---|
1143 | )
|
---|
1144 | {
|
---|
1145 | UINTN LoopVar;
|
---|
1146 |
|
---|
1147 | if (Script == NULL) {
|
---|
1148 | return;
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | for (LoopVar = 0; LoopVar < Script->Argc; LoopVar++) {
|
---|
1152 | SHELL_FREE_NON_NULL (Script->Argv[LoopVar]);
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | if (Script->Argv != NULL) {
|
---|
1156 | SHELL_FREE_NON_NULL (Script->Argv);
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | Script->CurrentCommand = NULL;
|
---|
1160 | while (!IsListEmpty (&Script->CommandList)) {
|
---|
1161 | Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode (&Script->CommandList);
|
---|
1162 | if (Script->CurrentCommand != NULL) {
|
---|
1163 | RemoveEntryList (&Script->CurrentCommand->Link);
|
---|
1164 | if (Script->CurrentCommand->Cl != NULL) {
|
---|
1165 | SHELL_FREE_NON_NULL (Script->CurrentCommand->Cl);
|
---|
1166 | }
|
---|
1167 |
|
---|
1168 | if (Script->CurrentCommand->Data != NULL) {
|
---|
1169 | SHELL_FREE_NON_NULL (Script->CurrentCommand->Data);
|
---|
1170 | }
|
---|
1171 |
|
---|
1172 | SHELL_FREE_NON_NULL (Script->CurrentCommand);
|
---|
1173 | }
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | SHELL_FREE_NON_NULL (Script->ScriptName);
|
---|
1177 | SHELL_FREE_NON_NULL (Script);
|
---|
1178 | }
|
---|
1179 |
|
---|
1180 | /**
|
---|
1181 | Function to return a pointer to the currently running script file object.
|
---|
1182 |
|
---|
1183 | @retval NULL A script file is not currently running.
|
---|
1184 | @return A pointer to the current script file object.
|
---|
1185 | **/
|
---|
1186 | SCRIPT_FILE *
|
---|
1187 | EFIAPI
|
---|
1188 | ShellCommandGetCurrentScriptFile (
|
---|
1189 | VOID
|
---|
1190 | )
|
---|
1191 | {
|
---|
1192 | SCRIPT_FILE_LIST *List;
|
---|
1193 |
|
---|
1194 | if (IsListEmpty (&mScriptList.Link)) {
|
---|
1195 | return (NULL);
|
---|
1196 | }
|
---|
1197 |
|
---|
1198 | List = ((SCRIPT_FILE_LIST *)GetFirstNode (&mScriptList.Link));
|
---|
1199 | return (List->Data);
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | /**
|
---|
1203 | Function to set a new script as the currently running one.
|
---|
1204 |
|
---|
1205 | This function will correctly stack and unstack nested scripts.
|
---|
1206 |
|
---|
1207 | @param[in] Script Pointer to new script information structure. if NULL
|
---|
1208 | will remove and de-allocate the top-most Script structure.
|
---|
1209 |
|
---|
1210 | @return A pointer to the current running script file after this
|
---|
1211 | change. NULL if removing the final script.
|
---|
1212 | **/
|
---|
1213 | SCRIPT_FILE *
|
---|
1214 | EFIAPI
|
---|
1215 | ShellCommandSetNewScript (
|
---|
1216 | IN SCRIPT_FILE *Script OPTIONAL
|
---|
1217 | )
|
---|
1218 | {
|
---|
1219 | SCRIPT_FILE_LIST *Node;
|
---|
1220 |
|
---|
1221 | if (Script == NULL) {
|
---|
1222 | if (IsListEmpty (&mScriptList.Link)) {
|
---|
1223 | return (NULL);
|
---|
1224 | }
|
---|
1225 |
|
---|
1226 | Node = (SCRIPT_FILE_LIST *)GetFirstNode (&mScriptList.Link);
|
---|
1227 | RemoveEntryList (&Node->Link);
|
---|
1228 | DeleteScriptFileStruct (Node->Data);
|
---|
1229 | FreePool (Node);
|
---|
1230 | } else {
|
---|
1231 | Node = AllocateZeroPool (sizeof (SCRIPT_FILE_LIST));
|
---|
1232 | if (Node == NULL) {
|
---|
1233 | return (NULL);
|
---|
1234 | }
|
---|
1235 |
|
---|
1236 | Node->Data = Script;
|
---|
1237 | InsertHeadList (&mScriptList.Link, &Node->Link);
|
---|
1238 | }
|
---|
1239 |
|
---|
1240 | return (ShellCommandGetCurrentScriptFile ());
|
---|
1241 | }
|
---|
1242 |
|
---|
1243 | /**
|
---|
1244 | Function to generate the next default mapping name.
|
---|
1245 |
|
---|
1246 | If the return value is not NULL then it must be callee freed.
|
---|
1247 |
|
---|
1248 | @param Type What kind of mapping name to make.
|
---|
1249 |
|
---|
1250 | @retval NULL a memory allocation failed.
|
---|
1251 | @return a new map name string
|
---|
1252 | **/
|
---|
1253 | CHAR16 *
|
---|
1254 | EFIAPI
|
---|
1255 | ShellCommandCreateNewMappingName (
|
---|
1256 | IN CONST SHELL_MAPPING_TYPE Type
|
---|
1257 | )
|
---|
1258 | {
|
---|
1259 | CHAR16 *String;
|
---|
1260 |
|
---|
1261 | ASSERT (Type < MappingTypeMax);
|
---|
1262 |
|
---|
1263 | String = NULL;
|
---|
1264 |
|
---|
1265 | String = AllocateZeroPool (PcdGet8 (PcdShellMapNameLength) * sizeof (String[0]));
|
---|
1266 | if (String == NULL) {
|
---|
1267 | return (NULL);
|
---|
1268 | }
|
---|
1269 |
|
---|
1270 | UnicodeSPrint (
|
---|
1271 | String,
|
---|
1272 | PcdGet8 (PcdShellMapNameLength) * sizeof (String[0]),
|
---|
1273 | Type == MappingTypeFileSystem ? L"FS%d:" : L"BLK%d:",
|
---|
1274 | Type == MappingTypeFileSystem ? mFsMaxCount++ : mBlkMaxCount++
|
---|
1275 | );
|
---|
1276 |
|
---|
1277 | return (String);
|
---|
1278 | }
|
---|
1279 |
|
---|
1280 | /**
|
---|
1281 | Function to add a map node to the list of map items and update the "path" environment variable (optionally).
|
---|
1282 |
|
---|
1283 | If Path is TRUE (during initialization only), the path environment variable will also be updated to include
|
---|
1284 | default paths on the new map name...
|
---|
1285 |
|
---|
1286 | Path should be FALSE when this function is called from the protocol SetMap function.
|
---|
1287 |
|
---|
1288 | @param[in] Name The human readable mapped name.
|
---|
1289 | @param[in] DevicePath The Device Path for this map.
|
---|
1290 | @param[in] Flags The Flags attribute for this map item.
|
---|
1291 | @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
|
---|
1292 |
|
---|
1293 | @retval EFI_SUCCESS The addition was successful.
|
---|
1294 | @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
|
---|
1295 | @retval EFI_INVALID_PARAMETER A parameter was invalid.
|
---|
1296 | **/
|
---|
1297 | EFI_STATUS
|
---|
1298 | EFIAPI
|
---|
1299 | ShellCommandAddMapItemAndUpdatePath (
|
---|
1300 | IN CONST CHAR16 *Name,
|
---|
1301 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
---|
1302 | IN CONST UINT64 Flags,
|
---|
1303 | IN CONST BOOLEAN Path
|
---|
1304 | )
|
---|
1305 | {
|
---|
1306 | EFI_STATUS Status;
|
---|
1307 | SHELL_MAP_LIST *MapListNode;
|
---|
1308 | CONST CHAR16 *OriginalPath;
|
---|
1309 | CHAR16 *NewPath;
|
---|
1310 | UINTN NewPathSize;
|
---|
1311 |
|
---|
1312 | NewPathSize = 0;
|
---|
1313 | NewPath = NULL;
|
---|
1314 | OriginalPath = NULL;
|
---|
1315 | Status = EFI_SUCCESS;
|
---|
1316 |
|
---|
1317 | MapListNode = AllocateZeroPool (sizeof (SHELL_MAP_LIST));
|
---|
1318 | if (MapListNode == NULL) {
|
---|
1319 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1320 | } else {
|
---|
1321 | MapListNode->Flags = Flags;
|
---|
1322 | MapListNode->MapName = AllocateCopyPool (StrSize (Name), Name);
|
---|
1323 | MapListNode->DevicePath = DuplicateDevicePath (DevicePath);
|
---|
1324 | if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)) {
|
---|
1325 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1326 | } else {
|
---|
1327 | InsertTailList (&gShellMapList.Link, &MapListNode->Link);
|
---|
1328 | }
|
---|
1329 | }
|
---|
1330 |
|
---|
1331 | if (EFI_ERROR (Status)) {
|
---|
1332 | if (MapListNode != NULL) {
|
---|
1333 | if (MapListNode->DevicePath != NULL) {
|
---|
1334 | FreePool (MapListNode->DevicePath);
|
---|
1335 | }
|
---|
1336 |
|
---|
1337 | if (MapListNode->MapName != NULL) {
|
---|
1338 | FreePool (MapListNode->MapName);
|
---|
1339 | }
|
---|
1340 |
|
---|
1341 | FreePool (MapListNode);
|
---|
1342 | }
|
---|
1343 | } else if (Path) {
|
---|
1344 | //
|
---|
1345 | // Since there was no error and Path was TRUE
|
---|
1346 | // Now add the correct path for that mapping
|
---|
1347 | //
|
---|
1348 | OriginalPath = gEfiShellProtocol->GetEnv (L"path");
|
---|
1349 | ASSERT ((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));
|
---|
1350 | if (OriginalPath != NULL) {
|
---|
1351 | StrnCatGrow (&NewPath, &NewPathSize, OriginalPath, 0);
|
---|
1352 | StrnCatGrow (&NewPath, &NewPathSize, L";", 0);
|
---|
1353 | }
|
---|
1354 |
|
---|
1355 | StrnCatGrow (&NewPath, &NewPathSize, Name, 0);
|
---|
1356 | StrnCatGrow (&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
|
---|
1357 | StrnCatGrow (&NewPath, &NewPathSize, Name, 0);
|
---|
1358 | StrnCatGrow (&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
|
---|
1359 | StrnCatGrow (&NewPath, &NewPathSize, Name, 0);
|
---|
1360 | StrnCatGrow (&NewPath, &NewPathSize, L"\\", 0);
|
---|
1361 |
|
---|
1362 | Status = gEfiShellProtocol->SetEnv (L"path", NewPath, TRUE);
|
---|
1363 | ASSERT_EFI_ERROR (Status);
|
---|
1364 | FreePool (NewPath);
|
---|
1365 | }
|
---|
1366 |
|
---|
1367 | return (Status);
|
---|
1368 | }
|
---|
1369 |
|
---|
1370 | /**
|
---|
1371 | Creates the default map names for each device path in the system with
|
---|
1372 | a protocol depending on the Type.
|
---|
1373 |
|
---|
1374 | Creates the consistent map names for each device path in the system with
|
---|
1375 | a protocol depending on the Type.
|
---|
1376 |
|
---|
1377 | Note: This will reset all mappings in the system("map -r").
|
---|
1378 |
|
---|
1379 | Also sets up the default path environment variable if Type is FileSystem.
|
---|
1380 |
|
---|
1381 | @retval EFI_SUCCESS All map names were created successfully.
|
---|
1382 | @retval EFI_NOT_FOUND No protocols were found in the system.
|
---|
1383 | @return Error returned from gBS->LocateHandle().
|
---|
1384 |
|
---|
1385 | @sa LocateHandle
|
---|
1386 | **/
|
---|
1387 | EFI_STATUS
|
---|
1388 | EFIAPI
|
---|
1389 | ShellCommandCreateInitialMappingsAndPaths (
|
---|
1390 | VOID
|
---|
1391 | )
|
---|
1392 | {
|
---|
1393 | EFI_STATUS Status;
|
---|
1394 | EFI_HANDLE *HandleList;
|
---|
1395 | UINTN Count;
|
---|
1396 | EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
|
---|
1397 | CHAR16 *NewDefaultName;
|
---|
1398 | CHAR16 *NewConsistName;
|
---|
1399 | EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
|
---|
1400 | SHELL_MAP_LIST *MapListNode;
|
---|
1401 | CONST CHAR16 *CurDir;
|
---|
1402 | CHAR16 *SplitCurDir;
|
---|
1403 | CHAR16 *MapName;
|
---|
1404 | SHELL_MAP_LIST *MapListItem;
|
---|
1405 |
|
---|
1406 | ConsistMappingTable = NULL;
|
---|
1407 | SplitCurDir = NULL;
|
---|
1408 | MapName = NULL;
|
---|
1409 | MapListItem = NULL;
|
---|
1410 | HandleList = NULL;
|
---|
1411 |
|
---|
1412 | //
|
---|
1413 | // Reset the static members back to zero
|
---|
1414 | //
|
---|
1415 | mFsMaxCount = 0;
|
---|
1416 | mBlkMaxCount = 0;
|
---|
1417 |
|
---|
1418 | gEfiShellProtocol->SetEnv (L"path", L"", TRUE);
|
---|
1419 |
|
---|
1420 | //
|
---|
1421 | // First empty out the existing list.
|
---|
1422 | //
|
---|
1423 | if (!IsListEmpty (&gShellMapList.Link)) {
|
---|
1424 | for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)
|
---|
1425 | ; !IsListEmpty (&gShellMapList.Link)
|
---|
1426 | ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)
|
---|
1427 | )
|
---|
1428 | {
|
---|
1429 | RemoveEntryList (&MapListNode->Link);
|
---|
1430 | SHELL_FREE_NON_NULL (MapListNode->DevicePath);
|
---|
1431 | SHELL_FREE_NON_NULL (MapListNode->MapName);
|
---|
1432 | SHELL_FREE_NON_NULL (MapListNode->CurrentDirectoryPath);
|
---|
1433 | FreePool (MapListNode);
|
---|
1434 | } // for loop
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | //
|
---|
1438 | // Find each handle with Simple File System
|
---|
1439 | //
|
---|
1440 | HandleList = GetHandleListByProtocol (&gEfiSimpleFileSystemProtocolGuid);
|
---|
1441 | if (HandleList != NULL) {
|
---|
1442 | //
|
---|
1443 | // Do a count of the handles
|
---|
1444 | //
|
---|
1445 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1446 | }
|
---|
1447 |
|
---|
1448 | //
|
---|
1449 | // Get all Device Paths
|
---|
1450 | //
|
---|
1451 | DevicePathList = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL *) * Count);
|
---|
1452 | if (DevicePathList == NULL) {
|
---|
1453 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1454 | return EFI_OUT_OF_RESOURCES;
|
---|
1455 | }
|
---|
1456 |
|
---|
1457 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1458 | DevicePathList[Count] = DevicePathFromHandle (HandleList[Count]);
|
---|
1459 | }
|
---|
1460 |
|
---|
1461 | //
|
---|
1462 | // Sort all DevicePaths
|
---|
1463 | //
|
---|
1464 | PerformQuickSort (DevicePathList, Count, sizeof (EFI_DEVICE_PATH_PROTOCOL *), DevicePathCompare);
|
---|
1465 |
|
---|
1466 | Status = ShellCommandConsistMappingInitialize (&ConsistMappingTable);
|
---|
1467 | if (EFI_ERROR (Status)) {
|
---|
1468 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1469 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1470 | return Status;
|
---|
1471 | }
|
---|
1472 |
|
---|
1473 | //
|
---|
1474 | // Assign new Mappings to all...
|
---|
1475 | //
|
---|
1476 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1477 | //
|
---|
1478 | // Get default name first
|
---|
1479 | //
|
---|
1480 | NewDefaultName = ShellCommandCreateNewMappingName (MappingTypeFileSystem);
|
---|
1481 | if (NewDefaultName == NULL) {
|
---|
1482 | ASSERT (NewDefaultName != NULL);
|
---|
1483 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1484 | break;
|
---|
1485 | }
|
---|
1486 |
|
---|
1487 | Status = ShellCommandAddMapItemAndUpdatePath (NewDefaultName, DevicePathList[Count], 0, TRUE);
|
---|
1488 | ASSERT_EFI_ERROR (Status);
|
---|
1489 | FreePool (NewDefaultName);
|
---|
1490 |
|
---|
1491 | //
|
---|
1492 | // Now do consistent name
|
---|
1493 | //
|
---|
1494 | NewConsistName = ShellCommandConsistMappingGenMappingName (DevicePathList[Count], ConsistMappingTable);
|
---|
1495 | if (NewConsistName != NULL) {
|
---|
1496 | Status = ShellCommandAddMapItemAndUpdatePath (NewConsistName, DevicePathList[Count], 0, FALSE);
|
---|
1497 | ASSERT_EFI_ERROR (Status);
|
---|
1498 | FreePool (NewConsistName);
|
---|
1499 | }
|
---|
1500 | }
|
---|
1501 |
|
---|
1502 | if (ConsistMappingTable != NULL) {
|
---|
1503 | ShellCommandConsistMappingUnInitialize (ConsistMappingTable);
|
---|
1504 | }
|
---|
1505 |
|
---|
1506 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1507 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1508 |
|
---|
1509 | HandleList = NULL;
|
---|
1510 |
|
---|
1511 | //
|
---|
1512 | // gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,
|
---|
1513 | // all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,
|
---|
1514 | // after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.
|
---|
1515 | //
|
---|
1516 | if (gShellCurMapping != NULL) {
|
---|
1517 | gShellCurMapping = NULL;
|
---|
1518 | CurDir = gEfiShellProtocol->GetEnv (L"cwd");
|
---|
1519 | if (CurDir != NULL) {
|
---|
1520 | MapName = AllocateCopyPool (StrSize (CurDir), CurDir);
|
---|
1521 | if (MapName == NULL) {
|
---|
1522 | return EFI_OUT_OF_RESOURCES;
|
---|
1523 | }
|
---|
1524 |
|
---|
1525 | SplitCurDir = StrStr (MapName, L":");
|
---|
1526 | if (SplitCurDir == NULL) {
|
---|
1527 | SHELL_FREE_NON_NULL (MapName);
|
---|
1528 | return EFI_UNSUPPORTED;
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | *(SplitCurDir + 1) = CHAR_NULL;
|
---|
1532 | MapListItem = ShellCommandFindMapItem (MapName);
|
---|
1533 | if (MapListItem != NULL) {
|
---|
1534 | gShellCurMapping = MapListItem;
|
---|
1535 | }
|
---|
1536 |
|
---|
1537 | SHELL_FREE_NON_NULL (MapName);
|
---|
1538 | }
|
---|
1539 | }
|
---|
1540 | } else {
|
---|
1541 | Count = (UINTN)-1;
|
---|
1542 | }
|
---|
1543 |
|
---|
1544 | //
|
---|
1545 | // Find each handle with Block Io
|
---|
1546 | //
|
---|
1547 | HandleList = GetHandleListByProtocol (&gEfiBlockIoProtocolGuid);
|
---|
1548 | if (HandleList != NULL) {
|
---|
1549 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1550 | }
|
---|
1551 |
|
---|
1552 | //
|
---|
1553 | // Get all Device Paths
|
---|
1554 | //
|
---|
1555 | DevicePathList = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL *) * Count);
|
---|
1556 | if (DevicePathList == NULL) {
|
---|
1557 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1558 | return EFI_OUT_OF_RESOURCES;
|
---|
1559 | }
|
---|
1560 |
|
---|
1561 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1562 | DevicePathList[Count] = DevicePathFromHandle (HandleList[Count]);
|
---|
1563 | }
|
---|
1564 |
|
---|
1565 | //
|
---|
1566 | // Sort all DevicePaths
|
---|
1567 | //
|
---|
1568 | PerformQuickSort (DevicePathList, Count, sizeof (EFI_DEVICE_PATH_PROTOCOL *), DevicePathCompare);
|
---|
1569 |
|
---|
1570 | //
|
---|
1571 | // Assign new Mappings to all...
|
---|
1572 | //
|
---|
1573 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1574 | //
|
---|
1575 | // Get default name first
|
---|
1576 | //
|
---|
1577 | NewDefaultName = ShellCommandCreateNewMappingName (MappingTypeBlockIo);
|
---|
1578 | if (NewDefaultName == NULL) {
|
---|
1579 | ASSERT (NewDefaultName != NULL);
|
---|
1580 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1581 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1582 | return EFI_OUT_OF_RESOURCES;
|
---|
1583 | }
|
---|
1584 |
|
---|
1585 | Status = ShellCommandAddMapItemAndUpdatePath (NewDefaultName, DevicePathList[Count], 0, FALSE);
|
---|
1586 | ASSERT_EFI_ERROR (Status);
|
---|
1587 | FreePool (NewDefaultName);
|
---|
1588 | }
|
---|
1589 |
|
---|
1590 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1591 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1592 | } else if (Count == (UINTN)-1) {
|
---|
1593 | return (EFI_NOT_FOUND);
|
---|
1594 | }
|
---|
1595 |
|
---|
1596 | return (EFI_SUCCESS);
|
---|
1597 | }
|
---|
1598 |
|
---|
1599 | /**
|
---|
1600 | Add mappings for any devices without one. Do not change any existing maps.
|
---|
1601 |
|
---|
1602 | @retval EFI_SUCCESS The operation was successful.
|
---|
1603 | **/
|
---|
1604 | EFI_STATUS
|
---|
1605 | EFIAPI
|
---|
1606 | ShellCommandUpdateMapping (
|
---|
1607 | VOID
|
---|
1608 | )
|
---|
1609 | {
|
---|
1610 | EFI_STATUS Status;
|
---|
1611 | EFI_HANDLE *HandleList;
|
---|
1612 | UINTN Count;
|
---|
1613 | EFI_DEVICE_PATH_PROTOCOL **DevicePathList;
|
---|
1614 | CHAR16 *NewDefaultName;
|
---|
1615 | CHAR16 *NewConsistName;
|
---|
1616 | EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;
|
---|
1617 |
|
---|
1618 | HandleList = NULL;
|
---|
1619 | Status = EFI_SUCCESS;
|
---|
1620 |
|
---|
1621 | //
|
---|
1622 | // remove mappings that represent removed devices.
|
---|
1623 | //
|
---|
1624 |
|
---|
1625 | //
|
---|
1626 | // Find each handle with Simple File System
|
---|
1627 | //
|
---|
1628 | HandleList = GetHandleListByProtocol (&gEfiSimpleFileSystemProtocolGuid);
|
---|
1629 | if (HandleList != NULL) {
|
---|
1630 | //
|
---|
1631 | // Do a count of the handles
|
---|
1632 | //
|
---|
1633 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1634 | }
|
---|
1635 |
|
---|
1636 | //
|
---|
1637 | // Get all Device Paths
|
---|
1638 | //
|
---|
1639 | DevicePathList = AllocateZeroPool (sizeof (EFI_DEVICE_PATH_PROTOCOL *) * Count);
|
---|
1640 | if (DevicePathList == NULL) {
|
---|
1641 | return (EFI_OUT_OF_RESOURCES);
|
---|
1642 | }
|
---|
1643 |
|
---|
1644 | for (Count = 0; HandleList[Count] != NULL; Count++) {
|
---|
1645 | DevicePathList[Count] = DevicePathFromHandle (HandleList[Count]);
|
---|
1646 | }
|
---|
1647 |
|
---|
1648 | //
|
---|
1649 | // Sort all DevicePaths
|
---|
1650 | //
|
---|
1651 | PerformQuickSort (DevicePathList, Count, sizeof (EFI_DEVICE_PATH_PROTOCOL *), DevicePathCompare);
|
---|
1652 |
|
---|
1653 | Status = ShellCommandConsistMappingInitialize (&ConsistMappingTable);
|
---|
1654 | if (EFI_ERROR (Status)) {
|
---|
1655 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1656 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1657 | return Status;
|
---|
1658 | }
|
---|
1659 |
|
---|
1660 | //
|
---|
1661 | // Assign new Mappings to remainders
|
---|
1662 | //
|
---|
1663 | for (Count = 0; !EFI_ERROR (Status) && HandleList[Count] != NULL; Count++) {
|
---|
1664 | //
|
---|
1665 | // Skip ones that already have
|
---|
1666 | //
|
---|
1667 | if (gEfiShellProtocol->GetMapFromDevicePath (&DevicePathList[Count]) != NULL) {
|
---|
1668 | continue;
|
---|
1669 | }
|
---|
1670 |
|
---|
1671 | //
|
---|
1672 | // Get default name
|
---|
1673 | //
|
---|
1674 | NewDefaultName = ShellCommandCreateNewMappingName (MappingTypeFileSystem);
|
---|
1675 | if (NewDefaultName == NULL) {
|
---|
1676 | Status = EFI_OUT_OF_RESOURCES;
|
---|
1677 | break;
|
---|
1678 | }
|
---|
1679 |
|
---|
1680 | //
|
---|
1681 | // Call shell protocol SetMap function now...
|
---|
1682 | //
|
---|
1683 | Status = gEfiShellProtocol->SetMap (DevicePathList[Count], NewDefaultName);
|
---|
1684 |
|
---|
1685 | if (!EFI_ERROR (Status)) {
|
---|
1686 | //
|
---|
1687 | // Now do consistent name
|
---|
1688 | //
|
---|
1689 | NewConsistName = ShellCommandConsistMappingGenMappingName (DevicePathList[Count], ConsistMappingTable);
|
---|
1690 | if (NewConsistName != NULL) {
|
---|
1691 | Status = gEfiShellProtocol->SetMap (DevicePathList[Count], NewConsistName);
|
---|
1692 | FreePool (NewConsistName);
|
---|
1693 | }
|
---|
1694 | }
|
---|
1695 |
|
---|
1696 | FreePool (NewDefaultName);
|
---|
1697 | }
|
---|
1698 |
|
---|
1699 | ShellCommandConsistMappingUnInitialize (ConsistMappingTable);
|
---|
1700 | SHELL_FREE_NON_NULL (HandleList);
|
---|
1701 | SHELL_FREE_NON_NULL (DevicePathList);
|
---|
1702 |
|
---|
1703 | HandleList = NULL;
|
---|
1704 | } else {
|
---|
1705 | Count = (UINTN)-1;
|
---|
1706 | }
|
---|
1707 |
|
---|
1708 | //
|
---|
1709 | // Do it all over again for gEfiBlockIoProtocolGuid
|
---|
1710 | //
|
---|
1711 |
|
---|
1712 | return (Status);
|
---|
1713 | }
|
---|
1714 |
|
---|
1715 | /**
|
---|
1716 | Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
|
---|
1717 |
|
---|
1718 | @param[in] Handle The SHELL_FILE_HANDLE to convert.
|
---|
1719 |
|
---|
1720 | @return a EFI_FILE_PROTOCOL* representing the same file.
|
---|
1721 | **/
|
---|
1722 | EFI_FILE_PROTOCOL *
|
---|
1723 | EFIAPI
|
---|
1724 | ConvertShellHandleToEfiFileProtocol (
|
---|
1725 | IN CONST SHELL_FILE_HANDLE Handle
|
---|
1726 | )
|
---|
1727 | {
|
---|
1728 | return ((EFI_FILE_PROTOCOL *)(Handle));
|
---|
1729 | }
|
---|
1730 |
|
---|
1731 | /**
|
---|
1732 | Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
|
---|
1733 |
|
---|
1734 | @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
|
---|
1735 | @param[in] Path The path to the file for verification.
|
---|
1736 |
|
---|
1737 | @return A SHELL_FILE_HANDLE representing the same file.
|
---|
1738 | @retval NULL There was not enough memory.
|
---|
1739 | **/
|
---|
1740 | SHELL_FILE_HANDLE
|
---|
1741 | EFIAPI
|
---|
1742 | ConvertEfiFileProtocolToShellHandle (
|
---|
1743 | IN CONST EFI_FILE_PROTOCOL *Handle,
|
---|
1744 | IN CONST CHAR16 *Path
|
---|
1745 | )
|
---|
1746 | {
|
---|
1747 | SHELL_COMMAND_FILE_HANDLE *Buffer;
|
---|
1748 | BUFFER_LIST *NewNode;
|
---|
1749 |
|
---|
1750 | if (Path != NULL) {
|
---|
1751 | Buffer = AllocateZeroPool (sizeof (SHELL_COMMAND_FILE_HANDLE));
|
---|
1752 | if (Buffer == NULL) {
|
---|
1753 | return (NULL);
|
---|
1754 | }
|
---|
1755 |
|
---|
1756 | NewNode = AllocateZeroPool (sizeof (BUFFER_LIST));
|
---|
1757 | if (NewNode == NULL) {
|
---|
1758 | SHELL_FREE_NON_NULL (Buffer);
|
---|
1759 | return (NULL);
|
---|
1760 | }
|
---|
1761 |
|
---|
1762 | Buffer->FileHandle = (EFI_FILE_PROTOCOL *)Handle;
|
---|
1763 | Buffer->Path = StrnCatGrow (&Buffer->Path, NULL, Path, 0);
|
---|
1764 | if (Buffer->Path == NULL) {
|
---|
1765 | SHELL_FREE_NON_NULL (NewNode);
|
---|
1766 | SHELL_FREE_NON_NULL (Buffer);
|
---|
1767 | return (NULL);
|
---|
1768 | }
|
---|
1769 |
|
---|
1770 | NewNode->Buffer = Buffer;
|
---|
1771 |
|
---|
1772 | InsertHeadList (&mFileHandleList.Link, &NewNode->Link);
|
---|
1773 | }
|
---|
1774 |
|
---|
1775 | return ((SHELL_FILE_HANDLE)(Handle));
|
---|
1776 | }
|
---|
1777 |
|
---|
1778 | /**
|
---|
1779 | Find the path that was logged with the specified SHELL_FILE_HANDLE.
|
---|
1780 |
|
---|
1781 | @param[in] Handle The SHELL_FILE_HANDLE to query on.
|
---|
1782 |
|
---|
1783 | @return A pointer to the path for the file.
|
---|
1784 | **/
|
---|
1785 | CONST CHAR16 *
|
---|
1786 | EFIAPI
|
---|
1787 | ShellFileHandleGetPath (
|
---|
1788 | IN CONST SHELL_FILE_HANDLE Handle
|
---|
1789 | )
|
---|
1790 | {
|
---|
1791 | BUFFER_LIST *Node;
|
---|
1792 |
|
---|
1793 | for (Node = (BUFFER_LIST *)GetFirstNode (&mFileHandleList.Link)
|
---|
1794 | ; !IsNull (&mFileHandleList.Link, &Node->Link)
|
---|
1795 | ; Node = (BUFFER_LIST *)GetNextNode (&mFileHandleList.Link, &Node->Link)
|
---|
1796 | )
|
---|
1797 | {
|
---|
1798 | if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)) {
|
---|
1799 | return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
|
---|
1800 | }
|
---|
1801 | }
|
---|
1802 |
|
---|
1803 | return (NULL);
|
---|
1804 | }
|
---|
1805 |
|
---|
1806 | /**
|
---|
1807 | Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
|
---|
1808 |
|
---|
1809 | @param[in] Handle The SHELL_FILE_HANDLE to remove.
|
---|
1810 |
|
---|
1811 | @retval TRUE The item was removed.
|
---|
1812 | @retval FALSE The item was not found.
|
---|
1813 | **/
|
---|
1814 | BOOLEAN
|
---|
1815 | EFIAPI
|
---|
1816 | ShellFileHandleRemove (
|
---|
1817 | IN CONST SHELL_FILE_HANDLE Handle
|
---|
1818 | )
|
---|
1819 | {
|
---|
1820 | BUFFER_LIST *Node;
|
---|
1821 |
|
---|
1822 | for (Node = (BUFFER_LIST *)GetFirstNode (&mFileHandleList.Link)
|
---|
1823 | ; !IsNull (&mFileHandleList.Link, &Node->Link)
|
---|
1824 | ; Node = (BUFFER_LIST *)GetNextNode (&mFileHandleList.Link, &Node->Link)
|
---|
1825 | )
|
---|
1826 | {
|
---|
1827 | if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)) {
|
---|
1828 | RemoveEntryList (&Node->Link);
|
---|
1829 | SHELL_FREE_NON_NULL (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
|
---|
1830 | SHELL_FREE_NON_NULL (Node->Buffer);
|
---|
1831 | SHELL_FREE_NON_NULL (Node);
|
---|
1832 | return (TRUE);
|
---|
1833 | }
|
---|
1834 | }
|
---|
1835 |
|
---|
1836 | return (FALSE);
|
---|
1837 | }
|
---|
1838 |
|
---|
1839 | /**
|
---|
1840 | Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
|
---|
1841 |
|
---|
1842 | This will NOT work on directories.
|
---|
1843 |
|
---|
1844 | If Handle is NULL, then ASSERT.
|
---|
1845 |
|
---|
1846 | @param[in] Handle the file handle
|
---|
1847 |
|
---|
1848 | @retval TRUE the position is at the end of the file
|
---|
1849 | @retval FALSE the position is not at the end of the file
|
---|
1850 | **/
|
---|
1851 | BOOLEAN
|
---|
1852 | EFIAPI
|
---|
1853 | ShellFileHandleEof (
|
---|
1854 | IN SHELL_FILE_HANDLE Handle
|
---|
1855 | )
|
---|
1856 | {
|
---|
1857 | EFI_FILE_INFO *Info;
|
---|
1858 | UINT64 Pos;
|
---|
1859 | BOOLEAN RetVal;
|
---|
1860 |
|
---|
1861 | //
|
---|
1862 | // ASSERT if Handle is NULL
|
---|
1863 | //
|
---|
1864 | ASSERT (Handle != NULL);
|
---|
1865 |
|
---|
1866 | gEfiShellProtocol->GetFilePosition (Handle, &Pos);
|
---|
1867 | Info = gEfiShellProtocol->GetFileInfo (Handle);
|
---|
1868 | gEfiShellProtocol->SetFilePosition (Handle, Pos);
|
---|
1869 |
|
---|
1870 | if (Info == NULL) {
|
---|
1871 | return (FALSE);
|
---|
1872 | }
|
---|
1873 |
|
---|
1874 | if (Pos == Info->FileSize) {
|
---|
1875 | RetVal = TRUE;
|
---|
1876 | } else {
|
---|
1877 | RetVal = FALSE;
|
---|
1878 | }
|
---|
1879 |
|
---|
1880 | FreePool (Info);
|
---|
1881 |
|
---|
1882 | return (RetVal);
|
---|
1883 | }
|
---|
1884 |
|
---|
1885 | /**
|
---|
1886 | Frees any BUFFER_LIST defined type.
|
---|
1887 |
|
---|
1888 | @param[in] List The BUFFER_LIST object to free.
|
---|
1889 | **/
|
---|
1890 | VOID
|
---|
1891 | EFIAPI
|
---|
1892 | FreeBufferList (
|
---|
1893 | IN BUFFER_LIST *List
|
---|
1894 | )
|
---|
1895 | {
|
---|
1896 | BUFFER_LIST *BufferListEntry;
|
---|
1897 |
|
---|
1898 | if (List == NULL) {
|
---|
1899 | return;
|
---|
1900 | }
|
---|
1901 |
|
---|
1902 | //
|
---|
1903 | // enumerate through the buffer list and free all memory
|
---|
1904 | //
|
---|
1905 | for ( BufferListEntry = (BUFFER_LIST *)GetFirstNode (&List->Link)
|
---|
1906 | ; !IsListEmpty (&List->Link)
|
---|
1907 | ; BufferListEntry = (BUFFER_LIST *)GetFirstNode (&List->Link)
|
---|
1908 | )
|
---|
1909 | {
|
---|
1910 | RemoveEntryList (&BufferListEntry->Link);
|
---|
1911 | if (BufferListEntry->Buffer != NULL) {
|
---|
1912 | FreePool (BufferListEntry->Buffer);
|
---|
1913 | }
|
---|
1914 |
|
---|
1915 | FreePool (BufferListEntry);
|
---|
1916 | }
|
---|
1917 | }
|
---|
1918 |
|
---|
1919 | /**
|
---|
1920 | Dump some hexadecimal data to the screen.
|
---|
1921 |
|
---|
1922 | @param[in] Indent How many spaces to indent the output.
|
---|
1923 | @param[in] Offset The offset of the printing.
|
---|
1924 | @param[in] DataSize The size in bytes of UserData.
|
---|
1925 | @param[in] UserData The data to print out.
|
---|
1926 | **/
|
---|
1927 | VOID
|
---|
1928 | EFIAPI
|
---|
1929 | DumpHex (
|
---|
1930 | IN UINTN Indent,
|
---|
1931 | IN UINTN Offset,
|
---|
1932 | IN UINTN DataSize,
|
---|
1933 | IN VOID *UserData
|
---|
1934 | )
|
---|
1935 | {
|
---|
1936 | UINT8 *Data;
|
---|
1937 |
|
---|
1938 | CHAR8 Val[50];
|
---|
1939 |
|
---|
1940 | CHAR8 Str[20];
|
---|
1941 |
|
---|
1942 | UINT8 TempByte;
|
---|
1943 | UINTN Size;
|
---|
1944 | UINTN Index;
|
---|
1945 |
|
---|
1946 | Data = UserData;
|
---|
1947 | while (DataSize != 0) {
|
---|
1948 | Size = 16;
|
---|
1949 | if (Size > DataSize) {
|
---|
1950 | Size = DataSize;
|
---|
1951 | }
|
---|
1952 |
|
---|
1953 | for (Index = 0; Index < Size; Index += 1) {
|
---|
1954 | TempByte = Data[Index];
|
---|
1955 | Val[Index * 3 + 0] = Hex[TempByte >> 4];
|
---|
1956 | Val[Index * 3 + 1] = Hex[TempByte & 0xF];
|
---|
1957 | Val[Index * 3 + 2] = (CHAR8)((Index == 7) ? '-' : ' ');
|
---|
1958 | Str[Index] = (CHAR8)((TempByte < ' ' || TempByte > '~') ? '.' : TempByte);
|
---|
1959 | }
|
---|
1960 |
|
---|
1961 | Val[Index * 3] = 0;
|
---|
1962 | Str[Index] = 0;
|
---|
1963 | ShellPrintEx (-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
|
---|
1964 |
|
---|
1965 | Data += Size;
|
---|
1966 | Offset += Size;
|
---|
1967 | DataSize -= Size;
|
---|
1968 | }
|
---|
1969 | }
|
---|
1970 |
|
---|
1971 | /**
|
---|
1972 | Dump HEX data into buffer.
|
---|
1973 |
|
---|
1974 | @param[in] Buffer HEX data to be dumped in Buffer.
|
---|
1975 | @param[in] Indent How many spaces to indent the output.
|
---|
1976 | @param[in] Offset The offset of the printing.
|
---|
1977 | @param[in] DataSize The size in bytes of UserData.
|
---|
1978 | @param[in] UserData The data to print out.
|
---|
1979 | **/
|
---|
1980 | CHAR16 *
|
---|
1981 | EFIAPI
|
---|
1982 | CatSDumpHex (
|
---|
1983 | IN CHAR16 *Buffer,
|
---|
1984 | IN UINTN Indent,
|
---|
1985 | IN UINTN Offset,
|
---|
1986 | IN UINTN DataSize,
|
---|
1987 | IN VOID *UserData
|
---|
1988 | )
|
---|
1989 | {
|
---|
1990 | UINT8 *Data;
|
---|
1991 | UINT8 TempByte;
|
---|
1992 | UINTN Size;
|
---|
1993 | UINTN Index;
|
---|
1994 | CHAR8 Val[50];
|
---|
1995 | CHAR8 Str[20];
|
---|
1996 | CHAR16 *RetVal;
|
---|
1997 | CHAR16 *TempRetVal;
|
---|
1998 |
|
---|
1999 | Data = UserData;
|
---|
2000 | RetVal = Buffer;
|
---|
2001 | while (DataSize != 0) {
|
---|
2002 | Size = 16;
|
---|
2003 | if (Size > DataSize) {
|
---|
2004 | Size = DataSize;
|
---|
2005 | }
|
---|
2006 |
|
---|
2007 | for (Index = 0; Index < Size; Index += 1) {
|
---|
2008 | TempByte = Data[Index];
|
---|
2009 | Val[Index * 3 + 0] = Hex[TempByte >> 4];
|
---|
2010 | Val[Index * 3 + 1] = Hex[TempByte & 0xF];
|
---|
2011 | Val[Index * 3 + 2] = (CHAR8)((Index == 7) ? '-' : ' ');
|
---|
2012 | Str[Index] = (CHAR8)((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
|
---|
2013 | }
|
---|
2014 |
|
---|
2015 | Val[Index * 3] = 0;
|
---|
2016 | Str[Index] = 0;
|
---|
2017 | TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
|
---|
2018 | SHELL_FREE_NON_NULL (RetVal);
|
---|
2019 | RetVal = TempRetVal;
|
---|
2020 |
|
---|
2021 | Data += Size;
|
---|
2022 | Offset += Size;
|
---|
2023 | DataSize -= Size;
|
---|
2024 | }
|
---|
2025 |
|
---|
2026 | return RetVal;
|
---|
2027 | }
|
---|
2028 |
|
---|
2029 | /**
|
---|
2030 | ORDERED_COLLECTION_USER_COMPARE function for SHELL_SORT_UNIQUE_NAME objects.
|
---|
2031 |
|
---|
2032 | @param[in] Unique1AsVoid The first SHELL_SORT_UNIQUE_NAME object (Unique1),
|
---|
2033 | passed in as a pointer-to-VOID.
|
---|
2034 |
|
---|
2035 | @param[in] Unique2AsVoid The second SHELL_SORT_UNIQUE_NAME object (Unique2),
|
---|
2036 | passed in as a pointer-to-VOID.
|
---|
2037 |
|
---|
2038 | @retval <0 If Unique1 compares less than Unique2.
|
---|
2039 |
|
---|
2040 | @retval 0 If Unique1 compares equal to Unique2.
|
---|
2041 |
|
---|
2042 | @retval >0 If Unique1 compares greater than Unique2.
|
---|
2043 | **/
|
---|
2044 | STATIC
|
---|
2045 | INTN
|
---|
2046 | EFIAPI
|
---|
2047 | UniqueNameCompare (
|
---|
2048 | IN CONST VOID *Unique1AsVoid,
|
---|
2049 | IN CONST VOID *Unique2AsVoid
|
---|
2050 | )
|
---|
2051 | {
|
---|
2052 | CONST SHELL_SORT_UNIQUE_NAME *Unique1;
|
---|
2053 | CONST SHELL_SORT_UNIQUE_NAME *Unique2;
|
---|
2054 |
|
---|
2055 | Unique1 = Unique1AsVoid;
|
---|
2056 | Unique2 = Unique2AsVoid;
|
---|
2057 |
|
---|
2058 | //
|
---|
2059 | // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
|
---|
2060 | //
|
---|
2061 | return gUnicodeCollation->StriColl (
|
---|
2062 | gUnicodeCollation,
|
---|
2063 | (CHAR16 *)Unique1->Alias,
|
---|
2064 | (CHAR16 *)Unique2->Alias
|
---|
2065 | );
|
---|
2066 | }
|
---|
2067 |
|
---|
2068 | /**
|
---|
2069 | ORDERED_COLLECTION_KEY_COMPARE function for SHELL_SORT_UNIQUE_NAME objects.
|
---|
2070 |
|
---|
2071 | @param[in] UniqueAliasAsVoid The CHAR16 string UniqueAlias, passed in as a
|
---|
2072 | pointer-to-VOID.
|
---|
2073 |
|
---|
2074 | @param[in] UniqueAsVoid The SHELL_SORT_UNIQUE_NAME object (Unique),
|
---|
2075 | passed in as a pointer-to-VOID.
|
---|
2076 |
|
---|
2077 | @retval <0 If UniqueAlias compares less than Unique->Alias.
|
---|
2078 |
|
---|
2079 | @retval 0 If UniqueAlias compares equal to Unique->Alias.
|
---|
2080 |
|
---|
2081 | @retval >0 If UniqueAlias compares greater than Unique->Alias.
|
---|
2082 | **/
|
---|
2083 | STATIC
|
---|
2084 | INTN
|
---|
2085 | EFIAPI
|
---|
2086 | UniqueNameAliasCompare (
|
---|
2087 | IN CONST VOID *UniqueAliasAsVoid,
|
---|
2088 | IN CONST VOID *UniqueAsVoid
|
---|
2089 | )
|
---|
2090 | {
|
---|
2091 | CONST CHAR16 *UniqueAlias;
|
---|
2092 | CONST SHELL_SORT_UNIQUE_NAME *Unique;
|
---|
2093 |
|
---|
2094 | UniqueAlias = UniqueAliasAsVoid;
|
---|
2095 | Unique = UniqueAsVoid;
|
---|
2096 |
|
---|
2097 | //
|
---|
2098 | // We need to cast away CONST for EFI_UNICODE_COLLATION_STRICOLL.
|
---|
2099 | //
|
---|
2100 | return gUnicodeCollation->StriColl (
|
---|
2101 | gUnicodeCollation,
|
---|
2102 | (CHAR16 *)UniqueAlias,
|
---|
2103 | (CHAR16 *)Unique->Alias
|
---|
2104 | );
|
---|
2105 | }
|
---|
2106 |
|
---|
2107 | /**
|
---|
2108 | Sort an EFI_SHELL_FILE_INFO list, optionally moving duplicates to a separate
|
---|
2109 | list.
|
---|
2110 |
|
---|
2111 | @param[in,out] FileList The list of EFI_SHELL_FILE_INFO objects to sort.
|
---|
2112 |
|
---|
2113 | If FileList is NULL on input, then FileList is
|
---|
2114 | considered an empty, hence already sorted, list.
|
---|
2115 |
|
---|
2116 | Otherwise, if (*FileList) is NULL on input, then
|
---|
2117 | EFI_INVALID_PARAMETER is returned.
|
---|
2118 |
|
---|
2119 | Otherwise, the caller is responsible for having
|
---|
2120 | initialized (*FileList)->Link with
|
---|
2121 | InitializeListHead(). No other fields in the
|
---|
2122 | (**FileList) head element are accessed by this
|
---|
2123 | function.
|
---|
2124 |
|
---|
2125 | On output, (*FileList) is sorted according to Order.
|
---|
2126 | If Duplicates is NULL on input, then duplicate
|
---|
2127 | elements are preserved, sorted stably, on
|
---|
2128 | (*FileList). If Duplicates is not NULL on input,
|
---|
2129 | then duplicates are moved (stably sorted) to the
|
---|
2130 | new, dynamically allocated (*Duplicates) list.
|
---|
2131 |
|
---|
2132 | @param[out] Duplicates If Duplicates is NULL on input, (*FileList) will be
|
---|
2133 | a monotonically ordered list on output, with
|
---|
2134 | duplicates stably sorted.
|
---|
2135 |
|
---|
2136 | If Duplicates is not NULL on input, (*FileList) will
|
---|
2137 | be a strictly monotonically oredered list on output,
|
---|
2138 | with duplicates separated (stably sorted) to
|
---|
2139 | (*Duplicates). All fields except Link will be
|
---|
2140 | zero-initialized in the (**Duplicates) head element.
|
---|
2141 | If no duplicates exist, then (*Duplicates) is set to
|
---|
2142 | NULL on output.
|
---|
2143 |
|
---|
2144 | @param[in] Order Determines the comparison operation between
|
---|
2145 | EFI_SHELL_FILE_INFO objects.
|
---|
2146 |
|
---|
2147 | @retval EFI_INVALID_PARAMETER (UINTN)Order is greater than or equal to
|
---|
2148 | (UINTN)ShellSortFileListMax. Neither the
|
---|
2149 | (*FileList) nor the (*Duplicates) list has
|
---|
2150 | been modified.
|
---|
2151 |
|
---|
2152 | @retval EFI_INVALID_PARAMETER (*FileList) was NULL on input. Neither the
|
---|
2153 | (*FileList) nor the (*Duplicates) list has
|
---|
2154 | been modified.
|
---|
2155 |
|
---|
2156 | @retval EFI_OUT_OF_RESOURCES Memory allocation failed. Neither the
|
---|
2157 | (*FileList) nor the (*Duplicates) list has
|
---|
2158 | been modified.
|
---|
2159 |
|
---|
2160 | @retval EFI_SUCCESS Sorting successful, including the case when
|
---|
2161 | FileList is NULL on input.
|
---|
2162 | **/
|
---|
2163 | EFI_STATUS
|
---|
2164 | EFIAPI
|
---|
2165 | ShellSortFileList (
|
---|
2166 | IN OUT EFI_SHELL_FILE_INFO **FileList,
|
---|
2167 | OUT EFI_SHELL_FILE_INFO **Duplicates OPTIONAL,
|
---|
2168 | IN SHELL_SORT_FILE_LIST Order
|
---|
2169 | )
|
---|
2170 | {
|
---|
2171 | LIST_ENTRY *FilesHead;
|
---|
2172 | ORDERED_COLLECTION *Sort;
|
---|
2173 | LIST_ENTRY *FileEntry;
|
---|
2174 | EFI_SHELL_FILE_INFO *FileInfo;
|
---|
2175 | SHELL_SORT_UNIQUE_NAME *Unique;
|
---|
2176 | EFI_STATUS Status;
|
---|
2177 | EFI_SHELL_FILE_INFO *Dupes;
|
---|
2178 | LIST_ENTRY *NextFileEntry;
|
---|
2179 | CONST CHAR16 *Alias;
|
---|
2180 | ORDERED_COLLECTION_ENTRY *SortEntry;
|
---|
2181 | LIST_ENTRY *TargetFileList;
|
---|
2182 | ORDERED_COLLECTION_ENTRY *NextSortEntry;
|
---|
2183 | VOID *UniqueAsVoid;
|
---|
2184 |
|
---|
2185 | if ((UINTN)Order >= (UINTN)ShellSortFileListMax) {
|
---|
2186 | return EFI_INVALID_PARAMETER;
|
---|
2187 | }
|
---|
2188 |
|
---|
2189 | if (FileList == NULL) {
|
---|
2190 | //
|
---|
2191 | // FileList is considered empty, hence already sorted, with no duplicates.
|
---|
2192 | //
|
---|
2193 | if (Duplicates != NULL) {
|
---|
2194 | *Duplicates = NULL;
|
---|
2195 | }
|
---|
2196 |
|
---|
2197 | return EFI_SUCCESS;
|
---|
2198 | }
|
---|
2199 |
|
---|
2200 | if (*FileList == NULL) {
|
---|
2201 | return EFI_INVALID_PARAMETER;
|
---|
2202 | }
|
---|
2203 |
|
---|
2204 | FilesHead = &(*FileList)->Link;
|
---|
2205 |
|
---|
2206 | //
|
---|
2207 | // Collect all the unique names.
|
---|
2208 | //
|
---|
2209 | Sort = OrderedCollectionInit (UniqueNameCompare, UniqueNameAliasCompare);
|
---|
2210 | if (Sort == NULL) {
|
---|
2211 | return EFI_OUT_OF_RESOURCES;
|
---|
2212 | }
|
---|
2213 |
|
---|
2214 | BASE_LIST_FOR_EACH (FileEntry, FilesHead) {
|
---|
2215 | FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
|
---|
2216 |
|
---|
2217 | //
|
---|
2218 | // Try to record the name of this file as a unique name.
|
---|
2219 | //
|
---|
2220 | Unique = AllocatePool (sizeof (*Unique));
|
---|
2221 | if (Unique == NULL) {
|
---|
2222 | Status = EFI_OUT_OF_RESOURCES;
|
---|
2223 | goto UninitSort;
|
---|
2224 | }
|
---|
2225 |
|
---|
2226 | Unique->Alias = ((Order == ShellSortFileListByFileName) ?
|
---|
2227 | FileInfo->FileName :
|
---|
2228 | FileInfo->FullName);
|
---|
2229 | InitializeListHead (&Unique->SameNameList);
|
---|
2230 |
|
---|
2231 | Status = OrderedCollectionInsert (Sort, NULL, Unique);
|
---|
2232 | if (EFI_ERROR (Status)) {
|
---|
2233 | //
|
---|
2234 | // Only two errors are possible: memory allocation failed, or this name
|
---|
2235 | // has been encountered before. In either case, the
|
---|
2236 | // SHELL_SORT_UNIQUE_NAME object being constructed has to be released.
|
---|
2237 | //
|
---|
2238 | FreePool (Unique);
|
---|
2239 | //
|
---|
2240 | // Memory allocation failure is fatal, while having seen the same name
|
---|
2241 | // before is normal.
|
---|
2242 | //
|
---|
2243 | if (Status == EFI_OUT_OF_RESOURCES) {
|
---|
2244 | goto UninitSort;
|
---|
2245 | }
|
---|
2246 |
|
---|
2247 | ASSERT (Status == EFI_ALREADY_STARTED);
|
---|
2248 | }
|
---|
2249 | }
|
---|
2250 |
|
---|
2251 | //
|
---|
2252 | // Set Dupes to suppress incorrect compiler/analyzer warnings.
|
---|
2253 | //
|
---|
2254 | Dupes = NULL;
|
---|
2255 |
|
---|
2256 | //
|
---|
2257 | // If separation of duplicates has been requested, allocate the list for
|
---|
2258 | // them.
|
---|
2259 | //
|
---|
2260 | if (Duplicates != NULL) {
|
---|
2261 | Dupes = AllocateZeroPool (sizeof (*Dupes));
|
---|
2262 | if (Dupes == NULL) {
|
---|
2263 | Status = EFI_OUT_OF_RESOURCES;
|
---|
2264 | goto UninitSort;
|
---|
2265 | }
|
---|
2266 |
|
---|
2267 | InitializeListHead (&Dupes->Link);
|
---|
2268 | }
|
---|
2269 |
|
---|
2270 | //
|
---|
2271 | // No memory allocation beyond this point; thus, no chance to fail. We can
|
---|
2272 | // now migrate the EFI_SHELL_FILE_INFO objects from (*FileList) to Sort.
|
---|
2273 | //
|
---|
2274 | BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, FilesHead) {
|
---|
2275 | FileInfo = (EFI_SHELL_FILE_INFO *)FileEntry;
|
---|
2276 | //
|
---|
2277 | // Look up the SHELL_SORT_UNIQUE_NAME that matches FileInfo's name.
|
---|
2278 | //
|
---|
2279 | Alias = ((Order == ShellSortFileListByFileName) ?
|
---|
2280 | FileInfo->FileName :
|
---|
2281 | FileInfo->FullName);
|
---|
2282 | SortEntry = OrderedCollectionFind (Sort, Alias);
|
---|
2283 | ASSERT (SortEntry != NULL);
|
---|
2284 | Unique = OrderedCollectionUserStruct (SortEntry);
|
---|
2285 | //
|
---|
2286 | // Move FileInfo from (*FileList) to the end of the list of files whose
|
---|
2287 | // names all compare identical to FileInfo's name.
|
---|
2288 | //
|
---|
2289 | RemoveEntryList (&FileInfo->Link);
|
---|
2290 | InsertTailList (&Unique->SameNameList, &FileInfo->Link);
|
---|
2291 | }
|
---|
2292 |
|
---|
2293 | //
|
---|
2294 | // All EFI_SHELL_FILE_INFO objects originally in (*FileList) have been
|
---|
2295 | // distributed to Sort. Now migrate them back to (*FileList), advancing in
|
---|
2296 | // unique name order.
|
---|
2297 | //
|
---|
2298 | for (SortEntry = OrderedCollectionMin (Sort);
|
---|
2299 | SortEntry != NULL;
|
---|
2300 | SortEntry = OrderedCollectionNext (SortEntry))
|
---|
2301 | {
|
---|
2302 | Unique = OrderedCollectionUserStruct (SortEntry);
|
---|
2303 | //
|
---|
2304 | // The first FileInfo encountered for each unique name goes back on
|
---|
2305 | // (*FileList) unconditionally. Further FileInfo instances for the same
|
---|
2306 | // unique name -- that is, duplicates -- are either returned to (*FileList)
|
---|
2307 | // or separated, dependent on the caller's request.
|
---|
2308 | //
|
---|
2309 | TargetFileList = FilesHead;
|
---|
2310 | BASE_LIST_FOR_EACH_SAFE (FileEntry, NextFileEntry, &Unique->SameNameList) {
|
---|
2311 | RemoveEntryList (FileEntry);
|
---|
2312 | InsertTailList (TargetFileList, FileEntry);
|
---|
2313 | if (Duplicates != NULL) {
|
---|
2314 | TargetFileList = &Dupes->Link;
|
---|
2315 | }
|
---|
2316 | }
|
---|
2317 | }
|
---|
2318 |
|
---|
2319 | //
|
---|
2320 | // We're done. If separation of duplicates has been requested, output the
|
---|
2321 | // list of duplicates -- and free that list at once, if it's empty (i.e., if
|
---|
2322 | // no duplicates have been found).
|
---|
2323 | //
|
---|
2324 | if (Duplicates != NULL) {
|
---|
2325 | if (IsListEmpty (&Dupes->Link)) {
|
---|
2326 | FreePool (Dupes);
|
---|
2327 | *Duplicates = NULL;
|
---|
2328 | } else {
|
---|
2329 | *Duplicates = Dupes;
|
---|
2330 | }
|
---|
2331 | }
|
---|
2332 |
|
---|
2333 | Status = EFI_SUCCESS;
|
---|
2334 |
|
---|
2335 | //
|
---|
2336 | // Fall through.
|
---|
2337 | //
|
---|
2338 | UninitSort:
|
---|
2339 | for (SortEntry = OrderedCollectionMin (Sort);
|
---|
2340 | SortEntry != NULL;
|
---|
2341 | SortEntry = NextSortEntry)
|
---|
2342 | {
|
---|
2343 | NextSortEntry = OrderedCollectionNext (SortEntry);
|
---|
2344 | OrderedCollectionDelete (Sort, SortEntry, &UniqueAsVoid);
|
---|
2345 | Unique = UniqueAsVoid;
|
---|
2346 | ASSERT (IsListEmpty (&Unique->SameNameList));
|
---|
2347 | FreePool (Unique);
|
---|
2348 | }
|
---|
2349 |
|
---|
2350 | OrderedCollectionUninit (Sort);
|
---|
2351 |
|
---|
2352 | return Status;
|
---|
2353 | }
|
---|