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