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