]> code.delx.au - refind/commitdiff
Improve initrd auto-detection to support better matching of strings
authorsrs5694 <srs5694@users.sourceforge.net>
Thu, 2 Mar 2017 19:00:42 +0000 (14:00 -0500)
committersrs5694 <srs5694@users.sourceforge.net>
Thu, 2 Mar 2017 19:00:42 +0000 (14:00 -0500)
after the kernel version number string.

Makefile
refind/config.c
refind/main.c
refind/mystrings.c
refind/mystrings.h

index d894fbca6dd8ba935927d47da00be632000e0c4a..34fe46133e92647029531f1e3fb2beaabe3cb649 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ MOK_DIR=mok
 GPTSYNC_DIR=gptsync
 EFILIB_DIR=EfiLib
 export EDK2BASE=/usr/local/UDK2014/MyWorkSpace
-export REFIND_VERSION='L"0.10.4.2"'
+export REFIND_VERSION='L"0.10.4.4"'
 
 # The "all" target builds with the TianoCore library if possible, but falls
 # back on the more easily-installed GNU-EFI library if TianoCore isn't
index b7851d4f33ebe6ff536855c81d18ab0cd435eb8c..6f33549ec5d3eb64f15353e8ab2d5bb45c29a56d 100644 (file)
@@ -1139,14 +1139,9 @@ static REFIT_FILE * GenerateOptionsFromPartTypes(VOID) {
 // you pass this function the filename of the Linux kernel, initial RAM disk, or other
 // file in the target directory, and this function finds the file with a name in the
 // comma-delimited list of names specified by LINUX_OPTIONS_FILENAMES within that
-// directory and loads it. This function tries multiple files because I originally
-// used the filename linux.conf, but close on the heels of that decision, the Linux
-// kernel developers decided to use that name for a similar purpose, but with a
-// different file format. Thus, I'm migrating rEFInd to use the name refind_linux.conf,
-// but I want a migration period in which both names are used.
-// If a rEFInd options file can't be found, try to generate minimal options from
-// /etc/fstab on the same volume as the kernel. This typically works only if the
-// kernel is being read from the Linux root filesystem.
+// directory and loads it. If a rEFInd options file can't be found, try to generate
+// minimal options from /etc/fstab on the same volume as the kernel. This typically
+// works only if the kernel is being read from the Linux root filesystem.
 //
 // The return value is a pointer to the REFIT_FILE handle for the file, or NULL if
 // it wasn't found.
index 7bbd8fca9782927fb525226617d30652e51937b8..bdfa6acaa0f1c69b1ba6646a7c866cf87bbdca3a 100644 (file)
@@ -530,13 +530,16 @@ static VOID StartLoader(LOADER_ENTRY *Entry, CHAR16 *SelectionName)
 // For instance, if LoaderPath is \EFI\kernels\bzImage-3.3.0.efi, and if \EFI\kernels
 // has a file called initramfs-3.3.0.img, this function will return the string
 // '\EFI\kernels\initramfs-3.3.0.img'. If the directory ALSO contains the file
-// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match;
-// however, initmine-3.3.0.img might match. (FindInitrd() returns the first match it
-// finds.) Thus, care should be taken to avoid placing duplicate matching files in
-// the kernel's directory.
+// initramfs-3.3.0-rc7.img or initramfs-13.3.0.img, those files will NOT match.
+// If more than one initrd file matches the extracted version string, the one
+// that matches more characters AFTER (actually, from the start of) the version
+// string is used.
 // If no matching init file can be found, returns NULL.
 static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
     CHAR16              *InitrdName = NULL, *FileName, *KernelVersion, *InitrdVersion, *Path;
+    CHAR16              *KernelPostNum, *InitrdPostNum;
+    UINTN               MaxSharedChars, SharedChars;
+    STRING_LIST         *InitrdNames = NULL, *FinalInitrdName = NULL, *CurrentInitrdName = NULL, *MaxSharedInitrd;
     REFIT_DIR_ITER      DirIter;
     EFI_FILE_INFO       *DirEntry;
 
@@ -555,20 +558,44 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) {
     // 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)) {
+    while (DirIterNext(&DirIter, 2, L"init*", &DirEntry)) {
         InitrdVersion = FindNumbers(DirEntry->FileName);
-        if (KernelVersion != NULL) {
-            if (MyStriCmp(InitrdVersion, KernelVersion)) {
-                InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
-            } // if
+        if (((KernelVersion != NULL) && (MyStriCmp(InitrdVersion, KernelVersion))) ||
+            ((KernelVersion == NULL) && (InitrdVersion == NULL))) {
+                CurrentInitrdName = AllocateZeroPool(sizeof(STRING_LIST));
+                if (InitrdNames == NULL)
+                    InitrdNames = FinalInitrdName = CurrentInitrdName;
+                if (CurrentInitrdName) {
+                    CurrentInitrdName->Value = PoolPrint(L"%s%s", Path, DirEntry->FileName);
+                    if (CurrentInitrdName != FinalInitrdName) {
+                        FinalInitrdName->Next = CurrentInitrdName;
+                        FinalInitrdName = CurrentInitrdName;
+                    } // if
+                } // if
+        } // if
+    } // while
+    if (InitrdNames) {
+        if (InitrdNames->Next == NULL) {
+            InitrdName = StrDuplicate(InitrdNames -> Value);
         } else {
-            if (InitrdVersion == NULL) {
-                InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName);
-            } // if
+            MaxSharedInitrd = CurrentInitrdName = InitrdNames;
+            MaxSharedChars = 0;
+            while (CurrentInitrdName != NULL) {
+                KernelPostNum = MyStrStr(LoaderPath, KernelVersion);
+                InitrdPostNum = MyStrStr(CurrentInitrdName->Value, KernelVersion);
+                SharedChars = NumCharsInCommon(KernelPostNum, InitrdPostNum);
+                if (SharedChars > MaxSharedChars) {
+                    MaxSharedChars = SharedChars;
+                    MaxSharedInitrd = CurrentInitrdName;
+                } // if
+                // TODO: Compute number of shared characters & compare with max.
+                CurrentInitrdName = CurrentInitrdName->Next;
+            }
+            if (MaxSharedInitrd)
+                InitrdName = StrDuplicate(MaxSharedInitrd->Value);
         } // if/else
-        MyFreePool(InitrdVersion);
-    } // while
-    DirIterClose(&DirIter);
+    } // if
+    DeleteStringList(InitrdNames);
 
     // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed.
     MyFreePool(KernelVersion);
