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