X-Git-Url: https://code.delx.au/refind/blobdiff_plain/514e47ab9e1a2ed6c82e8ddbd8f78e04bfc3a057..622ed08c231f81a83b5e2807e7abace1dec9502f:/refind/main.c diff --git a/refind/main.c b/refind/main.c index ea16053..0196aab 100644 --- a/refind/main.c +++ b/refind/main.c @@ -49,6 +49,7 @@ #include "icns.h" #include "menu.h" #include "refit_call_wrapper.h" +#include "driver_support.h" #include "../include/syslinux_mbr.h" // @@ -72,7 +73,7 @@ static REFIT_MENU_ENTRY MenuEntryExit = { L"Exit rEFInd", TAG_EXIT, 1, 0, 0, static REFIT_MENU_SCREEN MainMenu = { L"Main Menu", NULL, 0, NULL, 0, NULL, 0, L"Automatic boot" }; static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL }; -REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, +REFIT_CONFIG GlobalConfig = { FALSE, 20, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, {TAG_SHELL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, 0, 0, 0, 0, 0 }}; // @@ -83,7 +84,7 @@ static VOID AboutrEFInd(VOID) { if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.4.2"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.7.1"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -115,7 +116,8 @@ static VOID AboutrEFInd(VOID) static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, IN CHAR16 *ImageTitle, - OUT UINTN *ErrorInStep) + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose) { EFI_STATUS Status, ReturnStatus; EFI_HANDLE ChildImageHandle; @@ -124,7 +126,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, CHAR16 ErrorInfo[256]; CHAR16 *FullLoadOptions = NULL; - Print(L"Starting %s\n", ImageTitle); + if (Verbose) + Print(L"Starting %s\n", ImageTitle); if (ErrorInStep != NULL) *ErrorInStep = 0; @@ -160,7 +163,8 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, // NOTE: We also include the terminating null in the length for safety. ChildLoadedImage->LoadOptions = (VOID *)LoadOptions; ChildLoadedImage->LoadOptionsSize = ((UINT32)StrLen(LoadOptions) + 1) * sizeof(CHAR16); - Print(L"Using load options '%s'\n", LoadOptions); + if (Verbose) + Print(L"Using load options '%s'\n", LoadOptions); } // close open file handles @@ -175,7 +179,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, if (ErrorInStep != NULL) *ErrorInStep = 3; } - + // re-open file handles ReinitRefitLib(); @@ -191,13 +195,14 @@ bailout: static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix, IN CHAR16 *ImageTitle, - OUT UINTN *ErrorInStep) + OUT UINTN *ErrorInStep, + IN BOOLEAN Verbose) { EFI_DEVICE_PATH *DevicePaths[2]; - + DevicePaths[0] = DevicePath; DevicePaths[1] = NULL; - return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep); + return StartEFIImageList(DevicePaths, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep, Verbose); } /* static EFI_STATUS StartEFIImage() */ // @@ -210,7 +215,7 @@ static VOID StartLoader(IN LOADER_ENTRY *Entry) BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); StartEFIImage(Entry->DevicePath, Entry->LoadOptions, - Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep); + Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), &ErrorInStep, TRUE); FinishExternalScreen(); } @@ -234,15 +239,25 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { KernelVersion = FindNumbers(FileName); Path = FindPath(LoaderPath); + // Add trailing backslash for root directory; necessary on some systems, but must + // NOT be added to all directories, since on other systems, a trailing backslash on + // anything but the root directory causes them to flake out! + if (StrLen(Path) == 0) { + MergeStrings(&Path, L"\\", 0); + } // if DirIterOpen(Volume->RootDir, Path, &DirIter); + // Now add a trailing backslash if it was NOT added earlier, for consistency in + // 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)) { InitrdVersion = FindNumbers(DirEntry->FileName); if (KernelVersion != NULL) { if (StriCmp(InitrdVersion, KernelVersion) == 0) - InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } else { if (InitrdVersion == NULL) - InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } // if/else if (InitrdVersion != NULL) FreePool(InitrdVersion); @@ -340,7 +355,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { Entry->Title = NULL; } SubScreen = InitializeSubScreen(Entry); - + // loader-specific submenu entries if (Entry->OSType == 'M') { // entries for Mac OS X #if defined(EFIX64) @@ -367,7 +382,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { SubEntry->LoadOptions = L"-v"; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } // if - + #if defined(EFIX64) SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { @@ -385,7 +400,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); } #endif - + SubEntry = InitializeLoaderEntry(Entry); if (SubEntry != NULL) { SubEntry->me.Title = L"Boot Mac OS X in single user mode"; @@ -467,7 +482,7 @@ VOID GenerateSubScreen(LOADER_ENTRY *Entry, IN REFIT_VOLUME *Volume) { AddMenuInfoLine(SubScreen, L"NOTE: This is an example. Entries"); AddMenuInfoLine(SubScreen, L"marked with (*) may not work."); - + } else if (Entry->OSType == 'X') { // entries for xom.efi // by default, skip the built-in selection and boot from hard disk only Entry->LoadOptions = L"-s -h"; @@ -521,17 +536,20 @@ static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Vol // that will (with luck) work fairly automatically. VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 IconFileName[256]; - CHAR16 *FileName, *OSIconName = NULL, *Temp; + CHAR16 *FileName, *PathOnly, *OSIconName = NULL, *Temp; CHAR16 ShortcutLetter = 0; FileName = Basename(LoaderPath); + PathOnly = FindPath(LoaderPath); // locate a custom icon for the loader StrCpy(IconFileName, LoaderPath); ReplaceExtension(IconFileName, L".icns"); if (FileExists(Volume->RootDir, IconFileName)) { Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128); - } // if + } else if ((StrLen(PathOnly) == 0) && (Volume->VolIconImage != NULL)) { + Entry->me.Image = Volume->VolIconImage; + } // icon matched to loader or volume Temp = FindLastDirName(LoaderPath); MergeStrings(&OSIconName, Temp, L','); @@ -552,6 +570,9 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) { + if (Volume->VolIconImage != NULL) { // custom icon file found + Entry->me.Image = Volume->VolIconImage; + } MergeStrings(&OSIconName, L"mac", L','); Entry->UseGraphicsMode = TRUE; Entry->OSType = 'M'; @@ -581,6 +602,8 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Entry->me.ShortcutLetter = ShortcutLetter; if (Entry->me.Image == NULL) Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); + if (PathOnly != NULL) + FreePool(PathOnly); } // VOID SetLoaderDefaults() // Add a specified EFI boot loader to the list, using automatic settings @@ -588,6 +611,7 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume) { LOADER_ENTRY *Entry; + CleanUpPathNameSlashes(LoaderPath); Entry = InitializeLoaderEntry(NULL); if (Entry != NULL) { Entry->Title = StrDuplicate(LoaderTitle); @@ -601,7 +625,7 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN GenerateSubScreen(Entry, Volume); AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); } - + return(Entry); } // LOADER_ENTRY * AddLoaderEntry() @@ -612,12 +636,18 @@ static VOID ScanLoaderDir(IN REFIT_VOLUME *Volume, IN CHAR16 *Path) EFI_STATUS Status; REFIT_DIR_ITER DirIter; EFI_FILE_INFO *DirEntry; - CHAR16 FileName[256]; + CHAR16 FileName[256], *SelfPath; + UINTN i = 0; - // Note: SelfDirPath includes a leading backslash ('\'), but Path - // doesn't, so we rejigger the string to compensate.... - if (!SelfDirPath || !Path || ((StriCmp(Path, &SelfDirPath[1]) == 0) && Volume != SelfVolume) || - (StriCmp(Path, &SelfDirPath[1]) != 0)) { + // Skip past leading slashes, which are sometimes (but not always) included + // in SelfDirPath, to get a path that's known to never include this feature. + while ((SelfDirPath != NULL) && (SelfDirPath[i] == L'\\')) { + i++; + } + SelfPath = &SelfDirPath[i]; // NOTE: *DO NOT* call FreePool() on SelfPath!!! + + if (!SelfPath || !Path || ((StriCmp(Path, SelfPath) == 0) && Volume != SelfVolume) || + (StriCmp(Path, SelfPath) != 0)) { // look through contents of the directory DirIterOpen(Volume->RootDir, Path, &DirIter); while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) { @@ -649,7 +679,8 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { EFI_STATUS Status; REFIT_DIR_ITER EfiDirIter; EFI_FILE_INFO *EfiDirEntry; - CHAR16 FileName[256]; + CHAR16 FileName[256], *Directory; + UINTN i, Length; if ((Volume->RootDir != NULL) && (Volume->VolName != NULL)) { // check for Mac OS X boot loader @@ -672,10 +703,6 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { // scan the root directory for EFI executables ScanLoaderDir(Volume, NULL); - // scan the elilo directory (as used on gimli's first Live CD) - ScanLoaderDir(Volume, L"elilo"); - // scan the boot directory - ScanLoaderDir(Volume, L"boot"); // scan subdirectories of the EFI directory (as per the standard) DirIterOpen(Volume->RootDir, L"EFI", &EfiDirIter); @@ -688,6 +715,20 @@ static VOID ScanEfiFiles(REFIT_VOLUME *Volume) { Status = DirIterClose(&EfiDirIter); if (Status != EFI_NOT_FOUND) CheckError(Status, L"while scanning the EFI directory"); + + // Scan user-specified (or additional default) directories.... + i = 0; + while ((Directory = FindCommaDelimited(GlobalConfig.AlsoScan, i++)) != NULL) { + Length = StrLen(Directory); + // Some EFI implementations won't read a directory if the path ends in + // a backslash, so eliminate this character, if it's present.... + while ((Length > 0) && (Directory[Length - 1] == L'\\')) { + Directory[--Length] = 0; + } // while + if (Length > 0) + ScanLoaderDir(Volume, Directory); + FreePool(Directory); + } // while } // if } // static VOID ScanEfiFiles() @@ -819,7 +860,7 @@ static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN Partit if (PartitionIndex < LogicalPartitionIndex) break; // stop the loop, no need to touch further EMBRs } - + } return EFI_SUCCESS; @@ -903,7 +944,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); - Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep); + Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, NULL, L"legacy loader", &ErrorInStep, TRUE); if (Status == EFI_NOT_FOUND) { if (ErrorInStep == 1) { Print(L"\nPlease make sure that you have the latest firmware update installed.\n"); @@ -960,7 +1001,7 @@ static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Vo SubEntry->Volume = Entry->Volume; SubEntry->LoadOptions = Entry->LoadOptions; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); - + AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); @@ -1047,7 +1088,7 @@ static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start