From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Application/Shell/ShellParametersProtocol.c | 1414 ++++++++++++++++++++ 1 file changed, 1414 insertions(+) create mode 100644 roms/edk2/ShellPkg/Application/Shell/ShellParametersProtocol.c (limited to 'roms/edk2/ShellPkg/Application/Shell/ShellParametersProtocol.c') diff --git a/roms/edk2/ShellPkg/Application/Shell/ShellParametersProtocol.c b/roms/edk2/ShellPkg/Application/Shell/ShellParametersProtocol.c new file mode 100644 index 000000000..7e0c8ce42 --- /dev/null +++ b/roms/edk2/ShellPkg/Application/Shell/ShellParametersProtocol.c @@ -0,0 +1,1414 @@ +/** @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
+ Copyright (C) 2014, Red Hat, Inc. + (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ 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); + 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; + + 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" 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 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); + ASSERT(TempHandle != NULL); + } + 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); + ASSERT(TempHandle != NULL); + } + 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); + ASSERT(TempHandle != NULL); + 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); + ASSERT(TempHandle != NULL); + 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); + } + 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) { + ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle); + } else if (EFI_ERROR(Status)) { + ShellPrintHiiEx(-1, -1, NULL, 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 (OldArgc != 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; +} -- cgit