summaryrefslogtreecommitdiffstats
path: root/libparted/labels/bsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'libparted/labels/bsd.c')
-rw-r--r--libparted/labels/bsd.c654
1 files changed, 654 insertions, 0 deletions
diff --git a/libparted/labels/bsd.c b/libparted/labels/bsd.c
new file mode 100644
index 0000000..38bc64c
--- /dev/null
+++ b/libparted/labels/bsd.c
@@ -0,0 +1,654 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2007-2014, 2019-2023 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/>.
+
+ Contributor: Matt Wilson <msw@redhat.com>
+*/
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+/* struct's & #define's stolen from libfdisk, which probably came from
+ * Linux...
+ */
+
+#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
+#define BSD_MAXPARTITIONS 8
+#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
+
+#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
+#define BSD_DTYPE_MSCP 2 /* MSCP */
+#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
+#define BSD_DTYPE_SCSI 4 /* SCSI */
+#define BSD_DTYPE_ESDI 5 /* ESDI interface */
+#define BSD_DTYPE_ST506 6 /* ST506 etc. */
+#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
+#define BSD_DTYPE_FLOPPY 10 /* floppy */
+
+#define BSD_BBSIZE 8192 /* size of boot area, with label */
+#define BSD_SBSIZE 8192 /* max size of fs superblock */
+
+typedef struct _BSDRawPartition BSDRawPartition;
+typedef struct _BSDRawLabel BSDRawLabel;
+typedef struct _BSDDiskData BSDDiskData;
+
+struct _BSDRawPartition { /* the partition table */
+ uint32_t p_size; /* number of sectors in partition */
+ uint32_t p_offset; /* starting sector */
+ uint32_t p_fsize; /* file system basic fragment size */
+ uint8_t p_fstype; /* file system type, see below */
+ uint8_t p_frag; /* file system fragments per block */
+ uint16_t p_cpg; /* file system cylinders per group */
+} __attribute__((packed));
+
+struct _BSDRawLabel {
+ uint32_t d_magic; /* the magic number */
+ int16_t d_type; /* drive type */
+ int16_t d_subtype; /* controller/d_type specific */
+ int8_t d_typename[16]; /* type name, e.g. "eagle" */
+ int8_t d_packname[16]; /* pack identifier */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_ncylinders; /* # of data cylinders per unit */
+ uint32_t d_secpercyl; /* # of data sectors per cylinder */
+ uint32_t d_secperunit; /* # of data sectors per unit */
+ uint16_t d_sparespertrack; /* # of spare sectors per track */
+ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
+ uint32_t d_acylinders; /* # of alt. cylinders per unit */
+ uint16_t d_rpm; /* rotational speed */
+ uint16_t d_interleave; /* hardware sector interleave */
+ uint16_t d_trackskew; /* sector 0 skew, per track */
+ uint16_t d_cylskew; /* sector 0 skew, per cylinder */
+ uint32_t d_headswitch; /* head switch time, usec */
+ uint32_t d_trkseek; /* track-to-track seek, usec */
+ uint32_t d_flags; /* generic flags */
+#define NDDATA 5
+ uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ uint32_t d_spare[NSPARE]; /* reserved for future use */
+ uint32_t d_magic2; /* the magic number (again) */
+ uint16_t d_checksum; /* xor of data incl. partitions */
+
+ /* file system and partition information: */
+ uint16_t d_npartitions; /* number of partitions in following */
+ uint32_t d_bbsize; /* size of boot area at sn0, bytes */
+ uint32_t d_sbsize; /* max size of fs superblock, bytes */
+#define D_PARTITIONS_WORDS 59
+ BSDRawPartition d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+} __attribute__((packed, aligned(2)));
+
+struct _BSDDiskData {
+ char boot_code[64];
+ BSDRawLabel label; /* label is offset by 64 bytes */
+ char unused[172]; /* May contain more partitions */
+} __attribute__((packed, aligned(2)));
+
+typedef struct {
+ uint8_t type;
+ int boot;
+ int raid;
+ int lvm;
+} BSDPartitionData;
+
+static PedDiskType bsd_disk_type;
+
+/* XXX fixme: endian? */
+static unsigned short
+xbsd_dkcksum (BSDRawLabel *lp) {
+ const u_short* word = (u_short*)(lp);
+ const u_short* end = word + D_PARTITIONS_WORDS + PED_LE16_TO_CPU(lp->d_npartitions);
+ u_short sum;
+
+ lp->d_checksum = 0;
+ for(sum=0; word < end; word++)
+ sum ^= PED_LE16_TO_CPU(*word);
+ return sum;
+}
+
+/* XXX fixme: endian? */
+static void
+alpha_bootblock_checksum (void *boot) {
+ uint64_t* dp = (uint64_t *)boot;
+ uint64_t sum=0;
+ int i;
+
+ for (i = 0; i < 63; i++)
+ sum += dp[i];
+ dp[63] = sum;
+}
+
+static int
+bsd_probe (const PedDevice *dev)
+{
+ BSDRawLabel *label;
+
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size < 512)
+ return 0;
+
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+
+ label = &((BSDDiskData*) s0)->label;
+
+ /* check magic */
+ bool found = PED_LE32_TO_CPU (label->d_magic) == BSD_DISKMAGIC;
+ free (s0);
+ return found;
+}
+
+static PedDisk*
+bsd_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ BSDDiskData* bsd_specific;
+ BSDRawLabel *label;
+
+ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type);
+ if (!disk)
+ goto error;
+ disk->disk_specific = bsd_specific = ped_calloc (sizeof (BSDDiskData));
+ if (!bsd_specific)
+ goto error_free_disk;
+
+ /* Initialize the disk label's default values */
+ label = &bsd_specific->label;
+ label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
+ label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
+ label->d_flags = 0;
+ label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size);
+ label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
+ label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
+ label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
+ label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
+ * dev->bios_geom.heads);
+ label->d_secperunit
+ = PED_CPU_TO_LE32 (dev->bios_geom.sectors
+ * dev->bios_geom.heads
+ * dev->bios_geom.cylinders);
+
+ label->d_rpm = PED_CPU_TO_LE16 (3600);
+ label->d_interleave = PED_CPU_TO_LE16 (1);
+ label->d_trackskew = 0;
+ label->d_cylskew = 0;
+ label->d_headswitch = 0;
+ label->d_trkseek = 0;
+
+ label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
+ label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
+ label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
+
+ label->d_npartitions = 0;
+ label->d_checksum = xbsd_dkcksum (label);
+
+ return disk;
+
+error_free_disk:
+ free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk*
+bsd_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ BSDDiskData* new_bsd_data;
+ BSDDiskData* old_bsd_data = (BSDDiskData*) disk->disk_specific;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
+ memcpy (new_bsd_data, old_bsd_data, sizeof(BSDDiskData));
+ return new_disk;
+}
+
+static void
+bsd_free (PedDisk* disk)
+{
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+static int
+bsd_read (PedDisk* disk)
+{
+ BSDDiskData* bsd_specific = (BSDDiskData*) disk->disk_specific;
+ BSDRawLabel* label;
+ int i;
+
+ ped_disk_delete_all (disk);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return 0;
+
+ memcpy (bsd_specific, s0, sizeof (BSDDiskData));
+ free (s0);
+
+ label = &bsd_specific->label;
+
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ PedPartition* part;
+ BSDPartitionData* bsd_part_data;
+ PedSector start;
+ PedSector end;
+
+ if (!label->d_partitions[i - 1].p_size
+ || !label->d_partitions[i - 1].p_fstype)
+ continue;
+ start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
+ end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
+ + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, start, end);
+ if (!part)
+ goto error;
+ bsd_part_data = part->disk_specific;
+ bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
+ part->num = i;
+ part->fs_type = ped_file_system_probe (&part->geom);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ if (constraint_exact == NULL)
+ goto error;
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok)
+ goto error;
+ }
+
+ return 1;
+
+error:
+ return 0;
+}
+
+static void
+_probe_and_add_boot_code (const PedDisk* disk)
+{
+ BSDDiskData *old_data;
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return;
+ old_data = (BSDDiskData*) s0;
+ if (old_data->boot_code [0]
+ && old_data->label.d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC)) {
+ BSDDiskData *bsd_specific = (BSDDiskData*) disk->disk_specific;
+ memcpy (bsd_specific, old_data, sizeof (BSDDiskData));
+ }
+ free (s0);
+}
+
+#ifndef DISCOVER_ONLY
+static int
+bsd_write (const PedDisk* disk)
+{
+ BSDDiskData* bsd_specific;
+ BSDRawLabel* label;
+ BSDPartitionData* bsd_data;
+ PedPartition* part;
+ int i;
+ int max_part = 0;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ bsd_specific = (BSDDiskData*) disk->disk_specific;
+ label = &bsd_specific->label;
+
+ if (!bsd_specific->boot_code[0])
+ _probe_and_add_boot_code (disk);
+
+ memset (label->d_partitions, 0,
+ sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);
+
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ part = ped_disk_get_partition (disk, i);
+ if (!part)
+ continue;
+ bsd_data = part->disk_specific;
+ label->d_partitions[i - 1].p_fstype = bsd_data->type;
+ label->d_partitions[i - 1].p_offset
+ = PED_CPU_TO_LE32 (part->geom.start);
+ label->d_partitions[i - 1].p_size
+ = PED_CPU_TO_LE32 (part->geom.length);
+ max_part = i;
+ }
+
+ label->d_npartitions = PED_CPU_TO_LE16 (max_part + 1);
+ label->d_checksum = xbsd_dkcksum (label);
+
+ alpha_bootblock_checksum (bsd_specific);
+
+ if (!ptt_write_sector (disk, bsd_specific,
+ sizeof (BSDDiskData)))
+ goto error;
+ return ped_device_sync (disk->dev);
+
+error:
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ BSDPartitionData* bsd_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = bsd_data = ped_malloc (sizeof (BSDPartitionData));
+ if (!bsd_data)
+ goto error_free_part;
+ bsd_data->type = 0;
+ bsd_data->boot = 0;
+ bsd_data->raid = 0;
+ bsd_data->lvm = 0;
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return 0;
+}
+
+static PedPartition*
+bsd_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ BSDPartitionData* new_bsd_data;
+ BSDPartitionData* old_bsd_data;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_bsd_data = (BSDPartitionData*) part->disk_specific;
+ new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
+ new_bsd_data->type = old_bsd_data->type;
+ new_bsd_data->boot = old_bsd_data->boot;
+ new_bsd_data->raid = old_bsd_data->raid;
+ new_bsd_data->lvm = old_bsd_data->lvm;
+ return new_part;
+}
+
+static void
+bsd_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part))
+ free (part->disk_specific);
+ _ped_partition_free (part);
+}
+
+static int
+bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ BSDPartitionData* bsd_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ if (!fs_type)
+ bsd_data->type = 0x8;
+ else if (is_linux_swap (fs_type->name))
+ bsd_data->type = 0x1;
+ else
+ bsd_data->type = 0x8;
+
+ return 1;
+}
+
+static int
+bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ BSDPartitionData* bsd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ bsd_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ bsd_data->boot = state;
+ return 1;
+ case PED_PARTITION_RAID:
+ if (state) {
+ bsd_data->lvm = 0;
+ }
+ bsd_data->raid = state;
+ return 1;
+ case PED_PARTITION_LVM:
+ if (state) {
+ bsd_data->raid = 0;
+ }
+ bsd_data->lvm = state;
+ return 1;
+ default:
+ ;
+ }
+ return 0;
+}
+
+static int _GL_ATTRIBUTE_PURE
+bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ BSDPartitionData* bsd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ bsd_data = part->disk_specific;
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ return bsd_data->boot;
+
+ case PED_PARTITION_RAID:
+ return bsd_data->raid;
+
+ case PED_PARTITION_LVM:
+ return bsd_data->lvm;
+
+ default:
+ ;
+ }
+ return 0;
+}
+
+static int
+bsd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ case PED_PARTITION_RAID:
+ case PED_PARTITION_LVM:
+ return 1;
+ default:
+ ;
+ }
+ return 0;
+}
+
+
+static int
+bsd_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return BSD_MAXPARTITIONS;
+}
+
+static bool
+bsd_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
+{
+ *max_n = BSD_MAXPARTITIONS;
+ return true;
+}
+
+static PedConstraint*
+_get_constraint (const PedDevice* dev)
+{
+ PedGeometry max;
+
+ ped_geometry_init (&max, dev, 1, dev->length - 1);
+ return ped_constraint_new_from_max (&max);
+}
+
+static int
+bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ if (_ped_partition_attempt_align (part, constraint,
+ _get_constraint (part->disk->dev)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+bsd_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number */
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a bsd disklabel slot."));
+#endif
+ return 0;
+}
+
+static int
+bsd_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* allocate 1 sector for the disk label at the start */
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (bsd)
+
+static PedDiskOps bsd_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (bsd_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (bsd)
+};
+
+static PedDiskType bsd_disk_type = {
+ next: NULL,
+ name: "bsd",
+ ops: &bsd_disk_ops,
+ features: 0
+};
+
+void
+ped_disk_bsd_init ()
+{
+ PED_ASSERT (sizeof (BSDRawPartition) == 16);
+ PED_ASSERT (sizeof (BSDRawLabel) == 276);
+
+ ped_disk_type_register (&bsd_disk_type);
+}
+
+void
+ped_disk_bsd_done ()
+{
+ ped_disk_type_unregister (&bsd_disk_type);
+}