]> code.delx.au - refind/blobdiff - refind/main.c
New config file option: "also_scan_dirs".
[refind] / refind / main.c
index b1839c953a634508acd84cf64780afe8bd16b55a..058728cfa181d0f7a2675e7722d10f222c036dbe 100644 (file)
 // variables
 
 #define MACOSX_LOADER_PATH      L"\\System\\Library\\CoreServices\\boot.efi"
+#if defined (EFIX64)
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\shellx64.efi"
+#elif defined (EFI32)
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi,\\shellia32.efi"
+#else
+#define SHELL_NAMES             L"\\EFI\\tools\\shell.efi"
+#endif
 
 static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', NULL, NULL, NULL };
-static REFIT_MENU_ENTRY MenuEntryReset    = { L"Restart Computer", TAG_RESET, 1, 0, 'R', NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryReset    = { L"Reboot Computer", TAG_REBOOT, 1, 0, 'R', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryShutdown = { L"Shut Down Computer", TAG_SHUTDOWN, 1, 0, 'U', NULL, NULL, NULL };
 static REFIT_MENU_ENTRY MenuEntryReturn   = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL };
+static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, NULL, NULL, NULL };
 
 static REFIT_MENU_SCREEN MainMenu       = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" };
 static REFIT_MENU_SCREEN AboutMenu      = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL };
 
-REFIT_CONFIG        GlobalConfig = { FALSE, 20, 0, 0, FALSE, NULL, NULL, NULL, NULL };
+REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, NULL,
+                              {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
 
 //
 // misc functions
@@ -74,15 +83,16 @@ static VOID AboutrEFInd(VOID)
 {
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.2");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.6.1");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
         AddMenuInfoLine(&AboutMenu, L"Portions Copyright (c) Intel Corporation and others");
+        AddMenuInfoLine(&AboutMenu, L"Distributed under the terms of the GNU GPLv3 license");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Running on:");
         AddMenuInfoLine(&AboutMenu, PoolPrint(L" EFI Revision %d.%02d",
-            ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1)));
+                        ST->Hdr.Revision >> 16, ST->Hdr.Revision & ((1 << 16) - 1)));
 #if defined(EFI32)
         AddMenuInfoLine(&AboutMenu, L" Platform: x86 (32 bit)");
 #elif defined(EFIX64)
@@ -134,13 +144,13 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
 
     // set load options
     if (LoadOptions != NULL) {
-      ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage);
+        ReturnStatus = Status = refit_call3_wrapper(BS->HandleProtocol, ChildImageHandle, &LoadedImageProtocol, (VOID **) &ChildLoadedImage);
         if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
             if (ErrorInStep != NULL)
                 *ErrorInStep = 2;
             goto bailout_unload;
         }
-        
+
         if (LoadOptionsPrefix != NULL) {
             FullLoadOptions = PoolPrint(L"%s %s ", LoadOptionsPrefix, LoadOptions);
             // NOTE: That last space is also added by the EFI shell and seems to be significant
@@ -165,7 +175,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
         if (ErrorInStep != NULL)
             *ErrorInStep = 3;
     }
-    
+
     // re-open file handles
     ReinitRefitLib();
 
@@ -184,7 +194,7 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
                                 OUT UINTN *ErrorInStep)
 {
     EFI_DEVICE_PATH *DevicePaths[2];
-    
+
     DevicePaths[0] = DevicePath;
     DevicePaths[1] = NULL;
     return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep);
@@ -196,9 +206,11 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
 
 static VOID StartLoader(IN LOADER_ENTRY *Entry)
 {
+    UINTN ErrorInStep = 0;
+
     BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS");
     StartEFIImage(Entry->DevicePath, Entry->LoadOptions,
-                  Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL);
+                  Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep);
     FinishExternalScreen();
 }
 
@@ -222,17 +234,25 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
    KernelVersion = FindNumbers(FileName);
    Path = FindPath(LoaderPath);
 
