]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ShellParametersProtocol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellParametersProtocol.c
1 /** @file
2 Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation,
3 manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL.
4
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 Copyright (C) 2014, Red Hat, Inc.
7 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
8 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include "Shell.h"
14
15 BOOLEAN AsciiRedirection = FALSE;
16
17 /**
18 Return the next parameter's end from a command line string.
19
20 @param[in] String the string to parse
21 **/
22 CONST CHAR16 *
23 FindEndOfParameter (
24 IN CONST CHAR16 *String
25 )
26 {
27 CONST CHAR16 *First;
28 CONST CHAR16 *CloseQuote;
29
30 First = FindFirstCharacter (String, L" \"", L'^');
31
32 //
33 // nothing, all one parameter remaining
34 //
35 if (*First == CHAR_NULL) {
36 return (First);
37 }
38
39 //
40 // If space before a quote (or neither found, i.e. both CHAR_NULL),
41 // then that's the end.
42 //
43 if (*First == L' ') {
44 return (First);
45 }
46
47 CloseQuote = FindFirstCharacter (First+1, L"\"", L'^');
48
49 //
50 // We did not find a terminator...
51 //
52 if (*CloseQuote == CHAR_NULL) {
53 return (NULL);
54 }
55
56 return (FindEndOfParameter (CloseQuote+1));
57 }
58
59 /**
60 Return the next parameter from a command line string.
61
62 This function moves the next parameter from Walker into TempParameter and moves
63 Walker up past that parameter for recursive calling. When the final parameter
64 is moved *Walker will be set to NULL;
65
66 Temp Parameter must be large enough to hold the parameter before calling this
67 function.
68
69 This will also remove all remaining ^ characters after processing.
70
71 @param[in, out] Walker pointer to string of command line. Adjusted to
72 remaining command line on return
73 @param[in, out] TempParameter pointer to string of command line item extracted.
74 @param[in] Length buffer size of TempParameter.
75 @param[in] StripQuotation if TRUE then strip the quotation marks surrounding
76 the parameters.
77
78 @return EFI_INVALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string.
79 @return EFI_NOT_FOUND A closing " could not be found on the specified string
80 **/
81 EFI_STATUS
82 GetNextParameter (
83 IN OUT CHAR16 **Walker,
84 IN OUT CHAR16 **TempParameter,
85 IN CONST UINTN Length,
86 IN BOOLEAN StripQuotation
87 )
88 {
89 CONST CHAR16 *NextDelim;
90
91 if ( (Walker == NULL)
92 || (*Walker == NULL)
93 || (TempParameter == NULL)
94 || (*TempParameter == NULL)
95 )
96 {
97 return (EFI_INVALID_PARAMETER);
98 }
99
100 //
101 // make sure we dont have any leading spaces
102 //
103 while ((*Walker)[0] == L' ') {
104 (*Walker)++;
105 }
106
107 //
108 // make sure we still have some params now...
109 //
110 if (StrLen (*Walker) == 0) {
111 DEBUG_CODE_BEGIN ();
112 *Walker = NULL;
113 DEBUG_CODE_END ();
114 return (EFI_INVALID_PARAMETER);
115 }
116
117 NextDelim = FindEndOfParameter (*Walker);
118
119 if (NextDelim == NULL) {
120 DEBUG_CODE_BEGIN ();
121 *Walker = NULL;
122 DEBUG_CODE_END ();
123 return (EFI_NOT_FOUND);
124 }
125
126 StrnCpyS (*TempParameter, Length / sizeof (CHAR16), (*Walker), NextDelim - *Walker);
127
128 //
129 // Add a CHAR_NULL if we didn't get one via the copy
130 //
131 if (*NextDelim != CHAR_NULL) {
132 (*TempParameter)[NextDelim - *Walker] = CHAR_NULL;
133 }
134
135 //
136 // Update Walker for the next iteration through the function
137 //
138 *Walker = (CHAR16 *)NextDelim;
139
140 //
141 // Remove any non-escaped quotes in the string
142 // Remove any remaining escape characters in the string
143 //
144 for (NextDelim = FindFirstCharacter (*TempParameter, L"\"^", CHAR_NULL)
145 ; *NextDelim != CHAR_NULL
146 ; NextDelim = FindFirstCharacter (NextDelim, L"\"^", CHAR_NULL)
147 )
148 {
149 if (*NextDelim == L'^') {
150 //
151 // eliminate the escape ^
152 //
153 CopyMem ((CHAR16 *)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
154 NextDelim++;
155 } else if (*NextDelim == L'\"') {
156 //
157 // eliminate the unescaped quote
158 //
159 if (StripQuotation) {
160 CopyMem ((CHAR16 *)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
161 } else {
162 NextDelim++;
163 }
164 }
165 }
166
167 return EFI_SUCCESS;
168 }
169
170 /**
171 Function to populate Argc and Argv.
172
173 This function parses the CommandLine and divides it into standard C style Argc/Argv
174 parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space
175 delimited and quote surrounded parameter definition.
176
177 All special character processing (alias, environment variable, redirection,
178 etc... must be complete before calling this API.
179
180 @param[in] CommandLine String of command line to parse
181 @param[in] StripQuotation if TRUE then strip the quotation marks surrounding
182 the parameters.
183 @param[in, out] Argv pointer to array of strings; one for each parameter
184 @param[in, out] Argc pointer to number of strings in Argv array
185
186 @return EFI_SUCCESS the operation was successful
187 @return EFI_INVALID_PARAMETER some parameters are invalid
188 @return EFI_OUT_OF_RESOURCES a memory allocation failed.
189 **/
190 EFI_STATUS
191 ParseCommandLineToArgs (
192 IN CONST CHAR16 *CommandLine,
193 IN BOOLEAN StripQuotation,
194 IN OUT CHAR16 ***Argv,
195 IN OUT UINTN *Argc
196 )
197 {
198 UINTN Count;
199 CHAR16 *TempParameter;
200 CHAR16 *Walker;
201 CHAR16 *NewParam;
202 CHAR16 *NewCommandLine;
203 UINTN Size;
204 EFI_STATUS Status;
205
206 ASSERT (Argc != NULL);
207 ASSERT (Argv != NULL);
208
209 if ((CommandLine == NULL) || (StrLen (CommandLine) == 0)) {
210 (*Argc) = 0;
211 (*Argv) = NULL;
212 return (EFI_SUCCESS);
213 }
214
215 NewCommandLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);
216 if (NewCommandLine == NULL) {
217 return (EFI_OUT_OF_RESOURCES);
218 }
219
220 TrimSpaces (&NewCommandLine);
221 Size = StrSize (NewCommandLine);
222 TempParameter = AllocateZeroPool (Size);
223 if (TempParameter == NULL) {
224 SHELL_FREE_NON_NULL (NewCommandLine);
225 return (EFI_OUT_OF_RESOURCES);
226 }
227
228 for ( Count = 0,
229 Walker = (CHAR16 *)NewCommandLine
230 ; Walker != NULL && *Walker != CHAR_NULL
231 ; Count++
232 )
233 {
234 if (EFI_ERROR (GetNextParameter (&Walker, &TempParameter, Size, TRUE))) {
235 break;
236 }
237 }
238
239 //
240 // lets allocate the pointer array
241 //
242 (*Argv) = AllocateZeroPool ((Count)*sizeof (CHAR16 *));
243 if (*Argv == NULL) {
244 Status = EFI_OUT_OF_RESOURCES;
245 goto Done;
246 }
247
248 *Argc = 0;
249 Walker = (CHAR16 *)NewCommandLine;
250 while (Walker != NULL && *Walker != CHAR_NULL) {
251 SetMem16 (TempParameter, Size, CHAR_NULL);
252 if (EFI_ERROR (GetNextParameter (&Walker, &TempParameter, Size, StripQuotation))) {
253 Status = EFI_INVALID_PARAMETER;
254 goto Done;
255 }
256
257 NewParam = AllocateCopyPool (StrSize (TempParameter), TempParameter);
258 if (NewParam == NULL) {
259 Status = EFI_OUT_OF_RESOURCES;
260 goto Done;
261 }
262
263 ((CHAR16 **)(*Argv))[(*Argc)] = NewParam;
264 (*Argc)++;
265 }
266
267 ASSERT (Count >= (*Argc));
268 Status = EFI_SUCCESS;
269
270 Done:
271 SHELL_FREE_NON_NULL (TempParameter);
272 SHELL_FREE_NON_NULL (NewCommandLine);
273 return (Status);
274 }
275
276 /**
277 creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then
278 installs it on our handle and if there is an existing version of the protocol
279 that one is cached for removal later.
280
281 @param[in, out] NewShellParameters on a successful return, a pointer to pointer
282 to the newly installed interface.
283 @param[in, out] RootShellInstance on a successful return, pointer to boolean.
284 TRUE if this is the root shell instance.
285
286 @retval EFI_SUCCESS the operation completed successfully.
287 @return other the operation failed.
288 @sa ReinstallProtocolInterface
289 @sa InstallProtocolInterface
290 @sa ParseCommandLineToArgs
291 **/
292 EFI_STATUS
293 CreatePopulateInstallShellParametersProtocol (
294 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters,
295 IN OUT BOOLEAN *RootShellInstance
296 )
297 {
298 EFI_STATUS Status;
299 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
300 CHAR16 *FullCommandLine;
301 UINTN Size;
302
303 Size = 0;
304 FullCommandLine = NULL;
305 LoadedImage = NULL;
306
307 //
308 // Assert for valid parameters
309 //
310 ASSERT (NewShellParameters != NULL);
311 ASSERT (RootShellInstance != NULL);
312
313 //
314 // See if we have a shell parameters placed on us
315 //
316 Status = gBS->OpenProtocol (
317 gImageHandle,
318 &gEfiShellParametersProtocolGuid,
319 (VOID **)&ShellInfoObject.OldShellParameters,
320 gImageHandle,
321 NULL,
322 EFI_OPEN_PROTOCOL_GET_PROTOCOL
323 );
324 //
325 // if we don't then we must be the root shell (error is expected)
326 //
327 if (EFI_ERROR (Status)) {
328 *RootShellInstance = TRUE;
329 }
330
331 //
332 // Allocate the new structure
333 //
334 *NewShellParameters = AllocateZeroPool (sizeof (EFI_SHELL_PARAMETERS_PROTOCOL));
335 if ((*NewShellParameters) == NULL) {
336 return (EFI_OUT_OF_RESOURCES);
337 }
338
339 //
340 // get loaded image protocol
341 //
342 Status = gBS->OpenProtocol (
343 gImageHandle,
344 &gEfiLoadedImageProtocolGuid,
345 (VOID **)&LoadedImage,
346 gImageHandle,
347 NULL,
348 EFI_OPEN_PROTOCOL_GET_PROTOCOL
349 );
350 ASSERT_EFI_ERROR (Status);
351 //
352 // Build the full command line
353 //
354 Status = SHELL_GET_ENVIRONMENT_VARIABLE (L"ShellOpt", &Size, FullCommandLine);
355 if (Status == EFI_BUFFER_TOO_SMALL) {
356 FullCommandLine = AllocateZeroPool (Size + LoadedImage->LoadOptionsSize);
357 Status = SHELL_GET_ENVIRONMENT_VARIABLE (L"ShellOpt", &Size, FullCommandLine);
358 }
359
360 if (Status == EFI_NOT_FOUND) {
361 //
362 // no parameters via environment... ok
363 //
364 } else {
365 if (EFI_ERROR (Status)) {
366 return (Status);
367 }
368 }
369
370 if ((Size == 0) && (LoadedImage->LoadOptionsSize != 0)) {
371 ASSERT (FullCommandLine == NULL);
372 //
373 // Now we need to include a NULL terminator in the size.
374 //
375 Size = LoadedImage->LoadOptionsSize + sizeof (FullCommandLine[0]);
376 FullCommandLine = AllocateZeroPool (Size);
377 }
378
379 if (FullCommandLine != NULL) {
380 CopyMem (FullCommandLine, LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize);
381 //
382 // Populate Argc and Argv
383 //
384 Status = ParseCommandLineToArgs (
385 FullCommandLine,
386 TRUE,
387 &(*NewShellParameters)->Argv,
388 &(*NewShellParameters)->Argc
389 );
390
391 FreePool (FullCommandLine);
392
393 ASSERT_EFI_ERROR (Status);
394 } else {
395 (*NewShellParameters)->Argv = NULL;
396 (*NewShellParameters)->Argc = 0;
397 }
398
399 //
400 // Populate the 3 faked file systems...
401 //
402 if (*RootShellInstance) {
403 (*NewShellParameters)->StdIn = &FileInterfaceStdIn;
404 (*NewShellParameters)->StdOut = &FileInterfaceStdOut;
405 (*NewShellParameters)->StdErr = &FileInterfaceStdErr;
406 Status = gBS->InstallProtocolInterface (
407 &gImageHandle,
408 &gEfiShellParametersProtocolGuid,
409 EFI_NATIVE_INTERFACE,
410 (VOID *)(*NewShellParameters)
411 );
412 } else {
413 //
414 // copy from the existing ones
415 //
416 (*NewShellParameters)->StdIn = ShellInfoObject.OldShellParameters->StdIn;
417 (*NewShellParameters)->StdOut = ShellInfoObject.OldShellParameters->StdOut;
418 (*NewShellParameters)->StdErr = ShellInfoObject.OldShellParameters->StdErr;
419 Status = gBS->ReinstallProtocolInterface (
420 gImageHandle,
421 &gEfiShellParametersProtocolGuid,
422 (VOID *)ShellInfoObject.OldShellParameters,
423 (VOID *)(*NewShellParameters)
424 );
425 }
426
427 return (Status);
428 }
429
430 /**
431 frees all memory used by creation and installation of shell parameters protocol
432 and if there was an old version installed it will restore that one.
433
434 @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is
435 being cleaned up.
436
437 @retval EFI_SUCCESS the cleanup was successful
438 @return other the cleanup failed
439 @sa ReinstallProtocolInterface
440 @sa UninstallProtocolInterface
441 **/
442 EFI_STATUS
443 CleanUpShellParametersProtocol (
444 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters
445 )
446 {
447 EFI_STATUS Status;
448 UINTN LoopCounter;
449
450 //
451 // If the old exists we need to restore it
452 //
453 if (ShellInfoObject.OldShellParameters != NULL) {
454 Status = gBS->ReinstallProtocolInterface (
455 gImageHandle,
456 &gEfiShellParametersProtocolGuid,
457 (VOID *)NewShellParameters,
458 (VOID *)ShellInfoObject.OldShellParameters
459 );
460 DEBUG_CODE (
461 ShellInfoObject.OldShellParameters = NULL;
462 );
463 } else {
464 //
465 // No old one, just uninstall us...
466 //
467 Status = gBS->UninstallProtocolInterface (
468 gImageHandle,
469 &gEfiShellParametersProtocolGuid,
470 (VOID *)NewShellParameters
471 );
472 }
473
474 if (NewShellParameters->Argv != NULL) {
475 for ( LoopCounter = 0
476 ; LoopCounter < NewShellParameters->Argc
477 ; LoopCounter++
478 )
479 {
480 FreePool (NewShellParameters->Argv[LoopCounter]);
481 }
482
483 FreePool (NewShellParameters->Argv);
484 }
485
486 FreePool (NewShellParameters);
487 return (Status);
488 }
489
490 /**
491 Determine if a file name represents a unicode file.
492
493 @param[in] FileName Pointer to the filename to open.
494
495 @retval EFI_SUCCESS The file is a unicode file.
496 @return An error upon failure.
497 **/
498 EFI_STATUS
499 IsUnicodeFile (
500 IN CONST CHAR16 *FileName
501 )
502 {
503 SHELL_FILE_HANDLE Handle;
504 EFI_STATUS Status;
505 UINT64 OriginalFilePosition;
506 UINTN CharSize;
507 CHAR16 CharBuffer;
508
509 Status = gEfiShellProtocol->OpenFileByName (FileName, &Handle, EFI_FILE_MODE_READ);
510 if (EFI_ERROR (Status)) {
511 return (Status);
512 }
513
514 gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);
515 gEfiShellProtocol->SetFilePosition (Handle, 0);
516 CharSize = sizeof (CHAR16);
517 Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
518 if (EFI_ERROR (Status) || (CharBuffer != gUnicodeFileTag)) {
519 Status = EFI_BUFFER_TOO_SMALL;
520 }
521
522 gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition);
523 gEfiShellProtocol->CloseFile (Handle);
524 return (Status);
525 }
526
527 /**
528 Strips out quotes sections of a string.
529
530 All of the characters between quotes is replaced with spaces.
531
532 @param[in, out] TheString A pointer to the string to update.
533 **/
534 VOID
535 StripQuotes (
536 IN OUT CHAR16 *TheString
537 )
538 {
539 BOOLEAN RemoveNow;
540
541 for (RemoveNow = FALSE; TheString != NULL && *TheString != CHAR_NULL; TheString++) {
542 if ((*TheString == L'^') && (*(TheString + 1) == L'\"')) {
543 TheString++;
544 } else if (*TheString == L'\"') {
545 RemoveNow = (BOOLEAN) !RemoveNow;
546 } else if (RemoveNow) {
547 *TheString = L' ';
548 }
549 }
550 }
551
552 /**
553 Calculate the 32-bit CRC in a EFI table using the service provided by the
554 gRuntime service.
555
556 @param Hdr Pointer to an EFI standard header
557
558 **/
559 VOID
560 CalculateEfiHdrCrc (
561 IN OUT EFI_TABLE_HEADER *Hdr
562 )
563 {
564 UINT32 Crc;
565
566 Hdr->CRC32 = 0;
567
568 //
569 // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
570 // Crc will come back as zero if we set it to zero here
571 //
572 Crc = 0;
573 gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
574 Hdr->CRC32 = Crc;
575 }
576
577 /**
578 Fix a string to only have the file name, removing starting at the first space of whatever is quoted.
579
580 @param[in] FileName The filename to start with.
581
582 @retval NULL FileName was invalid.
583 @return The modified FileName.
584 **/
585 CHAR16 *
586 FixFileName (
587 IN CHAR16 *FileName
588 )
589 {
590 CHAR16 *Copy;
591 CHAR16 *TempLocation;
592
593 if (FileName == NULL) {
594 return (NULL);
595 }
596
597 if (FileName[0] == L'\"') {
598 Copy = FileName+1;
599 if ((TempLocation = StrStr (Copy, L"\"")) != NULL) {
600 TempLocation[0] = CHAR_NULL;
601 }
602 } else {
603 Copy = FileName;
604 while (Copy[0] == L' ') {
605 Copy++;
606 }
607
608 if ((TempLocation = StrStr (Copy, L" ")) != NULL) {
609 TempLocation[0] = CHAR_NULL;
610 }
611 }
612
613 if (Copy[0] == CHAR_NULL) {
614 return (NULL);
615 }
616
617 return (Copy);
618 }
619
620 /**
621 Fix a string to only have the environment variable name, removing starting at the first space of whatever is quoted and removing the leading and trailing %.
622
623 @param[in] FileName The filename to start with.
624
625 @retval NULL FileName was invalid.
626 @return The modified FileName.
627 **/
628 CHAR16 *
629 FixVarName (
630 IN CHAR16 *FileName
631 )
632 {
633 CHAR16 *Copy;
634 CHAR16 *TempLocation;
635
636 Copy = FileName;
637
638 if (FileName[0] == L'%') {
639 Copy = FileName+1;
640 if ((TempLocation = StrStr (Copy, L"%")) != NULL) {
641 TempLocation[0] = CHAR_NULL;
642 }
643 }
644
645 return (FixFileName (Copy));
646 }
647
648 /**
649 Write the unicode file tag to the specified file.
650
651 It is the caller's responsibility to ensure that
652 ShellInfoObject.NewEfiShellProtocol has been initialized before calling this
653 function.
654
655 @param[in] FileHandle The file to write the unicode file tag to.
656
657 @return Status code from ShellInfoObject.NewEfiShellProtocol->WriteFile.
658 **/
659 EFI_STATUS
660 WriteFileTag (
661 IN SHELL_FILE_HANDLE FileHandle
662 )
663 {
664 CHAR16 FileTag;
665 UINTN Size;
666 EFI_STATUS Status;
667
668 FileTag = gUnicodeFileTag;
669 Size = sizeof FileTag;
670 Status = ShellInfoObject.NewEfiShellProtocol->WriteFile (
671 FileHandle,
672 &Size,
673 &FileTag
674 );
675 ASSERT (EFI_ERROR (Status) || Size == sizeof FileTag);
676 return Status;
677 }
678
679 /**
680 Function will replace the current StdIn and StdOut in the ShellParameters protocol
681 structure by parsing NewCommandLine. The current values are returned to the
682 user.
683
684 This will also update the system table.
685
686 @param[in, out] ShellParameters Pointer to parameter structure to modify.
687 @param[in] NewCommandLine The new command line to parse and use.
688 @param[out] OldStdIn Pointer to old StdIn.
689 @param[out] OldStdOut Pointer to old StdOut.
690 @param[out] OldStdErr Pointer to old StdErr.
691 @param[out] SystemTableInfo Pointer to old system table information.
692
693 @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid.
694 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
695 **/
696 EFI_STATUS
697 UpdateStdInStdOutStdErr (
698 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
699 IN CHAR16 *NewCommandLine,
700 OUT SHELL_FILE_HANDLE *OldStdIn,
701 OUT SHELL_FILE_HANDLE *OldStdOut,
702 OUT SHELL_FILE_HANDLE *OldStdErr,
703 OUT SYSTEM_TABLE_INFO *SystemTableInfo
704 )
705 {
706 CHAR16 *CommandLineCopy;
707 CHAR16 *CommandLineWalker;
708 CHAR16 *StdErrFileName;
709 CHAR16 *StdOutFileName;
710 CHAR16 *StdInFileName;
711 CHAR16 *StdInVarName;
712 CHAR16 *StdOutVarName;
713 CHAR16 *StdErrVarName;
714 EFI_STATUS Status;
715 SHELL_FILE_HANDLE TempHandle;
716 UINT64 FileSize;
717 BOOLEAN OutUnicode;
718 BOOLEAN InUnicode;
719 BOOLEAN ErrUnicode;
720 BOOLEAN OutAppend;
721 BOOLEAN ErrAppend;
722 UINTN Size;
723 SPLIT_LIST *Split;
724 CHAR16 *FirstLocation;
725 BOOLEAN Volatile;
726
727 OutUnicode = TRUE;
728 InUnicode = TRUE;
729 AsciiRedirection = FALSE;
730 ErrUnicode = TRUE;
731 StdInVarName = NULL;
732 StdOutVarName = NULL;
733 StdErrVarName = NULL;
734 StdErrFileName = NULL;
735 StdInFileName = NULL;
736 StdOutFileName = NULL;
737 ErrAppend = FALSE;
738 OutAppend = FALSE;
739 CommandLineCopy = NULL;
740 FirstLocation = NULL;
741
742 if ((ShellParameters == NULL) || (SystemTableInfo == NULL) || (OldStdIn == NULL) || (OldStdOut == NULL) || (OldStdErr == NULL)) {
743 return (EFI_INVALID_PARAMETER);
744 }
745
746 SystemTableInfo->ConIn = gST->ConIn;
747 SystemTableInfo->ConInHandle = gST->ConsoleInHandle;
748 SystemTableInfo->ConOut = gST->ConOut;
749 SystemTableInfo->ConOutHandle = gST->ConsoleOutHandle;
750 SystemTableInfo->ErrOut = gST->StdErr;
751 SystemTableInfo->ErrOutHandle = gST->StandardErrorHandle;
752 *OldStdIn = ShellParameters->StdIn;
753 *OldStdOut = ShellParameters->StdOut;
754 *OldStdErr = ShellParameters->StdErr;
755
756 if (NewCommandLine == NULL) {
757 return (EFI_SUCCESS);
758 }
759
760 CommandLineCopy = StrnCatGrow (&CommandLineCopy, NULL, NewCommandLine, 0);
761 if (CommandLineCopy == NULL) {
762 return (EFI_OUT_OF_RESOURCES);
763 }
764
765 Status = EFI_SUCCESS;
766 Split = NULL;
767 FirstLocation = CommandLineCopy + StrLen (CommandLineCopy);
768
769 StripQuotes (CommandLineCopy);
770
771 if (!IsListEmpty (&ShellInfoObject.SplitList.Link)) {
772 Split = (SPLIT_LIST *)GetFirstNode (&ShellInfoObject.SplitList.Link);
773 if ((Split != NULL) && (Split->SplitStdIn != NULL)) {
774 ShellParameters->StdIn = Split->SplitStdIn;
775 }
776
777 if ((Split != NULL) && (Split->SplitStdOut != NULL)) {
778 ShellParameters->StdOut = Split->SplitStdOut;
779 }
780 }
781
782 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>>v ")) != NULL)) {
783 FirstLocation = MIN (CommandLineWalker, FirstLocation);
784 SetMem16 (CommandLineWalker, 12, L' ');
785 StdErrVarName = CommandLineWalker += 6;
786 ErrAppend = TRUE;
787 if (StrStr (CommandLineWalker, L" 2>>v ") != NULL) {
788 Status = EFI_NOT_FOUND;
789 }
790 }
791
792 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>>v ")) != NULL)) {
793 FirstLocation = MIN (CommandLineWalker, FirstLocation);
794 SetMem16 (CommandLineWalker, 12, L' ');
795 StdOutVarName = CommandLineWalker += 6;
796 OutAppend = TRUE;
797 if (StrStr (CommandLineWalker, L" 1>>v ") != NULL) {
798 Status = EFI_NOT_FOUND;
799 }
800 } else if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >>v ")) != NULL)) {
801 FirstLocation = MIN (CommandLineWalker, FirstLocation);
802 SetMem16 (CommandLineWalker, 10, L' ');
803 StdOutVarName = CommandLineWalker += 5;
804 OutAppend = TRUE;
805 if (StrStr (CommandLineWalker, L" >>v ") != NULL) {
806 Status = EFI_NOT_FOUND;
807 }
808 } else if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >v ")) != NULL)) {
809 FirstLocation = MIN (CommandLineWalker, FirstLocation);
810 SetMem16 (CommandLineWalker, 8, L' ');
811 StdOutVarName = CommandLineWalker += 4;
812 OutAppend = FALSE;
813 if (StrStr (CommandLineWalker, L" >v ") != NULL) {
814 Status = EFI_NOT_FOUND;
815 }
816 }
817
818 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>>a ")) != NULL)) {
819 FirstLocation = MIN (CommandLineWalker, FirstLocation);
820 SetMem16 (CommandLineWalker, 12, L' ');
821 StdOutFileName = CommandLineWalker += 6;
822 OutAppend = TRUE;
823 OutUnicode = FALSE;
824 if (StrStr (CommandLineWalker, L" 1>>a ") != NULL) {
825 Status = EFI_NOT_FOUND;
826 }
827 }
828
829 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>> ")) != NULL)) {
830 FirstLocation = MIN (CommandLineWalker, FirstLocation);
831 SetMem16 (CommandLineWalker, 10, L' ');
832 if (StdOutFileName != NULL) {
833 Status = EFI_INVALID_PARAMETER;
834 } else {
835 StdOutFileName = CommandLineWalker += 5;
836 OutAppend = TRUE;
837 }
838
839 if (StrStr (CommandLineWalker, L" 1>> ") != NULL) {
840 Status = EFI_NOT_FOUND;
841 }
842 }
843
844 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >> ")) != NULL)) {
845 FirstLocation = MIN (CommandLineWalker, FirstLocation);
846 SetMem16 (CommandLineWalker, 8, L' ');
847 if (StdOutFileName != NULL) {
848 Status = EFI_INVALID_PARAMETER;
849 } else {
850 StdOutFileName = CommandLineWalker += 4;
851 OutAppend = TRUE;
852 }
853
854 if (StrStr (CommandLineWalker, L" >> ") != NULL) {
855 Status = EFI_NOT_FOUND;
856 }
857 }
858
859 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >>a ")) != NULL)) {
860 FirstLocation = MIN (CommandLineWalker, FirstLocation);
861 SetMem16 (CommandLineWalker, 10, L' ');
862 if (StdOutFileName != NULL) {
863 Status = EFI_INVALID_PARAMETER;
864 } else {
865 StdOutFileName = CommandLineWalker += 5;
866 OutAppend = TRUE;
867 OutUnicode = FALSE;
868 }
869
870 if (StrStr (CommandLineWalker, L" >>a ") != NULL) {
871 Status = EFI_NOT_FOUND;
872 }
873 }
874
875 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>a ")) != NULL)) {
876 FirstLocation = MIN (CommandLineWalker, FirstLocation);
877 SetMem16 (CommandLineWalker, 10, L' ');
878 if (StdOutFileName != NULL) {
879 Status = EFI_INVALID_PARAMETER;
880 } else {
881 StdOutFileName = CommandLineWalker += 5;
882 OutAppend = FALSE;
883 OutUnicode = FALSE;
884 }
885
886 if (StrStr (CommandLineWalker, L" 1>a ") != NULL) {
887 Status = EFI_NOT_FOUND;
888 }
889 }
890
891 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >a ")) != NULL)) {
892 FirstLocation = MIN (CommandLineWalker, FirstLocation);
893 SetMem16 (CommandLineWalker, 8, L' ');
894 if (StdOutFileName != NULL) {
895 Status = EFI_INVALID_PARAMETER;
896 } else {
897 StdOutFileName = CommandLineWalker += 4;
898 OutAppend = FALSE;
899 OutUnicode = FALSE;
900 }
901
902 if (StrStr (CommandLineWalker, L" >a ") != NULL) {
903 Status = EFI_NOT_FOUND;
904 }
905 }
906
907 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>> ")) != NULL)) {
908 FirstLocation = MIN (CommandLineWalker, FirstLocation);
909 SetMem16 (CommandLineWalker, 10, L' ');
910 if (StdErrFileName != NULL) {
911 Status = EFI_INVALID_PARAMETER;
912 } else {
913 StdErrFileName = CommandLineWalker += 5;
914 ErrAppend = TRUE;
915 }
916
917 if (StrStr (CommandLineWalker, L" 2>> ") != NULL) {
918 Status = EFI_NOT_FOUND;
919 }
920 }
921
922 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>v ")) != NULL)) {
923 FirstLocation = MIN (CommandLineWalker, FirstLocation);
924 SetMem16 (CommandLineWalker, 10, L' ');
925 if (StdErrVarName != NULL) {
926 Status = EFI_INVALID_PARAMETER;
927 } else {
928 StdErrVarName = CommandLineWalker += 5;
929 ErrAppend = FALSE;
930 }
931
932 if (StrStr (CommandLineWalker, L" 2>v ") != NULL) {
933 Status = EFI_NOT_FOUND;
934 }
935 }
936
937 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>v ")) != NULL)) {
938 FirstLocation = MIN (CommandLineWalker, FirstLocation);
939 SetMem16 (CommandLineWalker, 10, L' ');
940 if (StdOutVarName != NULL) {
941 Status = EFI_INVALID_PARAMETER;
942 } else {
943 StdOutVarName = CommandLineWalker += 5;
944 OutAppend = FALSE;
945 }
946
947 if (StrStr (CommandLineWalker, L" 1>v ") != NULL) {
948 Status = EFI_NOT_FOUND;
949 }
950 }
951
952 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>a ")) != NULL)) {
953 FirstLocation = MIN (CommandLineWalker, FirstLocation);
954 SetMem16 (CommandLineWalker, 10, L' ');
955 if (StdErrFileName != NULL) {
956 Status = EFI_INVALID_PARAMETER;
957 } else {
958 StdErrFileName = CommandLineWalker += 5;
959 ErrAppend = FALSE;
960 ErrUnicode = FALSE;
961 }
962
963 if (StrStr (CommandLineWalker, L" 2>a ") != NULL) {
964 Status = EFI_NOT_FOUND;
965 }
966 }
967
968 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2> ")) != NULL)) {
969 FirstLocation = MIN (CommandLineWalker, FirstLocation);
970 SetMem16 (CommandLineWalker, 8, L' ');
971 if (StdErrFileName != NULL) {
972 Status = EFI_INVALID_PARAMETER;
973 } else {
974 StdErrFileName = CommandLineWalker += 4;
975 ErrAppend = FALSE;
976 }
977
978 if (StrStr (CommandLineWalker, L" 2> ") != NULL) {
979 Status = EFI_NOT_FOUND;
980 }
981 }
982
983 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1> ")) != NULL)) {
984 FirstLocation = MIN (CommandLineWalker, FirstLocation);
985 SetMem16 (CommandLineWalker, 8, L' ');
986 if (StdOutFileName != NULL) {
987 Status = EFI_INVALID_PARAMETER;
988 } else {
989 StdOutFileName = CommandLineWalker += 4;
990 OutAppend = FALSE;
991 }
992
993 if (StrStr (CommandLineWalker, L" 1> ") != NULL) {
994 Status = EFI_NOT_FOUND;
995 }
996 }
997
998 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" > ")) != NULL)) {
999 FirstLocation = MIN (CommandLineWalker, FirstLocation);
1000 SetMem16 (CommandLineWalker, 6, L' ');
1001 if (StdOutFileName != NULL) {
1002 Status = EFI_INVALID_PARAMETER;
1003 } else {
1004 StdOutFileName = CommandLineWalker += 3;
1005 OutAppend = FALSE;
1006 }
1007
1008 if (StrStr (CommandLineWalker, L" > ") != NULL) {
1009 Status = EFI_NOT_FOUND;
1010 }
1011 }
1012
1013 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" < ")) != NULL)) {
1014 FirstLocation = MIN (CommandLineWalker, FirstLocation);
1015 SetMem16 (CommandLineWalker, 6, L' ');
1016 if (StdInFileName != NULL) {
1017 Status = EFI_INVALID_PARAMETER;
1018 } else {
1019 StdInFileName = CommandLineWalker += 3;
1020 }
1021
1022 if (StrStr (CommandLineWalker, L" < ") != NULL) {
1023 Status = EFI_NOT_FOUND;
1024 }
1025 }
1026
1027 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" <a ")) != NULL)) {
1028 FirstLocation = MIN (CommandLineWalker, FirstLocation);
1029 SetMem16 (CommandLineWalker, 8, L' ');
1030 if (StdInFileName != NULL) {
1031 Status = EFI_INVALID_PARAMETER;
1032 } else {
1033 StdInFileName = CommandLineWalker += 4;
1034 InUnicode = FALSE;
1035 AsciiRedirection = TRUE;
1036 }
1037
1038 if (StrStr (CommandLineWalker, L" <a ") != NULL) {
1039 Status = EFI_NOT_FOUND;
1040 }
1041 }
1042
1043 if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" <v ")) != NULL)) {
1044 FirstLocation = MIN (CommandLineWalker, FirstLocation);
1045 SetMem16 (CommandLineWalker, 8, L' ');
1046 if (StdInVarName != NULL) {
1047 Status = EFI_INVALID_PARAMETER;
1048 } else {
1049 StdInVarName = CommandLineWalker += 4;
1050 }
1051
1052 if (StrStr (CommandLineWalker, L" <v ") != NULL) {
1053 Status = EFI_NOT_FOUND;
1054 }
1055 }
1056
1057 //
1058 // re-populate the string to support any filenames that were in quotes.
1059 //
1060 StrnCpyS (CommandLineCopy, StrSize (CommandLineCopy)/sizeof (CHAR16), NewCommandLine, StrLen (NewCommandLine));
1061
1062 if ( (FirstLocation != CommandLineCopy + StrLen (CommandLineCopy))
1063 && (((UINTN)FirstLocation - (UINTN)CommandLineCopy)/sizeof (CHAR16) < StrLen (NewCommandLine))
1064 )
1065 {
1066 *(NewCommandLine + ((UINTN)FirstLocation - (UINTN)CommandLineCopy)/sizeof (CHAR16)) = CHAR_NULL;
1067 }
1068
1069 if (!EFI_ERROR (Status)) {
1070 if (StdErrFileName != NULL) {
1071 if ((StdErrFileName = FixFileName (StdErrFileName)) == NULL) {
1072 Status = EFI_INVALID_PARAMETER;
1073 }
1074 }
1075
1076 if (StdOutFileName != NULL) {
1077 if ((StdOutFileName = FixFileName (StdOutFileName)) == NULL) {
1078 Status = EFI_INVALID_PARAMETER;
1079 }
1080 }
1081
1082 if (StdInFileName != NULL) {
1083 if ((StdInFileName = FixFileName (StdInFileName)) == NULL) {
1084 Status = EFI_INVALID_PARAMETER;
1085 }
1086 }
1087
1088 if (StdErrVarName != NULL) {
1089 if ((StdErrVarName = FixVarName (StdErrVarName)) == NULL) {
1090 Status = EFI_INVALID_PARAMETER;
1091 }
1092 }
1093
1094 if (StdOutVarName != NULL) {
1095 if ((StdOutVarName = FixVarName (StdOutVarName)) == NULL) {
1096 Status = EFI_INVALID_PARAMETER;
1097 }
1098 }
1099
1100 if (StdInVarName != NULL) {
1101 if ((StdInVarName = FixVarName (StdInVarName)) == NULL) {
1102 Status = EFI_INVALID_PARAMETER;
1103 }
1104 }
1105
1106 //
1107 // Verify not the same and not duplicating something from a split
1108 //
1109 if (
1110 //
1111 // Check that no 2 filenames are the same
1112 //
1113 ((StdErrFileName != NULL) && (StdOutFileName != NULL) && (StringNoCaseCompare (&StdErrFileName, &StdOutFileName) == 0))
1114 || ((StdErrFileName != NULL) && (StdInFileName != NULL) && (StringNoCaseCompare (&StdErrFileName, &StdInFileName) == 0))
1115 || ((StdOutFileName != NULL) && (StdInFileName != NULL) && (StringNoCaseCompare (&StdOutFileName, &StdInFileName) == 0))
1116 //
1117 // Check that no 2 variable names are the same
1118 //
1119 || ((StdErrVarName != NULL) && (StdInVarName != NULL) && (StringNoCaseCompare (&StdErrVarName, &StdInVarName) == 0))
1120 || ((StdOutVarName != NULL) && (StdInVarName != NULL) && (StringNoCaseCompare (&StdOutVarName, &StdInVarName) == 0))
1121 || ((StdErrVarName != NULL) && (StdOutVarName != NULL) && (StringNoCaseCompare (&StdErrVarName, &StdOutVarName) == 0))
1122 //
1123 // When a split (using | operator) is in place some are not allowed
1124 //
1125 || ((Split != NULL) && (Split->SplitStdIn != NULL) && ((StdInVarName != NULL) || (StdInFileName != NULL)))
1126 || ((Split != NULL) && (Split->SplitStdOut != NULL) && ((StdOutVarName != NULL) || (StdOutFileName != NULL)))
1127 //
1128 // Check that nothing is trying to be output to 2 locations.
1129 //
1130 || ((StdErrFileName != NULL) && (StdErrVarName != NULL))
1131 || ((StdOutFileName != NULL) && (StdOutVarName != NULL))
1132 || ((StdInFileName != NULL) && (StdInVarName != NULL))
1133 //
1134 // Check for no volatile environment variables
1135 //
1136 || ((StdErrVarName != NULL) && !EFI_ERROR (IsVolatileEnv (StdErrVarName, &Volatile)) && !Volatile)
1137 || ((StdOutVarName != NULL) && !EFI_ERROR (IsVolatileEnv (StdOutVarName, &Volatile)) && !Volatile)
1138 //
1139 // Cant redirect during a reconnect operation.
1140 //
1141 || ( (StrStr (NewCommandLine, L"connect -r") != NULL)
1142 && ((StdOutVarName != NULL) || (StdOutFileName != NULL) || (StdErrFileName != NULL) || (StdErrVarName != NULL)))
1143 //
1144 // Check that filetypes (Unicode/Ascii) do not change during an append
1145 //
1146 || ((StdOutFileName != NULL) && OutUnicode && OutAppend && (!EFI_ERROR (ShellFileExists (StdOutFileName)) && EFI_ERROR (IsUnicodeFile (StdOutFileName))))
1147 || ((StdErrFileName != NULL) && ErrUnicode && ErrAppend && (!EFI_ERROR (ShellFileExists (StdErrFileName)) && EFI_ERROR (IsUnicodeFile (StdErrFileName))))
1148 || ((StdOutFileName != NULL) && !OutUnicode && OutAppend && (!EFI_ERROR (ShellFileExists (StdOutFileName)) && !EFI_ERROR (IsUnicodeFile (StdOutFileName))))
1149 || ((StdErrFileName != NULL) && !ErrUnicode && ErrAppend && (!EFI_ERROR (ShellFileExists (StdErrFileName)) && !EFI_ERROR (IsUnicodeFile (StdErrFileName))))
1150 )
1151 {
1152 Status = EFI_INVALID_PARAMETER;
1153 ShellParameters->StdIn = *OldStdIn;
1154 ShellParameters->StdOut = *OldStdOut;
1155 ShellParameters->StdErr = *OldStdErr;
1156 } else if (!EFI_ERROR (Status)) {
1157 //
1158 // Open the Std<Whatever> and we should not have conflicts here...
1159 //
1160
1161 //
1162 // StdErr to a file
1163 //
1164 if (StdErrFileName != NULL) {
1165 if (!ErrAppend) {
1166 //
1167 // delete existing file.
1168 //
1169 ShellInfoObject.NewEfiShellProtocol->DeleteFileByName (StdErrFileName);
1170 }
1171
1172 Status = ShellOpenFileByName (StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, 0);
1173 if (!ErrAppend && ErrUnicode && !EFI_ERROR (Status)) {
1174 Status = WriteFileTag (TempHandle);
1175 }
1176
1177 if (!ErrUnicode && !EFI_ERROR (Status)) {
1178 TempHandle = CreateFileInterfaceFile (TempHandle, FALSE);
1179 ASSERT (TempHandle != NULL);
1180 }
1181
1182 if (!EFI_ERROR (Status)) {
1183 ShellParameters->StdErr = TempHandle;
1184 gST->StdErr = CreateSimpleTextOutOnFile (TempHandle, &gST->StandardErrorHandle, gST->StdErr);
1185 }
1186 }
1187
1188 //
1189 // StdOut to a file
1190 //
1191 if (!EFI_ERROR (Status) && (StdOutFileName != NULL)) {
1192 if (!OutAppend) {
1193 //
1194 // delete existing file.
1195 //
1196 ShellInfoObject.NewEfiShellProtocol->DeleteFileByName (StdOutFileName);
1197 }
1198
1199 Status = ShellOpenFileByName (StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, 0);
1200 if (TempHandle == NULL) {
1201 Status = EFI_INVALID_PARAMETER;
1202 } else {
1203 if (gUnicodeCollation->MetaiMatch (gUnicodeCollation, StdOutFileName, L"NUL")) {
1204 // no-op
1205 } else if (!OutAppend && OutUnicode && !EFI_ERROR (Status)) {
1206 Status = WriteFileTag (TempHandle);
1207 } else if (OutAppend) {
1208 Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize (TempHandle, &FileSize);
1209 if (!EFI_ERROR (Status)) {
1210 //
1211 // When appending to a new unicode file, write the file tag.
1212 // Otherwise (ie. when appending to a new ASCII file, or an
1213 // existent file with any encoding), just seek to the end.
1214 //
1215 Status = (FileSize == 0 && OutUnicode) ?
1216 WriteFileTag (TempHandle) :
1217 ShellInfoObject.NewEfiShellProtocol->SetFilePosition (
1218 TempHandle,
1219 FileSize
1220 );
1221 }
1222 }
1223
1224 if (!OutUnicode && !EFI_ERROR (Status)) {
1225 TempHandle = CreateFileInterfaceFile (TempHandle, FALSE);
1226 ASSERT (TempHandle != NULL);
1227 }
1228
1229 if (!EFI_ERROR (Status)) {
1230 ShellParameters->StdOut = TempHandle;
1231 gST->ConOut = CreateSimpleTextOutOnFile (TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
1232 }
1233 }
1234 }
1235
1236 //
1237 // StdOut to a var
1238 //
1239 if (!EFI_ERROR (Status) && (StdOutVarName != NULL)) {
1240 if (!OutAppend) {
1241 //
1242 // delete existing variable.
1243 //
1244 SHELL_SET_ENVIRONMENT_VARIABLE_V (StdOutVarName, 0, L"");
1245 }
1246
1247 TempHandle = CreateFileInterfaceEnv (StdOutVarName);
1248 ASSERT (TempHandle != NULL);
1249 ShellParameters->StdOut = TempHandle;
1250 gST->ConOut = CreateSimpleTextOutOnFile (TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
1251 }
1252
1253 //
1254 // StdErr to a var
1255 //
1256 if (!EFI_ERROR (Status) && (StdErrVarName != NULL)) {
1257 if (!ErrAppend) {
1258 //
1259 // delete existing variable.
1260 //
1261 SHELL_SET_ENVIRONMENT_VARIABLE_V (StdErrVarName, 0, L"");
1262 }
1263
1264 TempHandle = CreateFileInterfaceEnv (StdErrVarName);
1265 ASSERT (TempHandle != NULL);
1266 ShellParameters->StdErr = TempHandle;
1267 gST->StdErr = CreateSimpleTextOutOnFile (TempHandle, &gST->StandardErrorHandle, gST->StdErr);
1268 }
1269
1270 //
1271 // StdIn from a var
1272 //
1273 if (!EFI_ERROR (Status) && (StdInVarName != NULL)) {
1274 TempHandle = CreateFileInterfaceEnv (StdInVarName);
1275 if (TempHandle == NULL) {
1276 Status = EFI_OUT_OF_RESOURCES;
1277 } else {
1278 if (!InUnicode) {
1279 TempHandle = CreateFileInterfaceFile (TempHandle, FALSE);
1280 }
1281
1282 Size = 0;
1283 if ((TempHandle == NULL) || (((EFI_FILE_PROTOCOL *)TempHandle)->Read (TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL)) {
1284 Status = EFI_INVALID_PARAMETER;
1285 } else {
1286 ShellParameters->StdIn = TempHandle;
1287 gST->ConIn = CreateSimpleTextInOnFile (TempHandle, &gST->ConsoleInHandle);
1288 }
1289 }
1290 }
1291
1292 //
1293 // StdIn from a file
1294 //
1295 if (!EFI_ERROR (Status) && (StdInFileName != NULL)) {
1296 Status = ShellOpenFileByName (
1297 StdInFileName,
1298 &TempHandle,
1299 EFI_FILE_MODE_READ,
1300 0
1301 );
1302 if (!EFI_ERROR (Status)) {
1303 if (!InUnicode) {
1304 //
1305 // Create the ASCII->Unicode conversion layer
1306 //
1307 TempHandle = CreateFileInterfaceFile (TempHandle, FALSE);
1308 }
1309
1310 ShellParameters->StdIn = TempHandle;
1311 gST->ConIn = CreateSimpleTextInOnFile (TempHandle, &gST->ConsoleInHandle);
1312 }
1313 }
1314 }
1315 }
1316
1317 FreePool (CommandLineCopy);
1318
1319 CalculateEfiHdrCrc (&gST->Hdr);
1320
1321 if ((gST->ConIn == NULL) || (gST->ConOut == NULL)) {
1322 Status = EFI_OUT_OF_RESOURCES;
1323 }
1324
1325 if (Status == EFI_NOT_FOUND) {
1326 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle);
1327 } else if (EFI_ERROR (Status)) {
1328 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);
1329 }
1330
1331 return (Status);
1332 }
1333
1334 /**
1335 Function will replace the current StdIn and StdOut in the ShellParameters protocol
1336 structure with StdIn and StdOut. The current values are de-allocated.
1337
1338 @param[in, out] ShellParameters Pointer to parameter structure to modify.
1339 @param[in] OldStdIn Pointer to old StdIn.
1340 @param[in] OldStdOut Pointer to old StdOut.
1341 @param[in] OldStdErr Pointer to old StdErr.
1342 @param[in] SystemTableInfo Pointer to old system table information.
1343 **/
1344 EFI_STATUS
1345 RestoreStdInStdOutStdErr (
1346 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1347 IN SHELL_FILE_HANDLE *OldStdIn,
1348 IN SHELL_FILE_HANDLE *OldStdOut,
1349 IN SHELL_FILE_HANDLE *OldStdErr,
1350 IN SYSTEM_TABLE_INFO *SystemTableInfo
1351 )
1352 {
1353 SPLIT_LIST *Split;
1354
1355 if ( (ShellParameters == NULL)
1356 || (OldStdIn == NULL)
1357 || (OldStdOut == NULL)
1358 || (OldStdErr == NULL)
1359 || (SystemTableInfo == NULL))
1360 {
1361 return (EFI_INVALID_PARAMETER);
1362 }
1363
1364 if (!IsListEmpty (&ShellInfoObject.SplitList.Link)) {
1365 Split = (SPLIT_LIST *)GetFirstNode (&ShellInfoObject.SplitList.Link);
1366 } else {
1367 Split = NULL;
1368 }
1369
1370 if (ShellParameters->StdIn != *OldStdIn) {
1371 if (((Split != NULL) && (Split->SplitStdIn != ShellParameters->StdIn)) || (Split == NULL)) {
1372 gEfiShellProtocol->CloseFile (ShellParameters->StdIn);
1373 }
1374
1375 ShellParameters->StdIn = *OldStdIn;
1376 }
1377
1378 if (ShellParameters->StdOut != *OldStdOut) {
1379 if (((Split != NULL) && (Split->SplitStdOut != ShellParameters->StdOut)) || (Split == NULL)) {
1380 gEfiShellProtocol->CloseFile (ShellParameters->StdOut);
1381 }
1382
1383 ShellParameters->StdOut = *OldStdOut;
1384 }
1385
1386 if (ShellParameters->StdErr != *OldStdErr) {
1387 gEfiShellProtocol->CloseFile (ShellParameters->StdErr);
1388 ShellParameters->StdErr = *OldStdErr;
1389 }
1390
1391 if (gST->ConIn != SystemTableInfo->ConIn) {
1392 CloseSimpleTextInOnFile (gST->ConIn);
1393 gST->ConIn = SystemTableInfo->ConIn;
1394 gST->ConsoleInHandle = SystemTableInfo->ConInHandle;
1395 }
1396
1397 if (gST->ConOut != SystemTableInfo->ConOut) {
1398 CloseSimpleTextOutOnFile (gST->ConOut);
1399 gST->ConOut = SystemTableInfo->ConOut;
1400 gST->ConsoleOutHandle = SystemTableInfo->ConOutHandle;
1401 }
1402
1403 if (gST->StdErr != SystemTableInfo->ErrOut) {
1404 CloseSimpleTextOutOnFile (gST->StdErr);
1405 gST->StdErr = SystemTableInfo->ErrOut;
1406 gST->StandardErrorHandle = SystemTableInfo->ErrOutHandle;
1407 }
1408
1409 CalculateEfiHdrCrc (&gST->Hdr);
1410
1411 return (EFI_SUCCESS);
1412 }
1413
1414 /**
1415 Function will replace the current Argc and Argv in the ShellParameters protocol
1416 structure by parsing NewCommandLine. The current values are returned to the
1417 user.
1418
1419 If OldArgv or OldArgc is NULL then that value is not returned.
1420
1421 @param[in, out] ShellParameters Pointer to parameter structure to modify.
1422 @param[in] NewCommandLine The new command line to parse and use.
1423 @param[in] Type The type of operation.
1424 @param[out] OldArgv Pointer to old list of parameters.
1425 @param[out] OldArgc Pointer to old number of items in Argv list.
1426
1427
1428 @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid.
1429 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1430 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1431 **/
1432 EFI_STATUS
1433 UpdateArgcArgv (
1434 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1435 IN CONST CHAR16 *NewCommandLine,
1436 IN SHELL_OPERATION_TYPES Type,
1437 OUT CHAR16 ***OldArgv OPTIONAL,
1438 OUT UINTN *OldArgc OPTIONAL
1439 )
1440 {
1441 BOOLEAN StripParamQuotation;
1442
1443 ASSERT (ShellParameters != NULL);
1444 StripParamQuotation = TRUE;
1445
1446 if (OldArgc != NULL) {
1447 *OldArgc = ShellParameters->Argc;
1448 }
1449
1450 if (OldArgc != NULL) {
1451 *OldArgv = ShellParameters->Argv;
1452 }
1453
1454 if (Type == Script_File_Name) {
1455 StripParamQuotation = FALSE;
1456 }
1457
1458 return ParseCommandLineToArgs (
1459 NewCommandLine,
1460 StripParamQuotation,
1461 &(ShellParameters->Argv),
1462 &(ShellParameters->Argc)
1463 );
1464 }
1465
1466 /**
1467 Function will replace the current Argc and Argv in the ShellParameters protocol
1468 structure with Argv and Argc. The current values are de-allocated and the
1469 OldArgv must not be deallocated by the caller.
1470
1471 @param[in, out] ShellParameters pointer to parameter structure to modify
1472 @param[in] OldArgv pointer to old list of parameters
1473 @param[in] OldArgc pointer to old number of items in Argv list
1474 **/
1475 VOID
1476 RestoreArgcArgv (
1477 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1478 IN CHAR16 ***OldArgv,
1479 IN UINTN *OldArgc
1480 )
1481 {
1482 UINTN LoopCounter;
1483
1484 ASSERT (ShellParameters != NULL);
1485 ASSERT (OldArgv != NULL);
1486 ASSERT (OldArgc != NULL);
1487
1488 if (ShellParameters->Argv != NULL) {
1489 for ( LoopCounter = 0
1490 ; LoopCounter < ShellParameters->Argc
1491 ; LoopCounter++
1492 )
1493 {
1494 FreePool (ShellParameters->Argv[LoopCounter]);
1495 }
1496
1497 FreePool (ShellParameters->Argv);
1498 }
1499
1500 ShellParameters->Argv = *OldArgv;
1501 *OldArgv = NULL;
1502 ShellParameters->Argc = *OldArgc;
1503 *OldArgc = 0;
1504 }