X-Git-Url: https://code.delx.au/refind/blobdiff_plain/a9f6601d6e5b85fb50ae214718a00064dc5a9143..39f21d099c9fb310bae28b54dc68d266ed610ed7:/refind/config.c diff --git a/refind/config.c b/refind/config.c index 9a6996b..63d0f31 100644 --- a/refind/config.c +++ b/refind/config.c @@ -53,7 +53,6 @@ // constants -#define CONFIG_FILE_NAME L"refind.conf" #define LINUX_OPTIONS_FILENAMES L"refind_linux.conf,refind-linux.conf" #define MAXCONFIGFILESIZE (128*1024) @@ -67,19 +66,21 @@ static REFIT_MENU_ENTRY MenuEntryReturn = { L"Return to Main Menu", TAG_RETURN // read a file into a buffer // -static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_FILE *File) +EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, IN CHAR16 *FileName, IN OUT REFIT_FILE *File, OUT UINTN *size) { EFI_STATUS Status; EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo; UINT64 ReadSize; + CHAR16 Message[256]; File->Buffer = NULL; File->BufferSize = 0; // read the file, allocating a buffer on the way Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); - if (CheckError(Status, L"while loading the configuration file")) + SPrint(Message, 255, L"while loading the file '%s'", FileName); + if (CheckError(Status, Message)) return Status; FileInfo = LibFileInfo(FileHandle); @@ -89,14 +90,18 @@ static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_F return EFI_LOAD_ERROR; } ReadSize = FileInfo->FileSize; - if (ReadSize > MAXCONFIGFILESIZE) - ReadSize = MAXCONFIGFILESIZE; FreePool(FileInfo); - File->BufferSize = (UINTN)ReadSize; // was limited to a few K before, so this is safe + File->BufferSize = (UINTN)ReadSize; File->Buffer = AllocatePool(File->BufferSize); + if (File->Buffer == NULL) { + size = 0; + return EFI_OUT_OF_RESOURCES; + } else { + *size = File->BufferSize; + } // if/else Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &File->BufferSize, File->Buffer); - if (CheckError(Status, L"while loading the configuration file")) { + if (CheckError(Status, Message)) { MyFreePool(File->Buffer); File->Buffer = NULL; refit_call1_wrapper(FileHandle->Close, FileHandle); @@ -126,7 +131,7 @@ static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_F } // TODO: detect other encodings as they are implemented } - + return EFI_SUCCESS; } @@ -209,10 +214,43 @@ static CHAR16 *ReadLine(REFIT_FILE *File) return Line; } +// Returns FALSE if *p points to the end of a token, TRUE otherwise. +// Also modifies *p **IF** the first and second characters are both +// quotes ('"'); it deletes one of them. +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; + + if (*p == L'\0') + return FALSE; + + if ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || *IsQuoted) { + MoreToRead = TRUE; + } + if (*p == L'"') { + if (p[1] == L'"') { + Temp = StrDuplicate(&p[1]); + if (Temp != NULL) { + StrCpy(p, Temp); + FreePool(Temp); + } + MoreToRead = TRUE; + } else { + *IsQuoted = !(*IsQuoted); + MoreToRead = FALSE; + } // if/else second character is a quote + } // if first character is a quote + + return MoreToRead; +} // BOOLEAN KeepReading() + // // get a line of tokens from a file // - UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) { BOOLEAN LineFinished, IsQuoted = FALSE; @@ -229,7 +267,7 @@ UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) p = Line; LineFinished = FALSE; while (!LineFinished) { - // skip whitespace + // skip whitespace & find start of token while ((*p == ' ' || *p == '\t' || *p == '=' || *p == ',') && !IsQuoted) p++; if (*p == 0 || *p == '#') @@ -242,14 +280,12 @@ UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) Token = p; // find end of token - while (*p && *p != '"' && ((*p != ' ' && *p != '\t' && *p != '=' && *p != '#' && *p != ',') || IsQuoted)) { - if ((*p == '/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators - *p = '\\'; + while (KeepReading(p, &IsQuoted)) { + if ((*p == L'/') && !IsQuoted) // Switch Unix-style to DOS-style directory separators + *p = L'\\'; p++; - } // if - if (*p == '"') - IsQuoted = !IsQuoted; - if (*p == 0 || *p == '#') + } // while + if (*p == L'\0' || *p == L'#') LineFinished = TRUE; *p++ = 0; @@ -299,20 +335,40 @@ static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 } // static VOID HandleStrings() // read config file -VOID ReadConfig(VOID) +VOID ReadConfig(CHAR16 *FileName) { EFI_STATUS Status; REFIT_FILE File; CHAR16 **TokenList; CHAR16 *FlagName; + CHAR16 *SelfPath = NULL; UINTN TokenCount, i; - if (!FileExists(SelfDir, CONFIG_FILE_NAME)) { - Print(L"Configuration file missing!\n"); + // Set a few defaults only if we're loading the default file. + if (StriCmp(FileName, CONFIG_FILE_NAME) == 0) { + MyFreePool(GlobalConfig.AlsoScan); + GlobalConfig.AlsoScan = StrDuplicate(ALSO_SCAN_DIRS); +// MyFreePool(GlobalConfig.DontScanVolumes); +// GlobalConfig.DontScanVolumes = StrDuplicate(L" "); + MyFreePool(GlobalConfig.DontScanDirs); + if (SelfVolume->VolName) { + SelfPath = StrDuplicate(SelfVolume->VolName); + } else { + SelfPath = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SelfPath, 255, L"fs%d", SelfVolume->VolNumber); + } // if/else + MergeStrings(&SelfPath, SelfDirPath, L':'); + GlobalConfig.DontScanDirs = SelfPath; + MyFreePool(GlobalConfig.DontScanFiles); + GlobalConfig.DontScanFiles = StrDuplicate(DONT_SCAN_FILES); + } + + if (!FileExists(SelfDir, FileName)) { + Print(L"Configuration file '%s' missing!\n", FileName); return; } - Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File); + Status = ReadFile(SelfDir, FileName, &File, &i); if (EFI_ERROR(Status)) return; @@ -332,13 +388,17 @@ VOID ReadConfig(VOID) } else if (StriCmp(FlagName, L"label") == 0) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_LABEL; } else if (StriCmp(FlagName, L"singleuser") == 0) { - GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SINGLEUSER; + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_SINGLEUSER; } else if (StriCmp(FlagName, L"hwtest") == 0) { - GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HWTEST; + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HWTEST; } else if (StriCmp(FlagName, L"arrows") == 0) { GlobalConfig.HideUIFlags |= HIDEUI_FLAG_ARROWS; + } else if (StriCmp(FlagName, L"hints") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_HINTS; + } else if (StriCmp(FlagName, L"editor") == 0) { + GlobalConfig.HideUIFlags |= HIDEUI_FLAG_EDITOR; } else if (StriCmp(FlagName, L"all") == 0) { - GlobalConfig.HideUIFlags = HIDEUI_ALL; + GlobalConfig.HideUIFlags = HIDEUI_FLAG_ALL; } else { Print(L" unknown hideui flag: '%s'\n", FlagName); } @@ -361,8 +421,20 @@ VOID ReadConfig(VOID) } else if (StriCmp(TokenList[0], L"also_scan_dirs") == 0) { 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','); + } + } else if ((StriCmp(TokenList[0], L"don't_scan_dirs") == 0) || (StriCmp(TokenList[0], L"dont_scan_dirs") == 0)) { - HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScan)); + HandleStrings(TokenList, TokenCount, &(GlobalConfig.DontScanDirs)); + + } 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"scan_driver_dirs") == 0) { HandleStrings(TokenList, TokenCount, &(GlobalConfig.DriverDirs)); @@ -383,6 +455,10 @@ VOID ReadConfig(VOID) GlobalConfig.ShowTools[i - 1] = TAG_REBOOT; } else if (StriCmp(FlagName, L"shutdown") == 0) { 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"mok_tool") == 0) { + GlobalConfig.ShowTools[i - 1] = TAG_MOK_TOOL; } else { Print(L" unknown showtools flag: '%s'\n", FlagName); } @@ -401,11 +477,21 @@ VOID ReadConfig(VOID) HandleString(TokenList, TokenCount, &(GlobalConfig.DefaultSelection)); } else if (StriCmp(TokenList[0], L"textonly") == 0) { - GlobalConfig.TextOnly = TRUE; + if ((TokenCount >= 2) && (StriCmp(TokenList[1], L"0") == 0)) { + GlobalConfig.TextOnly = FALSE; + } else { + GlobalConfig.TextOnly = TRUE; + } - } else if ((StriCmp(TokenList[0], L"resolution") == 0) && (TokenCount == 3)) { + } else if (StriCmp(TokenList[0], L"textmode") == 0) { + HandleInt(TokenList, TokenCount, &(GlobalConfig.RequestedTextMode)); + + } else if ((StriCmp(TokenList[0], L"resolution") == 0) && ((TokenCount == 2) || (TokenCount == 3))) { GlobalConfig.RequestedScreenWidth = Atoi(TokenList[1]); - GlobalConfig.RequestedScreenHeight = Atoi(TokenList[2]); + if (TokenCount == 3) + GlobalConfig.RequestedScreenHeight = Atoi(TokenList[2]); + else + GlobalConfig.RequestedScreenHeight = 0; } else if (StriCmp(TokenList[0], L"use_graphics_for") == 0) { GlobalConfig.GraphicsFor = 0; @@ -424,13 +510,19 @@ VOID ReadConfig(VOID) } // for (graphics_on tokens) } else if (StriCmp(TokenList[0], L"scan_all_linux_kernels") == 0) { - GlobalConfig.ScanAllLinux = TRUE; + if ((TokenCount >= 2) && (StriCmp(TokenList[1], L"0") == 0)) { + GlobalConfig.ScanAllLinux = FALSE; + } else { + GlobalConfig.ScanAllLinux = TRUE; + } } else if (StriCmp(TokenList[0], L"max_tags") == 0) { HandleInt(TokenList, TokenCount, &(GlobalConfig.MaxTags)); - } else if ((StriCmp(TokenList[0], L"space_after_boot_options") == 0) && (TokenCount == 2)) { - GlobalConfig.SpaceAfterBootOptions = (StriCmp(TokenList[1], L"true") == 0); + } else if ((StriCmp(TokenList[0], L"include") == 0) && (TokenCount == 2) && (StriCmp(FileName, CONFIG_FILE_NAME) == 0)) { + if (StriCmp(TokenList[1], FileName) != 0) { + ReadConfig(TokenList[1]); + } } @@ -439,6 +531,39 @@ VOID ReadConfig(VOID) MyFreePool(File.Buffer); } /* VOID ReadConfig() */ +// Finds a volume with the specified Identifier (a volume label or a number +// followed by a colon, for the moment). If found, sets *Volume to point to +// 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; + INTN Number = -1; + BOOLEAN Found = FALSE; + + if ((StrLen(Identifier) >= 2) && (Identifier[StrLen(Identifier) - 1] == L':') && + (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) { + Number = (INTN) Atoi(Identifier); + } + while ((i < VolumesCount) && (!Found)) { + if (Number >= 0) { // User specified a volume by number + if (Volumes[i]->IsReadable) { + if (CountedVolumes == Number) { + *Volume = Volumes[i]; + Found = TRUE; + } + CountedVolumes++; + } // if + } else { // User specified a volume by label + if (StriCmp(Identifier, Volumes[i]->VolName) == 0) { + *Volume = Volumes[i]; + Found = TRUE; + } // if + } // if/else + i++; + } // while() + return (Found); +} // static VOID FindVolume() + static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volume, CHAR16 *Title) { REFIT_MENU_SCREEN *SubScreen; LOADER_ENTRY *SubEntry; @@ -461,6 +586,15 @@ static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volu SubEntry->LoaderPath = StrDuplicate(TokenList[1]); SubEntry->DevicePath = FileDevicePath(Volume->DeviceHandle, SubEntry->LoaderPath); + } else if ((StriCmp(TokenList[0], L"volume") == 0) && (TokenCount > 1)) { + if (FindVolume(&Volume, TokenList[1])) { + MyFreePool(SubEntry->me.Title); + SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(SubEntry->me.Title, 255, L"Boot %s from %s", (Title != NULL) ? Title : L"Unknown", Volume->VolName); + SubEntry->me.BadgeImage = Volume->VolBadgeImage; + SubEntry->VolName = Volume->VolName; + } // if match found + } else if (StriCmp(TokenList[0], L"initrd") == 0) { MyFreePool(SubEntry->InitrdPath); SubEntry->InitrdPath = NULL; @@ -500,39 +634,6 @@ static VOID AddSubmenu(LOADER_ENTRY *Entry, REFIT_FILE *File, REFIT_VOLUME *Volu Entry->me.SubScreen = SubScreen; } // VOID AddSubmenu() -// Finds a volume with the specified Identifier (a volume label or a number -// followed by a colon, for the moment). If found, sets *Volume to point to -// 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; - INTN Number = -1; - BOOLEAN Found = FALSE; - - if ((StrLen(Identifier) >= 2) && (Identifier[StrLen(Identifier) - 1] == L':') && - (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) { - Number = (INTN) Atoi(Identifier); - } - while ((i < VolumesCount) && (!Found)) { - if (Number >= 0) { // User specified a volume by number - if (Volumes[i]->IsReadable) { - if (CountedVolumes == Number) { - *Volume = Volumes[i]; - Found = TRUE; - } - CountedVolumes++; - } // if - } else { // User specified a volume by label - if (StriCmp(Identifier, Volumes[i]->VolName) == 0) { - *Volume = Volumes[i]; - Found = TRUE; - } // if - } // if/else - i++; - } // while() - return (Found); -} // static VOID FindVolume() - // Adds the options from a SINGLE refind.conf stanza to a new loader entry and returns // that entry. The calling function is then responsible for adding the entry to the // list of entries. @@ -565,6 +666,7 @@ static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, C MyFreePool(Entry->LoadOptions); Entry->LoadOptions = NULL; // Discard default options, if any DefaultsSet = TRUE; + } else if ((StriCmp(TokenList[0], L"volume") == 0) && (TokenCount > 1)) { if (FindVolume(&CurrentVolume, TokenList[1])) { MyFreePool(Entry->me.Title); @@ -573,29 +675,37 @@ static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, C Entry->me.BadgeImage = CurrentVolume->VolBadgeImage; Entry->VolName = CurrentVolume->VolName; } // if match found + } else if ((StriCmp(TokenList[0], L"icon") == 0) && (TokenCount > 1)) { MyFreePool(Entry->me.Image); Entry->me.Image = LoadIcns(CurrentVolume->RootDir, TokenList[1], 128); if (Entry->me.Image == NULL) { Entry->me.Image = DummyImage(128); } + } else if ((StriCmp(TokenList[0], L"initrd") == 0) && (TokenCount > 1)) { MyFreePool(Entry->InitrdPath); Entry->InitrdPath = StrDuplicate(TokenList[1]); + } else if ((StriCmp(TokenList[0], L"options") == 0) && (TokenCount > 1)) { MyFreePool(Entry->LoadOptions); Entry->LoadOptions = StrDuplicate(TokenList[1]); + } else if ((StriCmp(TokenList[0], L"ostype") == 0) && (TokenCount > 1)) { if (TokenCount > 1) { Entry->OSType = TokenList[1][0]; } + } else if ((StriCmp(TokenList[0], L"graphics") == 0) && (TokenCount > 1)) { Entry->UseGraphicsMode = (StriCmp(TokenList[1], L"on") == 0); + } else if (StriCmp(TokenList[0], L"disabled") == 0) { Entry->Enabled = FALSE; + } else if ((StriCmp(TokenList[0], L"submenuentry") == 0) && (TokenCount > 1)) { AddSubmenu(Entry, File, CurrentVolume, TokenList[1]); AddedSubmenu = TRUE; + } // set options to pass to the loader program FreeTokenLine(&TokenList, &TokenCount); } // while() @@ -616,7 +726,7 @@ static LOADER_ENTRY * AddStanzaEntries(REFIT_FILE *File, REFIT_VOLUME *Volume, C return(Entry); } // static VOID AddStanzaEntries() -// Read the user-configured loaders file, refind_loaders.conf, and add or delete +// Read the user-configured menu entries from refind.conf and add or delete // entries based on the contents of that file.... VOID ScanUserConfigured(VOID) { @@ -625,11 +735,11 @@ VOID ScanUserConfigured(VOID) REFIT_VOLUME *Volume; CHAR16 **TokenList; CHAR16 *Title = NULL; - UINTN TokenCount; + UINTN TokenCount, size; LOADER_ENTRY *Entry; if (FileExists(SelfDir, CONFIG_FILE_NAME)) { - Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File); + Status = ReadFile(SelfDir, CONFIG_FILE_NAME, &File, &size); if (EFI_ERROR(Status)) return; @@ -669,7 +779,7 @@ VOID ScanUserConfigured(VOID) REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 *OptionsFilename, *FullFilename; BOOLEAN GoOn = TRUE; - UINTN i = 0; + UINTN i = 0, size; REFIT_FILE *File = NULL; EFI_STATUS Status; @@ -680,7 +790,7 @@ REFIT_FILE * ReadLinuxOptionsFile(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume MergeStrings(&FullFilename, OptionsFilename, '\\'); if (FileExists(Volume->RootDir, FullFilename)) { File = AllocateZeroPool(sizeof(REFIT_FILE)); - Status = ReadFile(Volume->RootDir, FullFilename, File); + Status = ReadFile(Volume->RootDir, FullFilename, File, &size); GoOn = FALSE; if (CheckError(Status, L"while loading the Linux options file")) { if (File != NULL)