diff options
Diffstat (limited to '')
-rw-r--r-- | libparted/labels/bsd.c | 654 |
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); +} |