]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/Shell.c
ShellPkg: Refactor Pipe handling
[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
19a44972
JC
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
733f138d 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
ed8b5297 162 &ShellInfoObject.CtrlSNotifyHandle3);\r
733f138d 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
ed8b5297 170 &ShellInfoObject.CtrlSNotifyHandle4);\r
733f138d 171 }\r
172 return (Status);\r
173}\r
174\r
175\r
176\r
a405b86d 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
a49f6a2f 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
a405b86d 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
3c865f20 208 if (EFI_ERROR(Status)) {\r
209 return (Status);\r
210 }\r
a405b86d 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
3c865f20 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
a405b86d 257\r
3c865f20 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
a405b86d 264\r
3c865f20 265 //\r
266 // install our (solitary) HII package\r
267 //\r
268 ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL);\r
a405b86d 269 if (ShellInfoObject.HiiHandle == NULL) {\r
3c865f20 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
a405b86d 276 }\r
a405b86d 277\r
3c865f20 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
a405b86d 284\r
3c865f20 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
a405b86d 291\r
3c865f20 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
a405b86d 297\r
3c865f20 298 Status = CommandInit();\r
299 ASSERT_EFI_ERROR(Status);\r
a405b86d 300\r
3c865f20 301 //\r
302 // Check the command line\r
303 //\r
304 Status = ProcessCommandLine();\r
a405b86d 305\r
3c865f20 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
a405b86d 312\r
3c865f20 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
a405b86d 318 ASSERT_EFI_ERROR(Status);\r
a405b86d 319\r
3c865f20 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
284e034f 328 STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL),\r
3c865f20 329 ShellInfoObject.HiiHandle,\r
330 SupportLevel[PcdGet8(PcdShellSupportLevel)],\r
331 gEfiShellProtocol->MajorVersion,\r
284e034f
CP
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
3c865f20 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
a405b86d 356\r
3c865f20 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
a405b86d 364\r
3c865f20 365 //\r
366 // init all the built in alias'\r
367 //\r
368 Status = SetBuiltInAlias();\r
369 ASSERT_EFI_ERROR(Status);\r
a405b86d 370\r
3c865f20 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
a405b86d 378\r
3c865f20 379 Size = 100;\r
380 TempString = AllocateZeroPool(Size);\r
a405b86d 381\r
3c865f20 382 UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel));\r
383 Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE);\r
384 ASSERT_EFI_ERROR(Status);\r
a405b86d 385\r
3c865f20 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
a405b86d 389\r
3c865f20 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
a405b86d 393\r
3c865f20 394 FreePool(TempString);\r
a405b86d 395\r
3c865f20 396 if (!EFI_ERROR(Status)) {\r
397 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {\r
a405b86d 398 //\r
3c865f20 399 // Set up the event for CTRL-C monitoring...\r
a405b86d 400 //\r
8be0ba36 401 Status = InernalEfiShellStartMonitor();\r
3c865f20 402 }\r
403\r
733f138d 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
a49f6a2f 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
3c865f20 423 if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) {\r
a405b86d 424 //\r
3c865f20 425 // process the startup script or launch the called app.\r
a405b86d 426 //\r
3c865f20 427 Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
428 }\r
a405b86d 429\r
ca79c798 430 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
a405b86d 431 //\r
3c865f20 432 // begin the UI waiting loop\r
a405b86d 433 //\r
3c865f20 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
8be0ba36 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
3c865f20 455 //\r
456 // Display Prompt\r
457 //\r
458 Status = DoShellPrompt();\r
459 } while (!ShellCommandGetExit());\r
460 }\r
a49f6a2f 461 if (OldConIn != NULL && ConInHandle != NULL) {\r
462 CloseSimpleTextInOnFile (gST->ConIn);\r
463 gST->ConIn = OldConIn;\r
464 gST->ConsoleInHandle = ConInHandle;\r
465 }\r
a405b86d 466 }\r
467 }\r
3c865f20 468\r
a405b86d 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
a405b86d 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
8be0ba36 489 if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){\r
92670471 490 InternalEfiShellSetEnv(L"cwd", NULL, TRUE);\r
8be0ba36 491 }\r
a405b86d 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
3c865f20 501 ASSERT(FALSE); ///@todo finish this de-allocation.\r
a405b86d 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
b6b22b13 530 if (ShellCommandGetExit()) {\r
531 return ((EFI_STATUS)ShellCommandGetExitCode());\r
532 }\r
a405b86d 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
a405b86d 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
4ff7e37b
ED
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
a405b86d 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
a49f6a2f 666 gBS->CloseProtocol(\r
667 LoadedImage->DeviceHandle,\r
668 &gEfiDevicePathProtocolGuid,\r
669 gImageHandle,\r
670 NULL);\r
a405b86d 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
ca79c798 691 {L"-_exit", TypeFlag},\r
a405b86d 692 {NULL, TypeMax}\r
693 };\r
a49f6a2f 694\r
a405b86d 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
733f138d 735 UINT64 Intermediate;\r
a405b86d 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
733f138d 746 ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(TempConst));\r
3c865f20 747 if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
748 return (EFI_OUT_OF_RESOURCES);\r
749 }\r
a405b86d 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
3c865f20 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
a405b86d 768 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
769 &Size,\r
770 gEfiShellParametersProtocol->Argv[LoopVar],\r
771 0);\r
3c865f20 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
a405b86d 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
ca79c798 799 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = ShellCommandLineGetFlag(Package, L"-_exit");\r
a405b86d 800\r
733f138d 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
a405b86d 806 TempConst = ShellCommandLineGetValue(Package, L"-delay");\r
33c031ee 807 if (TempConst != NULL && *TempConst == L':') {\r
733f138d 808 TempConst++;\r
809 }\r
810 if (TempConst != NULL && !EFI_ERROR(ShellConvertStringToUint64(TempConst, &Intermediate, FALSE, FALSE))) {\r
811 ShellInfoObject.ShellInitSettings.Delay = (UINTN)Intermediate;\r
a405b86d 812 }\r
a405b86d 813 }\r
a405b86d 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
733f138d 843 CHAR16 *TempSpot;\r
a405b86d 844 UINTN NewSize;\r
733f138d 845 CONST CHAR16 *MapName;\r
a405b86d 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
3c865f20 860 if (FileStringPath == NULL) {\r
861 return (EFI_OUT_OF_RESOURCES);\r
862 }\r
a405b86d 863 StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
864 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
3c865f20 865 StrCat(FileStringPath, L" ");\r
a405b86d 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
5559a41a 884 gST->ConOut->EnableCursor(gST->ConOut, FALSE);\r
a405b86d 885 //\r
886 // print out our warning and see if they press a key\r
887 //\r
284e034f 888 for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay\r
733f138d 889 ; Delay != 0 && EFI_ERROR(Status)\r
a405b86d 890 ; Delay--\r
891 ){\r
284e034f
CP
892 ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay);\r
893 gBS->Stall (1000000);\r
733f138d 894 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
895 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
896 }\r
a405b86d 897 }\r
898 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle);\r
5559a41a 899 gST->ConOut->EnableCursor(gST->ConOut, TRUE);\r
a405b86d 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
a405b86d 908 //\r
733f138d 909 // Try the first location (must be file system)\r
a405b86d 910 //\r
733f138d 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
532691c8 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
733f138d 928 }\r
733f138d 929 }\r
a405b86d 930 if (EFI_ERROR(Status)) {\r
733f138d 931 NamePath = FileDevicePath (NULL, mStartupScript);\r
932 NewPath = AppendDevicePathNode (ImagePath, NamePath);\r
933 FreePool(NamePath);\r
934\r
a405b86d 935 //\r
733f138d 936 // Try the location\r
a405b86d 937 //\r
a405b86d 938 Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
733f138d 939 FreePool(NewPath);\r
a405b86d 940 }\r
a405b86d 941 //\r
942 // If we got a file, run it\r
943 //\r
733f138d 944 if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
3c865f20 945 Status = RunScriptFileHandle (FileHandle, mStartupScript);\r
a405b86d 946 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
947 } else {\r
3c865f20 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
a405b86d 959 }\r
960\r
a405b86d 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
4ff7e37b
ED
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
a405b86d 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
733f138d 1104 *CommandString = AllocateZeroPool(StrSize(NewString));\r
a405b86d 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
df07baea 1134 CHAR16 *Temp2;\r
a405b86d 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
a405b86d 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
3c865f20 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
a405b86d 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
df07baea
JC
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
a405b86d 1260 }\r
1261\r
df07baea
JC
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
a405b86d 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
532691c8 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
19216573 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
a405b86d 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
a405b86d 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
64c7a749 1402 EFI_STATUS StatusCode;\r
a405b86d 1403 CHAR16 *CommandName;\r
1404 SHELL_STATUS ShellStatus;\r
1405 UINTN Argc;\r
1406 CHAR16 **Argv;\r
1407 BOOLEAN LastError;\r
ed34da40 1408 CHAR16 LeString[19];\r
a405b86d 1409 CHAR16 *PostAliasCmdLine;\r
1410 UINTN PostAliasSize;\r
1411 CHAR16 *PostVariableCmdLine;\r
1412 CHAR16 *CommandWithPath;\r
733f138d 1413 CONST EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
a405b86d 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
8be0ba36 1419 SYSTEM_TABLE_INFO OriginalSystemTableInfo;\r
a405b86d 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
532691c8 1440 if (CleanOriginal == NULL) {\r
1441 return (EFI_OUT_OF_RESOURCES);\r
1442 }\r
284e034f
CP
1443\r
1444 //\r
13acebbd 1445 // Remove any spaces and tabs at the beginning of the string.\r
284e034f 1446 //\r
13acebbd 1447 while ((CleanOriginal[0] == L' ') || (CleanOriginal[0] == L'\t')) {\r
a405b86d 1448 CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));\r
1449 }\r
1450\r
284e034f
CP
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
a405b86d 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
3c865f20 1510 if (PostVariableCmdLine == NULL) {\r
1511 return (EFI_OUT_OF_RESOURCES);\r
1512 }\r
1513\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 // We dont do normal processing with a split command line (output from one command input to another)\r
1523 //\r
19a44972 1524 if (ContainsSplit(PostVariableCmdLine)) {\r
a405b86d 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
19216573 1537 if (EFI_ERROR(Status)) {\r
1538 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, PostVariableCmdLine);\r
1539 }\r
a405b86d 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
8be0ba36 1559 Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);\r
a405b86d 1560 if (EFI_ERROR(Status)) {\r
733f138d 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
a405b86d 1566 } else {\r
a405b86d 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
5b5cd144
CP
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
a405b86d 1620 if (LastError) {\r
5b5cd144 1621 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
a405b86d 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
5b5cd144
CP
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
a405b86d 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
64c7a749 1671 &StatusCode\r
a405b86d 1672 );\r
64c7a749
ED
1673\r
1674 //\r
5b5cd144 1675 // Update last error status.\r
64c7a749 1676 //\r
5b5cd144
CP
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
a405b86d 1684 }\r
1685 }\r
1686 }\r
64c7a749
ED
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
a405b86d 1695 CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1696\r
1697 RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);\r
1698\r
8be0ba36 1699 RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);\r
a405b86d 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
a405b86d 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
848997b5 1775 BOOLEAN PreCommandEchoState;\r
a405b86d 1776 CONST CHAR16 *CurDir;\r
1777 UINTN LineCount;\r
b6b22b13 1778 CHAR16 LeString[50];\r
a405b86d 1779\r
1780 ASSERT(!ShellCommandGetScriptExit());\r
1781\r
1782 PreScriptEchoState = ShellCommandGetEchoState();\r
1783\r
1784 NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));\r
3c865f20 1785 if (NewScriptFile == NULL) {\r
1786 return (EFI_OUT_OF_RESOURCES);\r
1787 }\r
a405b86d 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
3c865f20 1794 if (NewScriptFile->ScriptName == NULL) {\r
1795 DeleteScriptFileStruct(NewScriptFile);\r
1796 return (EFI_OUT_OF_RESOURCES);\r
1797 }\r
a405b86d 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
3c865f20 1805 if (NewScriptFile->Argv == NULL) {\r
1806 DeleteScriptFileStruct(NewScriptFile);\r
1807 return (EFI_OUT_OF_RESOURCES);\r
1808 }\r
a405b86d 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
3c865f20 1812 if (NewScriptFile->Argv[LoopVar] == NULL) {\r
1813 DeleteScriptFileStruct(NewScriptFile);\r
1814 return (EFI_OUT_OF_RESOURCES);\r
1815 }\r
a405b86d 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
3c865f20 1835 if (NewScriptFile->CurrentCommand == NULL) {\r
1836 DeleteScriptFileStruct(NewScriptFile);\r
1837 return (EFI_OUT_OF_RESOURCES);\r
1838 }\r
a405b86d 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
733f138d 1855 CommandLine = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1856 if (CommandLine == NULL) {\r
1857 DeleteScriptFileStruct(NewScriptFile);\r
1858 return (EFI_OUT_OF_RESOURCES);\r
1859 }\r
733f138d 1860 CommandLine2 = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1861 if (CommandLine2 == NULL) {\r
1862 FreePool(CommandLine);\r
1863 DeleteScriptFileStruct(NewScriptFile);\r
1864 return (EFI_OUT_OF_RESOURCES);\r
1865 }\r
a405b86d 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
3c865f20 1871 ASSERT(CommandLine2 != NULL);\r
a405b86d 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
3c865f20 1949 if (CommandLine3 != NULL && CommandLine3[0] == L':' ) {\r
a405b86d 1950 //\r
1951 // This line is a goto target / label\r
1952 //\r
1953 } else {\r
1954 if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) {\r
848997b5 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
284e034f 1965 // If command was "@echo -off" or "@echo -on" then don't restore echo state\r
848997b5 1966 //\r
284e034f
CP
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
848997b5 1974 } else {\r
0d11446d 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
848997b5 1984 Status = RunCommand(CommandLine3);\r
1985 }\r
a405b86d 1986 }\r
1987\r
1988 if (ShellCommandGetScriptExit()) {\r
5b5cd144
CP
1989 //\r
1990 // ShellCommandGetExitCode() always returns a UINT64\r
1991 //\r
ed34da40 1992 UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode());\r
5b5cd144
CP
1993 DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
1994 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
b6b22b13 1995\r
1996 ShellCommandRegisterExit(FALSE, 0);\r
a405b86d 1997 Status = EFI_SUCCESS;\r
1998 break;\r
1999 }\r
c6a7fef8
ED
2000 if (ShellGetExecutionBreakFlag()) {\r
2001 break;\r
2002 }\r
a405b86d 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
a405b86d 2027\r
2028 FreePool(CommandLine);\r
2029 FreePool(CommandLine2);\r
2030 ShellCommandSetNewScript (NULL);\r
733f138d 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
a405b86d 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