]> code.delx.au - refind/blobdiff - refind/main.c
Added support for "%v" as a variable for the kernel version number in
[refind] / refind / main.c
index 7bbd8fca9782927fb525226617d30652e51937b8..eeb7719078fbac792c50d11a71a54bcddb3bff21 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
 // 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;
 // 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;
 
     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);
     // 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);
         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 {
         } 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
         } // 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);
 
     // Note: Don't FreePool(FileName), since Basename returns a pointer WITHIN the string it's passed.
     MyFreePool(KernelVersion);
@@ -730,7 +757,7 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) {
 VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) {
     REFIT_MENU_SCREEN  *SubScreen;
     LOADER_ENTRY       *SubEntry;
 VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) {
     REFIT_MENU_SCREEN  *SubScreen;
     LOADER_ENTRY       *SubEntry;
-    CHAR16             *InitrdName;
+    CHAR16             *InitrdName, *KernelVersion = NULL;
     CHAR16             DiagsFileName[256];
     REFIT_FILE         *File;
     UINTN              TokenCount;
     CHAR16             DiagsFileName[256];
     REFIT_FILE         *File;
     UINTN              TokenCount;
@@ -828,6 +855,8 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN
         if (File != NULL) {
             InitrdName =  FindInitrd(Entry->LoaderPath, Volume);
             TokenCount = ReadTokenLine(File, &TokenList);
         if (File != NULL) {
             InitrdName =  FindInitrd(Entry->LoaderPath, Volume);
             TokenCount = ReadTokenLine(File, &TokenList);
+            KernelVersion = FindNumbers(Entry->LoaderPath);
+            ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion);
             // first entry requires special processing, since it was initially set
             // up with a default title but correct options by InitializeSubScreen(),
             // earlier....
             // first entry requires special processing, since it was initially set
             // up with a default title but correct options by InitializeSubScreen(),
             // earlier....
@@ -837,6 +866,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN
             } // if
             FreeTokenLine(&TokenList, &TokenCount);
             while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
             } // if
             FreeTokenLine(&TokenList, &TokenCount);
             while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+                ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion);
                 SubEntry = InitializeLoaderEntry(Entry);
                 SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux");
                 MyFreePool(SubEntry->LoadOptions);
                 SubEntry = InitializeLoaderEntry(Entry);
                 SubEntry->me.Title = TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux");
                 MyFreePool(SubEntry->LoadOptions);
@@ -916,20 +946,24 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN
     if (GenerateReturn)
         AddMenuEntry(SubScreen, &MenuEntryReturn);
     Entry->me.SubScreen = SubScreen;
     if (GenerateReturn)
         AddMenuEntry(SubScreen, &MenuEntryReturn);
     Entry->me.SubScreen = SubScreen;
+    MyFreePool(KernelVersion);
 } // VOID GenerateSubScreen()
 
 // Returns options for a Linux kernel. Reads them from an options file in the
 // kernel's directory; and if present, adds an initrd= option for an initial
 // RAM disk file with the same version number as the kernel file.
 static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) {
 } // VOID GenerateSubScreen()
 
 // Returns options for a Linux kernel. Reads them from an options file in the
 // kernel's directory; and if present, adds an initrd= option for an initial
 // RAM disk file with the same version number as the kernel file.
 static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Volume) {
-    CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL;
+    CHAR16 *Options = NULL, *InitrdName, *FullOptions = NULL, *KernelVersion;
 
     Options = GetFirstOptionsFromFile(LoaderPath, Volume);
     InitrdName = FindInitrd(LoaderPath, Volume);
 
     Options = GetFirstOptionsFromFile(LoaderPath, Volume);
     InitrdName = FindInitrd(LoaderPath, Volume);
+    KernelVersion = FindNumbers(InitrdName);
+    ReplaceSubstring(&Options, KERNEL_VERSION, KernelVersion);
     FullOptions = AddInitrdToOptions(Options, InitrdName);
 
     MyFreePool(Options);
     MyFreePool(InitrdName);
     FullOptions = AddInitrdToOptions(Options, InitrdName);
 
     MyFreePool(Options);
     MyFreePool(InitrdName);
+    MyFreePool(KernelVersion);
     return (FullOptions);
 } // static CHAR16 * GetMainLinuxOptions()
 
     return (FullOptions);
 } // static CHAR16 * GetMainLinuxOptions()
 
@@ -1116,16 +1150,19 @@ static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTit
 // Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry.
 static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) {
     REFIT_FILE          *File;
 // Add a Linux kernel as a submenu entry for another (pre-existing) Linux kernel entry.
 static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, REFIT_VOLUME *Volume) {
     REFIT_FILE          *File;
-    CHAR16              **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL, *Path = NULL, *Title;
+    CHAR16              **TokenList = NULL, *InitrdName, *SubmenuName = NULL, *VolName = NULL;
+    CHAR16              *Path = NULL, *Title, *KernelVersion;
     REFIT_MENU_SCREEN   *SubScreen;
     LOADER_ENTRY        *SubEntry;
     UINTN               TokenCount;
 
     REFIT_MENU_SCREEN   *SubScreen;
     LOADER_ENTRY        *SubEntry;
     UINTN               TokenCount;
 
+    KernelVersion = FindNumbers(FileName);
     File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume);
     if (File != NULL) {
         SubScreen = TargetLoader->me.SubScreen;
         InitrdName = FindInitrd(FileName, Volume);
         while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
     File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume);
     if (File != NULL) {
         SubScreen = TargetLoader->me.SubScreen;
         InitrdName = FindInitrd(FileName, Volume);
         while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) {
+            ReplaceSubstring(&(TokenList[1]), KERNEL_VERSION, KernelVersion);
             SubEntry = InitializeLoaderEntry(TargetLoader);
             SplitPathName(FileName, &VolName, &Path, &SubmenuName);
             MergeStrings(&SubmenuName, L": ", '\0');
             SubEntry = InitializeLoaderEntry(TargetLoader);
             SplitPathName(FileName, &VolName, &Path, &SubmenuName);
             MergeStrings(&SubmenuName, L": ", '\0');
@@ -1149,6 +1186,7 @@ static VOID AddKernelToSubmenu(LOADER_ENTRY * TargetLoader, CHAR16 *FileName, RE
         MyFreePool(InitrdName);
         MyFreePool(File);
     } // if
         MyFreePool(InitrdName);
         MyFreePool(File);
     } // if
+    MyFreePool(KernelVersion);
 } // static VOID AddKernelToSubmenu()
 
 // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if
 } // static VOID AddKernelToSubmenu()
 
 // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if