]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
Roll back check in r15180 which caused the shell always returns EFI_ABORTED no matter...
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index e4680139d0b1ad30a7b305debd8e1d4c001f3fce..b0303962ff6939cb3771452973b6c537360aba74 100644 (file)
@@ -2,6 +2,7 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
+  (C) Copyright 2014, Hewlett-Packard Development Company, L.P.\r
   Copyright (c) 2009 - 2014, 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
@@ -460,6 +461,7 @@ EfiShellGetFilePathFromDevicePath(
           ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
 \r
           AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
+          ASSERT (AlignedNode != NULL);\r
 \r
           // File Path Device Path Nodes 'can optionally add a "\" separator to\r
           //  the beginning and/or the end of the Path Name string.'\r
@@ -528,18 +530,17 @@ EfiShellGetDevicePathFromFilePath(
     if (Cwd == NULL) {\r
       return (NULL);\r
     }\r
-    Size = StrSize(Cwd);\r
-    Size += StrSize(Path);\r
+    Size = StrSize(Cwd) + StrSize(Path) - sizeof(CHAR16);\r
     NewPath = AllocateZeroPool(Size);\r
     if (NewPath == NULL) {\r
       return (NULL);\r
     }\r
-    StrCpy(NewPath, Cwd);\r
+    StrnCpy(NewPath, Cwd, Size/sizeof(CHAR16)-1);\r
     if (*Path == L'\\') {\r
       Path++;\r
       while (PathRemoveLastItem(NewPath)) ;\r
     }\r
-    StrCat(NewPath, Path);\r
+    StrnCat(NewPath, Path, Size/sizeof(CHAR16) - 1 - StrLen(NewPath));\r
     DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
     FreePool(NewPath);\r
     return (DevicePathForReturn);\r
@@ -1144,12 +1145,39 @@ EfiShellCreateFile(
     return (EFI_NOT_FOUND);\r
   }\r
 \r
-  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs); // 0 = no specific file attributes\r
+  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);\r
   FreePool(DevicePath);\r
 \r
   return(Status);\r
 }\r
 \r
