X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e99aa7a04054658c8d5d4595717b9b10e848564d..e3d2b4a15b8e4a6e7d6e3a6421270fccfb06c4f0:/refind/config.c diff --git a/refind/config.c b/refind/config.c index b1e0929..c1a7b5d 100644 --- a/refind/config.c +++ b/refind/config.c @@ -1,5 +1,5 @@ /* - * refit/config.c + * refind/config.c * Configuration file functions * * Copyright (c) 2006 Christoph Pfisterer @@ -35,7 +35,7 @@ */ /* - * Modifications copyright (c) 2012 Roderick W. Smith + * Modifications copyright (c) 2012-2014 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), a copy of which must be distributed @@ -60,6 +60,9 @@ #define ENCODING_UTF8 (1) #define ENCODING_UTF16_LE (2) +#define GetTime ST->RuntimeServices->GetTime +#define LAST_MINUTE 1439 /* Last minute of a day */ + static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN, 0, 0, 0, NULL, NULL, NULL }; // @@ -220,7 +223,6 @@ static CHAR16 *ReadLine(REFIT_FILE *File) static BOOLEAN KeepReading(IN OUT CHAR16 *p, IN OUT BOOLEAN *IsQuoted) { BOOLEAN MoreToRead = FALSE; CHAR16 *Temp = NULL; -// while (*p && *p != '"' && ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || IsQuoted)) { if ((p == NULL) || (IsQuoted == NULL)) return FALSE; @@ -306,8 +308,12 @@ VOID FreeTokenLine(IN OUT CHAR16 ***TokenList, IN OUT UINTN *TokenCount) // handle a parameter with a single integer argument static VOID HandleInt(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT UINTN *Value) { - if (TokenCount == 2) - *Value = Atoi(TokenList[1]); + if (TokenCount == 2) { + if (StriCmp(TokenList[1], L"-1") == 0) + *Value = -1; + else + *Value = Atoi(TokenList[1]); + } } // handle a parameter with a single string argument @@ -318,22 +324,91 @@ static VOID HandleString(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 } // if } // static VOID HandleString() -// Handle a parameter with a series of string arguments, to be added to a comma-delimited -// list. Passes each token through the CleanUpPathNameSlashes() function to ensure -// consistency in subsequent comparisons of filenames. +// Handle a parameter with a series of string arguments, to replace or be added to a +// comma-delimited list. Passes each token through the CleanUpPathNameSlashes() function +// to ensure consistency in subsequent comparisons of filenames. If the first +// non-keyword token is "+", the list is added to the existing target string; otherwise, +// the tokens replace the current string. static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 **Target) { UINTN i; + BOOLEAN AddMode = FALSE; - if (*Target != NULL) { + if ((TokenCount > 2) && (StriCmp(TokenList[1], L"+") == 0)) { + AddMode = TRUE; + } + + if ((*Target != NULL) && !AddMode) { FreePool(*Target); *Target = NULL; } // if for (i = 1; i < TokenCount; i++) { - CleanUpPathNameSlashes(TokenList[i]); - MergeStrings(Target, TokenList[i], L','); - } + if ((i != 1) || !AddMode) { + CleanUpPathNameSlashes(TokenList[i]); + MergeStrings(Target, TokenList[i], L','); + } // if + } // for } // static VOID HandleStrings() +// Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be +// in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE). +// Any value outside that range denotes an error in the specification. Note that if +// the input is a number that includes no colon, this function will return the original +// number in UINTN form. +static UINTN HandleTime(IN CHAR16 *TimeString) { + UINTN Hour = 0, Minute = 0, TimeLength, i = 0; + + TimeLength = StrLen(TimeString); + while (i < TimeLength) { + if (TimeString[i] == L':') { + Hour = Minute; + Minute = 0; + } // if + if ((TimeString[i] >= L'0') && (TimeString[i] <= '9')) { + Minute *= 10; + Minute += (TimeString[i] - L'0'); + } // if + i++; + } // while + return (Hour * 60 + Minute); +} // BOOLEAN HandleTime() + +// Sets the default boot loader IF the current time is within the bounds +// defined by the third and fourth tokens in the TokenList. +static VOID SetDefaultByTime(IN CHAR16 **TokenList, OUT CHAR16 **Default) { + EFI_STATUS Status; + EFI_TIME CurrentTime; + UINTN StartTime = LAST_MINUTE + 1, EndTime = LAST_MINUTE + 1, Now; + BOOLEAN SetIt = FALSE; + + StartTime = HandleTime(TokenList[2]); + EndTime = HandleTime(TokenList[3]); + + if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) { + Status = refit_call2_wrapper(GetTime, &CurrentTime, NULL); + if (Status != EFI_SUCCESS) + return; + Now = CurrentTime.Hour * 60 + CurrentTime.Minute; + + if (Now > LAST_MINUTE) { // Shouldn't happen; just being paranoid + Print(L"Warning: Impossible system time: %d:%d\n", CurrentTime.Hour, CurrentTime.Minute); + return; + } // if impossible time + + if (StartTime < EndTime) { // Time range does NOT cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } else { // Time range DOES cross midnight + if ((Now >= StartTime) && (Now <= EndTime)) + SetIt = TRUE; + } // if/else time range crosses midnight + + if (SetIt) { + MyFreePool(*Default); + *Default = StrDuplicate(TokenList[1]); + } // if (SetIt) + } // if ((StartTime <= LAST_MINUTE) && (EndTime <= LAST_MINUTE)) +} // VOID SetDefaultByTime() + // read config file VOID ReadConfig(CHAR16 *FileName) { @@ -341,19 +416,33 @@ VOID ReadConfig(CHAR16 *FileName) REFIT_FILE File; CHAR16 **TokenList; CHAR16 *FlagName; + CHAR16 *TempStr = NULL; UINTN TokenCount, i; // Set a few defaults only if we're loading the default file. - if (StriCmp(FileName, CONFIG_FILE_NAME) == 0) { + if (StriCmp(FileName, GlobalConfig.ConfigFilename) == 0) { MyFreePool(GlobalConfig.AlsoScan); GlobalConfig.AlsoScan = StrDuplicate(ALSO_SCAN_DIRS); -// MyFreePool(GlobalConfig.DontScanVolumes); -// GlobalConfig.DontScanVolumes = StrDuplicate(L" "); MyFreePool(GlobalConfig.DontScanDirs); - GlobalConfig.DontScanDirs = StrDuplicate(SelfDirPath); + if (SelfVolume) { + if (SelfVolume->VolName) { + TempStr = SelfVolume->VolName ? StrDuplicate(SelfVolume->VolName) : NULL; + } else { + TempStr = AllocateZeroPool(256 * sizeof(CHAR16)); + if (TempStr != NULL) + SPrint(TempStr, 255, L"fs%d", SelfVolume->VolNumber); + } // if/else + } + MergeStrings(&TempStr, SelfDirPath, L':'); + MergeStrings(&TempStr, MEMTEST_LOCATIONS, L','); + GlobalConfig.DontScanDirs = TempStr; MyFreePool(GlobalConfig.DontScanFiles); GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES); - } + MergeStrings(&(GlobalConfig.DontScanFiles), MOK_NAMES, L','); + MyFreePool(GlobalConfig.DontScanVolumes); + GlobalConfig.DontScanVolumes = StrDuplicate(DONT_SCAN_VOLUMES); + GlobalConfig.WindowsRecoveryFiles = StrDuplicate(WINDOWS_RECOVERY_FILES); + } // if if (!FileExists(SelfDir, FileName)) { Print(L"Configuration file '%s' missing!\n", FileName); @@ -389,6 +478,8 @@ VOID ReadConfig(CHAR16 *FileName) GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HINTS; } else if (StriCmp(FlagName, L"editor") == 0) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_EDITOR; + } else if (StriCmp(FlagName, L"safemode") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SAFEMODE; } else if (StriCmp(FlagName, L"all") == 0) { GlobalConfig.HideUIFlags = HIDEUI_FLAG_ALL; } else { @@ -414,13 +505,12 @@ VOID ReadConfig(CHAR16 *FileName) HandleStrings(TokenList, TokenCount, &(GlobalConfig.AlsoScan)); } else if ((StriCmp(TokenList[0], L"don't_scan_volumes") == 0) || (StriCmp(TokenList[0], L"dont_scan_volumes") == 0)) { - HandleStrings(TokenList, TokenCount, &(GlobalConfig.AlsoScan)); // Note: Don't use HandleStrings() because it modifies slashes, which might be present in volume name - MyFreePool(GlobalConfig.DontScanVolumes); - GlobalConfig.DontScanVolumes = NULL; - for (i = 1; i < TokenCount; i++) { - MergeStrings(&GlobalConfig.DontScanVolumes, TokenList[i], L','); - } + MyFreePool(GlobalConfig.DontScanVolumes); + GlobalConfig.DontScanVolumes = NULL; + for (i = 1; i < TokenCount; i++) { + MergeStrings(&GlobalConfig.DontScanVolumes, TokenList[i], L','); + } } else if ((StriCmp(TokenList[0], L"don't_scan_dirs") == 0) || (StriCmp(TokenList[0], L"dont_scan_dirs") == 0)) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanDirs)); @@ -428,6 +518,9 @@ VOID ReadConfig(CHAR16 *FileName) } else if ((StriCmp(TokenList[0], L"don't_scan_files") == 0) || (StriCmp(TokenList[0], L"dont_scan_files") == 0)) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanFiles)); + } else if (StriCmp(TokenList[0], L"windows_recovery_files") == 0) { + HandleStrings(TokenList, TokenCount, &(GlobalConfig.WindowsRecoveryFiles)); + } else if (StriCmp(TokenList[0], L"scan_driver_dirs") == 0) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DriverDirs)); @@ -439,6 +532,8 @@ VOID ReadConfig(CHAR16 *FileName) GlobalConfig.ShowTools[i - 1] = TAG_SHELL; } else if (StriCmp(FlagName, L"gptsync") == 0) { GlobalConfig.ShowTools[i - 1] = TAG_GPTSYNC; + } else if (StriCmp(FlagName, L"gdisk") == 0) { + GlobalConfig.ShowTools[i - 1] = TAG_GDISK; } else if (StriCmp(FlagName, L"about") == 0) { GlobalConfig.ShowTools[i - 1] = TAG_ABOUT; } else if (StriCmp(FlagName, L"exit") == 0) { @@ -449,8 +544,14 @@ VOID ReadConfig(CHAR16 *FileName) GlobalConfig.ShowTools[i - 1] = TAG_SHUTDOWN; } else if (StriCmp(FlagName, L"apple_recovery") == 0) { GlobalConfig.ShowTools[i - 1] = TAG_APPLE_RECOVERY; + } else if (StriCmp(FlagName, L"windows_recovery") == 0) { + GlobalConfig.ShowTools[i - 1] = TAG_WINDOWS_RECOVERY; } else if (StriCmp(FlagName, L"mok_tool") == 0) { GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL; + } else if (StriCmp(FlagName, L"firmware") == 0) { + GlobalConfig.ShowTools[i - 1] = TAG_FIRMWARE; + } else if ((StriCmp(FlagName, L"memtest86") == 0) || (StriCmp(FlagName, L"memtest") == 0)) { + GlobalConfig.ShowTools[i - 1] = TAG_MEMTEST; } else { Print(L" unknown showtools flag: '%s'\n", FlagName); } @@ -459,6 +560,27 @@ VOID ReadConfig(CHAR16 *FileName) } else if (StriCmp(TokenList[0], L"banner") == 0) { HandleString(TokenList, TokenCount, &(GlobalConfig.BannerFileName)); + } else if ((StriCmp(TokenList[0], L"banner_scale") == 0) && (TokenCount == 2)) { + if (StriCmp(TokenList[1], L"noscale") == 0) { + GlobalConfig.BannerScale = BANNER_NOSCALE; + } else if ((StriCmp(TokenList[1], L"fillscreen") == 0) || (StriCmp(TokenList[1], L"fullscreen") == 0)) { + GlobalConfig.BannerScale = BANNER_FILLSCREEN; + } else { + Print(L" unknown banner_type flag: '%s'\n", TokenList[1]); + } // if/else + + } else if ((StriCmp(TokenList[0], L"small_icon_size") == 0) && (TokenCount == 2)) { + HandleInt(TokenList, TokenCount, &i); + if (i >= 32) + GlobalConfig.IconSizes[ICON_SIZE_SMALL] = i; + + } else if ((StriCmp(TokenList[0], L"big_icon_size") == 0) && (TokenCount == 2)) { + HandleInt(TokenList, TokenCount, &i); + if (i >= 32) { + GlobalConfig.IconSizes[ICON_SIZE_BIG] = i; + GlobalConfig.IconSizes[ICON_SIZE_BADGE] = i / 4; + } + } else if (StriCmp(TokenList[0], L"selection_small") == 0) { HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionSmallFileName)); @@ -466,7 +588,11 @@ VOID ReadConfig(CHAR16 *FileName) HandleString(TokenList, TokenCount, &(GlobalConfig.SelectionBigFileName)); } else if (StriCmp(TokenList[0], L"default_selection") == 0) { - HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + if (TokenCount == 4) { + SetDefaultByTime(TokenList, &(GlobalConfig.DefaultSelection)); + } else { + HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); + } } else if (StriCmp(TokenList[0], L"textonly") == 0) { if ((TokenCount >= 2) && (StriCmp(TokenList[1], L"0") == 0)) { @@ -485,8 +611,12 @@ VOID ReadConfig(CHAR16 *FileName) else GlobalConfig.RequestedScreenHeight = 0; + } else if (StriCmp(TokenList[0], L"screensaver") == 0) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.ScreensaverTime)); + } else if (StriCmp(TokenList[0], L"use_graphics_for") == 0) { - GlobalConfig.GraphicsFor = 0; + if ((TokenCount == 2) || ((TokenCount > 2) && (StriCmp(TokenList[1], L"+") != 0))) + GlobalConfig.GraphicsFor = 0; for (i = 1; i < TokenCount; i++) { if (StriCmp(TokenList[i], L"osx") == 0) { GlobalConfig.GraphicsFor |= GRAPHICS_FOR_OSX; @@ -501,6 +631,9 @@ VOID ReadConfig(CHAR16 *FileName) } } // for (graphics_on tokens) + } else if ((StriCmp(TokenList[0], L"font") == 0) && (TokenCount == 2)) { + egLoadFont(TokenList[1]); + } else if (StriCmp(TokenList[0], L"scan_all_linux_kernels") == 0) { if ((TokenCount >= 2) && (StriCmp(TokenList[1], L"0") == 0)) { GlobalConfig.ScanAllLinux = FALSE; @@ -511,7 +644,8 @@ VOID ReadConfig(CHAR16 *FileName) } else if (StriCmp(TokenList[0], L"max_tags") == 0) { HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags)); - } else if ((StriCmp(TokenList[0], L"include") == 0) && (TokenCount == 2) && (StriCmp(FileName, CONFIG_FILE_NAME) == 0)) { + } else if ((StriCmp(TokenList[0], L"include") == 0) && (TokenCount == 2) && + (StriCmp(FileName, GlobalConfig.ConfigFilename) == 0)) { if (StriCmp(TokenList[1], FileName) != 0) { ReadConfig(TokenList[1]); } @@ -520,6 +654,8 @@ VOID ReadConfig(CHAR16 *FileName) FreeTokenLine(&TokenList, &TokenCount); } + if ((GlobalConfig.DontScanFiles) && (GlobalConfig.WindowsRecoveryFiles)) + MergeStrings(&(GlobalConfig.DontScanFiles), GlobalConfig.WindowsRecoveryFiles, L','); MyFreePool(File.Buffer); } /* VOID ReadConfig() */ @@ -528,13 +664,18 @@ VOID ReadConfig(CHAR16 *FileName) // that volume. If not, leaves it unchanged. // Returns TRUE if a match was found, FALSE if not. static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { - UINTN i = 0, CountedVolumes = 0; + UINTN i = 0, CountedVolumes = 0, Length; INTN Number = -1; - BOOLEAN Found = FALSE; + BOOLEAN Found = FALSE, IdIsGuid = FALSE; + EFI_GUID VolGuid, NullGuid = NULL_GUID_VALUE; - if ((StrLen(Identifier) >= 2) && (Identifier[StrLen(Identifier) - 1] == L':') && + VolGuid = StringAsGuid(Identifier); + Length = StrLen(Identifier); + if ((Length >= 2) && (Identifier[Length - 1] == L':') && (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) { Number = (INTN) Atoi(Identifier); + } else if (IsGuid(Identifier)) { + IdIsGuid = TRUE; } while ((i < VolumesCount) && (!Found)) { if (Number >= 0) { // User specified a volume by number @@ -545,11 +686,17 @@ static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { } CountedVolumes++; } // if - } else { // User specified a volume by label + } else { // User specified a volume by label or GUID if (StriCmp(Identifier, Volumes[i]->VolName) == 0) { *Volume = Volumes[i]; Found = TRUE; } // if + if (IdIsGuid && !Found) { + if (GuidsAreEqual(&VolGuid, &(Volumes[i]->PartGuid)) && !GuidsAreEqual(&NullGuid, &(Volumes[i]->PartGuid))) { + *Volume = Volumes[i]; + Found = TRUE; + } // if + } // if } // if/else i++; } // while() @@ -670,9 +817,9 @@ static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, C } else if ((StriCmp(TokenList[0], L"icon") == 0) && (TokenCount > 1)) { MyFreePool(Entry->me.Image); - Entry->me.Image = LoadIcns(CurrentVolume->RootDir, TokenList[1], 128); + Entry->me.Image = egLoadIcon(CurrentVolume->RootDir, TokenList[1], GlobalConfig.IconSizes[ICON_SIZE_BIG]); if (Entry->me.Image == NULL) { - Entry->me.Image = DummyImage(128); + Entry->me.Image = DummyImage(GlobalConfig.IconSizes[ICON_SIZE_BIG]); } } else if ((StriCmp(TokenList[0], L"initrd") == 0) && (TokenCount > 1)) { @@ -713,14 +860,14 @@ static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, C } // if if (!DefaultsSet) - SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", CurrentVolume); // user included no entry; use bogus one + SetLoaderDefaults(Entry, L"\\EFI\\BOOT\\nemo.efi", CurrentVolume); // user included no "loader" line; use bogus one return(Entry); } // static VOID AddStanzaEntries() // Read the user-configured menu entries from refind.conf and add or delete // entries based on the contents of that file.... -VOID ScanUserConfigured(VOID) +VOID ScanUserConfigured(CHAR16 *FileName) { EFI_STATUS Status; REFIT_FILE File; @@ -730,8 +877,8 @@ VOID ScanUserConfigured(VOID) UINTN TokenCount, size; LOADER_ENTRY *Entry; - if (FileExists(SelfDir, CONFIG_FILE_NAME)) { - Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File, &size); + if (FileExists(SelfDir, FileName)) { + Status = ReadFile(SelfDir, FileName, &File, &size); if (EFI_ERROR(Status)) return; @@ -749,12 +896,78 @@ VOID ScanUserConfigured(VOID) MyFreePool(Entry); } // if/else MyFreePool(Title); - } // if + + } else if ((StriCmp(TokenList[0], L"include") == 0) && (TokenCount == 2) && + (StriCmp(FileName, GlobalConfig.ConfigFilename) == 0)) { + if (StriCmp(TokenList[1], FileName) != 0) { + ScanUserConfigured(TokenList[1]); + } + + } // if/else if... FreeTokenLine(&TokenList, &TokenCount); } // while() } // if() } // VOID ScanUserConfigured() +// Create an options file based on /etc/fstab. The resulting file has two options +// lines, one of which boots the system with "ro root={rootfs}" and the other of +// which boots the system with "ro root={rootfs} single", where "{rootfs}" is the +// filesystem identifier associated with the "/" line in /etc/fstab. +static REFIT_FILE * GenerateOptionsFromEtcFstab(REFIT_VOLUME *Volume) { + UINTN TokenCount, i; + REFIT_FILE *Options = NULL, *Fstab = NULL; + EFI_STATUS Status; + CHAR16 **TokenList, *Line, Root[100]; + + if (FileExists(Volume->RootDir, L"\\etc\\fstab")) { + Options = AllocateZeroPool(sizeof(REFIT_FILE)); + Fstab = AllocateZeroPool(sizeof(REFIT_FILE)); + Status = ReadFile(Volume->RootDir, L"\\etc\\fstab", Fstab, &i); + if (CheckError(Status, L"while reading /etc/fstab")) { + if (Options != NULL) + FreePool(Options); + if (Fstab != NULL) + FreePool(Fstab); + Options = NULL; + Fstab = NULL; + } else { // File read; locate root fs and create entries + Options->Encoding = ENCODING_UTF16_LE; + while ((TokenCount = ReadTokenLine(Fstab, &TokenList)) > 0) { + if (TokenCount > 2) { + Root[0] = '\0'; + if (StriCmp(TokenList[1], L"\\") == 0) { + SPrint(Root, 99, L"%s", TokenList[0]); + } else if (StriCmp(TokenList[2], L"\\") == 0) { + SPrint(Root, 99, L"%s=%s", TokenList[0], TokenList[1]); + } // if/elseif/elseif + if (Root[0] != L'\0') { + for (i = 0; i < StrLen(Root); i++) + if (Root[i] == '\\') + Root[i] = '/'; + Line = PoolPrint(L"\"Boot with normal options\" \"ro root=%s\"\n", Root); + MergeStrings((CHAR16 **) &(Options->Buffer), Line, 0); + MyFreePool(Line); + Line = PoolPrint(L"\"Boot into single-user mode\" \"ro root=%s single\"\n", Root); + MergeStrings((CHAR16**) &(Options->Buffer), Line, 0); + Options->BufferSize = StrLen((CHAR16*) Options->Buffer) * sizeof(CHAR16); + } // if + } // if + FreeTokenLine(&TokenList, &TokenCount); + } // while + + Options->Current8Ptr = (CHAR8 *)Options->Buffer; + Options->End8Ptr = Options->Current8Ptr + Options->BufferSize; + Options->Current16Ptr = (CHAR16 *)Options->Buffer; + Options->End16Ptr = Options->Current16Ptr + (Options->BufferSize >> 1); + + MyFreePool(Fstab->Buffer); + MyFreePool(Fstab); + } // if/else file read error + } // if /etc/fstab exists + return Options; +} // GenerateOptionsFromEtcFstab() + + // Read a Linux kernel options file for a Linux boot loader into memory. The LoaderPath // and Volume variables identify the location of the options file, but not its name -- // you pass this function the filename of the Linux kernel, initial RAM disk, or other @@ -765,12 +978,15 @@ VOID ScanUserConfigured(VOID) // 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. // // The return value is a pointer to the REFIT_FILE handle for the file, or NULL if // it wasn't found. REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *OptionsFilename, *FullFilename; - BOOLEAN GoOn = TRUE; + BOOLEAN GoOn = TRUE, FileFound = FALSE; UINTN i = 0, size; REFIT_FILE *File = NULL; EFI_STATUS Status; @@ -783,17 +999,20 @@ REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume if (FileExists(Volume->RootDir, FullFilename)) { File = AllocateZeroPool(sizeof(REFIT_FILE)); Status = ReadFile(Volume->RootDir, FullFilename, File, &size); - GoOn = FALSE; if (CheckError(Status, L"while loading the Linux options file")) { if (File != NULL) FreePool(File); File = NULL; - GoOn = TRUE; - } // if error + } else { + GoOn = FALSE; + FileFound = TRUE; + } // if/else error } // if file exists } else { // a filename string is NULL GoOn = FALSE; } // if/else + if (!FileFound) + File = GenerateOptionsFromEtcFstab(Volume); MyFreePool(OptionsFilename); MyFreePool(FullFilename); OptionsFilename = FullFilename = NULL;