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