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