]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/Shell.c
This refactors 3 functions out of ShellCommandLib and puts them into a new library...
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
1 /** @file
2 This is THE shell (application)
3
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Shell.h"
16
17 //
18 // Initialize the global structure
19 //
20 SHELL_INFO ShellInfoObject = {
21 NULL,
22 NULL,
23 FALSE,
24 FALSE,
25 {
26 0,
27 0,
28 0,
29 0,
30 0,
31 0,
32 0,
33 0,
34 0,
35 0,
36 NULL,
37 NULL
38 },
39 {0,0},
40 {
41 {0,0},
42 0,
43 0,
44 TRUE
45 },
46 NULL,
47 0,
48 NULL,
49 NULL,
50 NULL,
51 NULL,
52 NULL,
53 {0,0,NULL,NULL},
54 {0,0},
55 NULL,
56 NULL,
57 NULL,
58 NULL,
59 FALSE
60 };
61
62 STATIC CONST CHAR16 mScriptExtension[] = L".NSH";
63 STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI";
64 STATIC CONST CHAR16 mStartupScript[] = L"startup.nsh";
65
66 /**
67 Function to start monitoring for CTRL-S using SimpleTextInputEx. This
68 feature's enabled state was not known when the shell initially launched.
69
70 @retval EFI_SUCCESS The feature is enabled.
71 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
72 **/
73 EFI_STATUS
74 EFIAPI
75 InternalEfiShellStartCtrlSMonitor(
76 VOID
77 )
78 {
79 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;
80 EFI_KEY_DATA KeyData;
81 EFI_STATUS Status;
82
83 Status = gBS->OpenProtocol(
84 gST->ConsoleInHandle,
85 &gEfiSimpleTextInputExProtocolGuid,
86 (VOID**)&SimpleEx,
87 gImageHandle,
88 NULL,
89 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
90 if (EFI_ERROR(Status)) {
91 ShellPrintHiiEx(
92 -1,
93 -1,
94 NULL,
95 STRING_TOKEN (STR_SHELL_NO_IN_EX),
96 ShellInfoObject.HiiHandle);
97 return (EFI_SUCCESS);
98 }
99
100 KeyData.KeyState.KeyToggleState = 0;
101 KeyData.Key.ScanCode = 0;
102 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
103 KeyData.Key.UnicodeChar = L's';
104
105 Status = SimpleEx->RegisterKeyNotify(
106 SimpleEx,
107 &KeyData,
108 NotificationFunction,
109 &ShellInfoObject.CtrlSNotifyHandle1);
110
111 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
112 if (!EFI_ERROR(Status)) {
113 Status = SimpleEx->RegisterKeyNotify(
114 SimpleEx,
115 &KeyData,
116 NotificationFunction,
117 &ShellInfoObject.CtrlSNotifyHandle2);
118 }
119 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;
120 KeyData.Key.UnicodeChar = 19;
121
122 if (!EFI_ERROR(Status)) {
123 Status = SimpleEx->RegisterKeyNotify(
124 SimpleEx,
125 &KeyData,
126 NotificationFunction,
127 &ShellInfoObject.CtrlSNotifyHandle2);
128 }
129 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;
130 if (!EFI_ERROR(Status)) {
131 Status = SimpleEx->RegisterKeyNotify(
132 SimpleEx,
133 &KeyData,
134 NotificationFunction,
135 &ShellInfoObject.CtrlSNotifyHandle2);
136 }
137 return (Status);
138 }
139
140
141
142 /**
143 The entry point for the application.
144
145 @param[in] ImageHandle The firmware allocated handle for the EFI image.
146 @param[in] SystemTable A pointer to the EFI System Table.
147
148 @retval EFI_SUCCESS The entry point is executed successfully.
149 @retval other Some error occurs when executing this entry point.
150
151 **/
152 EFI_STATUS
153 EFIAPI
154 UefiMain (
155 IN EFI_HANDLE ImageHandle,
156 IN EFI_SYSTEM_TABLE *SystemTable
157 )
158 {
159 EFI_STATUS Status;
160 CHAR16 *TempString;
161 UINTN Size;
162 EFI_HANDLE ConInHandle;
163 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn;
164
165 if (PcdGet8(PcdShellSupportLevel) > 3) {
166 return (EFI_UNSUPPORTED);
167 }
168
169 //
170 // Clear the screen
171 //
172 Status = gST->ConOut->ClearScreen(gST->ConOut);
173 if (EFI_ERROR(Status)) {
174 return (Status);
175 }
176
177 //
178 // Populate the global structure from PCDs
179 //
180 ShellInfoObject.ImageDevPath = NULL;
181 ShellInfoObject.FileDevPath = NULL;
182 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);
183 ShellInfoObject.ViewingSettings.InsertMode = PcdGetBool(PcdShellInsertModeDefault);
184 ShellInfoObject.LogScreenCount = PcdGet8 (PcdShellScreenLogCount );
185
186 //
187 // verify we dont allow for spec violation
188 //
189 ASSERT(ShellInfoObject.LogScreenCount >= 3);
190
191 //
192 // Initialize the LIST ENTRY objects...
193 //
194 InitializeListHead(&ShellInfoObject.BufferToFreeList.Link);
195 InitializeListHead(&ShellInfoObject.ViewingSettings.CommandHistory.Link);
196 InitializeListHead(&ShellInfoObject.SplitList.Link);
197
198 //
199 // Check PCDs for optional features that are not implemented yet.
200 //
201 if ( PcdGetBool(PcdShellSupportOldProtocols)
202 || !FeaturePcdGet(PcdShellRequireHiiPlatform)
203 || FeaturePcdGet(PcdShellSupportFrameworkHii)
204 ) {
205 return (EFI_UNSUPPORTED);
206 }
207
208 //
209 // turn off the watchdog timer
210 //
211 gBS->SetWatchdogTimer (0, 0, 0, NULL);
212
213 //
214 // install our console logger. This will keep a log of the output for back-browsing
215 //
216 Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo);
217 if (!EFI_ERROR(Status)) {
218 //
219 // Enable the cursor to be visible
220 //
221 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
222
223 //
224 // If supporting EFI 1.1 we need to install HII protocol
225 // only do this if PcdShellRequireHiiPlatform == FALSE
226 //
227 // remove EFI_UNSUPPORTED check above when complete.
228 ///@todo add support for Framework HII
229
230 //
231 // install our (solitary) HII package
232 //
233 ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL);
234 if (ShellInfoObject.HiiHandle == NULL) {
235 if (PcdGetBool(PcdShellSupportFrameworkHii)) {
236 ///@todo Add our package into Framework HII
237 }
238 if (ShellInfoObject.HiiHandle == NULL) {
239 return (EFI_NOT_STARTED);
240 }
241 }
242
243 //
244 // create and install the EfiShellParametersProtocol
245 //
246 Status = CreatePopulateInstallShellParametersProtocol(&ShellInfoObject.NewShellParametersProtocol, &ShellInfoObject.RootShellInstance);
247 ASSERT_EFI_ERROR(Status);
248 ASSERT(ShellInfoObject.NewShellParametersProtocol != NULL);
249
250 //
251 // create and install the EfiShellProtocol
252 //
253 Status = CreatePopulateInstallShellProtocol(&ShellInfoObject.NewEfiShellProtocol);
254 ASSERT_EFI_ERROR(Status);
255 ASSERT(ShellInfoObject.NewEfiShellProtocol != NULL);
256
257 //
258 // Now initialize the shell library (it requires Shell Parameters protocol)
259 //
260 Status = ShellInitialize();
261 ASSERT_EFI_ERROR(Status);
262
263 Status = CommandInit();
264 ASSERT_EFI_ERROR(Status);
265
266 //
267 // Check the command line
268 //
269 Status = ProcessCommandLine();
270
271 //
272 // If shell support level is >= 1 create the mappings and paths
273 //
274 if (PcdGet8(PcdShellSupportLevel) >= 1) {
275 Status = ShellCommandCreateInitialMappingsAndPaths();
276 }
277
278 //
279 // save the device path for the loaded image and the device path for the filepath (under loaded image)
280 // These are where to look for the startup.nsh file
281 //
282 Status = GetDevicePathsForImageAndFile(&ShellInfoObject.ImageDevPath, &ShellInfoObject.FileDevPath);
283 ASSERT_EFI_ERROR(Status);
284
285 //
286 // Display the version
287 //
288 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) {
289 ShellPrintHiiEx (
290 0,
291 gST->ConOut->Mode->CursorRow,
292 NULL,
293 STRING_TOKEN (STR_VER_OUTPUT_MAIN),
294 ShellInfoObject.HiiHandle,
295 SupportLevel[PcdGet8(PcdShellSupportLevel)],
296 gEfiShellProtocol->MajorVersion,
297 gEfiShellProtocol->MinorVersion,
298 (gST->Hdr.Revision&0xffff0000)>>16,
299 (gST->Hdr.Revision&0x0000ffff),
300 gST->FirmwareVendor,
301 gST->FirmwareRevision
302 );
303 }
304
305 //
306 // Display the mapping
307 //
308 if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {
309 Status = RunCommand(L"map");
310 ASSERT_EFI_ERROR(Status);
311 }
312
313 //
314 // init all the built in alias'
315 //
316 Status = SetBuiltInAlias();
317 ASSERT_EFI_ERROR(Status);
318
319 //
320 // Initialize environment variables
321 //
322 if (ShellCommandGetProfileList() != NULL) {
323 Status = InternalEfiShellSetEnv(L"profiles", ShellCommandGetProfileList(), TRUE);
324 ASSERT_EFI_ERROR(Status);
325 }
326
327 Size = 100;
328 TempString = AllocateZeroPool(Size);
329
330 UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel));
331 Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE);
332 ASSERT_EFI_ERROR(Status);
333
334 UnicodeSPrint(TempString, Size, L"%d.%d", ShellInfoObject.NewEfiShellProtocol->MajorVersion, ShellInfoObject.NewEfiShellProtocol->MinorVersion);
335 Status = InternalEfiShellSetEnv(L"uefishellversion", TempString, TRUE);
336 ASSERT_EFI_ERROR(Status);
337
338 UnicodeSPrint(TempString, Size, L"%d.%d", (gST->Hdr.Revision & 0xFFFF0000) >> 16, gST->Hdr.Revision & 0x0000FFFF);
339 Status = InternalEfiShellSetEnv(L"uefiversion", TempString, TRUE);
340 ASSERT_EFI_ERROR(Status);
341
342 FreePool(TempString);
343
344 if (!EFI_ERROR(Status)) {
345 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {
346 //
347 // Set up the event for CTRL-C monitoring...
348 //
349 Status = InernalEfiShellStartMonitor();
350 }
351
352 if (!EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {
353 //
354 // Set up the event for CTRL-S monitoring...
355 //
356 Status = InternalEfiShellStartCtrlSMonitor();
357 }
358
359 if (!EFI_ERROR(Status) && ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {
360 //
361 // close off the gST->ConIn
362 //
363 OldConIn = gST->ConIn;
364 ConInHandle = gST->ConsoleInHandle;
365 gST->ConIn = CreateSimpleTextInOnFile((SHELL_FILE_HANDLE)&FileInterfaceNulFile, &gST->ConsoleInHandle);
366 } else {
367 OldConIn = NULL;
368 ConInHandle = NULL;
369 }
370
371 if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) {
372 //
373 // process the startup script or launch the called app.
374 //
375 Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);
376 }
377
378 if (!ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {
379 //
380 // begin the UI waiting loop
381 //
382 do {
383 //
384 // clean out all the memory allocated for CONST <something> * return values
385 // between each shell prompt presentation
386 //
387 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){
388 FreeBufferList(&ShellInfoObject.BufferToFreeList);
389 }
390
391 //
392 // Reset page break back to default.
393 //
394 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);
395 ShellInfoObject.ConsoleInfo->Enabled = TRUE;
396 ShellInfoObject.ConsoleInfo->RowCounter = 0;
397
398 //
399 // Reset the CTRL-C event (yes we ignore the return values)
400 //
401 Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);
402
403 //
404 // Display Prompt
405 //
406 Status = DoShellPrompt();
407 } while (!ShellCommandGetExit());
408 }
409 if (OldConIn != NULL && ConInHandle != NULL) {
410 CloseSimpleTextInOnFile (gST->ConIn);
411 gST->ConIn = OldConIn;
412 gST->ConsoleInHandle = ConInHandle;
413 }
414 }
415 }
416
417 //
418 // uninstall protocols / free memory / etc...
419 //
420 if (ShellInfoObject.UserBreakTimer != NULL) {
421 gBS->CloseEvent(ShellInfoObject.UserBreakTimer);
422 DEBUG_CODE(ShellInfoObject.UserBreakTimer = NULL;);
423 }
424 if (ShellInfoObject.ImageDevPath != NULL) {
425 FreePool(ShellInfoObject.ImageDevPath);
426 DEBUG_CODE(ShellInfoObject.ImageDevPath = NULL;);
427 }
428 if (ShellInfoObject.FileDevPath != NULL) {
429 FreePool(ShellInfoObject.FileDevPath);
430 DEBUG_CODE(ShellInfoObject.FileDevPath = NULL;);
431 }
432 if (ShellInfoObject.NewShellParametersProtocol != NULL) {
433 CleanUpShellParametersProtocol(ShellInfoObject.NewShellParametersProtocol);
434 DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;);
435 }
436 if (ShellInfoObject.NewEfiShellProtocol != NULL){
437 if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){
438 ShellInfoObject.NewEfiShellProtocol->SetEnv(L"cwd", L"", TRUE);
439 }
440 CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol);
441 DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;);
442 }
443
444 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){
445 FreeBufferList(&ShellInfoObject.BufferToFreeList);
446 }
447
448 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){
449 ASSERT(FALSE); ///@todo finish this de-allocation.
450 }
451
452 if (ShellInfoObject.ShellInitSettings.FileName != NULL) {
453 FreePool(ShellInfoObject.ShellInitSettings.FileName);
454 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileName = NULL;);
455 }
456
457 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {
458 FreePool(ShellInfoObject.ShellInitSettings.FileOptions);
459 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileOptions = NULL;);
460 }
461
462 if (ShellInfoObject.HiiHandle != NULL) {
463 HiiRemovePackages(ShellInfoObject.HiiHandle);
464 DEBUG_CODE(ShellInfoObject.HiiHandle = NULL;);
465 }
466
467 if (!IsListEmpty(&ShellInfoObject.ViewingSettings.CommandHistory.Link)){
468 FreeBufferList(&ShellInfoObject.ViewingSettings.CommandHistory);
469 }
470
471 ASSERT(ShellInfoObject.ConsoleInfo != NULL);
472 if (ShellInfoObject.ConsoleInfo != NULL) {
473 ConsoleLoggerUninstall(ShellInfoObject.ConsoleInfo);
474 FreePool(ShellInfoObject.ConsoleInfo);
475 DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);
476 }
477
478 return (Status);
479 }
480
481 /**
482 Sets all the alias' that were registered with the ShellCommandLib library.
483
484 @retval EFI_SUCCESS all init commands were run sucessfully.
485 **/
486 EFI_STATUS
487 EFIAPI
488 SetBuiltInAlias(
489 )
490 {
491 EFI_STATUS Status;
492 CONST ALIAS_LIST *List;
493 ALIAS_LIST *Node;
494
495 //
496 // Get all the commands we want to run
497 //
498 List = ShellCommandGetInitAliasList();
499
500 //
501 // for each command in the List
502 //
503 for ( Node = (ALIAS_LIST*)GetFirstNode(&List->Link)
504 ; !IsNull (&List->Link, &Node->Link)
505 ; Node = (ALIAS_LIST *)GetNextNode(&List->Link, &Node->Link)
506 ){
507 //
508 // install the alias'
509 //
510 Status = InternalSetAlias(Node->CommandString, Node->Alias, TRUE);
511 ASSERT_EFI_ERROR(Status);
512 }
513 return (EFI_SUCCESS);
514 }
515
516 /**
517 Internal function to determine if 2 command names are really the same.
518
519 @param[in] Command1 The pointer to the first command name.
520 @param[in] Command2 The pointer to the second command name.
521
522 @retval TRUE The 2 command names are the same.
523 @retval FALSE The 2 command names are not the same.
524 **/
525 BOOLEAN
526 EFIAPI
527 IsCommand(
528 IN CONST CHAR16 *Command1,
529 IN CONST CHAR16 *Command2
530 )
531 {
532 if (StringNoCaseCompare(&Command1, &Command2) == 0) {
533 return (TRUE);
534 }
535 return (FALSE);
536 }
537
538 /**
539 Internal function to determine if a command is a script only command.
540
541 @param[in] CommandName The pointer to the command name.
542
543 @retval TRUE The command is a script only command.
544 @retval FALSE The command is not a script only command.
545 **/
546 BOOLEAN
547 EFIAPI
548 IsScriptOnlyCommand(
549 IN CONST CHAR16 *CommandName
550 )
551 {
552 if (IsCommand(CommandName, L"for")
553 ||IsCommand(CommandName, L"endfor")
554 ||IsCommand(CommandName, L"if")
555 ||IsCommand(CommandName, L"else")
556 ||IsCommand(CommandName, L"endif")
557 ||IsCommand(CommandName, L"goto")) {
558 return (TRUE);
559 }
560 return (FALSE);
561 }
562
563 /**
564 This function will populate the 2 device path protocol parameters based on the
565 global gImageHandle. The DevPath will point to the device path for the handle that has
566 loaded image protocol installed on it. The FilePath will point to the device path
567 for the file that was loaded.
568
569 @param[in,out] DevPath On a sucessful return the device path to the loaded image.
570 @param[in,out] FilePath On a sucessful return the device path to the file.
571
572 @retval EFI_SUCCESS The 2 device paths were sucessfully returned.
573 @retval other A error from gBS->HandleProtocol.
574
575 @sa HandleProtocol
576 **/
577 EFI_STATUS
578 EFIAPI
579 GetDevicePathsForImageAndFile (
580 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath,
581 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath
582 )
583 {
584 EFI_STATUS Status;
585 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
586 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
587
588 ASSERT(DevPath != NULL);
589 ASSERT(FilePath != NULL);
590
591 Status = gBS->OpenProtocol (
592 gImageHandle,
593 &gEfiLoadedImageProtocolGuid,
594 (VOID**)&LoadedImage,
595 gImageHandle,
596 NULL,
597 EFI_OPEN_PROTOCOL_GET_PROTOCOL
598 );
599 if (!EFI_ERROR (Status)) {
600 Status = gBS->OpenProtocol (
601 LoadedImage->DeviceHandle,
602 &gEfiDevicePathProtocolGuid,
603 (VOID**)&ImageDevicePath,
604 gImageHandle,
605 NULL,
606 EFI_OPEN_PROTOCOL_GET_PROTOCOL
607 );
608 if (!EFI_ERROR (Status)) {
609 *DevPath = DuplicateDevicePath (ImageDevicePath);
610 *FilePath = DuplicateDevicePath (LoadedImage->FilePath);
611 gBS->CloseProtocol(
612 LoadedImage->DeviceHandle,
613 &gEfiDevicePathProtocolGuid,
614 gImageHandle,
615 NULL);
616 }
617 gBS->CloseProtocol(
618 gImageHandle,
619 &gEfiLoadedImageProtocolGuid,
620 gImageHandle,
621 NULL);
622 }
623 return (Status);
624 }
625
626 STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = {
627 {L"-nostartup", TypeFlag},
628 {L"-startup", TypeFlag},
629 {L"-noconsoleout", TypeFlag},
630 {L"-noconsolein", TypeFlag},
631 {L"-nointerrupt", TypeFlag},
632 {L"-nomap", TypeFlag},
633 {L"-noversion", TypeFlag},
634 {L"-startup", TypeFlag},
635 {L"-delay", TypeValue},
636 {NULL, TypeMax}
637 };
638
639 /**
640 Process all Uefi Shell 2.0 command line options.
641
642 see Uefi Shell 2.0 section 3.2 for full details.
643
644 the command line must resemble the following:
645
646 shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]
647
648 ShellOpt-options Options which control the initialization behavior of the shell.
649 These options are read from the EFI global variable "ShellOpt"
650 and are processed before options or file-name.
651
652 options Options which control the initialization behavior of the shell.
653
654 file-name The name of a UEFI shell application or script to be executed
655 after initialization is complete. By default, if file-name is
656 specified, then -nostartup is implied. Scripts are not supported
657 by level 0.
658
659 file-name-options The command-line options that are passed to file-name when it
660 is invoked.
661
662 This will initialize the ShellInfoObject.ShellInitSettings global variable.
663
664 @retval EFI_SUCCESS The variable is initialized.
665 **/
666 EFI_STATUS
667 EFIAPI
668 ProcessCommandLine(
669 VOID
670 )
671 {
672 EFI_STATUS Status;
673 LIST_ENTRY *Package;
674 UINTN Size;
675 CONST CHAR16 *TempConst;
676 UINTN Count;
677 UINTN LoopVar;
678 CHAR16 *ProblemParam;
679 UINT64 Intermediate;
680
681 Package = NULL;
682 ProblemParam = NULL;
683
684 Status = ShellCommandLineParse (mShellParamList, &Package, NULL, FALSE);
685
686 Count = 1;
687 Size = 0;
688 TempConst = ShellCommandLineGetRawValue(Package, Count++);
689 if (TempConst != NULL && StrLen(TempConst)) {
690 ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(TempConst));
691 if (ShellInfoObject.ShellInitSettings.FileName == NULL) {
692 return (EFI_OUT_OF_RESOURCES);
693 }
694 StrCpy(ShellInfoObject.ShellInitSettings.FileName, TempConst);
695 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;
696 for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {
697 if (StrCmp(gEfiShellParametersProtocol->Argv[LoopVar], ShellInfoObject.ShellInitSettings.FileName)==0) {
698 LoopVar++;
699 //
700 // We found the file... add the rest of the params...
701 //
702 for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {
703 ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));
704 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,
705 &Size,
706 L" ",
707 0);
708 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {
709 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);
710 return (EFI_OUT_OF_RESOURCES);
711 }
712 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,
713 &Size,
714 gEfiShellParametersProtocol->Argv[LoopVar],
715 0);
716 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {
717 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);
718 return (EFI_OUT_OF_RESOURCES);
719 }
720 }
721 }
722 }
723 } else {
724 ShellCommandLineFreeVarList(Package);
725 Package = NULL;
726 Status = ShellCommandLineParse (mShellParamList, &Package, &ProblemParam, FALSE);
727 if (EFI_ERROR(Status)) {
728 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), ShellInfoObject.HiiHandle, ProblemParam);
729 FreePool(ProblemParam);
730 ShellCommandLineFreeVarList(Package);
731 return (EFI_INVALID_PARAMETER);
732 }
733 }
734
735 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = ShellCommandLineGetFlag(Package, L"-startup");
736 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = ShellCommandLineGetFlag(Package, L"-nostartup");
737 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = ShellCommandLineGetFlag(Package, L"-noconsoleout");
738 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = ShellCommandLineGetFlag(Package, L"-noconsolein");
739 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = ShellCommandLineGetFlag(Package, L"-nointerrupt");
740 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = ShellCommandLineGetFlag(Package, L"-nomap");
741 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = ShellCommandLineGetFlag(Package, L"-noversion");
742 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = ShellCommandLineGetFlag(Package, L"-delay");
743
744 ShellInfoObject.ShellInitSettings.Delay = 5;
745
746 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {
747 ShellInfoObject.ShellInitSettings.Delay = 0;
748 } else if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay) {
749 TempConst = ShellCommandLineGetValue(Package, L"-delay");
750 if (TempConst != NULL && *TempConst == L':') {
751 TempConst++;
752 }
753 if (TempConst != NULL && !EFI_ERROR(ShellConvertStringToUint64(TempConst, &Intermediate, FALSE, FALSE))) {
754 ShellInfoObject.ShellInitSettings.Delay = (UINTN)Intermediate;
755 }
756 }
757 ShellCommandLineFreeVarList(Package);
758
759 return (Status);
760 }
761
762 /**
763 Handles all interaction with the default startup script.
764
765 this will check that the correct command line parameters were passed, handle the delay, and then start running the script.
766
767 @param ImagePath the path to the image for shell. first place to look for the startup script
768 @param FilePath the path to the file for shell. second place to look for the startup script.
769
770 @retval EFI_SUCCESS the variable is initialized.
771 **/
772 EFI_STATUS
773 EFIAPI
774 DoStartupScript(
775 EFI_DEVICE_PATH_PROTOCOL *ImagePath,
776 EFI_DEVICE_PATH_PROTOCOL *FilePath
777 )
778 {
779 EFI_STATUS Status;
780 UINTN Delay;
781 EFI_INPUT_KEY Key;
782 SHELL_FILE_HANDLE FileHandle;
783 EFI_DEVICE_PATH_PROTOCOL *NewPath;
784 EFI_DEVICE_PATH_PROTOCOL *NamePath;
785 CHAR16 *FileStringPath;
786 CHAR16 *TempSpot;
787 UINTN NewSize;
788 CONST CHAR16 *MapName;
789
790 Key.UnicodeChar = CHAR_NULL;
791 Key.ScanCode = 0;
792 FileHandle = NULL;
793
794 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) {
795 //
796 // launch something else instead
797 //
798 NewSize = StrSize(ShellInfoObject.ShellInitSettings.FileName);
799 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {
800 NewSize += StrSize(ShellInfoObject.ShellInitSettings.FileOptions) + sizeof(CHAR16);
801 }
802 FileStringPath = AllocateZeroPool(NewSize);
803 if (FileStringPath == NULL) {
804 return (EFI_OUT_OF_RESOURCES);
805 }
806 StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);
807 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {
808 StrCat(FileStringPath, L" ");
809 StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);
810 }
811 Status = RunCommand(FileStringPath);
812 FreePool(FileStringPath);
813 return (Status);
814
815 }
816
817 //
818 // for shell level 0 we do no scripts
819 // Without the Startup bit overriding we allow for nostartup to prevent scripts
820 //
821 if ( (PcdGet8(PcdShellSupportLevel) < 1)
822 || (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup)
823 ){
824 return (EFI_SUCCESS);
825 }
826
827 //
828 // print out our warning and see if they press a key
829 //
830 for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay * 10
831 ; Delay != 0 && EFI_ERROR(Status)
832 ; Delay--
833 ){
834 ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay/10);
835 gBS->Stall (100000);
836 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {
837 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
838 }
839 }
840 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle);
841
842 //
843 // ESC was pressed
844 //
845 if (Status == EFI_SUCCESS && Key.UnicodeChar == 0 && Key.ScanCode == SCAN_ESC) {
846 return (EFI_SUCCESS);
847 }
848
849 //
850 // Try the first location (must be file system)
851 //
852 MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath(&ImagePath);
853 if (MapName != NULL) {
854 FileStringPath = NULL;
855 NewSize = 0;
856 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, MapName, 0);
857 TempSpot = StrStr(FileStringPath, L";");
858 if (TempSpot != NULL) {
859 *TempSpot = CHAR_NULL;
860 }
861 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, ((FILEPATH_DEVICE_PATH*)FilePath)->PathName, 0);
862 PathRemoveLastItem(FileStringPath);
863 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, mStartupScript, 0);
864 Status = ShellInfoObject.NewEfiShellProtocol->OpenFileByName(FileStringPath, &FileHandle, EFI_FILE_MODE_READ);
865 FreePool(FileStringPath);
866 }
867 if (EFI_ERROR(Status)) {
868 NamePath = FileDevicePath (NULL, mStartupScript);
869 NewPath = AppendDevicePathNode (ImagePath, NamePath);
870 FreePool(NamePath);
871
872 //
873 // Try the location
874 //
875 Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);
876 FreePool(NewPath);
877 }
878 //
879 // If we got a file, run it
880 //
881 if (!EFI_ERROR(Status) && FileHandle != NULL) {
882 Status = RunScriptFileHandle (FileHandle, mStartupScript);
883 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);
884 } else {
885 FileStringPath = ShellFindFilePath(mStartupScript);
886 if (FileStringPath == NULL) {
887 //
888 // we return success since we dont need to have a startup script
889 //
890 Status = EFI_SUCCESS;
891 ASSERT(FileHandle == NULL);
892 } else {
893 Status = RunScriptFile(FileStringPath);
894 FreePool(FileStringPath);
895 }
896 }
897
898
899 return (Status);
900 }
901
902 /**
903 Function to perform the shell prompt looping. It will do a single prompt,
904 dispatch the result, and then return. It is expected that the caller will
905 call this function in a loop many times.
906
907 @retval EFI_SUCCESS
908 @retval RETURN_ABORTED
909 **/
910 EFI_STATUS
911 EFIAPI
912 DoShellPrompt (
913 VOID
914 )
915 {
916 UINTN Column;
917 UINTN Row;
918 CHAR16 *CmdLine;
919 CONST CHAR16 *CurDir;
920 UINTN BufferSize;
921 EFI_STATUS Status;
922
923 CurDir = NULL;
924
925 //
926 // Get screen setting to decide size of the command line buffer
927 //
928 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Column, &Row);
929 BufferSize = Column * Row * sizeof (CHAR16);
930 CmdLine = AllocateZeroPool (BufferSize);
931 if (CmdLine == NULL) {
932 return EFI_OUT_OF_RESOURCES;
933 }
934
935 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");
936
937 //
938 // Prompt for input
939 //
940 gST->ConOut->SetCursorPosition (gST->ConOut, 0, gST->ConOut->Mode->CursorRow);
941
942 if (CurDir != NULL && StrLen(CurDir) > 1) {
943 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);
944 } else {
945 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);
946 }
947
948 //
949 // Read a line from the console
950 //
951 Status = ShellInfoObject.NewEfiShellProtocol->ReadFile(ShellInfoObject.NewShellParametersProtocol->StdIn, &BufferSize, CmdLine);
952
953 //
954 // Null terminate the string and parse it
955 //
956 if (!EFI_ERROR (Status)) {
957 CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;
958 Status = RunCommand(CmdLine);
959 }
960
961 //
962 // Done with this command
963 //
964 FreePool (CmdLine);
965 return Status;
966 }
967
968 /**
969 Add a buffer to the Buffer To Free List for safely returning buffers to other
970 places without risking letting them modify internal shell information.
971
972 @param Buffer Something to pass to FreePool when the shell is exiting.
973 **/
974 VOID*
975 EFIAPI
976 AddBufferToFreeList(
977 VOID *Buffer
978 )
979 {
980 BUFFER_LIST *BufferListEntry;
981
982 if (Buffer == NULL) {
983 return (NULL);
984 }
985
986 BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST));
987 ASSERT(BufferListEntry != NULL);
988 BufferListEntry->Buffer = Buffer;
989 InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);
990 return (Buffer);
991 }
992
993 /**
994 Add a buffer to the Line History List
995
996 @param Buffer The line buffer to add.
997 **/
998 VOID
999 EFIAPI
1000 AddLineToCommandHistory(
1001 IN CONST CHAR16 *Buffer
1002 )
1003 {
1004 BUFFER_LIST *Node;
1005
1006 Node = AllocateZeroPool(sizeof(BUFFER_LIST));
1007 ASSERT(Node != NULL);
1008 Node->Buffer = AllocateZeroPool(StrSize(Buffer));
1009 ASSERT(Node->Buffer != NULL);
1010 StrCpy(Node->Buffer, Buffer);
1011
1012 InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);
1013 }
1014
1015 /**
1016 Checks if a string is an alias for another command. If yes, then it replaces the alias name
1017 with the correct command name.
1018
1019 @param[in,out] CommandString Upon entry the potential alias. Upon return the
1020 command name if it was an alias. If it was not
1021 an alias it will be unchanged. This function may
1022 change the buffer to fit the command name.
1023
1024 @retval EFI_SUCCESS The name was changed.
1025 @retval EFI_SUCCESS The name was not an alias.
1026 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1027 **/
1028 EFI_STATUS
1029 EFIAPI
1030 ShellConvertAlias(
1031 IN OUT CHAR16 **CommandString
1032 )
1033 {
1034 CONST CHAR16 *NewString;
1035
1036 NewString = ShellInfoObject.NewEfiShellProtocol->GetAlias(*CommandString, NULL);
1037 if (NewString == NULL) {
1038 return (EFI_SUCCESS);
1039 }
1040 FreePool(*CommandString);
1041 *CommandString = AllocateZeroPool(StrSize(NewString));
1042 if (*CommandString == NULL) {
1043 return (EFI_OUT_OF_RESOURCES);
1044 }
1045 StrCpy(*CommandString, NewString);
1046 return (EFI_SUCCESS);
1047 }
1048
1049 /**
1050 Function allocates a new command line and replaces all instances of environment
1051 variable names that are correctly preset to their values.
1052
1053 If the return value is not NULL the memory must be caller freed.
1054
1055 @param[in] OriginalCommandLine The original command line
1056
1057 @retval NULL An error ocurred.
1058 @return The new command line with no environment variables present.
1059 **/
1060 CHAR16*
1061 EFIAPI
1062 ShellConvertVariables (
1063 IN CONST CHAR16 *OriginalCommandLine
1064 )
1065 {
1066 CONST CHAR16 *MasterEnvList;
1067 UINTN NewSize;
1068 CHAR16 *NewCommandLine1;
1069 CHAR16 *NewCommandLine2;
1070 CHAR16 *Temp;
1071 UINTN ItemSize;
1072 CHAR16 *ItemTemp;
1073 SCRIPT_FILE *CurrentScriptFile;
1074 ALIAS_LIST *AliasListNode;
1075
1076 ASSERT(OriginalCommandLine != NULL);
1077
1078 ItemSize = 0;
1079 NewSize = StrSize(OriginalCommandLine);
1080 CurrentScriptFile = ShellCommandGetCurrentScriptFile();
1081 Temp = NULL;
1082
1083 ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ?
1084
1085 //
1086 // calculate the size required for the post-conversion string...
1087 //
1088 if (CurrentScriptFile != NULL) {
1089 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)
1090 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)
1091 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)
1092 ){
1093 for (Temp = StrStr(OriginalCommandLine, AliasListNode->Alias)
1094 ; Temp != NULL
1095 ; Temp = StrStr(Temp+1, AliasListNode->Alias)
1096 ){
1097 //
1098 // we need a preceeding and if there is space no ^ preceeding (if no space ignore)
1099 //
1100 if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) {
1101 NewSize += StrSize(AliasListNode->CommandString);
1102 }
1103 }
1104 }
1105 }
1106
1107 for (MasterEnvList = EfiShellGetEnv(NULL)
1108 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL
1109 ; MasterEnvList += StrLen(MasterEnvList) + 1
1110 ){
1111 if (StrSize(MasterEnvList) > ItemSize) {
1112 ItemSize = StrSize(MasterEnvList);
1113 }
1114 for (Temp = StrStr(OriginalCommandLine, MasterEnvList)
1115 ; Temp != NULL
1116 ; Temp = StrStr(Temp+1, MasterEnvList)
1117 ){
1118 //
1119 // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)
1120 //
1121 if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' &&
1122 ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) {
1123 NewSize+=StrSize(EfiShellGetEnv(MasterEnvList));
1124 }
1125 }
1126 }
1127
1128 //
1129 // Quick out if none were found...
1130 //
1131 if (NewSize == StrSize(OriginalCommandLine)) {
1132 ASSERT(Temp == NULL);
1133 Temp = StrnCatGrow(&Temp, NULL, OriginalCommandLine, 0);
1134 return (Temp);
1135 }
1136
1137 //
1138 // now do the replacements...
1139 //
1140 NewCommandLine1 = AllocateZeroPool(NewSize);
1141 NewCommandLine2 = AllocateZeroPool(NewSize);
1142 ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));
1143 if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {
1144 SHELL_FREE_NON_NULL(NewCommandLine1);
1145 SHELL_FREE_NON_NULL(NewCommandLine2);
1146 SHELL_FREE_NON_NULL(ItemTemp);
1147 return (NULL);
1148 }
1149 StrCpy(NewCommandLine1, OriginalCommandLine);
1150 for (MasterEnvList = EfiShellGetEnv(NULL)
1151 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL
1152 ; MasterEnvList += StrLen(MasterEnvList) + 1
1153 ){
1154 StrCpy(ItemTemp, L"%");
1155 StrCat(ItemTemp, MasterEnvList);
1156 StrCat(ItemTemp, L"%");
1157 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);
1158 StrCpy(NewCommandLine1, NewCommandLine2);
1159 }
1160 if (CurrentScriptFile != NULL) {
1161 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)
1162 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)
1163 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)
1164 ){
1165 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);
1166 StrCpy(NewCommandLine1, NewCommandLine2);
1167 }
1168 }
1169
1170 FreePool(NewCommandLine2);
1171 FreePool(ItemTemp);
1172
1173 return (NewCommandLine1);
1174 }
1175
1176 /**
1177 Internal function to run a command line with pipe usage.
1178
1179 @param[in] CmdLine The pointer to the command line.
1180 @param[in] StdIn The pointer to the Standard input.
1181 @param[in] StdOut The pointer to the Standard output.
1182
1183 @retval EFI_SUCCESS The split command is executed successfully.
1184 @retval other Some error occurs when executing the split command.
1185 **/
1186 EFI_STATUS
1187 EFIAPI
1188 RunSplitCommand(
1189 IN CONST CHAR16 *CmdLine,
1190 IN SHELL_FILE_HANDLE *StdIn,
1191 IN SHELL_FILE_HANDLE *StdOut
1192 )
1193 {
1194 EFI_STATUS Status;
1195 CHAR16 *NextCommandLine;
1196 CHAR16 *OurCommandLine;
1197 UINTN Size1;
1198 UINTN Size2;
1199 SPLIT_LIST *Split;
1200 SHELL_FILE_HANDLE *TempFileHandle;
1201 BOOLEAN Unicode;
1202
1203 ASSERT(StdOut == NULL);
1204
1205 ASSERT(StrStr(CmdLine, L"|") != NULL);
1206
1207 Status = EFI_SUCCESS;
1208 NextCommandLine = NULL;
1209 OurCommandLine = NULL;
1210 Size1 = 0;
1211 Size2 = 0;
1212
1213 NextCommandLine = StrnCatGrow(&NextCommandLine, &Size1, StrStr(CmdLine, L"|")+1, 0);
1214 OurCommandLine = StrnCatGrow(&OurCommandLine , &Size2, CmdLine , StrStr(CmdLine, L"|") - CmdLine);
1215 if (NextCommandLine[0] != CHAR_NULL &&
1216 NextCommandLine[0] == L'a' &&
1217 NextCommandLine[1] == L' '
1218 ){
1219 CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0]));
1220 Unicode = FALSE;
1221 } else {
1222 Unicode = TRUE;
1223 }
1224
1225
1226 //
1227 // make a SPLIT_LIST item and add to list
1228 //
1229 Split = AllocateZeroPool(sizeof(SPLIT_LIST));
1230 ASSERT(Split != NULL);
1231 Split->SplitStdIn = StdIn;
1232 Split->SplitStdOut = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL);
1233 ASSERT(Split->SplitStdOut != NULL);
1234 InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);
1235
1236 ASSERT(StrStr(OurCommandLine, L"|") == NULL);
1237 Status = RunCommand(OurCommandLine);
1238
1239 //
1240 // move the output from the first to the in to the second.
1241 //
1242 TempFileHandle = Split->SplitStdOut;
1243 if (Split->SplitStdIn == StdIn) {
1244 Split->SplitStdOut = NULL;
1245 } else {
1246 Split->SplitStdOut = Split->SplitStdIn;
1247 }
1248 Split->SplitStdIn = TempFileHandle;
1249 ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);
1250
1251 if (!EFI_ERROR(Status)) {
1252 Status = RunCommand(NextCommandLine);
1253 }
1254
1255 //
1256 // remove the top level from the ScriptList
1257 //
1258 ASSERT((SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link) == Split);
1259 RemoveEntryList(&Split->Link);
1260
1261 //
1262 // Note that the original StdIn is now the StdOut...
1263 //
1264 if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) {
1265 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));
1266 }
1267 if (Split->SplitStdIn != NULL) {
1268 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));
1269 }
1270
1271 FreePool(Split);
1272 FreePool(NextCommandLine);
1273 FreePool(OurCommandLine);
1274
1275 return (Status);
1276 }
1277
1278 /**
1279 Function will process and run a command line.
1280
1281 This will determine if the command line represents an internal shell
1282 command or dispatch an external application.
1283
1284 @param[in] CmdLine The command line to parse.
1285
1286 @retval EFI_SUCCESS The command was completed.
1287 @retval EFI_ABORTED The command's operation was aborted.
1288 **/
1289 EFI_STATUS
1290 EFIAPI
1291 RunCommand(
1292 IN CONST CHAR16 *CmdLine
1293 )
1294 {
1295 EFI_STATUS Status;
1296 CHAR16 *CommandName;
1297 SHELL_STATUS ShellStatus;
1298 UINTN Argc;
1299 CHAR16 **Argv;
1300 BOOLEAN LastError;
1301 CHAR16 LeString[11];
1302 CHAR16 *PostAliasCmdLine;
1303 UINTN PostAliasSize;
1304 CHAR16 *PostVariableCmdLine;
1305 CHAR16 *CommandWithPath;
1306 CONST EFI_DEVICE_PATH_PROTOCOL *DevPath;
1307 CONST CHAR16 *TempLocation;
1308 CONST CHAR16 *TempLocation2;
1309 SHELL_FILE_HANDLE OriginalStdIn;
1310 SHELL_FILE_HANDLE OriginalStdOut;
1311 SHELL_FILE_HANDLE OriginalStdErr;
1312 SYSTEM_TABLE_INFO OriginalSystemTableInfo;
1313 CHAR16 *TempLocation3;
1314 UINTN Count;
1315 UINTN Count2;
1316 CHAR16 *CleanOriginal;
1317 SPLIT_LIST *Split;
1318
1319 ASSERT(CmdLine != NULL);
1320 if (StrLen(CmdLine) == 0) {
1321 return (EFI_SUCCESS);
1322 }
1323
1324 CommandName = NULL;
1325 PostVariableCmdLine = NULL;
1326 PostAliasCmdLine = NULL;
1327 CommandWithPath = NULL;
1328 DevPath = NULL;
1329 Status = EFI_SUCCESS;
1330 CleanOriginal = NULL;
1331 Split = NULL;
1332
1333 CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0);
1334 while (CleanOriginal[StrLen(CleanOriginal)-1] == L' ') {
1335 CleanOriginal[StrLen(CleanOriginal)-1] = CHAR_NULL;
1336 }
1337 while (CleanOriginal[0] == L' ') {
1338 CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));
1339 }
1340
1341 CommandName = NULL;
1342 if (StrStr(CleanOriginal, L" ") == NULL){
1343 StrnCatGrow(&CommandName, NULL, CleanOriginal, 0);
1344 } else {
1345 StrnCatGrow(&CommandName, NULL, CleanOriginal, StrStr(CleanOriginal, L" ") - CleanOriginal);
1346 }
1347
1348 ASSERT(PostAliasCmdLine == NULL);
1349 if (!ShellCommandIsCommandOnList(CommandName)) {
1350 //
1351 // Convert via alias
1352 //
1353 Status = ShellConvertAlias(&CommandName);
1354 PostAliasSize = 0;
1355 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, CommandName, 0);
1356 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, StrStr(CleanOriginal, L" "), 0);
1357 ASSERT_EFI_ERROR(Status);
1358 } else {
1359 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, NULL, CleanOriginal, 0);
1360 }
1361
1362 if (CleanOriginal != NULL) {
1363 FreePool(CleanOriginal);
1364 CleanOriginal = NULL;
1365 }
1366
1367 if (CommandName != NULL) {
1368 FreePool(CommandName);
1369 CommandName = NULL;
1370 }
1371
1372 PostVariableCmdLine = ShellConvertVariables(PostAliasCmdLine);
1373
1374 //
1375 // we can now free the modified by alias command line
1376 //
1377 if (PostAliasCmdLine != NULL) {
1378 FreePool(PostAliasCmdLine);
1379 PostAliasCmdLine = NULL;
1380 }
1381
1382 if (PostVariableCmdLine == NULL) {
1383 return (EFI_OUT_OF_RESOURCES);
1384 }
1385
1386 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {
1387 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;
1388 }
1389 while (PostVariableCmdLine[0] == L' ') {
1390 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));
1391 }
1392
1393 //
1394 // We dont do normal processing with a split command line (output from one command input to another)
1395 //
1396 TempLocation3 = NULL;
1397 if (StrStr(PostVariableCmdLine, L"|") != NULL) {
1398 for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) {
1399 if (*TempLocation3 == L'^' && *(TempLocation3+1) == L'|') {
1400 TempLocation3++;
1401 } else if (*TempLocation3 == L'|') {
1402 break;
1403 }
1404 }
1405 }
1406 if (TempLocation3 != NULL && *TempLocation3 != CHAR_NULL) {
1407 //
1408 // are we in an existing split???
1409 //
1410 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {
1411 Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);
1412 }
1413
1414 if (Split == NULL) {
1415 Status = RunSplitCommand(PostVariableCmdLine, NULL, NULL);
1416 } else {
1417 Status = RunSplitCommand(PostVariableCmdLine, Split->SplitStdIn, Split->SplitStdOut);
1418 }
1419 } else {
1420
1421 //
1422 // If this is a mapped drive change handle that...
1423 //
1424 if (PostVariableCmdLine[(StrLen(PostVariableCmdLine)-1)] == L':' && StrStr(PostVariableCmdLine, L" ") == NULL) {
1425 Status = ShellInfoObject.NewEfiShellProtocol->SetCurDir(NULL, PostVariableCmdLine);
1426 if (EFI_ERROR(Status)) {
1427 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_MAPPING), ShellInfoObject.HiiHandle, PostVariableCmdLine);
1428 }
1429 FreePool(PostVariableCmdLine);
1430 return (Status);
1431 }
1432
1433 ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file...
1434 /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files...
1435
1436
1437
1438 Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);
1439 if (EFI_ERROR(Status)) {
1440 if (Status == EFI_NOT_FOUND) {
1441 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle);
1442 } else {
1443 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);
1444 }
1445 } else {
1446 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {
1447 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;
1448 }
1449 while (PostVariableCmdLine[0] == L' ') {
1450 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));
1451 }
1452
1453 //
1454 // get the argc and argv updated for internal commands
1455 //
1456 Status = UpdateArgcArgv(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &Argv, &Argc);
1457 ASSERT_EFI_ERROR(Status);
1458
1459 for (Count = 0 ; Count < ShellInfoObject.NewShellParametersProtocol->Argc ; Count++) {
1460 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[Count], L"-?") == ShellInfoObject.NewShellParametersProtocol->Argv[Count]
1461 || (ShellInfoObject.NewShellParametersProtocol->Argv[0][0] == L'?' && ShellInfoObject.NewShellParametersProtocol->Argv[0][1] == CHAR_NULL)
1462 ) {
1463 //
1464 // We need to redo the arguments since a parameter was -?
1465 // move them all down 1 to the end, then up one then replace the first with help
1466 //
1467 FreePool(ShellInfoObject.NewShellParametersProtocol->Argv[Count]);
1468 ShellInfoObject.NewShellParametersProtocol->Argv[Count] = NULL;
1469 for (Count2 = Count ; (Count2 + 1) < ShellInfoObject.NewShellParametersProtocol->Argc ; Count2++) {
1470 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2+1];
1471 }
1472 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = NULL;
1473 for (Count2 = ShellInfoObject.NewShellParametersProtocol->Argc -1 ; Count2 > 0 ; Count2--) {
1474 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2-1];
1475 }
1476 ShellInfoObject.NewShellParametersProtocol->Argv[0] = NULL;
1477 ShellInfoObject.NewShellParametersProtocol->Argv[0] = StrnCatGrow(&ShellInfoObject.NewShellParametersProtocol->Argv[0], NULL, L"help", 0);
1478 break;
1479 }
1480 }
1481
1482 //
1483 // command or file?
1484 //
1485 if (ShellCommandIsCommandOnList(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {
1486 //
1487 // Run the command (which was converted if it was an alias)
1488 //
1489 if (!EFI_ERROR(Status)) {
1490 Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError);
1491 ASSERT_EFI_ERROR(Status);
1492 UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%08x", ShellStatus);
1493 DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE););
1494 if (LastError) {
1495 InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE);
1496 }
1497 //
1498 // Pass thru the exitcode from the app.
1499 //
1500 if (ShellCommandGetExit()) {
1501 Status = ShellStatus;
1502 } else if (ShellStatus != 0 && IsScriptOnlyCommand(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {
1503 Status = EFI_ABORTED;
1504 }
1505 }
1506 } else {
1507 //
1508 // run an external file (or script)
1509 //
1510 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[0], L":") != NULL) {
1511 ASSERT (CommandWithPath == NULL);
1512 if (ShellIsFile(ShellInfoObject.NewShellParametersProtocol->Argv[0]) == EFI_SUCCESS) {
1513 CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);
1514 }
1515 }
1516 if (CommandWithPath == NULL) {
1517 CommandWithPath = ShellFindFilePathEx(ShellInfoObject.NewShellParametersProtocol->Argv[0], mExecutableExtensions);
1518 }
1519 if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) {
1520 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]);
1521 } else {
1522 //
1523 // Check if it's a NSH (script) file.
1524 //
1525 TempLocation = CommandWithPath+StrLen(CommandWithPath)-4;
1526 TempLocation2 = mScriptExtension;
1527 if ((StrLen(CommandWithPath) > 4) && (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0)) {
1528 Status = RunScriptFile (CommandWithPath);
1529 } else {
1530 DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath);
1531 ASSERT(DevPath != NULL);
1532 Status = InternalShellExecuteDevicePath(
1533 &gImageHandle,
1534 DevPath,
1535 PostVariableCmdLine,
1536 NULL,
1537 NULL
1538 );
1539 }
1540 }
1541 }
1542 CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);
1543
1544 RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);
1545
1546 RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);
1547 }
1548 if (CommandName != NULL) {
1549 if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) {
1550 //
1551 // if this is NOT a scipt only command return success so the script won't quit.
1552 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)
1553 //
1554 Status = EFI_SUCCESS;
1555 }
1556 }
1557 }
1558
1559 SHELL_FREE_NON_NULL(CommandName);
1560 SHELL_FREE_NON_NULL(CommandWithPath);
1561 SHELL_FREE_NON_NULL(PostVariableCmdLine);
1562
1563 return (Status);
1564 }
1565
1566 STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};
1567 /**
1568 Function determins if the CommandName COULD be a valid command. It does not determine whether
1569 this is a valid command. It only checks for invalid characters.
1570
1571 @param[in] CommandName The name to check
1572
1573 @retval TRUE CommandName could be a command name
1574 @retval FALSE CommandName could not be a valid command name
1575 **/
1576 BOOLEAN
1577 EFIAPI
1578 IsValidCommandName(
1579 IN CONST CHAR16 *CommandName
1580 )
1581 {
1582 UINTN Count;
1583 if (CommandName == NULL) {
1584 ASSERT(FALSE);
1585 return (FALSE);
1586 }
1587 for ( Count = 0
1588 ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])
1589 ; Count++
1590 ){
1591 if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {
1592 return (FALSE);
1593 }
1594 }
1595 return (TRUE);
1596 }
1597
1598 /**
1599 Function to process a NSH script file via SHELL_FILE_HANDLE.
1600
1601 @param[in] Handle The handle to the already opened file.
1602 @param[in] Name The name of the script file.
1603
1604 @retval EFI_SUCCESS the script completed sucessfully
1605 **/
1606 EFI_STATUS
1607 EFIAPI
1608 RunScriptFileHandle (
1609 IN SHELL_FILE_HANDLE Handle,
1610 IN CONST CHAR16 *Name
1611 )
1612 {
1613 EFI_STATUS Status;
1614 SCRIPT_FILE *NewScriptFile;
1615 UINTN LoopVar;
1616 CHAR16 *CommandLine;
1617 CHAR16 *CommandLine2;
1618 CHAR16 *CommandLine3;
1619 SCRIPT_COMMAND_LIST *LastCommand;
1620 BOOLEAN Ascii;
1621 BOOLEAN PreScriptEchoState;
1622 CONST CHAR16 *CurDir;
1623 UINTN LineCount;
1624
1625 ASSERT(!ShellCommandGetScriptExit());
1626
1627 PreScriptEchoState = ShellCommandGetEchoState();
1628
1629 NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));
1630 if (NewScriptFile == NULL) {
1631 return (EFI_OUT_OF_RESOURCES);
1632 }
1633
1634 //
1635 // Set up the name
1636 //
1637 ASSERT(NewScriptFile->ScriptName == NULL);
1638 NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0);
1639 if (NewScriptFile->ScriptName == NULL) {
1640 DeleteScriptFileStruct(NewScriptFile);
1641 return (EFI_OUT_OF_RESOURCES);
1642 }
1643
1644 //
1645 // Save the parameters (used to replace %0 to %9 later on)
1646 //
1647 NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc;
1648 if (NewScriptFile->Argc != 0) {
1649 NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*));
1650 if (NewScriptFile->Argv == NULL) {
1651 DeleteScriptFileStruct(NewScriptFile);
1652 return (EFI_OUT_OF_RESOURCES);
1653 }
1654 for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {
1655 ASSERT(NewScriptFile->Argv[LoopVar] == NULL);
1656 NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);
1657 if (NewScriptFile->Argv[LoopVar] == NULL) {
1658 DeleteScriptFileStruct(NewScriptFile);
1659 return (EFI_OUT_OF_RESOURCES);
1660 }
1661 }
1662 } else {
1663 NewScriptFile->Argv = NULL;
1664 }
1665
1666 InitializeListHead(&NewScriptFile->CommandList);
1667 InitializeListHead(&NewScriptFile->SubstList);
1668
1669 //
1670 // Now build the list of all script commands.
1671 //
1672 LineCount = 0;
1673 while(!ShellFileHandleEof(Handle)) {
1674 CommandLine = ShellFileHandleReturnLine(Handle, &Ascii);
1675 LineCount++;
1676 if (CommandLine == NULL || StrLen(CommandLine) == 0) {
1677 continue;
1678 }
1679 NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST));
1680 if (NewScriptFile->CurrentCommand == NULL) {
1681 DeleteScriptFileStruct(NewScriptFile);
1682 return (EFI_OUT_OF_RESOURCES);
1683 }
1684
1685 NewScriptFile->CurrentCommand->Cl = CommandLine;
1686 NewScriptFile->CurrentCommand->Data = NULL;
1687 NewScriptFile->CurrentCommand->Line = LineCount;
1688
1689 InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);
1690 }
1691
1692 //
1693 // Add this as the topmost script file
1694 //
1695 ShellCommandSetNewScript (NewScriptFile);
1696
1697 //
1698 // Now enumerate through the commands and run each one.
1699 //
1700 CommandLine = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));
1701 if (CommandLine == NULL) {
1702 DeleteScriptFileStruct(NewScriptFile);
1703 return (EFI_OUT_OF_RESOURCES);
1704 }
1705 CommandLine2 = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));
1706 if (CommandLine2 == NULL) {
1707 FreePool(CommandLine);
1708 DeleteScriptFileStruct(NewScriptFile);
1709 return (EFI_OUT_OF_RESOURCES);
1710 }
1711
1712 for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList)
1713 ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)
1714 ; // conditional increment in the body of the loop
1715 ){
1716 ASSERT(CommandLine2 != NULL);
1717 StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);
1718
1719 //
1720 // NULL out comments
1721 //
1722 for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {
1723 if (*CommandLine3 == L'^') {
1724 if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {
1725 CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));
1726 }
1727 } else if (*CommandLine3 == L'#') {
1728 *CommandLine3 = CHAR_NULL;
1729 }
1730 }
1731
1732 if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) {
1733 //
1734 // Due to variability in starting the find and replace action we need to have both buffers the same.
1735 //
1736 StrCpy(CommandLine, CommandLine2);
1737
1738 //
1739 // Remove the %0 to %9 from the command line (if we have some arguments)
1740 //
1741 if (NewScriptFile->Argv != NULL) {
1742 switch (NewScriptFile->Argc) {
1743 default:
1744 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);
1745 ASSERT_EFI_ERROR(Status);
1746 case 9:
1747 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);
1748 ASSERT_EFI_ERROR(Status);
1749 case 8:
1750 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);
1751 ASSERT_EFI_ERROR(Status);
1752 case 7:
1753 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);
1754 ASSERT_EFI_ERROR(Status);
1755 case 6:
1756 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);
1757 ASSERT_EFI_ERROR(Status);
1758 case 5:
1759 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);
1760 ASSERT_EFI_ERROR(Status);
1761 case 4:
1762 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);
1763 ASSERT_EFI_ERROR(Status);
1764 case 3:
1765 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);
1766 ASSERT_EFI_ERROR(Status);
1767 case 2:
1768 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);
1769 ASSERT_EFI_ERROR(Status);
1770 case 1:
1771 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);
1772 ASSERT_EFI_ERROR(Status);
1773 break;
1774 case 0:
1775 break;
1776 }
1777 }
1778 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE);
1779 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE);
1780 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE);
1781 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE);
1782 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE);
1783 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE);
1784 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE);
1785 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);
1786 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);
1787
1788 StrCpy(CommandLine2, CommandLine);
1789
1790 LastCommand = NewScriptFile->CurrentCommand;
1791
1792 for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++);
1793
1794 if (CommandLine3 != NULL && CommandLine3[0] == L':' ) {
1795 //
1796 // This line is a goto target / label
1797 //
1798 } else {
1799 if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) {
1800 if (ShellCommandGetEchoState()) {
1801 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");
1802 if (CurDir != NULL && StrLen(CurDir) > 1) {
1803 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);
1804 } else {
1805 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);
1806 }
1807 ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);
1808 }
1809 Status = RunCommand(CommandLine3);
1810 }
1811
1812 if (ShellCommandGetScriptExit()) {
1813 ShellCommandRegisterExit(FALSE);
1814 Status = EFI_SUCCESS;
1815 break;
1816 }
1817 if (EFI_ERROR(Status)) {
1818 break;
1819 }
1820 if (ShellCommandGetExit()) {
1821 break;
1822 }
1823 }
1824 //
1825 // If that commend did not update the CurrentCommand then we need to advance it...
1826 //
1827 if (LastCommand == NewScriptFile->CurrentCommand) {
1828 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);
1829 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {
1830 NewScriptFile->CurrentCommand->Reset = TRUE;
1831 }
1832 }
1833 } else {
1834 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);
1835 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {
1836 NewScriptFile->CurrentCommand->Reset = TRUE;
1837 }
1838 }
1839 }
1840
1841
1842 FreePool(CommandLine);
1843 FreePool(CommandLine2);
1844 ShellCommandSetNewScript (NULL);
1845
1846 //
1847 // Only if this was the last script reset the state.
1848 //
1849 if (ShellCommandGetCurrentScriptFile()==NULL) {
1850 ShellCommandSetEchoState(PreScriptEchoState);
1851 }
1852 return (EFI_SUCCESS);
1853 }
1854
1855 /**
1856 Function to process a NSH script file.
1857
1858 @param[in] ScriptPath Pointer to the script file name (including file system path).
1859
1860 @retval EFI_SUCCESS the script completed sucessfully
1861 **/
1862 EFI_STATUS
1863 EFIAPI
1864 RunScriptFile (
1865 IN CONST CHAR16 *ScriptPath
1866 )
1867 {
1868 EFI_STATUS Status;
1869 SHELL_FILE_HANDLE FileHandle;
1870
1871 if (ShellIsFile(ScriptPath) != EFI_SUCCESS) {
1872 return (EFI_INVALID_PARAMETER);
1873 }
1874
1875 Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);
1876 if (EFI_ERROR(Status)) {
1877 return (Status);
1878 }
1879
1880 Status = RunScriptFileHandle(FileHandle, ScriptPath);
1881
1882 ShellCloseFile(&FileHandle);
1883
1884 return (Status);
1885 }