From 2f0e524a93415ad4a3128320dfc043841c3a0da8 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Tue, 21 Jul 2015 08:21:42 -0400 Subject: [PATCH] Added new fold_linux_kernels option, which combines Linux kernels in a single directory into one main-menu token. This is still a bit buggy; it usually works, but sometimes the submenu text is corrupted. --- docs/refind/drivers.html | 2 +- refind.conf-sample | 9 +++++ refind/config.c | 5 ++- refind/global.h | 4 +- refind/lib.c | 18 +-------- refind/main.c | 83 ++++++++++++++++++++++++++++++++-------- 6 files changed, 84 insertions(+), 37 deletions(-) diff --git a/docs/refind/drivers.html b/docs/refind/drivers.html index 0a86376..782e170 100644 --- a/docs/refind/drivers.html +++ b/docs/refind/drivers.html @@ -228,7 +228,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

2.0 Btrfs driver. I've tested this driver with a simple one-partition filesystem and with a filesystem that spans two physical devices (although I've made no attempt to ensure that the driver can actually - read files written to both devices). Lamuel Liao has used the driver + read files written to both devices). Samuel Liao has used the driver with a compressed Btrfs volume. The driver will handle subvolumes, but you may need to add kernel options if you're booting a Linux kernel directly from a filesystem that uses subvolumes. For instance, on a diff --git a/refind.conf-sample b/refind.conf-sample index b4ee9e6..615a357 100644 --- a/refind.conf-sample +++ b/refind.conf-sample @@ -309,6 +309,15 @@ timeout 20 # #scan_all_linux_kernels false +# Combine all Linux kernels in a given directory into a single entry. +# When so set, the kernel with the most recent time stamp will be launched +# by default, and its filename will appear in the entry's description. +# To launch other kernels, the user must press F2 or Insert; alternate +# kernels then appear as options on the sub-menu. +# Default is "true" -- kernels are "folded" into a single menu entry. +# +#fold_linux_kernels false + # 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 diff --git a/refind/config.c b/refind/config.c index 4abd48b..d3b7580 100644 --- a/refind/config.c +++ b/refind/config.c @@ -679,6 +679,9 @@ VOID ReadConfig(CHAR16 *FileName) } else if (StriCmp(TokenList[0], L"scan_all_linux_kernels") == 0) { GlobalConfig.ScanAllLinux = HandleBoolean(TokenList, TokenCount); + } else if (StriCmp(TokenList[0], L"fold_linux_kernels") == 0) { + GlobalConfig.FoldLinuxKernels = HandleBoolean(TokenList, TokenCount); + } else if (StriCmp(TokenList[0], L"max_tags") == 0) { HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags)); @@ -941,7 +944,7 @@ VOID ScanUserConfigured(CHAR16 *FileName) Entry = AddStanzaEntries(&File, Volume, TokenList[1]); if (Entry->Enabled) { if (Entry->me.SubScreen == NULL) - GenerateSubScreen(Entry, Volume); + GenerateSubScreen(Entry, Volume, TRUE); AddPreparedLoaderEntry(Entry); } else { MyFreePool(Entry); diff --git a/refind/global.h b/refind/global.h index 33087c2..2871c61 100644 --- a/refind/global.h +++ b/refind/global.h @@ -275,6 +275,7 @@ typedef struct { BOOLEAN ScanAllLinux; BOOLEAN DeepLegacyScan; BOOLEAN EnableAndLockVMX; + BOOLEAN FoldLinuxKernels; UINTN RequestedScreenWidth; UINTN RequestedScreenHeight; UINTN BannerBottomEdge; @@ -331,10 +332,9 @@ EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, IN BOOLEAN IsDriver); LOADER_ENTRY *InitializeLoaderEntry(IN LOADER_ENTRY *Entry); REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry); -VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume); +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn); EG_IMAGE * GetDiskBadge(IN UINTN DiskType); LOADER_ENTRY * MakeGenericLoaderEntry(VOID); -LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume); VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume); LOADER_ENTRY * AddPreparedLoaderEntry(LOADER_ENTRY *Entry); VOID StoreLoaderName(IN CHAR16 *Name); diff --git a/refind/lib.c b/refind/lib.c index 7d2a573..416a1f1 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -310,25 +310,12 @@ EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, // list functions // -VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount) -{ - UINTN AllocateCount; - - *ElementCount = InitialElementCount; - if (*ElementCount > 0) { - AllocateCount = (*ElementCount + 7) & ~7; // next multiple of 8 - *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); - } else { - *ListPtr = NULL; - } -} - VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement) { UINTN AllocateCount; - if ((*ElementCount & 7) == 0) { - AllocateCount = *ElementCount + 8; + if ((*ElementCount & 15) == 0) { + AllocateCount = *ElementCount + 16; if (*ElementCount == 0) *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); else @@ -1336,7 +1323,6 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, LastBufferSize = BufferSize = 256; Buffer = AllocatePool(BufferSize); for (IterCount = 0; ; IterCount++) { - Print(L"In DirNextEntry(), about to call Directory->Read()\n"); Status = refit_call3_wrapper(Directory->Read, Directory, &BufferSize, Buffer); if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4) break; diff --git a/refind/main.c b/refind/main.c index fc31005..586fdd9 100644 --- a/refind/main.c +++ b/refind/main.c @@ -140,7 +140,7 @@ REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L" L"Insert or F2 for more options; Esc to refresh" }; static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" }; -REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, +REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC, 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, BANNER_NOSCALE, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL, @@ -170,7 +170,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.7.12"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.7.14"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith"); @@ -673,7 +673,7 @@ REFIT_MENU_SCREEN *InitializeSubScreen(IN LOADER_ENTRY *Entry) { return SubScreen; } // REFIT_MENU_SCREEN *InitializeSubScreen() -VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { +VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume, IN BOOLEAN GenerateReturn) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; CHAR16 *InitrdName; @@ -859,7 +859,8 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } } // entries for xom.efi - AddMenuEntry(SubScreen, &MenuEntryReturn); + if (GenerateReturn) + AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; } // VOID GenerateSubScreen() @@ -1028,7 +1029,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, REFIT_VOLUME *Vo // 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) { +static LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN BOOLEAN SubScreenReturn) { LOADER_ENTRY *Entry; CleanUpPathNameSlashes(LoaderPath); @@ -1054,13 +1055,50 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN Entry->VolName = Volume->VolName; Entry->DevicePath = FileDevicePath(Volume->DeviceHandle, Entry->LoaderPath); SetLoaderDefaults(Entry, LoaderPath, Volume); - GenerateSubScreen(Entry, Volume); + GenerateSubScreen(Entry, Volume, SubScreenReturn); AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); } return(Entry); } // LOADER_ENTRY * AddLoaderEntry() +// 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; + REFIT_MENU_SCREEN *SubScreen; + LOADER_ENTRY *SubEntry; + UINTN TokenCount; + + File = ReadLinuxOptionsFile(TargetLoader->LoaderPath, Volume); + if (File != NULL) { + SubScreen = TargetLoader->me.SubScreen; + InitrdName = FindInitrd(FileName, Volume); + while ((TokenCount = ReadTokenLine(File, &TokenList)) > 1) { + SubEntry = InitializeLoaderEntry(TargetLoader); + SplitPathName(FileName, &VolName, &Path, &SubmenuName); + MyFreePool(VolName); + MyFreePool(Path); + MergeStrings(&SubmenuName, L": ", '\0'); + MergeStrings(&SubmenuName, TokenList[0] ? StrDuplicate(TokenList[0]) : StrDuplicate(L"Boot Linux"), '\0'); + Title = StrDuplicate(SubmenuName); + SubEntry->me.Title = Title; + MyFreePool(SubEntry->LoadOptions); + SubEntry->LoadOptions = AddInitrdToOptions(TokenList[1], InitrdName); + MyFreePool(SubEntry->LoaderPath); + SubEntry->LoaderPath = StrDuplicate(FileName); + CleanUpPathNameSlashes(SubEntry->LoaderPath); + SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + FreeTokenLine(&TokenList, &TokenCount); + SubEntry->UseGraphicsMode = GlobalConfig.GraphicsFor & GRAPHICS_FOR_LINUX; + AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); + } // while + MyFreePool(SubmenuName); + MyFreePool(InitrdName); + MyFreePool(File); + } // if +} // static VOID AddKernelToSubmenu() + // Returns -1 if (Time1 < Time2), +1 if (Time1 > Time2), or 0 if // (Time1 == Time2). Precision is only to the nearest second; since // this is used for sorting boot loader entries, differences smaller @@ -1296,7 +1334,8 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 EFI_FILE_INFO *DirEntry; CHAR16 FileName[256], *Extension; struct LOADER_LIST *LoaderList = NULL, *NewLoader; - BOOLEAN FoundFallbackDuplicate = FALSE; + LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; + BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE; if ((!SelfDirPath || !Path || ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle != SelfVolume->DeviceHandle)) || (StriCmp(Path, SelfDirPath) != 0)) && (ShouldScan(Volume, Path))) { @@ -1336,9 +1375,18 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 NewLoader = LoaderList; while (NewLoader != NULL) { - AddLoaderEntry(NewLoader->FileName, NULL, Volume); - NewLoader = NewLoader->NextEntry; + IsLinux = (StriSubCmp(L"bzImage", NewLoader->FileName) || StriSubCmp(L"vmlinuz", NewLoader->FileName)); + if ((FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) { + AddKernelToSubmenu(FirstKernel, NewLoader->FileName, Volume); + } else { + LatestEntry = AddLoaderEntry(NewLoader->FileName, NULL, Volume, !(IsLinux && GlobalConfig.FoldLinuxKernels)); + if (IsLinux && (FirstKernel == NULL)) + FirstKernel = LatestEntry; + } + NewLoader = NewLoader->NextEntry; } // while + if ((NewLoader != NULL) && (FirstKernel != NULL) && IsLinux && GlobalConfig.FoldLinuxKernels) + AddMenuEntry(FirstKernel->me.SubScreen, &MenuEntryReturn); CleanUpLoaderList(LoaderList); Status = DirIterClose(&DirIter); @@ -1399,7 +1447,7 @@ static VOID ScanNetboot() { NetVolume->DiskKind = DISK_KIND_NET; NetVolume->VolBadgeImage = BuiltinIcon(BUILTIN_ICON_VOL_NET); NetVolume->PartName = NetVolume->VolName = NULL; - AddLoaderEntry(iPXEFileName, Location, NetVolume); + AddLoaderEntry(iPXEFileName, Location, NetVolume, TRUE); MyFreePool(NetVolume); } // if support files exist and are valid } @@ -1423,7 +1471,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { if (ShouldScan(Volume, MACOSX_LOADER_DIR)) { StrCpy(FileName, MACOSX_LOADER_PATH); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"boot.efi", GlobalConfig.DontScanFiles)) { - AddLoaderEntry(FileName, L"Mac OS X", Volume); + AddLoaderEntry(FileName, L"Mac OS X", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } @@ -1431,7 +1479,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { // check for XOM StrCpy(FileName, L"System\\Library\\CoreServices\\xom.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, MACOSX_LOADER_DIR, L"xom.efi", GlobalConfig.DontScanFiles)) { - AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume); + AddLoaderEntry(FileName, L"Windows XP (XoM)", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } @@ -1442,7 +1490,7 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { StrCpy(FileName, L"EFI\\Microsoft\\Boot\\bkpbootmgfw.efi"); if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bkpbootmgfw.efi", GlobalConfig.DontScanFiles)) { - AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume); + AddLoaderEntry(FileName, L"Microsoft EFI boot (Boot Repair backup)", Volume, TRUE); FoundBRBackup = TRUE; if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; @@ -1451,9 +1499,9 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { if (FileExists(Volume->RootDir, FileName) && !FilenameIn(Volume, L"EFI\\Microsoft\\Boot", L"bootmgfw.efi", GlobalConfig.DontScanFiles)) { if (FoundBRBackup) - AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume); + AddLoaderEntry(FileName, L"Supposed Microsoft EFI boot (probably GRUB)", Volume, TRUE); else - AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume); + AddLoaderEntry(FileName, L"Microsoft EFI boot", Volume, TRUE); if (DuplicatesFallback(Volume, FileName)) ScanFallbackLoader = FALSE; } @@ -1498,8 +1546,9 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { // If not a duplicate & if it exists & if it's not us, create an entry // for the fallback boot loader - if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT")) - AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume); + if (ScanFallbackLoader && FileExists(Volume->RootDir, FALLBACK_FULLNAME) && ShouldScan(Volume, L"EFI\\BOOT")) { + AddLoaderEntry(FALLBACK_FULLNAME, L"Fallback boot loader", Volume, TRUE); + } } // if } // static VOID ScanEfiFiles() -- 2.39.2