+/**\r
+  Register a GUID and a localized human readable name for it.\r
+\r
+  If Guid is not assigned a name, then assign GuidName to Guid.  This list of GUID\r
+  names must be used whenever a shell command outputs GUID information.\r
+\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
+\r
+  @param[in] Guid       A pointer to the GUID being registered.\r
+  @param[in] GuidName   A pointer to the localized name for the GUID being registered.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_ACCESS_DENIED       Guid already is assigned a name.\r
+**/\r
+EFI_STATUS\r
+EFIAPI \r
+EfiShellRegisterGuidName(\r
+  IN CONST EFI_GUID *Guid,\r
+  IN CONST CHAR16   *GuidName\r
+  )\r
+{\r
+  return (AddNewGuidNameMapping(Guid, GuidName, NULL));\r
+}\r
+\r
 /**\r
   Opens a file or a directory by file name.\r
 \r
@@ -1317,6 +1345,8 @@ EfiShellDeleteFileByName(
   SHELL_FILE_HANDLE FileHandle;\r
   EFI_STATUS        Status;\r
 \r
+  FileHandle = NULL;\r
+\r
   //\r
   // get a handle to the file\r
   //\r
@@ -1371,8 +1401,6 @@ EfiShellEnablePageBreak (
                                 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
@@ -1387,9 +1415,7 @@ InternalShellExecuteDevicePath(
   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
@@ -1399,18 +1425,10 @@ InternalShellExecuteDevicePath(
   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
@@ -1419,6 +1437,17 @@ InternalShellExecuteDevicePath(
   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
@@ -1448,9 +1477,9 @@ InternalShellExecuteDevicePath(
 \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
@@ -1469,7 +1498,7 @@ InternalShellExecuteDevicePath(
     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
@@ -1504,13 +1533,13 @@ InternalShellExecuteDevicePath(
     ///@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
@@ -1548,6 +1577,8 @@ FreeAlloc:
     ASSERT_EFI_ERROR (CleanupStatus);\r
   }\r
 \r
+  FreePool (NewCmdLine);\r
+\r
   return(Status);\r
 }\r
 /**\r
@@ -1597,8 +1628,6 @@ EfiShellExecute(
   CHAR16                    *Temp;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   UINTN                     Size;\r
-  UINTN                     ExitDataSize;\r
-  CHAR16                    *ExitData;\r
 \r
   if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
     return (EFI_UNSUPPORTED);\r
@@ -1626,32 +1655,7 @@ EfiShellExecute(
     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
+    StatusCode);\r
 \r
   //\r
   // de-allocate and return\r
@@ -1815,10 +1819,9 @@ InternalDuplicateShellFileInfo(
   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
@@ -1834,9 +1837,6 @@ InternalDuplicateShellFileInfo(
   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
@@ -1959,6 +1959,7 @@ EfiShellFindFilesInDir(
   UINTN                     Size;\r
   CHAR16                    *TempSpot;\r
 \r
+  BasePath = NULL;\r
   Status = FileHandleGetFileName(FileDirHandle, &BasePath);\r
   if (EFI_ERROR(Status)) {\r
     return (Status);\r
@@ -2025,6 +2026,87 @@ EfiShellFindFilesInDir(
   return(Status);\r
 }\r
 \r
+/**\r
+  Get the GUID value from a human readable name.\r
+\r
+  If GuidName is a known GUID name, then update Guid to have the correct value for\r
+  that GUID.\r
+\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
+\r
+  @param[in]  GuidName   A pointer to the localized name for the GUID being queried.\r
+  @param[out] Guid       A pointer to the GUID structure to be filled in.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_NOT_FOUND           GuidName is not a known GUID Name.\r
+**/\r
+EFI_STATUS\r
+EFIAPI \r
+EfiShellGetGuidFromName(\r
+  IN  CONST CHAR16   *GuidName,\r
+  OUT       EFI_GUID *Guid\r
+  )\r
+{\r
+  EFI_GUID    *NewGuid;\r
+  EFI_STATUS  Status;\r
+\r
+  if (Guid == NULL || GuidName == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
\r
+  Status = GetGuidFromStringName(GuidName, NULL, &NewGuid);\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyGuid(NewGuid, Guid);\r
+  }\r
+\r
+  return (Status);\r
+}\r
+\r
+/**\r
+  Get the human readable name for a GUID from the value.\r
+\r
+  If Guid is assigned a name, then update *GuidName to point to the name. The callee\r
+  should not modify the value.\r
+\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
+\r
+  @param[in]  Guid       A pointer to the GUID being queried.\r
+  @param[out] GuidName   A pointer to a pointer the localized to name for the GUID being requested\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_NOT_FOUND           Guid is not assigned a name.\r
+**/\r
+EFI_STATUS\r
+EFIAPI \r
+EfiShellGetGuidName(\r
+  IN  CONST EFI_GUID *Guid,\r
+  OUT CONST CHAR16   **GuidName\r
+  )\r
+{\r
+  CHAR16   *Name;\r
+\r
+  if (Guid == NULL || GuidName == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  Name = GetStringNameFromGuid(Guid, NULL);\r
+  if (Name == NULL || StrLen(Name) == 0) {\r
+    SHELL_FREE_NON_NULL(Name);\r
+    return (EFI_NOT_FOUND);\r
+  }\r
+\r
+  *GuidName = AddBufferToFreeList(Name);\r
+\r
+  return (EFI_SUCCESS);\r
+}\r
+\r
 /**\r
   Updates a file name to be preceeded by the mapped drive name\r
 \r
@@ -2200,8 +2282,8 @@ ShellSearchHandle(
             if (NewFullName == NULL) {\r
               Status = EFI_OUT_OF_RESOURCES;\r
             } else {\r
-              StrCpy(NewFullName, MapName);\r
-              StrCat(NewFullName, ShellInfoNode->FullName+1);\r
+              StrnCpy(NewFullName, MapName, Size/sizeof(CHAR16)-1);\r
+              StrnCat(NewFullName, ShellInfoNode->FullName+1, (Size/sizeof(CHAR16))-StrLen(NewFullName)-1);\r
               FreePool((VOID*)ShellInfoNode->FullName);\r
               ShellInfoNode->FullName = NewFullName;\r
             }\r
@@ -2324,11 +2406,10 @@ EfiShellFindFiles(
   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
@@ -2457,34 +2538,32 @@ EfiShellOpenFileList(
 }\r
 \r
 /**\r
-  This function updated with errata.\r
-\r
-  Gets either a single or list of environment variables.\r
-\r
-  If name is not NULL then this function returns the current value of the specified\r
-  environment variable.\r
-\r
-  If Name is NULL, then a list of all environment variable names is returned.  Each is a\r
-  NULL terminated string with a double NULL terminating the list.\r
-\r
-  @param Name                   A pointer to the environment variable name.  If\r
-                                Name is NULL, then the function will return all\r
-                                of the defined shell environment variables.  In\r
-                                the case where multiple environment variables are\r
-                                being returned, each variable will be terminated by\r
-                                a NULL, and the list will be terminated by a double\r
-                                NULL.\r
-\r
-  @return !=NULL                A pointer to the returned string.\r
-                                The returned pointer does not need to be freed by the caller.\r
-\r
-  @retval NULL                  The environment variable doesn't exist or there are\r
-                                no environment variables.\r
+  Gets the environment variable and Attributes, or list of environment variables.  Can be\r
+  used instead of GetEnv().\r
+\r
+  This function returns the current value of the specified environment variable and\r
+  the Attributes. If no variable name was specified, then all of the known\r
+  variables will be returned.\r
+\r
+  @param[in] Name               A pointer to the environment variable name. If Name is NULL,\r
+                                then the function will return all of the defined shell\r
+                                environment variables. In the case where multiple environment\r
+                                variables are being returned, each variable will be terminated\r
+                                by a NULL, and the list will be terminated by a double NULL.\r
+  @param[out] Attributes        If not NULL, a pointer to the returned attributes bitmask for\r
+                                the environment variable. In the case where Name is NULL, and\r
+                                multiple environment variables are being returned, Attributes\r
+                                is undefined.\r
+\r
+  @retval NULL                  The environment variable doesn't exist.\r
+  @return                       A non-NULL value points to the variable's value. The returned\r
+                                pointer does not need to be freed by the caller.\r
 **/\r
 CONST CHAR16 *\r
-EFIAPI\r
-EfiShellGetEnv(\r
-  IN CONST CHAR16 *Name\r
+EFIAPI \r
+EfiShellGetEnvEx(\r
+  IN  CONST CHAR16 *Name,\r
+  OUT       UINT32 *Attributes OPTIONAL\r
   )\r
 {\r
   EFI_STATUS  Status;\r
@@ -2534,7 +2613,7 @@ EfiShellGetEnv(
       ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
      ){\r
       ASSERT(Node->Key != NULL);\r
-      StrCpy(CurrentWriteLocation, Node->Key);\r
+      StrnCpy(CurrentWriteLocation, Node->Key,  (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)) - 1);\r
       CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
     }\r
 \r
@@ -2552,14 +2631,13 @@ EfiShellGetEnv(
     //\r
     // get the size we need for this EnvVariable\r
     //\r
-    Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer);\r
+    Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
     if (Status == EFI_BUFFER_TOO_SMALL) {\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(Name, &Size, Buffer);\r
+      Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
     }\r
     //\r
     // we didnt get it (might not exist)\r
@@ -2579,6 +2657,38 @@ EfiShellGetEnv(
   return (AddBufferToFreeList(Buffer));\r
 }\r
 \r
+/**\r
+  Gets either a single or list of environment variables.\r
+\r
+  If name is not NULL then this function returns the current value of the specified\r
+  environment variable.\r
+\r
+  If Name is NULL, then a list of all environment variable names is returned.  Each is a\r
+  NULL terminated string with a double NULL terminating the list.\r
+\r
+  @param Name                   A pointer to the environment variable name.  If\r
+                                Name is NULL, then the function will return all\r
+                                of the defined shell environment variables.  In\r
+                                the case where multiple environment variables are\r
+                                being returned, each variable will be terminated by\r
+                                a NULL, and the list will be terminated by a double\r
+                                NULL.\r
+\r
+  @retval !=NULL                A pointer to the returned string.\r
+                                The returned pointer does not need to be freed by the caller.\r
+\r
+  @retval NULL                  The environment variable doesn't exist or there are\r
+                                no environment variables.\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetEnv(\r
+  IN CONST CHAR16 *Name\r
+  )\r
+{\r
+  return (EfiShellGetEnvEx(Name, NULL));\r
+}\r
+\r
 /**\r
   Internal variable setting function.  Allows for setting of the read only variables.\r
 \r
@@ -3044,7 +3154,7 @@ InternalEfiShellGetListAlias(
   \r
   @return        The null-terminated string converted into all lowercase.  \r
 **/\r
-STATIC CHAR16 *\r
+CHAR16 *\r
 ToLower (\r
   CHAR16 *Str\r
   )\r
@@ -3279,7 +3389,13 @@ EFI_SHELL_PROTOCOL         mShellProtocol = {
   EfiShellOpenRootByHandle,\r
   NULL,\r
   SHELL_MAJOR_VERSION,\r
-  SHELL_MINOR_VERSION\r
+  SHELL_MINOR_VERSION,\r
+\r
+  // New for UEFI Shell 2.1\r
+  EfiShellRegisterGuidName,\r
+  EfiShellGetGuidName,\r
+  EfiShellGetGuidFromName,\r
+  EfiShellGetEnvEx\r
 };\r
 \r
 /**\r