/* * gptsync/showpart.c * Platform-independent code for analyzing hard disk partitioning * * Copyright (c) 2006 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 "gptsync.h" // // memory string search // static INTN FindMem(VOID *Buffer, UINTN BufferLength, VOID *SearchString, UINTN SearchStringLength) { UINT8 *BufferPtr; UINTN Offset; BufferPtr = Buffer; BufferLength -= SearchStringLength; for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) { if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0) return (INTN)Offset; } return -1; } // // detect boot code // static UINTN detect_bootcode(UINT64 partlba, CHARN **bootcodename) { UINTN status; BOOLEAN bootable; // read MBR data status = read_sector(partlba, sector); if (status != 0) return status; // check bootable signature if (*((UINT16 *)(sector + 510)) == 0xaa55 && sector[0] != 0) bootable = TRUE; else bootable = FALSE; *bootcodename = NULL; // detect specific boot codes if (CompareMem(sector + 2, "LILO", 4) == 0 || CompareMem(sector + 6, "LILO", 4) == 0) { *bootcodename = STR("LILO"); } else if (CompareMem(sector + 3, "SYSLINUX", 8) == 0) { *bootcodename = STR("SYSLINUX"); } else if (FindMem(sector, 512, "ISOLINUX", 8) >= 0) { *bootcodename = STR("ISOLINUX"); } else if (FindMem(sector, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { *bootcodename = STR("GRUB"); } else if ((*((UINT32 *)(sector + 502)) == 0 && *((UINT32 *)(sector + 506)) == 50000 && *((UINT16 *)(sector + 510)) == 0xaa55) || FindMem(sector, 512, "Starting the BTX loader", 23) >= 0) { *bootcodename = STR("FreeBSD"); } else if (FindMem(sector, 512, "!Loading", 8) >= 0 || FindMem(sector, 512, "/cdboot\0/CDBOOT\0", 16) >= 0) { *bootcodename = STR("OpenBSD"); } else if (FindMem(sector, 512, "Not a bootxx image", 18) >= 0) { *bootcodename = STR("NetBSD"); } else if (FindMem(sector, 512, "NTLDR", 5) >= 0) { *bootcodename = STR("Windows NTLDR"); } else if (FindMem(sector, 512, "BOOTMGR", 7) >= 0) { *bootcodename = STR("Windows BOOTMGR (Vista)"); } else if (FindMem(sector, 512, "CPUBOOT SYS", 11) >= 0 || FindMem(sector, 512, "KERNEL SYS", 11) >= 0) { *bootcodename = STR("FreeDOS"); } else if (FindMem(sector, 512, "OS2LDR", 6) >= 0 || FindMem(sector, 512, "OS2BOOT", 7) >= 0) { *bootcodename = STR("eComStation"); } else if (FindMem(sector, 512, "Be Boot Loader", 14) >= 0) { *bootcodename = STR("BeOS"); } else if (FindMem(sector, 512, "yT Boot Loader", 14) >= 0) { *bootcodename = STR("ZETA"); } else if (FindMem(sector, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0) { *bootcodename = STR("Haiku"); } else if (FindMem(sector, 512, "\x0A\x0Dboot0ss: ", 11) >= 0) { *bootcodename = STR ("Mac OS X (boot0ss)"); } else if (FindMem(sector, 512, "\x0A\x0Dboot0af: ", 11) >= 0) { *bootcodename = STR ("Mac OS X (boot0af)"); } else if (FindMem(sector, 512, "\x0A\x0Dboot0: ", 9) >= 0) { *bootcodename = STR ("Mac OS X (boot0)"); } if (FindMem(sector, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector *bootcodename = STR("None (Non-system disk message)"); // TODO: Add a note if a specific code was detected, but the sector is not bootable? if (*bootcodename == NULL) { if (bootable) *bootcodename = STR("Unknown, but bootable"); else *bootcodename = STR("None"); } return 0; } // // check one partition // static UINTN analyze_part(UINT64 partlba) { UINTN status; UINTN i; CHARN *bootcodename; UINTN parttype; CHARN *fsname; if (partlba == 0) Print(L"\nMBR contents:\n"); else Print(L"\nPartition at LBA %lld:\n", partlba); // detect boot code status = detect_bootcode(partlba, &bootcodename); if (status) return status; Print(L" Boot Code: %s\n", bootcodename); if (partlba == 0) return 0; // short-circuit MBR analysis // detect file system status = detect_mbrtype_fs(partlba, &parttype, &fsname); if (status) return status; Print(L" File System: %s\n", fsname); // cross-reference with partition table for (i = 0; i < gpt_part_count; i++) { if (gpt_parts[i].start_lba == partlba) { Print(L" Listed in GPT as partition %d, type %s\n", i+1, gpt_parts[i].gpt_parttype->name); } } for (i = 0; i < mbr_part_count; i++) { if (mbr_parts[i].start_lba == partlba) { Print(L" Listed in MBR as partition %d, type %02x %s%s\n", i+1, mbr_parts[i].mbr_type, mbr_parttype_name((UINT8)mbr_parts[i].mbr_type), mbr_parts[i].active ? STR(", active") : STR("")); } } return 0; } // // check all partitions // static UINTN analyze_parts(VOID) { UINTN i, k; UINTN status; BOOLEAN is_dupe; // check MBR (bootcode only) status = analyze_part(0); if (status) return status; // check partitions listed in GPT for (i = 0; i < gpt_part_count; i++) { status = analyze_part(gpt_parts[i].start_lba); if (status) return status; } // check partitions listed in MBR, but not in GPT for (i = 0; i < mbr_part_count; i++) { if (mbr_parts[i].start_lba == 1 && mbr_parts[i].mbr_type == 0xee) continue; // skip EFI Protective entry is_dupe = FALSE; for (k = 0; k < gpt_part_count; k++) if (gpt_parts[k].start_lba == mbr_parts[i].start_lba) is_dupe = TRUE; if (!is_dupe) { status = analyze_part(mbr_parts[i].start_lba); if (status) return status; } } return 0; } // // display algorithm entry point // UINTN showpart(VOID) { UINTN status = 0; UINTN status_gpt, status_mbr; // get full information from disk status_gpt = read_gpt(); status_mbr = read_mbr(); if (status_gpt != 0 || status_mbr != 0) return (status_gpt || status_mbr); // analyze all partitions status = analyze_parts(); if (status != 0) return status; return status; }