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