+   // Add trailing backslash for root directory; necessary on some systems, but must
+   // NOT be added to all directories, since on other systems, a trailing backslash on
+   // anything but the root directory causes them to flake out!
+   if (StrLen(Path) == 0) {
+      MergeStrings(&Path, L"\\", 0);
+   } // if
    DirIterOpen(Volume->RootDir, Path, &DirIter);
+   // Now add a trailing backslash if it was NOT added earlier, for consistency in
+   // building the InitrdName later....
+   if ((StrLen(Path) > 0) && (Path[StrLen(Path) - 1] != L'\\'))
+      MergeStrings(&Path, L"\\", 0);
    while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) {
       InitrdVersion = FindNumbers(DirEntry->FileName);
       if (KernelVersion != NULL) {
-//         if (StriSubCmp(KernelVersion, DirEntry->FileName)) {
             if (StriCmp(InitrdVersion, KernelVersion) == 0)
-               InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
-//         } // if match found
+               InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
       } else {
          if (InitrdVersion == NULL)
-            InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName);
+            InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
       } // if/else
       if (InitrdVersion != NULL)
          FreePool(InitrdVersion);
@@ -300,7 +320,6 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
          SubEntry = InitializeLoaderEntry(Entry);
          if (SubEntry != NULL) {
             SubEntry->me.Title = L"Boot using default options";
-//            SubEntry->me.Title = (Entry->OSType == 'M') ? L"Boot Mac OS X" : PoolPrint(L"Run %s", FileName);
             if ((SubEntry->InitrdPath != NULL) && (StrLen(SubEntry->InitrdPath) > 0) && (!StriSubCmp(L"initrd", SubEntry->LoadOptions))) {
                Temp = PoolPrint(L"initrd=%s", SubEntry->InitrdPath);
                MergeStrings(&SubEntry->LoadOptions, Temp, L' ');
@@ -331,7 +350,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
       Entry->Title = NULL;
    }
    SubScreen = InitializeSubScreen(Entry);
-   
+
    // loader-specific submenu entries
    if (Entry->OSType == 'M') {          // entries for Mac OS X
 #if defined(EFIX64)
@@ -350,7 +369,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
       } // if
 #endif
 
-      if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SINGLEUSER)) {
+      if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_SINGLEUSER)) {
          SubEntry = InitializeLoaderEntry(Entry);
          if (SubEntry != NULL) {
             SubEntry->me.Title        = L"Boot Mac OS X in verbose mode";
@@ -358,7 +377,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
             SubEntry->LoadOptions     = L"-v";
             AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
          } // if
-      
+
 #if defined(EFIX64)
          SubEntry = InitializeLoaderEntry(Entry);
          if (SubEntry != NULL) {
@@ -388,7 +407,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
 
       // check for Apple hardware diagnostics
       StrCpy(DiagsFileName, L"\\System\\Library\\CoreServices\\.diagnostics\\diags.efi");
-      if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.DisableFlags & DISABLE_FLAG_HWTEST)) {
+      if (FileExists(Volume->RootDir, DiagsFileName) && !(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HWTEST)) {
          SubEntry = InitializeLoaderEntry(Entry);
          if (SubEntry != NULL) {
             SubEntry->me.Title        = L"Run Apple Hardware Test";
@@ -458,7 +477,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) {
 
       AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries");
       AddMenuInfoLine(SubScreen, L"marked with (*) may not work.");
-        
+
    } else if (Entry->OSType == 'X') {   // entries for xom.efi
         // by default, skip the built-in selection and boot from hard disk only
         Entry->LoadOptions = L"-s -h";
@@ -512,18 +531,21 @@ static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Vol
 // that will (with luck) work fairly automatically.
 VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
    CHAR16          IconFileName[256];
-   CHAR16          *FileName, *OSIconName = NULL, *Temp;
+   CHAR16          *FileName, *PathOnly, *OSIconName = NULL, *Temp;
    CHAR16          ShortcutLetter = 0;
 
    FileName = Basename(LoaderPath);
-   
+   PathOnly = FindPath(LoaderPath);
+
    // locate a custom icon for the loader
    StrCpy(IconFileName, LoaderPath);
    ReplaceExtension(IconFileName, L".icns");
    if (FileExists(Volume->RootDir, IconFileName)) {
       Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128);
-   } // if
-   
+   } else if ((StrLen(PathOnly) == 0) && (Volume->VolIconImage != NULL)) {
+      Entry->me.Image = Volume->VolIconImage;
+   } // icon matched to loader or volume
+
    Temp = FindLastDirName(LoaderPath);
    MergeStrings(&OSIconName, Temp, L',');
    FreePool(Temp);
@@ -543,6 +565,9 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
       Entry->OSType = 'R';
       ShortcutLetter = 'R';
    } else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) {
+      if (Volume->VolIconImage != NULL) { // custom icon file found
+         Entry->me.Image = Volume->VolIconImage;
+      }
       MergeStrings(&OSIconName, L"mac", L',');
       Entry->UseGraphicsMode = TRUE;
       Entry->OSType = 'M';
@@ -572,13 +597,16 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME
    Entry->me.ShortcutLetter = ShortcutLetter;
    if (Entry->me.Image == NULL)
       Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE);
