]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ShellParametersProtocol.c
8d76fb4be7ff0910d333b1814ed471a9e23099f1
[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 (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 - 2017, 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*
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 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
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
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
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
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
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
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*
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*
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
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
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
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 - (UINTN)CommandLineCopy)/sizeof(CHAR16) < StrLen(NewCommandLine))
1038 ){
1039 *(NewCommandLine + ((UINTN)FirstLocation - (UINTN)CommandLineCopy)/sizeof(CHAR16)) = 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
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
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
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 }