summaryrefslogtreecommitdiffstats
path: root/gptsync
diff options
context:
space:
mode:
authorPeter Jones <pjones@redhat.com>2007-10-17 14:06:10 +0000
committerPeter Jones <pjones@redhat.com>2007-10-17 14:06:10 +0000
commitb9066b3eeb59af0a94d0f3d9b2dde3a979fd2cdb (patch)
tree28fdc4287996069347cf1574a521ded8ba470dca /gptsync
parent37138ec2d6fb809bd6dec2991f3100d49bab9a80 (diff)
downloadanaconda-b9066b3eeb59af0a94d0f3d9b2dde3a979fd2cdb.tar.gz
anaconda-b9066b3eeb59af0a94d0f3d9b2dde3a979fd2cdb.tar.xz
anaconda-b9066b3eeb59af0a94d0f3d9b2dde3a979fd2cdb.zip
- update to gptsync 0.10 to fix "Santa Rosa" macs. Also add "showpart" from
gptsync.
Diffstat (limited to 'gptsync')
-rw-r--r--gptsync/Makefile21
-rw-r--r--gptsync/README2
-rw-r--r--gptsync/gptsync.c408
-rw-r--r--gptsync/gptsync.h104
-rw-r--r--gptsync/lib.c469
-rw-r--r--gptsync/os_unix.c14
-rw-r--r--gptsync/showpart.c257
7 files changed, 941 insertions, 334 deletions
diff --git a/gptsync/Makefile b/gptsync/Makefile
index 8ba73595a..8cc91dd51 100644
--- a/gptsync/Makefile
+++ b/gptsync/Makefile
@@ -2,29 +2,33 @@
# Makefile for gptsync on Unix platforms
#
-OBJS = gptsync.o os_unix.o
-TARGET = gptsync
+TARGETS = gptsync showpart
+OBJS = showpart.c lib.c os_unix.c gptsync.c
CPPFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
CFLAGS = -Wall -Werror
LDFLAGS =
LIBS =
+CC = gcc
# real making
-all: $(TARGET)
+all: $(TARGETS)
-$(TARGET): $(OBJS)
- $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
+gptsync: gptsync.o lib.o
+ $(CC) $(LDFLAGS) -DPROGNAME=$@ -o $@ os_unix.c $^ $(LIBS)
-$(OBJS): %.o: %.c
- $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+showpart: showpart.o lib.o
+ $(CC) $(LDFLAGS) -DPROGNAME=$@ -o $@ os_unix.c $^ $(LIBS)
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
# cleanup
clean:
- $(RM) *.o *~ *% $(TARGET) .depend
+ $(RM) *.o *~ *% $(TARGETS) .depend
# automatic dependencies
@@ -42,3 +46,4 @@ endif
install: all
mkdir -p $(DESTDIR)/usr/sbin
install -m 755 gptsync $(DESTDIR)/usr/sbin/gptsync
+ install -m 755 showpart $(DESTDIR)/usr/sbin/showpart
diff --git a/gptsync/README b/gptsync/README
index f364b6367..cb306bd76 100644
--- a/gptsync/README
+++ b/gptsync/README
@@ -8,7 +8,7 @@ The original license follows.
rEFIt License
===============
-Copyright (c) 2006 Christoph Pfisterer
+Copyright (c) 2006-2007 Christoph Pfisterer
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/gptsync/gptsync.c b/gptsync/gptsync.c
index 8de9b8093..2909c5935 100644
--- a/gptsync/gptsync.c
+++ b/gptsync/gptsync.c
@@ -2,7 +2,7 @@
* gptsync/gptsync.c
* Platform-independent code for syncing GPT and MBR
*
- * Copyright (c) 2006 Christoph Pfisterer
+ * Copyright (c) 2006-2007 Christoph Pfisterer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,216 +38,10 @@
#include "syslinux_mbr.h"
-// types
-
-typedef struct {
- UINT8 flags;
- UINT8 start_chs[3];
- UINT8 type;
- UINT8 end_chs[3];
- UINT32 start_lba;
- UINT32 size;
-} MBR_PARTITION_INFO;
-
-typedef struct {
- UINT8 type;
- CHARN *name;
-} MBR_PARTTYPE;
-
-typedef struct {
- UINT64 signature;
- UINT32 spec_revision;
- UINT32 header_size;
- UINT32 header_crc32;
- UINT32 reserved;
- UINT64 header_lba;
- UINT64 alternate_header_lba;
- UINT64 first_usable_lba;
- UINT64 last_usable_lba;
- UINT8 disk_guid[16];
- UINT64 entry_lba;
- UINT32 entry_count;
- UINT32 entry_size;
- UINT32 entry_crc32;
-} GPT_HEADER;
-
-typedef struct {
- UINT8 type_guid[16];
- UINT8 partition_guid[16];
- UINT64 start_lba;
- UINT64 end_lba;
- UINT64 attributes;
- CHAR16 name[36];
-} GPT_ENTRY;
-
-#define GPT_KIND_SYSTEM (0)
-#define GPT_KIND_DATA (1)
-#define GPT_KIND_BASIC_DATA (2)
-#define GPT_KIND_FATAL (3)
-
-typedef struct {
- UINT8 guid[16];
- UINT8 mbr_type;
- CHARN *name;
- UINTN kind;
-} GPT_PARTTYPE;
-
-typedef struct {
- UINTN index;
- UINT64 start_lba;
- UINT64 end_lba;
- UINTN mbr_type;
- UINT8 gpt_type[16];
- GPT_PARTTYPE *gpt_parttype;
- BOOLEAN active;
-} PARTITION_INFO;
-
-// variables
-
-UINT8 empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
-
-PARTITION_INFO mbr_parts[4];
-UINTN mbr_part_count = 0;
-PARTITION_INFO gpt_parts[128];
-UINTN gpt_part_count = 0;
-
-PARTITION_INFO new_mbr_parts[4];
-UINTN new_mbr_part_count = 0;
-
-UINT8 sector[512];
-
-MBR_PARTTYPE mbr_types[] = {
- { 0x01, STR("FAT12") },
- { 0x04, STR("FAT16 <32M") },
- { 0x05, STR("DOS Extended") },
- { 0x06, STR("FAT16") },
- { 0x07, STR("NTFS") },
- { 0x0b, STR("FAT32") },
- { 0x0c, STR("FAT32 (LBA)") },
- { 0x0e, STR("FAT16 (LBA)") },
- { 0x0f, STR("Win95 Extended (LBA)") },
- { 0x11, STR("Hidden FAT12") },
- { 0x14, STR("Hidden FAT16 <32M") },
- { 0x16, STR("Hidden FAT16") },
- { 0x17, STR("Hidden NTFS") },
- { 0x1b, STR("Hidden FAT32") },
- { 0x1c, STR("Hidden FAT32 (LBA)") },
- { 0x1e, STR("Hidden FAT16 (LBA)") },
- { 0x82, STR("Linux swap / Solaris") },
- { 0x83, STR("Linux") },
- { 0x85, STR("Linux Extended") },
- { 0x86, STR("NTFS volume set") },
- { 0x87, STR("NTFS volume set") },
- { 0x8e, STR("Linux LVM") },
- { 0xa5, STR("FreeBSD") },
- { 0xa6, STR("OpenBSD") },
- { 0xa7, STR("NeXTSTEP") },
- { 0xa9, STR("NetBSD") },
- { 0xaf, STR("Mac OS X HFS+") },
- { 0xeb, STR("BeOS") },
- { 0xee, STR("EFI Protective") },
- { 0xef, STR("EFI System (FAT)") },
- { 0xfd, STR("Linux RAID") },
- { 0, NULL },
-};
-
-GPT_PARTTYPE gpt_types[] = {
- { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM },
- { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL },
- { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM },
- { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA },
- { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL },
- { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL },
- { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA },
- { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_DATA },
- { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA },
- { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM },
- { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("Mac OS X HFS+"), GPT_KIND_DATA },
- { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 },
-};
-GPT_PARTTYPE gpt_dummy_type =
- { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL };
-
//
// MBR functions
//
-static CHARN * mbr_parttype_name(UINT8 type)
-{
- int i;
-
- for (i = 0; mbr_types[i].name; i++)
- if (mbr_types[i].type == type)
- return mbr_types[i].name;
- return STR("Unknown");
-}
-
-static UINTN read_mbr(VOID)
-{
- UINTN status;
- UINTN i;
- BOOLEAN used;
- MBR_PARTITION_INFO *table;
-
- Print(L"\nCurrent MBR partition table:\n");
-
- // read MBR data
- status = read_sector(0, sector);
- if (status != 0)
- return status;
-
- // check for validity
- if (*((UINT16 *)(sector + 510)) != 0xaa55) {
- Print(L" No MBR partition table present!\n");
- return 1;
- }
- table = (MBR_PARTITION_INFO *)(sector + 446);
- for (i = 0; i < 4; i++) {
- if (table[i].flags != 0x00 && table[i].flags != 0x80) {
- Print(L" MBR partition table is invalid!\n");
- return 1;
- }
- }
-
- // check if used
- used = FALSE;
- for (i = 0; i < 4; i++) {
- if (table[i].start_lba > 0 && table[i].size > 0) {
- used = TRUE;
- break;
- }
- }
- if (!used) {
- Print(L" No partitions defined\n");
- return 0;
- }
-
- // dump current state & fill internal structures
- Print(L" # A Start LBA End LBA Type\n");
- for (i = 0; i < 4; i++) {
- if (table[i].start_lba == 0 || table[i].size == 0)
- continue;
-
- mbr_parts[mbr_part_count].index = i;
- mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba;
- mbr_parts[mbr_part_count].end_lba = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1;
- mbr_parts[mbr_part_count].mbr_type = table[i].type;
- mbr_parts[mbr_part_count].active = (table[i].flags == 0x80) ? TRUE : FALSE;
-
- Print(L" %d %s %12lld %12lld %02x %s\n",
- mbr_parts[mbr_part_count].index + 1,
- mbr_parts[mbr_part_count].active ? STR("*") : STR(" "),
- mbr_parts[mbr_part_count].start_lba,
- mbr_parts[mbr_part_count].end_lba,
- mbr_parts[mbr_part_count].mbr_type,
- mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type));
-
- mbr_part_count++;
- }
-
- return 0;
-}
-
static UINTN check_mbr(VOID)
{
UINTN i, k;
@@ -350,7 +144,6 @@ static UINTN write_mbr(VOID)
}
}
if (!have_bootcode) {
- Print(L"Writing boot code to MBR\n");
// no boot code found in the MBR, add the syslinux MBR code
SetMem(sector, MBR_BOOTCODE_SIZE, 0);
CopyMem(sector, syslinux_mbr, SYSLINUX_MBR_SIZE);
@@ -370,83 +163,6 @@ static UINTN write_mbr(VOID)
// GPT functions
//
-static GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid)
-{
- int i;
-
- for (i = 0; gpt_types[i].name; i++)
- if (guids_are_equal(gpt_types[i].guid, type_guid))
- return &(gpt_types[i]);
- return &gpt_dummy_type;
-}
-
-static UINTN read_gpt(VOID)
-{
- UINTN status;
- GPT_HEADER *header;
- GPT_ENTRY *entry;
- UINT64 entry_lba;
- UINTN entry_count, entry_size, i;
-
- Print(L"\nCurrent GPT partition table:\n");
-
- // read GPT header
- status = read_sector(1, sector);
- if (status != 0)
- return status;
-
- // check signature
- header = (GPT_HEADER *)sector;
- if (header->signature != 0x5452415020494645ULL) {
- Print(L" No GPT partition table present!\n");
- return 0;
- }
- if (header->spec_revision != 0x00010000UL) {
- Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision);
- }
- if ((512 % header->entry_size) > 0 || header->entry_size > 512) {
- Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n");
- return 0;
- }
-
- // read entries
- entry_lba = header->entry_lba;
- entry_size = header->entry_size;
- entry_count = header->entry_count;
-
- Print(L" # Start LBA End LBA Type\n");
- for (i = 0; i < entry_count; i++) {
- if (((i * entry_size) % 512) == 0) {
- status = read_sector(entry_lba, sector);
- if (status != 0)
- return status;
- entry_lba++;
- }
- entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512));
-
- if (guids_are_equal(entry->type_guid, empty_guid))
- continue;
-
- gpt_parts[gpt_part_count].index = i;
- gpt_parts[gpt_part_count].start_lba = entry->start_lba;
- gpt_parts[gpt_part_count].end_lba = entry->end_lba;
- gpt_parts[gpt_part_count].mbr_type = 0;
- copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid);
- gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type);
- gpt_parts[gpt_part_count].active = FALSE;
-
- Print(L" %d %12lld %12lld %s\n",
- gpt_parts[gpt_part_count].index + 1,
- gpt_parts[gpt_part_count].start_lba,
- gpt_parts[gpt_part_count].end_lba,
- gpt_parts[gpt_part_count].gpt_parttype->name);
-
- gpt_part_count++;
- }
-
- return 0;
-}
-
static UINTN check_gpt(VOID)
{
UINTN i, k;
@@ -502,14 +218,49 @@ static UINTN check_gpt(VOID)
static UINTN analyze(VOID)
{
- UINTN action = ACTION_NONE;
- UINTN i, k, iter;
+ UINTN action;
+ UINTN i, k, iter, count_active, detected_parttype;
+ CHARN *fsname;
UINT64 min_start_lba;
- BOOLEAN have_active;
+ UINTN status;
+ BOOLEAN have_esp;
new_mbr_part_count = 0;
+ // determine correct MBR types for GPT partitions
+ if (gpt_part_count == 0) {
+ Print(L"Status: No GPT partitions defined, nothing to sync.\n");
+ return 0;
+ }
+ have_esp = FALSE;
+ for (i = 0; i < gpt_part_count; i++) {
+ gpt_parts[i].mbr_type = gpt_parts[i].gpt_parttype->mbr_type;
+ if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) {
+ // Basic Data: need to look at data in the partition
+ status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
+ if (detected_parttype)
+ gpt_parts[i].mbr_type = detected_parttype;
+ else
+ gpt_parts[i].mbr_type = 0x0b; // fallback: FAT32
+ } else if (gpt_parts[i].mbr_type == 0xef) {
+ // EFI System Partition: GNU parted can put this on any partition,
+ // need to detect file systems
+ status = detect_mbrtype_fs(gpt_parts[i].start_lba, &detected_parttype, &fsname);
+ if (!have_esp && (detected_parttype == 0x01 || detected_parttype == 0x0e || detected_parttype == 0x0c))
+ ; // seems to be a legitimate ESP, don't change
+ else if (detected_parttype)
+ gpt_parts[i].mbr_type = detected_parttype;
+ else if (have_esp) // make sure there's no more than one ESP per disk
+ gpt_parts[i].mbr_type = 0x83; // fallback: Linux
+ }
+ // NOTE: mbr_type may still be 0 if content detection fails for exotic GPT types or file systems
+
+ if (gpt_parts[i].mbr_type == 0xef)
+ have_esp = TRUE;
+ }
+
// check for common scenarios
+ action = ACTION_NONE;
if (mbr_part_count == 0) {
// current MBR is empty
action = ACTION_REWRITE;
@@ -519,7 +270,7 @@ static UINTN analyze(VOID)
}
if (action == ACTION_NONE && mbr_part_count > 0) {
if (mbr_parts[0].mbr_type == 0xee &&
- gpt_parts[0].gpt_parttype->mbr_type == 0xef &&
+ gpt_parts[0].mbr_type == 0xef &&
mbr_parts[0].start_lba == 1 &&
mbr_parts[0].end_lba == gpt_parts[0].end_lba) {
// The Apple Way, "EFI Protective" covering the tables and the ESP
@@ -533,11 +284,18 @@ static UINTN analyze(VOID)
for (i = 1; i < mbr_part_count; i++) {
if (mbr_parts[i].start_lba != gpt_parts[i].start_lba ||
mbr_parts[i].end_lba != gpt_parts[i].end_lba ||
- (gpt_parts[i].gpt_parttype->mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].gpt_parttype->mbr_type))
+ (gpt_parts[i].mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].mbr_type))
// position or type has changed
action = ACTION_REWRITE;
}
}
+ // check number of active partitions
+ count_active = 0;
+ for (i = 0; i < mbr_part_count; i++)
+ if (mbr_parts[i].active)
+ count_active++;
+ if (count_active!= 1)
+ action = ACTION_REWRITE;
}
}
if (action == ACTION_NONE && mbr_part_count > 0 && mbr_parts[0].mbr_type == 0xef) {
@@ -547,7 +305,7 @@ static UINTN analyze(VOID)
for (i = 0; i < mbr_part_count; i++) {
if (mbr_parts[i].start_lba != gpt_parts[i].start_lba ||
mbr_parts[i].end_lba != gpt_parts[i].end_lba ||
- (gpt_parts[i].gpt_parttype->mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].gpt_parttype->mbr_type))
+ (gpt_parts[i].mbr_type && mbr_parts[i].mbr_type != gpt_parts[i].mbr_type))
// position or type has changed -> better don't touch
action = ACTION_NONE;
}
@@ -571,7 +329,7 @@ static UINTN analyze(VOID)
new_mbr_parts[0].mbr_type = 0xee;
new_mbr_part_count = 1;
- if (gpt_parts[0].gpt_parttype->mbr_type == 0xef) {
+ if (gpt_parts[0].mbr_type == 0xef) {
new_mbr_parts[0].end_lba = gpt_parts[0].end_lba;
i = 1;
} else {
@@ -585,54 +343,70 @@ static UINTN analyze(VOID)
}
// add other GPT partitions until the table is full
+ // TODO: in the future, prioritize partitions by kind
for (; i < gpt_part_count && new_mbr_part_count < 4; i++) {
new_mbr_parts[new_mbr_part_count].index = new_mbr_part_count;
new_mbr_parts[new_mbr_part_count].start_lba = gpt_parts[i].start_lba;
new_mbr_parts[new_mbr_part_count].end_lba = gpt_parts[i].end_lba;
- new_mbr_parts[new_mbr_part_count].mbr_type = gpt_parts[i].gpt_parttype->mbr_type;
+ new_mbr_parts[new_mbr_part_count].mbr_type = gpt_parts[i].mbr_type;
new_mbr_parts[new_mbr_part_count].active = FALSE;
// find matching partition in the old MBR table
for (k = 0; k < mbr_part_count; k++) {
if (mbr_parts[k].start_lba == gpt_parts[i].start_lba) {
+ // keep type if not detected
if (new_mbr_parts[new_mbr_part_count].mbr_type == 0)
new_mbr_parts[new_mbr_part_count].mbr_type = mbr_parts[k].mbr_type;
+ // keep active flag
new_mbr_parts[new_mbr_part_count].active = mbr_parts[k].active;
break;
}
}
- if (new_mbr_parts[new_mbr_part_count].mbr_type == 0) {
- // TODO: detect the actual file system on the partition
-
- // fallback: use linux native
- //if (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) {
- new_mbr_parts[new_mbr_part_count].mbr_type = 0x83;
- }
+ if (new_mbr_parts[new_mbr_part_count].mbr_type == 0)
+ // final fallback: set to a (hopefully) unused type
+ new_mbr_parts[new_mbr_part_count].mbr_type = 0xc0;
new_mbr_part_count++;
}
- // if no partition is active, pick one
+ // make sure there's exactly one active partition
for (iter = 0; iter < 3; iter++) {
// check
- have_active = FALSE;
+ count_active = 0;
for (i = 0; i < new_mbr_part_count; i++)
if (new_mbr_parts[i].active)
- have_active = TRUE;
- if (have_active)
+ count_active++;
+ if (count_active == 1)
break;
// set active on the first matching partition
- for (i = 0; i < new_mbr_part_count; i++) {
- if ((iter >= 0 && (new_mbr_parts[i].mbr_type == 0x07 ||
- new_mbr_parts[i].mbr_type == 0x0b ||
- new_mbr_parts[i].mbr_type == 0x0c)) ||
- (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) ||
- (iter >= 2 && i > 0)) {
- new_mbr_parts[i].active = TRUE;
- break;
+ if (count_active == 0) {
+ for (i = 0; i < new_mbr_part_count; i++) {
+ if ((iter >= 0 && (new_mbr_parts[i].mbr_type == 0x07 || // NTFS
+ new_mbr_parts[i].mbr_type == 0x0b || // FAT32
+ new_mbr_parts[i].mbr_type == 0x0c)) || // FAT32 (LBA)
+ (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) || // Linux
+ (iter >= 2 && i > 0)) {
+ new_mbr_parts[i].active = TRUE;
+ break;
+ }
+ }
+ } else if (count_active > 1 && iter == 0) {
+ // too many active partitions, try deactivating the ESP / EFI Protective entry
+ if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) &&
+ new_mbr_parts[0].active) {
+ new_mbr_parts[0].active = FALSE;
}
+ } else if (count_active > 1 && iter > 0) {
+ // too many active partitions, deactivate all but the first one
+ count_active = 0;
+ for (i = 0; i < new_mbr_part_count; i++)
+ if (new_mbr_parts[i].active) {
+ if (count_active > 0)
+ new_mbr_parts[i].active = FALSE;
+ count_active++;
+ }
}
}
@@ -660,7 +434,7 @@ UINTN gptsync(VOID)
{
UINTN status = 0;
UINTN status_gpt, status_mbr;
- // BOOLEAN proceed = FALSE;
+ BOOLEAN proceed = FALSE;
// get full information from disk
status_gpt = read_gpt();
@@ -676,16 +450,16 @@ UINTN gptsync(VOID)
status = check_mbr(); // check MBR for consistency
if (status != 0)
return status;
- status = analyze(); // analyze the situation
+ status = analyze(); // analyze the situation & compose new MBR table
if (status != 0)
return status;
if (new_mbr_part_count == 0)
return status;
// offer user the choice what to do
- // status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed);
- // if (status != 0 || proceed != TRUE)
- // return status;
+ // status = input_boolean(STR("\nMay I update the MBR as printed above? [y/N] "), &proceed);
+ // if (status != 0 || proceed != TRUE)
+ // return status;
// adjust the MBR and write it back
status = write_mbr();
diff --git a/gptsync/gptsync.h b/gptsync/gptsync.h
index c14d32959..8bb5da4dc 100644
--- a/gptsync/gptsync.h
+++ b/gptsync/gptsync.h
@@ -1,6 +1,6 @@
/*
* gptsync/gptsync.h
- * Common header for gptsync
+ * Common header for gptsync and showpart
*
* Copyright (c) 2006 Christoph Pfisterer
* All rights reserved.
@@ -38,12 +38,12 @@
// config
//
-#ifdef EFI32
+#if defined(EFI32) || defined(EFIX64)
#define CONFIG_EFI
#endif
//
-// types
+// platform-dependent types
//
#ifdef CONFIG_EFI
@@ -73,6 +73,7 @@ typedef CHAR16 CHARN;
#include <sys/time.h>
#include <fcntl.h>
+typedef int INTN;
typedef unsigned int UINTN;
typedef unsigned char UINT8;
typedef unsigned short UINT16;
@@ -106,6 +107,72 @@ void Print(wchar_t *format, ...);
#endif
//
+// platform-independent types
+//
+
+typedef struct {
+ UINT8 flags;
+ UINT8 start_chs[3];
+ UINT8 type;
+ UINT8 end_chs[3];
+ UINT32 start_lba;
+ UINT32 size;
+} MBR_PARTITION_INFO;
+
+typedef struct {
+ UINT8 type;
+ CHARN *name;
+} MBR_PARTTYPE;
+
+typedef struct {
+ UINT64 signature;
+ UINT32 spec_revision;
+ UINT32 header_size;
+ UINT32 header_crc32;
+ UINT32 reserved;
+ UINT64 header_lba;
+ UINT64 alternate_header_lba;
+ UINT64 first_usable_lba;
+ UINT64 last_usable_lba;
+ UINT8 disk_guid[16];
+ UINT64 entry_lba;
+ UINT32 entry_count;
+ UINT32 entry_size;
+ UINT32 entry_crc32;
+} GPT_HEADER;
+
+typedef struct {
+ UINT8 type_guid[16];
+ UINT8 partition_guid[16];
+ UINT64 start_lba;
+ UINT64 end_lba;
+ UINT64 attributes;
+ CHAR16 name[36];
+} GPT_ENTRY;
+
+#define GPT_KIND_SYSTEM (0)
+#define GPT_KIND_DATA (1)
+#define GPT_KIND_BASIC_DATA (2)
+#define GPT_KIND_FATAL (3)
+
+typedef struct {
+ UINT8 guid[16];
+ UINT8 mbr_type;
+ CHARN *name;
+ UINTN kind;
+} GPT_PARTTYPE;
+
+typedef struct {
+ UINTN index;
+ UINT64 start_lba;
+ UINT64 end_lba;
+ UINTN mbr_type;
+ UINT8 gpt_type[16];
+ GPT_PARTTYPE *gpt_parttype;
+ BOOLEAN active;
+} PARTITION_INFO;
+
+//
// functions provided by the OS-specific module
//
@@ -114,9 +181,38 @@ UINTN write_sector(UINT64 lba, UINT8 *buffer);
UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out);
//
-// common platform-independent function
+// vars and functions provided by the common lib module
+//
+
+extern UINT8 empty_guid[16];
+
+extern PARTITION_INFO mbr_parts[4];
+extern UINTN mbr_part_count;
+extern PARTITION_INFO gpt_parts[128];
+extern UINTN gpt_part_count;
+
+extern PARTITION_INFO new_mbr_parts[4];
+extern UINTN new_mbr_part_count;
+
+extern UINT8 sector[512];
+
+extern MBR_PARTTYPE mbr_types[];
+extern GPT_PARTTYPE gpt_types[];
+extern GPT_PARTTYPE gpt_dummy_type;
+
+CHARN * mbr_parttype_name(UINT8 type);
+UINTN read_mbr(VOID);
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid);
+UINTN read_gpt(VOID);
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname);
+
+//
+// actual platform-independent programs
//
UINTN gptsync(VOID);
+UINTN showpart(VOID);
/* EOF */
diff --git a/gptsync/lib.c b/gptsync/lib.c
new file mode 100644
index 000000000..271dc9999
--- /dev/null
+++ b/gptsync/lib.c
@@ -0,0 +1,469 @@
+/*
+ * gptsync/lib.c
+ * Platform-independent code common to gptsync and showpart
+ *
+ * Copyright (c) 2006-2007 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"
+
+// variables
+
+UINT8 empty_guid[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+PARTITION_INFO mbr_parts[4];
+UINTN mbr_part_count = 0;
+PARTITION_INFO gpt_parts[128];
+UINTN gpt_part_count = 0;
+
+PARTITION_INFO new_mbr_parts[4];
+UINTN new_mbr_part_count = 0;
+
+UINT8 sector[512];
+
+MBR_PARTTYPE mbr_types[] = {
+ { 0x01, STR("FAT12 (CHS)") },
+ { 0x04, STR("FAT16 <32M (CHS)") },
+ { 0x05, STR("Extended (CHS)") },
+ { 0x06, STR("FAT16 (CHS)") },
+ { 0x07, STR("NTFS/HPFS") },
+ { 0x0b, STR("FAT32 (CHS)") },
+ { 0x0c, STR("FAT32 (LBA)") },
+ { 0x0e, STR("FAT16 (LBA)") },
+ { 0x0f, STR("Extended (LBA)") },
+ { 0x11, STR("Hidden FAT12 (CHS)") },
+ { 0x14, STR("Hidden FAT16 <32M (CHS)") },
+ { 0x16, STR("Hidden FAT16 (CHS)") },
+ { 0x17, STR("Hidden NTFS/HPFS") },
+ { 0x1b, STR("Hidden FAT32 (CHS)") },
+ { 0x1c, STR("Hidden FAT32 (LBA)") },
+ { 0x1e, STR("Hidden FAT16 (LBA)") },
+ { 0x82, STR("Linux swap / Solaris") },
+ { 0x83, STR("Linux") },
+ { 0x85, STR("Linux Extended") },
+ { 0x86, STR("NT FAT volume set") },
+ { 0x87, STR("NTFS volume set") },
+ { 0x8e, STR("Linux LVM") },
+ { 0xa5, STR("FreeBSD") },
+ { 0xa6, STR("OpenBSD") },
+ { 0xa7, STR("NeXTSTEP") },
+ { 0xa8, STR("Mac OS X UFS") },
+ { 0xa9, STR("NetBSD") },
+ { 0xab, STR("Mac OS X Boot") },
+ { 0xac, STR("Apple RAID") },
+ { 0xaf, STR("Mac OS X HFS+") },
+ { 0xbe, STR("Solaris Boot") },
+ { 0xbf, STR("Solaris") },
+ { 0xeb, STR("BeOS") },
+ { 0xee, STR("EFI Protective") },
+ { 0xef, STR("EFI System (FAT)") },
+ { 0xfd, STR("Linux RAID") },
+ { 0, NULL },
+};
+
+GPT_PARTTYPE gpt_types[] = {
+ { "\x28\x73\x2A\xC1\x1F\xF8\xD2\x11\xBA\x4B\x00\xA0\xC9\x3E\xC9\x3B", 0xef, STR("EFI System (FAT)"), GPT_KIND_SYSTEM },
+ { "\x41\xEE\x4D\x02\xE7\x33\xD3\x11\x9D\x69\x00\x08\xC7\x81\xF3\x9F", 0x00, STR("MBR partition scheme"), GPT_KIND_FATAL },
+ { "\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE", 0x00, STR("MS Reserved"), GPT_KIND_SYSTEM },
+ { "\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7", 0x00, STR("Basic Data"), GPT_KIND_BASIC_DATA },
+ { "\xAA\xC8\x08\x58\x8F\x7E\xE0\x42\x85\xD2\xE1\xE9\x04\x34\xCF\xB3", 0x00, STR("MS LDM Metadata"), GPT_KIND_FATAL },
+ { "\xA0\x60\x9B\xAF\x31\x14\x62\x4F\xBC\x68\x33\x11\x71\x4A\x69\xAD", 0x00, STR("MS LDM Data"), GPT_KIND_FATAL },
+ { "\x1E\x4C\x89\x75\xEB\x3A\xD3\x11\xB7\xC1\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Data"), GPT_KIND_DATA },
+ { "\x28\xE7\xA1\xE2\xE3\x32\xD6\x11\xA6\x82\x7B\x03\xA0\x00\x00\x00", 0x00, STR("HP/UX Service"), GPT_KIND_SYSTEM },
+ { "\x0F\x88\x9D\xA1\xFC\x05\x3B\x4D\xA0\x06\x74\x3F\x0F\x84\x91\x1E", 0xfd, STR("Linux RAID"), GPT_KIND_DATA },
+ { "\x6D\xFD\x57\x06\xAB\xA4\xC4\x43\x84\xE5\x09\x33\xC8\x4B\x4F\x4F", 0x82, STR("Linux Swap"), GPT_KIND_SYSTEM },
+ { "\x79\xD3\xD6\xE6\x07\xF5\xC2\x44\xA2\x3C\x23\x8F\x2A\x3D\xF9\x28", 0x8e, STR("Linux LVM"), GPT_KIND_DATA },
+ { "\x39\x33\xA6\x8D\x07\x00\xC0\x60\xC4\x36\x08\x3A\xC8\x23\x09\x08", 0x00, STR("Linux Reserved"), GPT_KIND_SYSTEM },
+ { "\xB4\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD Data"), GPT_KIND_DATA },
+ { "\xB5\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Swap"), GPT_KIND_SYSTEM },
+ { "\xB6\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0xa5, STR("FreeBSD UFS"), GPT_KIND_DATA },
+ { "\xB8\x7C\x6E\x51\xCF\x6E\xD6\x11\x8F\xF8\x00\x02\x2D\x09\x71\x2B", 0x00, STR("FreeBSD Vinum"), GPT_KIND_DATA },
+ { "\x00\x53\x46\x48\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xaf, STR("Mac OS X HFS+"), GPT_KIND_DATA },
+ { "\x00\x53\x46\x55\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xa8, STR("Mac OS X UFS"), GPT_KIND_DATA },
+ { "\x74\x6F\x6F\x42\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xab, STR("Mac OS X Boot"), GPT_KIND_DATA },
+ { "\x44\x49\x41\x52\x00\x00\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID"), GPT_KIND_DATA },
+ { "\x44\x49\x41\x52\x4F\x5F\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0xac, STR("Apple RAID (Offline)"), GPT_KIND_DATA },
+ { "\x65\x62\x61\x4C\x00\x6C\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Label"), GPT_KIND_SYSTEM },
+ { "\x6F\x63\x65\x52\x65\x76\xAA\x11\xAA\x11\x00\x30\x65\x43\xEC\xAC", 0x00, STR("Apple Recovery"), GPT_KIND_BASIC_DATA },
+ { "\x7f\x23\x96\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Reserved"), GPT_KIND_SYSTEM },
+ { "\x45\xCB\x82\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Boot"), GPT_KIND_DATA },
+ { "\x4D\xCF\x85\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Root"), GPT_KIND_DATA },
+ { "\x6F\xC4\x87\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Swap"), GPT_KIND_SYSTEM },
+ { "\xC3\x8C\x89\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Usr"), GPT_KIND_DATA },
+ { "\x2B\x64\x8B\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Backup"), GPT_KIND_SYSTEM },
+ { "\xC7\x2A\x8D\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Stand"), GPT_KIND_DATA },
+ { "\xE9\xF2\x8E\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Var"), GPT_KIND_DATA },
+ { "\x39\xBA\x90\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris Home"), GPT_KIND_DATA },
+ { "\xA5\x83\x92\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0xbf, STR("Solaris ALTSCTR"), GPT_KIND_DATA },
+ { "\x3B\x5A\x94\x6A\xD2\x1D\xB2\x11\x99\xa6\x08\x00\x20\x73\x66\x31", 0x00, STR("Solaris Cache"), GPT_KIND_SYSTEM },
+ { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, NULL, 0 },
+};
+GPT_PARTTYPE gpt_dummy_type =
+ { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, 0, STR("Unknown"), GPT_KIND_FATAL };
+
+//
+// MBR functions
+//
+
+CHARN * mbr_parttype_name(UINT8 type)
+{
+ int i;
+
+ for (i = 0; mbr_types[i].name; i++)
+ if (mbr_types[i].type == type)
+ return mbr_types[i].name;
+ return STR("Unknown");
+}
+
+UINTN read_mbr(VOID)
+{
+ UINTN status;
+ UINTN i;
+ BOOLEAN used;
+ MBR_PARTITION_INFO *table;
+
+ Print(L"\nCurrent MBR partition table:\n");
+
+ // read MBR data
+ status = read_sector(0, sector);
+ if (status != 0)
+ return status;
+
+ // check for validity
+ if (*((UINT16 *)(sector + 510)) != 0xaa55) {
+ Print(L" No MBR partition table present!\n");
+ return 1;
+ }
+ table = (MBR_PARTITION_INFO *)(sector + 446);
+ for (i = 0; i < 4; i++) {
+ if (table[i].flags != 0x00 && table[i].flags != 0x80) {
+ Print(L" MBR partition table is invalid!\n");
+ return 1;
+ }
+ }
+
+ // check if used
+ used = FALSE;
+ for (i = 0; i < 4; i++) {
+ if (table[i].start_lba > 0 && table[i].size > 0) {
+ used = TRUE;
+ break;
+ }
+ }
+ if (!used) {
+ Print(L" No partitions defined\n");
+ return 0;
+ }
+
+ // dump current state & fill internal structures
+ Print(L" # A Start LBA End LBA Type\n");
+ for (i = 0; i < 4; i++) {
+ if (table[i].start_lba == 0 || table[i].size == 0)
+ continue;
+
+ mbr_parts[mbr_part_count].index = i;
+ mbr_parts[mbr_part_count].start_lba = (UINT64)table[i].start_lba;
+ mbr_parts[mbr_part_count].end_lba = (UINT64)table[i].start_lba + (UINT64)table[i].size - 1;
+ mbr_parts[mbr_part_count].mbr_type = table[i].type;
+ mbr_parts[mbr_part_count].active = (table[i].flags == 0x80) ? TRUE : FALSE;
+
+ Print(L" %d %s %12lld %12lld %02x %s\n",
+ mbr_parts[mbr_part_count].index + 1,
+ mbr_parts[mbr_part_count].active ? STR("*") : STR(" "),
+ mbr_parts[mbr_part_count].start_lba,
+ mbr_parts[mbr_part_count].end_lba,
+ mbr_parts[mbr_part_count].mbr_type,
+ mbr_parttype_name(mbr_parts[mbr_part_count].mbr_type));
+
+ mbr_part_count++;
+ }
+
+ return 0;
+}
+
+//
+// GPT functions
+//
+
+GPT_PARTTYPE * gpt_parttype(UINT8 *type_guid)
+{
+ int i;
+
+ for (i = 0; gpt_types[i].name; i++)
+ if (guids_are_equal(gpt_types[i].guid, type_guid))
+ return &(gpt_types[i]);
+ return &gpt_dummy_type;
+}
+
+UINTN read_gpt(VOID)
+{
+ UINTN status;
+ GPT_HEADER *header;
+ GPT_ENTRY *entry;
+ UINT64 entry_lba;
+ UINTN entry_count, entry_size, i;
+
+ Print(L"\nCurrent GPT partition table:\n");
+
+ // read GPT header
+ status = read_sector(1, sector);
+ if (status != 0)
+ return status;
+
+ // check signature
+ header = (GPT_HEADER *)sector;
+ if (header->signature != 0x5452415020494645ULL) {
+ Print(L" No GPT partition table present!\n");
+ return 0;
+ }
+ if (header->spec_revision != 0x00010000UL) {
+ Print(L" Warning: Unknown GPT spec revision 0x%08x\n", header->spec_revision);
+ }
+ if ((512 % header->entry_size) > 0 || header->entry_size > 512) {
+ Print(L" Error: Invalid GPT entry size (misaligned or more than 512 bytes)\n");
+ return 0;
+ }
+
+ // read entries
+ entry_lba = header->entry_lba;
+ entry_size = header->entry_size;
+ entry_count = header->entry_count;
+
+ for (i = 0; i < entry_count; i++) {
+ if (((i * entry_size) % 512) == 0) {
+ status = read_sector(entry_lba, sector);
+ if (status != 0)
+ return status;
+ entry_lba++;
+ }
+ entry = (GPT_ENTRY *)(sector + ((i * entry_size) % 512));
+
+ if (guids_are_equal(entry->type_guid, empty_guid))
+ continue;
+ if (gpt_part_count == 0) {
+ Print(L" # Start LBA End LBA Type\n");
+ }
+
+ gpt_parts[gpt_part_count].index = i;
+ gpt_parts[gpt_part_count].start_lba = entry->start_lba;
+ gpt_parts[gpt_part_count].end_lba = entry->end_lba;
+ gpt_parts[gpt_part_count].mbr_type = 0;
+ copy_guid(gpt_parts[gpt_part_count].gpt_type, entry->type_guid);
+ gpt_parts[gpt_part_count].gpt_parttype = gpt_parttype(gpt_parts[gpt_part_count].gpt_type);
+ gpt_parts[gpt_part_count].active = FALSE;
+
+ Print(L" %d %12lld %12lld %s\n",
+ gpt_parts[gpt_part_count].index + 1,
+ gpt_parts[gpt_part_count].start_lba,
+ gpt_parts[gpt_part_count].end_lba,
+ gpt_parts[gpt_part_count].gpt_parttype->name);
+
+ gpt_part_count++;
+ }
+ if (gpt_part_count == 0) {
+ Print(L" No partitions defined\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+//
+// detect file system type
+//
+
+UINTN detect_mbrtype_fs(UINT64 partlba, UINTN *parttype, CHARN **fsname)
+{
+ UINTN status;
+ UINTN signature, score;
+ UINTN sectsize, clustersize, reserved, fatcount, dirsize, sectcount, fatsize, clustercount;
+
+ *fsname = STR("Unknown");
+ *parttype = 0;
+
+ // READ sector 0 / offset 0K
+ status = read_sector(partlba, sector);
+ if (status != 0)
+ return status;
+
+ // detect XFS
+ signature = *((UINT32 *)(sector));
+ if (signature == 0x42534658) {
+ *parttype = 0x83;
+ *fsname = STR("XFS");
+ return 0;
+ }
+
+ // detect FAT and NTFS
+ sectsize = *((UINT16 *)(sector + 11));
+ clustersize = sector[13];
+ if (sectsize >= 512 && (sectsize & (sectsize - 1)) == 0 &&
+ clustersize > 0 && (clustersize & (clustersize - 1)) == 0) {
+ // preconditions for both FAT and NTFS are now met
+
+ if (CompareMem(sector + 3, "NTFS ", 8) == 0) {
+ *parttype = 0x07;
+ *fsname = STR("NTFS");
+ return 0;
+ }
+
+ score = 0;
+ // boot jump
+ if ((sector[0] == 0xEB && sector[2] == 0x90) ||
+ sector[0] == 0xE9)
+ score++;
+ // boot signature
+ if (sector[510] == 0x55 && sector[511] == 0xAA)
+ score++;
+ // reserved sectors
+ reserved = *((UINT16 *)(sector + 14));
+ if (reserved == 1 || reserved == 32)
+ score++;
+ // number of FATs
+ fatcount = sector[16];
+ if (fatcount == 2)
+ score++;
+ // number of root dir entries
+ dirsize = *((UINT16 *)(sector + 17));
+ // sector count (16-bit and 32-bit versions)
+ sectcount = *((UINT16 *)(sector + 19));
+ if (sectcount == 0)
+ sectcount = *((UINT32 *)(sector + 32));
+ // media byte
+ if (sector[21] == 0xF0 || sector[21] >= 0xF8)
+ score++;
+ // FAT size in sectors
+ fatsize = *((UINT16 *)(sector + 22));
+ if (fatsize == 0)
+ fatsize = *((UINT32 *)(sector + 36));
+
+ // determine FAT type
+ dirsize = ((dirsize * 32) + (sectsize - 1)) / sectsize;
+ clustercount = sectcount - (reserved + (fatcount * fatsize) + dirsize);
+ clustercount /= clustersize;
+
+ if (score >= 3) {
+ if (clustercount < 4085) {
+ *parttype = 0x01;
+ *fsname = STR("FAT12");
+ } else if (clustercount < 65525) {
+ *parttype = 0x0e;
+ *fsname = STR("FAT16");
+ } else {
+ *parttype = 0x0c;
+ *fsname = STR("FAT32");
+ }
+ // TODO: check if 0e and 0c are okay to use, maybe we should use 06 and 0b instead...
+ return 0;
+ }
+ }
+
+ // READ sector 2 / offset 1K
+ status = read_sector(partlba + 2, sector);
+ if (status != 0)
+ return status;
+
+ // detect HFS+
+ signature = *((UINT16 *)(sector));
+ if (signature == 0x4442) {
+ *parttype = 0xaf;
+ if (*((UINT16 *)(sector + 0x7c)) == 0x2B48)
+ *fsname = STR("HFS Extended (HFS+)");
+ else
+ *fsname = STR("HFS Standard");
+ return 0;
+ } else if (signature == 0x2B48) {
+ *parttype = 0xaf;
+ *fsname = STR("HFS Extended (HFS+)");
+ return 0;
+ }
+
+ // detect ext2/ext3
+ signature = *((UINT16 *)(sector + 56));
+ if (signature == 0xEF53) {
+ *parttype = 0x83;
+ if (*((UINT16 *)(sector + 92)) & 0x0004)
+ *fsname = STR("ext3");
+ else
+ *fsname = STR("ext2");
+ return 0;
+ }
+
+ // READ sector 128 / offset 64K
+ status = read_sector(partlba + 128, sector);
+ if (status != 0)
+ return status;
+
+ // detect ReiserFS
+ if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+ CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+ CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+ *parttype = 0x83;
+ *fsname = STR("ReiserFS");
+ return 0;
+ }
+
+ // detect Reiser4
+ if (CompareMem(sector, "ReIsEr4", 7) == 0) {
+ *parttype = 0x83;
+ *fsname = STR("Reiser4");
+ return 0;
+ }
+
+ // READ sector 64 / offset 32K
+ status = read_sector(partlba + 64, sector);
+ if (status != 0)
+ return status;
+
+ // detect JFS
+ if (CompareMem(sector, "JFS1", 4) == 0) {
+ *parttype = 0x83;
+ *fsname = STR("JFS");
+ return 0;
+ }
+
+ // READ sector 16 / offset 8K
+ status = read_sector(partlba + 16, sector);
+ if (status != 0)
+ return status;
+
+ // detect ReiserFS
+ if (CompareMem(sector + 52, "ReIsErFs", 8) == 0 ||
+ CompareMem(sector + 52, "ReIsEr2Fs", 9) == 0 ||
+ CompareMem(sector + 52, "ReIsEr3Fs", 9) == 0) {
+ *parttype = 0x83;
+ *fsname = STR("ReiserFS");
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/gptsync/os_unix.c b/gptsync/os_unix.c
index 775554d7d..b43685b58 100644
--- a/gptsync/os_unix.c
+++ b/gptsync/os_unix.c
@@ -38,6 +38,10 @@
#include <stdarg.h>
+#define STRINGIFY(s) #s
+#define STRINGIFY2(s) STRINGIFY(s)
+#define PROGNAME_S STRINGIFY2(PROGNAME)
+
// variables
static int fd;
@@ -55,7 +59,7 @@ void error(const char *msg, ...)
vsnprintf(buf, 4096, msg, par);
va_end(par);
- fprintf(stderr, "gptsync: %s\n", buf);
+ fprintf(stderr, PROGNAME_S ": %s\n", buf);
}
void errore(const char *msg, ...)
@@ -67,7 +71,7 @@ void errore(const char *msg, ...)
vsnprintf(buf, 4096, msg, par);
va_end(par);
- fprintf(stderr, "gptsync: %s: %s\n", buf, strerror(errno));
+ fprintf(stderr, PROGNAME_S ": %s: %s\n", buf, strerror(errno));
}
//
@@ -187,7 +191,7 @@ int main(int argc, char *argv[])
// argument check
if (argc != 2) {
- fprintf(stderr, "Usage: gptsync <device>\n");
+ fprintf(stderr, "Usage: " PROGNAME_S " <device>\n");
return 1;
}
filename = argv[1];
@@ -231,8 +235,10 @@ int main(int argc, char *argv[])
fd = open(filename, O_RDWR);
if (fd < 0 && errno == EBUSY) {
fd = open(filename, O_RDONLY);
+#ifndef NOREADONLYWARN
if (fd >= 0)
printf("Warning: %.300s opened read-only\n", filename);
+#endif
}
if (fd < 0) {
errore("Can't open %.300s", filename);
@@ -248,7 +254,7 @@ int main(int argc, char *argv[])
}
// run sync algorithm
- status = gptsync();
+ status = PROGNAME();
printf("\n");
// close file
diff --git a/gptsync/showpart.c b/gptsync/showpart.c
new file mode 100644
index 000000000..3d52ba34e
--- /dev/null
+++ b/gptsync/showpart.c
@@ -0,0 +1,257 @@
+/*
+ * 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;
+}