+   if (PathOnly != NULL)
+      FreePool(PathOnly);
 } // VOID SetLoaderDefaults()
-      
+
 // Add a specified EFI boot loader to the list, using automatic settings
 // for icons, options, etc.
 LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) {
    LOADER_ENTRY      *Entry;
 
+   CleanUpPathNameSlashes(LoaderPath);
    Entry = InitializeLoaderEntry(NULL);
    if (Entry != NULL) {
       Entry->Title = StrDuplicate(LoaderTitle);
@@ -592,7 +620,7 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN
       GenerateSubScreen(Entry, Volume);
       AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
    }
-   
+
    return(Entry);
 } // LOADER_ENTRY * AddLoaderEntry()
 
@@ -603,19 +631,26 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path)
     EFI_STATUS              Status;
     REFIT_DIR_ITER          DirIter;
     EFI_FILE_INFO           *DirEntry;
-    CHAR16                  FileName[256];
+    CHAR16                  FileName[256], *SelfPath;
+    UINTN                   i = 0;
+
+    // Skip past leading slashes, which are sometimes (but not always) included
+    // in SelfDirPath, to get a path that's known to never include this feature.
+    while ((SelfDirPath != NULL) && (SelfDirPath[i] == L'\\')) {
+       i++;
+    }
+    SelfPath = &SelfDirPath[i]; // NOTE: *DO NOT* call FreePool() on SelfPath!!!
 
-    // Note: SelfDirPath includes a leading backslash ('\'), but Path
-    // doesn't, so we rejigger the string to compensate....
-    if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) ||
-        (StriCmp(Path, &SelfDirPath[1]) != 0)) {
+    if (!SelfPath || !Path || ((StriCmp(Path, SelfPath) == 0) && Volume != SelfVolume) ||
+        (StriCmp(Path, SelfPath) != 0)) {
        // look through contents of the directory
        DirIterOpen(Volume->RootDir, Path, &DirIter);
        while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
           if (DirEntry->FileName[0] == '.' ||
               StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 ||
               StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 ||
-              StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0)
+              StriCmp(DirEntry->FileName, L"GraphicsConsole.efi") == 0 ||
+              StriSubCmp(L"shell", DirEntry->FileName))
                 continue;   // skip this
 
           if (Path)
@@ -639,8 +674,8 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
    EFI_FILE_INFO           *EfiDirEntry;
-   CHAR16                  FileName[256];
-//   LOADER_ENTRY            *Entry;
+   CHAR16                  FileName[256], *Directory;
+   UINTN                   i, Length;
 
    if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
       // check for Mac OS X boot loader
@@ -663,15 +698,11 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
 
       // scan the root directory for EFI executables
       ScanLoaderDir(Volume, NULL);
-      // scan the elilo directory (as used on gimli's first Live CD)
-      ScanLoaderDir(Volume, L"elilo");
-      // scan the boot directory
-      ScanLoaderDir(Volume, L"boot");
 
       // scan subdirectories of the EFI directory (as per the standard)
       DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
       while (DirIterNext(&EfiDirIter, 1, NULL, &EfiDirEntry)) {
-         if (StriCmp(EfiDirEntry->FileName, L"TOOLS") == 0 || EfiDirEntry->FileName[0] == '.')
+         if (StriCmp(EfiDirEntry->FileName, L"tools") == 0 || EfiDirEntry->FileName[0] == '.')
             continue;   // skip this, doesn't contain boot loaders
          SPrint(FileName, 255, L"EFI\\%s", EfiDirEntry->FileName);
          ScanLoaderDir(Volume, FileName);
@@ -679,6 +710,20 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
       Status = DirIterClose(&EfiDirIter);
       if (Status != EFI_NOT_FOUND)
          CheckError(Status, L"while scanning the EFI directory");
+
+      // Scan user-specified (or additional default) directories....
+      i = 0;
+      while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) {
+         Length = StrLen(Directory);
+         // Some EFI implementations won't read a directory if the path ends in
+         // a backslash, so eliminate this character, if it's present....
+         while ((Length > 0) && (Directory[Length - 1] == L'\\')) {
+            Directory[--Length] = 0;
+         } // while
+         if (Length > 0)
+            ScanLoaderDir(Volume, Directory);
+         FreePool(Directory);
+      } // while
    } // if
 } // static VOID ScanEfiFiles()
 
