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