]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg: Make Argv[0] the full file path of the command
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index 214693f2ae37dbeff58762930eab5740c5b42d5e..502713770501158cf80c12e596f6a5bc2b4eef38 100644 (file)
@@ -2,7 +2,7 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\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
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -14,7 +14,6 @@
 **/\r
 \r
 #include "Shell.h"\r
-#include <Library/FileHandleLib.h>\r
 \r
 /**\r
   Close an open file handle.\r
@@ -34,7 +33,37 @@ EfiShellClose (
   )\r
 {\r
   ShellFileHandleRemove(FileHandle);\r
-  return (FileHandleClose(FileHandle));\r
+  return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle)));\r
+}\r
+\r
+/**\r
+  Internal worker to determine whether there is a BlockIo somewhere\r
+  upon the device path specified.\r
+\r
+  @param[in] DevicePath    The device path to test.\r
+\r
+  @retval TRUE      gEfiBlockIoProtocolGuid was installed on a handle with this device path\r
+  @retval FALSE     gEfiBlockIoProtocolGuid was not found.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+InternalShellProtocolIsBlockIoPresent(\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathCopy;\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                Handle;\r
+\r
+  Handle = NULL;\r
+\r
+  DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;\r
+  Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);\r
+\r
+  if ((Handle != NULL) && (!EFI_ERROR(Status))) {\r
+    return (TRUE);\r
+  }\r
+  return (FALSE);\r
 }\r
 \r
 /**\r
@@ -86,27 +115,19 @@ InternalShellProtocolDebugPrintMessage (
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
   )\r
 {\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
   EFI_STATUS                        Status;\r
   CHAR16                            *Temp;\r
 \r
   Status = EFI_SUCCESS;\r
   DEBUG_CODE_BEGIN();\r
-  DevicePathToText = NULL;\r
 \r
-  Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid,\r
-                               NULL,\r
-                               (VOID**)&DevicePathToText);\r
   if (Mapping != NULL) {\r
     DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));\r
   }\r
-  if (!EFI_ERROR(Status)) {\r
-    if (DevicePath != NULL) {\r
-      Temp = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-      DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
-      FreePool(Temp);\r
-    }\r
-  }\r
+  Temp = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+  DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
+  FreePool(Temp);\r
+\r
   DEBUG_CODE_END();\r
   return (Status);\r
 }\r
@@ -176,7 +197,8 @@ EfiShellSetMap(
   // make sure this is a valid to add device path\r
   //\r
   ///@todo add BlockIo to this test...\r
-  if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)) {\r
+  if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)\r
+    && !InternalShellProtocolIsBlockIoPresent(DevicePath)) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
@@ -386,6 +408,7 @@ EfiShellGetFilePathFromDevicePath(
   EFI_HANDLE                      MapHandle;\r
   EFI_STATUS                      Status;\r
   FILEPATH_DEVICE_PATH            *FilePath;\r
+  FILEPATH_DEVICE_PATH            *AlignedNode;\r
 \r
   PathForReturn = NULL;\r
   PathSize = 0;\r
@@ -435,8 +458,22 @@ EfiShellGetFilePathFromDevicePath(
           // append the path part onto the filepath.\r
           //\r
           ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L"\\", 1);\r
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, FilePath->PathName, 0);\r
+\r
+          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\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
+          // (UEFI Spec 2.4 section 9.3.6.4).\r
+          // If necessary, add a "\", but otherwise don't\r
+          // (This is specified in the above section, and also implied by the\r
+          //  UEFI Shell spec section 3.7)\r
+          if ((PathForReturn[PathSize - 1] != L'\\') &&\r
+              (AlignedNode->PathName[0]    != L'\\')) {\r
+            PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
+          }\r
+\r
+          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
+          FreePool(AlignedNode);\r
         }\r
       } // for loop of remaining nodes\r
     }\r
@@ -453,10 +490,12 @@ EfiShellGetFilePathFromDevicePath(
   This function converts a file system style name to a device path, by replacing any\r
   mapping references to the associated device path.\r
 \r
-  @param Path                   the pointer to the path\r
+  @param[in] Path               The pointer to the path.\r
 \r
-  @return all                   The pointer of the file path. The file path is callee\r
+  @return                       The pointer of the file path. The file path is callee\r
                                 allocated and should be freed by the caller.\r
+  @retval NULL                  The path could not be found.\r
+  @retval NULL                  There was not enough available memory.\r
 **/\r
 EFI_DEVICE_PATH_PROTOCOL *\r
 EFIAPI\r
