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