]> code.delx.au - refind/commitdiff
Added "scan_all_linux_kernels" refind.conf option & improved case
authorsrs5694 <srs5694@users.sourceforge.net>
Sat, 21 Apr 2012 17:50:10 +0000 (13:50 -0400)
committersrs5694 <srs5694@users.sourceforge.net>
Sat, 21 Apr 2012 17:50:10 +0000 (13:50 -0400)
sensitivity issues on Gigabyte's buggy Hybrid EFI

NEWS.txt
refind.conf-sample
refind/config.c
refind/global.h
refind/lib.c
refind/main.c

index 36f1777628585f6521cfff1ca94004e239c21082..71e4ab0b7369d04abab933569f86ff51c7f3ff38 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -1,6 +1,17 @@
 0.2.8 (?/??/2012):
 ------------------
 
+- Added new refind.conf option: scan_all_linux_kernels, which causes Linux
+  kernels that lack ".efi" extensions to be included in scans for EFI boot
+  loaders. This may help integration with Linux distributions that don't
+  give their kernels such names by default. Beware, though: It can detect
+  unwanted files, such as older non-stub-loader kernels or .icns files used
+  to give kernels with .efi extensions custom icons.
+
+- Improved EFI boot loader detection on boards with Gigabyte's Hybrid EFI,
+  and perhaps other EFIs with a buggy StriCmp() function. Files with both
+  ".efi" and ".EFI" extensions should now be detected as boot loaders.
+
 - Fixed a bug that caused rEFInd to fail to scan for drivers if the
   filesystem driver didn't set a volume name (that is, if the relevant
   field was set to NULL rather than even an empty string). In such
index 1dc58a93e3f57b4e5d3ce100574106583407818d..26ee27b10911eb490610c05f2d45ac49f65540f5 100644 (file)
@@ -93,6 +93,22 @@ timeout 20
 #
 #also_scan_dirs boot,EFI/linux/kernels
 
+# Scan for Linux kernels that lack a ".efi" filename extension. This is
+# useful for better integration with Linux distributions that provide
+# kernels with EFI stub loaders but that don't give those kernels filenames
+# that end in ".efi", particularly if the kernels are stored on a
+# filesystem that the EFI can read. When uncommented, this option causes
+# all files in scanned directories with names that begin with "vmlinuz"
+# or "bzImage" to be included as loaders, even if they lack ".efi"
+# extensions. The drawback to this option is that it can pick up kernels
+# that lack EFI stub loader support and other files. Most notably, if you
+# want to give a kernel a custom icon by placing an icon with the kernel's
+# filename but a ".icns" extension in the same directory as the kernel, this
+# option will cause the icon file to show up as a non-functional loader tag.
+# Default is to NOT scan for kernels without ".efi" extensions.
+#
+#scan_all_linux_kernels
+
 # Set the maximum number of tags that can be displayed on the screen at
 # any time. If more loaders are discovered than this value, rEFInd shows
 # a subset in a scrolling list. If this value is set too high for the
index dc8f2eac4961400ecf28de6f55f1f8682c94f0eb..f08d3dcd37648fc24b8549b58d67d9c4895c11cd 100644 (file)
@@ -410,9 +410,9 @@ VOID ReadConfig(VOID)
         } else if (StriCmp(TokenList[0], L"textonly") == 0) {
             GlobalConfig.TextOnly = TRUE;
 
-//         } else if ((StriCmp(TokenList[0], L"}") == 0) || (StriCmp(TokenList[0], L"loader") == 0) ||
-//                    (StriCmp(TokenList[0], L"icon") == 0) || (StriCmp(TokenList[0], L"options") == 0)) {
-//            // Do nothing; handled by ScanUserConfigured()
+        } else if (StriCmp(TokenList[0], L"scan_all_linux_kernels") == 0) {
+           GlobalConfig.ScanAllLinux = TRUE;
+
         } else if ((StriCmp(TokenList[0], L"max_tags") == 0) && (TokenCount > 1)) {
            GlobalConfig.MaxTags = Atoi(TokenList[1]);
         }
index 433de0f8994c1e3d072bd4a1e1d182ba23b176c7..d4e8aaa29e13651191634bf69b43b62e1605f74d 100644 (file)
@@ -152,6 +152,7 @@ typedef struct {
 
 typedef struct {
    BOOLEAN     TextOnly;
+   BOOLEAN     ScanAllLinux;
    UINTN       Timeout;
    UINTN       HideUIFlags;
    UINTN       MaxTags;     // max. number of OS entries to show simultaneously in graphics mode
index d19e21e5230e48a995f0d61f53a8888ca9c47040..174c27be652296db9fbf70cd8bdc54da8ae71302 100644 (file)
@@ -946,6 +946,10 @@ VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REF
 BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL,
                     OUT EFI_FILE_INFO **DirEntry)
 {
+    BOOLEAN KeepGoing = TRUE;
+    UINTN   i;
+    CHAR16  *OnePattern;
+
     if (DirIter->LastFileInfo != NULL) {
         FreePool(DirIter->LastFileInfo);
         DirIter->LastFileInfo = NULL;
@@ -954,7 +958,7 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR
     if (EFI_ERROR(DirIter->LastStatus))
         return FALSE;   // stop iteration
 
-    for (;;) {
+    do {
         DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode);
         if (EFI_ERROR(DirIter->LastStatus))
             return FALSE;
@@ -962,13 +966,16 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR
             return FALSE;
         if (FilePattern != NULL) {
             if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY))
-                break;
-            if (MetaiMatch(DirIter->LastFileInfo->FileName, FilePattern))
-                break;
+                KeepGoing = FALSE;
+            i = 0;
+            while (KeepGoing && (OnePattern = FindCommaDelimited(FilePattern, i++)) != NULL) {
+               if (MetaiMatch(DirIter->LastFileInfo->FileName, OnePattern))
+                   KeepGoing = FALSE;
+            } // while
             // else continue loop
         } else
             break;
-    }
+    } while (KeepGoing);
 
     *DirEntry = DirIter->LastFileInfo;
     return TRUE;
