summaryrefslogtreecommitdiffstats
path: root/debian/patches/gptsync.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/gptsync.patch')
-rw-r--r--debian/patches/gptsync.patch466
1 files changed, 466 insertions, 0 deletions
diff --git a/debian/patches/gptsync.patch b/debian/patches/gptsync.patch
new file mode 100644
index 0000000..27820fe
--- /dev/null
+++ b/debian/patches/gptsync.patch
@@ -0,0 +1,466 @@
+From aa55572c980da038e675fc963d98a90964a2ce33 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@srcf.ucam.org>
+Date: Fri, 28 Mar 2014 17:10:01 +0000
+Subject: GPT syncing for Intel Macs
+
+On Intel Mac systems, write a synced MBR rather than a protective MBR.
+
+From: Colin Watson <cjwatson@ubuntu.com>
+Forwarded: no
+Last-Update: 2022-04-19
+
+Patch-Name: gptsync.patch
+---
+ libparted/labels/gpt.c | 205 +++++++++++++++++++++++++++++++++++++++--
+ tests/Makefile.am | 1 +
+ tests/t0290-gptsync.sh | 175 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 371 insertions(+), 10 deletions(-)
+ create mode 100644 tests/t0290-gptsync.sh
+
+diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
+index 130b9bd1..bebedb47 100644
+--- a/libparted/labels/gpt.c
++++ b/libparted/labels/gpt.c
+@@ -369,6 +369,40 @@ typedef struct _GPTPartitionData
+
+ static PedDiskType gpt_disk_type;
+
++
++#if (defined(__i386__) || defined(__x86_64__)) && defined(__linux__)
++# define USE_DMI
++#endif
++
++#define APPLE_DMI "Apple Computer, Inc."
++#define APPLE_DMI_2 "Apple Inc."
++static int is_apple = 0;
++
++static char *
++dmi_system_manufacturer (void)
++{
++#ifdef USE_DMI
++ FILE *dmidecode;
++ char *manufacturer = NULL;
++ size_t manufacturer_len = 0;
++
++ dmidecode = popen ("dmidecode -s system-manufacturer 2>/dev/null", "r");
++ if (getline (&manufacturer, &manufacturer_len, dmidecode) < 0) {
++ /* ignore; will return NULL */
++ }
++ pclose (dmidecode);
++ if (manufacturer) {
++ char *newline = strchr (manufacturer, '\n');
++ if (newline)
++ *newline = '\0';
++ }
++ return manufacturer;
++#else /* !USE_DMI */
++ return NULL;
++#endif /* USE_DMI */
++}
++
++
+ static inline uint32_t
+ pth_get_size (const PedDevice *dev)
+ {
+@@ -544,16 +578,19 @@ gpt_probe (const PedDevice *dev)
+ if (dev->length <= 1)
+ return 0;
+
+- void *label;
+- if (!ptt_read_sector (dev, 0, &label))
+- return 0;
+-
+- if (!_pmbr_is_valid (label))
++ if (!is_apple)
+ {
++ void *label;
++ if (!ptt_read_sector (dev, 0, &label))
++ return 0;
++
++ if (!_pmbr_is_valid (label))
++ {
++ free (label);
++ return 0;
++ }
+ free (label);
+- return 0;
+ }
+- free (label);
+
+ void *pth_raw = ped_malloc (pth_get_size (dev));
+ if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
+@@ -973,6 +1010,10 @@ gpt_read_headers (PedDisk const *disk,
+ * warn if it's not there, and treat the disk as MSDOS, with a note
+ * for users to use Parted to "fix up" their disk if they
+ * really want it to be considered GPT.
++ *
++ * Of course, this is incompatible with how Apple handle things. For
++ * legacy BIOS compatibility on Apple machines, we need a valid legacy MBR
++ * rather than a protective one. Aren't standards wonderful?
+ ************************************************************/
+ static int
+ gpt_read (PedDisk *disk)
+@@ -1181,6 +1222,129 @@ _write_pmbr (PedDevice *dev, bool pmbr_boot)
+ return write_ok;
+ }
+
++static void
++fill_raw_part (PartitionRecord_t* raw_part, PedPartition *part, PedSector offset, int number)
++{
++ GPTPartitionData* gpt_part_data = part->disk_specific;
++
++ if (part->fs_type) {
++ if (strncmp (part->fs_type->name, "fat", 3) == 0)
++ raw_part->OSType = 0x0b;
++ else if (strncmp (part->fs_type->name, "ntfs", 4) == 0)
++ raw_part->OSType = 0x07;
++ else if (strncmp (part->fs_type->name, "hfs", 3) == 0)
++ raw_part->OSType = 0xaf;
++ else if (strncmp (part->fs_type->name, "linux-swap", 10) == 0)
++ raw_part->OSType = 0x82;
++ else
++ raw_part->OSType = 0x83;
++ } else
++ raw_part->OSType = 0xda;
++
++ /* Apple's firmware appears to become unhappy if the second partition
++ isn't bootable */
++
++ if (number == 2)
++ raw_part->BootIndicator = 0x80;
++
++ raw_part->StartingLBA = PED_CPU_TO_LE32 ((part->geom.start - offset)
++ / (part->disk->dev->sector_size / 512));
++
++ raw_part->SizeInLBA = PED_CPU_TO_LE32 (part->geom.length
++ / (part->disk->dev->sector_size / 512));
++
++ /* EFI system partitions will have a FAT filesystem and
++ PARTITION_SYSTEM_GUID; however, it is not wise to rely on filesystem
++ probing */
++
++ if (number == 1) {
++ if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID) ||
++ !guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID)) {
++ raw_part->OSType = EFI_PMBR_OSTYPE_EFI;
++ raw_part->OSType = EFI_PMBR_OSTYPE_EFI;
++ }
++ }
++
++ /* Apple's firmware also appears to be unhappy if the EFI system
++ partition doesn't extend all the way to the start of the disk */
++
++ if (number == 1 && raw_part->OSType == EFI_PMBR_OSTYPE_EFI) {
++ raw_part->StartSector = 1;
++ raw_part->SizeInLBA += raw_part->StartingLBA - 1;
++ raw_part->StartingLBA = 1;
++ } else {
++ raw_part->StartHead = 0xfe;
++ raw_part->StartSector = 0xff;
++ raw_part->StartTrack = 0xff;
++ }
++
++ raw_part->EndHead = 0xfe;
++ raw_part->EndSector = 0xff;
++ raw_part->EndTrack = 0xff;
++}
++
++static int
++_gptsync (const PedDisk *disk)
++{
++ void *s0;
++ PedPartition* part;
++ int i;
++
++ if (!ptt_read_sector (disk->dev, GPT_PMBR_LBA, &s0))
++ return 0;
++ LegacyMBR_t *pmbr = s0;
++
++ int ok = 0;
++
++ memset(&pmbr->PartitionRecord, 0, sizeof(pmbr->PartitionRecord));
++ pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
++
++ bool prot = false; /* have we found a protective partition? */
++ for (i=1; i<=4; i++) {
++ part = ped_disk_get_partition (disk, i);
++ if (!part)
++ continue;
++
++ fill_raw_part (&pmbr->PartitionRecord [i - 1], part, 0, i);
++ if (pmbr->PartitionRecord[i - 1].OSType == EFI_PMBR_OSTYPE_EFI)
++ prot = true;
++ }
++
++ if (!prot) { /* create one covering the gpt entries */
++ uint32_t prot_size;
++ for (i=2; i>=0; i--)
++ pmbr->PartitionRecord[i + 1] = pmbr->PartitionRecord[i];
++ memset (&pmbr->PartitionRecord[0], 0, sizeof pmbr->PartitionRecord[0]);
++ pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
++ pmbr->PartitionRecord[0].StartSector = 1;
++ pmbr->PartitionRecord[0].EndHead = 0xfe;
++ pmbr->PartitionRecord[0].EndSector = 0xff;
++ pmbr->PartitionRecord[0].EndTrack = 0xff;
++ pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
++ if ((disk->dev->length - 1ULL) > 0xFFFFFFFFULL)
++ prot_size = 0xFFFFFFFF;
++ else
++ prot_size = disk->dev->length - 1UL;
++ for (i=1; i<=3; i++) {
++ if (pmbr->PartitionRecord[i].StartingLBA) {
++ uint32_t starting_lba =
++ PED_LE32_TO_CPU (pmbr->PartitionRecord[i].StartingLBA);
++ if (starting_lba - 1 < prot_size)
++ prot_size = starting_lba - 1;
++ }
++ }
++ pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (prot_size);
++ }
++
++ if (!ped_device_write (disk->dev, pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
++ goto error;
++
++ ok = ped_device_sync (disk->dev);
++error:
++ free (s0);
++ return ok;
++}
++
+ static int
+ _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
+ GuidPartitionTableHeader_t **gpt_p)
+@@ -1287,9 +1451,15 @@ gpt_write (const PedDisk *disk)
+
+ ptes_crc = efi_crc32 (ptes, ptes_bytes);
+
+- /* Write protective MBR */
+- if (!_write_pmbr (disk->dev, gpt_disk_data->pmbr_boot))
+- goto error_free_ptes;
++ if (is_apple) {
++ /* Write synced MBR */
++ if (!_gptsync (disk))
++ goto error_free_ptes;
++ } else {
++ /* Write protective MBR */
++ if (!_write_pmbr (disk->dev, gpt_disk_data->pmbr_boot))
++ goto error_free_ptes;
++ }
+
+ /* Write PTH and PTEs */
+ /* FIXME: Caution: this code is nearly identical to what's just below. */
+@@ -1938,6 +2108,21 @@ void
+ ped_disk_gpt_init ()
+ {
+ ped_disk_type_register (&gpt_disk_type);
++
++ char *force_gpt_apple = getenv ("PARTED_GPT_APPLE");
++ if (force_gpt_apple) {
++ if (strcmp (force_gpt_apple, "1") == 0)
++ is_apple = 1;
++ } else {
++ char *manufacturer = dmi_system_manufacturer ();
++ if (manufacturer &&
++ (strncasecmp (APPLE_DMI, manufacturer,
++ strlen (APPLE_DMI)) == 0 ||
++ strncasecmp (APPLE_DMI_2, manufacturer,
++ strlen (APPLE_DMI_2)) == 0))
++ is_apple = 1;
++ free (manufacturer);
++ }
+ }
+
+ void
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index da093119..3c1f929a 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -32,6 +32,7 @@ TESTS = \
+ t0282-gpt-move-backup.sh \
+ t0283-overlap-partitions.sh \
+ t0290-gpt-name.sh \
++ t0290-gptsync.sh \
+ t0300-dos-on-gpt.sh \
+ t0301-overwrite-gpt-pmbr.sh \
+ t0350-mac-PT-increases-sector-size.sh \
+diff --git a/tests/t0290-gptsync.sh b/tests/t0290-gptsync.sh
+new file mode 100644
+index 00000000..367d61bd
+--- /dev/null
++++ b/tests/t0290-gptsync.sh
+@@ -0,0 +1,175 @@
++#!/bin/sh
++# test GPT -> hybrid MBR syncing for Apple systems
++# http://www.rodsbooks.com/gdisk/hybrid.html
++
++# Copyright (C) 2012 Canonical Ltd.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++if test "$VERBOSE" = yes; then
++ set -x
++ parted --version
++fi
++
++: ${srcdir=.}
++. $srcdir/t-lib.sh
++
++require_root_
++require_scsi_debug_module_
++
++ss=$sector_size_
++# must be big enough for a 32MiB partition in order to be big enough for FAT16
++n_sectors=131072
++bootcode_size=446
++mbr_table_size=$((512 - $bootcode_size))
++
++dump_mbr_table () {
++ dd if=$dev bs=1 skip=$bootcode_size count=$mbr_table_size 2>/dev/null | od -v -An -tx1
++}
++
++# create memory-backed device
++sectors_per_MiB=$((1024 * 1024 / $ss))
++n_MiB=$((($n_sectors + $sectors_per_MiB - 1) / $sectors_per_MiB))
++scsi_debug_setup_ dev_size_mb=$n_MiB > dev-name ||
++ skip_test_ 'failed to create scsi_debug device'
++dev=$(cat dev-name)
++
++# force Apple mode
++export PARTED_GPT_APPLE=1
++
++# create gpt label
++parted -s $dev mklabel gpt > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++
++# print the empty table
++parted -m -s $dev unit s print > t 2>&1 || fail=1
++sed "s,.*/$dev:,$dev:," t > out || fail=1
++
++# check for expected output
++printf "BYT;\n$dev:${n_sectors}s:scsi:$sector_size_:$sector_size_:gpt:Linux scsi_debug;\n" \
++ > exp || fail=1
++compare exp out || fail=1
++
++# the empty table should have a MBR containing only a protective entry
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff ff 01 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# create a 32MiB FAT16 EFI System Partition
++parted -s $dev mkpart p1 fat16 2048s 67583s set 1 boot on > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++mkfs.vfat -F 16 ${dev}1 >/dev/null || skip_ "mkfs.vfat failed"
++
++# this is represented as a protective partition, but now it only extends as
++# far as the end of the first partition rather than covering the whole disk
++# (matching refit gptsync's strategy); it still starts at sector one
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff 07 01 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# add a 2MiB ext3 partition
++parted -s $dev mkpart p2 ext3 67584s 71679s > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++mkfs.ext3 ${dev}2 >/dev/null 2>&1 || skip_ "mkfs.ext3 failed"
++
++# this should have an MBR representing both partitions; the second partition
++# should be marked bootable
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff 07 01 00
++ 80 fe ff ff 83 fe ff ff 00 08 01 00 00 10 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# add a 1MiB partition with no filesystem
++parted -s $dev mkpart p3 71680s 73727s > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++
++# the new partition should be represented as 0xda (Non-FS data)
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff 07 01 00
++ 80 fe ff ff 83 fe ff ff 00 08 01 00 00 10 00 00
++ 00 fe ff ff da fe ff ff 00 18 01 00 00 08 00 00
++ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# add two more 1MiB partitions
++parted -s $dev mkpart p4 73728s 75775s > empty 2>&1 || fail=1
++parted -s $dev mkpart p5 75776s 77823s > empty 2>&1 || fail=1
++
++# only the first four partitions will be represented
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff 07 01 00
++ 80 fe ff ff 83 fe ff ff 00 08 01 00 00 10 00 00
++ 00 fe ff ff da fe ff ff 00 18 01 00 00 08 00 00
++ 00 fe ff ff da fe ff ff 00 20 01 00 00 08 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# convert first partition to a BIOS Boot Partition
++parted -s $dev set 1 boot off set 1 bios_grub on > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++
++# this should be represented in the same way as an EFI System Partition
++dump_mbr_table > out || fail=1
++compare exp out || fail=1
++
++# convert first partition to an ordinary FAT partition
++parted -s $dev set 1 bios_grub off > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++
++# this should result in a protective partition covering the GPT data up to
++# the start of the first partition, and then representations of the first
++# three partitions
++dump_mbr_table > out || fail=1
++cat <<EOF > exp || fail=1
++ 00 00 01 00 ee fe ff ff 01 00 00 00 ff 07 00 00
++ 00 fe ff ff 0b fe ff ff 00 08 00 00 00 00 01 00
++ 80 fe ff ff 83 fe ff ff 00 08 01 00 00 10 00 00
++ 00 fe ff ff da fe ff ff 00 18 01 00 00 08 00 00
++ 55 aa
++EOF
++compare exp out || fail=1
++
++# convert third partition to a BIOS Boot Partition
++parted -s $dev set 3 bios_grub on > empty 2>&1 || fail=1
++compare /dev/null empty || fail=1
++
++# since this isn't the first partition, it shouldn't become a protective
++# partition or have its starting LBA address set to 1 (and GRUB doesn't care
++# whether it's in the hybrid MBR anyway)
++dump_mbr_table > out || fail=1
++compare exp out || fail=1
++
++Exit $fail