2 This is THE shell (application)
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
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.
18 // Initialize the global structure
20 SHELL_INFO ShellInfoObject
= {
62 STATIC CONST CHAR16 mScriptExtension
[] = L
".NSH";
63 STATIC CONST CHAR16 mExecutableExtensions
[] = L
".NSH;.EFI";
64 STATIC CONST CHAR16 mStartupScript
[] = L
"startup.nsh";
67 Function to start monitoring for CTRL-S using SimpleTextInputEx. This
68 feature's enabled state was not known when the shell initially launched.
70 @retval EFI_SUCCESS The feature is enabled.
71 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
75 InternalEfiShellStartCtrlSMonitor(
79 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
83 Status
= gBS
->OpenProtocol(
85 &gEfiSimpleTextInputExProtocolGuid
,
89 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
90 if (EFI_ERROR(Status
)) {
95 STRING_TOKEN (STR_SHELL_NO_IN_EX
),
96 ShellInfoObject
.HiiHandle
);
100 KeyData
.KeyState
.KeyToggleState
= 0;
101 KeyData
.Key
.ScanCode
= 0;
102 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
103 KeyData
.Key
.UnicodeChar
= L
's';
105 Status
= SimpleEx
->RegisterKeyNotify(
108 NotificationFunction
,
109 &ShellInfoObject
.CtrlSNotifyHandle1
);
111 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
112 if (!EFI_ERROR(Status
)) {
113 Status
= SimpleEx
->RegisterKeyNotify(
116 NotificationFunction
,
117 &ShellInfoObject
.CtrlSNotifyHandle2
);
119 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
120 KeyData
.Key
.UnicodeChar
= 19;
122 if (!EFI_ERROR(Status
)) {
123 Status
= SimpleEx
->RegisterKeyNotify(
126 NotificationFunction
,
127 &ShellInfoObject
.CtrlSNotifyHandle2
);
129 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
130 if (!EFI_ERROR(Status
)) {
131 Status
= SimpleEx
->RegisterKeyNotify(
134 NotificationFunction
,
135 &ShellInfoObject
.CtrlSNotifyHandle2
);
143 The entry point for the application.
145 @param[in] ImageHandle The firmware allocated handle for the EFI image.
146 @param[in] SystemTable A pointer to the EFI System Table.
148 @retval EFI_SUCCESS The entry point is executed successfully.
149 @retval other Some error occurs when executing this entry point.
155 IN EFI_HANDLE ImageHandle
,
156 IN EFI_SYSTEM_TABLE
*SystemTable
162 EFI_HANDLE ConInHandle
;
163 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*OldConIn
;
165 if (PcdGet8(PcdShellSupportLevel
) > 3) {
166 return (EFI_UNSUPPORTED
);
172 Status
= gST
->ConOut
->ClearScreen(gST
->ConOut
);
173 if (EFI_ERROR(Status
)) {
178 // Populate the global structure from PCDs
180 ShellInfoObject
.ImageDevPath
= NULL
;
181 ShellInfoObject
.FileDevPath
= NULL
;
182 ShellInfoObject
.PageBreakEnabled
= PcdGetBool(PcdShellPageBreakDefault
);
183 ShellInfoObject
.ViewingSettings
.InsertMode
= PcdGetBool(PcdShellInsertModeDefault
);
184 ShellInfoObject
.LogScreenCount
= PcdGet8 (PcdShellScreenLogCount
);
187 // verify we dont allow for spec violation
189 ASSERT(ShellInfoObject
.LogScreenCount
>= 3);
192 // Initialize the LIST ENTRY objects...
194 InitializeListHead(&ShellInfoObject
.BufferToFreeList
.Link
);
195 InitializeListHead(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
);
196 InitializeListHead(&ShellInfoObject
.SplitList
.Link
);
199 // Check PCDs for optional features that are not implemented yet.
201 if ( PcdGetBool(PcdShellSupportOldProtocols
)
202 || !FeaturePcdGet(PcdShellRequireHiiPlatform
)
203 || FeaturePcdGet(PcdShellSupportFrameworkHii
)
205 return (EFI_UNSUPPORTED
);
209 // turn off the watchdog timer
211 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);
214 // install our console logger. This will keep a log of the output for back-browsing
216 Status
= ConsoleLoggerInstall(ShellInfoObject
.LogScreenCount
, &ShellInfoObject
.ConsoleInfo
);
217 if (!EFI_ERROR(Status
)) {
219 // Enable the cursor to be visible
221 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
224 // If supporting EFI 1.1 we need to install HII protocol
225 // only do this if PcdShellRequireHiiPlatform == FALSE
227 // remove EFI_UNSUPPORTED check above when complete.
228 ///@todo add support for Framework HII
231 // install our (solitary) HII package
233 ShellInfoObject
.HiiHandle
= HiiAddPackages (&gEfiCallerIdGuid
, gImageHandle
, ShellStrings
, NULL
);
234 if (ShellInfoObject
.HiiHandle
== NULL
) {
235 if (PcdGetBool(PcdShellSupportFrameworkHii
)) {
236 ///@todo Add our package into Framework HII
238 if (ShellInfoObject
.HiiHandle
== NULL
) {
239 return (EFI_NOT_STARTED
);
244 // create and install the EfiShellParametersProtocol
246 Status
= CreatePopulateInstallShellParametersProtocol(&ShellInfoObject
.NewShellParametersProtocol
, &ShellInfoObject
.RootShellInstance
);
247 ASSERT_EFI_ERROR(Status
);
248 ASSERT(ShellInfoObject
.NewShellParametersProtocol
!= NULL
);
251 // create and install the EfiShellProtocol
253 Status
= CreatePopulateInstallShellProtocol(&ShellInfoObject
.NewEfiShellProtocol
);
254 ASSERT_EFI_ERROR(Status
);
255 ASSERT(ShellInfoObject
.NewEfiShellProtocol
!= NULL
);
258 // Now initialize the shell library (it requires Shell Parameters protocol)
260 Status
= ShellInitialize();
261 ASSERT_EFI_ERROR(Status
);
263 Status
= CommandInit();
264 ASSERT_EFI_ERROR(Status
);
267 // Check the command line
269 Status
= ProcessCommandLine();
272 // If shell support level is >= 1 create the mappings and paths
274 if (PcdGet8(PcdShellSupportLevel
) >= 1) {
275 Status
= ShellCommandCreateInitialMappingsAndPaths();
279 // save the device path for the loaded image and the device path for the filepath (under loaded image)
280 // These are where to look for the startup.nsh file
282 Status
= GetDevicePathsForImageAndFile(&ShellInfoObject
.ImageDevPath
, &ShellInfoObject
.FileDevPath
);
283 ASSERT_EFI_ERROR(Status
);
286 // Display the version
288 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoVersion
) {
291 gST
->ConOut
->Mode
->CursorRow
,
293 STRING_TOKEN (STR_VER_OUTPUT_MAIN
),
294 ShellInfoObject
.HiiHandle
,
295 SupportLevel
[PcdGet8(PcdShellSupportLevel
)],
296 gEfiShellProtocol
->MajorVersion
,
297 gEfiShellProtocol
->MinorVersion
,
298 (gST
->Hdr
.Revision
&0xffff0000)>>16,
299 (gST
->Hdr
.Revision
&0x0000ffff),
301 gST
->FirmwareRevision
306 // Display the mapping
308 if (PcdGet8(PcdShellSupportLevel
) >= 2 && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoMap
) {
309 Status
= RunCommand(L
"map");
310 ASSERT_EFI_ERROR(Status
);
314 // init all the built in alias'
316 Status
= SetBuiltInAlias();
317 ASSERT_EFI_ERROR(Status
);
320 // Initialize environment variables
322 if (ShellCommandGetProfileList() != NULL
) {
323 Status
= InternalEfiShellSetEnv(L
"profiles", ShellCommandGetProfileList(), TRUE
);
324 ASSERT_EFI_ERROR(Status
);
328 TempString
= AllocateZeroPool(Size
);
330 UnicodeSPrint(TempString
, Size
, L
"%d", PcdGet8(PcdShellSupportLevel
));
331 Status
= InternalEfiShellSetEnv(L
"uefishellsupport", TempString
, TRUE
);
332 ASSERT_EFI_ERROR(Status
);
334 UnicodeSPrint(TempString
, Size
, L
"%d.%d", ShellInfoObject
.NewEfiShellProtocol
->MajorVersion
, ShellInfoObject
.NewEfiShellProtocol
->MinorVersion
);
335 Status
= InternalEfiShellSetEnv(L
"uefishellversion", TempString
, TRUE
);
336 ASSERT_EFI_ERROR(Status
);
338 UnicodeSPrint(TempString
, Size
, L
"%d.%d", (gST
->Hdr
.Revision
& 0xFFFF0000) >> 16, gST
->Hdr
.Revision
& 0x0000FFFF);
339 Status
= InternalEfiShellSetEnv(L
"uefiversion", TempString
, TRUE
);
340 ASSERT_EFI_ERROR(Status
);
342 FreePool(TempString
);
344 if (!EFI_ERROR(Status
)) {
345 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
) {
347 // Set up the event for CTRL-C monitoring...
349 Status
= InernalEfiShellStartMonitor();
352 if (!EFI_ERROR(Status
) && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
354 // Set up the event for CTRL-S monitoring...
356 Status
= InternalEfiShellStartCtrlSMonitor();
359 if (!EFI_ERROR(Status
) && ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
361 // close off the gST->ConIn
363 OldConIn
= gST
->ConIn
;
364 ConInHandle
= gST
->ConsoleInHandle
;
365 gST
->ConIn
= CreateSimpleTextInOnFile((SHELL_FILE_HANDLE
)&FileInterfaceNulFile
, &gST
->ConsoleInHandle
);
371 if (!EFI_ERROR(Status
) && PcdGet8(PcdShellSupportLevel
) >= 1) {
373 // process the startup script or launch the called app.
375 Status
= DoStartupScript(ShellInfoObject
.ImageDevPath
, ShellInfoObject
.FileDevPath
);
378 if (!ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel
) >= 3 || PcdGetBool(PcdShellForceConsole
)) && !EFI_ERROR(Status
) && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
380 // begin the UI waiting loop
384 // clean out all the memory allocated for CONST <something> * return values
385 // between each shell prompt presentation
387 if (!IsListEmpty(&ShellInfoObject
.BufferToFreeList
.Link
)){
388 FreeBufferList(&ShellInfoObject
.BufferToFreeList
);
392 // Reset page break back to default.
394 ShellInfoObject
.PageBreakEnabled
= PcdGetBool(PcdShellPageBreakDefault
);
395 ShellInfoObject
.ConsoleInfo
->Enabled
= TRUE
;
396 ShellInfoObject
.ConsoleInfo
->RowCounter
= 0;
399 // Reset the CTRL-C event (yes we ignore the return values)
401 Status
= gBS
->CheckEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
);
406 Status
= DoShellPrompt();
407 } while (!ShellCommandGetExit());
409 if (OldConIn
!= NULL
&& ConInHandle
!= NULL
) {
410 CloseSimpleTextInOnFile (gST
->ConIn
);
411 gST
->ConIn
= OldConIn
;
412 gST
->ConsoleInHandle
= ConInHandle
;
418 // uninstall protocols / free memory / etc...
420 if (ShellInfoObject
.UserBreakTimer
!= NULL
) {
421 gBS
->CloseEvent(ShellInfoObject
.UserBreakTimer
);
422 DEBUG_CODE(ShellInfoObject
.UserBreakTimer
= NULL
;);
424 if (ShellInfoObject
.ImageDevPath
!= NULL
) {
425 FreePool(ShellInfoObject
.ImageDevPath
);
426 DEBUG_CODE(ShellInfoObject
.ImageDevPath
= NULL
;);
428 if (ShellInfoObject
.FileDevPath
!= NULL
) {
429 FreePool(ShellInfoObject
.FileDevPath
);
430 DEBUG_CODE(ShellInfoObject
.FileDevPath
= NULL
;);
432 if (ShellInfoObject
.NewShellParametersProtocol
!= NULL
) {
433 CleanUpShellParametersProtocol(ShellInfoObject
.NewShellParametersProtocol
);
434 DEBUG_CODE(ShellInfoObject
.NewShellParametersProtocol
= NULL
;);
436 if (ShellInfoObject
.NewEfiShellProtocol
!= NULL
){
437 if (ShellInfoObject
.NewEfiShellProtocol
->IsRootShell()){
438 ShellInfoObject
.NewEfiShellProtocol
->SetEnv(L
"cwd", L
"", TRUE
);
440 CleanUpShellProtocol(ShellInfoObject
.NewEfiShellProtocol
);
441 DEBUG_CODE(ShellInfoObject
.NewEfiShellProtocol
= NULL
;);
444 if (!IsListEmpty(&ShellInfoObject
.BufferToFreeList
.Link
)){
445 FreeBufferList(&ShellInfoObject
.BufferToFreeList
);
448 if (!IsListEmpty(&ShellInfoObject
.SplitList
.Link
)){
449 ASSERT(FALSE
); ///@todo finish this de-allocation.
452 if (ShellInfoObject
.ShellInitSettings
.FileName
!= NULL
) {
453 FreePool(ShellInfoObject
.ShellInitSettings
.FileName
);
454 DEBUG_CODE(ShellInfoObject
.ShellInitSettings
.FileName
= NULL
;);
457 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
458 FreePool(ShellInfoObject
.ShellInitSettings
.FileOptions
);
459 DEBUG_CODE(ShellInfoObject
.ShellInitSettings
.FileOptions
= NULL
;);
462 if (ShellInfoObject
.HiiHandle
!= NULL
) {
463 HiiRemovePackages(ShellInfoObject
.HiiHandle
);
464 DEBUG_CODE(ShellInfoObject
.HiiHandle
= NULL
;);
467 if (!IsListEmpty(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
)){
468 FreeBufferList(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
471 ASSERT(ShellInfoObject
.ConsoleInfo
!= NULL
);
472 if (ShellInfoObject
.ConsoleInfo
!= NULL
) {
473 ConsoleLoggerUninstall(ShellInfoObject
.ConsoleInfo
);
474 FreePool(ShellInfoObject
.ConsoleInfo
);
475 DEBUG_CODE(ShellInfoObject
.ConsoleInfo
= NULL
;);
478 if (ShellCommandGetExit()) {
479 return ((EFI_STATUS
)ShellCommandGetExitCode());
485 Sets all the alias' that were registered with the ShellCommandLib library.
487 @retval EFI_SUCCESS all init commands were run sucessfully.
495 CONST ALIAS_LIST
*List
;
499 // Get all the commands we want to run
501 List
= ShellCommandGetInitAliasList();
504 // for each command in the List
506 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&List
->Link
)
507 ; !IsNull (&List
->Link
, &Node
->Link
)
508 ; Node
= (ALIAS_LIST
*)GetNextNode(&List
->Link
, &Node
->Link
)
511 // install the alias'
513 Status
= InternalSetAlias(Node
->CommandString
, Node
->Alias
, TRUE
);
514 ASSERT_EFI_ERROR(Status
);
516 return (EFI_SUCCESS
);
520 Internal function to determine if 2 command names are really the same.
522 @param[in] Command1 The pointer to the first command name.
523 @param[in] Command2 The pointer to the second command name.
525 @retval TRUE The 2 command names are the same.
526 @retval FALSE The 2 command names are not the same.
531 IN CONST CHAR16
*Command1
,
532 IN CONST CHAR16
*Command2
535 if (StringNoCaseCompare(&Command1
, &Command2
) == 0) {
542 Internal function to determine if a command is a script only command.
544 @param[in] CommandName The pointer to the command name.
546 @retval TRUE The command is a script only command.
547 @retval FALSE The command is not a script only command.
552 IN CONST CHAR16
*CommandName
555 if (IsCommand(CommandName
, L
"for")
556 ||IsCommand(CommandName
, L
"endfor")
557 ||IsCommand(CommandName
, L
"if")
558 ||IsCommand(CommandName
, L
"else")
559 ||IsCommand(CommandName
, L
"endif")
560 ||IsCommand(CommandName
, L
"goto")) {
567 This function will populate the 2 device path protocol parameters based on the
568 global gImageHandle. The DevPath will point to the device path for the handle that has
569 loaded image protocol installed on it. The FilePath will point to the device path
570 for the file that was loaded.
572 @param[in, out] DevPath On a sucessful return the device path to the loaded image.
573 @param[in, out] FilePath On a sucessful return the device path to the file.
575 @retval EFI_SUCCESS The 2 device paths were sucessfully returned.
576 @retval other A error from gBS->HandleProtocol.
582 GetDevicePathsForImageAndFile (
583 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevPath
,
584 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
588 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
589 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
591 ASSERT(DevPath
!= NULL
);
592 ASSERT(FilePath
!= NULL
);
594 Status
= gBS
->OpenProtocol (
596 &gEfiLoadedImageProtocolGuid
,
597 (VOID
**)&LoadedImage
,
600 EFI_OPEN_PROTOCOL_GET_PROTOCOL
602 if (!EFI_ERROR (Status
)) {
603 Status
= gBS
->OpenProtocol (
604 LoadedImage
->DeviceHandle
,
605 &gEfiDevicePathProtocolGuid
,
606 (VOID
**)&ImageDevicePath
,
609 EFI_OPEN_PROTOCOL_GET_PROTOCOL
611 if (!EFI_ERROR (Status
)) {
612 *DevPath
= DuplicateDevicePath (ImageDevicePath
);
613 *FilePath
= DuplicateDevicePath (LoadedImage
->FilePath
);
615 LoadedImage
->DeviceHandle
,
616 &gEfiDevicePathProtocolGuid
,
622 &gEfiLoadedImageProtocolGuid
,
629 STATIC CONST SHELL_PARAM_ITEM mShellParamList
[] = {
630 {L
"-nostartup", TypeFlag
},
631 {L
"-startup", TypeFlag
},
632 {L
"-noconsoleout", TypeFlag
},
633 {L
"-noconsolein", TypeFlag
},
634 {L
"-nointerrupt", TypeFlag
},
635 {L
"-nomap", TypeFlag
},
636 {L
"-noversion", TypeFlag
},
637 {L
"-startup", TypeFlag
},
638 {L
"-delay", TypeValue
},
643 Process all Uefi Shell 2.0 command line options.
645 see Uefi Shell 2.0 section 3.2 for full details.
647 the command line must resemble the following:
649 shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]
651 ShellOpt-options Options which control the initialization behavior of the shell.
652 These options are read from the EFI global variable "ShellOpt"
653 and are processed before options or file-name.
655 options Options which control the initialization behavior of the shell.
657 file-name The name of a UEFI shell application or script to be executed
658 after initialization is complete. By default, if file-name is
659 specified, then -nostartup is implied. Scripts are not supported
662 file-name-options The command-line options that are passed to file-name when it
665 This will initialize the ShellInfoObject.ShellInitSettings global variable.
667 @retval EFI_SUCCESS The variable is initialized.
678 CONST CHAR16
*TempConst
;
681 CHAR16
*ProblemParam
;
687 Status
= ShellCommandLineParse (mShellParamList
, &Package
, NULL
, FALSE
);
691 TempConst
= ShellCommandLineGetRawValue(Package
, Count
++);
692 if (TempConst
!= NULL
&& StrLen(TempConst
)) {
693 ShellInfoObject
.ShellInitSettings
.FileName
= AllocateZeroPool(StrSize(TempConst
));
694 if (ShellInfoObject
.ShellInitSettings
.FileName
== NULL
) {
695 return (EFI_OUT_OF_RESOURCES
);
697 StrCpy(ShellInfoObject
.ShellInitSettings
.FileName
, TempConst
);
698 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
= 1;
699 for (LoopVar
= 0 ; LoopVar
< gEfiShellParametersProtocol
->Argc
; LoopVar
++) {
700 if (StrCmp(gEfiShellParametersProtocol
->Argv
[LoopVar
], ShellInfoObject
.ShellInitSettings
.FileName
)==0) {
703 // We found the file... add the rest of the params...
705 for ( ; LoopVar
< gEfiShellParametersProtocol
->Argc
; LoopVar
++) {
706 ASSERT((ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
&& Size
== 0) || (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
));
707 StrnCatGrow(&ShellInfoObject
.ShellInitSettings
.FileOptions
,
711 if (ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
) {
712 SHELL_FREE_NON_NULL(ShellInfoObject
.ShellInitSettings
.FileName
);
713 return (EFI_OUT_OF_RESOURCES
);
715 StrnCatGrow(&ShellInfoObject
.ShellInitSettings
.FileOptions
,
717 gEfiShellParametersProtocol
->Argv
[LoopVar
],
719 if (ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
) {
720 SHELL_FREE_NON_NULL(ShellInfoObject
.ShellInitSettings
.FileName
);
721 return (EFI_OUT_OF_RESOURCES
);
727 ShellCommandLineFreeVarList(Package
);
729 Status
= ShellCommandLineParse (mShellParamList
, &Package
, &ProblemParam
, FALSE
);
730 if (EFI_ERROR(Status
)) {
731 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), ShellInfoObject
.HiiHandle
, ProblemParam
);
732 FreePool(ProblemParam
);
733 ShellCommandLineFreeVarList(Package
);
734 return (EFI_INVALID_PARAMETER
);
738 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
= ShellCommandLineGetFlag(Package
, L
"-startup");
739 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
= ShellCommandLineGetFlag(Package
, L
"-nostartup");
740 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
= ShellCommandLineGetFlag(Package
, L
"-noconsoleout");
741 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
= ShellCommandLineGetFlag(Package
, L
"-noconsolein");
742 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
= ShellCommandLineGetFlag(Package
, L
"-nointerrupt");
743 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoMap
= ShellCommandLineGetFlag(Package
, L
"-nomap");
744 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoVersion
= ShellCommandLineGetFlag(Package
, L
"-noversion");
745 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Delay
= ShellCommandLineGetFlag(Package
, L
"-delay");
747 ShellInfoObject
.ShellInitSettings
.Delay
= 5;
749 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
) {
750 ShellInfoObject
.ShellInitSettings
.Delay
= 0;
751 } else if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Delay
) {
752 TempConst
= ShellCommandLineGetValue(Package
, L
"-delay");
753 if (TempConst
!= NULL
&& *TempConst
== L
':') {
756 if (TempConst
!= NULL
&& !EFI_ERROR(ShellConvertStringToUint64(TempConst
, &Intermediate
, FALSE
, FALSE
))) {
757 ShellInfoObject
.ShellInitSettings
.Delay
= (UINTN
)Intermediate
;
760 ShellCommandLineFreeVarList(Package
);
766 Handles all interaction with the default startup script.
768 this will check that the correct command line parameters were passed, handle the delay, and then start running the script.
770 @param ImagePath the path to the image for shell. first place to look for the startup script
771 @param FilePath the path to the file for shell. second place to look for the startup script.
773 @retval EFI_SUCCESS the variable is initialized.
778 EFI_DEVICE_PATH_PROTOCOL
*ImagePath
,
779 EFI_DEVICE_PATH_PROTOCOL
*FilePath
785 SHELL_FILE_HANDLE FileHandle
;
786 EFI_DEVICE_PATH_PROTOCOL
*NewPath
;
787 EFI_DEVICE_PATH_PROTOCOL
*NamePath
;
788 CHAR16
*FileStringPath
;
791 CONST CHAR16
*MapName
;
793 Key
.UnicodeChar
= CHAR_NULL
;
797 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
&& ShellInfoObject
.ShellInitSettings
.FileName
!= NULL
) {
799 // launch something else instead
801 NewSize
= StrSize(ShellInfoObject
.ShellInitSettings
.FileName
);
802 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
803 NewSize
+= StrSize(ShellInfoObject
.ShellInitSettings
.FileOptions
) + sizeof(CHAR16
);
805 FileStringPath
= AllocateZeroPool(NewSize
);
806 if (FileStringPath
== NULL
) {
807 return (EFI_OUT_OF_RESOURCES
);
809 StrCpy(FileStringPath
, ShellInfoObject
.ShellInitSettings
.FileName
);
810 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
811 StrCat(FileStringPath
, L
" ");
812 StrCat(FileStringPath
, ShellInfoObject
.ShellInitSettings
.FileOptions
);
814 Status
= RunCommand(FileStringPath
);
815 FreePool(FileStringPath
);
821 // for shell level 0 we do no scripts
822 // Without the Startup bit overriding we allow for nostartup to prevent scripts
824 if ( (PcdGet8(PcdShellSupportLevel
) < 1)
825 || (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
&& !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
)
827 return (EFI_SUCCESS
);
831 // print out our warning and see if they press a key
833 for ( Status
= EFI_UNSUPPORTED
, Delay
= ShellInfoObject
.ShellInitSettings
.Delay
* 10
834 ; Delay
!= 0 && EFI_ERROR(Status
)
837 ShellPrintHiiEx(0, gST
->ConOut
->Mode
->CursorRow
, NULL
, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION
), ShellInfoObject
.HiiHandle
, Delay
/10);
839 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
840 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
843 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CRLF
), ShellInfoObject
.HiiHandle
);
848 if (Status
== EFI_SUCCESS
&& Key
.UnicodeChar
== 0 && Key
.ScanCode
== SCAN_ESC
) {
849 return (EFI_SUCCESS
);
853 // Try the first location (must be file system)
855 MapName
= ShellInfoObject
.NewEfiShellProtocol
->GetMapFromDevicePath(&ImagePath
);
856 if (MapName
!= NULL
) {
857 FileStringPath
= NULL
;
859 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, MapName
, 0);
860 if (FileStringPath
== NULL
) {
861 Status
= EFI_OUT_OF_RESOURCES
;
863 TempSpot
= StrStr(FileStringPath
, L
";");
864 if (TempSpot
!= NULL
) {
865 *TempSpot
= CHAR_NULL
;
867 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, ((FILEPATH_DEVICE_PATH
*)FilePath
)->PathName
, 0);
868 PathRemoveLastItem(FileStringPath
);
869 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, mStartupScript
, 0);
870 Status
= ShellInfoObject
.NewEfiShellProtocol
->OpenFileByName(FileStringPath
, &FileHandle
, EFI_FILE_MODE_READ
);
871 FreePool(FileStringPath
);
874 if (EFI_ERROR(Status
)) {
875 NamePath
= FileDevicePath (NULL
, mStartupScript
);
876 NewPath
= AppendDevicePathNode (ImagePath
, NamePath
);
882 Status
= InternalOpenFileDevicePath(NewPath
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
886 // If we got a file, run it
888 if (!EFI_ERROR(Status
) && FileHandle
!= NULL
) {
889 Status
= RunScriptFileHandle (FileHandle
, mStartupScript
);
890 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(FileHandle
);
892 FileStringPath
= ShellFindFilePath(mStartupScript
);
893 if (FileStringPath
== NULL
) {
895 // we return success since we dont need to have a startup script
897 Status
= EFI_SUCCESS
;
898 ASSERT(FileHandle
== NULL
);
900 Status
= RunScriptFile(FileStringPath
);
901 FreePool(FileStringPath
);
910 Function to perform the shell prompt looping. It will do a single prompt,
911 dispatch the result, and then return. It is expected that the caller will
912 call this function in a loop many times.
915 @retval RETURN_ABORTED
926 CONST CHAR16
*CurDir
;
933 // Get screen setting to decide size of the command line buffer
935 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &Column
, &Row
);
936 BufferSize
= Column
* Row
* sizeof (CHAR16
);
937 CmdLine
= AllocateZeroPool (BufferSize
);
938 if (CmdLine
== NULL
) {
939 return EFI_OUT_OF_RESOURCES
;
942 CurDir
= ShellInfoObject
.NewEfiShellProtocol
->GetEnv(L
"cwd");
947 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, gST
->ConOut
->Mode
->CursorRow
);
949 if (CurDir
!= NULL
&& StrLen(CurDir
) > 1) {
950 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CURDIR
), ShellInfoObject
.HiiHandle
, CurDir
);
952 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_SHELL
), ShellInfoObject
.HiiHandle
);
956 // Read a line from the console
958 Status
= ShellInfoObject
.NewEfiShellProtocol
->ReadFile(ShellInfoObject
.NewShellParametersProtocol
->StdIn
, &BufferSize
, CmdLine
);
961 // Null terminate the string and parse it
963 if (!EFI_ERROR (Status
)) {
964 CmdLine
[BufferSize
/ sizeof (CHAR16
)] = CHAR_NULL
;
965 Status
= RunCommand(CmdLine
);
969 // Done with this command
976 Add a buffer to the Buffer To Free List for safely returning buffers to other
977 places without risking letting them modify internal shell information.
979 @param Buffer Something to pass to FreePool when the shell is exiting.
987 BUFFER_LIST
*BufferListEntry
;
989 if (Buffer
== NULL
) {
993 BufferListEntry
= AllocateZeroPool(sizeof(BUFFER_LIST
));
994 ASSERT(BufferListEntry
!= NULL
);
995 BufferListEntry
->Buffer
= Buffer
;
996 InsertTailList(&ShellInfoObject
.BufferToFreeList
.Link
, &BufferListEntry
->Link
);
1001 Add a buffer to the Line History List
1003 @param Buffer The line buffer to add.
1007 AddLineToCommandHistory(
1008 IN CONST CHAR16
*Buffer
1013 Node
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1014 ASSERT(Node
!= NULL
);
1015 Node
->Buffer
= AllocateZeroPool(StrSize(Buffer
));
1016 ASSERT(Node
->Buffer
!= NULL
);
1017 StrCpy(Node
->Buffer
, Buffer
);
1019 InsertTailList(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
);
1023 Checks if a string is an alias for another command. If yes, then it replaces the alias name
1024 with the correct command name.
1026 @param[in, out] CommandString Upon entry the potential alias. Upon return the
1027 command name if it was an alias. If it was not
1028 an alias it will be unchanged. This function may
1029 change the buffer to fit the command name.
1031 @retval EFI_SUCCESS The name was changed.
1032 @retval EFI_SUCCESS The name was not an alias.
1033 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1038 IN OUT CHAR16
**CommandString
1041 CONST CHAR16
*NewString
;
1043 NewString
= ShellInfoObject
.NewEfiShellProtocol
->GetAlias(*CommandString
, NULL
);
1044 if (NewString
== NULL
) {
1045 return (EFI_SUCCESS
);
1047 FreePool(*CommandString
);
1048 *CommandString
= AllocateZeroPool(StrSize(NewString
));
1049 if (*CommandString
== NULL
) {
1050 return (EFI_OUT_OF_RESOURCES
);
1052 StrCpy(*CommandString
, NewString
);
1053 return (EFI_SUCCESS
);
1057 Function allocates a new command line and replaces all instances of environment
1058 variable names that are correctly preset to their values.
1060 If the return value is not NULL the memory must be caller freed.
1062 @param[in] OriginalCommandLine The original command line
1064 @retval NULL An error ocurred.
1065 @return The new command line with no environment variables present.
1069 ShellConvertVariables (
1070 IN CONST CHAR16
*OriginalCommandLine
1073 CONST CHAR16
*MasterEnvList
;
1075 CHAR16
*NewCommandLine1
;
1076 CHAR16
*NewCommandLine2
;
1080 SCRIPT_FILE
*CurrentScriptFile
;
1081 ALIAS_LIST
*AliasListNode
;
1083 ASSERT(OriginalCommandLine
!= NULL
);
1086 NewSize
= StrSize(OriginalCommandLine
);
1087 CurrentScriptFile
= ShellCommandGetCurrentScriptFile();
1090 ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ?
1093 // calculate the size required for the post-conversion string...
1095 if (CurrentScriptFile
!= NULL
) {
1096 for (AliasListNode
= (ALIAS_LIST
*)GetFirstNode(&CurrentScriptFile
->SubstList
)
1097 ; !IsNull(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1098 ; AliasListNode
= (ALIAS_LIST
*)GetNextNode(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1100 for (Temp
= StrStr(OriginalCommandLine
, AliasListNode
->Alias
)
1102 ; Temp
= StrStr(Temp
+1, AliasListNode
->Alias
)
1105 // we need a preceeding and if there is space no ^ preceeding (if no space ignore)
1107 if ((((Temp
-OriginalCommandLine
)>2) && *(Temp
-2) != L
'^') || ((Temp
-OriginalCommandLine
)<=2)) {
1108 NewSize
+= StrSize(AliasListNode
->CommandString
);
1114 for (MasterEnvList
= EfiShellGetEnv(NULL
)
1115 ; MasterEnvList
!= NULL
&& *MasterEnvList
!= CHAR_NULL
//&& *(MasterEnvList+1) != CHAR_NULL
1116 ; MasterEnvList
+= StrLen(MasterEnvList
) + 1
1118 if (StrSize(MasterEnvList
) > ItemSize
) {
1119 ItemSize
= StrSize(MasterEnvList
);
1121 for (Temp
= StrStr(OriginalCommandLine
, MasterEnvList
)
1123 ; Temp
= StrStr(Temp
+1, MasterEnvList
)
1126 // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)
1128 if (*(Temp
-1) == L
'%' && *(Temp
+StrLen(MasterEnvList
)) == L
'%' &&
1129 ((((Temp
-OriginalCommandLine
)>2) && *(Temp
-2) != L
'^') || ((Temp
-OriginalCommandLine
)<=2))) {
1130 NewSize
+=StrSize(EfiShellGetEnv(MasterEnvList
));
1136 // Quick out if none were found...
1138 if (NewSize
== StrSize(OriginalCommandLine
)) {
1139 ASSERT(Temp
== NULL
);
1140 Temp
= StrnCatGrow(&Temp
, NULL
, OriginalCommandLine
, 0);
1145 // now do the replacements...
1147 NewCommandLine1
= AllocateZeroPool(NewSize
);
1148 NewCommandLine2
= AllocateZeroPool(NewSize
);
1149 ItemTemp
= AllocateZeroPool(ItemSize
+(2*sizeof(CHAR16
)));
1150 if (NewCommandLine1
== NULL
|| NewCommandLine2
== NULL
|| ItemTemp
== NULL
) {
1151 SHELL_FREE_NON_NULL(NewCommandLine1
);
1152 SHELL_FREE_NON_NULL(NewCommandLine2
);
1153 SHELL_FREE_NON_NULL(ItemTemp
);
1156 StrCpy(NewCommandLine1
, OriginalCommandLine
);
1157 for (MasterEnvList
= EfiShellGetEnv(NULL
)
1158 ; MasterEnvList
!= NULL
&& *MasterEnvList
!= CHAR_NULL
//&& *(MasterEnvList+1) != CHAR_NULL
1159 ; MasterEnvList
+= StrLen(MasterEnvList
) + 1
1161 StrCpy(ItemTemp
, L
"%");
1162 StrCat(ItemTemp
, MasterEnvList
);
1163 StrCat(ItemTemp
, L
"%");
1164 ShellCopySearchAndReplace(NewCommandLine1
, NewCommandLine2
, NewSize
, ItemTemp
, EfiShellGetEnv(MasterEnvList
), TRUE
, FALSE
);
1165 StrCpy(NewCommandLine1
, NewCommandLine2
);
1167 if (CurrentScriptFile
!= NULL
) {
1168 for (AliasListNode
= (ALIAS_LIST
*)GetFirstNode(&CurrentScriptFile
->SubstList
)
1169 ; !IsNull(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1170 ; AliasListNode
= (ALIAS_LIST
*)GetNextNode(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1172 ShellCopySearchAndReplace(NewCommandLine1
, NewCommandLine2
, NewSize
, AliasListNode
->Alias
, AliasListNode
->CommandString
, TRUE
, FALSE
);
1173 StrCpy(NewCommandLine1
, NewCommandLine2
);
1177 FreePool(NewCommandLine2
);
1180 return (NewCommandLine1
);
1184 Internal function to run a command line with pipe usage.
1186 @param[in] CmdLine The pointer to the command line.
1187 @param[in] StdIn The pointer to the Standard input.
1188 @param[in] StdOut The pointer to the Standard output.
1190 @retval EFI_SUCCESS The split command is executed successfully.
1191 @retval other Some error occurs when executing the split command.
1196 IN CONST CHAR16
*CmdLine
,
1197 IN SHELL_FILE_HANDLE
*StdIn
,
1198 IN SHELL_FILE_HANDLE
*StdOut
1202 CHAR16
*NextCommandLine
;
1203 CHAR16
*OurCommandLine
;
1207 SHELL_FILE_HANDLE
*TempFileHandle
;
1210 ASSERT(StdOut
== NULL
);
1212 ASSERT(StrStr(CmdLine
, L
"|") != NULL
);
1214 Status
= EFI_SUCCESS
;
1215 NextCommandLine
= NULL
;
1216 OurCommandLine
= NULL
;
1220 NextCommandLine
= StrnCatGrow(&NextCommandLine
, &Size1
, StrStr(CmdLine
, L
"|")+1, 0);
1221 OurCommandLine
= StrnCatGrow(&OurCommandLine
, &Size2
, CmdLine
, StrStr(CmdLine
, L
"|") - CmdLine
);
1223 if (NextCommandLine
== NULL
|| OurCommandLine
== NULL
) {
1224 SHELL_FREE_NON_NULL(OurCommandLine
);
1225 SHELL_FREE_NON_NULL(NextCommandLine
);
1226 return (EFI_OUT_OF_RESOURCES
);
1228 if (NextCommandLine
[0] != CHAR_NULL
&&
1229 NextCommandLine
[0] == L
'a' &&
1230 NextCommandLine
[1] == L
' '
1232 CopyMem(NextCommandLine
, NextCommandLine
+1, StrSize(NextCommandLine
) - sizeof(NextCommandLine
[0]));
1240 // make a SPLIT_LIST item and add to list
1242 Split
= AllocateZeroPool(sizeof(SPLIT_LIST
));
1243 ASSERT(Split
!= NULL
);
1244 Split
->SplitStdIn
= StdIn
;
1245 Split
->SplitStdOut
= ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode
), NULL
);
1246 ASSERT(Split
->SplitStdOut
!= NULL
);
1247 InsertHeadList(&ShellInfoObject
.SplitList
.Link
, &Split
->Link
);
1249 ASSERT(StrStr(OurCommandLine
, L
"|") == NULL
);
1250 Status
= RunCommand(OurCommandLine
);
1253 // move the output from the first to the in to the second.
1255 TempFileHandle
= Split
->SplitStdOut
;
1256 if (Split
->SplitStdIn
== StdIn
) {
1257 Split
->SplitStdOut
= NULL
;
1259 Split
->SplitStdOut
= Split
->SplitStdIn
;
1261 Split
->SplitStdIn
= TempFileHandle
;
1262 ShellInfoObject
.NewEfiShellProtocol
->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdIn
), 0);
1264 if (!EFI_ERROR(Status
)) {
1265 Status
= RunCommand(NextCommandLine
);
1269 // remove the top level from the ScriptList
1271 ASSERT((SPLIT_LIST
*)GetFirstNode(&ShellInfoObject
.SplitList
.Link
) == Split
);
1272 RemoveEntryList(&Split
->Link
);
1275 // Note that the original StdIn is now the StdOut...
1277 if (Split
->SplitStdOut
!= NULL
&& Split
->SplitStdOut
!= StdIn
) {
1278 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdOut
));
1280 if (Split
->SplitStdIn
!= NULL
) {
1281 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdIn
));
1285 FreePool(NextCommandLine
);
1286 FreePool(OurCommandLine
);
1292 Function will process and run a command line.
1294 This will determine if the command line represents an internal shell
1295 command or dispatch an external application.
1297 @param[in] CmdLine The command line to parse.
1299 @retval EFI_SUCCESS The command was completed.
1300 @retval EFI_ABORTED The command's operation was aborted.
1305 IN CONST CHAR16
*CmdLine
1309 CHAR16
*CommandName
;
1310 SHELL_STATUS ShellStatus
;
1314 CHAR16 LeString
[11];
1315 CHAR16
*PostAliasCmdLine
;
1316 UINTN PostAliasSize
;
1317 CHAR16
*PostVariableCmdLine
;
1318 CHAR16
*CommandWithPath
;
1319 CONST EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1320 CONST CHAR16
*TempLocation
;
1321 CONST CHAR16
*TempLocation2
;
1322 SHELL_FILE_HANDLE OriginalStdIn
;
1323 SHELL_FILE_HANDLE OriginalStdOut
;
1324 SHELL_FILE_HANDLE OriginalStdErr
;
1325 SYSTEM_TABLE_INFO OriginalSystemTableInfo
;
1326 CHAR16
*TempLocation3
;
1329 CHAR16
*CleanOriginal
;
1332 ASSERT(CmdLine
!= NULL
);
1333 if (StrLen(CmdLine
) == 0) {
1334 return (EFI_SUCCESS
);
1338 PostVariableCmdLine
= NULL
;
1339 PostAliasCmdLine
= NULL
;
1340 CommandWithPath
= NULL
;
1342 Status
= EFI_SUCCESS
;
1343 CleanOriginal
= NULL
;
1346 CleanOriginal
= StrnCatGrow(&CleanOriginal
, NULL
, CmdLine
, 0);
1347 if (CleanOriginal
== NULL
) {
1348 return (EFI_OUT_OF_RESOURCES
);
1350 while (CleanOriginal
[StrLen(CleanOriginal
)-1] == L
' ') {
1351 CleanOriginal
[StrLen(CleanOriginal
)-1] = CHAR_NULL
;
1353 while (CleanOriginal
[0] == L
' ') {
1354 CopyMem(CleanOriginal
, CleanOriginal
+1, StrSize(CleanOriginal
) - sizeof(CleanOriginal
[0]));
1358 if (StrStr(CleanOriginal
, L
" ") == NULL
){
1359 StrnCatGrow(&CommandName
, NULL
, CleanOriginal
, 0);
1361 StrnCatGrow(&CommandName
, NULL
, CleanOriginal
, StrStr(CleanOriginal
, L
" ") - CleanOriginal
);
1364 ASSERT(PostAliasCmdLine
== NULL
);
1365 if (!ShellCommandIsCommandOnList(CommandName
)) {
1367 // Convert via alias
1369 Status
= ShellConvertAlias(&CommandName
);
1371 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, &PostAliasSize
, CommandName
, 0);
1372 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, &PostAliasSize
, StrStr(CleanOriginal
, L
" "), 0);
1373 ASSERT_EFI_ERROR(Status
);
1375 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, NULL
, CleanOriginal
, 0);
1378 if (CleanOriginal
!= NULL
) {
1379 FreePool(CleanOriginal
);
1380 CleanOriginal
= NULL
;
1383 if (CommandName
!= NULL
) {
1384 FreePool(CommandName
);
1388 PostVariableCmdLine
= ShellConvertVariables(PostAliasCmdLine
);
1391 // we can now free the modified by alias command line
1393 if (PostAliasCmdLine
!= NULL
) {
1394 FreePool(PostAliasCmdLine
);
1395 PostAliasCmdLine
= NULL
;
1398 if (PostVariableCmdLine
== NULL
) {
1399 return (EFI_OUT_OF_RESOURCES
);
1402 while (PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] == L
' ') {
1403 PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] = CHAR_NULL
;
1405 while (PostVariableCmdLine
[0] == L
' ') {
1406 CopyMem(PostVariableCmdLine
, PostVariableCmdLine
+1, StrSize(PostVariableCmdLine
) - sizeof(PostVariableCmdLine
[0]));
1410 // We dont do normal processing with a split command line (output from one command input to another)
1412 TempLocation3
= NULL
;
1413 if (StrStr(PostVariableCmdLine
, L
"|") != NULL
) {
1414 for (TempLocation3
= PostVariableCmdLine
; TempLocation3
!= NULL
&& *TempLocation3
!= CHAR_NULL
; TempLocation3
++) {
1415 if (*TempLocation3
== L
'^' && *(TempLocation3
+1) == L
'|') {
1417 } else if (*TempLocation3
== L
'|') {
1422 if (TempLocation3
!= NULL
&& *TempLocation3
!= CHAR_NULL
) {
1424 // are we in an existing split???
1426 if (!IsListEmpty(&ShellInfoObject
.SplitList
.Link
)) {
1427 Split
= (SPLIT_LIST
*)GetFirstNode(&ShellInfoObject
.SplitList
.Link
);
1430 if (Split
== NULL
) {
1431 Status
= RunSplitCommand(PostVariableCmdLine
, NULL
, NULL
);
1433 Status
= RunSplitCommand(PostVariableCmdLine
, Split
->SplitStdIn
, Split
->SplitStdOut
);
1438 // If this is a mapped drive change handle that...
1440 if (PostVariableCmdLine
[(StrLen(PostVariableCmdLine
)-1)] == L
':' && StrStr(PostVariableCmdLine
, L
" ") == NULL
) {
1441 Status
= ShellInfoObject
.NewEfiShellProtocol
->SetCurDir(NULL
, PostVariableCmdLine
);
1442 if (EFI_ERROR(Status
)) {
1443 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_INVALID_MAPPING
), ShellInfoObject
.HiiHandle
, PostVariableCmdLine
);
1445 FreePool(PostVariableCmdLine
);
1449 ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file...
1450 /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files...
1454 Status
= UpdateStdInStdOutStdErr(ShellInfoObject
.NewShellParametersProtocol
, PostVariableCmdLine
, &OriginalStdIn
, &OriginalStdOut
, &OriginalStdErr
, &OriginalSystemTableInfo
);
1455 if (EFI_ERROR(Status
)) {
1456 if (Status
== EFI_NOT_FOUND
) {
1457 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR
), ShellInfoObject
.HiiHandle
);
1459 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_INVALID_REDIR
), ShellInfoObject
.HiiHandle
);
1462 while (PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] == L
' ') {
1463 PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] = CHAR_NULL
;
1465 while (PostVariableCmdLine
[0] == L
' ') {
1466 CopyMem(PostVariableCmdLine
, PostVariableCmdLine
+1, StrSize(PostVariableCmdLine
) - sizeof(PostVariableCmdLine
[0]));
1470 // get the argc and argv updated for internal commands
1472 Status
= UpdateArgcArgv(ShellInfoObject
.NewShellParametersProtocol
, PostVariableCmdLine
, &Argv
, &Argc
);
1473 ASSERT_EFI_ERROR(Status
);
1475 for (Count
= 0 ; Count
< ShellInfoObject
.NewShellParametersProtocol
->Argc
; Count
++) {
1476 if (StrStr(ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
], L
"-?") == ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
]
1477 || (ShellInfoObject
.NewShellParametersProtocol
->Argv
[0][0] == L
'?' && ShellInfoObject
.NewShellParametersProtocol
->Argv
[0][1] == CHAR_NULL
)
1480 // We need to redo the arguments since a parameter was -?
1481 // move them all down 1 to the end, then up one then replace the first with help
1483 FreePool(ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
]);
1484 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
] = NULL
;
1485 for (Count2
= Count
; (Count2
+ 1) < ShellInfoObject
.NewShellParametersProtocol
->Argc
; Count2
++) {
1486 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
+1];
1488 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = NULL
;
1489 for (Count2
= ShellInfoObject
.NewShellParametersProtocol
->Argc
-1 ; Count2
> 0 ; Count2
--) {
1490 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
-1];
1492 ShellInfoObject
.NewShellParametersProtocol
->Argv
[0] = NULL
;
1493 ShellInfoObject
.NewShellParametersProtocol
->Argv
[0] = StrnCatGrow(&ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], NULL
, L
"help", 0);
1501 if (ShellCommandIsCommandOnList(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0])) {
1503 // Run the command (which was converted if it was an alias)
1505 if (!EFI_ERROR(Status
)) {
1506 Status
= ShellCommandRunCommandHandler(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], &ShellStatus
, &LastError
);
1507 ASSERT_EFI_ERROR(Status
);
1508 UnicodeSPrint(LeString
, sizeof(LeString
)*sizeof(LeString
[0]), L
"0x%08x", ShellStatus
);
1509 DEBUG_CODE(InternalEfiShellSetEnv(L
"DebugLasterror", LeString
, TRUE
););
1511 InternalEfiShellSetEnv(L
"Lasterror", LeString
, TRUE
);
1514 // Pass thru the exitcode from the app.
1516 if (ShellCommandGetExit()) {
1517 Status
= ShellStatus
;
1518 } else if (ShellStatus
!= 0 && IsScriptOnlyCommand(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0])) {
1519 Status
= EFI_ABORTED
;
1524 // run an external file (or script)
1526 if (StrStr(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], L
":") != NULL
) {
1527 ASSERT (CommandWithPath
== NULL
);
1528 if (ShellIsFile(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0]) == EFI_SUCCESS
) {
1529 CommandWithPath
= StrnCatGrow(&CommandWithPath
, NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], 0);
1532 if (CommandWithPath
== NULL
) {
1533 CommandWithPath
= ShellFindFilePathEx(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], mExecutableExtensions
);
1535 if (CommandWithPath
== NULL
|| ShellIsDirectory(CommandWithPath
) == EFI_SUCCESS
) {
1536 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_NOT_FOUND
), ShellInfoObject
.HiiHandle
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0]);
1539 // Check if it's a NSH (script) file.
1541 TempLocation
= CommandWithPath
+StrLen(CommandWithPath
)-4;
1542 TempLocation2
= mScriptExtension
;
1543 if ((StrLen(CommandWithPath
) > 4) && (StringNoCaseCompare((VOID
*)(&TempLocation
), (VOID
*)(&TempLocation2
)) == 0)) {
1544 Status
= RunScriptFile (CommandWithPath
);
1546 DevPath
= ShellInfoObject
.NewEfiShellProtocol
->GetDevicePathFromFilePath(CommandWithPath
);
1547 ASSERT(DevPath
!= NULL
);
1548 Status
= InternalShellExecuteDevicePath(
1551 PostVariableCmdLine
,
1558 CommandName
= StrnCatGrow(&CommandName
, NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], 0);
1560 RestoreArgcArgv(ShellInfoObject
.NewShellParametersProtocol
, &Argv
, &Argc
);
1562 RestoreStdInStdOutStdErr(ShellInfoObject
.NewShellParametersProtocol
, &OriginalStdIn
, &OriginalStdOut
, &OriginalStdErr
, &OriginalSystemTableInfo
);
1564 if (CommandName
!= NULL
) {
1565 if (ShellCommandGetCurrentScriptFile() != NULL
&& !IsScriptOnlyCommand(CommandName
)) {
1567 // if this is NOT a scipt only command return success so the script won't quit.
1568 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)
1570 Status
= EFI_SUCCESS
;
1575 SHELL_FREE_NON_NULL(CommandName
);
1576 SHELL_FREE_NON_NULL(CommandWithPath
);
1577 SHELL_FREE_NON_NULL(PostVariableCmdLine
);
1582 STATIC CONST UINT16 InvalidChars
[] = {L
'*', L
'?', L
'<', L
'>', L
'\\', L
'/', L
'\"', 0x0001, 0x0002};
1584 Function determins if the CommandName COULD be a valid command. It does not determine whether
1585 this is a valid command. It only checks for invalid characters.
1587 @param[in] CommandName The name to check
1589 @retval TRUE CommandName could be a command name
1590 @retval FALSE CommandName could not be a valid command name
1595 IN CONST CHAR16
*CommandName
1599 if (CommandName
== NULL
) {
1604 ; Count
< sizeof(InvalidChars
) / sizeof(InvalidChars
[0])
1607 if (ScanMem16(CommandName
, StrSize(CommandName
), InvalidChars
[Count
]) != NULL
) {
1615 Function to process a NSH script file via SHELL_FILE_HANDLE.
1617 @param[in] Handle The handle to the already opened file.
1618 @param[in] Name The name of the script file.
1620 @retval EFI_SUCCESS the script completed sucessfully
1624 RunScriptFileHandle (
1625 IN SHELL_FILE_HANDLE Handle
,
1626 IN CONST CHAR16
*Name
1630 SCRIPT_FILE
*NewScriptFile
;
1632 CHAR16
*CommandLine
;
1633 CHAR16
*CommandLine2
;
1634 CHAR16
*CommandLine3
;
1635 SCRIPT_COMMAND_LIST
*LastCommand
;
1637 BOOLEAN PreScriptEchoState
;
1638 BOOLEAN PreCommandEchoState
;
1639 CONST CHAR16
*CurDir
;
1641 CHAR16 LeString
[50];
1643 ASSERT(!ShellCommandGetScriptExit());
1645 PreScriptEchoState
= ShellCommandGetEchoState();
1647 NewScriptFile
= (SCRIPT_FILE
*)AllocateZeroPool(sizeof(SCRIPT_FILE
));
1648 if (NewScriptFile
== NULL
) {
1649 return (EFI_OUT_OF_RESOURCES
);
1655 ASSERT(NewScriptFile
->ScriptName
== NULL
);
1656 NewScriptFile
->ScriptName
= StrnCatGrow(&NewScriptFile
->ScriptName
, NULL
, Name
, 0);
1657 if (NewScriptFile
->ScriptName
== NULL
) {
1658 DeleteScriptFileStruct(NewScriptFile
);
1659 return (EFI_OUT_OF_RESOURCES
);
1663 // Save the parameters (used to replace %0 to %9 later on)
1665 NewScriptFile
->Argc
= ShellInfoObject
.NewShellParametersProtocol
->Argc
;
1666 if (NewScriptFile
->Argc
!= 0) {
1667 NewScriptFile
->Argv
= (CHAR16
**)AllocateZeroPool(NewScriptFile
->Argc
* sizeof(CHAR16
*));
1668 if (NewScriptFile
->Argv
== NULL
) {
1669 DeleteScriptFileStruct(NewScriptFile
);
1670 return (EFI_OUT_OF_RESOURCES
);
1672 for (LoopVar
= 0 ; LoopVar
< 10 && LoopVar
< NewScriptFile
->Argc
; LoopVar
++) {
1673 ASSERT(NewScriptFile
->Argv
[LoopVar
] == NULL
);
1674 NewScriptFile
->Argv
[LoopVar
] = StrnCatGrow(&NewScriptFile
->Argv
[LoopVar
], NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[LoopVar
], 0);
1675 if (NewScriptFile
->Argv
[LoopVar
] == NULL
) {
1676 DeleteScriptFileStruct(NewScriptFile
);
1677 return (EFI_OUT_OF_RESOURCES
);
1681 NewScriptFile
->Argv
= NULL
;
1684 InitializeListHead(&NewScriptFile
->CommandList
);
1685 InitializeListHead(&NewScriptFile
->SubstList
);
1688 // Now build the list of all script commands.
1691 while(!ShellFileHandleEof(Handle
)) {
1692 CommandLine
= ShellFileHandleReturnLine(Handle
, &Ascii
);
1694 if (CommandLine
== NULL
|| StrLen(CommandLine
) == 0) {
1697 NewScriptFile
->CurrentCommand
= AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST
));
1698 if (NewScriptFile
->CurrentCommand
== NULL
) {
1699 DeleteScriptFileStruct(NewScriptFile
);
1700 return (EFI_OUT_OF_RESOURCES
);
1703 NewScriptFile
->CurrentCommand
->Cl
= CommandLine
;
1704 NewScriptFile
->CurrentCommand
->Data
= NULL
;
1705 NewScriptFile
->CurrentCommand
->Line
= LineCount
;
1707 InsertTailList(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
1711 // Add this as the topmost script file
1713 ShellCommandSetNewScript (NewScriptFile
);
1716 // Now enumerate through the commands and run each one.
1718 CommandLine
= AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize
));
1719 if (CommandLine
== NULL
) {
1720 DeleteScriptFileStruct(NewScriptFile
);
1721 return (EFI_OUT_OF_RESOURCES
);
1723 CommandLine2
= AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize
));
1724 if (CommandLine2
== NULL
) {
1725 FreePool(CommandLine
);
1726 DeleteScriptFileStruct(NewScriptFile
);
1727 return (EFI_OUT_OF_RESOURCES
);
1730 for ( NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&NewScriptFile
->CommandList
)
1731 ; !IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)
1732 ; // conditional increment in the body of the loop
1734 ASSERT(CommandLine2
!= NULL
);
1735 StrCpy(CommandLine2
, NewScriptFile
->CurrentCommand
->Cl
);
1738 // NULL out comments
1740 for (CommandLine3
= CommandLine2
; CommandLine3
!= NULL
&& *CommandLine3
!= CHAR_NULL
; CommandLine3
++) {
1741 if (*CommandLine3
== L
'^') {
1742 if (*(CommandLine3
+1) == L
'#' || *(CommandLine3
+1) == L
':') {
1743 CopyMem(CommandLine3
, CommandLine3
+1, StrSize(CommandLine3
) - sizeof(CommandLine3
[0]));
1745 } else if (*CommandLine3
== L
'#') {
1746 *CommandLine3
= CHAR_NULL
;
1750 if (CommandLine2
!= NULL
&& StrLen(CommandLine2
) >= 1) {
1752 // Due to variability in starting the find and replace action we need to have both buffers the same.
1754 StrCpy(CommandLine
, CommandLine2
);
1757 // Remove the %0 to %9 from the command line (if we have some arguments)
1759 if (NewScriptFile
->Argv
!= NULL
) {
1760 switch (NewScriptFile
->Argc
) {
1762 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%9", NewScriptFile
->Argv
[9], FALSE
, TRUE
);
1763 ASSERT_EFI_ERROR(Status
);
1765 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%8", NewScriptFile
->Argv
[8], FALSE
, TRUE
);
1766 ASSERT_EFI_ERROR(Status
);
1768 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%7", NewScriptFile
->Argv
[7], FALSE
, TRUE
);
1769 ASSERT_EFI_ERROR(Status
);
1771 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%6", NewScriptFile
->Argv
[6], FALSE
, TRUE
);
1772 ASSERT_EFI_ERROR(Status
);
1774 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%5", NewScriptFile
->Argv
[5], FALSE
, TRUE
);
1775 ASSERT_EFI_ERROR(Status
);
1777 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%4", NewScriptFile
->Argv
[4], FALSE
, TRUE
);
1778 ASSERT_EFI_ERROR(Status
);
1780 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%3", NewScriptFile
->Argv
[3], FALSE
, TRUE
);
1781 ASSERT_EFI_ERROR(Status
);
1783 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%2", NewScriptFile
->Argv
[2], FALSE
, TRUE
);
1784 ASSERT_EFI_ERROR(Status
);
1786 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%1", NewScriptFile
->Argv
[1], FALSE
, TRUE
);
1787 ASSERT_EFI_ERROR(Status
);
1789 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%0", NewScriptFile
->Argv
[0], FALSE
, TRUE
);
1790 ASSERT_EFI_ERROR(Status
);
1796 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%1", L
"\"\"", FALSE
, FALSE
);
1797 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%2", L
"\"\"", FALSE
, FALSE
);
1798 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%3", L
"\"\"", FALSE
, FALSE
);
1799 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%4", L
"\"\"", FALSE
, FALSE
);
1800 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%5", L
"\"\"", FALSE
, FALSE
);
1801 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%6", L
"\"\"", FALSE
, FALSE
);
1802 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%7", L
"\"\"", FALSE
, FALSE
);
1803 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%8", L
"\"\"", FALSE
, FALSE
);
1804 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%9", L
"\"\"", FALSE
, FALSE
);
1806 StrCpy(CommandLine2
, CommandLine
);
1808 LastCommand
= NewScriptFile
->CurrentCommand
;
1810 for (CommandLine3
= CommandLine2
; CommandLine3
[0] == L
' ' ; CommandLine3
++);
1812 if (CommandLine3
!= NULL
&& CommandLine3
[0] == L
':' ) {
1814 // This line is a goto target / label
1817 if (CommandLine3
!= NULL
&& StrLen(CommandLine3
) > 0) {
1818 if (ShellCommandGetEchoState()) {
1819 CurDir
= ShellInfoObject
.NewEfiShellProtocol
->GetEnv(L
"cwd");
1820 if (CurDir
!= NULL
&& StrLen(CurDir
) > 1) {
1821 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CURDIR
), ShellInfoObject
.HiiHandle
, CurDir
);
1823 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_SHELL
), ShellInfoObject
.HiiHandle
);
1825 ShellPrintEx(-1, -1, L
"%s\r\n", CommandLine2
);
1827 if (CommandLine3
[0] == L
'@') {
1829 // We need to save the current echo state
1830 // and disable echo for just this command.
1832 PreCommandEchoState
= ShellCommandGetEchoState();
1833 ShellCommandSetEchoState(FALSE
);
1834 Status
= RunCommand(CommandLine3
+1);
1837 // Now restore the pre-'@' echo state.
1839 ShellCommandSetEchoState(PreCommandEchoState
);
1841 Status
= RunCommand(CommandLine3
);
1845 if (ShellCommandGetScriptExit()) {
1846 UnicodeSPrint(LeString
, sizeof(LeString
)*sizeof(LeString
[0]), L
"0x%Lx", ShellCommandGetExitCode());
1847 DEBUG_CODE(InternalEfiShellSetEnv(L
"DebugLasterror", LeString
, TRUE
););
1848 InternalEfiShellSetEnv(L
"Lasterror", LeString
, TRUE
);
1850 ShellCommandRegisterExit(FALSE
, 0);
1851 Status
= EFI_SUCCESS
;
1854 if (EFI_ERROR(Status
)) {
1857 if (ShellCommandGetExit()) {
1862 // If that commend did not update the CurrentCommand then we need to advance it...
1864 if (LastCommand
== NewScriptFile
->CurrentCommand
) {
1865 NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetNextNode(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
1866 if (!IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)) {
1867 NewScriptFile
->CurrentCommand
->Reset
= TRUE
;
1871 NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetNextNode(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
1872 if (!IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)) {
1873 NewScriptFile
->CurrentCommand
->Reset
= TRUE
;
1879 FreePool(CommandLine
);
1880 FreePool(CommandLine2
);
1881 ShellCommandSetNewScript (NULL
);
1884 // Only if this was the last script reset the state.
1886 if (ShellCommandGetCurrentScriptFile()==NULL
) {
1887 ShellCommandSetEchoState(PreScriptEchoState
);
1889 return (EFI_SUCCESS
);
1893 Function to process a NSH script file.
1895 @param[in] ScriptPath Pointer to the script file name (including file system path).
1897 @retval EFI_SUCCESS the script completed sucessfully
1902 IN CONST CHAR16
*ScriptPath
1906 SHELL_FILE_HANDLE FileHandle
;
1908 if (ShellIsFile(ScriptPath
) != EFI_SUCCESS
) {
1909 return (EFI_INVALID_PARAMETER
);
1912 Status
= ShellOpenFileByName(ScriptPath
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
1913 if (EFI_ERROR(Status
)) {
1917 Status
= RunScriptFileHandle(FileHandle
, ScriptPath
);
1919 ShellCloseFile(&FileHandle
);