/** @file\r
This is THE shell (application)\r
\r
- Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>\r
+ Copyright 2015-2018 Dell Technologies.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
}\r
\r
/**\r
- Parse for the next instance of one string within another string. Can optionally make sure that \r
+ Parse for the next instance of one string within another string. Can optionally make sure that\r
the string was not escaped (^ character) per the shell specification.\r
\r
@param[in] SourceString The string to search within\r
)\r
{\r
CONST CHAR16 *Walker;\r
- \r
+\r
Walker = NULL;\r
\r
ASSERT (BeginPercent != NULL);\r
ASSERT (EndPercent != NULL);\r
ASSERT (BeginPercent < EndPercent);\r
- \r
+\r
if ((BeginPercent + 1) == EndPercent) {\r
return FALSE;\r
}\r
SecondQuote = NULL;\r
TempSpot = FindFirstCharacter(CmdLine, L"|", L'^');\r
\r
- if (FirstQuote == NULL || \r
- TempSpot == NULL || \r
- TempSpot == CHAR_NULL || \r
+ if (FirstQuote == NULL ||\r
+ TempSpot == NULL ||\r
+ TempSpot == CHAR_NULL ||\r
FirstQuote > TempSpot\r
) {\r
return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) {\r
if (FirstQuote == NULL || FirstQuote > TempSpot) {\r
break;\r
- } \r
+ }\r
SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE);\r
if (SecondQuote == NULL) {\r
break;\r
FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);\r
TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');\r
continue;\r
- } \r
+ }\r
}\r
- \r
+\r
return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
}\r
\r
/**\r
- Function to start monitoring for CTRL-S using SimpleTextInputEx. This \r
+ Function to start monitoring for CTRL-S using SimpleTextInputEx. This\r
feature's enabled state was not known when the shell initially launched.\r
\r
@retval EFI_SUCCESS The feature is enabled.\r
EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
if (EFI_ERROR(Status)) {\r
ShellPrintHiiEx(\r
- -1, \r
- -1, \r
+ -1,\r
+ -1,\r
NULL,\r
STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
ShellInfoObject.HiiHandle);\r
&KeyData,\r
NotificationFunction,\r
&ShellInfoObject.CtrlSNotifyHandle1);\r
- \r
+\r
KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
if (!EFI_ERROR(Status)) {\r
Status = SimpleEx->RegisterKeyNotify(\r
&KeyData,\r
NotificationFunction,\r
&ShellInfoObject.CtrlSNotifyHandle3);\r
- } \r
+ }\r
KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
if (!EFI_ERROR(Status)) {\r
Status = SimpleEx->RegisterKeyNotify(\r
ShellInfoObject.ConsoleInfo->Enabled = TRUE;\r
ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
\r
- //\r
- // Reset the CTRL-C event (yes we ignore the return values)\r
- //\r
- Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
-\r
//\r
// Display Prompt\r
//\r
**/\r
EFI_STATUS\r
SetBuiltInAlias(\r
+ VOID\r
)\r
{\r
EFI_STATUS Status;\r
) == 0) {\r
ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = TRUE;\r
// Check for optional delay value following "-delay"\r
- DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+ if ((LoopVar + 1) >= gEfiShellParametersProtocol->Argc) {\r
+ DelayValueStr = NULL;\r
+ } else {\r
+ DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+ }\r
if (DelayValueStr != NULL){\r
if (*DelayValueStr == L':') {\r
DelayValueStr++;\r
\r
/**\r
Function try to find location of the Startup.nsh file.\r
- \r
+\r
The buffer is callee allocated and should be freed by the caller.\r
\r
@param ImageDevicePath The path to the image for shell. first place to look for the startup script\r
// Try to find 'Startup.nsh' in the directory where the shell itself was launched.\r
//\r
MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath (&ImageDevicePath);\r
- if (MapName != NULL) { \r
+ if (MapName != NULL) {\r
StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0);\r
if (StartupScriptPath == NULL) {\r
//\r
*TempSpot = CHAR_NULL;\r
}\r
\r
+ InternalEfiShellSetEnv(L"homefilesystem", StartupScriptPath, TRUE);\r
+\r
StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0);\r
PathRemoveLastItem (StartupScriptPath);\r
StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0);\r
UINTN Delay;\r
EFI_INPUT_KEY Key;\r
CHAR16 *FileStringPath;\r
+ CHAR16 *FullFileStringPath;\r
UINTN NewSize;\r
\r
Key.UnicodeChar = CHAR_NULL;\r
\r
FileStringPath = LocateStartupScript (ImagePath, FilePath);\r
if (FileStringPath != NULL) {\r
- Status = RunScriptFile (FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
+ FullFileStringPath = FullyQualifyPath(FileStringPath);\r
+ if (FullFileStringPath == NULL) {\r
+ Status = RunScriptFile (FileStringPath, NULL, FileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
+ } else {\r
+ Status = RunScriptFile (FullFileStringPath, NULL, FullFileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
+ FreePool(FullFileStringPath);\r
+ }\r
FreePool (FileStringPath);\r
} else {\r
//\r
// Null terminate the string and parse it\r
//\r
if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Reset the CTRL-C event just before running the command (yes we ignore the return values)\r
+ //\r
+ Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
+\r
CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
Status = RunCommand(CmdLine);\r
- }\r
+ }\r
\r
//\r
// Done with this command\r
\r
\r
/**\r
- Create a new buffer list and stores the old one to OldBufferList \r
+ Create a new buffer list and stores the old one to OldBufferList\r
\r
@param OldBufferList The temporary list head used to store the nodes in BufferToFreeList.\r
**/\r
\r
Count = 0;\r
MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount);\r
- \r
+\r
if (MaxHistoryCmdCount == 0) {\r
return ;\r
}\r
}\r
continue;\r
}\r
- \r
+\r
if (FirstQuote == NULL || SecondPercent < FirstQuote) {\r
if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) {\r
//\r
//\r
// now do the replacements...\r
//\r
- NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\r
+ NewCommandLine1 = AllocateZeroPool (NewSize);\r
NewCommandLine2 = AllocateZeroPool(NewSize);\r
ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
SHELL_FREE_NON_NULL(ItemTemp);\r
return (NULL);\r
}\r
+ CopyMem (NewCommandLine1, OriginalCommandLine, StrSize (OriginalCommandLine));\r
+\r
for (MasterEnvList = EfiShellGetEnv(NULL)\r
; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
; MasterEnvList += StrLen(MasterEnvList) + 1\r
){\r
- StrCpyS( ItemTemp, \r
- ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+ StrCpyS( ItemTemp,\r
+ ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
L"%"\r
);\r
- StrCatS( ItemTemp, \r
- ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+ StrCatS( ItemTemp,\r
+ ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
MasterEnvList\r
);\r
- StrCatS( ItemTemp, \r
- ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+ StrCatS( ItemTemp,\r
+ ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)),\r
L"%"\r
);\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
//\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
- \r
+\r
FreePool(NewCommandLine2);\r
FreePool(ItemTemp);\r
\r
}\r
if (Split->SplitStdIn != NULL) {\r
ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn);\r
- FreePool (Split->SplitStdIn);\r
}\r
\r
FreePool(Split);\r
}\r
\r
/**\r
- Take the original command line, substitute any variables, free \r
+ Take the original command line, substitute any variables, free\r
the original string, return the modified copy.\r
\r
@param[in] CmdLine pointer to the command line to update.\r
}\r
\r
/**\r
- Take the original command line, substitute any alias in the first group of space delimited characters, free \r
+ Take the original command line, substitute any alias in the first group of space delimited characters, free\r
the original string, return the modified copy.\r
\r
@param[in] CmdLine pointer to the command line to update.\r
\r
SHELL_FREE_NON_NULL(*CmdLine);\r
SHELL_FREE_NON_NULL(CommandName);\r
- \r
+\r
//\r
// re-assign the passed in double pointer to point to our newly allocated buffer\r
//\r
Takes the Argv[0] part of the command line and determine the meaning of it.\r
\r
@param[in] CmdName pointer to the command line to update.\r
- \r
+\r
@retval Internal_Command The name is an internal command.\r
@retval File_Sys_Change the name is a file system change.\r
@retval Script_File_Name the name is a NSH script file.\r
// Test for file system change request. anything ending with first : and cant have spaces.\r
//\r
if (CmdName[(StrLen(CmdName)-1)] == L':') {\r
- if ( StrStr(CmdName, L" ") != NULL \r
+ if ( StrStr(CmdName, L" ") != NULL\r
|| StrLen(StrStr(CmdName, L":")) > 1\r
) {\r
return (Unknown_Invalid);\r
SHELL_FREE_NON_NULL(FileWithPath);\r
return (Efi_Application);\r
}\r
- \r
+\r
SHELL_FREE_NON_NULL(FileWithPath);\r
//\r
// No clue what this is... return invalid flag...\r
@retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
@retval EFI_NOT_FOUND The operation type is unknown or invalid.\r
**/\r
-EFI_STATUS \r
+EFI_STATUS\r
IsValidSplit(\r
IN CONST CHAR16 *CmdLine\r
)\r
// recurse to verify the next item\r
//\r
TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;\r
- if (*TempSpot == L'a' && \r
+ if (*TempSpot == L'a' &&\r
(*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL)\r
) {\r
// If it's an ASCII pipe '|a'\r
TempSpot += 1;\r
}\r
- \r
+\r
return (VerifySplit(TempSpot));\r
}\r
\r
// make sure we are the right operation\r
//\r
ASSERT(CmdLine[(StrLen(CmdLine)-1)] == L':' && StrStr(CmdLine, L" ") == NULL);\r
- \r
+\r
//\r
// Call the protocol API to do the work\r
//\r
Run an internal shell command.\r
\r
This API will update the shell's environment since these commands are libraries.\r
- \r
+\r
@param[in] CmdLine the command line to run.\r
@param[in] FirstParameter the first parameter on the command line\r
@param[in] ParamProtocol the shell parameters protocol pointer\r
SHELL_STATUS CommandReturnedStatus;\r
BOOLEAN LastError;\r
CHAR16 *Walker;\r
- CHAR16 *NewCmdLine; \r
+ CHAR16 *NewCmdLine;\r
\r
NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
if (NewCmdLine == NULL) {\r
EFI_STATUS Status;\r
EFI_STATUS StartStatus;\r
CHAR16 *CommandWithPath;\r
+ CHAR16 *FullCommandWithPath;\r
EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
SHELL_STATUS CalleeExitStatus;\r
\r
}\r
switch (Type) {\r
case Script_File_Name:\r
- Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
+ FullCommandWithPath = FullyQualifyPath(CommandWithPath);\r
+ if (FullCommandWithPath == NULL) {\r
+ Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
+ } else {\r
+ Status = RunScriptFile (FullCommandWithPath, NULL, CmdLine, ParamProtocol);\r
+ FreePool(FullCommandWithPath);\r
+ }\r
break;\r
case Efi_Application:\r
//\r
/**\r
Function will process and run a command line.\r
\r
- This will determine if the command line represents an internal shell \r
+ This will determine if the command line represents an internal shell\r
command or dispatch an external application.\r
\r
@param[in] CmdLine The command line to parse.\r
CHAR16 *FirstParameter;\r
CHAR16 *TempWalker;\r
SHELL_OPERATION_TYPES Type;\r
+ CONST CHAR16 *CurDir;\r
\r
ASSERT(CmdLine != NULL);\r
if (StrLen(CmdLine) == 0) {\r
Status = ProcessNewSplitCommandLine(CleanOriginal);\r
SHELL_FREE_NON_NULL(CleanOriginal);\r
return (Status);\r
- } \r
+ }\r
\r
//\r
// We need the first parameter information so we can determine the operation type\r
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
SetLastError(SHELL_NOT_FOUND);\r
}\r
- \r
+ //\r
+ // Check whether the current file system still exists. If not exist, we need update "cwd" and gShellCurMapping.\r
+ //\r
+ CurDir = EfiShellGetCurDir (NULL);\r
+ if (CurDir != NULL) {\r
+ if (EFI_ERROR(ShellFileExists (CurDir))) {\r
+ //\r
+ // EfiShellSetCurDir() cannot set current directory to NULL.\r
+ // EfiShellSetEnv() is not allowed to set the "cwd" variable.\r
+ // Only InternalEfiShellSetEnv () is allowed setting the "cwd" variable.\r
+ //\r
+ InternalEfiShellSetEnv (L"cwd", NULL, TRUE);\r
+ gShellCurMapping = NULL;\r
+ }\r
+ }\r
+\r
SHELL_FREE_NON_NULL(CleanOriginal);\r
SHELL_FREE_NON_NULL(FirstParameter);\r
\r
/**\r
Function will process and run a command line.\r
\r
- This will determine if the command line represents an internal shell \r
+ This will determine if the command line represents an internal shell\r
command or dispatch an external application.\r
\r
@param[in] CmdLine The command line to parse.\r
return (RunShellCommand(CmdLine, NULL));\r
}\r
\r
-\r
-STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
-/**\r
- Function determines if the CommandName COULD be a valid command. It does not determine whether\r
- this is a valid command. It only checks for invalid characters.\r
-\r
- @param[in] CommandName The name to check\r
-\r
- @retval TRUE CommandName could be a command name\r
- @retval FALSE CommandName could not be a valid command name\r
-**/\r
-BOOLEAN\r
-IsValidCommandName(\r
- IN CONST CHAR16 *CommandName\r
- )\r
-{\r
- UINTN Count;\r
- if (CommandName == NULL) {\r
- ASSERT(FALSE);\r
- return (FALSE);\r
- }\r
- for ( Count = 0\r
- ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
- ; Count++\r
- ){\r
- if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
- return (FALSE);\r
- }\r
- }\r
- return (TRUE);\r
-}\r
-\r
/**\r
Function to process a NSH script file via SHELL_FILE_HANDLE.\r
\r
DeleteScriptFileStruct(NewScriptFile);\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
+ //\r
+ // Put the full path of the script file into Argv[0] as required by section\r
+ // 3.6.2 of version 2.2 of the shell specification.\r
+ //\r
+ NewScriptFile->Argv[0] = StrnCatGrow(&NewScriptFile->Argv[0], NULL, NewScriptFile->ScriptName, 0);\r
+ for (LoopVar = 1 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
if (NewScriptFile->Argv[LoopVar] == NULL) {\r
; // conditional increment in the body of the loop\r
){\r
ASSERT(CommandLine2 != NULL);\r
- StrnCpyS( CommandLine2, \r
- PrintBuffSize/sizeof(CHAR16), \r
+ StrnCpyS( CommandLine2,\r
+ PrintBuffSize/sizeof(CHAR16),\r
NewScriptFile->CurrentCommand->Cl,\r
PrintBuffSize/sizeof(CHAR16) - 1\r
);\r
//\r
// Due to variability in starting the find and replace action we need to have both buffers the same.\r
//\r
- StrnCpyS( CommandLine, \r
- PrintBuffSize/sizeof(CHAR16), \r
+ StrnCpyS( CommandLine,\r
+ PrintBuffSize/sizeof(CHAR16),\r
CommandLine2,\r
PrintBuffSize/sizeof(CHAR16) - 1\r
);\r
Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PrintBuffSize, L"%8", L"\"\"", FALSE, FALSE);\r
Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PrintBuffSize, L"%9", L"\"\"", FALSE, FALSE);\r
\r
- StrnCpyS( CommandLine2, \r
- PrintBuffSize/sizeof(CHAR16), \r
+ StrnCpyS( CommandLine2,\r
+ PrintBuffSize/sizeof(CHAR16),\r
CommandLine,\r
PrintBuffSize/sizeof(CHAR16) - 1\r
);\r