@@ -1185,7 +1192,8 @@ CHAR16 *FindNumbers(IN CHAR16 *InString) {
 // Find the #Index element (numbered from 0) in a comma-delimited string
 // of elements.
 // Returns the found element, or NULL if Index is out of range or InString
-// is NULL.
+// is NULL. Note that the calling function is responsible for freeing the
+// memory associated with the returned string pointer.
 CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) {
    UINTN    StartPos = 0, CurPos = 0;
    BOOLEAN  Found = FALSE;
index 12d2b8f654a0039c9b572230916e812859120397..7ce4bcc5b78411447c5df03967cab2de236b838f 100644 (file)
 #define SHELL_NAMES             L"\\EFI\\tools\\shell.efi"
 #endif
 
+// Filename patterns that identify EFI boot loaders. Note that a single case (either L"*.efi" or
+// L"*.EFI") is fine for most systems; but Gigabyte's buggy Hybrid EFI does a case-sensitive
+// comparison when it should do a case-insensitive comparison, so I'm doubling this up. It does
+// no harm on other computers, AFAIK. In theory, every case variation should be done for
+// completeness, but that's ridiculous....
+#define LOADER_MATCH_PATTERNS   L"*.efi,*.EFI"
+
+// Patterns that identify Linux kernels. Added to the loader match pattern when the
+// scan_all_linux_kernels option is set in the configuration file. Causes kernels WITHOUT
+// a ".efi" extension to be found when scanning for boot loaders.
+#define LINUX_MATCH_PATTERNS    L"vmlinuz*,bzImage*"
+
 static REFIT_MENU_ENTRY MenuEntryAbout    = { L"About rEFInd", TAG_ABOUT, 1, 0, 'A', 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 };
@@ -73,7 +85,7 @@ static REFIT_MENU_ENTRY MenuEntryExit     = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0,
 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, NULL, NULL, NULL, NULL, NULL, NULL,
+REFIT_CONFIG GlobalConfig = { FALSE, FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL,
                               {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }};
 
 //
@@ -84,7 +96,7 @@ static VOID AboutrEFInd(VOID)
 {
     if (AboutMenu.EntryCount == 0) {
         AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
-        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.7.1");
+        AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.7.2");
         AddMenuInfoLine(&AboutMenu, L"");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
         AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith");
@@ -631,19 +643,18 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN
 
 // Scan an individual directory for EFI boot loader files and, if found,
 // add them to the list.
-static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path)
+static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Pattern)
 {
     EFI_STATUS              Status;
     REFIT_DIR_ITER          DirIter;
     EFI_FILE_INFO           *DirEntry;
-    CHAR16                  *FileName;
+    CHAR16                  FileName[256];
 
-    FileName = AllocateZeroPool(256 * sizeof(CHAR16));
-    if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && Volume != SelfVolume) ||
-        (StriCmp(Path, SelfDirPath) != 0)) && FileName) {
+    if (!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && Volume != SelfVolume) ||
+        (StriCmp(Path, SelfDirPath) != 0)) {
        // look through contents of the directory
        DirIterOpen(Volume->RootDir, Path, &DirIter);
-       while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
+       while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) {
           if (DirEntry->FileName[0] == '.' ||
               StriCmp(DirEntry->FileName, L"TextMode.efi") == 0 ||
               StriCmp(DirEntry->FileName, L"ebounce.efi") == 0 ||
@@ -672,9 +683,13 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
    EFI_STATUS              Status;
    REFIT_DIR_ITER          EfiDirIter;
    EFI_FILE_INFO           *EfiDirEntry;
-   CHAR16                  FileName[256], *Directory;
+   CHAR16                  FileName[256], *Directory, *MatchPatterns;
    UINTN                   i, Length;
 
+    MatchPatterns = StrDuplicate(LOADER_MATCH_PATTERNS);
+    if (GlobalConfig.ScanAllLinux)
+       MergeStrings(&MatchPatterns, LINUX_MATCH_PATTERNS, L',');
+
    if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) {
       // check for Mac OS X boot loader
       StrCpy(FileName, MACOSX_LOADER_PATH);
@@ -695,7 +710,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
       }
 
       // scan the root directory for EFI executables
-      ScanLoaderDir(Volume, NULL);
+      ScanLoaderDir(Volume, NULL, MatchPatterns);
 
       // scan subdirectories of the EFI directory (as per the standard)
       DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter);
@@ -703,7 +718,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
          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);
+         ScanLoaderDir(Volume, FileName, MatchPatterns);
       } // while()
       Status = DirIterClose(&EfiDirIter);
       if (Status != EFI_NOT_FOUND)
@@ -719,7 +734,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) {
             Directory[--Length] = 0;
          } // while
          if (Length > 0)
-            ScanLoaderDir(Volume, Directory);
+            ScanLoaderDir(Volume, Directory, MatchPatterns);
          FreePool(Directory);
       } // while
    } // if
@@ -1149,11 +1164,6 @@ static EFI_STATUS ConnectAllDriversToAllControllers(VOID)
     BOOLEAN              Parent;
     BOOLEAN              Device;
 
-    // GNU EFI's EFI_BOOT_SERVICES data structure is truncated, but all the
-    // items are in memory, so point a more complete data structure to it
-    // so that we can use items not in GNU EFI's implementation....
-//    gBS = (MY_BOOT_SERVICES*) BS;
-
     Status = LibLocateHandle(AllHandles,
                              NULL,
                              NULL,