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