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