]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/Shell.c
Update the comments for SizeofPartitionEntry field to follow the UEFI Spec.
[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
33c031ee 734 if (TempConst != NULL && *TempConst == L':') {\r
733f138d 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
a405b86d 1430 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {\r
1431 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;\r
1432 }\r
1433 while (PostVariableCmdLine[0] == L' ') {\r
1434 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));\r
1435 }\r
1436\r
1437 //\r
1438 // get the argc and argv updated for internal commands\r
1439 //\r
1440 Status = UpdateArgcArgv(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &Argv, &Argc);\r
1441 ASSERT_EFI_ERROR(Status);\r
1442\r
1443 for (Count = 0 ; Count < ShellInfoObject.NewShellParametersProtocol->Argc ; Count++) {\r
1444 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[Count], L"-?") == ShellInfoObject.NewShellParametersProtocol->Argv[Count]\r
1445 || (ShellInfoObject.NewShellParametersProtocol->Argv[0][0] == L'?' && ShellInfoObject.NewShellParametersProtocol->Argv[0][1] == CHAR_NULL)\r
1446 ) {\r
1447 //\r
1448 // We need to redo the arguments since a parameter was -?\r
1449 // move them all down 1 to the end, then up one then replace the first with help\r
1450 //\r
1451 FreePool(ShellInfoObject.NewShellParametersProtocol->Argv[Count]);\r
1452 ShellInfoObject.NewShellParametersProtocol->Argv[Count] = NULL;\r
1453 for (Count2 = Count ; (Count2 + 1) < ShellInfoObject.NewShellParametersProtocol->Argc ; Count2++) {\r
1454 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2+1];\r
1455 }\r
1456 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = NULL;\r
1457 for (Count2 = ShellInfoObject.NewShellParametersProtocol->Argc -1 ; Count2 > 0 ; Count2--) {\r
1458 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2-1];\r
1459 }\r
1460 ShellInfoObject.NewShellParametersProtocol->Argv[0] = NULL;\r
1461 ShellInfoObject.NewShellParametersProtocol->Argv[0] = StrnCatGrow(&ShellInfoObject.NewShellParametersProtocol->Argv[0], NULL, L"help", 0);\r
1462 break;\r
1463 }\r
1464 }\r
1465\r
1466 //\r
1467 // command or file?\r
1468 //\r
1469 if (ShellCommandIsCommandOnList(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1470 //\r
1471 // Run the command (which was converted if it was an alias)\r
1472 //\r
1473 if (!EFI_ERROR(Status)) {\r
1474 Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError);\r
1475 ASSERT_EFI_ERROR(Status);\r
1476 UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%08x", ShellStatus);\r
1477 DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE););\r
1478 if (LastError) {\r
1479 InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE);\r
1480 }\r
1481 //\r
1482 // Pass thru the exitcode from the app.\r
1483 //\r
1484 if (ShellCommandGetExit()) {\r
1485 Status = ShellStatus;\r
1486 } else if (ShellStatus != 0 && IsScriptOnlyCommand(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1487 Status = EFI_ABORTED;\r
1488 }\r
1489 }\r
1490 } else {\r
1491 //\r
1492 // run an external file (or script)\r
1493 //\r
1494 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[0], L":") != NULL) {\r
1495 ASSERT (CommandWithPath == NULL);\r
1496 if (ShellIsFile(ShellInfoObject.NewShellParametersProtocol->Argv[0]) == EFI_SUCCESS) {\r
1497 CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1498 }\r
1499 }\r
1500 if (CommandWithPath == NULL) {\r
1501 CommandWithPath = ShellFindFilePathEx(ShellInfoObject.NewShellParametersProtocol->Argv[0], mExecutableExtensions);\r
1502 }\r
1503 if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) {\r
1504 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]);\r
1505 } else {\r
1506 //\r
1507 // Check if it's a NSH (script) file.\r
1508 //\r
1509 TempLocation = CommandWithPath+StrLen(CommandWithPath)-4;\r
1510 TempLocation2 = mScriptExtension;\r
1511 if ((StrLen(CommandWithPath) > 4) && (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0)) {\r
1512 Status = RunScriptFile (CommandWithPath);\r
1513 } else {\r
1514 DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath);\r
1515 ASSERT(DevPath != NULL);\r
1516 Status = InternalShellExecuteDevicePath(\r
1517 &gImageHandle,\r
1518 DevPath,\r
1519 PostVariableCmdLine,\r
1520 NULL,\r
1521 NULL\r
1522 );\r
1523 }\r
1524 }\r
1525 }\r
1526 CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1527\r
1528 RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);\r
1529\r
8be0ba36 1530 RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);\r
a405b86d 1531 }\r
1532 if (CommandName != NULL) {\r
1533 if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) {\r
1534 //\r
1535 // if this is NOT a scipt only command return success so the script won't quit.\r
1536 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)\r
1537 //\r
1538 Status = EFI_SUCCESS;\r
1539 }\r
1540 }\r
1541 }\r
1542\r
1543 SHELL_FREE_NON_NULL(CommandName);\r
1544 SHELL_FREE_NON_NULL(CommandWithPath);\r
1545 SHELL_FREE_NON_NULL(PostVariableCmdLine);\r
a405b86d 1546\r
1547 return (Status);\r
1548}\r
1549\r
1550STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
1551/**\r
1552 Function determins if the CommandName COULD be a valid command. It does not determine whether\r
1553 this is a valid command. It only checks for invalid characters.\r
1554\r
1555 @param[in] CommandName The name to check\r
1556\r
1557 @retval TRUE CommandName could be a command name\r
1558 @retval FALSE CommandName could not be a valid command name\r
1559**/\r
1560BOOLEAN\r
1561EFIAPI\r
1562IsValidCommandName(\r
1563 IN CONST CHAR16 *CommandName\r
1564 )\r
1565{\r
1566 UINTN Count;\r
1567 if (CommandName == NULL) {\r
1568 ASSERT(FALSE);\r
1569 return (FALSE);\r
1570 }\r
1571 for ( Count = 0\r
1572 ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
1573 ; Count++\r
1574 ){\r
1575 if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
1576 return (FALSE);\r
1577 }\r
1578 }\r
1579 return (TRUE);\r
1580}\r
1581\r
1582/**\r
1583 Function to process a NSH script file via SHELL_FILE_HANDLE.\r
1584\r
1585 @param[in] Handle The handle to the already opened file.\r
1586 @param[in] Name The name of the script file.\r
1587\r
1588 @retval EFI_SUCCESS the script completed sucessfully\r
1589**/\r
1590EFI_STATUS\r
1591EFIAPI\r
1592RunScriptFileHandle (\r
1593 IN SHELL_FILE_HANDLE Handle,\r
1594 IN CONST CHAR16 *Name\r
1595 )\r
1596{\r
1597 EFI_STATUS Status;\r
1598 SCRIPT_FILE *NewScriptFile;\r
1599 UINTN LoopVar;\r
1600 CHAR16 *CommandLine;\r
1601 CHAR16 *CommandLine2;\r
1602 CHAR16 *CommandLine3;\r
1603 SCRIPT_COMMAND_LIST *LastCommand;\r
1604 BOOLEAN Ascii;\r
1605 BOOLEAN PreScriptEchoState;\r
1606 CONST CHAR16 *CurDir;\r
1607 UINTN LineCount;\r
1608\r
1609 ASSERT(!ShellCommandGetScriptExit());\r
1610\r
1611 PreScriptEchoState = ShellCommandGetEchoState();\r
1612\r
1613 NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));\r
3c865f20 1614 if (NewScriptFile == NULL) {\r
1615 return (EFI_OUT_OF_RESOURCES);\r
1616 }\r
a405b86d 1617\r
1618 //\r
1619 // Set up the name\r
1620 //\r
1621 ASSERT(NewScriptFile->ScriptName == NULL);\r
1622 NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0);\r
3c865f20 1623 if (NewScriptFile->ScriptName == NULL) {\r
1624 DeleteScriptFileStruct(NewScriptFile);\r
1625 return (EFI_OUT_OF_RESOURCES);\r
1626 }\r
a405b86d 1627\r
1628 //\r
1629 // Save the parameters (used to replace %0 to %9 later on)\r
1630 //\r
1631 NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc;\r
1632 if (NewScriptFile->Argc != 0) {\r
1633 NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*));\r
3c865f20 1634 if (NewScriptFile->Argv == NULL) {\r
1635 DeleteScriptFileStruct(NewScriptFile);\r
1636 return (EFI_OUT_OF_RESOURCES);\r
1637 }\r
a405b86d 1638 for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
1639 ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
1640 NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
3c865f20 1641 if (NewScriptFile->Argv[LoopVar] == NULL) {\r
1642 DeleteScriptFileStruct(NewScriptFile);\r
1643 return (EFI_OUT_OF_RESOURCES);\r
1644 }\r
a405b86d 1645 }\r
1646 } else {\r
1647 NewScriptFile->Argv = NULL;\r
1648 }\r
1649\r
1650 InitializeListHead(&NewScriptFile->CommandList);\r
1651 InitializeListHead(&NewScriptFile->SubstList);\r
1652\r
1653 //\r
1654 // Now build the list of all script commands.\r
1655 //\r
1656 LineCount = 0;\r
1657 while(!ShellFileHandleEof(Handle)) {\r
1658 CommandLine = ShellFileHandleReturnLine(Handle, &Ascii);\r
1659 LineCount++;\r
1660 if (CommandLine == NULL || StrLen(CommandLine) == 0) {\r
1661 continue;\r
1662 }\r
1663 NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST));\r
3c865f20 1664 if (NewScriptFile->CurrentCommand == NULL) {\r
1665 DeleteScriptFileStruct(NewScriptFile);\r
1666 return (EFI_OUT_OF_RESOURCES);\r
1667 }\r
a405b86d 1668\r
1669 NewScriptFile->CurrentCommand->Cl = CommandLine;\r
1670 NewScriptFile->CurrentCommand->Data = NULL;\r
1671 NewScriptFile->CurrentCommand->Line = LineCount;\r
1672\r
1673 InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1674 }\r
1675\r
1676 //\r
1677 // Add this as the topmost script file\r
1678 //\r
1679 ShellCommandSetNewScript (NewScriptFile);\r
1680\r
1681 //\r
1682 // Now enumerate through the commands and run each one.\r
1683 //\r
733f138d 1684 CommandLine = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1685 if (CommandLine == NULL) {\r
1686 DeleteScriptFileStruct(NewScriptFile);\r
1687 return (EFI_OUT_OF_RESOURCES);\r
1688 }\r
733f138d 1689 CommandLine2 = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1690 if (CommandLine2 == NULL) {\r
1691 FreePool(CommandLine);\r
1692 DeleteScriptFileStruct(NewScriptFile);\r
1693 return (EFI_OUT_OF_RESOURCES);\r
1694 }\r
a405b86d 1695\r
1696 for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList)\r
1697 ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)\r
1698 ; // conditional increment in the body of the loop\r
1699 ){\r
3c865f20 1700 ASSERT(CommandLine2 != NULL);\r
a405b86d 1701 StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
1702\r
1703 //\r
1704 // NULL out comments\r
1705 //\r
1706 for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
1707 if (*CommandLine3 == L'^') {\r
1708 if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
1709 CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
1710 }\r
1711 } else if (*CommandLine3 == L'#') {\r
1712 *CommandLine3 = CHAR_NULL;\r
1713 }\r
1714 }\r
1715\r
1716 if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) {\r
1717 //\r
1718 // Due to variability in starting the find and replace action we need to have both buffers the same.\r
1719 //\r
1720 StrCpy(CommandLine, CommandLine2);\r
1721\r
1722 //\r
1723 // Remove the %0 to %9 from the command line (if we have some arguments)\r
1724 //\r
1725 if (NewScriptFile->Argv != NULL) {\r
1726 switch (NewScriptFile->Argc) {\r
1727 default:\r
1728 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);\r
1729 ASSERT_EFI_ERROR(Status);\r
1730 case 9:\r
1731 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);\r
1732 ASSERT_EFI_ERROR(Status);\r
1733 case 8:\r
1734 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);\r
1735 ASSERT_EFI_ERROR(Status);\r
1736 case 7:\r
1737 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);\r
1738 ASSERT_EFI_ERROR(Status);\r
1739 case 6:\r
1740 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);\r
1741 ASSERT_EFI_ERROR(Status);\r
1742 case 5:\r
1743 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);\r
1744 ASSERT_EFI_ERROR(Status);\r
1745 case 4:\r
1746 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);\r
1747 ASSERT_EFI_ERROR(Status);\r
1748 case 3:\r
1749 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);\r
1750 ASSERT_EFI_ERROR(Status);\r
1751 case 2:\r
1752 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);\r
1753 ASSERT_EFI_ERROR(Status);\r
1754 case 1:\r
1755 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);\r
1756 ASSERT_EFI_ERROR(Status);\r
1757 break;\r
1758 case 0:\r
1759 break;\r
1760 }\r
1761 }\r
1762 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE);\r
1763 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE);\r
1764 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE);\r
1765 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE);\r
1766 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE);\r
1767 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE);\r
1768 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE);\r
1769 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
1770 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
1771\r
1772 StrCpy(CommandLine2, CommandLine);\r
1773\r
1774 LastCommand = NewScriptFile->CurrentCommand;\r
1775\r
1776 for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++);\r
1777\r
3c865f20 1778 if (CommandLine3 != NULL && CommandLine3[0] == L':' ) {\r
a405b86d 1779 //\r
1780 // This line is a goto target / label\r
1781 //\r
1782 } else {\r
1783 if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) {\r
1784 if (ShellCommandGetEchoState()) {\r
1785 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
1786 if (CurDir != NULL && StrLen(CurDir) > 1) {\r
1787 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);\r
1788 } else {\r
1789 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);\r
1790 }\r
1791 ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);\r
1792 }\r
1793 Status = RunCommand(CommandLine3);\r
1794 }\r
1795\r
1796 if (ShellCommandGetScriptExit()) {\r
1797 ShellCommandRegisterExit(FALSE);\r
1798 Status = EFI_SUCCESS;\r
1799 break;\r
1800 }\r
1801 if (EFI_ERROR(Status)) {\r
1802 break;\r
1803 }\r
1804 if (ShellCommandGetExit()) {\r
1805 break;\r
1806 }\r
1807 }\r
1808 //\r
1809 // If that commend did not update the CurrentCommand then we need to advance it...\r
1810 //\r
1811 if (LastCommand == NewScriptFile->CurrentCommand) {\r
1812 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1813 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
1814 NewScriptFile->CurrentCommand->Reset = TRUE;\r
1815 }\r
1816 }\r
1817 } else {\r
1818 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1819 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
1820 NewScriptFile->CurrentCommand->Reset = TRUE;\r
1821 }\r
1822 }\r
1823 }\r
1824\r
a405b86d 1825\r
1826 FreePool(CommandLine);\r
1827 FreePool(CommandLine2);\r
1828 ShellCommandSetNewScript (NULL);\r
733f138d 1829\r
1830 //\r
1831 // Only if this was the last script reset the state.\r
1832 //\r
1833 if (ShellCommandGetCurrentScriptFile()==NULL) {\r
1834 ShellCommandSetEchoState(PreScriptEchoState);\r
1835 }\r
a405b86d 1836 return (EFI_SUCCESS);\r
1837}\r
1838\r
1839/**\r
1840 Function to process a NSH script file.\r
1841\r
1842 @param[in] ScriptPath Pointer to the script file name (including file system path).\r
1843\r
1844 @retval EFI_SUCCESS the script completed sucessfully\r
1845**/\r
1846EFI_STATUS\r
1847EFIAPI\r
1848RunScriptFile (\r
1849 IN CONST CHAR16 *ScriptPath\r
1850 )\r
1851{\r
1852 EFI_STATUS Status;\r
1853 SHELL_FILE_HANDLE FileHandle;\r
1854\r
1855 if (ShellIsFile(ScriptPath) != EFI_SUCCESS) {\r
1856 return (EFI_INVALID_PARAMETER);\r
1857 }\r
1858\r
1859 Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
1860 if (EFI_ERROR(Status)) {\r
1861 return (Status);\r
1862 }\r
1863\r
1864 Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
1865\r
1866 ShellCloseFile(&FileHandle);\r
1867\r
1868 return (Status);\r
1869}\r