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