summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:16:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:16:35 +0000
commit0658a8b1efc58836eb6674a1b0aadfbdf0e54755 (patch)
treee1d58d026a886d854c9e01cb4a683ad81fcb6e59 /debian/patches
parentAdding upstream version 3.6. (diff)
downloadparted-0658a8b1efc58836eb6674a1b0aadfbdf0e54755.tar.xz
parted-0658a8b1efc58836eb6674a1b0aadfbdf0e54755.zip
Adding debian version 3.6-3.debian/3.6-3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/align-new-partitions-on-fresh-disks.patch45
-rw-r--r--debian/patches/doc-package.patch25
-rw-r--r--debian/patches/freebsd-geli.patch38
-rw-r--r--debian/patches/freebsd-ufs.patch291
-rw-r--r--debian/patches/freebsd-zvol.patch83
-rw-r--r--debian/patches/gptsync.patch466
-rw-r--r--debian/patches/kfreebsd-gnu.patch1434
-rw-r--r--debian/patches/kfreebsd_lvm.patch55
-rw-r--r--debian/patches/link-libuuid.patch32
-rw-r--r--debian/patches/preserve-hidden-parts.patch45
-rw-r--r--debian/patches/probe-lvs-again.patch34
-rw-r--r--debian/patches/series13
-rw-r--r--debian/patches/udevadm-settle.patch105
-rw-r--r--debian/patches/zfs.patch145
14 files changed, 2811 insertions, 0 deletions
diff --git a/debian/patches/align-new-partitions-on-fresh-disks.patch b/debian/patches/align-new-partitions-on-fresh-disks.patch
new file mode 100644
index 0000000..c37bfe0
--- /dev/null
+++ b/debian/patches/align-new-partitions-on-fresh-disks.patch
@@ -0,0 +1,45 @@
+From 8b6f34acaadd78d11415144dccf5c4750e3e1d0e Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Wed, 6 Aug 2014 16:07:28 +0200
+Subject: Align new partitions created on fresh disks
+
+Commit fa815ad05db248d78ef214ea79a78c22772a9ffe arranged to skip
+partition alignment while reading disks, but also has the effect of
+skipping partition alignment when creating a partition on a fresh disk,
+which is incorrect.
+
+The proper upstream fix probably involves adding a new member to PedDisk
+to keep track of whether we're in the middle of the initial read in
+ped_disk_new or not. To avoid changing ABI, we instead take this hacky
+approach of overloading an extra bit on PedDisk.needs_clobber.
+
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1352252
+Forwarded: no
+Last-Update: 2023-06-26
+
+Patch-Name: align-new-partitions-on-fresh-disks.patch
+---
+ libparted/disk.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/libparted/disk.c b/libparted/disk.c
+index 0db7b5c9..2d6b9d49 100644
+--- a/libparted/disk.c
++++ b/libparted/disk.c
+@@ -198,6 +198,7 @@ ped_disk_new (PedDevice* dev)
+ disk = ped_disk_new_fresh (dev, type);
+ if (!disk)
+ goto error_close_dev;
++ disk->needs_clobber |= 2;
+ if (!type->ops->read (disk))
+ goto error_destroy_disk;
+ disk->needs_clobber = 0;
+@@ -951,7 +952,7 @@ _partition_align (PedPartition* part, const PedConstraint* constraint)
+ PED_ASSERT (disk_type->ops->partition_align != NULL);
+ PED_ASSERT (part->disk->update_mode);
+
+- if (part->disk->needs_clobber)
++ if ((part->disk->needs_clobber & 2) != 0 || !constraint)
+ return 1; /* do not attempt to align partitions while reading them */
+ return disk_type->ops->partition_align (part, constraint);
+ }
diff --git a/debian/patches/doc-package.patch b/debian/patches/doc-package.patch
new file mode 100644
index 0000000..d4dc59a
--- /dev/null
+++ b/debian/patches/doc-package.patch
@@ -0,0 +1,25 @@
+From 2bf67dffffb5b09ce5b3deca65d279f8526a6033 Mon Sep 17 00:00:00 2001
+From: Timshel Knoll <timshel@debian.org>
+Date: Fri, 28 Mar 2014 17:09:39 +0000
+Subject: Small documentation fixes
+
+Forwarded: not-needed
+
+Patch-Name: doc-package.patch
+---
+ doc/C/parted.8 | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/doc/C/parted.8 b/doc/C/parted.8
+index 3069c335..18abf537 100644
+--- a/doc/C/parted.8
++++ b/doc/C/parted.8
+@@ -160,7 +160,7 @@ The \fIparted\fP program is fully documented in the
+ .BR info(1)
+ format
+ .IR "GNU partitioning software"
+-manual.
++manual which is distributed with the parted-doc Debian package.
+ .SH AUTHOR
+ This manual page was written by Timshel Knoll <timshel@debian.org>,
+ for the Debian GNU/Linux system (but may be used by others).
diff --git a/debian/patches/freebsd-geli.patch b/debian/patches/freebsd-geli.patch
new file mode 100644
index 0000000..0e71090
--- /dev/null
+++ b/debian/patches/freebsd-geli.patch
@@ -0,0 +1,38 @@
+From 981a6a2a87a90b25b83ecfc76f5c82c0fadcbbf8 Mon Sep 17 00:00:00 2001
+From: Robert Millan <rmh@debian.org>
+Date: Fri, 28 Mar 2014 17:09:51 +0000
+Subject: Detection of GEOM encryption devices (GELI)
+
+Bug-Debian: http://bugs.debian.org/635393
+Forwarded: no
+Last-Update: 2011-07-30
+
+Patch-Name: freebsd-geli.patch
+---
+ libparted/arch/freebsd.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/libparted/arch/freebsd.c b/libparted/arch/freebsd.c
+index a60b43f8..b78d2bb0 100644
+--- a/libparted/arch/freebsd.c
++++ b/libparted/arch/freebsd.c
+@@ -1096,6 +1096,8 @@ _probe_kern_disks ()
+ {
+ size_t listsize;
+ char *disklist, *pdisklist, *psave;
++ char buf[PATH_MAX];
++ struct stat st;
+
+ if (sysctlbyname("kern.disks", NULL, &listsize, NULL, 0) != 0) {
+ ped_exception_throw (
+@@ -1129,6 +1131,10 @@ _probe_kern_disks ()
+ strncat (dev_name, token, sizeof(dev_name) - strlen(_PATH_DEV) - 1);
+ dev_name[sizeof(dev_name) - 1] = '\0';
+ _ped_device_probe (dev_name);
++
++ snprintf (buf, sizeof (buf), "%s.eli", dev_name);
++ if (stat (buf, &st) == 0)
++ _ped_device_probe (buf);
+ }
+
+ free(disklist);
diff --git a/debian/patches/freebsd-ufs.patch b/debian/patches/freebsd-ufs.patch
new file mode 100644
index 0000000..2484d07
--- /dev/null
+++ b/debian/patches/freebsd-ufs.patch
@@ -0,0 +1,291 @@
+From 1bb66d74adb068f467668aa6f2cd36775cb63fee Mon Sep 17 00:00:00 2001
+From: Aurelien Jarno <aurelien@aurel32.net>
+Date: Fri, 28 Mar 2014 17:09:46 +0000
+Subject: Add FreeBSD UFS support
+
+This patch adds support for detection of FreeBSD UFS file systems and
+creation of the partition on DOS and GPT labels. It doesn't use the
+system of slices used by default on FreeBSD and places the partition
+directly in the dos label. This is something supported by the FreeBSD
+kernel, and the default on Debian GNU/kFreeBSD. Even on plain FreeBSD,
+some persons prefer to not use slices.
+
+This patch is used by debian-installer on Debian GNU/kFreeBSD for some
+months already.
+
+Last-Update: 2023-06-12
+
+Patch-Name: freebsd-ufs.patch
+---
+ libparted/fs/ufs/ufs.c | 103 ++++++++++++++++++++++++++++++++++---
+ libparted/labels/dos.c | 3 ++
+ libparted/labels/gpt.c | 9 ++++
+ tests/Makefile.am | 1 +
+ tests/t2500-freebsd-ufs.sh | 44 ++++++++++++++++
+ 5 files changed, 153 insertions(+), 7 deletions(-)
+ create mode 100644 tests/t2500-freebsd-ufs.sh
+
+diff --git a/libparted/fs/ufs/ufs.c b/libparted/fs/ufs/ufs.c
+index d2bf4214..08ed5603 100644
+--- a/libparted/fs/ufs/ufs.c
++++ b/libparted/fs/ufs/ufs.c
+@@ -45,6 +45,7 @@
+ #define UFS_MAGIC_LFN 0x00095014
+ #define UFS_MAGIC_FEA 0x00195612
+ #define UFS_MAGIC_4GB 0x05231994
++#define UFS2_MAGIC 0x19540119
+
+ struct __attribute__ ((packed)) ufs_csum {
+ uint32_t cs_ndir; /* number of directories */
+@@ -129,13 +130,50 @@ struct __attribute__ ((packed)) ufs_super_block {
+ int8_t fs_clean; /* file system is clean flag */
+ int8_t fs_ronly; /* mounted read-only flag */
+ int8_t fs_flags; /* currently unused flag */
+- int8_t fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */
+-/* these fields retain the current block allocation info */
+- uint32_t fs_cgrotor; /* last cg searched */
+- uint32_t fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */
+- uint32_t fs_maxcluster;
+- uint32_t fs_cpc; /* cyl per cycle in postbl */
+- uint16_t fs_opostbl[16][8]; /* old rotation block list head */
++ union {
++ struct {
++ int8_t fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */
++ /* these fields retain the current block allocation info */
++ uint32_t fs_cgrotor; /* last cg searched */
++ uint32_t fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */
++ uint32_t fs_maxcluster;
++ uint32_t fs_cpc; /* cyl per cycle in postbl */
++ uint16_t fs_opostbl[16][8]; /* old rotation block list head */
++ } fs_u1;
++ struct {
++ int8_t fs_fsmnt[468];
++ uint8_t fs_volname[32];
++ uint64_t fs_swuid;
++ int32_t fs_pad;
++ uint32_t fs_cgrotor;
++ uint32_t fs_ocsp[28];
++ uint32_t fs_contigdirs;
++ uint32_t fs_csp;
++ uint32_t fs_maxcluster;
++ uint32_t fs_active;
++ int32_t fs_old_cpc;
++ int32_t fs_maxbsize;
++ int64_t fs_sparecon64[17];
++ int64_t fs_sblockloc;
++ struct ufs2_csum_total {
++ uint64_t cs_ndir;
++ uint64_t cs_nbfree;
++ uint64_t cs_nifree;
++ uint64_t cs_nffree;
++ uint64_t cs_numclusters;
++ uint64_t cs_spare[3];
++ } fs_cstotal;
++ struct ufs_timeval {
++ int32_t tv_sec;
++ int32_t tv_usec;
++ } fs_time;
++ int64_t fs_size;
++ int64_t fs_dsize;
++ uint64_t fs_csaddr;
++ int64_t fs_pendingblocks;
++ int32_t fs_pendinginodes;
++ } __attribute__((packed)) fs_u2;
++ } fs_u11;
+ union {
+ struct {
+ int32_t fs_sparecon[53];/* reserved for future constants */
+@@ -244,6 +282,45 @@ ufs_probe_hp (PedGeometry* geom)
+ return NULL;
+ }
+
++static PedGeometry*
++ufs_probe_freebsd (PedGeometry* geom)
++{
++ int offsets[] = { 0, 16, 128, 512 };
++ char *buf = alloca (3 * geom->dev->sector_size);
++ struct ufs_super_block *sb;
++ PedSector block_size;
++ PedSector block_count;
++ int i;
++
++ if (geom->length < 5)
++ return 0;
++
++ /* The UFS superblock could be on four different positions */
++ for (i = 0; i < 4; i++) {
++ if (!ped_geometry_read (geom, buf, offsets[i], 3))
++ return 0;
++
++ sb = (struct ufs_super_block *)buf;
++
++ /* Little endian is more likely on FreeBSD boxes */
++ if (PED_LE32_TO_CPU(sb->fs_magic) == UFS2_MAGIC) {
++ block_size = PED_LE32_TO_CPU(sb->fs_fsize) / geom->dev->sector_size;
++ block_count = PED_LE32_TO_CPU(sb->fs_u11.fs_u2.fs_size);
++ return ped_geometry_new (geom->dev, geom->start,
++ block_size * block_count);
++ }
++
++ /* Then try big endian */
++ if (PED_BE32_TO_CPU(sb->fs_magic) == UFS2_MAGIC) {
++ block_size = PED_BE32_TO_CPU(sb->fs_fsize) / geom->dev->sector_size;
++ block_count = PED_BE32_TO_CPU(sb->fs_u11.fs_u2.fs_size);
++ return ped_geometry_new (geom->dev, geom->start,
++ block_size * block_count);
++ }
++ }
++ return NULL;
++}
++
+ static PedFileSystemOps ufs_ops_sun = {
+ probe: ufs_probe_sun,
+ };
+@@ -252,6 +329,10 @@ static PedFileSystemOps ufs_ops_hp = {
+ probe: ufs_probe_hp,
+ };
+
++static PedFileSystemOps ufs_ops_freebsd = {
++ probe: ufs_probe_freebsd,
++};
++
+ static PedFileSystemType ufs_type_sun = {
+ next: NULL,
+ ops: &ufs_ops_sun,
+@@ -264,6 +345,12 @@ static PedFileSystemType ufs_type_hp = {
+ name: "hp-ufs",
+ };
+
++static PedFileSystemType ufs_type_freebsd_ufs = {
++ next: NULL,
++ ops: &ufs_ops_freebsd,
++ name: "freebsd-ufs"
++};
++
+ void
+ ped_file_system_ufs_init ()
+ {
+@@ -271,11 +358,13 @@ ped_file_system_ufs_init ()
+
+ ped_file_system_type_register (&ufs_type_sun);
+ ped_file_system_type_register (&ufs_type_hp);
++ ped_file_system_type_register (&ufs_type_freebsd_ufs);
+ }
+
+ void
+ ped_file_system_ufs_done ()
+ {
++ ped_file_system_type_unregister (&ufs_type_freebsd_ufs);
+ ped_file_system_type_unregister (&ufs_type_hp);
+ ped_file_system_type_unregister (&ufs_type_sun);
+ }
+diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
+index 256f365d..95737d56 100644
+--- a/libparted/labels/dos.c
++++ b/libparted/labels/dos.c
+@@ -89,6 +89,7 @@ static const char MBR_BOOT_CODE[] = {
+ #define PARTITION_IRST 0x84
+ #define PARTITION_LINUX_EXT 0x85
+ #define PARTITION_LINUX_LVM 0x8e
++#define PARTITION_FREEBSD_UFS 0xa5
+ #define PARTITION_HFS 0xaf
+ #define PARTITION_SUN_UFS 0xbf
+ #define PARTITION_DELL_DIAG 0xde
+@@ -1610,6 +1611,8 @@ msdos_partition_set_system (PedPartition* part,
+ dos_data->system = PARTITION_UDF;
+ else if (!strcmp (fs_type->name, "sun-ufs"))
+ dos_data->system = PARTITION_SUN_UFS;
++ else if (!strcmp (fs_type->name, "freebsd-ufs"))
++ dos_data->system = PARTITION_FREEBSD_UFS;
+ else if (is_linux_swap (fs_type->name))
+ dos_data->system = PARTITION_LINUX_SWAP;
+ else
+diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
+index 780fb705..130b9bd1 100644
+--- a/libparted/labels/gpt.c
++++ b/libparted/labels/gpt.c
+@@ -169,6 +169,10 @@ typedef struct
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x933ac7e1), PED_CPU_TO_LE16 (0x2eb4), \
+ PED_CPU_TO_LE16 (0x4f13), 0xb8, 0x44, \
+ { 0x0e, 0x14, 0xe2, 0xae, 0xf9, 0x15 }})
++#define PARTITION_FREEBSD_UFS_GUID \
++ ((efi_guid_t) { PED_CPU_TO_LE32 (0x516e7cb6), PED_CPU_TO_LE16 (0x6ecf), \
++ PED_CPU_TO_LE16 (0x11d6), 0x8f, 0xf8, \
++ { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b }})
+
+ struct flag_uuid_mapping_t
+ {
+@@ -1490,6 +1494,11 @@ gpt_partition_set_system (PedPartition *part,
+ gpt_part_data->type = PARTITION_SWAP_GUID;
+ return 1;
+ }
++ if (strstr (fs_type->name, "freebsd-ufs"))
++ {
++ gpt_part_data->type = PARTITION_FREEBSD_UFS_GUID;
++ return 1;
++ }
+ }
+
+ gpt_part_data->type = PARTITION_LINUX_DATA_GUID;
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index fa27b44d..da093119 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -57,6 +57,7 @@ TESTS = \
+ t2320-dos-extended-noclobber.sh \
+ t2400-dos-hfs-partition-type.sh \
+ t2410-dos-udf-partition-type.sh \
++ t2500-freebsd-ufs.sh \
+ t2500-probe-corrupt-hfs.sh \
+ t3000-resize-fs.sh \
+ t3200-resize-partition.sh \
+diff --git a/tests/t2500-freebsd-ufs.sh b/tests/t2500-freebsd-ufs.sh
+new file mode 100644
+index 00000000..5a46263d
+--- /dev/null
++++ b/tests/t2500-freebsd-ufs.sh
+@@ -0,0 +1,44 @@
++#!/bin/sh
++# Probe FreeBSD UFS file system
++
++# Copyright (C) 2010 Free Software Foundation, Inc.
++
++# 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_512_byte_sector_size_
++
++dev=loop-file
++ss=$sector_size_
++n_sectors=8000
++
++fail=0
++
++( type mkfs.ufs ) >/dev/null 2>&1 || skip_test_ "no freebsd-ufs support"
++
++# create a freebsd-ufs file system
++dd if=/dev/zero of=$dev bs=1024 count=4096 >/dev/null || fail=1
++mkfs.ufs `pwd`/$dev >/dev/null || fail=1
++
++# probe the freebsd-ufs file system
++parted -m -s $dev u s print >out 2>&1 || fail=1
++grep '^1:.*:freebsd-ufs::;$' out || fail=1
++
++Exit $fail
diff --git a/debian/patches/freebsd-zvol.patch b/debian/patches/freebsd-zvol.patch
new file mode 100644
index 0000000..b7826bc
--- /dev/null
+++ b/debian/patches/freebsd-zvol.patch
@@ -0,0 +1,83 @@
+From 3b19f4af4398d71eb3dd58041d4aff94e05efb6d Mon Sep 17 00:00:00 2001
+From: Robert Millan <rmh@debian.org>
+Date: Fri, 28 Mar 2014 17:09:50 +0000
+Subject: Detection of ZFS volumes (ZVOL)
+
+ZFS volumes (ZVOL) are the ZFS equivalent of Logical Volumes in LVM.
+
+They implement a block device which can be used for swap or legacy
+filesystems.
+
+Bug-Debian: http://bugs.debian.org/635384
+Forwarded: no
+Last-Update: 2011-07-30
+
+Patch-Name: freebsd-zvol.patch
+---
+ libparted/arch/freebsd.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+diff --git a/libparted/arch/freebsd.c b/libparted/arch/freebsd.c
+index 4c690e5f..a60b43f8 100644
+--- a/libparted/arch/freebsd.c
++++ b/libparted/arch/freebsd.c
+@@ -23,6 +23,7 @@
+ #include <parted/debug.h>
+
+ #include <ctype.h>
++#include <dirent.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdint.h>
+@@ -1134,12 +1135,51 @@ _probe_kern_disks ()
+ return 1;
+ }
+
++static int
++_probe_zfs_volumes ()
++{
++ DIR* pool_dir;
++ DIR* zvol_dir;
++ struct dirent* pool_dent;
++ struct dirent* zvol_dent;
++ char buf[PATH_MAX];
++ struct stat st;
++
++ pool_dir = opendir ("/dev/zvol");
++ if (!pool_dir)
++ return 0;
++
++ while ((pool_dent = readdir (pool_dir))) {
++ if (strcmp (pool_dent->d_name, ".") == 0 || strcmp (pool_dent->d_name, "..") == 0)
++ continue;
++
++ snprintf (buf, sizeof (buf), "/dev/zvol/%s", pool_dent->d_name);
++ zvol_dir = opendir (buf);
++
++ while ((zvol_dent = readdir (zvol_dir))) {
++ if (strcmp (zvol_dent->d_name, ".") == 0 || strcmp (zvol_dent->d_name, "..") == 0)
++ continue;
++
++ snprintf (buf, sizeof (buf), "/dev/zvol/%s/%s", pool_dent->d_name, zvol_dent->d_name);
++ if (stat (buf, &st) != 0)
++ continue;
++ _ped_device_probe (buf);
++ }
++ closedir (zvol_dir);
++ }
++ closedir (pool_dir);
++
++ return 1;
++}
++
+ static void
+ freebsd_probe_all ()
+ {
+ _probe_standard_devices ();
+
+ _probe_kern_disks ();
++
++ _probe_zfs_volumes ();
+ }
+
+ static char*
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
diff --git a/debian/patches/kfreebsd-gnu.patch b/debian/patches/kfreebsd-gnu.patch
new file mode 100644
index 0000000..609a2a8
--- /dev/null
+++ b/debian/patches/kfreebsd-gnu.patch
@@ -0,0 +1,1434 @@
+From c55385989caf6e0fcdeb2a2157fbf2a3f3b59459 Mon Sep 17 00:00:00 2001
+From: Viktor Vasilev <Viktor Vasilev>
+Date: Fri, 28 Mar 2014 17:09:42 +0000
+Subject: Add GNU/kFreeBSD support
+
+Author: Robert Millan <rmh@aybabtu.com>
+Author: Colin Watson <cjwatson@debian.org>
+Author: Jeff Epler <jepler@unpythonic.net>
+Bug-Debian: http://bugs.debian.org/363381
+Bug-Debian: http://bugs.debian.org/693510
+Forwarded: no
+Last-Update: 2019-10-11
+
+Patch-Name: kfreebsd-gnu.patch
+---
+ configure.ac | 10 +-
+ libparted/Makefile.am | 3 +-
+ libparted/arch/freebsd.c | 1292 ++++++++++++++++++++++++++++++
+ libparted/architecture.c | 3 +
+ libparted/fs/xfs/platform_defs.h | 6 +-
+ libparted/labels/bsd.c | 1 +
+ libparted/labels/sun.c | 1 +
+ 7 files changed, 1311 insertions(+), 5 deletions(-)
+ create mode 100644 libparted/arch/freebsd.c
+
+diff --git a/configure.ac b/configure.ac
+index cf9fb8a5..d838c32c 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -62,7 +62,8 @@ case "$host_os" in
+ linux*|uclinux*) OS=linux ;;
+ gnu*) OS=gnu ;;
+ beos*) OS=beos ;;
+- *) AC_MSG_ERROR([Unknown or unsupported OS "$host_os". Only "linux", "uclinux", "gnu" and "beos" are supported in this version of GNU Parted.]) ;;
++ freebsd* | kfreebsd*-gnu) OS=freebsd ;;
++ *) AC_MSG_ERROR([Unknown or unsupported OS "$host_os". Only "linux", "gnu" and "beos" are supported in this version of GNU Parted.]) ;;
+ esac
+ AC_SUBST([OS])
+
+@@ -256,6 +257,7 @@ AC_CHECK_SIZEOF([off_t], [64], [
+ #include <sys/types.h>
+ #include <unistd.h>
+ ])
++AC_CHECK_TYPE([loff_t], [long long])
+
+ AC_ENABLE_SHARED([])
+ if test "$OS" = linux && test $ac_cv_sizeof_off_t -lt 8; then
+@@ -454,7 +456,7 @@ If you can't find one try:
+ http://web.mit.edu/tytso/www/linux/e2fsprogs.html])]
+ )
+
+-AC_CHECK_HEADERS([getopt.h])
++AC_CHECK_HEADERS([getopt.h endian.h sys/endian.h])
+ AC_CHECK_HEADERS([linux/ext2_fs.h])
+
+ dnl required for libparted/llseek.c (TODO: make linux-x86 only)
+@@ -513,7 +515,9 @@ AC_C_CONST
+ AC_C_RESTRICT
+
+ dnl Checks for library functions.
+-AC_CHECK_FUNCS([sigaction])
++if test "$OS" != freebsd; then
++ AC_CHECK_FUNCS([sigaction])
++fi
+ AC_CHECK_FUNCS([getuid])
+
+ dnl NOTE: We need to remove the gl_cv_ignore_unused_libraries flag if we
+diff --git a/libparted/Makefile.am b/libparted/Makefile.am
+index db29a189..b2b910e1 100644
+--- a/libparted/Makefile.am
++++ b/libparted/Makefile.am
+@@ -48,7 +48,8 @@ libparted_la_SOURCES = debug.c \
+ EXTRA_libparted_la_SOURCES = arch/linux.c \
+ arch/linux.h \
+ arch/gnu.c \
+- arch/beos.c
++ arch/beos.c \
++ arch/freebsd.c
+
+ libparted_la_LIBADD = \
+ fs/libfs.la \
+diff --git a/libparted/arch/freebsd.c b/libparted/arch/freebsd.c
+new file mode 100644
+index 00000000..4c690e5f
+--- /dev/null
++++ b/libparted/arch/freebsd.c
+@@ -0,0 +1,1292 @@
++/*
++ libparted - a library for manipulating disk partitions
++ Copyright (C) 1999 - 2009 Free Software Foundation, Inc.
++
++ 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 2 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, write to the Free Software
++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
++*/
++
++#include "config.h"
++
++#include <parted/parted.h>
++#include <parted/debug.h>
++
++#include <ctype.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <paths.h>
++#include <sys/param.h>
++#include <sys/mount.h>
++#include <sys/ioctl.h>
++#include <sys/sysctl.h>
++#include <sys/stat.h>
++#include <sys/disk.h>
++#include <sys/ata.h>
++#include <cam/cam.h>
++#include <cam/scsi/scsi_pass.h>
++
++#include "../architecture.h"
++
++#if ENABLE_NLS
++# include <libintl.h>
++# define _(String) dgettext (PACKAGE, String)
++#else
++# define _(String) (String)
++#endif /* ENABLE_NLS */
++
++#if !defined(__FreeBSD_version) && defined(__FreeBSD_kernel_version)
++#define __FreeBSD_version __FreeBSD_kernel_version
++#endif
++
++#define FREEBSD_SPECIFIC(dev) ((FreeBSDSpecific*) (dev)->arch_specific)
++
++typedef struct _FreeBSDSpecific FreeBSDSpecific;
++
++struct _FreeBSDSpecific {
++ int fd;
++ long long phys_sector_size;
++};
++
++static char* _device_get_part_path (PedDevice* dev, int num);
++static int _partition_is_mounted_by_path (const char* path);
++
++static int
++_device_stat (PedDevice* dev, struct stat * dev_stat)
++{
++ PED_ASSERT (dev != NULL);
++ PED_ASSERT (!dev->external_mode);
++
++ while (1) {
++ if (!stat (dev->path, dev_stat)) {
++ return 1;
++ } else {
++ if (ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_CANCEL,
++ _("Could not stat device %s - %s."),
++ dev->path,
++ strerror (errno))
++ != PED_EXCEPTION_RETRY)
++ return 0;
++ }
++ }
++}
++
++static int
++_device_probe_type (PedDevice* dev)
++{
++ struct stat dev_stat;
++ char *np;
++
++ if (!_device_stat (dev, &dev_stat))
++ return 0;
++
++ if (!S_ISCHR(dev_stat.st_mode)) {
++ dev->type = PED_DEVICE_FILE;
++ return 1;
++ }
++
++ np = strrchr(dev->path, '/');
++ if (np == NULL) {
++ dev->type = PED_DEVICE_UNKNOWN;
++ return 0;
++ }
++ np += 1; /* advance past '/' */
++
++ if (strncmp(np, "ada", 3) == 0) {
++ dev->type = PED_DEVICE_SCSI;
++ } else if (strncmp(np, "ad", 2) == 0) {
++ dev->type = PED_DEVICE_IDE;
++ } else if (strncmp(np, "da", 2) == 0) {
++ dev->type = PED_DEVICE_SCSI;
++ } else if (strncmp(np, "acd", 2) == 0 ||
++ strncmp(np, "cd", 2) == 0) {
++ /* ignore CD-ROM drives */
++ dev->type = PED_DEVICE_UNKNOWN;
++ return 0;
++ } else {
++ dev->type = PED_DEVICE_UNKNOWN;
++ }
++
++ return 1;
++}
++
++static void
++_device_set_sector_size (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ int sector_size;
++
++ dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
++ dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
++
++ PED_ASSERT (dev->open_count);
++
++ if (ioctl (arch_specific->fd, DIOCGSECTORSIZE, &sector_size)) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Could not determine sector size for %s: %s.\n"
++ "Using the default sector size (%lld)."),
++ dev->path, strerror (errno), PED_SECTOR_SIZE_DEFAULT);
++ } else {
++ dev->sector_size = (long long)sector_size;;
++ }
++
++ if (arch_specific->phys_sector_size)
++ dev->phys_sector_size = arch_specific->phys_sector_size;
++
++ if (sector_size != PED_SECTOR_SIZE_DEFAULT) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Device %s has a logical sector size of %lld. Not "
++ "all parts of GNU Parted support this at the moment, "
++ "and the working code is HIGHLY EXPERIMENTAL.\n"),
++ dev->path, dev->sector_size);
++ }
++}
++
++static PedSector
++_device_get_length (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ off_t bytes = 0;
++
++ PED_ASSERT (dev->open_count > 0);
++ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
++
++ if(ioctl(arch_specific->fd, DIOCGMEDIASIZE, &bytes) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_BUG,
++ PED_EXCEPTION_CANCEL,
++ _("Unable to determine the size of %s (%s)."),
++ dev->path,
++ strerror (errno));
++ return 0;
++ }
++
++ return bytes / dev->sector_size;
++}
++
++
++static int
++_device_probe_geometry (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ struct stat dev_stat;
++ struct ata_params params;
++
++ if (!_device_stat (dev, &dev_stat))
++ return 0;
++ PED_ASSERT (S_ISCHR (dev_stat.st_mode));
++
++ _device_set_sector_size (dev);
++
++ dev->length = _device_get_length (dev);
++ if (!dev->length)
++ return 0;
++
++ dev->bios_geom.sectors = 63;
++ dev->bios_geom.heads = 255;
++ dev->bios_geom.cylinders
++ = dev->length / (63 * 255);
++
++ if (ioctl (arch_specific->fd, IOCATAGPARM, &params) != 0) {
++ dev->hw_geom.sectors = params.sectors;
++ dev->hw_geom.heads = params.heads;
++ dev->hw_geom.cylinders = params.cylinders;
++ } else {
++ dev->hw_geom = dev->bios_geom;
++ }
++
++ return 1;
++}
++
++static char*
++strip_name(char* str)
++{
++ int i;
++ int end = 0;
++
++ for (i = 0; str[i] != 0; i++) {
++ if (!isspace (str[i])
++ || (isspace (str[i]) && !isspace (str[i+1]) && str[i+1])) {
++ str [end] = str[i];
++ end++;
++ }
++ }
++ str[end] = 0;
++ return strdup (str);
++}
++
++static int
++init_ide (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ struct stat dev_stat;
++ struct ata_params params;
++ PedExceptionOption ex_status;
++ char vendor_buf[64];
++
++ if (!_device_stat (dev, &dev_stat))
++ goto error;
++
++ if (!ped_device_open (dev))
++ goto error;
++
++ if (ioctl (arch_specific->fd, IOCATAGPARM, &params) != 0) {
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Could not get identity of device %s - %s"),
++ dev->path, strerror (errno));
++ switch (ex_status) {
++ case PED_EXCEPTION_CANCEL:
++ goto error_close_dev;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_IGNORE:
++ dev->model = strdup(_("Generic IDE"));
++ break;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ } else {
++ snprintf(vendor_buf, 64, "%.40s/%.8s", params.model, params.revision);
++ dev->model = strip_name (vendor_buf);
++ }
++
++ if (!_device_probe_geometry (dev))
++ goto error_close_dev;
++
++ ped_device_close (dev);
++ return 1;
++
++error_close_dev:
++ ped_device_close (dev);
++error:
++ return 0;
++}
++
++static char *
++_scsi_pass_dev (PedDevice* dev)
++{
++ union ccb ccb;
++ int fd;
++ char result[64];
++
++ if (sscanf (dev->path, "/dev/%2s%u", ccb.cgdl.periph_name, &ccb.cgdl.unit_number) != 2 &&
++ sscanf (dev->path, "/dev/%3s%u", ccb.cgdl.periph_name, &ccb.cgdl.unit_number) != 2)
++ goto error;
++
++ if ((fd = open("/dev/xpt0", O_RDWR)) < 0)
++ goto error;
++
++ ccb.ccb_h.func_code = XPT_GDEVLIST;
++ if (ioctl(fd, CAMGETPASSTHRU, &ccb) != 0)
++ goto error_close_dev;
++
++ snprintf(result, sizeof(result), "/dev/%s%d", ccb.cgdl.periph_name, ccb.cgdl.unit_number);
++ close(fd);
++ return strdup(result);
++
++error_close_dev:
++ close(fd);
++error:
++ return NULL;
++}
++
++static uint32_t
++local_ata_logical_sector_size(struct ata_params *ident_data)
++{
++ if ((ident_data->pss & 0xc000) == 0x4000 &&
++ (ident_data->pss & ATA_PSS_LSSABOVE512)) {
++ return ((u_int32_t)ident_data->lss_1 |
++ ((u_int32_t)ident_data->lss_2 << 16));
++ }
++ return (512);
++}
++
++static uint64_t
++local_ata_physical_sector_size(struct ata_params *ident_data)
++{
++ if ((ident_data->pss & 0xc000) == 0x4000 &&
++ (ident_data->pss & ATA_PSS_MULTLS)) {
++ return ((uint64_t)local_ata_logical_sector_size(ident_data) *
++ (1 << (ident_data->pss & ATA_PSS_LSPPS)));
++ }
++ return (512);
++}
++
++static int
++init_scsi (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ PedExceptionOption ex_status;
++ struct stat dev_stat;
++ char* pass_dev;
++ int pass_fd;
++ union ccb ccb;
++
++ if (!_device_stat (dev, &dev_stat))
++ goto error;
++
++ if (!ped_device_open (dev))
++ goto error;
++
++ pass_dev = _scsi_pass_dev(dev);
++ if (!pass_dev)
++ goto error_close_dev;
++
++ pass_fd = open(pass_dev, O_RDWR);
++ if (pass_fd < 0) {
++ dev->host = 0;
++ dev->did = 0;
++ if (ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Error initialising SCSI device %s - %s"),
++ dev->path, strerror (errno))
++ != PED_EXCEPTION_IGNORE)
++ goto error_close_dev;
++ if (!_device_probe_geometry (dev))
++ goto error_close_dev;
++ ped_device_close (dev);
++ return 1;
++ }
++
++ ccb.ccb_h.func_code = XPT_GDEVLIST;
++ if (ioctl(pass_fd, CAMGETPASSTHRU, &ccb) != 0) {
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Could not get ID of devices %s - %s"),
++ dev->path, strerror (errno));
++ switch (ex_status) {
++ case PED_EXCEPTION_CANCEL:
++ goto error_close_fd_dev;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_IGNORE:
++ dev->host = 0;
++ dev->did = 0;
++ break;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++
++ dev->host = ccb.ccb_h.target_id;
++ dev->did = ccb.ccb_h.target_lun;
++
++ ccb.ccb_h.func_code = XPT_GDEV_TYPE;
++ if (ioctl(pass_fd, CAMIOCOMMAND, &ccb) != 0) {
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Could not get identity of device %s - %s"),
++ dev->path, strerror (errno));
++ switch (ex_status) {
++ case PED_EXCEPTION_CANCEL:
++ goto error_close_fd_dev;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_IGNORE:
++ dev->model = strdup(_("Generic SCSI"));
++ break;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ } else {
++ size_t model_length = (8 + 16 + 2);
++ dev->model = (char*) ped_malloc (model_length);
++ if (!dev->model)
++ goto error_close_fd_dev;
++ if (ccb.cgd.protocol == PROTO_ATA && *ccb.cgd.ident_data.model) {
++ snprintf (dev->model, model_length, "%s", ccb.cgd.ident_data.model);
++ arch_specific->phys_sector_size = local_ata_physical_sector_size(&ccb.cgd.ident_data);
++ } else {
++ snprintf (dev->model, model_length, "%.8s %.16s", ccb.cgd.inq_data.vendor, ccb.cgd.inq_data.product);
++ }
++ }
++
++ if (!_device_probe_geometry (dev))
++ goto error_close_fd_dev;
++
++ close (pass_fd);
++ ped_device_close (dev);
++ return 1;
++
++error_close_fd_dev:
++ close (pass_fd);
++error_close_dev:
++ ped_device_close (dev);
++error:
++ return 0;
++}
++
++static int
++init_file (PedDevice* dev)
++{
++ struct stat dev_stat;
++
++ if (!_device_stat (dev, &dev_stat))
++ goto error;
++ if (!ped_device_open (dev))
++ goto error;
++
++ if (S_ISCHR(dev_stat.st_mode))
++ dev->length = _device_get_length (dev);
++ else
++ dev->length = dev_stat.st_size / 512;
++ if (dev->length <= 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_CANCEL,
++ _("The device %s is zero-length, and can't possibly "
++ "store a file system or partition table. Perhaps "
++ "you selected the wrong device?"),
++ dev->path);
++ goto error_close_dev;
++ }
++
++ ped_device_close (dev);
++
++ dev->bios_geom.cylinders = dev->length / 4 / 32;
++ dev->bios_geom.heads = 4;
++ dev->bios_geom.sectors = 32;
++ dev->hw_geom = dev->bios_geom;
++ dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
++ dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
++ dev->model = strdup ("");
++
++ return 1;
++
++error_close_dev:
++ ped_device_close (dev);
++error:
++ return 0;
++}
++
++static int
++init_generic (PedDevice* dev, char* model_name)
++{
++ struct stat dev_stat;
++ PedExceptionOption ex_status;
++
++ if (!_device_stat (dev, &dev_stat))
++ goto error;
++
++ if (!ped_device_open (dev))
++ goto error;
++
++ ped_exception_fetch_all ();
++ if (_device_probe_geometry (dev)) {
++ ped_exception_leave_all ();
++ } else {
++ /* hack to allow use of files, for testing */
++ ped_exception_catch ();
++ ped_exception_leave_all ();
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Unable to determine geometry of "
++ "file/device. You should not use Parted "
++ "unless you REALLY know what you're doing!"));
++ switch (ex_status) {
++ case PED_EXCEPTION_CANCEL:
++ goto error_close_dev;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_IGNORE:
++ break;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++
++ /* what should we stick in here? */
++ dev->length = dev_stat.st_size / PED_SECTOR_SIZE_DEFAULT;
++ dev->bios_geom.cylinders = dev->length / 4 / 32;
++ dev->bios_geom.heads = 4;
++ dev->bios_geom.sectors = 32;
++ dev->sector_size = PED_SECTOR_SIZE_DEFAULT;
++ dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT;
++ }
++
++ dev->model = strdup (model_name);
++
++ ped_device_close (dev);
++ return 1;
++
++error_close_dev:
++ ped_device_close (dev);
++error:
++ return 0;
++}
++
++static PedDevice*
++freebsd_new (const char* path)
++{
++ PedDevice* dev;
++
++ PED_ASSERT (path != NULL);
++
++ dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
++ if (!dev)
++ goto error;
++
++ dev->path = strdup (path);
++ if (!dev->path)
++ goto error_free_dev;
++
++ dev->arch_specific
++ = (FreeBSDSpecific*) ped_malloc (sizeof (FreeBSDSpecific));
++ if (!dev->arch_specific)
++ goto error_free_path;
++
++ memset(dev->arch_specific, 0, sizeof(FreeBSDSpecific));
++
++ dev->open_count = 0;
++ dev->read_only = 0;
++ dev->external_mode = 0;
++ dev->dirty = 0;
++ dev->boot_dirty = 0;
++
++ if (!_device_probe_type (dev))
++ goto error_free_arch_specific;
++
++ switch (dev->type) {
++ case PED_DEVICE_IDE:
++ if (!init_ide (dev))
++ goto error_free_arch_specific;
++ break;
++ case PED_DEVICE_SCSI:
++ if (!init_scsi (dev))
++ goto error_free_arch_specific;
++ break;
++ case PED_DEVICE_FILE:
++ if (!init_file (dev))
++ goto error_free_arch_specific;
++ break;
++ case PED_DEVICE_UNKNOWN:
++ if (!init_generic (dev, _("Unknown")))
++ goto error_free_arch_specific;
++ break;
++
++ default:
++ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
++ PED_EXCEPTION_CANCEL,
++ _("ped_device_new() Unsupported device type"));
++ goto error_free_arch_specific;
++ }
++ return dev;
++
++error_free_arch_specific:
++ free (dev->arch_specific);
++error_free_path:
++ free (dev->path);
++error_free_dev:
++ free (dev);
++error:
++ return NULL;
++}
++
++static void
++freebsd_destroy (PedDevice* dev)
++{
++ free (dev->arch_specific);
++ free (dev->path);
++ free (dev->model);
++ free (dev);
++}
++
++static int
++freebsd_is_busy (PedDevice* dev)
++{
++ int i;
++ char* part_name;
++
++ if (_partition_is_mounted_by_path (dev->path))
++ return 1;
++
++ for (i = 0; i < 32; i++) {
++ int status;
++
++ part_name = _device_get_part_path (dev, i);
++ if (!part_name)
++ return 1;
++ status = _partition_is_mounted_by_path (part_name);
++ free (part_name);
++
++ if (status)
++ return 1;
++ }
++
++ return 0;
++}
++
++static void
++_flush_cache (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++
++ if (dev->read_only)
++ return;
++ dev->dirty = 0;
++
++ if (dev->type == PED_DEVICE_FILE) {
++ if (fsync(arch_specific->fd) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Could not flush cache of file %s - %s."),
++ dev->path,
++ strerror (errno));
++ return;
++ }
++ } else {
++ if (ioctl (arch_specific->fd, DIOCGFLUSH) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Could not flush cache of device %s - %s."),
++ dev->path,
++ strerror (errno));
++ return;
++ }
++ }
++
++ return;
++}
++
++/* By default, kernel of FreeBSD does not allow overwriting MBR */
++#define GEOM_SYSCTL "kern.geom.debugflags"
++
++static int
++freebsd_open (PedDevice* dev)
++{
++ int old_flags, flags;
++ size_t flagssize;
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++
++retry:
++ flagssize = sizeof (old_flags);
++
++ if (sysctlbyname (GEOM_SYSCTL, &old_flags, &flagssize, NULL, 0) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Unable to get %s sysctl (%s)."),
++ GEOM_SYSCTL,
++ strerror (errno));
++ }
++
++ if ((old_flags & 0x10) == 0) {
++ /* "allow foot shooting", see geom(4) */
++ flags = old_flags | 0x10;
++
++ if (sysctlbyname (GEOM_SYSCTL, NULL, NULL, &flags, sizeof (int)) != 0) {
++ flags = old_flags;
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Unable to set %s sysctl (%s)."),
++ GEOM_SYSCTL,
++ strerror (errno));
++ }
++ } else
++ flags = old_flags;
++
++ arch_specific->fd = open (dev->path, O_RDWR);
++
++ if (flags != old_flags) {
++ if (sysctlbyname (GEOM_SYSCTL, NULL, NULL, &old_flags, sizeof (int)) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Unable to set %s sysctl (%s)."),
++ GEOM_SYSCTL,
++ strerror (errno));
++ }
++ }
++
++ if (arch_specific->fd == -1) {
++ char* rw_error_msg = strerror (errno);
++
++ arch_specific->fd = open (dev->path, O_RDONLY);
++
++ if (arch_specific->fd == -1) {
++ if (ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_CANCEL,
++ _("Error opening %s: %s"),
++ dev->path, strerror (errno))
++ != PED_EXCEPTION_RETRY) {
++ return 0;
++ } else {
++ goto retry;
++ }
++ } else {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Unable to open %s read-write (%s). %s has "
++ "been opened read-only."),
++ dev->path, rw_error_msg, dev->path);
++ dev->read_only = 1;
++ }
++ } else {
++ dev->read_only = 0;
++ }
++
++ _flush_cache (dev);
++
++ return 1;
++}
++
++static int
++freebsd_refresh_open (PedDevice* dev)
++{
++ return 1;
++}
++
++static int
++freebsd_close (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++
++ if (dev->dirty)
++ _flush_cache (dev);
++ close (arch_specific->fd);
++ return 1;
++}
++
++static int
++freebsd_refresh_close (PedDevice* dev)
++{
++ if (dev->dirty)
++ _flush_cache (dev);
++ return 1;
++}
++
++static int
++_device_seek (const PedDevice* dev, PedSector sector)
++{
++ FreeBSDSpecific* arch_specific;
++ off_t pos;
++
++ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
++ PED_ASSERT (dev != NULL);
++ PED_ASSERT (!dev->external_mode);
++
++ arch_specific = FREEBSD_SPECIFIC (dev);
++
++ pos = sector * dev->sector_size;
++ return lseek (arch_specific->fd, pos, SEEK_SET) == pos;
++}
++
++static int
++freebsd_read (const PedDevice* dev, void* buffer, PedSector start,
++ PedSector count)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ PedExceptionOption ex_status;
++ void* diobuf = NULL;
++
++ PED_ASSERT (dev != NULL);
++ PED_ASSERT (dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
++
++ while (1) {
++ if (_device_seek (dev, start))
++ break;
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
++ _("%s during seek for read on %s"),
++ strerror (errno), dev->path);
++
++ switch (ex_status) {
++ case PED_EXCEPTION_IGNORE:
++ return 1;
++
++ case PED_EXCEPTION_RETRY:
++ break;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_CANCEL:
++ return 0;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++
++ size_t read_length = count * dev->sector_size;
++ if (posix_memalign (&diobuf, dev->sector_size, read_length) != 0)
++ return 0;
++
++ while (1) {
++ ssize_t status = read (arch_specific->fd, diobuf, read_length);
++ if (status > 0) {
++ memcpy(buffer, diobuf, status);
++ }
++ if (status == (ssize_t) read_length)
++ break;
++ if (status > 0) {
++ read_length -= status;
++ buffer = (char *) buffer + status;
++ continue;
++ }
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
++ _("%s during read on %s"),
++ strerror (errno),
++ dev->path);
++
++ switch (ex_status) {
++ case PED_EXCEPTION_IGNORE:
++ return 1;
++
++ case PED_EXCEPTION_RETRY:
++ break;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_CANCEL:
++ return 0;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++
++ free (diobuf);
++
++ return 1;
++}
++
++static int
++freebsd_write (PedDevice* dev, const void* buffer, PedSector start,
++ PedSector count)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ PedExceptionOption ex_status;
++ void* diobuf;
++ void* diobuf_start;
++
++ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
++
++ if (dev->read_only) {
++ if (ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_IGNORE_CANCEL,
++ _("Can't write to %s, because it is opened read-only."),
++ dev->path)
++ != PED_EXCEPTION_IGNORE)
++ return 0;
++ else
++ return 1;
++ }
++
++ while (1) {
++ if (_device_seek (dev, start))
++ break;
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL,
++ _("%s during seek for write on %s"),
++ strerror (errno), dev->path);
++
++ switch (ex_status) {
++ case PED_EXCEPTION_IGNORE:
++ return 1;
++
++ case PED_EXCEPTION_RETRY:
++ break;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_CANCEL:
++ return 0;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++
++#ifdef READ_ONLY
++ printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
++ dev->path, buffer, (int) start, (int) count);
++#else
++ size_t write_length = count * dev->sector_size;
++ dev->dirty = 1;
++ if (posix_memalign(&diobuf, dev->sector_size, write_length) != 0)
++ return 0;
++ memcpy(diobuf, buffer, write_length);
++ diobuf_start = diobuf;
++ while (1) {
++ ssize_t status = write (arch_specific->fd, diobuf, write_length);
++ if (status == count * PED_SECTOR_SIZE_DEFAULT) break;
++ if (status > 0) {
++ write_length -= status;
++ diobuf = (char *) diobuf + status;
++ continue;
++ }
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
++ _("%s during write on %s"),
++ strerror (errno), dev->path);
++
++ switch (ex_status) {
++ case PED_EXCEPTION_IGNORE:
++ return 1;
++
++ case PED_EXCEPTION_RETRY:
++ break;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_CANCEL:
++ return 0;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++ free(diobuf_start);
++#endif /* !READ_ONLY */
++ return 1;
++}
++
++/* returns the number of sectors that are ok.
++ */
++static PedSector
++freebsd_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ PedSector done = 0;
++ int status;
++ void* diobuf;
++
++ if (!_device_seek (dev, start))
++ return 0;
++
++ if (posix_memalign(&diobuf, PED_SECTOR_SIZE_DEFAULT,
++ count * PED_SECTOR_SIZE_DEFAULT) != 0)
++ return 0;
++
++ for (done = 0; done < count; done += status / dev->sector_size) {
++ status = read (arch_specific->fd, diobuf,
++ (size_t) ((count-done) * dev->sector_size));
++ if (status > 0)
++ memcpy(buffer, diobuf, status);
++ if (status < 0)
++ break;
++ }
++ free(diobuf);
++
++ return done;
++}
++
++static int
++_do_fsync (PedDevice* dev)
++{
++ FreeBSDSpecific* arch_specific = FREEBSD_SPECIFIC (dev);
++ int status;
++ PedExceptionOption ex_status;
++
++ while (1) {
++ status = fsync (arch_specific->fd);
++ if (status >= 0) break;
++
++ ex_status = ped_exception_throw (
++ PED_EXCEPTION_ERROR,
++ PED_EXCEPTION_RETRY_IGNORE_CANCEL,
++ _("%s during write on %s"),
++ strerror (errno), dev->path);
++
++ switch (ex_status) {
++ case PED_EXCEPTION_IGNORE:
++ return 1;
++
++ case PED_EXCEPTION_RETRY:
++ break;
++
++ case PED_EXCEPTION_UNHANDLED:
++ ped_exception_catch ();
++ case PED_EXCEPTION_CANCEL:
++ return 0;
++ default:
++ PED_ASSERT (0);
++ break;
++ }
++ }
++ return 1;
++}
++
++static int
++freebsd_sync (PedDevice* dev)
++{
++ PED_ASSERT (dev != NULL);
++ PED_ASSERT (!dev->external_mode);
++
++ if (dev->read_only)
++ return 1;
++ if (!_do_fsync (dev))
++ return 0;
++ _flush_cache (dev);
++ return 1;
++}
++
++static int
++freebsd_sync_fast (PedDevice* dev)
++{
++ PED_ASSERT (dev != NULL);
++ PED_ASSERT (!dev->external_mode);
++
++ if (dev->read_only)
++ return 1;
++ if (!_do_fsync (dev))
++ return 0;
++ /* no cache flush... */
++ return 1;
++}
++
++static int
++_probe_standard_devices ()
++{
++ /* Add standard devices that are not autodetected here. */
++ return 1;
++}
++
++static int
++_probe_kern_disks ()
++{
++ size_t listsize;
++ char *disklist, *pdisklist, *psave;
++
++ if (sysctlbyname("kern.disks", NULL, &listsize, NULL, 0) != 0) {
++ ped_exception_throw (
++ PED_EXCEPTION_WARNING,
++ PED_EXCEPTION_OK,
++ _("Could not get the list of devices through kern.disks sysctl."));
++ return 0;
++ }
++
++ if (listsize == 0)
++ return 0;
++
++ disklist = ped_malloc(listsize + 1);
++ if (!disklist)
++ return 0;
++
++ if (sysctlbyname("kern.disks", disklist, &listsize, NULL, 0) != 0) {
++ free(disklist);
++ return 0;
++ }
++
++ for (pdisklist = disklist ; ; pdisklist = NULL) {
++ char dev_name [256];
++ char *token;
++
++ token = strtok_r(pdisklist, " ", &psave);
++ if (token == NULL)
++ break;
++
++ strncpy (dev_name, _PATH_DEV, sizeof(dev_name));
++ strncat (dev_name, token, sizeof(dev_name) - strlen(_PATH_DEV) - 1);
++ dev_name[sizeof(dev_name) - 1] = '\0';
++ _ped_device_probe (dev_name);
++ }
++
++ free(disklist);
++ return 1;
++}
++
++static void
++freebsd_probe_all ()
++{
++ _probe_standard_devices ();
++
++ _probe_kern_disks ();
++}
++
++static char*
++_device_get_part_path (PedDevice* dev, int num)
++{
++ int path_len = strlen (dev->path);
++ int result_len = path_len + 16;
++ int is_gpt;
++ char* result;
++ PedDisk* disk;
++
++ disk = ped_disk_new (dev);
++ if (!disk)
++ return NULL;
++
++ result = (char*) ped_malloc (result_len);
++ if (!result)
++ return NULL;
++
++ is_gpt = !strcmp (disk->type->name, "gpt");
++
++ ped_disk_destroy (disk);
++
++ /* append slice number (ad0, partition 1 => ad0s1)*/
++ snprintf (result, result_len, is_gpt ? "%sp%d" : "%ss%d", dev->path, num);
++
++ return result;
++}
++
++static char*
++freebsd_partition_get_path (const PedPartition* part)
++{
++ return _device_get_part_path (part->disk->dev, part->num);
++}
++
++static int
++_partition_is_mounted_by_dev (dev_t dev)
++{
++ struct stat mntdevstat;
++ struct statfs *mntbuf, *statfsp;
++ char *devname;
++ char device[256];
++ int mntsize, i;
++
++ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
++ for (i = 0; i < mntsize; i++) {
++ statfsp = &mntbuf[i];
++ devname = statfsp->f_mntfromname;
++ if (*devname != '/') {
++ strcpy(device, _PATH_DEV);
++ strcat(device, devname);
++ strcpy(statfsp->f_mntfromname, device);
++ }
++ if (stat(devname, &mntdevstat) == 0 &&
++ mntdevstat.st_rdev == dev)
++ return 1;
++ }
++
++ return 0;
++}
++
++static int
++_partition_is_mounted_by_path (const char *path)
++{
++ struct stat part_stat;
++ if (stat (path, &part_stat) != 0)
++ return 0;
++ if (!S_ISCHR(part_stat.st_mode))
++ return 0;
++ return _partition_is_mounted_by_dev (part_stat.st_rdev);
++}
++
++static int
++_partition_is_mounted (const PedPartition *part)
++{
++ int status;
++ char* part_name;
++
++ if (!ped_partition_is_active (part))
++ return 0;
++ part_name = _device_get_part_path (part->disk->dev, part->num);
++ if (!part_name)
++ return 0;
++ status = _partition_is_mounted_by_path (part_name);
++ free (part_name);
++ return status;
++}
++
++static int
++freebsd_partition_is_busy (const PedPartition* part)
++{
++ PedPartition* walk;
++
++ PED_ASSERT (part != NULL);
++
++ if (_partition_is_mounted (part))
++ return 1;
++ if (part->type == PED_PARTITION_EXTENDED) {
++ for (walk = part->part_list; walk; walk = walk->next) {
++ if (freebsd_partition_is_busy (walk))
++ return 1;
++ }
++ }
++ return 0;
++}
++
++static int
++_kernel_reread_part_table (PedDevice* dev)
++{
++ /* The FreeBSD kernel (at least the 7.x series) automatically
++ monitors the partition tables and re-read them if they
++ change. */
++ return 1;
++}
++
++static int
++freebsd_disk_commit (PedDisk* disk)
++{
++ if (disk->dev->type != PED_DEVICE_FILE)
++ return _kernel_reread_part_table (disk->dev);
++
++ return 1;
++}
++
++static PedDeviceArchOps freebsd_dev_ops = {
++ _new: freebsd_new,
++ destroy: freebsd_destroy,
++ is_busy: freebsd_is_busy,
++ open: freebsd_open,
++ refresh_open: freebsd_refresh_open,
++ close: freebsd_close,
++ refresh_close: freebsd_refresh_close,
++ read: freebsd_read,
++ write: freebsd_write,
++ check: freebsd_check,
++ sync: freebsd_sync,
++ sync_fast: freebsd_sync_fast,
++ probe_all: freebsd_probe_all
++};
++
++PedDiskArchOps freebsd_disk_ops = {
++ partition_get_path: freebsd_partition_get_path,
++ partition_is_busy: freebsd_partition_is_busy,
++ disk_commit: freebsd_disk_commit
++};
++
++PedArchitecture ped_freebsd_arch = {
++ dev_ops: &freebsd_dev_ops,
++ disk_ops: &freebsd_disk_ops
++};
+diff --git a/libparted/architecture.c b/libparted/architecture.c
+index 4020f98b..824ece69 100644
+--- a/libparted/architecture.c
++++ b/libparted/architecture.c
+@@ -34,6 +34,9 @@ ped_set_architecture ()
+ #elif defined(__BEOS__)
+ extern PedArchitecture ped_beos_arch;
+ const PedArchitecture* arch = &ped_beos_arch;
++#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
++ extern PedArchitecture ped_freebsd_arch;
++ const PedArchitecture* arch = &ped_freebsd_arch;
+ #else
+ extern PedArchitecture ped_gnu_arch;
+ const PedArchitecture* arch = &ped_gnu_arch;
+diff --git a/libparted/fs/xfs/platform_defs.h b/libparted/fs/xfs/platform_defs.h
+index a6ec8fb8..47a3a55f 100644
+--- a/libparted/fs/xfs/platform_defs.h
++++ b/libparted/fs/xfs/platform_defs.h
+@@ -37,7 +37,11 @@
+ #include <stdio.h>
+ #include <stdarg.h>
+ #include <assert.h>
+-#include <endian.h>
++#if HAVE_ENDIAN_H
++# include <endian.h>
++#elif HAVE_SYS_ENDIAN_H
++# include <sys/endian.h>
++#endif
+ #include <fcntl.h>
+ #include <stddef.h>
+ #include <stdlib.h>
+diff --git a/libparted/labels/bsd.c b/libparted/labels/bsd.c
+index 38bc64c1..bd36babc 100644
+--- a/libparted/labels/bsd.c
++++ b/libparted/labels/bsd.c
+@@ -27,6 +27,7 @@
+ #include <parted/debug.h>
+ #include <parted/endian.h>
+ #include <stdbool.h>
++#include <sys/types.h>
+
+ #if ENABLE_NLS
+ # include <libintl.h>
+diff --git a/libparted/labels/sun.c b/libparted/labels/sun.c
+index 5ed28869..09b82cbe 100644
+--- a/libparted/labels/sun.c
++++ b/libparted/labels/sun.c
+@@ -26,6 +26,7 @@
+ #include <parted/debug.h>
+ #include <parted/endian.h>
+ #include <stdbool.h>
++#include <sys/types.h>
+
+ #if ENABLE_NLS
+ # include <libintl.h>
diff --git a/debian/patches/kfreebsd_lvm.patch b/debian/patches/kfreebsd_lvm.patch
new file mode 100644
index 0000000..145d050
--- /dev/null
+++ b/debian/patches/kfreebsd_lvm.patch
@@ -0,0 +1,55 @@
+From 10e3164ce61e959817683edf52c1f1206f82ef0c Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Fri, 28 Mar 2014 17:09:52 +0000
+Subject: Add LVM support on kFreeBSD
+
+Patch-Name: kfreebsd_lvm.patch
+---
+ libparted/arch/freebsd.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/libparted/arch/freebsd.c b/libparted/arch/freebsd.c
+index b78d2bb0..f7061c74 100644
+--- a/libparted/arch/freebsd.c
++++ b/libparted/arch/freebsd.c
+@@ -1178,6 +1178,31 @@ _probe_zfs_volumes ()
+ return 1;
+ }
+
++static int
++_probe_lvm_volumes ()
++{
++ DIR* lvm_dir;
++ struct dirent* lvm_dent;
++ char buf[PATH_MAX];
++ struct stat st;
++
++ lvm_dir = opendir ("/dev/linux_lvm");
++ if (!lvm_dir)
++ return 0;
++
++ while ((lvm_dent = readdir (lvm_dir))) {
++ if (strcmp (lvm_dent->d_name, ".") == 0 || strcmp (lvm_dent->d_name, "..") == 0)
++ continue;
++ snprintf (buf, sizeof (buf), "/dev/linux_lvm/%s", lvm_dent->d_name);
++ if (stat (buf, &st) != 0)
++ continue;
++ _ped_device_probe (buf);
++ }
++ closedir (lvm_dir);
++
++ return 1;
++}
++
+ static void
+ freebsd_probe_all ()
+ {
+@@ -1186,6 +1211,8 @@ freebsd_probe_all ()
+ _probe_kern_disks ();
+
+ _probe_zfs_volumes ();
++
++ _probe_lvm_volumes ();
+ }
+
+ static char*
diff --git a/debian/patches/link-libuuid.patch b/debian/patches/link-libuuid.patch
new file mode 100644
index 0000000..3b6e9ca
--- /dev/null
+++ b/debian/patches/link-libuuid.patch
@@ -0,0 +1,32 @@
+From e7662734df72abed3e10dcb032d3fd7284e0e868 Mon Sep 17 00:00:00 2001
+From: Yegor Yefremov <yegorslists@googlemail.com>
+Date: Thu, 11 May 2023 10:03:59 +0200
+Subject: parted: link to libuuid
+
+parted.c uses libuuid since 61b3a9733c0e0a79ccc43096642d378c8706add6.
+Hence, add UUID_LIBS to PARTED_LIBS to avoid
+"DSO missing from command line" error.
+
+Signed-off-by: Brian C. Lane <bcl@redhat.com>
+
+Origin: upstream, https://git.savannah.gnu.org/cgit/parted.git/commit/?id=d22c2d01f62139e0d386d90584cac0705857a571
+Last-Update: 2023-06-13
+
+Patch-Name: link-libuuid.patch
+---
+ configure.ac | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index d838c32c..ea614430 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -300,6 +300,8 @@ Note: originally, libuuid was part of the e2fsprogs package. Later, it
+ moved to util-linux-ng-2.16, and that package is now the preferred source.])])
+ AC_SUBST([UUID_LIBS])
+
++PARTED_LIBS="$PARTED_LIBS $UUID_LIBS"
++
+ dnl Check for libdevmapper
+ DM_LIBS=
+ if test $ENABLE_DEVICE_MAPPER = yes; then
diff --git a/debian/patches/preserve-hidden-parts.patch b/debian/patches/preserve-hidden-parts.patch
new file mode 100644
index 0000000..e70378b
--- /dev/null
+++ b/debian/patches/preserve-hidden-parts.patch
@@ -0,0 +1,45 @@
+From 028c790ccdd95ef57a0b53404a32606d2e6a84ba Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Fri, 28 Mar 2014 17:09:40 +0000
+Subject: Avoid overwriting empty or hidden partitions
+
+It changes the DOS partition rewriting code to avoid overwriting empty
+or hidden primary partitions so long as their entries aren't reused.
+This makes fatresize and similar front-ends safe to use in the presence
+of hidden partitions.
+
+Forwarded: http://lists.gnu.org/archive/html/bug-parted/2008-10/msg00005.html
+Bug-Debian: http://bugs.debian.org/491797
+Last-Update: 2010-02-02
+
+Patch-Name: preserve-hidden-parts.patch
+---
+ libparted/labels/dos.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
+index e6a01059..256f365d 100644
+--- a/libparted/labels/dos.c
++++ b/libparted/labels/dos.c
+@@ -1452,13 +1452,18 @@ msdos_write (const PedDisk* disk)
+ if (!table->mbr_signature)
+ table->mbr_signature = generate_random_uint32 ();
+
+- memset (table->partitions, 0, sizeof (table->partitions));
+- table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
++ if (table->magic != PED_CPU_TO_LE16 (MSDOS_MAGIC)) {
++ memset (table->partitions, 0, sizeof (table->partitions));
++ table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
++ }
+
+ for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
+ part = ped_disk_get_partition (disk, i);
+- if (!part)
++ if (!part) {
++ if (table->partitions [i - 1].type != PARTITION_EMPTY)
++ memset (&table->partitions [i - 1], 0, sizeof (DosRawPartition));
+ continue;
++ }
+
+ if (!fill_raw_part (&table->partitions [i - 1], part, 0))
+ goto write_fail;
diff --git a/debian/patches/probe-lvs-again.patch b/debian/patches/probe-lvs-again.patch
new file mode 100644
index 0000000..77139c0
--- /dev/null
+++ b/debian/patches/probe-lvs-again.patch
@@ -0,0 +1,34 @@
+From 20f1477293d180b2141ae7f1047ff5df84d42826 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Sat, 9 Aug 2014 16:23:26 +0200
+Subject: Probe LVM logical volumes again
+
+parted 3.2 stopped probing LVM logical volumes. This breaks
+debian-installer, which wants to be able to "partition" these, at least
+to the extent of being able to see them in the partitioner and operate
+on them somewhat like ordinary partitions. Revert to the old behaviour.
+
+Bug-Debian: http://bugs.debian.org/757417
+Forwarded: no
+Last-Update: 2014-08-11
+
+Patch-Name: probe-lvs-again.patch
+---
+ libparted/arch/linux.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
+index f6f72360..3bad1e6e 100644
+--- a/libparted/arch/linux.c
++++ b/libparted/arch/linux.c
+@@ -608,8 +608,8 @@ _probe_dm_devices ()
+ if (stat (buf, &st) != 0)
+ continue;
+
+- if (_is_dm_major(major(st.st_rdev)) && _is_dmraid_device (buf)
+- && !_dm_is_part(buf))
++ if (_is_dm_major(major(st.st_rdev))
++ && !(_is_dmraid_device(buf) && _dm_is_part(buf)))
+ _ped_device_probe (buf);
+ }
+ closedir (mapper_dir);
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..8d4f4b7
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,13 @@
+doc-package.patch
+preserve-hidden-parts.patch
+kfreebsd-gnu.patch
+freebsd-ufs.patch
+zfs.patch
+freebsd-zvol.patch
+freebsd-geli.patch
+kfreebsd_lvm.patch
+gptsync.patch
+udevadm-settle.patch
+align-new-partitions-on-fresh-disks.patch
+probe-lvs-again.patch
+link-libuuid.patch
diff --git a/debian/patches/udevadm-settle.patch b/debian/patches/udevadm-settle.patch
new file mode 100644
index 0000000..96cdbcf
--- /dev/null
+++ b/debian/patches/udevadm-settle.patch
@@ -0,0 +1,105 @@
+From 3947abeeb92069705229bff681b28d8ac78aedaa Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Fri, 28 Mar 2014 17:10:16 +0000
+Subject: udev handling
+
+Run udevadm settle around partition table rereads, to avoid races.
+
+This should be replaced by a proper completion-notification mechanism
+between the kernel and udev.
+
+Forwarded: no
+Last-Update: 2019-10-11
+
+Patch-Name: udevadm-settle.patch
+---
+ libparted/arch/linux.c | 56 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 54 insertions(+), 2 deletions(-)
+
+diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
+index ccbba865..f6f72360 100644
+--- a/libparted/arch/linux.c
++++ b/libparted/arch/linux.c
+@@ -26,6 +26,7 @@
+ #include <parted/fdasd.h>
+ #endif
+
++#include <stdlib.h>
+ #include <ctype.h>
+ #include <errno.h>
+ #include <fcntl.h>
+@@ -3250,10 +3251,52 @@ _have_blkpg ()
+ return have_blkpg = kver >= KERNEL_VERSION (2,4,0) ? 1 : 0;
+ }
+
++static int
++_chrooted ()
++{
++ static int cached = -1;
++ struct stat root, init_root;
++
++ if (cached != -1)
++ return cached;
++
++ if (stat ("/", &root) || stat ("/proc/1/root", &init_root))
++ /* We can't tell, but are unlikely to be able to tell in the
++ * future either.
++ */
++ cached = 0;
++ else if (root.st_dev == init_root.st_dev &&
++ root.st_ino == init_root.st_ino)
++ /* / has the same dev/ino as /sbin/init's root, so we're not
++ * in a chroot.
++ */
++ cached = 0;
++ else
++ /* We must be in a chroot. */
++ cached = 1;
++
++ return cached;
++}
++
+ /* Return nonzero upon success, 0 if something fails. */
+ static int
+ linux_disk_commit (PedDisk* disk)
+ {
++ int ret = 1;
++
++ /* Modern versions of udev may notice the write activity on
++ * partition devices caused by _flush_cache, and may decide to
++ * synthesise some change events as a result. These may in turn run
++ * programs that open partition devices, which will race with us
++ * trying to remove those devices. To avoid this, we need to wait
++ * until udevd has finished processing its event queue.
++ * TODO: for upstream submission, this should check whether udevadm
++ * exists on $PATH.
++ */
++ if (!_chrooted () && system ("udevadm settle") != 0) {
++ /* ignore failures */
++ }
++
+ if (disk->dev->type != PED_DEVICE_FILE) {
+
+ /* We now require BLKPG support. If this assertion fails,
+@@ -3263,10 +3306,19 @@ linux_disk_commit (PedDisk* disk)
+ assert (_have_blkpg ());
+
+ if (!_disk_sync_part_table (disk))
+- return 0;
++ ret = 0;
+ }
+
+- return 1;
++ /* Now we wait for udevd to finish creating device nodes based on
++ * the above activity, so that callers can reliably use them.
++ * TODO: for upstream submission, this should check whether udevadm
++ * exists on $PATH.
++ */
++ if (!_chrooted () && system ("udevadm settle") != 0) {
++ /* ignore failures */
++ }
++
++ return ret;
+ }
+
+ #if USE_BLKID
diff --git a/debian/patches/zfs.patch b/debian/patches/zfs.patch
new file mode 100644
index 0000000..8d0e927
--- /dev/null
+++ b/debian/patches/zfs.patch
@@ -0,0 +1,145 @@
+From a652c80f142411473d14c038e91c24ba81537f5b Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Fri, 28 Mar 2014 17:09:48 +0000
+Subject: Add ZFS support
+
+Last-Update: 2019-10-11
+
+Patch-Name: zfs.patch
+---
+ libparted/fs/Makefile.am | 3 +-
+ libparted/fs/zfs/zfs.c | 77 ++++++++++++++++++++++++++++++++++++++++
+ libparted/libparted.c | 4 +++
+ 3 files changed, 83 insertions(+), 1 deletion(-)
+ create mode 100644 libparted/fs/zfs/zfs.c
+
+diff --git a/libparted/fs/Makefile.am b/libparted/fs/Makefile.am
+index 41a60d98..1636d49f 100644
+--- a/libparted/fs/Makefile.am
++++ b/libparted/fs/Makefile.am
+@@ -52,7 +52,8 @@ libfs_la_SOURCES = \
+ xfs/platform_defs.h \
+ xfs/xfs.c \
+ xfs/xfs_sb.h \
+- xfs/xfs_types.h
++ xfs/xfs_types.h \
++ zfs/zfs.c
+
+ lib_LTLIBRARIES = libparted-fs-resize.la
+
+diff --git a/libparted/fs/zfs/zfs.c b/libparted/fs/zfs/zfs.c
+new file mode 100644
+index 00000000..47cd6773
+--- /dev/null
++++ b/libparted/fs/zfs/zfs.c
+@@ -0,0 +1,77 @@
++/*
++ libparted - a library for manipulating disk partitions
++ Copyright (C) 2000, 2007, 2009-2010 Free Software Foundation, Inc.
++
++ 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/>.
++*/
++
++#include <config.h>
++
++#include <parted/parted.h>
++#include <parted/endian.h>
++
++#if ENABLE_NLS
++# include <libintl.h>
++# define _(String) dgettext (PACKAGE, String)
++#else
++# define _(String) (String)
++#endif /* ENABLE_NLS */
++
++#include <unistd.h>
++
++#define ZFS_SIGNATURE 0x00bab10c
++
++struct zfs_uberblock
++{
++ uint64_t signature;
++ uint64_t version;
++};
++
++static PedGeometry*
++zfs_probe (PedGeometry* geom)
++{
++ struct zfs_uberblock *uber = alloca (geom->dev->sector_size);
++
++ if (!ped_geometry_read (geom, uber, 256, 1))
++ return 0;
++
++ if ((le64toh (uber->signature) == ZFS_SIGNATURE
++ || be64toh (uber->signature) == ZFS_SIGNATURE)
++ && uber->version != 0)
++ return ped_geometry_new (geom->dev, geom->start, geom->length);
++ else
++ return NULL;
++}
++
++static PedFileSystemOps zfs_ops = {
++ probe: zfs_probe,
++};
++
++static PedFileSystemType zfs_type = {
++ next: NULL,
++ ops: &zfs_ops,
++ name: "zfs",
++};
++
++void
++ped_file_system_zfs_init ()
++{
++ ped_file_system_type_register (&zfs_type);
++}
++
++void
++ped_file_system_zfs_done ()
++{
++ ped_file_system_type_unregister (&zfs_type);
++}
+diff --git a/libparted/libparted.c b/libparted/libparted.c
+index 204ce007..88e7eea2 100644
+--- a/libparted/libparted.c
++++ b/libparted/libparted.c
+@@ -115,6 +115,7 @@ extern void ped_file_system_ext2_init (void);
+ extern void ped_file_system_nilfs2_init (void);
+ extern void ped_file_system_btrfs_init (void);
+ extern void ped_file_system_udf_init (void);
++extern void ped_file_system_zfs_init (void);
+
+ static void
+ init_file_system_types ()
+@@ -133,6 +134,7 @@ init_file_system_types ()
+ ped_file_system_nilfs2_init ();
+ ped_file_system_btrfs_init ();
+ ped_file_system_udf_init ();
++ ped_file_system_zfs_init ();
+ }
+
+ extern void ped_disk_aix_done ();
+@@ -200,10 +202,12 @@ extern void ped_file_system_xfs_done (void);
+ extern void ped_file_system_amiga_done (void);
+ extern void ped_file_system_btrfs_done (void);
+ extern void ped_file_system_udf_done (void);
++extern void ped_file_system_zfs_done (void);
+
+ static void
+ done_file_system_types ()
+ {
++ ped_file_system_zfs_done ();
+ ped_file_system_nilfs2_done ();
+ ped_file_system_ext2_done ();
+ ped_file_system_f2fs_done ();