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