@@ -475,8 +514,12 @@ EfiShellGetDevicePathFromFilePath(
   EFI_HANDLE                      Handle;\r
   EFI_STATUS                      Status;\r
 \r
+  if (Path == NULL) {\r
+    return (NULL);\r
+  }\r
+\r
   MapName = NULL;\r
-  ASSERT(Path != NULL);\r
+  NewPath = NULL;\r
 \r
   if (StrStr(Path, L":") == NULL) {\r
     Cwd = EfiShellGetCurDir(NULL);\r
@@ -486,10 +529,13 @@ EfiShellGetDevicePathFromFilePath(
     Size = StrSize(Cwd);\r
     Size += StrSize(Path);\r
     NewPath = AllocateZeroPool(Size);\r
-    ASSERT(NewPath != NULL);\r
+    if (NewPath == NULL) {\r
+      return (NULL);\r
+    }\r
     StrCpy(NewPath, Cwd);\r
-    if (NewPath[StrLen(NewPath)-1] == Path[0] == (CHAR16)L'\\') {\r
-      ((CHAR16*)NewPath)[StrLen(NewPath)-1] = CHAR_NULL;\r
+    if (*Path == L'\\') {\r
+      Path++;\r
+      while (PathRemoveLastItem(NewPath)) ;\r
     }\r
     StrCat(NewPath, Path);\r
     DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
@@ -503,8 +549,7 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   ASSERT((MapName == NULL && Size == 0) || (MapName != NULL));\r
   MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1));\r
-  if (MapName[StrLen(MapName)-1] != L':') {\r
-    ASSERT(FALSE);\r
+  if (MapName == NULL || MapName[StrLen(MapName)-1] != L':') {\r
     return (NULL);\r
   }\r
 \r
@@ -524,7 +569,6 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath);\r
   if (DevicePathCopy == NULL) {\r
-    ASSERT(FALSE);\r
     FreePool(MapName);\r
     return (NULL);\r
   }\r
@@ -545,7 +589,11 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   // build the full device path\r
   //\r
-  DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName)+1);\r
+  if (*(Path+StrLen(MapName)+1) == CHAR_NULL) {\r
+    DevicePathForReturn = FileDevicePath(Handle, L"\\");\r
+  } else {\r
+    DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName));\r
+  }\r
 \r
   FreePool(MapName);\r
   if (DevicePathCopyForFree != NULL) {\r
@@ -602,14 +650,16 @@ EfiShellGetDeviceName(
 {\r
   EFI_STATUS                        Status;\r
   EFI_COMPONENT_NAME2_PROTOCOL      *CompName2;\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
   EFI_HANDLE                        *HandleList;\r
   UINTN                             HandleCount;\r
   UINTN                             LoopVar;\r
   CHAR16                            *DeviceNameToReturn;\r
   CHAR8                             *Lang;\r
-  CHAR8                             *TempChar;\r
+  UINTN                             ParentControllerCount;\r
+  EFI_HANDLE                        *ParentControllerBuffer;\r
+  UINTN                             ParentDriverCount;\r
+  EFI_HANDLE                        *ParentDriverBuffer;\r
 \r
   if (BestDeviceName == NULL ||\r
       DeviceHandle   == NULL\r
@@ -662,17 +712,7 @@ EfiShellGetDeviceName(
       if (EFI_ERROR(Status)) {\r
         continue;\r
       }\r
-      if (Language == NULL) {\r
-        Lang = AllocatePool(AsciiStrSize(CompName2->SupportedLanguages));\r
-        AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
-        TempChar = AsciiStrStr(Lang, ";");\r
-        if (TempChar != NULL){\r
-          *TempChar = CHAR_NULL;\r
-        }\r
-      } else {\r
-        Lang = AllocatePool(AsciiStrSize(Language));\r
-        AsciiStrCpy(Lang, Language);\r
-      }\r
+      Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
       Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
       FreePool(Lang);\r
       Lang = NULL;\r
@@ -683,38 +723,79 @@ EfiShellGetDeviceName(
     if (HandleList != NULL) {\r
       FreePool(HandleList);\r
     }\r
-    if (DeviceNameToReturn != NULL){\r
-      ASSERT(BestDeviceName == NULL);\r
-      StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);\r
-      return (EFI_SUCCESS);\r
+\r
+    //\r
+    // Now check the parent controller using this as the child.\r
+    //\r
+    if (DeviceNameToReturn == NULL){\r
+      PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);\r
+      for (LoopVar = 0 ; LoopVar < ParentControllerCount ; LoopVar++) {\r
+        PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);\r
+        for (HandleCount = 0 ; HandleCount < ParentDriverCount ; HandleCount++) {\r
+          //\r
+          // try using that driver's component name with controller and our driver as the child.\r
+          //\r
+          Status = gBS->OpenProtocol(\r
+            ParentDriverBuffer[HandleCount],\r
+            &gEfiComponentName2ProtocolGuid,\r
+            (VOID**)&CompName2,\r
+            gImageHandle,\r
+            NULL,\r
+            EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+          if (EFI_ERROR(Status)) {\r
+            Status = gBS->OpenProtocol(\r
+              ParentDriverBuffer[HandleCount],\r
+              &gEfiComponentNameProtocolGuid,\r
+              (VOID**)&CompName2,\r
+              gImageHandle,\r
+              NULL,\r
+              EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+          }\r
+\r
+          if (EFI_ERROR(Status)) {\r
+            continue;\r
+          }\r
+          Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
+          Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
+          FreePool(Lang);\r
+          Lang = NULL;\r
+          if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
+            break;\r
+          }\r
+\r
+\r
+\r
+        }\r
+        SHELL_FREE_NON_NULL(ParentDriverBuffer);\r
+        if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
+          break;\r
+        }\r
+      }\r
+      SHELL_FREE_NON_NULL(ParentControllerBuffer);\r
     }\r
     //\r
     // dont return on fail since we will try device path if that bit is on\r
     //\r
+    if (DeviceNameToReturn != NULL){\r
+      ASSERT(BestDeviceName != NULL);\r
+      StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);\r
+      return (EFI_SUCCESS);\r
+    }\r
   }\r
   if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
-    Status = gBS->LocateProtocol(\r
-      &gEfiDevicePathToTextProtocolGuid,\r
+    Status = gBS->OpenProtocol(\r
+      DeviceHandle,\r
+      &gEfiDevicePathProtocolGuid,\r
+      (VOID**)&DevicePath,\r
+      gImageHandle,\r
       NULL,\r
-      (VOID**)&DevicePathToText);\r
-    //\r
-    // we now have the device path to text protocol\r
-    //\r
+      EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
     if (!EFI_ERROR(Status)) {\r
-      Status = gBS->OpenProtocol(\r
-        DeviceHandle,\r
-        &gEfiDevicePathProtocolGuid,\r
-        (VOID**)&DevicePath,\r
-        gImageHandle,\r
-        NULL,\r
-        EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
-      if (!EFI_ERROR(Status)) {\r
-        //\r
-        // use device path to text on the device path\r
-        //\r
-        *BestDeviceName = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-        return (EFI_SUCCESS);\r
-      }\r
+      //\r
+      // use device path to text on the device path\r
+      //\r
+      *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+      return (EFI_SUCCESS);\r
     }\r
   }\r
   //\r
@@ -795,6 +876,7 @@ EfiShellOpenRootByHandle(
                                 could not be opened.\r
   @retval EFI_VOLUME_CORRUPTED  The data structures in the volume were corrupted.\r
   @retval EFI_DEVICE_ERROR      The device had an error\r
+  @retval EFI_INVALID_PARAMETER FileHandle is NULL.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -806,6 +888,10 @@ EfiShellOpenRoot(
   EFI_STATUS Status;\r
   EFI_HANDLE Handle;\r
 \r
+  if (FileHandle == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
   //\r
   // find the handle of the device with that device handle and the file system\r
   //\r
@@ -867,110 +953,121 @@ InternalOpenFileDevicePath(
   SHELL_FILE_HANDLE               ShellHandle;\r
   EFI_FILE_PROTOCOL               *Handle1;\r
   EFI_FILE_PROTOCOL               *Handle2;\r
-  EFI_DEVICE_PATH_PROTOCOL        *DpCopy;\r
+  FILEPATH_DEVICE_PATH            *AlignedNode;\r
 \r
-  ASSERT(FileHandle != NULL);\r
-  *FileHandle = NULL;\r
-  Handle1     = NULL;\r
-  DpCopy      = DevicePath;\r
+  if (FileHandle == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+  *FileHandle   = NULL;\r
+  Handle1       = NULL;\r
+  Handle2       = NULL;\r
+  Handle        = NULL;\r
+  ShellHandle   = NULL;\r
+  FilePathNode  = NULL;\r
+  AlignedNode   = NULL;\r
 \r
   Status = EfiShellOpenRoot(DevicePath, &ShellHandle);\r
 \r
   if (!EFI_ERROR(Status)) {\r
     Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle);\r
-    //\r
-    // chop off the begining part before the file system part...\r
-    //\r
-    ///@todo BlockIo?\r
-    Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
-                                   &DevicePath,\r
-                                   &Handle);\r
-      if (!EFI_ERROR(Status)) {\r
+    if (Handle1 != NULL) {\r
       //\r
-      // To access as a file system, the file path should only\r
-      // contain file path components.  Follow the file path nodes\r
-      // and find the target file\r
+      // chop off the begining part before the file system part...\r
       //\r
-      for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
-          ; !IsDevicePathEnd (&FilePathNode->Header)\r
-          ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
-         ){\r
-        //\r
-        // For file system access each node should be a file path component\r
-        //\r
-        if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
-            DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
-           ) {\r
-          Status = EFI_UNSUPPORTED;\r
-          break;\r
-        }\r
-\r
-        //\r
-        // Open this file path node\r
-        //\r
-        Handle2 = Handle1;\r
-        Handle1 = NULL;\r
-\r
+      ///@todo BlockIo?\r
+      Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
+                                     &DevicePath,\r
+                                     &Handle);\r
+        if (!EFI_ERROR(Status)) {\r
         //\r
-        // if this is the last node in the DevicePath always create (if that was requested).\r
+        // To access as a file system, the file path should only\r
+        // contain file path components.  Follow the file path nodes\r
+        // and find the target file\r
         //\r
-        if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
-          Status = Handle2->Open (\r
-                                Handle2,\r
-                                &Handle1,\r
-                                FilePathNode->PathName,\r
-                                OpenMode,\r
-                                Attributes\r
-                               );\r
-        } else {\r
-\r
+        for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
+            ; !IsDevicePathEnd (&FilePathNode->Header)\r
+            ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
+           ){\r
+          SHELL_FREE_NON_NULL(AlignedNode);\r
+          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode);\r
           //\r
-          //  This is not the last node and we dont want to 'create' existing\r
-          //  directory entries...\r
+          // For file system access each node should be a file path component\r
           //\r
+          if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
+              DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
+             ) {\r
+            Status = EFI_UNSUPPORTED;\r
+            break;\r
+          }\r
 \r
           //\r
-          // open without letting it create\r
-          // prevents error on existing files/directories\r
+          // Open this file path node\r
           //\r
-          Status = Handle2->Open (\r
-                                Handle2,\r
-                                &Handle1,\r
-                                FilePathNode->PathName,\r
-                                OpenMode &~EFI_FILE_MODE_CREATE,\r
-                                Attributes\r
-                               );\r
+          Handle2 = Handle1;\r
+          Handle1 = NULL;\r
+\r
           //\r
-          // if above failed now open and create the 'item'\r
-          // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
+          // if this is the last node in the DevicePath always create (if that was requested).\r
           //\r
-          if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
+          if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
             Status = Handle2->Open (\r
                                   Handle2,\r
                                   &Handle1,\r
-                                  FilePathNode->PathName,\r
+                                  AlignedNode->PathName,\r
                                   OpenMode,\r
                                   Attributes\r
                                  );\r
+          } else {\r
+\r
+            //\r
+            //  This is not the last node and we dont want to 'create' existing\r
+            //  directory entries...\r
+            //\r
+\r
+            //\r
+            // open without letting it create\r
+            // prevents error on existing files/directories\r
+            //\r
+            Status = Handle2->Open (\r
+                                  Handle2,\r
+                                  &Handle1,\r
+                                  AlignedNode->PathName,\r
+                                  OpenMode &~EFI_FILE_MODE_CREATE,\r
+                                  Attributes\r
+                                 );\r
+            //\r
+            // if above failed now open and create the 'item'\r
+            // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
+            //\r
+            if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
+              Status = Handle2->Open (\r
+                                    Handle2,\r
+                                    &Handle1,\r
+                                    AlignedNode->PathName,\r
+                                    OpenMode,\r
+                                    Attributes\r
+                                   );\r
+            }\r
           }\r
-        }\r
-        //\r
-        // Close the last node\r
-        //\r
-        Handle2->Close (Handle2);\r
+          //\r
+          // Close the last node\r
+          //\r
+          ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
 \r
-        //\r
-        // If there's been an error, stop\r
-        //\r
-        if (EFI_ERROR (Status)) {\r
-          break;\r
-        }\r
-      } // for loop\r
+          //\r
+          // If there's been an error, stop\r
+          //\r
+          if (EFI_ERROR (Status)) {\r
+            break;\r
+          }\r
+        } // for loop\r
+      }\r
     }\r
   }\r
