| /** @file | |
| Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation, | |
| manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL. | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
| Copyright (C) 2014, Red Hat, Inc. | |
| (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR> | |
| Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "Shell.h" | |
| BOOLEAN AsciiRedirection = FALSE; | |
| /** | |
| Return the next parameter's end from a command line string. | |
| @param[in] String the string to parse | |
| **/ | |
| CONST CHAR16 * | |
| FindEndOfParameter ( | |
| IN CONST CHAR16 *String | |
| ) | |
| { | |
| CONST CHAR16 *First; | |
| CONST CHAR16 *CloseQuote; | |
| First = FindFirstCharacter (String, L" \"", L'^'); | |
| // | |
| // nothing, all one parameter remaining | |
| // | |
| if (*First == CHAR_NULL) { | |
| return (First); | |
| } | |
| // | |
| // If space before a quote (or neither found, i.e. both CHAR_NULL), | |
| // then that's the end. | |
| // | |
| if (*First == L' ') { | |
| return (First); | |
| } | |
| CloseQuote = FindFirstCharacter (First+1, L"\"", L'^'); | |
| // | |
| // We did not find a terminator... | |
| // | |
| if (*CloseQuote == CHAR_NULL) { | |
| return (NULL); | |
| } | |
| return (FindEndOfParameter (CloseQuote+1)); | |
| } | |
| /** | |
| Return the next parameter from a command line string. | |
| This function moves the next parameter from Walker into TempParameter and moves | |
| Walker up past that parameter for recursive calling. When the final parameter | |
| is moved *Walker will be set to NULL; | |
| Temp Parameter must be large enough to hold the parameter before calling this | |
| function. | |
| This will also remove all remaining ^ characters after processing. | |
| @param[in, out] Walker pointer to string of command line. Adjusted to | |
| remaining command line on return | |
| @param[in, out] TempParameter pointer to string of command line item extracted. | |
| @param[in] Length buffer size of TempParameter. | |
| @param[in] StripQuotation if TRUE then strip the quotation marks surrounding | |
| the parameters. | |
| @return EFI_INVALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string. | |
| @return EFI_NOT_FOUND A closing " could not be found on the specified string | |
| **/ | |
| EFI_STATUS | |
| GetNextParameter ( | |
| IN OUT CHAR16 **Walker, | |
| IN OUT CHAR16 **TempParameter, | |
| IN CONST UINTN Length, | |
| IN BOOLEAN StripQuotation | |
| ) | |
| { | |
| CONST CHAR16 *NextDelim; | |
| if ( (Walker == NULL) | |
| || (*Walker == NULL) | |
| || (TempParameter == NULL) | |
| || (*TempParameter == NULL) | |
| ) | |
| { | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| // | |
| // make sure we dont have any leading spaces | |
| // | |
| while ((*Walker)[0] == L' ') { | |
| (*Walker)++; | |
| } | |
| // | |
| // make sure we still have some params now... | |
| // | |
| if (StrLen (*Walker) == 0) { | |
| DEBUG_CODE_BEGIN (); | |
| *Walker = NULL; | |
| DEBUG_CODE_END (); | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| NextDelim = FindEndOfParameter (*Walker); | |
| if (NextDelim == NULL) { | |
| DEBUG_CODE_BEGIN (); | |
| *Walker = NULL; | |
| DEBUG_CODE_END (); | |
| return (EFI_NOT_FOUND); | |
| } | |
| StrnCpyS (*TempParameter, Length / sizeof (CHAR16), (*Walker), NextDelim - *Walker); | |
| // | |
| // Add a CHAR_NULL if we didn't get one via the copy | |
| // | |
| if (*NextDelim != CHAR_NULL) { | |
| (*TempParameter)[NextDelim - *Walker] = CHAR_NULL; | |
| } | |
| // | |
| // Update Walker for the next iteration through the function | |
| // | |
| *Walker = (CHAR16 *)NextDelim; | |
| // | |
| // Remove any non-escaped quotes in the string | |
| // Remove any remaining escape characters in the string | |
| // | |
| for (NextDelim = FindFirstCharacter (*TempParameter, L"\"^", CHAR_NULL) | |
| ; *NextDelim != CHAR_NULL | |
| ; NextDelim = FindFirstCharacter (NextDelim, L"\"^", CHAR_NULL) | |
| ) | |
| { | |
| if (*NextDelim == L'^') { | |
| // | |
| // eliminate the escape ^ | |
| // | |
| CopyMem ((CHAR16 *)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); | |
| NextDelim++; | |
| } else if (*NextDelim == L'\"') { | |
| // | |
| // eliminate the unescaped quote | |
| // | |
| if (StripQuotation) { | |
| CopyMem ((CHAR16 *)NextDelim, NextDelim + 1, StrSize (NextDelim + 1)); | |
| } else { | |
| NextDelim++; | |
| } | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Function to populate Argc and Argv. | |
| This function parses the CommandLine and divides it into standard C style Argc/Argv | |
| parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL. this supports space | |
| delimited and quote surrounded parameter definition. | |
| All special character processing (alias, environment variable, redirection, | |
| etc... must be complete before calling this API. | |
| @param[in] CommandLine String of command line to parse | |
| @param[in] StripQuotation if TRUE then strip the quotation marks surrounding | |
| the parameters. | |
| @param[in, out] Argv pointer to array of strings; one for each parameter | |
| @param[in, out] Argc pointer to number of strings in Argv array | |
| @return EFI_SUCCESS the operation was successful | |
| @return EFI_INVALID_PARAMETER some parameters are invalid | |
| @return EFI_OUT_OF_RESOURCES a memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| ParseCommandLineToArgs ( | |
| IN CONST CHAR16 *CommandLine, | |
| IN BOOLEAN StripQuotation, | |
| IN OUT CHAR16 ***Argv, | |
| IN OUT UINTN *Argc | |
| ) | |
| { | |
| UINTN Count; | |
| CHAR16 *TempParameter; | |
| CHAR16 *Walker; | |
| CHAR16 *NewParam; | |
| CHAR16 *NewCommandLine; | |
| UINTN Size; | |
| EFI_STATUS Status; | |
| ASSERT (Argc != NULL); | |
| ASSERT (Argv != NULL); | |
| if ((CommandLine == NULL) || (StrLen (CommandLine) == 0)) { | |
| (*Argc) = 0; | |
| (*Argv) = NULL; | |
| return (EFI_SUCCESS); | |
| } | |
| NewCommandLine = AllocateCopyPool (StrSize (CommandLine), CommandLine); | |
| if (NewCommandLine == NULL) { | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| TrimSpaces (&NewCommandLine); | |
| Size = StrSize (NewCommandLine); | |
| TempParameter = AllocateZeroPool (Size); | |
| if (TempParameter == NULL) { | |
| SHELL_FREE_NON_NULL (NewCommandLine); | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| for ( Count = 0, | |
| Walker = (CHAR16 *)NewCommandLine | |
| ; Walker != NULL && *Walker != CHAR_NULL | |
| ; Count++ | |
| ) | |
| { | |
| if (EFI_ERROR (GetNextParameter (&Walker, &TempParameter, Size, TRUE))) { | |
| break; | |
| } | |
| } | |
| // | |
| // lets allocate the pointer array | |
| // | |
| (*Argv) = AllocateZeroPool ((Count)*sizeof (CHAR16 *)); | |
| if (*Argv == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| *Argc = 0; | |
| Walker = (CHAR16 *)NewCommandLine; | |
| while (Walker != NULL && *Walker != CHAR_NULL) { | |
| SetMem16 (TempParameter, Size, CHAR_NULL); | |
| if (EFI_ERROR (GetNextParameter (&Walker, &TempParameter, Size, StripQuotation))) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| NewParam = AllocateCopyPool (StrSize (TempParameter), TempParameter); | |
| if (NewParam == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| ((CHAR16 **)(*Argv))[(*Argc)] = NewParam; | |
| (*Argc)++; | |
| } | |
| ASSERT (Count >= (*Argc)); | |
| Status = EFI_SUCCESS; | |
| Done: | |
| SHELL_FREE_NON_NULL (TempParameter); | |
| SHELL_FREE_NON_NULL (NewCommandLine); | |
| return (Status); | |
| } | |
| /** | |
| creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then | |
| installs it on our handle and if there is an existing version of the protocol | |
| that one is cached for removal later. | |
| @param[in, out] NewShellParameters on a successful return, a pointer to pointer | |
| to the newly installed interface. | |
| @param[in, out] RootShellInstance on a successful return, pointer to boolean. | |
| TRUE if this is the root shell instance. | |
| @retval EFI_SUCCESS the operation completed successfully. | |
| @return other the operation failed. | |
| @sa ReinstallProtocolInterface | |
| @sa InstallProtocolInterface | |
| @sa ParseCommandLineToArgs | |
| **/ | |
| EFI_STATUS | |
| CreatePopulateInstallShellParametersProtocol ( | |
| IN OUT EFI_SHELL_PARAMETERS_PROTOCOL **NewShellParameters, | |
| IN OUT BOOLEAN *RootShellInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; | |
| CHAR16 *FullCommandLine; | |
| UINTN Size; | |
| Size = 0; | |
| FullCommandLine = NULL; | |
| LoadedImage = NULL; | |
| // | |
| // Assert for valid parameters | |
| // | |
| ASSERT (NewShellParameters != NULL); | |
| ASSERT (RootShellInstance != NULL); | |
| // | |
| // See if we have a shell parameters placed on us | |
| // | |
| Status = gBS->OpenProtocol ( | |
| gImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| (VOID **)&ShellInfoObject.OldShellParameters, | |
| gImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| // | |
| // if we don't then we must be the root shell (error is expected) | |
| // | |
| if (EFI_ERROR (Status)) { | |
| *RootShellInstance = TRUE; | |
| } | |
| // | |
| // Allocate the new structure | |
| // | |
| *NewShellParameters = AllocateZeroPool (sizeof (EFI_SHELL_PARAMETERS_PROTOCOL)); | |
| if ((*NewShellParameters) == NULL) { | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| // | |
| // get loaded image protocol | |
| // | |
| Status = gBS->OpenProtocol ( | |
| gImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| (VOID **)&LoadedImage, | |
| gImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Build the full command line | |
| // | |
| Status = SHELL_GET_ENVIRONMENT_VARIABLE (L"ShellOpt", &Size, FullCommandLine); | |
| if (Status == EFI_BUFFER_TOO_SMALL) { | |
| FullCommandLine = AllocateZeroPool (Size + LoadedImage->LoadOptionsSize); | |
| if (FullCommandLine == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = SHELL_GET_ENVIRONMENT_VARIABLE (L"ShellOpt", &Size, FullCommandLine); | |
| } | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // no parameters via environment... ok | |
| // | |
| } else { | |
| if (EFI_ERROR (Status)) { | |
| return (Status); | |
| } | |
| } | |
| if ((Size == 0) && (LoadedImage->LoadOptionsSize != 0)) { | |
| ASSERT (FullCommandLine == NULL); | |
| // | |
| // Now we need to include a NULL terminator in the size. | |
| // | |
| Size = LoadedImage->LoadOptionsSize + sizeof (FullCommandLine[0]); | |
| FullCommandLine = AllocateZeroPool (Size); | |
| } | |
| if (FullCommandLine != NULL) { | |
| CopyMem (FullCommandLine, LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize); | |
| // | |
| // Populate Argc and Argv | |
| // | |
| Status = ParseCommandLineToArgs ( | |
| FullCommandLine, | |
| TRUE, | |
| &(*NewShellParameters)->Argv, | |
| &(*NewShellParameters)->Argc | |
| ); | |
| FreePool (FullCommandLine); | |
| ASSERT_EFI_ERROR (Status); | |
| } else { | |
| (*NewShellParameters)->Argv = NULL; | |
| (*NewShellParameters)->Argc = 0; | |
| } | |
| // | |
| // Populate the 3 faked file systems... | |
| // | |
| if (*RootShellInstance) { | |
| (*NewShellParameters)->StdIn = &FileInterfaceStdIn; | |
| (*NewShellParameters)->StdOut = &FileInterfaceStdOut; | |
| (*NewShellParameters)->StdErr = &FileInterfaceStdErr; | |
| Status = gBS->InstallProtocolInterface ( | |
| &gImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| (VOID *)(*NewShellParameters) | |
| ); | |
| } else { | |
| // | |
| // copy from the existing ones | |
| // | |
| (*NewShellParameters)->StdIn = ShellInfoObject.OldShellParameters->StdIn; | |
| (*NewShellParameters)->StdOut = ShellInfoObject.OldShellParameters->StdOut; | |
| (*NewShellParameters)->StdErr = ShellInfoObject.OldShellParameters->StdErr; | |
| Status = gBS->ReinstallProtocolInterface ( | |
| gImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| (VOID *)ShellInfoObject.OldShellParameters, | |
| (VOID *)(*NewShellParameters) | |
| ); | |
| } | |
| return (Status); | |
| } | |
| /** | |
| frees all memory used by creation and installation of shell parameters protocol | |
| and if there was an old version installed it will restore that one. | |
| @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is | |
| being cleaned up. | |
| @retval EFI_SUCCESS the cleanup was successful | |
| @return other the cleanup failed | |
| @sa ReinstallProtocolInterface | |
| @sa UninstallProtocolInterface | |
| **/ | |
| EFI_STATUS | |
| CleanUpShellParametersProtocol ( | |
| IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *NewShellParameters | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN LoopCounter; | |
| // | |
| // If the old exists we need to restore it | |
| // | |
| if (ShellInfoObject.OldShellParameters != NULL) { | |
| Status = gBS->ReinstallProtocolInterface ( | |
| gImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| (VOID *)NewShellParameters, | |
| (VOID *)ShellInfoObject.OldShellParameters | |
| ); | |
| DEBUG_CODE ( | |
| ShellInfoObject.OldShellParameters = NULL; | |
| ); | |
| } else { | |
| // | |
| // No old one, just uninstall us... | |
| // | |
| Status = gBS->UninstallProtocolInterface ( | |
| gImageHandle, | |
| &gEfiShellParametersProtocolGuid, | |
| (VOID *)NewShellParameters | |
| ); | |
| } | |
| if (NewShellParameters->Argv != NULL) { | |
| for ( LoopCounter = 0 | |
| ; LoopCounter < NewShellParameters->Argc | |
| ; LoopCounter++ | |
| ) | |
| { | |
| FreePool (NewShellParameters->Argv[LoopCounter]); | |
| } | |
| FreePool (NewShellParameters->Argv); | |
| } | |
| FreePool (NewShellParameters); | |
| return (Status); | |
| } | |
| /** | |
| Determine if a file name represents a unicode file. | |
| @param[in] FileName Pointer to the filename to open. | |
| @retval EFI_SUCCESS The file is a unicode file. | |
| @return An error upon failure. | |
| **/ | |
| EFI_STATUS | |
| IsUnicodeFile ( | |
| IN CONST CHAR16 *FileName | |
| ) | |
| { | |
| SHELL_FILE_HANDLE Handle; | |
| EFI_STATUS Status; | |
| UINT64 OriginalFilePosition; | |
| UINTN CharSize; | |
| CHAR16 CharBuffer; | |
| Status = gEfiShellProtocol->OpenFileByName (FileName, &Handle, EFI_FILE_MODE_READ); | |
| if (EFI_ERROR (Status)) { | |
| return (Status); | |
| } | |
| gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition); | |
| gEfiShellProtocol->SetFilePosition (Handle, 0); | |
| CharSize = sizeof (CHAR16); | |
| Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer); | |
| if (EFI_ERROR (Status) || (CharBuffer != gUnicodeFileTag)) { | |
| Status = EFI_BUFFER_TOO_SMALL; | |
| } | |
| gEfiShellProtocol->SetFilePosition (Handle, OriginalFilePosition); | |
| gEfiShellProtocol->CloseFile (Handle); | |
| return (Status); | |
| } | |
| /** | |
| Strips out quotes sections of a string. | |
| All of the characters between quotes is replaced with spaces. | |
| @param[in, out] TheString A pointer to the string to update. | |
| **/ | |
| VOID | |
| StripQuotes ( | |
| IN OUT CHAR16 *TheString | |
| ) | |
| { | |
| BOOLEAN RemoveNow; | |
| for (RemoveNow = FALSE; TheString != NULL && *TheString != CHAR_NULL; TheString++) { | |
| if ((*TheString == L'^') && (*(TheString + 1) == L'\"')) { | |
| TheString++; | |
| } else if (*TheString == L'\"') { | |
| RemoveNow = (BOOLEAN) !RemoveNow; | |
| } else if (RemoveNow) { | |
| *TheString = L' '; | |
| } | |
| } | |
| } | |
| /** | |
| Calculate the 32-bit CRC in a EFI table using the service provided by the | |
| gRuntime service. | |
| @param Hdr Pointer to an EFI standard header | |
| **/ | |
| VOID | |
| CalculateEfiHdrCrc ( | |
| IN OUT EFI_TABLE_HEADER *Hdr | |
| ) | |
| { | |
| UINT32 Crc; | |
| Hdr->CRC32 = 0; | |
| // | |
| // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then | |
| // Crc will come back as zero if we set it to zero here | |
| // | |
| Crc = 0; | |
| gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc); | |
| Hdr->CRC32 = Crc; | |
| } | |
| /** | |
| Fix a string to only have the file name, removing starting at the first space of whatever is quoted. | |
| @param[in] FileName The filename to start with. | |
| @retval NULL FileName was invalid. | |
| @return The modified FileName. | |
| **/ | |
| CHAR16 * | |
| FixFileName ( | |
| IN CHAR16 *FileName | |
| ) | |
| { | |
| CHAR16 *Copy; | |
| CHAR16 *TempLocation; | |
| if (FileName == NULL) { | |
| return (NULL); | |
| } | |
| if (FileName[0] == L'\"') { | |
| Copy = FileName+1; | |
| if ((TempLocation = StrStr (Copy, L"\"")) != NULL) { | |
| TempLocation[0] = CHAR_NULL; | |
| } | |
| } else { | |
| Copy = FileName; | |
| while (Copy[0] == L' ') { | |
| Copy++; | |
| } | |
| if ((TempLocation = StrStr (Copy, L" ")) != NULL) { | |
| TempLocation[0] = CHAR_NULL; | |
| } | |
| } | |
| if (Copy[0] == CHAR_NULL) { | |
| return (NULL); | |
| } | |
| return (Copy); | |
| } | |
| /** | |
| 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 %. | |
| @param[in] FileName The filename to start with. | |
| @retval NULL FileName was invalid. | |
| @return The modified FileName. | |
| **/ | |
| CHAR16 * | |
| FixVarName ( | |
| IN CHAR16 *FileName | |
| ) | |
| { | |
| CHAR16 *Copy; | |
| CHAR16 *TempLocation; | |
| Copy = FileName; | |
| if (FileName[0] == L'%') { | |
| Copy = FileName+1; | |
| if ((TempLocation = StrStr (Copy, L"%")) != NULL) { | |
| TempLocation[0] = CHAR_NULL; | |
| } | |
| } | |
| return (FixFileName (Copy)); | |
| } | |
| /** | |
| Write the unicode file tag to the specified file. | |
| It is the caller's responsibility to ensure that | |
| ShellInfoObject.NewEfiShellProtocol has been initialized before calling this | |
| function. | |
| @param[in] FileHandle The file to write the unicode file tag to. | |
| @return Status code from ShellInfoObject.NewEfiShellProtocol->WriteFile. | |
| **/ | |
| EFI_STATUS | |
| WriteFileTag ( | |
| IN SHELL_FILE_HANDLE FileHandle | |
| ) | |
| { | |
| CHAR16 FileTag; | |
| UINTN Size; | |
| EFI_STATUS Status; | |
| FileTag = gUnicodeFileTag; | |
| Size = sizeof FileTag; | |
| Status = ShellInfoObject.NewEfiShellProtocol->WriteFile ( | |
| FileHandle, | |
| &Size, | |
| &FileTag | |
| ); | |
| ASSERT (EFI_ERROR (Status) || Size == sizeof FileTag); | |
| return Status; | |
| } | |
| /** | |
| Function will replace the current StdIn and StdOut in the ShellParameters protocol | |
| structure by parsing NewCommandLine. The current values are returned to the | |
| user. | |
| This will also update the system table. | |
| @param[in, out] ShellParameters Pointer to parameter structure to modify. | |
| @param[in] NewCommandLine The new command line to parse and use. | |
| @param[out] OldStdIn Pointer to old StdIn. | |
| @param[out] OldStdOut Pointer to old StdOut. | |
| @param[out] OldStdErr Pointer to old StdErr. | |
| @param[out] SystemTableInfo Pointer to old system table information. | |
| @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| 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 | |
| ) | |
| { | |
| CHAR16 *CommandLineCopy; | |
| CHAR16 *CommandLineWalker; | |
| CHAR16 *StdErrFileName; | |
| CHAR16 *StdOutFileName; | |
| CHAR16 *StdInFileName; | |
| CHAR16 *StdInVarName; | |
| CHAR16 *StdOutVarName; | |
| CHAR16 *StdErrVarName; | |
| EFI_STATUS Status; | |
| SHELL_FILE_HANDLE TempHandle; | |
| UINT64 FileSize; | |
| BOOLEAN OutUnicode; | |
| BOOLEAN InUnicode; | |
| BOOLEAN ErrUnicode; | |
| BOOLEAN OutAppend; | |
| BOOLEAN ErrAppend; | |
| UINTN Size; | |
| SPLIT_LIST *Split; | |
| CHAR16 *FirstLocation; | |
| BOOLEAN Volatile; | |
| OutUnicode = TRUE; | |
| InUnicode = TRUE; | |
| AsciiRedirection = FALSE; | |
| ErrUnicode = TRUE; | |
| StdInVarName = NULL; | |
| StdOutVarName = NULL; | |
| StdErrVarName = NULL; | |
| StdErrFileName = NULL; | |
| StdInFileName = NULL; | |
| StdOutFileName = NULL; | |
| ErrAppend = FALSE; | |
| OutAppend = FALSE; | |
| CommandLineCopy = NULL; | |
| FirstLocation = NULL; | |
| TempHandle = NULL; | |
| if ((ShellParameters == NULL) || (SystemTableInfo == NULL) || (OldStdIn == NULL) || (OldStdOut == NULL) || (OldStdErr == NULL)) { | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| SystemTableInfo->ConIn = gST->ConIn; | |
| SystemTableInfo->ConInHandle = gST->ConsoleInHandle; | |
| SystemTableInfo->ConOut = gST->ConOut; | |
| SystemTableInfo->ConOutHandle = gST->ConsoleOutHandle; | |
| SystemTableInfo->ErrOut = gST->StdErr; | |
| SystemTableInfo->ErrOutHandle = gST->StandardErrorHandle; | |
| *OldStdIn = ShellParameters->StdIn; | |
| *OldStdOut = ShellParameters->StdOut; | |
| *OldStdErr = ShellParameters->StdErr; | |
| if (NewCommandLine == NULL) { | |
| return (EFI_SUCCESS); | |
| } | |
| CommandLineCopy = StrnCatGrow (&CommandLineCopy, NULL, NewCommandLine, 0); | |
| if (CommandLineCopy == NULL) { | |
| return (EFI_OUT_OF_RESOURCES); | |
| } | |
| Status = EFI_SUCCESS; | |
| Split = NULL; | |
| FirstLocation = CommandLineCopy + StrLen (CommandLineCopy); | |
| StripQuotes (CommandLineCopy); | |
| if (!IsListEmpty (&ShellInfoObject.SplitList.Link)) { | |
| Split = (SPLIT_LIST *)GetFirstNode (&ShellInfoObject.SplitList.Link); | |
| if ((Split != NULL) && (Split->SplitStdIn != NULL)) { | |
| ShellParameters->StdIn = Split->SplitStdIn; | |
| } | |
| if ((Split != NULL) && (Split->SplitStdOut != NULL)) { | |
| ShellParameters->StdOut = Split->SplitStdOut; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>>v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 12, L' '); | |
| StdErrVarName = CommandLineWalker += 6; | |
| ErrAppend = TRUE; | |
| if (StrStr (CommandLineWalker, L" 2>>v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>>v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 12, L' '); | |
| StdOutVarName = CommandLineWalker += 6; | |
| OutAppend = TRUE; | |
| if (StrStr (CommandLineWalker, L" 1>>v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } else if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >>v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| StdOutVarName = CommandLineWalker += 5; | |
| OutAppend = TRUE; | |
| if (StrStr (CommandLineWalker, L" >>v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } else if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| StdOutVarName = CommandLineWalker += 4; | |
| OutAppend = FALSE; | |
| if (StrStr (CommandLineWalker, L" >v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>>a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 12, L' '); | |
| StdOutFileName = CommandLineWalker += 6; | |
| OutAppend = TRUE; | |
| OutUnicode = FALSE; | |
| if (StrStr (CommandLineWalker, L" 1>>a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>> ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 5; | |
| OutAppend = TRUE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 1>> ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >> ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 4; | |
| OutAppend = TRUE; | |
| } | |
| if (StrStr (CommandLineWalker, L" >> ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >>a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 5; | |
| OutAppend = TRUE; | |
| OutUnicode = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" >>a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 5; | |
| OutAppend = FALSE; | |
| OutUnicode = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 1>a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" >a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 4; | |
| OutAppend = FALSE; | |
| OutUnicode = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" >a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>> ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdErrFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdErrFileName = CommandLineWalker += 5; | |
| ErrAppend = TRUE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 2>> ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdErrVarName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdErrVarName = CommandLineWalker += 5; | |
| ErrAppend = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 2>v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1>v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdOutVarName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutVarName = CommandLineWalker += 5; | |
| OutAppend = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 1>v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2>a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 10, L' '); | |
| if (StdErrFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdErrFileName = CommandLineWalker += 5; | |
| ErrAppend = FALSE; | |
| ErrUnicode = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 2>a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 2> ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdErrFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdErrFileName = CommandLineWalker += 4; | |
| ErrAppend = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 2> ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" 1> ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 4; | |
| OutAppend = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" 1> ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" > ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 6, L' '); | |
| if (StdOutFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdOutFileName = CommandLineWalker += 3; | |
| OutAppend = FALSE; | |
| } | |
| if (StrStr (CommandLineWalker, L" > ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" < ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 6, L' '); | |
| if (StdInFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdInFileName = CommandLineWalker += 3; | |
| } | |
| if (StrStr (CommandLineWalker, L" < ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" <a ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdInFileName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdInFileName = CommandLineWalker += 4; | |
| InUnicode = FALSE; | |
| AsciiRedirection = TRUE; | |
| } | |
| if (StrStr (CommandLineWalker, L" <a ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| if (!EFI_ERROR (Status) && ((CommandLineWalker = StrStr (CommandLineCopy, L" <v ")) != NULL)) { | |
| FirstLocation = MIN (CommandLineWalker, FirstLocation); | |
| SetMem16 (CommandLineWalker, 8, L' '); | |
| if (StdInVarName != NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| StdInVarName = CommandLineWalker += 4; | |
| } | |
| if (StrStr (CommandLineWalker, L" <v ") != NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| // | |
| // re-populate the string to support any filenames that were in quotes. | |
| // | |
| StrnCpyS (CommandLineCopy, StrSize (CommandLineCopy)/sizeof (CHAR16), NewCommandLine, StrLen (NewCommandLine)); | |
| if ( (FirstLocation != CommandLineCopy + StrLen (CommandLineCopy)) | |
| && (((UINTN)FirstLocation - (UINTN)CommandLineCopy)/sizeof (CHAR16) < StrLen (NewCommandLine)) | |
| ) | |
| { | |
| *(NewCommandLine + ((UINTN)FirstLocation - (UINTN)CommandLineCopy)/sizeof (CHAR16)) = CHAR_NULL; | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| if (StdErrFileName != NULL) { | |
| if ((StdErrFileName = FixFileName (StdErrFileName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (StdOutFileName != NULL) { | |
| if ((StdOutFileName = FixFileName (StdOutFileName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (StdInFileName != NULL) { | |
| if ((StdInFileName = FixFileName (StdInFileName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (StdErrVarName != NULL) { | |
| if ((StdErrVarName = FixVarName (StdErrVarName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (StdOutVarName != NULL) { | |
| if ((StdOutVarName = FixVarName (StdOutVarName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| if (StdInVarName != NULL) { | |
| if ((StdInVarName = FixVarName (StdInVarName)) == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // Verify not the same and not duplicating something from a split | |
| // | |
| if ( | |
| // | |
| // Check that no 2 filenames are the same | |
| // | |
| ((StdErrFileName != NULL) && (StdOutFileName != NULL) && (StringNoCaseCompare (&StdErrFileName, &StdOutFileName) == 0)) | |
| || ((StdErrFileName != NULL) && (StdInFileName != NULL) && (StringNoCaseCompare (&StdErrFileName, &StdInFileName) == 0)) | |
| || ((StdOutFileName != NULL) && (StdInFileName != NULL) && (StringNoCaseCompare (&StdOutFileName, &StdInFileName) == 0)) | |
| // | |
| // Check that no 2 variable names are the same | |
| // | |
| || ((StdErrVarName != NULL) && (StdInVarName != NULL) && (StringNoCaseCompare (&StdErrVarName, &StdInVarName) == 0)) | |
| || ((StdOutVarName != NULL) && (StdInVarName != NULL) && (StringNoCaseCompare (&StdOutVarName, &StdInVarName) == 0)) | |
| || ((StdErrVarName != NULL) && (StdOutVarName != NULL) && (StringNoCaseCompare (&StdErrVarName, &StdOutVarName) == 0)) | |
| // | |
| // When a split (using | operator) is in place some are not allowed | |
| // | |
| || ((Split != NULL) && (Split->SplitStdIn != NULL) && ((StdInVarName != NULL) || (StdInFileName != NULL))) | |
| || ((Split != NULL) && (Split->SplitStdOut != NULL) && ((StdOutVarName != NULL) || (StdOutFileName != NULL))) | |
| // | |
| // Check that nothing is trying to be output to 2 locations. | |
| // | |
| || ((StdErrFileName != NULL) && (StdErrVarName != NULL)) | |
| || ((StdOutFileName != NULL) && (StdOutVarName != NULL)) | |
| || ((StdInFileName != NULL) && (StdInVarName != NULL)) | |
| // | |
| // Check for no volatile environment variables | |
| // | |
| || ((StdErrVarName != NULL) && !EFI_ERROR (IsVolatileEnv (StdErrVarName, &Volatile)) && !Volatile) | |
| || ((StdOutVarName != NULL) && !EFI_ERROR (IsVolatileEnv (StdOutVarName, &Volatile)) && !Volatile) | |
| // | |
| // Cant redirect during a reconnect operation. | |
| // | |
| || ( (StrStr (NewCommandLine, L"connect -r") != NULL) | |
| && ((StdOutVarName != NULL) || (StdOutFileName != NULL) || (StdErrFileName != NULL) || (StdErrVarName != NULL))) | |
| // | |
| // Check that filetypes (Unicode/Ascii) do not change during an append | |
| // | |
| || ((StdOutFileName != NULL) && OutUnicode && OutAppend && (!EFI_ERROR (ShellFileExists (StdOutFileName)) && EFI_ERROR (IsUnicodeFile (StdOutFileName)))) | |
| || ((StdErrFileName != NULL) && ErrUnicode && ErrAppend && (!EFI_ERROR (ShellFileExists (StdErrFileName)) && EFI_ERROR (IsUnicodeFile (StdErrFileName)))) | |
| || ((StdOutFileName != NULL) && !OutUnicode && OutAppend && (!EFI_ERROR (ShellFileExists (StdOutFileName)) && !EFI_ERROR (IsUnicodeFile (StdOutFileName)))) | |
| || ((StdErrFileName != NULL) && !ErrUnicode && ErrAppend && (!EFI_ERROR (ShellFileExists (StdErrFileName)) && !EFI_ERROR (IsUnicodeFile (StdErrFileName)))) | |
| ) | |
| { | |
| Status = EFI_INVALID_PARAMETER; | |
| ShellParameters->StdIn = *OldStdIn; | |
| ShellParameters->StdOut = *OldStdOut; | |
| ShellParameters->StdErr = *OldStdErr; | |
| } else if (!EFI_ERROR (Status)) { | |
| // | |
| // Open the Std<Whatever> and we should not have conflicts here... | |
| // | |
| // | |
| // StdErr to a file | |
| // | |
| if (StdErrFileName != NULL) { | |
| if (!ErrAppend) { | |
| // | |
| // delete existing file. | |
| // | |
| ShellInfoObject.NewEfiShellProtocol->DeleteFileByName (StdErrFileName); | |
| } | |
| Status = ShellOpenFileByName (StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, 0); | |
| if (!ErrAppend && ErrUnicode && !EFI_ERROR (Status)) { | |
| Status = WriteFileTag (TempHandle); | |
| } | |
| if (!ErrUnicode && !EFI_ERROR (Status)) { | |
| TempHandle = CreateFileInterfaceFile (TempHandle, FALSE); | |
| if (TempHandle == NULL) { | |
| ASSERT (TempHandle != NULL); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| ShellParameters->StdErr = TempHandle; | |
| gST->StdErr = CreateSimpleTextOutOnFile (TempHandle, &gST->StandardErrorHandle, gST->StdErr); | |
| } | |
| } | |
| // | |
| // StdOut to a file | |
| // | |
| if (!EFI_ERROR (Status) && (StdOutFileName != NULL)) { | |
| if (!OutAppend) { | |
| // | |
| // delete existing file. | |
| // | |
| ShellInfoObject.NewEfiShellProtocol->DeleteFileByName (StdOutFileName); | |
| } | |
| Status = ShellOpenFileByName (StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, 0); | |
| if (TempHandle == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| if (gUnicodeCollation->MetaiMatch (gUnicodeCollation, StdOutFileName, L"NUL")) { | |
| // no-op | |
| } else if (!OutAppend && OutUnicode && !EFI_ERROR (Status)) { | |
| Status = WriteFileTag (TempHandle); | |
| } else if (OutAppend) { | |
| Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize (TempHandle, &FileSize); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // When appending to a new unicode file, write the file tag. | |
| // Otherwise (ie. when appending to a new ASCII file, or an | |
| // existent file with any encoding), just seek to the end. | |
| // | |
| Status = (FileSize == 0 && OutUnicode) ? | |
| WriteFileTag (TempHandle) : | |
| ShellInfoObject.NewEfiShellProtocol->SetFilePosition ( | |
| TempHandle, | |
| FileSize | |
| ); | |
| } | |
| } | |
| if (!OutUnicode && !EFI_ERROR (Status)) { | |
| TempHandle = CreateFileInterfaceFile (TempHandle, FALSE); | |
| if (TempHandle == NULL) { | |
| ASSERT (TempHandle != NULL); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| ShellParameters->StdOut = TempHandle; | |
| gST->ConOut = CreateSimpleTextOutOnFile (TempHandle, &gST->ConsoleOutHandle, gST->ConOut); | |
| } | |
| } | |
| } | |
| // | |
| // StdOut to a var | |
| // | |
| if (!EFI_ERROR (Status) && (StdOutVarName != NULL)) { | |
| if (!OutAppend) { | |
| // | |
| // delete existing variable. | |
| // | |
| SHELL_SET_ENVIRONMENT_VARIABLE_V (StdOutVarName, 0, L""); | |
| } | |
| TempHandle = CreateFileInterfaceEnv (StdOutVarName); | |
| if (TempHandle == NULL) { | |
| ASSERT (TempHandle != NULL); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| ShellParameters->StdOut = TempHandle; | |
| gST->ConOut = CreateSimpleTextOutOnFile (TempHandle, &gST->ConsoleOutHandle, gST->ConOut); | |
| } | |
| } | |
| // | |
| // StdErr to a var | |
| // | |
| if (!EFI_ERROR (Status) && (StdErrVarName != NULL)) { | |
| if (!ErrAppend) { | |
| // | |
| // delete existing variable. | |
| // | |
| SHELL_SET_ENVIRONMENT_VARIABLE_V (StdErrVarName, 0, L""); | |
| } | |
| TempHandle = CreateFileInterfaceEnv (StdErrVarName); | |
| if (TempHandle == NULL) { | |
| ASSERT (TempHandle != NULL); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| ShellParameters->StdErr = TempHandle; | |
| gST->StdErr = CreateSimpleTextOutOnFile (TempHandle, &gST->StandardErrorHandle, gST->StdErr); | |
| } | |
| } | |
| // | |
| // StdIn from a var | |
| // | |
| if (!EFI_ERROR (Status) && (StdInVarName != NULL)) { | |
| TempHandle = CreateFileInterfaceEnv (StdInVarName); | |
| if (TempHandle == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| if (!InUnicode) { | |
| TempHandle = CreateFileInterfaceFile (TempHandle, FALSE); | |
| } | |
| Size = 0; | |
| if ((TempHandle == NULL) || (((EFI_FILE_PROTOCOL *)TempHandle)->Read (TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL)) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } else { | |
| ShellParameters->StdIn = TempHandle; | |
| gST->ConIn = CreateSimpleTextInOnFile (TempHandle, &gST->ConsoleInHandle); | |
| } | |
| } | |
| } | |
| // | |
| // StdIn from a file | |
| // | |
| if (!EFI_ERROR (Status) && (StdInFileName != NULL)) { | |
| Status = ShellOpenFileByName ( | |
| StdInFileName, | |
| &TempHandle, | |
| EFI_FILE_MODE_READ, | |
| 0 | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| if (!InUnicode) { | |
| // | |
| // Create the ASCII->Unicode conversion layer | |
| // | |
| TempHandle = CreateFileInterfaceFile (TempHandle, FALSE); | |
| } | |
| if (TempHandle == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| ShellParameters->StdIn = TempHandle; | |
| gST->ConIn = CreateSimpleTextInOnFile (TempHandle, &gST->ConsoleInHandle); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| FreePool (CommandLineCopy); | |
| CalculateEfiHdrCrc (&gST->Hdr); | |
| if ((gST->ConIn == NULL) || (gST->ConOut == NULL)) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } | |
| if (Status == EFI_NOT_FOUND) { | |
| ShellPrintHiiDefaultEx (STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle); | |
| } else if (EFI_ERROR (Status)) { | |
| ShellPrintHiiDefaultEx (STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle); | |
| } | |
| return (Status); | |
| } | |
| /** | |
| Function will replace the current StdIn and StdOut in the ShellParameters protocol | |
| structure with StdIn and StdOut. The current values are de-allocated. | |
| @param[in, out] ShellParameters Pointer to parameter structure to modify. | |
| @param[in] OldStdIn Pointer to old StdIn. | |
| @param[in] OldStdOut Pointer to old StdOut. | |
| @param[in] OldStdErr Pointer to old StdErr. | |
| @param[in] SystemTableInfo Pointer to old system table information. | |
| **/ | |
| 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 | |
| ) | |
| { | |
| SPLIT_LIST *Split; | |
| if ( (ShellParameters == NULL) | |
| || (OldStdIn == NULL) | |
| || (OldStdOut == NULL) | |
| || (OldStdErr == NULL) | |
| || (SystemTableInfo == NULL)) | |
| { | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| if (!IsListEmpty (&ShellInfoObject.SplitList.Link)) { | |
| Split = (SPLIT_LIST *)GetFirstNode (&ShellInfoObject.SplitList.Link); | |
| } else { | |
| Split = NULL; | |
| } | |
| if (ShellParameters->StdIn != *OldStdIn) { | |
| if (((Split != NULL) && (Split->SplitStdIn != ShellParameters->StdIn)) || (Split == NULL)) { | |
| gEfiShellProtocol->CloseFile (ShellParameters->StdIn); | |
| } | |
| ShellParameters->StdIn = *OldStdIn; | |
| } | |
| if (ShellParameters->StdOut != *OldStdOut) { | |
| if (((Split != NULL) && (Split->SplitStdOut != ShellParameters->StdOut)) || (Split == NULL)) { | |
| gEfiShellProtocol->CloseFile (ShellParameters->StdOut); | |
| } | |
| ShellParameters->StdOut = *OldStdOut; | |
| } | |
| if (ShellParameters->StdErr != *OldStdErr) { | |
| gEfiShellProtocol->CloseFile (ShellParameters->StdErr); | |
| ShellParameters->StdErr = *OldStdErr; | |
| } | |
| if (gST->ConIn != SystemTableInfo->ConIn) { | |
| CloseSimpleTextInOnFile (gST->ConIn); | |
| gST->ConIn = SystemTableInfo->ConIn; | |
| gST->ConsoleInHandle = SystemTableInfo->ConInHandle; | |
| } | |
| if (gST->ConOut != SystemTableInfo->ConOut) { | |
| CloseSimpleTextOutOnFile (gST->ConOut); | |
| gST->ConOut = SystemTableInfo->ConOut; | |
| gST->ConsoleOutHandle = SystemTableInfo->ConOutHandle; | |
| } | |
| if (gST->StdErr != SystemTableInfo->ErrOut) { | |
| CloseSimpleTextOutOnFile (gST->StdErr); | |
| gST->StdErr = SystemTableInfo->ErrOut; | |
| gST->StandardErrorHandle = SystemTableInfo->ErrOutHandle; | |
| } | |
| CalculateEfiHdrCrc (&gST->Hdr); | |
| return (EFI_SUCCESS); | |
| } | |
| /** | |
| Function will replace the current Argc and Argv in the ShellParameters protocol | |
| structure by parsing NewCommandLine. The current values are returned to the | |
| user. | |
| If OldArgv or OldArgc is NULL then that value is not returned. | |
| @param[in, out] ShellParameters Pointer to parameter structure to modify. | |
| @param[in] NewCommandLine The new command line to parse and use. | |
| @param[in] Type The type of operation. | |
| @param[out] OldArgv Pointer to old list of parameters. | |
| @param[out] OldArgc Pointer to old number of items in Argv list. | |
| @retval EFI_SUCCESS Operation was successful, Argv and Argc are valid. | |
| @return EFI_INVALID_PARAMETER Some parameters are invalid. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| 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 | |
| ) | |
| { | |
| BOOLEAN StripParamQuotation; | |
| ASSERT (ShellParameters != NULL); | |
| StripParamQuotation = TRUE; | |
| if (OldArgc != NULL) { | |
| *OldArgc = ShellParameters->Argc; | |
| } | |
| if (OldArgv != NULL) { | |
| *OldArgv = ShellParameters->Argv; | |
| } | |
| if (Type == Script_File_Name) { | |
| StripParamQuotation = FALSE; | |
| } | |
| return ParseCommandLineToArgs ( | |
| NewCommandLine, | |
| StripParamQuotation, | |
| &(ShellParameters->Argv), | |
| &(ShellParameters->Argc) | |
| ); | |
| } | |
| /** | |
| Function will replace the current Argc and Argv in the ShellParameters protocol | |
| structure with Argv and Argc. The current values are de-allocated and the | |
| OldArgv must not be deallocated by the caller. | |
| @param[in, out] ShellParameters pointer to parameter structure to modify | |
| @param[in] OldArgv pointer to old list of parameters | |
| @param[in] OldArgc pointer to old number of items in Argv list | |
| **/ | |
| VOID | |
| RestoreArgcArgv ( | |
| IN OUT EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters, | |
| IN CHAR16 ***OldArgv, | |
| IN UINTN *OldArgc | |
| ) | |
| { | |
| UINTN LoopCounter; | |
| ASSERT (ShellParameters != NULL); | |
| ASSERT (OldArgv != NULL); | |
| ASSERT (OldArgc != NULL); | |
| if (ShellParameters->Argv != NULL) { | |
| for ( LoopCounter = 0 | |
| ; LoopCounter < ShellParameters->Argc | |
| ; LoopCounter++ | |
| ) | |
| { | |
| FreePool (ShellParameters->Argv[LoopCounter]); | |
| } | |
| FreePool (ShellParameters->Argv); | |
| } | |
| ShellParameters->Argv = *OldArgv; | |
| *OldArgv = NULL; | |
| ShellParameters->Argc = *OldArgc; | |
| *OldArgc = 0; | |
| } |