258 lines
7.6 KiB
C
258 lines
7.6 KiB
C
/*
|
|
* 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\0", 27) >= 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, "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");
|
|
|
|
}
|
|
|
|
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(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;
|
|
}
|