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