+  SHELL_FREE_NON_NULL(AlignedNode);\r
   if (EFI_ERROR(Status)) {\r
     if (Handle1 != NULL) {\r
-      Handle1->Close(Handle1);\r
+      ShellInfoObject.NewEfiShellProtocol->CloseFile(Handle1);\r
     }\r
   } else {\r
     *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle));\r
@@ -1270,7 +1367,9 @@ EfiShellEnablePageBreak (
                             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
+\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
@@ -1285,14 +1384,27 @@ InternalShellExecuteDevicePath(
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
   IN CONST CHAR16                   *CommandLine OPTIONAL,\r
   IN CONST CHAR16                   **Environment OPTIONAL,\r
-  OUT EFI_STATUS                    *StatusCode OPTIONAL\r
+  OUT UINTN                         *ExitDataSize OPTIONAL,\r
+  OUT CHAR16                        **ExitData OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanupStatus;\r
   EFI_HANDLE                    NewHandle;\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
+\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
 \r
   if (ParentImageHandle == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
@@ -1353,38 +1465,76 @@ InternalShellExecuteDevicePath(
     ShellParamsProtocol.StdErr  = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
     Status = UpdateArgcArgv(&ShellParamsProtocol, CommandLine, NULL, NULL);\r
     ASSERT_EFI_ERROR(Status);\r
+    //\r
+    // Replace Argv[0] with the full path of the binary we're executing:\r
+    // If the command line was "foo", the binary might be called "foo.efi".\r
+    // "The first entry in [Argv] is always the full file path of the\r
+    //  executable" - UEFI Shell Spec section 2.3\r
+    //\r
+    ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);\r
+    // The image we're executing isn't necessarily in a filesystem - it might\r
+    // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will\r
+    // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.\r
+    if (ImagePath != NULL) {\r
+      if (ShellParamsProtocol.Argv == NULL) {\r
+        // Command line was empty or null.\r
+        // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)\r
+        ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));\r
+        if (ShellParamsProtocol.Argv == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Cleanup;\r
+        }\r
+        ShellParamsProtocol.Argc = 1;\r
+      } else {\r
+        // Free the string UpdateArgcArgv put in Argv[0];\r
+        FreePool (ShellParamsProtocol.Argv[0]);\r
+      }\r
+      ShellParamsProtocol.Argv[0] = ImagePath;\r
+    }\r
+\r
     Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
     ASSERT_EFI_ERROR(Status);\r
 \r
     ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
 \r
     //\r
-    // now start the image and if the caller wanted the return code pass it to them...\r
+    // now start the image, passing up exit data if the caller requested it\r
     //\r
     if (!EFI_ERROR(Status)) {\r
-      if (StatusCode != NULL) {\r
-        *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);\r
-      } else {\r
-        Status      = gBS->StartImage(NewHandle, NULL, NULL);\r
-      }\r
+      Status      = gBS->StartImage(\r
+                          NewHandle,\r
+                          ExitDataSizePtr,\r
+                          ExitData\r
+                          );\r
     }\r
 \r
     //\r
     // Cleanup (and dont overwrite errors)\r
     //\r
     if (EFI_ERROR(Status)) {\r
-      gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
+      CleanupStatus = gBS->UninstallProtocolInterface(\r
+                            NewHandle,\r
+                            &gEfiShellParametersProtocolGuid,\r
+                            &ShellParamsProtocol\r
+                            );\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     } else {\r
-      Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
-      ASSERT_EFI_ERROR(Status);\r
+      CleanupStatus = gBS->UninstallProtocolInterface(\r
+                            NewHandle,\r
+                            &gEfiShellParametersProtocolGuid,\r
+                            &ShellParamsProtocol\r
+                            );\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     }\r
   }\r
 \r
   if (!IsListEmpty(&OrigEnvs)) {\r
     if (EFI_ERROR(Status)) {\r
-      SetEnvironmentVariableList(&OrigEnvs);\r
+      CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
     } else {\r
-      Status = SetEnvironmentVariableList(&OrigEnvs);\r
+      CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+      ASSERT_EFI_ERROR (CleanupStatus);\r
     }\r
   }\r
 \r
