Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
\r
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<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
#include "Shell.h"\r
\r
+#define INIT_NAME_BUFFER_SIZE 128\r
+\r
/**\r
Close an open file handle.\r
\r
if (Cwd == NULL) {\r
return (NULL);\r
}\r
- Size = StrSize(Cwd);\r
- Size += StrSize(Path);\r
+ Size = StrSize(Cwd) + StrSize(Path);\r
NewPath = AllocateZeroPool(Size);\r
if (NewPath == NULL) {\r
return (NULL);\r
}\r
- StrCpy(NewPath, Cwd);\r
+ StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd);\r
+ StrCatS(NewPath, Size/sizeof(CHAR16), L"\\");\r
if (*Path == L'\\') {\r
Path++;\r
while (PathRemoveLastItem(NewPath)) ;\r
}\r
- StrCat(NewPath, Path);\r
+ StrCatS(NewPath, Size/sizeof(CHAR16), Path);\r
DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
FreePool(NewPath);\r
return (DevicePathForReturn);\r
is NULL, then the current shell environment is used.\r
\r
@param[out] StartImageStatus Returned status from gBS->StartImage.\r
- @param[out] ExitDataSize ExitDataSize as returned from gBS->StartImage\r
- @param[out] ExitData ExitData as returned from gBS->StartImage\r
\r
@retval EFI_SUCCESS The command executed successfully. The status code\r
returned by the command is pointed to by StatusCode.\r
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
IN CONST CHAR16 *CommandLine OPTIONAL,\r
IN CONST CHAR16 **Environment OPTIONAL,\r
- OUT EFI_STATUS *StartImageStatus OPTIONAL,\r
- OUT UINTN *ExitDataSize OPTIONAL,\r
- OUT CHAR16 **ExitData OPTIONAL\r
+ OUT EFI_STATUS *StartImageStatus OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
LIST_ENTRY OrigEnvs;\r
EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
- UINTN InternalExitDataSize;\r
- UINTN *ExitDataSizePtr;\r
CHAR16 *ImagePath;\r
UINTN Index;\r
-\r
- // ExitDataSize is not OPTIONAL for gBS->BootServices, provide somewhere for\r
- // it to be dumped if the caller doesn't want it.\r
- if (ExitData == NULL) {\r
- ExitDataSizePtr = &InternalExitDataSize;\r
- } else {\r
- ExitDataSizePtr = ExitDataSize;\r
- }\r
+ CHAR16 *Walker;\r
+ CHAR16 *NewCmdLine;\r
\r
if (ParentImageHandle == NULL) {\r
return (EFI_INVALID_PARAMETER);\r
InitializeListHead(&OrigEnvs);\r
\r
NewHandle = NULL;\r
+ \r
+ NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);\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
// Load the image with:\r
\r
if (!EFI_ERROR(Status)) {\r
ASSERT(LoadedImage->LoadOptionsSize == 0);\r
- if (CommandLine != NULL) {\r
- LoadedImage->LoadOptionsSize = (UINT32)StrSize(CommandLine);\r
- LoadedImage->LoadOptions = (VOID*)CommandLine;\r
+ if (NewCmdLine != NULL) {\r
+ LoadedImage->LoadOptionsSize = (UINT32)StrSize(NewCmdLine);\r
+ LoadedImage->LoadOptions = (VOID*)NewCmdLine;\r
}\r
\r
//\r
ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
- Status = UpdateArgcArgv(&ShellParamsProtocol, CommandLine, NULL, NULL);\r
+ Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, NULL, NULL);\r
ASSERT_EFI_ERROR(Status);\r
//\r
// Replace Argv[0] with the full path of the binary we're executing:\r
///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
\r
//\r
- // now start the image, passing up exit data if the caller requested it\r
+ // now start the image and if the caller wanted the return code pass it to them...\r
//\r
if (!EFI_ERROR(Status)) {\r
StartStatus = gBS->StartImage(\r
NewHandle,\r
- ExitDataSizePtr,\r
- ExitData\r
+ 0,\r
+ NULL\r
);\r
if (StartImageStatus != NULL) {\r
*StartImageStatus = StartStatus;\r
ASSERT_EFI_ERROR (CleanupStatus);\r
}\r
\r
+ FreePool (NewCmdLine);\r
+\r
return(Status);\r
}\r
/**\r
CHAR16 *Temp;\r
EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
UINTN Size;\r
- UINTN ExitDataSize;\r
- CHAR16 *ExitData;\r
+ EFI_STATUS CalleeStatusCode;\r
\r
+ CalleeStatusCode = EFI_SUCCESS;\r
+ \r
if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
return (EFI_UNSUPPORTED);\r
}\r
\r
- DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
+ if (Environment != NULL) {\r
+ // If Environment isn't null, load a new image of the shell with its own\r
+ // environment\r
+ DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
+ \r
+ DEBUG_CODE_BEGIN();\r
+ Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ DEBUG_CODE_END();\r
+\r
+ Temp = NULL;\r
+ Size = 0;\r
+ ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
+ StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
+ StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
\r
- DEBUG_CODE_BEGIN();\r
- Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
- FreePool(Temp);\r
- Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
- FreePool(Temp);\r
- Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
- FreePool(Temp);\r
- DEBUG_CODE_END();\r
+ Status = InternalShellExecuteDevicePath(\r
+ ParentImageHandle,\r
+ DevPath,\r
+ Temp,\r
+ (CONST CHAR16**)Environment,\r
+ StatusCode);\r
\r
- Temp = NULL;\r
- Size = 0;\r
- ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
- StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
- StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
-\r
- Status = InternalShellExecuteDevicePath(\r
- ParentImageHandle,\r
- DevPath,\r
- Temp,\r
- (CONST CHAR16**)Environment,\r
- StatusCode,\r
- &ExitDataSize,\r
- &ExitData);\r
-\r
- if (Status == EFI_ABORTED) {\r
- // If the command exited with an error, the shell should put the exit\r
- // status in ExitData, preceded by a null-terminated string.\r
- ASSERT (ExitDataSize == StrSize (ExitData) + sizeof (SHELL_STATUS));\r
-\r
- if (StatusCode != NULL) {\r
- // Skip the null-terminated string\r
- ExitData += StrLen (ExitData) + 1;\r
-\r
- // Use CopyMem to avoid alignment faults\r
- CopyMem (StatusCode, ExitData, sizeof (SHELL_STATUS));\r
-\r
- // Convert from SHELL_STATUS to EFI_STATUS\r
- // EFI_STATUSes have top bit set when they are errors.\r
- // (See UEFI Spec Appendix D)\r
- if (*StatusCode != SHELL_SUCCESS) {\r
- *StatusCode = (EFI_STATUS) *StatusCode | MAX_BIT;\r
- }\r
- }\r
- FreePool (ExitData);\r
- Status = EFI_SUCCESS;\r
+ //\r
+ // de-allocate and return\r
+ //\r
+ FreePool(DevPath);\r
+ FreePool(Temp);\r
+ } else {\r
+ // If Environment is NULL, we are free to use and mutate the current shell\r
+ // environment. This is much faster as uses much less memory.\r
+\r
+ if (CommandLine == NULL) {\r
+ CommandLine = L"";\r
}\r
\r
- //\r
- // de-allocate and return\r
- //\r
- FreePool(DevPath);\r
- FreePool(Temp);\r
+ Status = RunShellCommand (CommandLine, &CalleeStatusCode);\r
+\r
+ // Pass up the command's exit code if the caller wants it\r
+ if (StatusCode != NULL) {\r
+ *StatusCode = (EFI_STATUS) CalleeStatusCode;\r
+ }\r
+ }\r
+\r
return(Status);\r
}\r
\r
if (NewNode == NULL) {\r
return (NULL);\r
}\r
- NewNode->FullName = AllocateZeroPool(StrSize(Node->FullName));\r
-\r
- NewNode->FileName = AllocateZeroPool(StrSize(Node->FileName));\r
- NewNode->Info = AllocateZeroPool((UINTN)Node->Info->Size);\r
+ NewNode->FullName = AllocateCopyPool(StrSize(Node->FullName), Node->FullName);\r
+ NewNode->FileName = AllocateCopyPool(StrSize(Node->FileName), Node->FileName);\r
+ NewNode->Info = AllocateCopyPool((UINTN)Node->Info->Size, Node->Info);\r
if ( NewNode->FullName == NULL\r
|| NewNode->FileName == NULL\r
|| NewNode->Info == NULL\r
if (!Save) {\r
Node->Handle = NULL;\r
}\r
- StrCpy((CHAR16*)NewNode->FullName, Node->FullName);\r
- StrCpy((CHAR16*)NewNode->FileName, Node->FileName);\r
- CopyMem(NewNode->Info, Node->Info, (UINTN)Node->Info->Size);\r
\r
return((EFI_SHELL_FILE_INFO*)NewNode);\r
}\r
\r
CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));\r
ASSERT(CurrentFilePattern != NULL);\r
- StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern);\r
+ StrnCpyS(CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
\r
if (CurrentFilePattern[0] == CHAR_NULL\r
&&NextFilePatternStart[0] == CHAR_NULL\r
if (NewFullName == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
} else {\r
- StrCpy(NewFullName, MapName);\r
- StrCat(NewFullName, ShellInfoNode->FullName+1);\r
+ StrCpyS(NewFullName, Size/sizeof(CHAR16), MapName);\r
+ StrCatS(NewFullName, Size/sizeof(CHAR16), ShellInfoNode->FullName+1);\r
FreePool((VOID*)ShellInfoNode->FullName);\r
ShellInfoNode->FullName = NewFullName;\r
}\r
RootDevicePath = NULL;\r
RootFileHandle = NULL;\r
MapName = NULL;\r
- PatternCopy = AllocateZeroPool(StrSize(FilePattern));\r
+ PatternCopy = AllocateCopyPool(StrSize(FilePattern), FilePattern);\r
if (PatternCopy == NULL) {\r
return (EFI_OUT_OF_RESOURCES);\r
}\r
- StrCpy(PatternCopy, FilePattern);\r
\r
PatternCopy = PathCleanUpDirectories(PatternCopy);\r
\r
CurDir = EfiShellGetCurDir(NULL);\r
ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
+ StrnCatGrow(&Path2, &Path2Size, L"\\", 0);\r
if (*Path == L'\\') {\r
Path++;\r
while (PathRemoveLastItem(Path2)) ;\r
; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
){\r
ASSERT(Node->Key != NULL);\r
- StrCpy(CurrentWriteLocation, Node->Key);\r
+ StrCpyS( CurrentWriteLocation, \r
+ (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)), \r
+ Node->Key\r
+ );\r
CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
}\r
\r
// Allocate the space and recall the get function\r
//\r
Buffer = AllocateZeroPool(Size);\r
- ASSERT(Buffer != NULL);\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
}\r
//\r
FileSystemMapping is not NULL, it returns the current directory associated with the\r
FileSystemMapping. In both cases, the returned name includes the file system\r
mapping (i.e. fs0:\current-dir).\r
+ \r
+ Note that the current directory string should exclude the tailing backslash character.\r
\r
@param FileSystemMapping A pointer to the file system mapping. If NULL,\r
then the current working directory is returned.\r
If the current working directory or the current working file system is changed then the\r
%cwd% environment variable will be updated\r
\r
+ Note that the current directory string should exclude the tailing backslash character.\r
+\r
@param FileSystem A pointer to the file system's mapped name. If NULL, then the current working\r
directory is changed.\r
@param Dir Points to the NULL-terminated directory on the device specified by FileSystem.\r
ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
}\r
- if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
+ if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
- MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+ if (MapListItem->CurrentDirectoryPath != NULL) {\r
+ MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
+ }\r
}\r
} else {\r
//\r
MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
- if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') {\r
+ if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') {\r
ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
- MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+ MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
}\r
}\r
}\r
FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
ASSERT(FixCommand != NULL);\r
\r
- StrnCpy(FixCommand, Command, StrLen(Command)-4);\r
+ StrnCpyS( FixCommand, \r
+ (StrSize(Command) - 4 * sizeof (CHAR16))/sizeof(CHAR16), \r
+ Command, \r
+ StrLen(Command)-4\r
+ );\r
Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
FreePool(FixCommand);\r
return Status;\r
InternalEfiShellGetListAlias(\r
)\r
{\r
- UINT64 MaxStorSize;\r
- UINT64 RemStorSize;\r
- UINT64 MaxVarSize;\r
+ \r
EFI_STATUS Status;\r
EFI_GUID Guid;\r
CHAR16 *VariableName;\r
UINTN NameSize;\r
+ UINTN NameBufferSize;\r
CHAR16 *RetVal;\r
UINTN RetSize;\r
\r
- Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- VariableName = AllocateZeroPool((UINTN)MaxVarSize);\r
+ NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
+ VariableName = AllocateZeroPool(NameBufferSize);\r
RetSize = 0;\r
RetVal = NULL;\r
\r
VariableName[0] = CHAR_NULL;\r
\r
while (TRUE) {\r
- NameSize = (UINTN)MaxVarSize;\r
+ NameSize = NameBufferSize;\r
Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
if (Status == EFI_NOT_FOUND){\r
break;\r
- }\r
- ASSERT_EFI_ERROR(Status);\r
- if (EFI_ERROR(Status)) {\r
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
+ SHELL_FREE_NON_NULL(VariableName);\r
+ VariableName = AllocateZeroPool(NameBufferSize);\r
+ if (VariableName == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ SHELL_FREE_NON_NULL(RetVal);\r
+ RetVal = NULL;\r
+ break;\r
+ }\r
+ \r
+ NameSize = NameBufferSize;\r
+ Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
+ }\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ SHELL_FREE_NON_NULL(RetVal);\r
+ RetVal = NULL;\r
break;\r
}\r
+ \r
if (CompareGuid(&Guid, &gShellAliasGuid)){\r
ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
} // compare guid\r
} // while\r
- FreePool(VariableName);\r
+ SHELL_FREE_NON_NULL(VariableName);\r
\r
return (RetVal);\r
}\r
\r
@return The null-terminated string converted into all lowercase. \r
**/\r
-STATIC CHAR16 *\r
+CHAR16 *\r
ToLower (\r
CHAR16 *Str\r
)\r
UINT32 Attribs;\r
EFI_STATUS Status;\r
CHAR16 *AliasLower;\r
+ CHAR16 *AliasVal;\r
\r
// Convert to lowercase to make aliases case-insensitive\r
if (Alias != NULL) {\r
ToLower (AliasLower);\r
\r
if (Volatile == NULL) {\r
- return (AddBufferToFreeList(GetVariable(AliasLower, &gShellAliasGuid)));\r
+ GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
+ return (AddBufferToFreeList(AliasVal));\r
}\r
RetSize = 0;\r
RetVal = NULL;\r
\r
// Pure FILE_HANDLE operations are passed to FileHandleLib\r
// these functions are indicated by the *\r
-EFI_SHELL_PROTOCOL21 mShellProtocol = {\r
+EFI_SHELL_PROTOCOL mShellProtocol = {\r
EfiShellExecute,\r
EfiShellGetEnv,\r
EfiShellSetEnv,\r
EfiShellOpenRoot,\r
EfiShellOpenRootByHandle,\r
NULL,\r
- 2, // SHELL_MAJOR_VERSION,\r
- 1, // SHELL_MINOR_VERSION,\r
+ SHELL_MAJOR_VERSION,\r
+ SHELL_MINOR_VERSION,\r
\r
// New for UEFI Shell 2.1\r
EfiShellRegisterGuidName,\r
EFI_STATUS\r
EFIAPI\r
CreatePopulateInstallShellProtocol (\r
- IN OUT EFI_SHELL_PROTOCOL21 **NewShell\r
+ IN OUT EFI_SHELL_PROTOCOL **NewShell\r
)\r
{\r
EFI_STATUS Status;\r
EFI_STATUS\r
EFIAPI\r
CleanUpShellProtocol (\r
- IN OUT EFI_SHELL_PROTOCOL21 *NewShell\r
+ IN OUT EFI_SHELL_PROTOCOL *NewShell\r
)\r
{\r
EFI_STATUS Status;\r