index a5c5823c67c4e21e4fd13c37bfe47b714eaee96d..75e2d899ca92c641d421af49897e1e806bb98a71 100644 (file)
@@ -267,6 +267,19 @@ CHAR16 *FindNumbers(IN CHAR16 *InString) {
     return (Found);
 } // CHAR16 *FindNumbers()
 
+// Returns the number of characters that are in common between
+// String1 and String2 before they diverge. For instance, if
+// String1 is "FooBar" and String2 is "FoodiesBar", this function
+// will return "3", since they both start with "Foo".
+UINTN NumCharsInCommon(IN CHAR16* String1, IN CHAR16* String2) {
+    UINTN Count = 0;
+    if ((String1 == NULL) || (String2 == NULL))
+        return 0;
+    while ((String1[Count] != L'\0') && (String2[Count] != L'\0') && (String1[Count] == String2[Count]))
+        Count++;
+    return Count;
+} // UINTN NumCharsInCommon()
+
 // 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
@@ -456,3 +469,15 @@ EFI_GUID StringAsGuid(CHAR16 * InString) {
 
     return Guid;
 } // EFI_GUID StringAsGuid()
+
+// Delete the STRING_LIST pointed to by *StringList.
+VOID DeleteStringList(STRING_LIST *StringList) {
+    STRING_LIST *Current = StringList, *Previous;
+
+    while (Current != NULL) {
+        MyFreePool(Current->Value);
+        Previous = Current;
+        Current = Current->Next;
+        MyFreePool(Previous);
+    }
+} // VOID DeleteStringList()
index 9b4faec9c4a82d8be79529f5adeae4a424d5de2f..b79a4b77c87dca04070593fae62ce6f00904a54f 100644 (file)
 #endif
 #include "../EfiLib/GenericBdsLib.h"
 
+typedef struct _string_list {
+    CHAR16               *Value;
+    struct _string_list  *Next;
+} STRING_LIST;
+
 BOOLEAN StriSubCmp(IN CHAR16 *TargetStr, IN CHAR16 *BigStr);
 BOOLEAN MyStriCmp(IN CONST CHAR16 *String1, IN CONST CHAR16 *String2);
 CHAR16* MyStrStr (IN CHAR16  *String, IN CHAR16  *StrCharSet);
@@ -42,6 +47,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar);
 VOID MergeWords(CHAR16 **MergeTo, CHAR16 *InString, CHAR16 AddChar);
 BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit);
 CHAR16 *FindNumbers(IN CHAR16 *InString);
+UINTN NumCharsInCommon(IN CHAR16* String1, IN CHAR16* String2);
 CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index);
 BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List);
 BOOLEAN IsInSubstring(IN CHAR16 *BigString, IN CHAR16 *List);
@@ -52,5 +58,6 @@ BOOLEAN IsGuid(CHAR16 *UnknownString);
 CHAR16 * GuidAsString(EFI_GUID *GuidData);
 EFI_GUID StringAsGuid(CHAR16 * InString);
 
+VOID DeleteStringList(STRING_LIST *StringList);
 
 #endif
\ No newline at end of file