X-Git-Url: https://code.delx.au/refind/blobdiff_plain/70c59b783f94768bd5875f44be2808454d000f3e..0d5abdda4c44431486484d4f5d3627967e005210:/refind/main.c diff --git a/refind/main.c b/refind/main.c index fc8d68d..bdfa6ac 100644 --- a/refind/main.c +++ b/refind/main.c @@ -34,7 +34,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* - * Modifications copyright (c) 2012-2016 Roderick W. Smith + * Modifications copyright (c) 2012-2017 Roderick W. Smith * * Modifications distributed under the terms of the GNU General Public * License (GPL) version 3 (GPLv3), or (at your option) any later version. @@ -157,16 +157,16 @@ static REFIT_MENU_ENTRY MenuEntryRotateCsr = { L"Change SIP Policy", TAG_CSR_ROT REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot", L"Use arrow keys to move cursor; Enter to boot;", - L"Insert or F2 for more options; Esc to refresh" }; + L"Insert, Tab, or F2 for more options; Esc or Backspace 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, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, +REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, 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, NULL, CONFIG_FILE_NAME, NULL, NULL, 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, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, + TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, TAG_FWUPDATE_TOOL, 0, 0, 0, 0, 0, 0, 0, 0 } }; @@ -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 -// 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; @@ -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); - 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); @@ -1300,9 +1327,7 @@ static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) return FALSE; } - if (FallbackSize != FileSize) { // not same size, so can't be identical - AreIdentical = FALSE; - } else { // could be identical; do full check.... + if (FallbackSize == FileSize) { // could be identical; do full check.... FileContents = AllocatePool(FileSize); FallbackContents = AllocatePool(FallbackSize); if (FileContents && FallbackContents) { @@ -1333,25 +1358,20 @@ static BOOLEAN DuplicatesFallback(IN REFIT_VOLUME *Volume, IN CHAR16 *FileName) // file to fail to open, which would return a false positive -- but as I use // this function to exclude symbolic links from the list of boot loaders, // that would be fine, since such boot loaders wouldn't work.) -static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO *DirEntry) { +// CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) +static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *FullName, EFI_FILE_INFO *DirEntry) { EFI_FILE_HANDLE FileHandle; EFI_FILE_INFO *FileInfo = NULL; EFI_STATUS Status; UINTN FileSize2 = 0; - CHAR16 *FileName; - FileName = StrDuplicate(Path); - MergeStrings(&FileName, DirEntry->FileName, L'\\'); - CleanUpPathNameSlashes(FileName); - - Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0); + Status = refit_call5_wrapper(Volume->RootDir->Open, Volume->RootDir, &FileHandle, FullName, EFI_FILE_MODE_READ, 0); if (Status == EFI_SUCCESS) { FileInfo = LibFileInfo(FileHandle); if (FileInfo != NULL) FileSize2 = FileInfo->FileSize; } - MyFreePool(FileName); MyFreePool(FileInfo); return (DirEntry->FileSize != FileSize2); @@ -1363,15 +1383,14 @@ static BOOLEAN IsSymbolicLink(REFIT_VOLUME *Volume, CHAR16 *Path, EFI_FILE_INFO // there's no point in cluttering the display with two kernels that will // behave identically on non-SB systems, or when one will fail when SB // is active. -static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 *Filename) { +// CAUTION: *FullName MUST be properly cleaned up (via CleanUpPathNameSlashes()) +static BOOLEAN HasSignedCounterpart(IN REFIT_VOLUME *Volume, IN CHAR16 *FullName) { CHAR16 *NewFile = NULL; BOOLEAN retval = FALSE; - MergeStrings(&NewFile, Path, 0); - MergeStrings(&NewFile, Filename, L'\\'); + MergeStrings(&NewFile, FullName, 0); MergeStrings(&NewFile, L".efi.signed", 0); if (NewFile != NULL) { - CleanUpPathNameSlashes(NewFile); if (FileExists(Volume->RootDir, NewFile)) retval = TRUE; MyFreePool(NewFile); @@ -1390,7 +1409,7 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 EFI_STATUS Status; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; - CHAR16 FileName[256], *Extension; + CHAR16 Message[256], *Extension, *FullName; struct LOADER_LIST *LoaderList = NULL, *NewLoader; LOADER_ENTRY *FirstKernel = NULL, *LatestEntry = NULL; BOOLEAN FoundFallbackDuplicate = FALSE, IsLinux = FALSE, InSelfPath; @@ -1402,34 +1421,31 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 DirIterOpen(Volume->RootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, Pattern, &DirEntry)) { Extension = FindExtension(DirEntry->FileName); + FullName = StrDuplicate(Path); + MergeStrings(&FullName, DirEntry->FileName, L'\\'); + CleanUpPathNameSlashes(FullName); if (DirEntry->FileName[0] == '.' || MyStriCmp(Extension, L".icns") || MyStriCmp(Extension, L".png") || (MyStriCmp(DirEntry->FileName, FALLBACK_BASENAME) && (MyStriCmp(Path, L"EFI\\BOOT"))) || - StriSubCmp(L"shell", DirEntry->FileName) || - IsSymbolicLink(Volume, Path, DirEntry) || /* is symbolic link */ - HasSignedCounterpart(Volume, Path, DirEntry->FileName) || /* a file with same name plus ".efi.signed" is present */ - FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles)) + FilenameIn(Volume, Path, DirEntry->FileName, SHELL_NAMES) || + IsSymbolicLink(Volume, FullName, DirEntry) || /* is symbolic link */ + HasSignedCounterpart(Volume, FullName) || /* a file with same name plus ".efi.signed" is present */ + FilenameIn(Volume, Path, DirEntry->FileName, GlobalConfig.DontScanFiles) || + !IsValidLoader(Volume->RootDir, FullName)) { continue; // skip this - - if (Path) - SPrint(FileName, 255, L"\\%s\\%s", Path, DirEntry->FileName); - else - SPrint(FileName, 255, L"\\%s", DirEntry->FileName); - CleanUpPathNameSlashes(FileName); - - if(!IsValidLoader(Volume->RootDir, FileName)) - continue; + } NewLoader = AllocateZeroPool(sizeof(struct LOADER_LIST)); if (NewLoader != NULL) { - NewLoader->FileName = StrDuplicate(FileName); + NewLoader->FileName = StrDuplicate(FullName); NewLoader->TimeStamp = DirEntry->ModificationTime; LoaderList = AddLoaderListEntry(LoaderList, NewLoader); - if (DuplicatesFallback(Volume, FileName)) + if (DuplicatesFallback(Volume, FullName)) FoundFallbackDuplicate = TRUE; } // if MyFreePool(Extension); + MyFreePool(FullName); } // while NewLoader = LoaderList; @@ -1457,10 +1473,10 @@ static BOOLEAN ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path, IN CHAR16 // it down to buggy EFI implementations and ignoring that particular error.... if ((Status != EFI_NOT_FOUND) && (Status != EFI_INVALID_PARAMETER)) { if (Path) - SPrint(FileName, 255, L"while scanning the %s directory", Path); + SPrint(Message, 255, L"while scanning the %s directory", Path); else - StrCpy(FileName, L"while scanning the root directory"); - CheckError(Status, FileName); + StrCpy(Message, L"while scanning the root directory"); + CheckError(Status, Message); } // if (Status != EFI_NOT_FOUND) } // if not scanning a blacklisted directory @@ -1920,6 +1936,10 @@ static VOID ScanForTools(VOID) { FindTool(MokLocations, MOK_NAMES, L"MOK utility", BUILTIN_ICON_TOOL_MOK_TOOL); break; + case TAG_FWUPDATE_TOOL: + FindTool(MokLocations, FWUPDATE_NAMES, L"firmware update utility", BUILTIN_ICON_TOOL_FWUPDATE); + break; + case TAG_CSR_ROTATE: if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr);