]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ShellParametersProtocol.c
3684f9cd827b175d2abcde6b07e042c15b6d351e
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellParametersProtocol.c
1 /** @file
2 Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation,
3 manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL.
4
5 Copyright (C) 2014, Red Hat, Inc.
6 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
7 Copyright (c) 2009 - 2016, 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
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
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
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
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
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
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
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
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
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
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
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
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
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 BOOLEAN Volatile;
740
741 OutUnicode = TRUE;
742 InUnicode = TRUE;
743 AsciiRedirection = FALSE;
744 ErrUnicode = TRUE;
745 StdInVarName = NULL;
746 StdOutVarName = NULL;
747 StdErrVarName = NULL;
748 StdErrFileName = NULL;
749 StdInFileName = NULL;
750 StdOutFileName = NULL;
751 ErrAppend = FALSE;
752 OutAppend = FALSE;
753 CommandLineCopy = NULL;
754 FirstLocation = NULL;
755
756 if (ShellParameters == NULL || SystemTableInfo == NULL || OldStdIn == NULL || OldStdOut == NULL || OldStdErr == NULL) {
757 return (EFI_INVALID_PARAMETER);
758 }
759
760 SystemTableInfo->ConIn = gST->ConIn;
761 SystemTableInfo->ConInHandle = gST->ConsoleInHandle;
762 SystemTableInfo->ConOut = gST->ConOut;
763 SystemTableInfo->ConOutHandle = gST->ConsoleOutHandle;
764 SystemTableInfo->ErrOut = gST->StdErr;
765 SystemTableInfo->ErrOutHandle = gST->StandardErrorHandle;
766 *OldStdIn = ShellParameters->StdIn;
767 *OldStdOut = ShellParameters->StdOut;
768 *OldStdErr = ShellParameters->StdErr;
769
770 if (NewCommandLine == NULL) {
771 return (EFI_SUCCESS);
772 }
773
774 CommandLineCopy = StrnCatGrow(&CommandLineCopy, NULL, NewCommandLine, 0);
775 if (CommandLineCopy == NULL) {
776 return (EFI_OUT_OF_RESOURCES);
777 }
778 Status = EFI_SUCCESS;
779 Split = NULL;
780 FirstLocation = CommandLineCopy + StrLen(CommandLineCopy);
781
782 StripQuotes(CommandLineCopy);
783
784 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {
785 Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);
786 if (Split != NULL && Split->SplitStdIn != NULL) {
787 ShellParameters->StdIn = Split->SplitStdIn;
788 }
789 if (Split != NULL && Split->SplitStdOut != NULL) {
790 ShellParameters->StdOut = Split->SplitStdOut;
791 }
792 }
793
794 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>>v ")) != NULL) {
795 FirstLocation = MIN(CommandLineWalker, FirstLocation);
796 SetMem16(CommandLineWalker, 12, L' ');
797 StdErrVarName = CommandLineWalker += 6;
798 ErrAppend = TRUE;
799 if (StrStr(CommandLineWalker, L" 2>>v ") != NULL) {
800 Status = EFI_NOT_FOUND;
801 }
802 }
803 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>v ")) != NULL) {
804 FirstLocation = MIN(CommandLineWalker, FirstLocation);
805 SetMem16(CommandLineWalker, 12, L' ');
806 StdOutVarName = CommandLineWalker += 6;
807 OutAppend = TRUE;
808 if (StrStr(CommandLineWalker, L" 1>>v ") != NULL) {
809 Status = EFI_NOT_FOUND;
810 }
811 } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>v ")) != NULL) {
812 FirstLocation = MIN(CommandLineWalker, FirstLocation);
813 SetMem16(CommandLineWalker, 10, L' ');
814 StdOutVarName = CommandLineWalker += 5;
815 OutAppend = TRUE;
816 if (StrStr(CommandLineWalker, L" >>v ") != NULL) {
817 Status = EFI_NOT_FOUND;
818 }
819 } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >v ")) != NULL) {
820 FirstLocation = MIN(CommandLineWalker, FirstLocation);
821 SetMem16(CommandLineWalker, 8, L' ');
822 StdOutVarName = CommandLineWalker += 4;
823 OutAppend = FALSE;
824 if (StrStr(CommandLineWalker, L" >v ") != NULL) {
825 Status = EFI_NOT_FOUND;
826 }
827 }
828 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>a ")) != NULL) {
829 FirstLocation = MIN(CommandLineWalker, FirstLocation);
830 SetMem16(CommandLineWalker, 12, L' ');
831 StdOutFileName = CommandLineWalker += 6;
832 OutAppend = TRUE;
833 OutUnicode = FALSE;
834 if (StrStr(CommandLineWalker, L" 1>>a ") != NULL) {
835 Status = EFI_NOT_FOUND;
836 }
837 }
838 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>> ")) != NULL) {
839 FirstLocation = MIN(CommandLineWalker, FirstLocation);
840 SetMem16(CommandLineWalker, 10, L' ');
841 if (StdOutFileName != NULL) {
842 Status = EFI_INVALID_PARAMETER;
843 } else {
844 StdOutFileName = CommandLineWalker += 5;
845 OutAppend = TRUE;
846 }
847 if (StrStr(CommandLineWalker, L" 1>> ") != NULL) {
848 Status = EFI_NOT_FOUND;
849 }
850 }
851 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >> ")) != NULL) {
852 FirstLocation = MIN(CommandLineWalker, FirstLocation);
853 SetMem16(CommandLineWalker, 8, L' ');
854 if (StdOutFileName != NULL) {
855 Status = EFI_INVALID_PARAMETER;
856 } else {
857 StdOutFileName = CommandLineWalker += 4;
858 OutAppend = TRUE;
859 }
860 if (StrStr(CommandLineWalker, L" >> ") != NULL) {
861 Status = EFI_NOT_FOUND;
862 }
863 }
864 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>a ")) != NULL) {
865 FirstLocation = MIN(CommandLineWalker, FirstLocation);
866 SetMem16(CommandLineWalker, 10, L' ');
867 if (StdOutFileName != NULL) {
868 Status = EFI_INVALID_PARAMETER;
869 } else {
870 StdOutFileName = CommandLineWalker += 5;
871 OutAppend = TRUE;
872 OutUnicode = FALSE;
873 }
874 if (StrStr(CommandLineWalker, L" >>a ") != NULL) {
875 Status = EFI_NOT_FOUND;
876 }
877 }
878 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>a ")) != NULL) {
879 FirstLocation = MIN(CommandLineWalker, FirstLocation);
880 SetMem16(CommandLineWalker, 10, L' ');
881 if (StdOutFileName != NULL) {
882 Status = EFI_INVALID_PARAMETER;
883 } else {
884 StdOutFileName = CommandLineWalker += 5;
885 OutAppend = FALSE;
886 OutUnicode = FALSE;
887 }
888 if (StrStr(CommandLineWalker, L" 1>a ") != NULL) {
889 Status = EFI_NOT_FOUND;
890 }
891 }
892 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >a ")) != NULL) {
893 FirstLocation = MIN(CommandLineWalker, FirstLocation);
894 SetMem16(CommandLineWalker, 8, L' ');
895 if (StdOutFileName != NULL) {
896 Status = EFI_INVALID_PARAMETER;
897 } else {
898 StdOutFileName = CommandLineWalker += 4;
899 OutAppend = FALSE;
900 OutUnicode = FALSE;
901 }
902 if (StrStr(CommandLineWalker, L" >a ") != NULL) {
903 Status = EFI_NOT_FOUND;
904 }
905 }
906 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>> ")) != NULL) {
907 FirstLocation = MIN(CommandLineWalker, FirstLocation);
908 SetMem16(CommandLineWalker, 10, L' ');
909 if (StdErrFileName != NULL) {
910 Status = EFI_INVALID_PARAMETER;
911 } else {
912 StdErrFileName = CommandLineWalker += 5;
913 ErrAppend = TRUE;
914 }
915 if (StrStr(CommandLineWalker, L" 2>> ") != NULL) {
916 Status = EFI_NOT_FOUND;
917 }
918 }
919
920 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>v ")) != NULL) {
921 FirstLocation = MIN(CommandLineWalker, FirstLocation);
922 SetMem16(CommandLineWalker, 10, L' ');
923 if (StdErrVarName != NULL) {
924 Status = EFI_INVALID_PARAMETER;
925 } else {
926 StdErrVarName = CommandLineWalker += 5;
927 ErrAppend = FALSE;
928 }
929 if (StrStr(CommandLineWalker, L" 2>v ") != NULL) {
930 Status = EFI_NOT_FOUND;
931 }
932 }
933 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>v ")) != NULL) {
934 FirstLocation = MIN(CommandLineWalker, FirstLocation);
935 SetMem16(CommandLineWalker, 10, L' ');
936 if (StdOutVarName != NULL) {
937 Status = EFI_INVALID_PARAMETER;
938 } else {
939 StdOutVarName = CommandLineWalker += 5;
940 OutAppend = FALSE;
941 }
942 if (StrStr(CommandLineWalker, L" 1>v ") != NULL) {
943 Status = EFI_NOT_FOUND;
944 }
945 }
946 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>a ")) != NULL) {
947 FirstLocation = MIN(CommandLineWalker, FirstLocation);
948 SetMem16(CommandLineWalker, 10, L' ');
949 if (StdErrFileName != NULL) {
950 Status = EFI_INVALID_PARAMETER;
951 } else {
952 StdErrFileName = CommandLineWalker += 5;
953 ErrAppend = FALSE;
954 ErrUnicode = FALSE;
955 }
956 if (StrStr(CommandLineWalker, L" 2>a ") != NULL) {
957 Status = EFI_NOT_FOUND;
958 }
959 }
960 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2> ")) != NULL) {
961 FirstLocation = MIN(CommandLineWalker, FirstLocation);
962 SetMem16(CommandLineWalker, 8, L' ');
963 if (StdErrFileName != NULL) {
964 Status = EFI_INVALID_PARAMETER;
965 } else {
966 StdErrFileName = CommandLineWalker += 4;
967 ErrAppend = FALSE;
968 }
969 if (StrStr(CommandLineWalker, L" 2> ") != NULL) {
970 Status = EFI_NOT_FOUND;
971 }
972 }
973
974 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1> ")) != NULL) {
975 FirstLocation = MIN(CommandLineWalker, FirstLocation);
976 SetMem16(CommandLineWalker, 8, L' ');
977 if (StdOutFileName != NULL) {
978 Status = EFI_INVALID_PARAMETER;
979 } else {
980 StdOutFileName = CommandLineWalker += 4;
981 OutAppend = FALSE;
982 }
983 if (StrStr(CommandLineWalker, L" 1> ") != NULL) {
984 Status = EFI_NOT_FOUND;
985 }
986 }
987
988 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" > ")) != NULL) {
989 FirstLocation = MIN(CommandLineWalker, FirstLocation);
990 SetMem16(CommandLineWalker, 6, L' ');
991 if (StdOutFileName != NULL) {
992 Status = EFI_INVALID_PARAMETER;
993 } else {
994 StdOutFileName = CommandLineWalker += 3;
995 OutAppend = FALSE;
996 }
997 if (StrStr(CommandLineWalker, L" > ") != NULL) {
998 Status = EFI_NOT_FOUND;
999 }
1000 }
1001
1002 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" < ")) != NULL) {
1003 FirstLocation = MIN(CommandLineWalker, FirstLocation);
1004 SetMem16(CommandLineWalker, 6, L' ');
1005 if (StdInFileName != NULL) {
1006 Status = EFI_INVALID_PARAMETER;
1007 } else {
1008 StdInFileName = CommandLineWalker += 3;
1009 }
1010 if (StrStr(CommandLineWalker, L" < ") != NULL) {
1011 Status = EFI_NOT_FOUND;
1012 }
1013 }
1014 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" <a ")) != NULL) {
1015 FirstLocation = MIN(CommandLineWalker, FirstLocation);
1016 SetMem16(CommandLineWalker, 8, L' ');
1017 if (StdInFileName != NULL) {
1018 Status = EFI_INVALID_PARAMETER;
1019 } else {
1020 StdInFileName = CommandLineWalker += 4;
1021 InUnicode = FALSE;
1022 AsciiRedirection = TRUE;
1023 }
1024 if (StrStr(CommandLineWalker, L" <a ") != NULL) {
1025 Status = EFI_NOT_FOUND;
1026 }
1027 }
1028 if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" <v ")) != NULL) {
1029 FirstLocation = MIN(CommandLineWalker, FirstLocation);
1030 SetMem16(CommandLineWalker, 8, L' ');
1031 if (StdInVarName != NULL) {
1032 Status = EFI_INVALID_PARAMETER;
1033 } else {
1034 StdInVarName = CommandLineWalker += 4;
1035 }
1036 if (StrStr(CommandLineWalker, L" <v ") != NULL) {
1037 Status = EFI_NOT_FOUND;
1038 }
1039 }
1040
1041 //
1042 // re-populate the string to support any filenames that were in quotes.
1043 //
1044 StrnCpyS(CommandLineCopy, StrSize(CommandLineCopy)/sizeof(CHAR16), NewCommandLine, StrLen(NewCommandLine));
1045
1046 if (FirstLocation != CommandLineCopy + StrLen(CommandLineCopy)
1047 && ((UINTN)(FirstLocation - CommandLineCopy) < StrLen(NewCommandLine))
1048 ){
1049 *(NewCommandLine + (UINTN)(FirstLocation - CommandLineCopy)) = CHAR_NULL;
1050 }
1051
1052 if (!EFI_ERROR(Status)) {
1053
1054 if (StdErrFileName != NULL) {
1055 if ((StdErrFileName = FixFileName(StdErrFileName)) == NULL) {
1056 Status = EFI_INVALID_PARAMETER;
1057 }
1058 }
1059 if (StdOutFileName != NULL) {
1060 if ((StdOutFileName = FixFileName(StdOutFileName)) == NULL) {
1061 Status = EFI_INVALID_PARAMETER;
1062 }
1063 }
1064 if (StdInFileName != NULL) {
1065 if ((StdInFileName = FixFileName(StdInFileName)) == NULL) {
1066 Status = EFI_INVALID_PARAMETER;
1067 }
1068 }
1069 if (StdErrVarName != NULL) {
1070 if ((StdErrVarName = FixVarName(StdErrVarName)) == NULL) {
1071 Status = EFI_INVALID_PARAMETER;
1072 }
1073 }
1074 if (StdOutVarName != NULL) {
1075 if ((StdOutVarName = FixVarName(StdOutVarName)) == NULL) {
1076 Status = EFI_INVALID_PARAMETER;
1077 }
1078 }
1079 if (StdInVarName != NULL) {
1080 if ((StdInVarName = FixVarName(StdInVarName)) == NULL) {
1081 Status = EFI_INVALID_PARAMETER;
1082 }
1083 }
1084
1085 //
1086 // Verify not the same and not duplicating something from a split
1087 //
1088 if (
1089 //
1090 // Check that no 2 filenames are the same
1091 //
1092 (StdErrFileName != NULL && StdOutFileName!= NULL && StringNoCaseCompare(&StdErrFileName, &StdOutFileName) == 0)
1093 ||(StdErrFileName != NULL && StdInFileName != NULL && StringNoCaseCompare(&StdErrFileName, &StdInFileName ) == 0)
1094 ||(StdOutFileName != NULL && StdInFileName != NULL && StringNoCaseCompare(&StdOutFileName, &StdInFileName ) == 0)
1095 //
1096 // Check that no 2 variable names are the same
1097 //
1098 ||(StdErrVarName != NULL && StdInVarName != NULL && StringNoCaseCompare(&StdErrVarName , &StdInVarName ) == 0)
1099 ||(StdOutVarName != NULL && StdInVarName != NULL && StringNoCaseCompare(&StdOutVarName , &StdInVarName ) == 0)
1100 ||(StdErrVarName != NULL && StdOutVarName != NULL && StringNoCaseCompare(&StdErrVarName , &StdOutVarName ) == 0)
1101 //
1102 // When a split (using | operator) is in place some are not allowed
1103 //
1104 ||(Split != NULL && Split->SplitStdIn != NULL && (StdInVarName != NULL || StdInFileName != NULL))
1105 ||(Split != NULL && Split->SplitStdOut != NULL && (StdOutVarName != NULL || StdOutFileName != NULL))
1106 //
1107 // Check that nothing is trying to be output to 2 locations.
1108 //
1109 ||(StdErrFileName != NULL && StdErrVarName != NULL)
1110 ||(StdOutFileName != NULL && StdOutVarName != NULL)
1111 ||(StdInFileName != NULL && StdInVarName != NULL)
1112 //
1113 // Check for no volatile environment variables
1114 //
1115 ||(StdErrVarName != NULL && !EFI_ERROR (IsVolatileEnv (StdErrVarName, &Volatile)) && !Volatile)
1116 ||(StdOutVarName != NULL && !EFI_ERROR (IsVolatileEnv (StdOutVarName, &Volatile)) && !Volatile)
1117 //
1118 // Cant redirect during a reconnect operation.
1119 //
1120 ||(StrStr(NewCommandLine, L"connect -r") != NULL
1121 && (StdOutVarName != NULL || StdOutFileName != NULL || StdErrFileName != NULL || StdErrVarName != NULL))
1122 //
1123 // Check that filetypes (Unicode/Ascii) do not change during an append
1124 //
1125 ||(StdOutFileName != NULL && OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && EFI_ERROR(IsUnicodeFile(StdOutFileName))))
1126 ||(StdErrFileName != NULL && ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && EFI_ERROR(IsUnicodeFile(StdErrFileName))))
1127 ||(StdOutFileName != NULL && !OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && !EFI_ERROR(IsUnicodeFile(StdOutFileName))))
1128 ||(StdErrFileName != NULL && !ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && !EFI_ERROR(IsUnicodeFile(StdErrFileName))))
1129 ){
1130 Status = EFI_INVALID_PARAMETER;
1131 ShellParameters->StdIn = *OldStdIn;
1132 ShellParameters->StdOut = *OldStdOut;
1133 ShellParameters->StdErr = *OldStdErr;
1134 } else if (!EFI_ERROR(Status)){
1135 //
1136 // Open the Std<Whatever> and we should not have conflicts here...
1137 //
1138
1139 //
1140 // StdErr to a file
1141 //
1142 if (StdErrFileName != NULL) {
1143 if (!ErrAppend) {
1144 //
1145 // delete existing file.
1146 //
1147 ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdErrFileName);
1148 }
1149 Status = ShellOpenFileByName(StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0);
1150 if (!ErrAppend && ErrUnicode && !EFI_ERROR(Status)) {
1151 Status = WriteFileTag (TempHandle);
1152 }
1153 if (!ErrUnicode && !EFI_ERROR(Status)) {
1154 TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
1155 ASSERT(TempHandle != NULL);
1156 }
1157 if (!EFI_ERROR(Status)) {
1158 ShellParameters->StdErr = TempHandle;
1159 gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr);
1160 }
1161 }
1162
1163 //
1164 // StdOut to a file
1165 //
1166 if (!EFI_ERROR(Status) && StdOutFileName != NULL) {
1167 if (!OutAppend) {
1168 //
1169 // delete existing file.
1170 //
1171 ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdOutFileName);
1172 }
1173 Status = ShellOpenFileByName(StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0);
1174 if (TempHandle == NULL) {
1175 Status = EFI_INVALID_PARAMETER;
1176 } else {
1177 if (StrStr(StdOutFileName, L"NUL")==StdOutFileName) {
1178 //no-op
1179 } else if (!OutAppend && OutUnicode && !EFI_ERROR(Status)) {
1180 Status = WriteFileTag (TempHandle);
1181 } else if (OutAppend) {
1182 Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize(TempHandle, &FileSize);
1183 if (!EFI_ERROR(Status)) {
1184 //
1185 // When appending to a new unicode file, write the file tag.
1186 // Otherwise (ie. when appending to a new ASCII file, or an
1187 // existent file with any encoding), just seek to the end.
1188 //
1189 Status = (FileSize == 0 && OutUnicode) ?
1190 WriteFileTag (TempHandle) :
1191 ShellInfoObject.NewEfiShellProtocol->SetFilePosition (
1192 TempHandle,
1193 FileSize);
1194 }
1195 }
1196 if (!OutUnicode && !EFI_ERROR(Status)) {
1197 TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
1198 ASSERT(TempHandle != NULL);
1199 }
1200 if (!EFI_ERROR(Status)) {
1201 ShellParameters->StdOut = TempHandle;
1202 gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
1203 }
1204 }
1205 }
1206
1207 //
1208 // StdOut to a var
1209 //
1210 if (!EFI_ERROR(Status) && StdOutVarName != NULL) {
1211 if (!OutAppend) {
1212 //
1213 // delete existing variable.
1214 //
1215 SHELL_SET_ENVIRONMENT_VARIABLE_V(StdOutVarName, 0, L"");
1216 }
1217 TempHandle = CreateFileInterfaceEnv(StdOutVarName);
1218 ASSERT(TempHandle != NULL);
1219 ShellParameters->StdOut = TempHandle;
1220 gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
1221 }
1222
1223 //
1224 // StdErr to a var
1225 //
1226 if (!EFI_ERROR(Status) && StdErrVarName != NULL) {
1227 if (!ErrAppend) {
1228 //
1229 // delete existing variable.
1230 //
1231 SHELL_SET_ENVIRONMENT_VARIABLE_V(StdErrVarName, 0, L"");
1232 }
1233 TempHandle = CreateFileInterfaceEnv(StdErrVarName);
1234 ASSERT(TempHandle != NULL);
1235 ShellParameters->StdErr = TempHandle;
1236 gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr);
1237 }
1238
1239 //
1240 // StdIn from a var
1241 //
1242 if (!EFI_ERROR(Status) && StdInVarName != NULL) {
1243 TempHandle = CreateFileInterfaceEnv(StdInVarName);
1244 if (TempHandle == NULL) {
1245 Status = EFI_OUT_OF_RESOURCES;
1246 } else {
1247 if (!InUnicode) {
1248 TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
1249 }
1250 Size = 0;
1251 if (TempHandle == NULL || ((EFI_FILE_PROTOCOL*)TempHandle)->Read(TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL) {
1252 Status = EFI_INVALID_PARAMETER;
1253 } else {
1254 ShellParameters->StdIn = TempHandle;
1255 gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle);
1256 }
1257 }
1258 }
1259
1260 //
1261 // StdIn from a file
1262 //
1263 if (!EFI_ERROR(Status) && StdInFileName != NULL) {
1264 Status = ShellOpenFileByName(
1265 StdInFileName,
1266 &TempHandle,
1267 EFI_FILE_MODE_READ,
1268 0);
1269 if (!EFI_ERROR(Status)) {
1270 if (!InUnicode) {
1271 //
1272 // Create the ASCII->Unicode conversion layer
1273 //
1274 TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
1275 }
1276 ShellParameters->StdIn = TempHandle;
1277 gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle);
1278 }
1279 }
1280 }
1281 }
1282 FreePool(CommandLineCopy);
1283
1284 CalculateEfiHdrCrc(&gST->Hdr);
1285
1286 if (gST->ConIn == NULL ||gST->ConOut == NULL) {
1287 Status = EFI_OUT_OF_RESOURCES;
1288 }
1289
1290 if (Status == EFI_NOT_FOUND) {
1291 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle);
1292 } else if (EFI_ERROR(Status)) {
1293 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);
1294 }
1295
1296 return (Status);
1297 }
1298
1299 /**
1300 Funcion will replace the current StdIn and StdOut in the ShellParameters protocol
1301 structure with StdIn and StdOut. The current values are de-allocated.
1302
1303 @param[in, out] ShellParameters Pointer to parameter structure to modify.
1304 @param[in] OldStdIn Pointer to old StdIn.
1305 @param[in] OldStdOut Pointer to old StdOut.
1306 @param[in] OldStdErr Pointer to old StdErr.
1307 @param[in] SystemTableInfo Pointer to old system table information.
1308 **/
1309 EFI_STATUS
1310 EFIAPI
1311 RestoreStdInStdOutStdErr (
1312 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1313 IN SHELL_FILE_HANDLE *OldStdIn,
1314 IN SHELL_FILE_HANDLE *OldStdOut,
1315 IN SHELL_FILE_HANDLE *OldStdErr,
1316 IN SYSTEM_TABLE_INFO *SystemTableInfo
1317 )
1318 {
1319 SPLIT_LIST *Split;
1320
1321 if (ShellParameters == NULL
1322 ||OldStdIn == NULL
1323 ||OldStdOut == NULL
1324 ||OldStdErr == NULL
1325 ||SystemTableInfo == NULL) {
1326 return (EFI_INVALID_PARAMETER);
1327 }
1328 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {
1329 Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);
1330 } else {
1331 Split = NULL;
1332 }
1333 if (ShellParameters->StdIn != *OldStdIn) {
1334 if ((Split != NULL && Split->SplitStdIn != ShellParameters->StdIn) || Split == NULL) {
1335 gEfiShellProtocol->CloseFile(ShellParameters->StdIn);
1336 }
1337 ShellParameters->StdIn = *OldStdIn;
1338 }
1339 if (ShellParameters->StdOut != *OldStdOut) {
1340 if ((Split != NULL && Split->SplitStdOut != ShellParameters->StdOut) || Split == NULL) {
1341 gEfiShellProtocol->CloseFile(ShellParameters->StdOut);
1342 }
1343 ShellParameters->StdOut = *OldStdOut;
1344 }
1345 if (ShellParameters->StdErr != *OldStdErr) {
1346 gEfiShellProtocol->CloseFile(ShellParameters->StdErr);
1347 ShellParameters->StdErr = *OldStdErr;
1348 }
1349
1350 if (gST->ConIn != SystemTableInfo->ConIn) {
1351 CloseSimpleTextInOnFile(gST->ConIn);
1352 gST->ConIn = SystemTableInfo->ConIn;
1353 gST->ConsoleInHandle = SystemTableInfo->ConInHandle;
1354 }
1355 if (gST->ConOut != SystemTableInfo->ConOut) {
1356 CloseSimpleTextOutOnFile(gST->ConOut);
1357 gST->ConOut = SystemTableInfo->ConOut;
1358 gST->ConsoleOutHandle = SystemTableInfo->ConOutHandle;
1359 }
1360 if (gST->StdErr != SystemTableInfo->ErrOut) {
1361 CloseSimpleTextOutOnFile(gST->StdErr);
1362 gST->StdErr = SystemTableInfo->ErrOut;
1363 gST->StandardErrorHandle = SystemTableInfo->ErrOutHandle;
1364 }
1365
1366 CalculateEfiHdrCrc(&gST->Hdr);
1367
1368 return (EFI_SUCCESS);
1369 }
1370 /**
1371 Funcion will replace the current Argc and Argv in the ShellParameters protocol
1372 structure by parsing NewCommandLine. The current values are returned to the
1373 user.
1374
1375 If OldArgv or OldArgc is NULL then that value is not returned.
1376
1377 @param[in, out] ShellParameters Pointer to parameter structure to modify.
1378 @param[in] NewCommandLine The new command line to parse and use.
1379 @param[in] Type The type of operation.
1380 @param[out] OldArgv Pointer to old list of parameters.
1381 @param[out] OldArgc Pointer to old number of items in Argv list.
1382
1383 @retval EFI_SUCCESS Operation was sucessful, Argv and Argc are valid.
1384 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1385 **/
1386 EFI_STATUS
1387 EFIAPI
1388 UpdateArgcArgv(
1389 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1390 IN CONST CHAR16 *NewCommandLine,
1391 IN SHELL_OPERATION_TYPES Type,
1392 OUT CHAR16 ***OldArgv OPTIONAL,
1393 OUT UINTN *OldArgc OPTIONAL
1394 )
1395 {
1396 BOOLEAN StripParamQuotation;
1397
1398 ASSERT(ShellParameters != NULL);
1399 StripParamQuotation = TRUE;
1400
1401 if (OldArgc != NULL) {
1402 *OldArgc = ShellParameters->Argc;
1403 }
1404 if (OldArgc != NULL) {
1405 *OldArgv = ShellParameters->Argv;
1406 }
1407
1408 if (Type == Script_File_Name) {
1409 StripParamQuotation = FALSE;
1410 }
1411
1412 return ParseCommandLineToArgs( NewCommandLine,
1413 StripParamQuotation,
1414 &(ShellParameters->Argv),
1415 &(ShellParameters->Argc)
1416 );
1417 }
1418
1419 /**
1420 Funcion will replace the current Argc and Argv in the ShellParameters protocol
1421 structure with Argv and Argc. The current values are de-allocated and the
1422 OldArgv must not be deallocated by the caller.
1423
1424 @param[in, out] ShellParameters pointer to parameter structure to modify
1425 @param[in] OldArgv pointer to old list of parameters
1426 @param[in] OldArgc pointer to old number of items in Argv list
1427 **/
1428 VOID
1429 EFIAPI
1430 RestoreArgcArgv(
1431 IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
1432 IN CHAR16 ***OldArgv,
1433 IN UINTN *OldArgc
1434 )
1435 {
1436 UINTN LoopCounter;
1437 ASSERT(ShellParameters != NULL);
1438 ASSERT(OldArgv != NULL);
1439 ASSERT(OldArgc != NULL);
1440
1441 if (ShellParameters->Argv != NULL) {
1442 for ( LoopCounter = 0
1443 ; LoopCounter < ShellParameters->Argc
1444 ; LoopCounter++
1445 ){
1446 FreePool(ShellParameters->Argv[LoopCounter]);
1447 }
1448 FreePool(ShellParameters->Argv);
1449 }
1450 ShellParameters->Argv = *OldArgv;
1451 *OldArgv = NULL;
1452 ShellParameters->Argc = *OldArgc;
1453 *OldArgc = 0;
1454 }