// 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.
// 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;
// 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);
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
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()
#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);
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);
CHAR16 * GuidAsString(EFI_GUID *GuidData);
EFI_GUID StringAsGuid(CHAR16 * InString);
+VOID DeleteStringList(STRING_LIST *StringList);
#endif
\ No newline at end of file