@@ -1437,6 +1587,8 @@ 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
@@ -1445,18 +1597,18 @@ EfiShellExecute(
   DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
 \r
   DEBUG_CODE_BEGIN();\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+  Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
   FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+  Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
   FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(DevPath, TRUE, TRUE);\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 ", 0);\r
+  StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
   StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
 \r
   Status = InternalShellExecuteDevicePath(\r
@@ -1464,7 +1616,33 @@ 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
+    } else if ((StatusCode != NULL) && !EFI_ERROR(Status)) {\r
+      *StatusCode = EFI_SUCCESS;\r
+    }\r
 \r
   //\r
   // de-allocate and return\r
@@ -1533,6 +1711,8 @@ EfiShellFreeFileList(
     RemoveEntryList(&ShellFileListItem->Link);\r
     InternalFreeShellFileInfoNode(ShellFileListItem);\r
   }\r
+  InternalFreeShellFileInfoNode(*FileList);\r
+  *FileList = NULL;\r
   return(EFI_SUCCESS);\r
 }\r
 \r
@@ -1554,6 +1734,7 @@ EfiShellRemoveDupInFileList(
 {\r
   EFI_SHELL_FILE_INFO *ShellFileListItem;\r
   EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
+  EFI_SHELL_FILE_INFO *TempNode;\r
 \r
   if (FileList == NULL || *FileList == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
@@ -1571,8 +1752,15 @@ EfiShellRemoveDupInFileList(
             (CHAR16*)ShellFileListItem->FullName,\r
             (CHAR16*)ShellFileListItem2->FullName) == 0\r
          ){\r
+        TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode(\r
+                                            &(*FileList)->Link,\r
+                                            &ShellFileListItem2->Link\r
+                                            );\r
         RemoveEntryList(&ShellFileListItem2->Link);\r
         InternalFreeShellFileInfoNode(ShellFileListItem2);\r
+        // Set ShellFileListItem2 to PreviousNode so we don't access Freed\r
+        // memory in GetNextNode in the loop expression above.\r
+        ShellFileListItem2 = TempNode;\r
       }\r
     }\r
   }\r
