/** @file\r
This is THE shell (application)\r
\r
- Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
- Copyright (c) 2013, Hewlett-Packard Development Company, L.P.\r
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.\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
///@todo Add our package into Framework HII\r
}\r
if (ShellInfoObject.HiiHandle == NULL) {\r
- return (EFI_NOT_STARTED);\r
+ Status = EFI_NOT_STARTED;\r
+ goto FreeResources;\r
}\r
}\r
\r
//\r
// Check the command line\r
//\r
- Status = ProcessCommandLine();\r
+ Status = ProcessCommandLine ();\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeResources;\r
+ }\r
\r
//\r
// If shell support level is >= 1 create the mappings and paths\r
// Reset page break back to default.\r
//\r
ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
+ ASSERT (ShellInfoObject.ConsoleInfo != NULL);\r
ShellInfoObject.ConsoleInfo->Enabled = TRUE;\r
ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
\r
}\r
}\r
\r
+FreeResources:\r
//\r
// uninstall protocols / free memory / etc...\r
//\r
return (Status);\r
}\r
\r
-STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = {\r
- {L"-nostartup", TypeFlag},\r
- {L"-startup", TypeFlag},\r
- {L"-noconsoleout", TypeFlag},\r
- {L"-noconsolein", TypeFlag},\r
- {L"-nointerrupt", TypeFlag},\r
- {L"-nomap", TypeFlag},\r
- {L"-noversion", TypeFlag},\r
- {L"-startup", TypeFlag},\r
- {L"-delay", TypeValue},\r
- {L"-_exit", TypeFlag},\r
- {NULL, TypeMax}\r
- };\r
-\r
/**\r
Process all Uefi Shell 2.0 command line options.\r
\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- LIST_ENTRY *Package;\r
- UINTN Size;\r
- CONST CHAR16 *TempConst;\r
- UINTN Count;\r
- UINTN LoopVar;\r
- CHAR16 *ProblemParam;\r
- UINT64 Intermediate;\r
-\r
- Package = NULL;\r
- ProblemParam = NULL;\r
- \r
- Status = ShellCommandLineParse (mShellParamList, &Package, NULL, FALSE);\r
-\r
- Count = 1;\r
- Size = 0;\r
- TempConst = ShellCommandLineGetRawValue(Package, Count++);\r
- if (TempConst != NULL && StrLen(TempConst)) {\r
- ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(TempConst));\r
- if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
- return (EFI_OUT_OF_RESOURCES);\r
+ UINTN Size;\r
+ UINTN LoopVar;\r
+ CHAR16 *CurrentArg;\r
+ CHAR16 *DelayValueStr;\r
+ UINT64 DelayValue;\r
+ EFI_STATUS Status;\r
+ EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation;\r
+\r
+ // `file-name-options` will contain arguments to `file-name` that we don't\r
+ // know about. This would cause ShellCommandLineParse to error, so we parse\r
+ // arguments manually, ignoring those after the first thing that doesn't look\r
+ // like a shell option (which is assumed to be `file-name`).\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiUnicodeCollationProtocolGuid,\r
+ NULL,\r
+ (VOID **) &UnicodeCollation\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Set default options\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = FALSE;\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = FALSE;\r
+ ShellInfoObject.ShellInitSettings.Delay = 5;\r
+\r
+ //\r
+ // Start LoopVar at 0 to parse only optional arguments at Argv[0]\r
+ // and parse other parameters from Argv[1]. This is for use case that\r
+ // UEFI Shell boot option is created, and OptionalData is provided\r
+ // that starts with shell command-line options.\r
+ //\r
+ for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
+ CurrentArg = gEfiShellParametersProtocol->Argv[LoopVar];\r
+ if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-startup",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = TRUE;\r
}\r
- StrCpy(ShellInfoObject.ShellInitSettings.FileName, TempConst);\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
- for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
- if (StrCmp(gEfiShellParametersProtocol->Argv[LoopVar], ShellInfoObject.ShellInitSettings.FileName)==0) {\r
- LoopVar++;\r
- //\r
- // We found the file... add the rest of the params...\r
- //\r
- for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
- ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
- StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
- &Size,\r
- L" ",\r
- 0);\r
- if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
- SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
- return (EFI_OUT_OF_RESOURCES);\r
- }\r
- StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
- &Size,\r
- gEfiShellParametersProtocol->Argv[LoopVar],\r
- 0);\r
- if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
- SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
- return (EFI_OUT_OF_RESOURCES);\r
- }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-nostartup",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-noconsoleout",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-noconsolein",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-nointerrupt",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-nomap",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-noversion",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = TRUE;\r
+ }\r
+ else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-delay",\r
+ CurrentArg\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 (DelayValueStr != NULL){\r
+ if (*DelayValueStr == L':') {\r
+ DelayValueStr++;\r
+ }\r
+ if (!EFI_ERROR(ShellConvertStringToUint64 (\r
+ DelayValueStr,\r
+ &DelayValue,\r
+ FALSE,\r
+ FALSE\r
+ ))) {\r
+ ShellInfoObject.ShellInitSettings.Delay = (UINTN)DelayValue;\r
+ LoopVar++;\r
+ }\r
+ }\r
+ } else if (UnicodeCollation->StriColl (\r
+ UnicodeCollation,\r
+ L"-_exit",\r
+ CurrentArg\r
+ ) == 0) {\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = TRUE;\r
+ } else if (StrnCmp (L"-", CurrentArg, 1) == 0) {\r
+ // Unrecognised option\r
+ ShellPrintHiiEx(-1, -1, NULL,\r
+ STRING_TOKEN (STR_GEN_PROBLEM),\r
+ ShellInfoObject.HiiHandle,\r
+ CurrentArg\r
+ );\r
+ return EFI_INVALID_PARAMETER;\r
+ } else {\r
+ //\r
+ // First argument should be Shell.efi image name\r
+ //\r
+ if (LoopVar == 0) {\r
+ continue;\r
+ }\r
+\r
+ ShellInfoObject.ShellInitSettings.FileName = AllocateCopyPool(StrSize(CurrentArg), CurrentArg);\r
+ if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ //\r
+ // We found `file-name`.\r
+ //\r
+ ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
+ LoopVar++;\r
+\r
+ // Add `file-name-options`\r
+ for (Size = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
+ ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
+ StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+ &Size,\r
+ L" ",\r
+ 0);\r
+ if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+ SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+ &Size,\r
+ gEfiShellParametersProtocol->Argv[LoopVar],\r
+ 0);\r
+ if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+ SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+ return (EFI_OUT_OF_RESOURCES);\r
}\r
}\r
- }\r
- } else {\r
- ShellCommandLineFreeVarList(Package);\r
- Package = NULL;\r
- Status = ShellCommandLineParse (mShellParamList, &Package, &ProblemParam, FALSE);\r
- if (EFI_ERROR(Status)) {\r
- ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), ShellInfoObject.HiiHandle, ProblemParam);\r
- FreePool(ProblemParam);\r
- ShellCommandLineFreeVarList(Package);\r
- return (EFI_INVALID_PARAMETER);\r
}\r
}\r
\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = ShellCommandLineGetFlag(Package, L"-startup");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = ShellCommandLineGetFlag(Package, L"-nostartup");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = ShellCommandLineGetFlag(Package, L"-noconsoleout");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = ShellCommandLineGetFlag(Package, L"-noconsolein");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = ShellCommandLineGetFlag(Package, L"-nointerrupt");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = ShellCommandLineGetFlag(Package, L"-nomap");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = ShellCommandLineGetFlag(Package, L"-noversion");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = ShellCommandLineGetFlag(Package, L"-delay");\r
- ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = ShellCommandLineGetFlag(Package, L"-_exit");\r
-\r
- ShellInfoObject.ShellInitSettings.Delay = 5;\r
-\r
+ // "-nointerrupt" overrides "-delay"\r
if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {\r
ShellInfoObject.ShellInitSettings.Delay = 0;\r
- } else if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay) {\r
- TempConst = ShellCommandLineGetValue(Package, L"-delay");\r
- if (TempConst != NULL && *TempConst == L':') {\r
- TempConst++;\r
- }\r
- if (TempConst != NULL && !EFI_ERROR(ShellConvertStringToUint64(TempConst, &Intermediate, FALSE, FALSE))) {\r
- ShellInfoObject.ShellInitSettings.Delay = (UINTN)Intermediate;\r
- }\r
}\r
- ShellCommandLineFreeVarList(Package);\r
\r
- return (Status);\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
EFI_STATUS\r
EFIAPI\r
DoStartupScript(\r
- EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
- EFI_DEVICE_PATH_PROTOCOL *FilePath\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
)\r
{\r
EFI_STATUS Status;\r
if (FileStringPath == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
+ StrnCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName, NewSize/sizeof(CHAR16) -1);\r
if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
- StrCat(FileStringPath, L" ");\r
- StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);\r
+ StrnCat(FileStringPath, L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
+ StrnCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
}\r
Status = RunCommand(FileStringPath);\r
FreePool(FileStringPath);\r
// If we got a file, run it\r
//\r
if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
- Status = RunScriptFileHandle (FileHandle, mStartupScript);\r
+ Status = RunScriptFile (mStartupScript, FileHandle, L"", ShellInfoObject.NewShellParametersProtocol);\r
ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
} else {\r
FileStringPath = ShellFindFilePath(mStartupScript);\r
Status = EFI_SUCCESS;\r
ASSERT(FileHandle == NULL);\r
} else {\r
- Status = RunScriptFile(FileStringPath);\r
+ Status = RunScriptFile(FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
FreePool(FileStringPath);\r
}\r
}\r
if (!EFI_ERROR (Status)) {\r
CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
Status = RunCommand(CmdLine);\r
- }\r
+ }\r
\r
//\r
// Done with this command\r
\r
Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ASSERT(Node != NULL);\r
- Node->Buffer = AllocateZeroPool(StrSize(Buffer));\r
+ Node->Buffer = AllocateCopyPool(StrSize(Buffer), Buffer);\r
ASSERT(Node->Buffer != NULL);\r
- StrCpy(Node->Buffer, Buffer);\r
\r
InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
}\r
return (EFI_SUCCESS);\r
}\r
FreePool(*CommandString);\r
- *CommandString = AllocateZeroPool(StrSize(NewString));\r
+ *CommandString = AllocateCopyPool(StrSize(NewString), NewString);\r
if (*CommandString == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(*CommandString, NewString);\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\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
+ @param[in] FindString The string to look for\r
+ @param[in] CheckForEscapeCharacter TRUE to skip escaped instances of FinfString, otherwise will return even escaped instances\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+FindNextInstance(\r
+ IN CONST CHAR16 *SourceString,\r
+ IN CONST CHAR16 *FindString,\r
+ IN CONST BOOLEAN CheckForEscapeCharacter\r
+ )\r
+{\r
+ CHAR16 *Temp;\r
+ if (SourceString == NULL) {\r
+ return (NULL);\r
+ }\r
+ Temp = StrStr(SourceString, FindString);\r
+\r
+ //\r
+ // If nothing found, or we dont care about escape characters\r
+ //\r
+ if (Temp == NULL || !CheckForEscapeCharacter) {\r
+ return (Temp);\r
+ }\r
+\r
+ //\r
+ // If we found an escaped character, try again on the remainder of the string\r
+ //\r
+ if ((Temp > (SourceString)) && *(Temp-1) == L'^') {\r
+ return FindNextInstance(Temp+1, FindString, CheckForEscapeCharacter);\r
+ }\r
+\r
+ //\r
+ // we found the right character\r
+ //\r
+ return (Temp);\r
+}\r
+\r
+/**\r
+ This function will eliminate unreplaced (and therefore non-found) environment variables.\r
+\r
+ @param[in,out] CmdLine The command line to update.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StripUnreplacedEnvironmentVariables(\r
+ IN OUT CHAR16 *CmdLine\r
+ )\r
+{\r
+ CHAR16 *FirstPercent;\r
+ CHAR16 *FirstQuote;\r
+ CHAR16 *SecondPercent;\r
+ CHAR16 *SecondQuote;\r
+ CHAR16 *CurrentLocator;\r
+\r
+ for (CurrentLocator = CmdLine ; CurrentLocator != NULL ; ) {\r
+ FirstQuote = FindNextInstance(CurrentLocator, L"\"", TRUE);\r
+ FirstPercent = FindNextInstance(CurrentLocator, L"%", TRUE);\r
+ SecondPercent = FirstPercent!=NULL?FindNextInstance(FirstPercent+1, L"%", TRUE):NULL;\r
+ if (FirstPercent == NULL || SecondPercent == NULL) {\r
+ //\r
+ // If we ever dont have 2 % we are done.\r
+ //\r
+ break;\r
+ }\r
+\r
+ if (FirstQuote < FirstPercent) {\r
+ SecondQuote = FirstQuote!= NULL?FindNextInstance(FirstQuote+1, L"\"", TRUE):NULL;\r
+ //\r
+ // Quote is first found\r
+ //\r
+\r
+ if (SecondQuote < FirstPercent) {\r
+ //\r
+ // restart after the pair of "\r
+ //\r
+ CurrentLocator = SecondQuote + 1;\r
+ } else /* FirstPercent < SecondQuote */{\r
+ //\r
+ // Restart on the first percent\r
+ //\r
+ CurrentLocator = FirstPercent;\r
+ }\r
+ continue;\r
+ }\r
+ ASSERT(FirstPercent < FirstQuote);\r
+ if (SecondPercent < FirstQuote) {\r
+ FirstPercent[0] = L'\"';\r
+ SecondPercent[0] = L'\"';\r
+\r
+ //\r
+ // We need to remove from FirstPercent to SecondPercent\r
+ //\r
+ CopyMem(FirstPercent + 1, SecondPercent, StrSize(SecondPercent));\r
+ CurrentLocator = FirstPercent + 2;\r
+ continue;\r
+ }\r
+ ASSERT(FirstQuote < SecondPercent);\r
+ CurrentLocator = FirstQuote;\r
+ }\r
return (EFI_SUCCESS);\r
}\r
\r
CHAR16 *NewCommandLine1;\r
CHAR16 *NewCommandLine2;\r
CHAR16 *Temp;\r
- CHAR16 *Temp2;\r
UINTN ItemSize;\r
CHAR16 *ItemTemp;\r
SCRIPT_FILE *CurrentScriptFile;\r
//\r
// now do the replacements...\r
//\r
- NewCommandLine1 = AllocateZeroPool(NewSize);\r
+ NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\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
- StrCpy(NewCommandLine1, OriginalCommandLine);\r
for (MasterEnvList = EfiShellGetEnv(NULL)\r
- ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
+ ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
; MasterEnvList += StrLen(MasterEnvList) + 1\r
){\r
- StrCpy(ItemTemp, L"%");\r
- StrCat(ItemTemp, MasterEnvList);\r
- StrCat(ItemTemp, L"%");\r
+ StrnCpy(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1);\r
+ StrnCat(ItemTemp, MasterEnvList, ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\r
+ StrnCat(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
}\r
if (CurrentScriptFile != NULL) {\r
for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
){\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
}\r
\r
//\r
// Remove non-existant environment variables in scripts only\r
//\r
- for (Temp = NewCommandLine1 ; Temp != NULL ; ) {\r
- Temp = StrStr(Temp, L"%");\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- while (*(Temp - 1) == L'^') {\r
- Temp = StrStr(Temp + 1, L"%");\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- }\r
- if (Temp == NULL) {\r
- break;\r
- }\r
- \r
- Temp2 = StrStr(Temp + 1, L"%");\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- while (*(Temp2 - 1) == L'^') {\r
- Temp2 = StrStr(Temp2 + 1, L"%");\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- }\r
- if (Temp2 == NULL) {\r
- break;\r
- }\r
- \r
- Temp2++;\r
- CopyMem(Temp, Temp2, StrSize(Temp2));\r
- }\r
-\r
+ StripUnreplacedEnvironmentVariables(NewCommandLine1);\r
}\r
\r
//\r
// Now cleanup any straggler intentionally ignored "%" characters\r
//\r
ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
- StrCpy(NewCommandLine1, NewCommandLine2);\r
+ StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
\r
FreePool(NewCommandLine2);\r
FreePool(ItemTemp);\r
}\r
\r
//\r
- // Test for file system change request. anything ending with : and cant have spaces.\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
}\r
return (File_Sys_Change);\r
return (Unknown_Invalid);\r
}\r
\r
+/**\r
+ Determine if the first item in a command line is valid.\r
+\r
+ @param[in] CmdLine The command line to parse.\r
+\r
+ @retval EFI_SUCCESS The item is valid.\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
EFIAPI\r
IsValidSplit(\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
TempWalker = (CHAR16*)Temp;\r
- GetNextParameter(&TempWalker, &FirstParameter);\r
+ GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine));\r
\r
if (GetOperationType(FirstParameter) == Unknown_Invalid) {\r
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
Walker = *CmdLine;\r
while(Walker != NULL && *Walker != CHAR_NULL) {\r
LastWalker = Walker;\r
- GetNextParameter(&Walker, &CurrentParameter);\r
+ GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine));\r
if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {\r
LastWalker[0] = L' ';\r
LastWalker[1] = L' ';\r
Status = EFI_OUT_OF_RESOURCES;\r
break;\r
}\r
- StrCpy(NewCommandLine, L"help ");\r
- StrCat(NewCommandLine, *CmdLine);\r
+\r
+ //\r
+ // We know the space is sufficient since we just calculated it.\r
+ //\r
+ StrnCpy(NewCommandLine, L"help ", 5);\r
+ StrnCat(NewCommandLine, *CmdLine, StrLen(*CmdLine));\r
SHELL_FREE_NON_NULL(*CmdLine);\r
*CmdLine = NewCommandLine;\r
break;\r
if (EFI_ERROR(Status)) {\r
return (Status);\r
}\r
+ ASSERT (*CmdLine != NULL);\r
\r
TrimSpaces(CmdLine);\r
\r
CHAR16 **Argv;\r
SHELL_STATUS CommandReturnedStatus;\r
BOOLEAN LastError;\r
+ CHAR16 *Walker;\r
+ CHAR16 *NewCmdLine; \r
+\r
+ NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
+ if (NewCmdLine == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+ if (*Walker == L'^' && *(Walker+1) == L'#') {\r
+ CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+ }\r
+ }\r
\r
//\r
// get the argc and argv updated for internal commands\r
//\r
- Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc);\r
+ Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, &Argv, &Argc);\r
if (!EFI_ERROR(Status)) {\r
//\r
// Run the internal command.\r
Status = EFI_SUCCESS;\r
}\r
\r
+ FreePool (NewCmdLine);\r
return (Status);\r
}\r
\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_STATUS StatusCode;\r
+ EFI_STATUS StartStatus;\r
CHAR16 *CommandWithPath;\r
EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+ SHELL_STATUS CalleeExitStatus;\r
\r
Status = EFI_SUCCESS;\r
CommandWithPath = NULL;\r
DevPath = NULL;\r
+ CalleeExitStatus = SHELL_INVALID_PARAMETER;\r
\r
switch (Type) {\r
case Internal_Command:\r
}\r
switch (Type) {\r
case Script_File_Name:\r
- Status = RunScriptFile (CommandWithPath);\r
+ Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
break;\r
case Efi_Application:\r
//\r
DevPath,\r
CmdLine,\r
NULL,\r
- &StatusCode\r
+ &StartStatus\r
);\r
\r
SHELL_FREE_NON_NULL(DevPath);\r
\r
+ if(EFI_ERROR (Status)) {\r
+ CalleeExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
+ } else {\r
+ CalleeExitStatus = (SHELL_STATUS) StartStatus;\r
+ }\r
+\r
//\r
// Update last error status.\r
//\r
- SetLastError(StatusCode);\r
+ // Status is an EFI_STATUS. Clear top bit to convert to SHELL_STATUS\r
+ SetLastError(CalleeExitStatus);\r
break;\r
default:\r
//\r
// Now run the command, script, or application\r
//\r
if (!EFI_ERROR(Status)) {\r
+ TrimSpaces(&CmdLine);\r
Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol);\r
}\r
\r
\r
TrimSpaces(&CleanOriginal);\r
\r
+ //\r
+ // NULL out comments (leveraged from RunScriptFileHandle() ).\r
+ // The # character on a line is used to denote that all characters on the same line\r
+ // and to the right of the # are to be ignored by the shell.\r
+ // Afterward, again remove spaces, in case any were between the last command-parameter and '#'.\r
+ //\r
+ for (TempWalker = CleanOriginal; TempWalker != NULL && *TempWalker != CHAR_NULL; TempWalker++) {\r
+ if (*TempWalker == L'^') {\r
+ if (*(TempWalker + 1) == L'#') {\r
+ TempWalker++;\r
+ }\r
+ } else if (*TempWalker == L'#') {\r
+ *TempWalker = CHAR_NULL;\r
+ }\r
+ }\r
+\r
+ TrimSpaces(&CleanOriginal);\r
+\r
//\r
// Handle case that passed in command line is just 1 or more " " characters.\r
//\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
TempWalker = CleanOriginal;\r
- GetNextParameter(&TempWalker, &FirstParameter);\r
+ GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal));\r
\r
//\r
// Depending on the first parameter we change the behavior\r
//\r
switch (Type = GetOperationType(FirstParameter)) {\r
case File_Sys_Change:\r
- Status = ChangeMappedDrive(CleanOriginal);\r
+ Status = ChangeMappedDrive (FirstParameter);\r
break;\r
case Internal_Command:\r
case Script_File_Name:\r
while(!ShellFileHandleEof(Handle)) {\r
CommandLine = ShellFileHandleReturnLine(Handle, &Ascii);\r
LineCount++;\r
- if (CommandLine == NULL || StrLen(CommandLine) == 0) {\r
+ if (CommandLine == NULL || StrLen(CommandLine) == 0 || CommandLine[0] == '#') {\r
+ SHELL_FREE_NON_NULL(CommandLine);\r
continue;\r
}\r
NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST));\r
if (NewScriptFile->CurrentCommand == NULL) {\r
+ SHELL_FREE_NON_NULL(CommandLine);\r
DeleteScriptFileStruct(NewScriptFile);\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
; // conditional increment in the body of the loop\r
){\r
ASSERT(CommandLine2 != NULL);\r
- StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
+ StrnCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
//\r
// NULL out comments\r
//\r
for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
if (*CommandLine3 == L'^') {\r
- if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
+ if ( *(CommandLine3+1) == L':') {\r
CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
+ } else if (*(CommandLine3+1) == L'#') {\r
+ CommandLine3++;\r
}\r
} else if (*CommandLine3 == L'#') {\r
*CommandLine3 = CHAR_NULL;\r
//\r
// Due to variability in starting the find and replace action we need to have both buffers the same.\r
//\r
- StrCpy(CommandLine, CommandLine2);\r
+ StrnCpy(CommandLine, CommandLine2, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
//\r
// Remove the %0 to %9 from the command line (if we have some arguments)\r
if (NewScriptFile->Argv != NULL) {\r
switch (NewScriptFile->Argc) {\r
default:\r
- Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 9:\r
- Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 8:\r
- Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 7:\r
- Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 6:\r
- Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 5:\r
- Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 4:\r
- Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 3:\r
- Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 2:\r
- Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
case 1:\r
- Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);\r
+ Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, FALSE);\r
ASSERT_EFI_ERROR(Status);\r
break;\r
case 0:\r
Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
\r
- StrCpy(CommandLine2, CommandLine);\r
+ StrnCpy(CommandLine2, CommandLine, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\r
\r
LastCommand = NewScriptFile->CurrentCommand;\r
\r
Function to process a NSH script file.\r
\r
@param[in] ScriptPath Pointer to the script file name (including file system path).\r
+ @param[in] Handle the handle of the script file already opened.\r
+ @param[in] CmdLine the command line to run.\r
+ @param[in] ParamProtocol the shell parameters protocol pointer\r
\r
@retval EFI_SUCCESS the script completed sucessfully\r
**/\r
EFI_STATUS\r
EFIAPI\r
RunScriptFile (\r
- IN CONST CHAR16 *ScriptPath\r
+ IN CONST CHAR16 *ScriptPath,\r
+ IN SHELL_FILE_HANDLE Handle OPTIONAL,\r
+ IN CONST CHAR16 *CmdLine,\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol\r
)\r
{\r
EFI_STATUS Status;\r
SHELL_FILE_HANDLE FileHandle;\r
+ UINTN Argc;\r
+ CHAR16 **Argv;\r
\r
if (ShellIsFile(ScriptPath) != EFI_SUCCESS) {\r
return (EFI_INVALID_PARAMETER);\r
}\r
\r
- Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
- if (EFI_ERROR(Status)) {\r
- return (Status);\r
- }\r
+ //\r
+ // get the argc and argv updated for scripts\r
+ //\r
+ Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc);\r
+ if (!EFI_ERROR(Status)) {\r
\r
- Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
+ if (Handle == NULL) {\r
+ //\r
+ // open the file\r
+ //\r
+ Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // run it\r
+ //\r
+ Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
\r
- ShellCloseFile(&FileHandle);\r
+ //\r
+ // now close the file\r
+ //\r
+ ShellCloseFile(&FileHandle);\r
+ }\r
+ } else {\r
+ Status = RunScriptFileHandle(Handle, ScriptPath);\r
+ }\r
+ }\r
+\r
+ //\r
+ // This is guarenteed to be called after UpdateArgcArgv no matter what else happened.\r
+ // This is safe even if the update API failed. In this case, it may be a no-op.\r
+ //\r
+ RestoreArgcArgv(ParamProtocol, &Argv, &Argc);\r
\r
return (Status);\r
}\r