@@ -810,7 +855,7 @@ static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN Partit
             if (PartitionIndex < LogicalPartitionIndex)
                 break;  // stop the loop, no need to touch further EMBRs
         }
-        
+
     }
 
     return EFI_SUCCESS;
@@ -1062,48 +1107,6 @@ static LOADER_ENTRY * AddToolEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle
     return Entry;
 } /* static LOADER_ENTRY * AddToolEntry() */
 
-static VOID ScanTool(VOID)
-{
-    CHAR16                  FileName[256];
-    LOADER_ENTRY            *Entry;
-
-    if (GlobalConfig.DisableFlags & DISABLE_FLAG_TOOLS)
-        return;
-
-    // look for the EFI shell
-    if (!(GlobalConfig.DisableFlags & DISABLE_FLAG_SHELL)) {
-        SPrint(FileName, 255, L"%s\\apps\\shell.efi", SelfDirPath);
-        if (FileExists(SelfRootDir, FileName)) {
-            AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
-        } else {
-            StrCpy(FileName, L"\\efi\\tools\\shell.efi");
-            if (FileExists(SelfRootDir, FileName)) {
-                AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
-            }
-        }
-    }
-
-    // look for the GPT/MBR sync tool
-    StrCpy(FileName, L"\\efi\\tools\\gptsync.efi");
-    if (FileExists(SelfRootDir, FileName)) {
-        AddToolEntry(FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
-    }
-
-    // look for rescue Linux
-    StrCpy(FileName, L"\\efi\\rescue\\elilo.efi");
-    if (SelfVolume != NULL && FileExists(SelfRootDir, FileName)) {
-        Entry = AddToolEntry(FileName, L"Rescue Linux", BuiltinIcon(BUILTIN_ICON_TOOL_RESCUE), '0', FALSE);
-        
-        if (UGAWidth == 1440 && UGAHeight == 900)
-            Entry->LoadOptions = L"-d 0 i17";
-        else if (UGAWidth == 1680 && UGAHeight == 1050)
-            Entry->LoadOptions = L"-d 0 i20";
-        else
-            Entry->LoadOptions = L"-d 0 mini";
-    }
-}
-
-
 #ifdef DEBIAN_ENABLE_EFI110
 //
 // pre-boot driver functions
@@ -1115,13 +1118,13 @@ static VOID ScanDriverDir(IN CHAR16 *Path)
     REFIT_DIR_ITER          DirIter;
     EFI_FILE_INFO           *DirEntry;
     CHAR16                  FileName[256];
-    
+
     // look through contents of the directory
     DirIterOpen(SelfRootDir, Path, &DirIter);
     while (DirIterNext(&DirIter, 2, L"*.EFI", &DirEntry)) {
         if (DirEntry->FileName[0] == '.')
             continue;   // skip this
-        
+
         SPrint(FileName, 255, L"%s\\%s", Path, DirEntry->FileName);
         Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName),
                                L"", DirEntry->FileName, DirEntry->FileName, NULL);
