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