X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ShellPkg%2FApplication%2FShell%2FShell.c;h=ec344137d355e2dad689bc54f71c3839a896d7f5;hp=dfcbfb89645373e50913eb6d0a6082898293ba66;hb=d3912eb99e88fa1d797e06881fc6589eae831859;hpb=6ca29fa310d49dd0b224357de7990fd775b61d18 diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c index dfcbfb8964..ec344137d3 100644 --- a/ShellPkg/Application/Shell/Shell.c +++ b/ShellPkg/Application/Shell/Shell.c @@ -1,8 +1,9 @@ /** @file This is THE shell (application) - Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
(C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
+ Copyright 2015-2018 Dell Technologies.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -104,7 +105,7 @@ TrimSpaces( } /** - Parse for the next instance of one string within another string. Can optionally make sure that + Parse for the next instance of one string within another string. Can optionally make sure that the string was not escaped (^ character) per the shell specification. @param[in] SourceString The string to search within @@ -160,13 +161,13 @@ IsValidEnvironmentVariableName( ) { CONST CHAR16 *Walker; - + Walker = NULL; ASSERT (BeginPercent != NULL); ASSERT (EndPercent != NULL); ASSERT (BeginPercent < EndPercent); - + if ((BeginPercent + 1) == EndPercent) { return FALSE; } @@ -212,9 +213,9 @@ ContainsSplit( SecondQuote = NULL; TempSpot = FindFirstCharacter(CmdLine, L"|", L'^'); - if (FirstQuote == NULL || - TempSpot == NULL || - TempSpot == CHAR_NULL || + if (FirstQuote == NULL || + TempSpot == NULL || + TempSpot == CHAR_NULL || FirstQuote > TempSpot ) { return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)); @@ -223,7 +224,7 @@ ContainsSplit( while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) { if (FirstQuote == NULL || FirstQuote > TempSpot) { break; - } + } SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE); if (SecondQuote == NULL) { break; @@ -235,14 +236,14 @@ ContainsSplit( FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE); TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^'); continue; - } + } } - + return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)); } /** - Function to start monitoring for CTRL-S using SimpleTextInputEx. This + Function to start monitoring for CTRL-S using SimpleTextInputEx. This feature's enabled state was not known when the shell initially launched. @retval EFI_SUCCESS The feature is enabled. @@ -266,8 +267,8 @@ InternalEfiShellStartCtrlSMonitor( EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { ShellPrintHiiEx( - -1, - -1, + -1, + -1, NULL, STRING_TOKEN (STR_SHELL_NO_IN_EX), ShellInfoObject.HiiHandle); @@ -284,7 +285,7 @@ InternalEfiShellStartCtrlSMonitor( &KeyData, NotificationFunction, &ShellInfoObject.CtrlSNotifyHandle1); - + KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; if (!EFI_ERROR(Status)) { Status = SimpleEx->RegisterKeyNotify( @@ -302,7 +303,7 @@ InternalEfiShellStartCtrlSMonitor( &KeyData, NotificationFunction, &ShellInfoObject.CtrlSNotifyHandle3); - } + } KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED; if (!EFI_ERROR(Status)) { Status = SimpleEx->RegisterKeyNotify( @@ -620,11 +621,6 @@ UefiMain ( ShellInfoObject.ConsoleInfo->Enabled = TRUE; ShellInfoObject.ConsoleInfo->RowCounter = 0; - // - // Reset the CTRL-C event (yes we ignore the return values) - // - Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); - // // Display Prompt // @@ -726,6 +722,7 @@ FreeResources: **/ EFI_STATUS SetBuiltInAlias( + VOID ) { EFI_STATUS Status; @@ -1005,7 +1002,11 @@ ProcessCommandLine( ) == 0) { ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = TRUE; // Check for optional delay value following "-delay" - DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1]; + if ((LoopVar + 1) >= gEfiShellParametersProtocol->Argc) { + DelayValueStr = NULL; + } else { + DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1]; + } if (DelayValueStr != NULL){ if (*DelayValueStr == L':') { DelayValueStr++; @@ -1133,11 +1134,11 @@ ProcessCommandLine( /** Function try to find location of the Startup.nsh file. - + The buffer is callee allocated and should be freed by the caller. - @param ImagePath The path to the image for shell. first place to look for the startup script - @param FilePath The path to the file for shell. second place to look for the startup script. + @param ImageDevicePath The path to the image for shell. first place to look for the startup script + @param FileDevicePath The path to the file for shell. second place to look for the startup script. @retval NULL No Startup.nsh file was found. @return !=NULL Pointer to NULL-terminated path. @@ -1160,13 +1161,21 @@ LocateStartupScript ( // Try to find 'Startup.nsh' in the directory where the shell itself was launched. // MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath (&ImageDevicePath); - if (MapName != NULL) { + if (MapName != NULL) { StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0); + if (StartupScriptPath == NULL) { + // + // Do not locate the startup script in sys path when out of resource. + // + return NULL; + } TempSpot = StrStr (StartupScriptPath, L";"); if (TempSpot != NULL) { *TempSpot = CHAR_NULL; } + InternalEfiShellSetEnv(L"homefilesystem", StartupScriptPath, TRUE); + StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0); PathRemoveLastItem (StartupScriptPath); StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0); @@ -1204,6 +1213,7 @@ DoStartupScript( UINTN Delay; EFI_INPUT_KEY Key; CHAR16 *FileStringPath; + CHAR16 *FullFileStringPath; UINTN NewSize; Key.UnicodeChar = CHAR_NULL; @@ -1271,8 +1281,19 @@ DoStartupScript( FileStringPath = LocateStartupScript (ImagePath, FilePath); if (FileStringPath != NULL) { - Status = RunScriptFile (FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol); + FullFileStringPath = FullyQualifyPath(FileStringPath); + if (FullFileStringPath == NULL) { + Status = RunScriptFile (FileStringPath, NULL, FileStringPath, ShellInfoObject.NewShellParametersProtocol); + } else { + Status = RunScriptFile (FullFileStringPath, NULL, FullFileStringPath, ShellInfoObject.NewShellParametersProtocol); + FreePool(FullFileStringPath); + } FreePool (FileStringPath); + } else { + // + // we return success since startup script is not mandatory. + // + Status = EFI_SUCCESS; } return (Status); @@ -1334,9 +1355,14 @@ DoShellPrompt ( // Null terminate the string and parse it // if (!EFI_ERROR (Status)) { + // + // Reset the CTRL-C event just before running the command (yes we ignore the return values) + // + Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak); + CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL; Status = RunCommand(CmdLine); - } + } // // Done with this command @@ -1375,7 +1401,7 @@ AddBufferToFreeList ( /** - Create a new buffer list and stores the old one to OldBufferList + Create a new buffer list and stores the old one to OldBufferList @param OldBufferList The temporary list head used to store the nodes in BufferToFreeList. **/ @@ -1420,7 +1446,7 @@ AddLineToCommandHistory( Count = 0; MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount); - + if (MaxHistoryCmdCount == 0) { return ; } @@ -1534,7 +1560,7 @@ StripUnreplacedEnvironmentVariables( } continue; } - + if (FirstQuote == NULL || SecondPercent < FirstQuote) { if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) { // @@ -1635,7 +1661,7 @@ ShellConvertVariables ( // // now do the replacements... // - NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine); + NewCommandLine1 = AllocateZeroPool (NewSize); NewCommandLine2 = AllocateZeroPool(NewSize); ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16))); if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) { @@ -1644,20 +1670,22 @@ ShellConvertVariables ( SHELL_FREE_NON_NULL(ItemTemp); return (NULL); } + CopyMem (NewCommandLine1, OriginalCommandLine, StrSize (OriginalCommandLine)); + for (MasterEnvList = EfiShellGetEnv(NULL) ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL ; MasterEnvList += StrLen(MasterEnvList) + 1 ){ - StrCpyS( ItemTemp, - ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + StrCpyS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), L"%" ); - StrCatS( ItemTemp, - ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + StrCatS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), MasterEnvList ); - StrCatS( ItemTemp, - ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), + StrCatS( ItemTemp, + ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), L"%" ); ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE); @@ -1683,7 +1711,7 @@ ShellConvertVariables ( // ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE); StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2); - + FreePool(NewCommandLine2); FreePool(ItemTemp); @@ -1703,8 +1731,8 @@ ShellConvertVariables ( EFI_STATUS RunSplitCommand( IN CONST CHAR16 *CmdLine, - IN SHELL_FILE_HANDLE *StdIn, - IN SHELL_FILE_HANDLE *StdOut + IN SHELL_FILE_HANDLE StdIn, + IN SHELL_FILE_HANDLE StdOut ) { EFI_STATUS Status; @@ -1713,7 +1741,7 @@ RunSplitCommand( UINTN Size1; UINTN Size2; SPLIT_LIST *Split; - SHELL_FILE_HANDLE *TempFileHandle; + SHELL_FILE_HANDLE TempFileHandle; BOOLEAN Unicode; ASSERT(StdOut == NULL); @@ -1779,7 +1807,7 @@ RunSplitCommand( Split->SplitStdOut = Split->SplitStdIn; } Split->SplitStdIn = TempFileHandle; - ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0); + ShellInfoObject.NewEfiShellProtocol->SetFilePosition (Split->SplitStdIn, 0); if (!EFI_ERROR(Status)) { Status = RunCommand(NextCommandLine); @@ -1795,11 +1823,10 @@ RunSplitCommand( // Note that the original StdIn is now the StdOut... // if (Split->SplitStdOut != NULL) { - ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut)); + ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdOut); } if (Split->SplitStdIn != NULL) { - ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn)); - FreePool (Split->SplitStdIn); + ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn); } FreePool(Split); @@ -1810,7 +1837,7 @@ RunSplitCommand( } /** - Take the original command line, substitute any variables, free + Take the original command line, substitute any variables, free the original string, return the modified copy. @param[in] CmdLine pointer to the command line to update. @@ -1834,7 +1861,7 @@ ShellSubstituteVariables( } /** - Take the original command line, substitute any alias in the first group of space delimited characters, free + Take the original command line, substitute any alias in the first group of space delimited characters, free the original string, return the modified copy. @param[in] CmdLine pointer to the command line to update. @@ -1893,7 +1920,7 @@ ShellSubstituteAliases( SHELL_FREE_NON_NULL(*CmdLine); SHELL_FREE_NON_NULL(CommandName); - + // // re-assign the passed in double pointer to point to our newly allocated buffer // @@ -1906,7 +1933,7 @@ ShellSubstituteAliases( Takes the Argv[0] part of the command line and determine the meaning of it. @param[in] CmdName pointer to the command line to update. - + @retval Internal_Command The name is an internal command. @retval File_Sys_Change the name is a file system change. @retval Script_File_Name the name is a NSH script file. @@ -1934,7 +1961,7 @@ GetOperationType( // Test for file system change request. anything ending with first : and cant have spaces. // if (CmdName[(StrLen(CmdName)-1)] == L':') { - if ( StrStr(CmdName, L" ") != NULL + if ( StrStr(CmdName, L" ") != NULL || StrLen(StrStr(CmdName, L":")) > 1 ) { return (Unknown_Invalid); @@ -1964,7 +1991,7 @@ GetOperationType( SHELL_FREE_NON_NULL(FileWithPath); return (Efi_Application); } - + SHELL_FREE_NON_NULL(FileWithPath); // // No clue what this is... return invalid flag... @@ -1981,7 +2008,7 @@ GetOperationType( @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @retval EFI_NOT_FOUND The operation type is unknown or invalid. **/ -EFI_STATUS +EFI_STATUS IsValidSplit( IN CONST CHAR16 *CmdLine ) @@ -2066,13 +2093,13 @@ VerifySplit( // recurse to verify the next item // TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1; - if (*TempSpot == L'a' && + if (*TempSpot == L'a' && (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL) ) { // If it's an ASCII pipe '|a' TempSpot += 1; } - + return (VerifySplit(TempSpot)); } @@ -2136,7 +2163,7 @@ ChangeMappedDrive( // make sure we are the right operation // ASSERT(CmdLine[(StrLen(CmdLine)-1)] == L':' && StrStr(CmdLine, L" ") == NULL); - + // // Call the protocol API to do the work // @@ -2281,7 +2308,7 @@ ProcessCommandLineToFinal( Run an internal shell command. This API will update the shell's environment since these commands are libraries. - + @param[in] CmdLine the command line to run. @param[in] FirstParameter the first parameter on the command line @param[in] ParamProtocol the shell parameters protocol pointer @@ -2304,7 +2331,7 @@ RunInternalCommand( SHELL_STATUS CommandReturnedStatus; BOOLEAN LastError; CHAR16 *Walker; - CHAR16 *NewCmdLine; + CHAR16 *NewCmdLine; NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine); if (NewCmdLine == NULL) { @@ -2414,6 +2441,7 @@ RunCommandOrFile( EFI_STATUS Status; EFI_STATUS StartStatus; CHAR16 *CommandWithPath; + CHAR16 *FullCommandWithPath; EFI_DEVICE_PATH_PROTOCOL *DevPath; SHELL_STATUS CalleeExitStatus; @@ -2459,7 +2487,13 @@ RunCommandOrFile( } switch (Type) { case Script_File_Name: - Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol); + FullCommandWithPath = FullyQualifyPath(CommandWithPath); + if (FullCommandWithPath == NULL) { + Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol); + } else { + Status = RunScriptFile (FullCommandWithPath, NULL, CmdLine, ParamProtocol); + FreePool(FullCommandWithPath); + } break; case Efi_Application: // @@ -2584,7 +2618,7 @@ SetupAndRunCommandOrFile( /** Function will process and run a command line. - This will determine if the command line represents an internal shell + This will determine if the command line represents an internal shell command or dispatch an external application. @param[in] CmdLine The command line to parse. @@ -2604,6 +2638,7 @@ RunShellCommand( CHAR16 *FirstParameter; CHAR16 *TempWalker; SHELL_OPERATION_TYPES Type; + CONST CHAR16 *CurDir; ASSERT(CmdLine != NULL); if (StrLen(CmdLine) == 0) { @@ -2659,7 +2694,7 @@ RunShellCommand( Status = ProcessNewSplitCommandLine(CleanOriginal); SHELL_FREE_NON_NULL(CleanOriginal); return (Status); - } + } // // We need the first parameter information so we can determine the operation type @@ -2695,7 +2730,22 @@ RunShellCommand( ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); SetLastError(SHELL_NOT_FOUND); } - + // + // Check whether the current file system still exists. If not exist, we need update "cwd" and gShellCurMapping. + // + CurDir = EfiShellGetCurDir (NULL); + if (CurDir != NULL) { + if (EFI_ERROR(ShellFileExists (CurDir))) { + // + // EfiShellSetCurDir() cannot set current directory to NULL. + // EfiShellSetEnv() is not allowed to set the "cwd" variable. + // Only InternalEfiShellSetEnv () is allowed setting the "cwd" variable. + // + InternalEfiShellSetEnv (L"cwd", NULL, TRUE); + gShellCurMapping = NULL; + } + } + SHELL_FREE_NON_NULL(CleanOriginal); SHELL_FREE_NON_NULL(FirstParameter); @@ -2705,7 +2755,7 @@ RunShellCommand( /** Function will process and run a command line. - This will determine if the command line represents an internal shell + This will determine if the command line represents an internal shell command or dispatch an external application. @param[in] CmdLine The command line to parse. @@ -2721,38 +2771,6 @@ RunCommand( return (RunShellCommand(CmdLine, NULL)); } - -STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002}; -/** - Function determines if the CommandName COULD be a valid command. It does not determine whether - this is a valid command. It only checks for invalid characters. - - @param[in] CommandName The name to check - - @retval TRUE CommandName could be a command name - @retval FALSE CommandName could not be a valid command name -**/ -BOOLEAN -IsValidCommandName( - IN CONST CHAR16 *CommandName - ) -{ - UINTN Count; - if (CommandName == NULL) { - ASSERT(FALSE); - return (FALSE); - } - for ( Count = 0 - ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0]) - ; Count++ - ){ - if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) { - return (FALSE); - } - } - return (TRUE); -} - /** Function to process a NSH script file via SHELL_FILE_HANDLE. @@ -2813,7 +2831,12 @@ RunScriptFileHandle ( DeleteScriptFileStruct(NewScriptFile); return (EFI_OUT_OF_RESOURCES); } - for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) { + // + // Put the full path of the script file into Argv[0] as required by section + // 3.6.2 of version 2.2 of the shell specification. + // + NewScriptFile->Argv[0] = StrnCatGrow(&NewScriptFile->Argv[0], NULL, NewScriptFile->ScriptName, 0); + for (LoopVar = 1 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) { ASSERT(NewScriptFile->Argv[LoopVar] == NULL); NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0); if (NewScriptFile->Argv[LoopVar] == NULL) { @@ -2878,8 +2901,8 @@ RunScriptFileHandle ( ; // conditional increment in the body of the loop ){ ASSERT(CommandLine2 != NULL); - StrnCpyS( CommandLine2, - PrintBuffSize/sizeof(CHAR16), + StrnCpyS( CommandLine2, + PrintBuffSize/sizeof(CHAR16), NewScriptFile->CurrentCommand->Cl, PrintBuffSize/sizeof(CHAR16) - 1 ); @@ -2905,8 +2928,8 @@ RunScriptFileHandle ( // // Due to variability in starting the find and replace action we need to have both buffers the same. // - StrnCpyS( CommandLine, - PrintBuffSize/sizeof(CHAR16), + StrnCpyS( CommandLine, + PrintBuffSize/sizeof(CHAR16), CommandLine2, PrintBuffSize/sizeof(CHAR16) - 1 ); @@ -2961,8 +2984,8 @@ RunScriptFileHandle ( Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", L"\"\"", FALSE, FALSE); Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", L"\"\"", FALSE, FALSE); - StrnCpyS( CommandLine2, - PrintBuffSize/sizeof(CHAR16), + StrnCpyS( CommandLine2, + PrintBuffSize/sizeof(CHAR16), CommandLine, PrintBuffSize/sizeof(CHAR16) - 1 );