]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg: Per UEFI Shell 2.2 SPEC to make Shell supports 'NoNesting'.
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index 22d398757fb59d64418c3610a35f6d947ace9d4e..2cb7befe29ea49031419545cdd69fe538b861ad8 100644 (file)
@@ -3,7 +3,7 @@
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
-  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2016, 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
@@ -1588,6 +1588,109 @@ FreeAlloc:
 \r
   return(Status);\r
 }\r
+\r
+/**\r
+  internal worker function to load and run an image in the current shell.\r
+\r
+  @param CommandLine            Points to the NULL-terminated UCS-2 encoded string\r
+                                containing the command line. If NULL then the command-\r
+                                line will be empty.\r
+  @param Environment            Points to a NULL-terminated array of environment\r
+                                variables with the format 'x=y', where x is the\r
+                                environment variable name and y is the value. If this\r
+                                is NULL, then the current shell environment is used.\r
+                \r
+  @param[out] StartImageStatus  Returned status from the command line.\r
+\r
+  @retval EFI_SUCCESS       The command executed successfully. The  status code\r
+                            returned by the command is pointed to by StatusCode.\r
+  @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES Out of resources.\r
+  @retval EFI_UNSUPPORTED   Nested shell invocations are not allowed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalShellExecute(\r
+  IN CONST CHAR16                   *CommandLine OPTIONAL,\r
+  IN CONST CHAR16                   **Environment OPTIONAL,\r
+  OUT EFI_STATUS                    *StartImageStatus OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanupStatus;\r
+  LIST_ENTRY                    OrigEnvs;\r
+\r
+  InitializeListHead(&OrigEnvs);\r
+\r
+  //\r
+  // Save our current environment settings for later restoration if necessary\r
+  //\r
+  if (Environment != NULL) {\r
+    Status = GetEnvironmentVariableList(&OrigEnvs);\r
+    if (!EFI_ERROR(Status)) {\r
+      Status = SetEnvironmentVariables(Environment);\r
+    } else {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = RunShellCommand(CommandLine, StartImageStatus);\r
+\r
+  // Restore environment variables\r
+  if (!IsListEmpty(&OrigEnvs)) {\r
+    CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+    ASSERT_EFI_ERROR (CleanupStatus);\r
+  }\r
+\r
+  return(Status);\r
+}\r
+\r
+/**\r
+  Determine if the UEFI Shell is currently running with nesting enabled or disabled.\r
+\r
+  @retval FALSE   nesting is required\r
+  @retval other   nesting is enabled\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+NestingEnabled(\r
+)\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR16      *Temp;\r
+  CHAR16      *Temp2;\r
+  UINTN       TempSize;\r
+  BOOLEAN     RetVal;\r
+\r
+  RetVal = TRUE;\r
+  Temp   = NULL;\r
+  Temp2  = NULL;\r
+\r
+  if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
+    TempSize = 0;\r
+    Temp     = NULL;\r
+    Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Temp = AllocateZeroPool(TempSize + sizeof(CHAR16));\r
+      if (Temp != NULL) {\r
+        Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
+      }\r
+    }\r
+    Temp2 = StrnCatGrow(&Temp2, NULL, mNoNestingTrue, 0);\r
+    if (Temp != NULL && Temp2 != NULL && StringNoCaseCompare(&Temp, &Temp2) == 0) {\r
+      //\r
+      // Use the no nesting method.\r
+      //\r
+      RetVal = FALSE;\r
+    }\r
+  }\r
+\r
+  SHELL_FREE_NON_NULL(Temp);\r
+  SHELL_FREE_NON_NULL(Temp2);\r
+  return (RetVal);\r
+}\r
+\r
 /**\r
   Execute the command line.\r
 \r
@@ -1611,7 +1714,7 @@ FreeAlloc:
                             variables with the format 'x=y', where x is the\r
                             environment variable name and y is the value. If this\r
                             is NULL, then the current shell environment is used.\r
-  @param StatusCode         Points to the status code returned by the command.\r
+  @param StatusCode         Points to the status code returned by the CommandLine.\r
 \r
   @retval EFI_SUCCESS       The command executed successfully. The  status code\r
                             returned by the command is pointed to by StatusCode.\r
@@ -1643,11 +1746,9 @@ EfiShellExecute(
     return (EFI_UNSUPPORTED);\r
   }\r
 \r
-  if (Environment != NULL) {\r
-    // If Environment isn't null, load a new image of the shell with its own\r
-    // environment\r
+  if (NestingEnabled()) {\r
     DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
\r
+\r
     DEBUG_CODE_BEGIN();\r
     Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
     FreePool(Temp);\r
@@ -1676,19 +1777,10 @@ EfiShellExecute(
     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
-    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
+    Status = InternalShellExecute(\r
+      (CONST CHAR16*)CommandLine,\r
+      (CONST CHAR16**)Environment,\r
+      StatusCode);\r
   }\r
 \r
   return(Status);\r
@@ -2814,6 +2906,11 @@ EfiShellSetEnv(
         gUnicodeCollation,\r
         (CHAR16*)Name,\r
         L"uefiversion") == 0\r
+    ||(!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
+      gUnicodeCollation->StriColl(\r
+        gUnicodeCollation,\r
+        (CHAR16*)Name,\r
+        (CHAR16*)mNoNestingEnvVarName) == 0)\r
        ){\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
@@ -2827,7 +2924,7 @@ EfiShellSetEnv(
   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
+\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
@@ -2981,7 +3078,7 @@ EfiShellSetCurDir(
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
       if (MapListItem->CurrentDirectoryPath != NULL) {\r
         MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
-      }\r
+    }\r
     }\r
   } else {\r
     //\r