@@ -1132,6 +1135,28 @@ static VOID ScanDriverDir(IN CHAR16 *Path)
         CheckError(Status, FileName);
     }
 }
+/* EFI_STATUS
+LibScanHandleDatabase (
+     EFI_HANDLE  DriverBindingHandle, OPTIONAL
+     UINT32      *DriverBindingHandleIndex, OPTIONAL
+     EFI_HANDLE  ControllerHandle, OPTIONAL
+     UINT32      *ControllerHandleIndex, OPTIONAL
+     UINTN       *HandleCount,
+     EFI_HANDLE  **HandleBuffer,
+     UINT32      **HandleType
+     );
+#define EFI_HANDLE_TYPE_UNKNOWN                     0x000
+#define EFI_HANDLE_TYPE_IMAGE_HANDLE                0x001
+#define EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE       0x002
+#define EFI_HANDLE_TYPE_DEVICE_DRIVER               0x004
+#define EFI_HANDLE_TYPE_BUS_DRIVER                  0x008
+#define EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
+#define EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE   0x020
+#define EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE       0x040
+#define EFI_HANDLE_TYPE_DEVICE_HANDLE               0x080
+#define EFI_HANDLE_TYPE_PARENT_HANDLE               0x100
+#define EFI_HANDLE_TYPE_CONTROLLER_HANDLE           0x200
+#define EFI_HANDLE_TYPE_CHILD_HANDLE                0x400 */
 
 static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
 {
@@ -1145,7 +1170,7 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
     UINTN       HandleIndex;
     BOOLEAN     Parent;
     BOOLEAN     Device;
-    
+
     Status = LibLocateHandle(AllHandles,
                              NULL,
                              NULL,
@@ -1153,7 +1178,7 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
                              &AllHandleBuffer);
     if (EFI_ERROR(Status))
         return Status;
-    
+
     for (Index = 0; Index < AllHandleCount; Index++) {
         //
         // Scan the handle database
@@ -1167,20 +1192,20 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
                                        &HandleType);
         if (EFI_ERROR (Status))
             goto Done;
-        
+
         Device = TRUE;
         if (HandleType[Index] & EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE)
             Device = FALSE;
         if (HandleType[Index] & EFI_HANDLE_TYPE_IMAGE_HANDLE)
             Device = FALSE;
-        
+
         if (Device) {
             Parent = FALSE;
             for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
                 if (HandleType[HandleIndex] & EFI_HANDLE_TYPE_PARENT_HANDLE)
                     Parent = TRUE;
             }
-            
+
             if (!Parent) {
                 if (HandleType[Index] & EFI_HANDLE_TYPE_DEVICE_HANDLE) {
                     Status = refit_call4_wrapper(BS->ConnectController,
@@ -1191,11 +1216,11 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
                 }
             }
         }
-        
+
         FreePool (HandleBuffer);
         FreePool (HandleType);
     }
-    
+
 Done:
     FreePool (AllHandleBuffer);
     return Status;
@@ -1260,28 +1285,61 @@ static VOID ScanForBootloaders(VOID) {
             break;
       } // switch()
    } // for
-   ScanTool();
 
-   // fixed other menu entries
-   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS)) {
-      MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-      AddMenuEntry(&MainMenu, &MenuEntryAbout);
-   }
-   if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.EntryCount == 0) {
-      MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
-      AddMenuEntry(&MainMenu, &MenuEntryShutdown);
-      MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
-      AddMenuEntry(&MainMenu, &MenuEntryReset);
-   }
-   
    // assign shortcut keys
    for (i = 0; i < MainMenu.EntryCount && MainMenu.Entries[i]->Row == 0 && i < 9; i++)
       MainMenu.Entries[i]->ShortcutDigit = (CHAR16)('1' + i);
-   
+
    // wait for user ACK when there were errors
    FinishTextScreen(FALSE);
 } // static VOID ScanForBootloaders()
 
