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