/* * refit/scan/legacy.c * * Copyright (c) 2006-2010 Christoph Pfisterer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * * Neither the name of Christoph Pfisterer nor the names of the * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "entry_scan.h" #ifndef DEBUG_ALL #define DEBUG_SCAN_LEGACY 1 #else #define DEBUG_SCAN_LEGACY DEBUG_ALL #endif #if DEBUG_SCAN_LEGACY == 0 #define DBG(...) #else #define DBG(...) DebugLog(DEBUG_SCAN_LEGACY, __VA_ARGS__) #endif static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *FullTitle, IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume, IN EG_IMAGE *Image, IN EG_IMAGE *DriveImage, IN CHAR16 Hotkey, IN BOOLEAN CustomEntry) { LEGACY_ENTRY *Entry, *SubEntry; REFIT_MENU_SCREEN *SubScreen; CONST CHAR16 *VolDesc; CHAR16 ShortcutLetter = 0; INTN i; if (Volume == NULL) { return NULL; } // Ignore this loader if it's device path is already present in another loader if (MainMenu.Entries) { for (i = 0; i < MainMenu.EntryCount; ++i) { REFIT_MENU_ENTRY *MainEntry = MainMenu.Entries[i]; // Only want legacy if (MainEntry && (MainEntry->Tag == TAG_LEGACY)) { LOADER_ENTRY *Loader = (LOADER_ENTRY *)MainEntry; if (StriCmp(Loader->DevicePathString, Volume->DevicePathString) == 0) { return NULL; } } } } // If this isn't a custom entry make sure it's not hidden by a custom entry if (!CustomEntry) { CUSTOM_LEGACY_ENTRY *Custom = gSettings.CustomLegacy; while (Custom) { if (OSFLAG_ISSET(Custom->Flags, OSFLAG_DISABLED) || (OSFLAG_ISSET(Custom->Flags, OSFLAG_HIDDEN) && !gSettings.ShowHiddenEntries)) { if (Custom->Volume) { if ((StrStr(Volume->DevicePathString, Custom->Volume) == NULL) && ((Volume->VolName == NULL) || (StrStr(Volume->VolName, Custom->Volume) == NULL))) { if (Custom->Type != 0) { if (Custom->Type == Volume->LegacyOS->Type) { return NULL; } } else { return NULL; } } } else if (Custom->Type != 0) { if (Custom->Type == Volume->LegacyOS->Type) { return NULL; } } } Custom = Custom->Next; } } if (LoaderTitle == NULL) { if (Volume->LegacyOS->Name != NULL) { LoaderTitle = Volume->LegacyOS->Name; if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L') ShortcutLetter = LoaderTitle[0]; } else LoaderTitle = L"Legacy OS"; } if (Volume->VolName != NULL) VolDesc = Volume->VolName; else VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD"; // prepare the menu entry Entry = (__typeof__(Entry))AllocateZeroPool(sizeof(LEGACY_ENTRY)); if (FullTitle) { Entry->me.Title = EfiStrDuplicate(FullTitle); } else { if (GlobalConfig.BootCampStyle) { Entry->me.Title = PoolPrint(L"%s", LoaderTitle); } else { Entry->me.Title = PoolPrint(L"Boot %s from %s", LoaderTitle, VolDesc); } } Entry->me.Tag = TAG_LEGACY; Entry->me.Row = 0; Entry->me.ShortcutLetter = (Hotkey == 0) ? ShortcutLetter : Hotkey; if (Image) { Entry->me.Image = Image; } else { Entry->me.Image = LoadOSIcon(Volume->LegacyOS->IconName, L"legacy", 128, FALSE, TRUE); } Entry->me.DriveImage = (DriveImage != NULL) ? DriveImage : ScanVolumeDefaultIcon(Volume, Volume->LegacyOS->Type, Volume->DevicePath); // DBG("HideBadges=%d Volume=%s\n", GlobalConfig.HideBadges, Volume->VolName); // DBG("Title=%s OSName=%s OSIconName=%s\n", LoaderTitle, Volume->OSName, Volume->OSIconName); //actions Entry->me.AtClick = ActionSelect; Entry->me.AtDoubleClick = ActionEnter; Entry->me.AtRightClick = ActionDetails; if (GlobalConfig.HideBadges & HDBADGES_SHOW) { if (GlobalConfig.HideBadges & HDBADGES_SWAP) { Entry->me.BadgeImage = egCopyScaledImage(Entry->me.DriveImage, GlobalConfig.BadgeScale); } else { Entry->me.BadgeImage = egCopyScaledImage(Entry->me.Image, GlobalConfig.BadgeScale); } } Entry->Volume = Volume; Entry->DevicePathString = Volume->DevicePathString; Entry->LoadOptions = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD"); // create the submenu SubScreen = (__typeof__(SubScreen))AllocateZeroPool(sizeof(REFIT_MENU_SCREEN)); SubScreen->Title = PoolPrint(L"Boot Options for %s on %s", LoaderTitle, VolDesc); SubScreen->TitleImage = Entry->me.Image; SubScreen->AnimeRun = GetAnime(SubScreen); // default entry SubEntry = (__typeof__(SubEntry))AllocateZeroPool(sizeof(LEGACY_ENTRY)); SubEntry->me.Title = PoolPrint(L"Boot %s", LoaderTitle); SubEntry->me.Tag = TAG_LEGACY; SubEntry->Volume = Entry->Volume; SubEntry->DevicePathString = Entry->DevicePathString; SubEntry->LoadOptions = Entry->LoadOptions; SubEntry->me.AtClick = ActionEnter; AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry); AddMenuEntry(SubScreen, &MenuEntryReturn); Entry->me.SubScreen = SubScreen; AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry); DBG(" added '%s' OSType=%d Icon=%s\n", Entry->me.Title, Volume->LegacyOS->Type, Volume->LegacyOS->IconName); return Entry; } VOID ScanLegacy(VOID) { UINTN VolumeIndex, VolumeIndex2; BOOLEAN ShowVolume, HideIfOthersFound; REFIT_VOLUME *Volume; DBG("Scanning legacy ...\n"); for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; if ((Volume->BootType != BOOTING_BY_PBR) && (Volume->BootType != BOOTING_BY_MBR) && (Volume->BootType != BOOTING_BY_CD)) { // DBG(" not legacy\n"); continue; } DBG("%2d: '%s' (%s)", VolumeIndex, Volume->VolName, Volume->LegacyOS->IconName); #if 0 // REFIT_DEBUG > 0 DBG(" %d %s\n %d %d %s %d %s\n", VolumeIndex, FileDevicePathToStr(Volume->DevicePath), Volume->DiskKind, Volume->MbrPartitionIndex, Volume->IsAppleLegacy ? L"AL" : L"--", Volume->HasBootCode, Volume->VolName ? Volume->VolName : L"(no name)"); #endif // skip volume if its kind is configured as disabled if ((Volume->DiskKind == DISK_KIND_OPTICAL && (GlobalConfig.DisableFlags & VOLTYPE_OPTICAL)) || (Volume->DiskKind == DISK_KIND_EXTERNAL && (GlobalConfig.DisableFlags & VOLTYPE_EXTERNAL)) || (Volume->DiskKind == DISK_KIND_INTERNAL && (GlobalConfig.DisableFlags & VOLTYPE_INTERNAL)) || (Volume->DiskKind == DISK_KIND_FIREWIRE && (GlobalConfig.DisableFlags & VOLTYPE_FIREWIRE))) { DBG(" hidden\n"); continue; } ShowVolume = FALSE; HideIfOthersFound = FALSE; if (Volume->IsAppleLegacy) { ShowVolume = TRUE; HideIfOthersFound = TRUE; } else if (Volume->HasBootCode) { ShowVolume = TRUE; //DBG("Volume %d will be shown BlockIo=%x WholeIo=%x\n", // VolumeIndex, Volume->BlockIO, Volume->WholeDiskBlockIO); if ((Volume->WholeDiskBlockIO == 0) && Volume->BlockIOOffset == 0 /* && Volume->OSName == NULL */) // this is a whole disk (MBR) entry; hide if we have entries for partitions HideIfOthersFound = TRUE; } if (HideIfOthersFound) { // check for other bootable entries on the same disk //if PBR exists then Hide MBR for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode && Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->BlockIO){ ShowVolume = FALSE; // DBG("PBR volume at index %d\n", VolumeIndex2); break; } } } if (ShowVolume && (!Volume->Hidden)){ DBG(" add legacy\n"); AddLegacyEntry(NULL, NULL, Volume, NULL, NULL, 0, FALSE); } else { DBG(" hidden\n"); } } } // Add custom legacy VOID AddCustomLegacy(VOID) { UINTN VolumeIndex, VolumeIndex2; BOOLEAN ShowVolume, HideIfOthersFound; REFIT_VOLUME *Volume; CUSTOM_LEGACY_ENTRY *Custom; EG_IMAGE *Image, *DriveImage; UINTN i = 0; // DBG("Custom legacy start\n"); if (gSettings.CustomLegacy) { DbgHeader("AddCustomLegacy"); } // Traverse the custom entries for (Custom = gSettings.CustomLegacy; Custom; ++i, Custom = Custom->Next) { if (OSFLAG_ISSET(Custom->Flags, OSFLAG_DISABLED)) { DBG("Custom legacy %d skipped because it is disabled.\n", i); continue; } if (!gSettings.ShowHiddenEntries && OSFLAG_ISSET(Custom->Flags, OSFLAG_HIDDEN)) { DBG("Custom legacy %d skipped because it is hidden.\n", i); continue; } if (Custom->Volume) { DBG("Custom legacy %d matching \"%s\" ...\n", i, Custom->Volume); } for (VolumeIndex = 0; VolumeIndex < VolumesCount; ++VolumeIndex) { Volume = Volumes[VolumeIndex]; DBG(" Checking volume \"%s\" (%s) ... ", Volume->VolName, Volume->DevicePathString); // skip volume if its kind is configured as disabled if ((Volume->DiskKind == DISK_KIND_OPTICAL && (GlobalConfig.DisableFlags & VOLTYPE_OPTICAL)) || (Volume->DiskKind == DISK_KIND_EXTERNAL && (GlobalConfig.DisableFlags & VOLTYPE_EXTERNAL)) || (Volume->DiskKind == DISK_KIND_INTERNAL && (GlobalConfig.DisableFlags & VOLTYPE_INTERNAL)) || (Volume->DiskKind == DISK_KIND_FIREWIRE && (GlobalConfig.DisableFlags & VOLTYPE_FIREWIRE))) { DBG("skipped because media is disabled\n"); continue; } if (Custom->VolumeType != 0) { if ((Volume->DiskKind == DISK_KIND_OPTICAL && ((Custom->VolumeType & VOLTYPE_OPTICAL) == 0)) || (Volume->DiskKind == DISK_KIND_EXTERNAL && ((Custom->VolumeType & VOLTYPE_EXTERNAL) == 0)) || (Volume->DiskKind == DISK_KIND_INTERNAL && ((Custom->VolumeType & VOLTYPE_INTERNAL) == 0)) || (Volume->DiskKind == DISK_KIND_FIREWIRE && ((Custom->VolumeType & VOLTYPE_FIREWIRE) == 0))) { DBG("skipped because media is ignored\n"); continue; } } if ((Volume->BootType != BOOTING_BY_PBR) && (Volume->BootType != BOOTING_BY_MBR) && (Volume->BootType != BOOTING_BY_CD)) { DBG("skipped because volume is not legacy bootable\n"); continue; } ShowVolume = FALSE; HideIfOthersFound = FALSE; if (Volume->IsAppleLegacy) { ShowVolume = TRUE; HideIfOthersFound = TRUE; } else if (Volume->HasBootCode) { ShowVolume = TRUE; if ((Volume->WholeDiskBlockIO == 0) && Volume->BlockIOOffset == 0) { // this is a whole disk (MBR) entry; hide if we have entries for partitions HideIfOthersFound = TRUE; } } if (HideIfOthersFound) { // check for other bootable entries on the same disk //if PBR exists then Hide MBR for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) { if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode && Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->BlockIO) { ShowVolume = FALSE; break; } } } if (!ShowVolume || (Volume->Hidden)) { DBG("skipped because volume is hidden\n"); continue; } // Check for exact volume matches if (Custom->Volume) { if ((StrStr(Volume->DevicePathString, Custom->Volume) == NULL) && ((Volume->VolName == NULL) || (StrStr(Volume->VolName, Custom->Volume) == NULL))) { DBG("skipped\n"); continue; } // Check if the volume should be of certain os type if ((Custom->Type != 0) && (Custom->Type != Volume->LegacyOS->Type)) { DBG("skipped because wrong type\n"); continue; } } else if ((Custom->Type != 0) && (Custom->Type != Volume->LegacyOS->Type)) { DBG("skipped because wrong type\n"); continue; } // Change to custom image if needed Image = Custom->Image; if ((Image == NULL) && Custom->ImagePath) { Image = egLoadImage(Volume->RootDir, Custom->ImagePath, TRUE); if (Image == NULL) { Image = egLoadImage(ThemeDir, Custom->ImagePath, TRUE); if (Image == NULL) { Image = egLoadImage(SelfDir, Custom->ImagePath, TRUE); if (Image == NULL) { Image = egLoadImage(SelfRootDir, Custom->ImagePath, TRUE); if (Image == NULL) { Image = LoadOSIcon(Custom->ImagePath, L"unknown", 128, FALSE, FALSE); } } } } } // Change to custom drive image if needed DriveImage = Custom->DriveImage; if ((DriveImage == NULL) && Custom->DriveImagePath) { DriveImage = egLoadImage(Volume->RootDir, Custom->DriveImagePath, TRUE); if (DriveImage == NULL) { DriveImage = egLoadImage(ThemeDir, Custom->DriveImagePath, TRUE); if (DriveImage == NULL) { DriveImage = egLoadImage(SelfDir, Custom->DriveImagePath, TRUE); if (DriveImage == NULL) { DriveImage = egLoadImage(SelfRootDir, Custom->DriveImagePath, TRUE); if (DriveImage == NULL) { DriveImage = LoadBuiltinIcon(Custom->DriveImagePath); } } } } } // Create a legacy entry for this volume AddLegacyEntry(Custom->FullTitle, Custom->Title, Volume, Image, DriveImage, Custom->Hotkey, TRUE); DBG("match!\n"); } } //DBG("Custom legacy end\n"); }