+// Add the second-row tags containing built-in and external tools (EFI shell,
+// reboot, etc.)
+static VOID ScanForTools(VOID) {
+   CHAR16 *FileName = NULL;
+   UINTN i, j;
+
+   for (i = 0; i < NUM_TOOLS; i++) {
+      switch(GlobalConfig.ShowTools[i]) {
+         case TAG_SHUTDOWN:
+            MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_SHUTDOWN);
+            AddMenuEntry(&MainMenu, &MenuEntryShutdown);
+            break;
+         case TAG_REBOOT:
+            MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
+            AddMenuEntry(&MainMenu, &MenuEntryReset);
+            break;
+         case TAG_ABOUT:
+            MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
+            AddMenuEntry(&MainMenu, &MenuEntryAbout);
+            break;
+         case TAG_EXIT:
+            MenuEntryExit.Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
+            AddMenuEntry(&MainMenu, &MenuEntryExit);
+            break;
+         case TAG_SHELL:
+            j = 0;
+            while ((FileName = FindCommaDelimited(SHELL_NAMES, j++)) != NULL) {
+               if (FileExists(SelfRootDir, FileName)) {
+                  AddToolEntry(FileName, L"EFI Shell", BuiltinIcon(BUILTIN_ICON_TOOL_SHELL), 'E', FALSE);
+               }
+            } // while
+            break;
+         case TAG_GPTSYNC:
+            MergeStrings(&FileName, L"\\efi\\tools\\gptsync.efi", 0);
+            if (FileExists(SelfRootDir, FileName)) {
+               AddToolEntry(FileName, L"Make Hybrid MBR", BuiltinIcon(BUILTIN_ICON_TOOL_PART), 'P', FALSE);
+            }
+            break;
+      } // switch()
+      if (FileName != NULL) {
+         FreePool(FileName);
+         FileName = NULL;
+      }
+   } // for
+} // static VOID ScanForTools
+
 //
 // main entry point
 //
@@ -1316,10 +1374,11 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
     LoadDrivers();
 #endif /* DEBIAN_ENABLE_EFI110 */
     ScanForBootloaders();
+    ScanForTools();
 
     while (MainLoopRunning) {
         MenuExit = RunMainMenu(&MainMenu, GlobalConfig.DefaultSelection, &ChosenEntry);
-        
+
         // We don't allow exiting the main menu with the Escape key.
         if (MenuExit == MENU_EXIT_ESCAPE) {
            // Commented-out below: Was part of an attempt to get rEFInd to
@@ -1330,37 +1389,42 @@ efi_main (IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
 //             SetupScreen();
             continue;
         }
-        
+
         switch (ChosenEntry->Tag) {
-            
-            case TAG_RESET:    // Restart
+
+            case TAG_REBOOT:    // Reboot
                 TerminateScreen();
                 refit_call4_wrapper(RT->ResetSystem, EfiResetCold, EFI_SUCCESS, 0, NULL);
                 MainLoopRunning = FALSE;   // just in case we get this far
                 break;
-                
+
             case TAG_SHUTDOWN: // Shut Down
                 TerminateScreen();
                 refit_call4_wrapper(RT->ResetSystem, EfiResetShutdown, EFI_SUCCESS, 0, NULL);
                 MainLoopRunning = FALSE;   // just in case we get this far
                 break;
-                
+
             case TAG_ABOUT:    // About rEFInd
                 AboutrEFInd();
                 break;
-                
+
             case TAG_LOADER:   // Boot OS via .EFI loader
                 StartLoader((LOADER_ENTRY *)ChosenEntry);
                 break;
-                
+
             case TAG_LEGACY:   // Boot legacy OS
                 StartLegacy((LEGACY_ENTRY *)ChosenEntry);
                 break;
-                
+
             case TAG_TOOL:     // Start a EFI tool
                 StartTool((LOADER_ENTRY *)ChosenEntry);
                 break;
-                
+
+            case TAG_EXIT:    // Terminate rEFInd
+                BeginTextScreen(L" ");
+                return EFI_SUCCESS;
+                break;
+
         }
     }