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