@@ -1596,14 +1784,14 @@ InternalDuplicateShellFileInfo(
 {\r
   EFI_SHELL_FILE_INFO *NewNode;\r
 \r
-  NewNode = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+  NewNode = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\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     = AllocatePool((UINTN)Node->Info->Size);\r
+  NewNode->Info     = AllocateZeroPool((UINTN)Node->Info->Size);\r
   if ( NewNode->FullName == NULL\r
     || NewNode->FileName == NULL\r
     || NewNode->Info == NULL\r
@@ -1628,7 +1816,6 @@ InternalDuplicateShellFileInfo(
 \r
   @param[in] BasePath         the Path to prepend onto filename for FullPath\r
   @param[in] Status           Status member initial value.\r
-  @param[in] FullName         FullName member initial value.\r
   @param[in] FileName         FileName member initial value.\r
   @param[in] Handle           Handle member initial value.\r
   @param[in] Info             Info struct to copy.\r
@@ -1641,7 +1828,6 @@ EFIAPI
 CreateAndPopulateShellFileInfo(\r
   IN CONST CHAR16 *BasePath,\r
   IN CONST EFI_STATUS Status,\r
-  IN CONST CHAR16 *FullName,\r
   IN CONST CHAR16 *FileName,\r
   IN CONST SHELL_FILE_HANDLE Handle,\r
   IN CONST EFI_FILE_INFO *Info\r
@@ -1658,7 +1844,7 @@ CreateAndPopulateShellFileInfo(
   if (ShellFileListItem == NULL) {\r
     return (NULL);\r
   }\r
-  if (Info != NULL) {\r
+  if (Info != NULL && Info->Size != 0) {\r
     ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size);\r
     if (ShellFileListItem->Info == NULL) {\r
       FreePool(ShellFileListItem);\r
@@ -1749,6 +1935,10 @@ EfiShellFindFilesInDir(
     TempString        = NULL;\r
     Size              = 0;\r
     TempString        = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);\r
+    if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
+      return (EFI_OUT_OF_RESOURCES);\r
+    }\r
     TempSpot          = StrStr(TempString, L";");\r
 \r
     if (TempSpot != NULL) {\r
@@ -1756,6 +1946,11 @@ EfiShellFindFilesInDir(
     }\r
 \r
     TempString        = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
+    if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
+      return (EFI_OUT_OF_RESOURCES);\r
+    }\r
+    SHELL_FREE_NON_NULL(BasePath);\r
     BasePath          = TempString;\r
   }\r
 \r
@@ -1770,20 +1965,14 @@ EfiShellFindFilesInDir(
       ; !EFI_ERROR(Status) && !NoFile\r
       ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)\r
      ){\r
-    TempString  = NULL;\r
-    Size        = 0;\r
     //\r
     // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
     //\r
-    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
-    TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
-    TempString = StrnCatGrow(&TempString, &Size, FileInfo->FileName, 0);\r
     ShellFileListItem = CreateAndPopulateShellFileInfo(\r
       BasePath,\r
-      EFI_SUCCESS, // success since we didnt fail to open it...\r
-      TempString,\r
+      EFI_SUCCESS,  // success since we didnt fail to open it...\r
       FileInfo->FileName,\r
-      NULL, // no handle since not open\r
+      NULL,         // no handle since not open\r
       FileInfo);\r
 \r
     if (ShellFileList == NULL) {\r
@@ -1806,8 +1995,8 @@ EfiShellFindFilesInDir(
 /**\r
   Updates a file name to be preceeded by the mapped drive name\r
 \r
-  @param[in] BasePath     the Mapped drive name to prepend\r
-  @param[in,out] Path     pointer to pointer to the file name to update.\r
+  @param[in] BasePath      the Mapped drive name to prepend\r
+  @param[in, out] Path     pointer to pointer to the file name to update.\r
 \r
   @retval EFI_SUCCESS\r
   @retval EFI_OUT_OF_RESOURCES\r
@@ -1859,19 +2048,15 @@ UpdateFileName(
   If FileHandle is a file and matches all of the remaining Pattern (which would be\r
   on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.\r
 \r
-  if FileList is NULL, then ASSERT\r
-  if FilePattern is NULL, then ASSERT\r
-  if UnicodeCollation is NULL, then ASSERT\r
-  if FileHandle is NULL, then ASSERT\r
-\r
   Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
   FreeFileList with FileList.\r
 \r
-  @param[in] FilePattern        The FilePattern to check against.\r
-  @param[in] UnicodeCollation   The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
-  @param[in] FileHandle         The FileHandle to start with\r
-  @param[in,out] FileList       pointer to pointer to list of found files.\r
-  @param[in] ParentNode         The node for the parent. Same file as identified by HANDLE.\r
+  @param[in] FilePattern         The FilePattern to check against.\r
+  @param[in] UnicodeCollation    The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
+  @param[in] FileHandle          The FileHandle to start with\r
+  @param[in, out] FileList       pointer to pointer to list of found files.\r
+  @param[in] ParentNode          The node for the parent. Same file as identified by HANDLE.\r
+  @param[in] MapName             The file system name this file is on.\r
 \r
   @retval EFI_SUCCESS           all files were found and the FileList contains a list.\r
   @retval EFI_NOT_FOUND         no files were found\r
@@ -1884,7 +2069,8 @@ ShellSearchHandle(
   IN           EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
   IN           SHELL_FILE_HANDLE              FileHandle,\r
   IN OUT       EFI_SHELL_FILE_INFO            **FileList,\r
-  IN     CONST EFI_SHELL_FILE_INFO            *ParentNode OPTIONAL\r
+  IN     CONST EFI_SHELL_FILE_INFO            *ParentNode OPTIONAL,\r
+  IN     CONST CHAR16                         *MapName\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -1894,6 +2080,8 @@ ShellSearchHandle(
   EFI_SHELL_FILE_INFO *ShellInfoNode;\r
   EFI_SHELL_FILE_INFO *NewShellNode;\r
   BOOLEAN             Directory;\r
+  CHAR16              *NewFullName;\r
+  UINTN               Size;\r
 \r
   if ( FilePattern      == NULL\r
     || UnicodeCollation == NULL\r
@@ -1931,7 +2119,7 @@ ShellSearchHandle(
       } else {\r
         NewShellNode->Handle = NULL;\r
         if (*FileList == NULL) {\r
-          *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+          *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
           InitializeListHead(&((*FileList)->Link));\r
         }\r
 \r
@@ -1957,7 +2145,20 @@ ShellSearchHandle(
           ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link)\r
          ){\r
         if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){\r
-          if (Directory){\r
+          if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) {\r
+            Size = StrSize(ShellInfoNode->FullName);\r
+            Size += StrSize(MapName) + sizeof(CHAR16);\r
+            NewFullName = AllocateZeroPool(Size);\r
+            if (NewFullName == NULL) {\r
+              Status = EFI_OUT_OF_RESOURCES;\r
+            } else {\r
+              StrCpy(NewFullName, MapName);\r
+              StrCat(NewFullName, ShellInfoNode->FullName+1);\r
+              FreePool((VOID*)ShellInfoNode->FullName);\r
+              ShellInfoNode->FullName = NewFullName;\r
+            }\r
+          }\r
+          if (Directory && !EFI_ERROR(Status) && ShellInfoNode->FullName != NULL && ShellInfoNode->FileName != NULL){\r
             //\r
             // should be a directory\r
             //\r
@@ -1971,7 +2172,6 @@ ShellSearchHandle(
               //\r
               //\r
               //\r
-              ASSERT_EFI_ERROR(Status);\r
               if (EFI_ERROR(Status)) {\r
                 break;\r
               }\r
@@ -1983,9 +2183,9 @@ ShellSearchHandle(
               //\r
               // recurse with the next part of the pattern\r
               //\r
-              Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode);\r
+              Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);\r
             }\r
-          } else {\r
+          } else if (!EFI_ERROR(Status)) {\r
             //\r
             // should be a file\r
             //\r
@@ -1999,7 +2199,7 @@ ShellSearchHandle(
               Status = EFI_OUT_OF_RESOURCES;\r
             }\r
             if (*FileList == NULL) {\r
-              *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+              *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
               InitializeListHead(&((*FileList)->Link));\r
             }\r
 \r
@@ -2076,21 +2276,22 @@ EfiShellFindFiles(
   RootDevicePath = NULL;\r
   RootFileHandle = NULL;\r
   MapName        = NULL;\r
-  PatternCopy = AllocatePool(StrSize(FilePattern));\r
+  PatternCopy = AllocateZeroPool(StrSize(FilePattern));\r
   if (PatternCopy == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
   StrCpy(PatternCopy, FilePattern);\r
 \r
-  PatternCopy = CleanPath(PatternCopy);\r
+  PatternCopy = PathCleanUpDirectories(PatternCopy);\r
 \r
   Count = StrStr(PatternCopy, L":") - PatternCopy;\r
   Count += 2;\r
 \r
   ASSERT(MapName == NULL);\r
   MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count);\r
-\r
-  if (!EFI_ERROR(Status)) {\r
+  if (MapName == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  } else {\r
     RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy);\r
     if (RootDevicePath == NULL) {\r
       Status = EFI_INVALID_PARAMETER;\r
@@ -2101,18 +2302,14 @@ EfiShellFindFiles(
             ; *PatternCurrentLocation != ':'\r
             ; PatternCurrentLocation++);\r
         PatternCurrentLocation++;\r
-        Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL);\r
+        Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
       }\r
       FreePool(RootDevicePath);\r
     }\r
   }\r
 \r
-  if (PatternCopy != NULL) {\r
-    FreePool(PatternCopy);\r
-  }\r
-  if (MapName != NULL) {\r
-    FreePool(MapName);\r
-  }\r
+  SHELL_FREE_NON_NULL(PatternCopy);\r
+  SHELL_FREE_NON_NULL(MapName);\r
 \r
   return(Status);\r
 }\r
@@ -2145,17 +2342,19 @@ EfiShellOpenFileList(
   CHAR16              *Path2;\r
   UINTN               Path2Size;\r
   CONST CHAR16        *CurDir;\r
+  BOOLEAN             Found;\r
 \r
-  ShellCommandCleanPath(Path);\r
+  PathCleanUpDirectories(Path);\r
 \r
   Path2Size     = 0;\r
   Path2         = NULL;\r
 \r
-  ASSERT(FileList  != NULL);\r
-  ASSERT(*FileList != NULL);\r
+  if (FileList == NULL || *FileList == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
 \r
   if (*Path == L'.' && *(Path+1) == L'\\') {\r
-    Path++;\r
+    Path+=2;\r
   }\r
 \r
   //\r
@@ -2167,6 +2366,7 @@ EfiShellOpenFileList(
     StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
     if (*Path == L'\\') {\r
       Path++;\r
+      while (PathRemoveLastItem(Path2)) ;\r
     }\r
     ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
     StrnCatGrow(&Path2, &Path2Size, Path, 0);\r
@@ -2175,7 +2375,7 @@ EfiShellOpenFileList(
     StrnCatGrow(&Path2, NULL, Path, 0);\r
   }\r
 \r
-  CleanPath (Path2);\r
+  PathCleanUpDirectories (Path2);\r
 \r
   //\r
   // do the search\r
@@ -2188,6 +2388,7 @@ EfiShellOpenFileList(
     return (Status);\r
   }\r
 \r
+  Found = FALSE;\r
   //\r
   // We had no errors so open all the files (that are not already opened...)\r
   //\r
@@ -2197,9 +2398,13 @@ EfiShellOpenFileList(
      ){\r
     if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) {\r
       ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
+      Found = TRUE;\r
     }\r
   }\r
 \r
+  if (!Found) {\r
+    return (EFI_NOT_FOUND);\r
+  }\r
   return(EFI_SUCCESS);\r
 }\r
 \r
@@ -2268,6 +2473,12 @@ EfiShellGetEnv(
     Size += 2*sizeof(CHAR16);\r
 \r
     Buffer = AllocateZeroPool(Size);\r
+    if (Buffer == NULL) {\r
+      if (!IsListEmpty (&List)) {\r
+        FreeEnvironmentVariableList(&List);\r
+      }\r
+      return (NULL);\r
+    }\r
     CurrentWriteLocation = (CHAR16*)Buffer;\r
 \r
     for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)\r
@@ -2282,7 +2493,9 @@ EfiShellGetEnv(
     //\r
     // Free the list...\r
     //\r
-    FreeEnvironmentVariableList(&List);\r
+    if (!IsListEmpty (&List)) {\r
+      FreeEnvironmentVariableList(&List);\r
+    }\r
   } else {\r
     //\r
     // We are doing a specific environment variable\r
@@ -2504,7 +2717,7 @@ EfiShellSetCurDir(
   TempString    = NULL;\r
   DirectoryName = NULL;\r
 \r
-  if (FileSystem == NULL && Dir == NULL) {\r
+  if ((FileSystem == NULL && Dir == NULL) || Dir == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
@@ -2515,7 +2728,7 @@ EfiShellSetCurDir(
   DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);\r
   ASSERT(DirectoryName != NULL);\r
 \r
-  CleanPath(DirectoryName);\r
+  PathCleanUpDirectories(DirectoryName);\r
 \r
   if (FileSystem == NULL) {\r
     //\r
@@ -2597,7 +2810,7 @@ EfiShellSetCurDir(
       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[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
       }\r
@@ -2653,15 +2866,33 @@ EfiShellGetHelpText(
   )\r
 {\r
   CONST CHAR16  *ManFileName;\r
+  CHAR16        *FixCommand;\r
+  EFI_STATUS    Status;\r
 \r
   ASSERT(HelpText != NULL);\r
+  FixCommand = NULL;\r
 \r
   ManFileName = ShellCommandGetManFileNameHandler(Command);\r
 \r
   if (ManFileName != NULL) {\r
     return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));\r
   } else {\r
-    return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    if ((StrLen(Command)> 4)\r
+    && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I')\r
+    && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F')\r
+    && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E')\r
+    && (Command[StrLen(Command)-4] == L'.')\r
+    ) {\r
+      FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
+      ASSERT(FixCommand != NULL);\r
+\r
+      StrnCpy(FixCommand, Command, StrLen(Command)-4);\r
+      Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
+      FreePool(FixCommand);\r
+      return Status;\r
+    } else {\r
+      return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    }\r
   }\r
 }\r
 \r
@@ -2722,7 +2953,6 @@ InternalEfiShellGetListAlias(
   UINTN             NameSize;\r
   CHAR16            *RetVal;\r
   UINTN             RetSize;\r
-  CHAR16            *Alias;\r
 \r
   Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
   ASSERT_EFI_ERROR(Status);\r
@@ -2731,6 +2961,10 @@ InternalEfiShellGetListAlias(
   RetSize       = 0;\r
   RetVal        = NULL;\r
 \r
+  if (VariableName == NULL) {\r
+    return (NULL);\r
+  }\r
+\r
   VariableName[0] = CHAR_NULL;\r
 \r
   while (TRUE) {\r
@@ -2744,7 +2978,6 @@ InternalEfiShellGetListAlias(
       break;\r
     }\r
     if (CompareGuid(&Guid, &gShellAliasGuid)){\r
-      Alias = GetVariable(VariableName, &gShellAliasGuid);\r
       ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
@@ -2958,7 +3191,7 @@ EFI_SHELL_PROTOCOL         mShellProtocol = {
 \r
   This must be removed via calling CleanUpShellProtocol().\r
 \r
-  @param[in,out] NewShell   The pointer to the pointer to the structure \r
+  @param[in, out] NewShell   The pointer to the pointer to the structure\r
   to install.\r
 \r
   @retval EFI_SUCCESS     The operation was successful.\r
@@ -2976,23 +3209,26 @@ CreatePopulateInstallShellProtocol (
   UINTN                       HandleCounter;\r
   SHELL_PROTOCOL_HANDLE_LIST  *OldProtocolNode;\r
 \r
+  if (NewShell == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
   BufferSize = 0;\r
   Buffer = NULL;\r
   OldProtocolNode = NULL;\r
   InitializeListHead(&ShellInfoObject.OldShellList.Link);\r
 \r
-  ASSERT(NewShell != NULL);\r
-\r
   //\r
   // Initialize EfiShellProtocol object...\r
   //\r
-  *NewShell = &mShellProtocol;\r
   Status = gBS->CreateEvent(0,\r
                             0,\r
                             NULL,\r
                             NULL,\r
                             &mShellProtocol.ExecutionBreak);\r
-  ASSERT_EFI_ERROR(Status);\r
+  if (EFI_ERROR(Status)) {\r
+    return (Status);\r
+  }\r
 \r
   //\r
   // Get the size of the buffer we need.\r
@@ -3007,13 +3243,18 @@ CreatePopulateInstallShellProtocol (
     // Allocate and recall with buffer of correct size\r
     //\r
     Buffer = AllocateZeroPool(BufferSize);\r
-    ASSERT(Buffer != NULL);\r
+    if (Buffer == NULL) {\r
+      return (EFI_OUT_OF_RESOURCES);\r
+    }\r
     Status = gBS->LocateHandle(ByProtocol,\r
                                &gEfiShellProtocolGuid,\r
                                NULL,\r
                                &BufferSize,\r
                                Buffer);\r
-    ASSERT_EFI_ERROR(Status);\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool(Buffer);\r
+      return (Status);\r
+    }\r
     //\r
     // now overwrite each of them, but save the info to restore when we end.\r
     //\r
@@ -3036,7 +3277,7 @@ CreatePopulateInstallShellProtocol (
                             OldProtocolNode->Handle,\r
                             &gEfiShellProtocolGuid,\r
                             OldProtocolNode->Interface,\r
-                            (VOID*)(*NewShell));\r
+                            (VOID*)(&mShellProtocol));\r
         if (!EFI_ERROR(Status)) {\r
           //\r
           // we reinstalled sucessfully.  log this so we can reverse it later.\r
@@ -3059,7 +3300,7 @@ CreatePopulateInstallShellProtocol (
                       &gImageHandle,\r
                       &gEfiShellProtocolGuid,\r
                       EFI_NATIVE_INTERFACE,\r
-                      (VOID*)(*NewShell));\r
+                      (VOID*)(&mShellProtocol));\r
   }\r
 \r
   if (PcdGetBool(PcdShellSupportOldProtocols)){\r
@@ -3067,16 +3308,19 @@ CreatePopulateInstallShellProtocol (
     ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?\r
   }\r
 \r
+  if (!EFI_ERROR(Status)) {\r
+    *NewShell = &mShellProtocol;\r
+  }\r
   return (Status);\r
 }\r
 \r
 /**\r
-  Opposite of CreatePopulateInstallShellProtocol.  \r
+  Opposite of CreatePopulateInstallShellProtocol.\r
 \r
   Free all memory and restore the system to the state it was in before calling\r
   CreatePopulateInstallShellProtocol.\r
 \r
-  @param[in,out] NewShell   The pointer to the new shell protocol structure.\r
+  @param[in, out] NewShell   The pointer to the new shell protocol structure.\r
 \r
   @retval EFI_SUCCESS       The operation was successful.\r
 **/\r
@@ -3086,8 +3330,9 @@ CleanUpShellProtocol (
   IN OUT EFI_SHELL_PROTOCOL  *NewShell\r
   )\r
 {\r
-  EFI_STATUS Status;\r
-  SHELL_PROTOCOL_HANDLE_LIST  *Node2;\r
+  EFI_STATUS                        Status;\r
+  SHELL_PROTOCOL_HANDLE_LIST        *Node2;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
 \r
   //\r
   // if we need to restore old protocols...\r
@@ -3102,7 +3347,6 @@ CleanUpShellProtocol (
                                                &gEfiShellProtocolGuid,\r
                                                NewShell,\r
                                                Node2->Interface);\r
-      ASSERT_EFI_ERROR(Status);\r
       FreePool(Node2);\r
     }\r
   } else {\r
@@ -3112,11 +3356,133 @@ CleanUpShellProtocol (
     Status = gBS->UninstallProtocolInterface(gImageHandle,\r
                                              &gEfiShellProtocolGuid,\r
                                              NewShell);\r
-    ASSERT_EFI_ERROR(Status);\r
   }\r
   Status = gBS->CloseEvent(NewShell->ExecutionBreak);\r
+  NewShell->ExecutionBreak = NULL;\r
+\r
+  Status = gBS->OpenProtocol(\r
+    gST->ConsoleInHandle,\r
+    &gEfiSimpleTextInputExProtocolGuid,\r
+    (VOID**)&SimpleEx,\r
+    gImageHandle,\r
+    NULL,\r
+    EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
 \r
+  if (!EFI_ERROR (Status)) {\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);\r
+  }\r
   return (Status);\r
 }\r
 \r
+/**\r
+  Notification function for keystrokes.\r
+\r
+  @param[in] KeyData    The key that was pressed.\r
+\r
+  @retval EFI_SUCCESS   The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NotificationFunction(\r
+  IN EFI_KEY_DATA *KeyData\r
+  )\r
+{\r
+  if ( ((KeyData->Key.UnicodeChar == L'c') &&\r
+        (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) ||\r
+      (KeyData->Key.UnicodeChar == 3)\r
+      ){ \r
+    if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
+      return (EFI_UNSUPPORTED);\r
+    }\r
+    return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
+  } else if  ((KeyData->Key.UnicodeChar == L's') &&\r
+              (KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))\r
+              ){ \r
+    ShellInfoObject.HaltOutput = TRUE;\r
+  }\r
+  return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+  Function to start monitoring for CTRL-C 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
+  @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InernalEfiShellStartMonitor(\r
+  VOID\r
+  )\r
+{\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
+  EFI_KEY_DATA                      KeyData;\r
+  EFI_STATUS                        Status;\r
+\r
+  Status = gBS->OpenProtocol(\r
+    gST->ConsoleInHandle,\r
+    &gEfiSimpleTextInputExProtocolGuid,\r
+    (VOID**)&SimpleEx,\r
+    gImageHandle,\r
+    NULL,\r
+    EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+  if (EFI_ERROR(Status)) {\r
+    ShellPrintHiiEx(\r
+      -1, \r
+      -1, \r
+      NULL,\r
+      STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
+      ShellInfoObject.HiiHandle);\r
+    return (EFI_SUCCESS);\r
+  }\r
+\r
+  if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
+    return (EFI_UNSUPPORTED);\r
+  }\r
+\r
+  KeyData.KeyState.KeyToggleState = 0;\r
+  KeyData.Key.ScanCode            = 0;\r
+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
+  KeyData.Key.UnicodeChar         = L'c';\r
 \r
+  Status = SimpleEx->RegisterKeyNotify(\r
+    SimpleEx,\r
+    &KeyData,\r
+    NotificationFunction,\r
+    &ShellInfoObject.CtrlCNotifyHandle1);\r
+  \r
+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = SimpleEx->RegisterKeyNotify(\r
+      SimpleEx,\r
+      &KeyData,\r
+      NotificationFunction,\r
+      &ShellInfoObject.CtrlCNotifyHandle2);\r
+  }\r
+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
+  KeyData.Key.UnicodeChar         = 3;\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = SimpleEx->RegisterKeyNotify(\r
+      SimpleEx,\r
+      &KeyData,\r
+      NotificationFunction,\r
+      &ShellInfoObject.CtrlCNotifyHandle3);\r
+  }\r
+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
+  if (!EFI_ERROR(Status)) {\r
+    Status = SimpleEx->RegisterKeyNotify(\r
+      SimpleEx,\r
+      &KeyData,\r
+      NotificationFunction,\r
+      &ShellInfoObject.CtrlCNotifyHandle4);\r
+  }\r
+  return (Status);\r
+}\r