diff options
Diffstat (limited to '')
-rw-r--r-- | libparted/labels/sun.c | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/libparted/labels/sun.c b/libparted/labels/sun.c new file mode 100644 index 0000000..5ed2886 --- /dev/null +++ b/libparted/labels/sun.c @@ -0,0 +1,910 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + + libparted - a library for manipulating disk partitions + Copyright (C) 2000-2001, 2005, 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: Ben Collins <bcollins@debian.org> +*/ + +#include <config.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" +#include "verify.h" + +/* Most of this came from util-linux's sun support, which was mostly done + by Jakub Jelinek. */ + +#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */ +#define SUN_DISK_MAXPARTITIONS 8 + +#define SUN_VTOC_VERSION 1 +#define SUN_VTOC_SANITY 0x600DDEEE + +#define WHOLE_DISK_ID 0x05 +#define WHOLE_DISK_PART 2 /* as in 0, 1, 2 (3rd partition) */ +#define LINUX_SWAP_ID 0x82 + +typedef struct _SunRawPartition SunRawPartition; +typedef struct _SunPartitionInfo SunPartitionInfo; +typedef struct _SunRawLabel SunRawLabel; +typedef struct _SunPartitionData SunPartitionData; +typedef struct _SunDiskData SunDiskData; + +struct __attribute__ ((packed)) _SunRawPartition { + u_int32_t start_cylinder; /* where the part starts... */ + u_int32_t num_sectors; /* ...and it's length */ +}; + +struct __attribute__ ((packed)) _SunPartitionInfo { + u_int8_t spare1; + u_int8_t id; /* Partition type */ + u_int8_t spare2; + u_int8_t flags; /* Partition flags */ +}; + +struct __attribute__ ((packed, aligned(2))) _SunRawLabel { + char info[128]; /* Informative text string */ + u_int32_t version; /* Layout version */ + u_int8_t volume[8]; /* Volume name */ + u_int16_t nparts; /* Number of partitions */ + SunPartitionInfo infos[SUN_DISK_MAXPARTITIONS]; + u_int16_t padding; /* Alignment padding */ + u_int32_t bootinfo[3]; /* Info needed by mboot */ + u_int32_t sanity; /* To verify vtoc sanity */ + u_int32_t reserved[10]; /* Free space */ + u_int32_t timestamp[8]; /* Partition timestamp */ + u_int32_t write_reinstruct; /* sectors to skip, writes */ + u_int32_t read_reinstruct; /* sectors to skip, reads */ + u_int8_t spare1[148]; /* Padding */ + u_int16_t rspeed; /* Disk rotational speed */ + u_int16_t pcylcount; /* Physical cylinder count */ + u_int16_t sparecyl; /* extra sects per cylinder */ + u_int8_t spare2[4]; /* More magic... */ + u_int16_t ilfact; /* Interleave factor */ + u_int16_t ncyl; /* Data cylinder count */ + u_int16_t nacyl; /* Alt. cylinder count */ + u_int16_t ntrks; /* Tracks per cylinder */ + u_int16_t nsect; /* Sectors per track */ + u_int8_t spare3[4]; /* Even more magic... */ + SunRawPartition partitions[SUN_DISK_MAXPARTITIONS]; + u_int16_t magic; /* Magic number */ + u_int16_t csum; /* Label xor'd checksum */ +}; + +struct _SunPartitionData { + u_int8_t type; + int is_boot; + int is_root; + int is_lvm; + int is_raid; +}; + +struct _SunDiskData { + PedSector length; /* This is based on cyl - alt-cyl */ + SunRawLabel raw_label; +}; + +static PedDiskType sun_disk_type; + +/* Checksum computation */ +static void +sun_compute_checksum (SunRawLabel *label) +{ + u_int16_t *ush = (u_int16_t *)label; + u_int16_t csum = 0; + + while(ush < (u_int16_t *)(&label->csum)) + csum ^= *ush++; + label->csum = csum; +} + +/* Checksum Verification */ +static int +sun_verify_checksum (SunRawLabel const *label) +{ + u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1; + u_int16_t csum = 0; + + while (ush >= (u_int16_t *)label) + csum ^= *ush--; + + return !csum; +} + +static int +sun_probe (const PedDevice *dev) +{ + PED_ASSERT (dev != NULL); + + void *s0; + if (!ptt_read_sector (dev, 0, &s0)) + return 0; + SunRawLabel const *label = (void const *) s0; + + int ok = 1; + /* check magic */ + if (PED_BE16_TO_CPU (label->magic) != SUN_DISK_MAGIC) { + ok = 0; + } else { +#ifndef DISCOVER_ONLY + if (!sun_verify_checksum(label)) { + ok = 0; + ped_exception_throw ( + PED_EXCEPTION_ERROR, + PED_EXCEPTION_CANCEL, + _("Corrupted Sun disk label detected.")); + } + } +#endif + + free (s0); + return ok; +} + +static PedDisk* +sun_alloc (const PedDevice* dev) +{ + PedDisk* disk; + SunRawLabel* label; + SunDiskData* sun_specific; + const PedCHSGeometry* bios_geom = &dev->bios_geom; + PedSector cyl_size = bios_geom->sectors * bios_geom->heads; + PED_ASSERT (cyl_size != 0); + + disk = _ped_disk_alloc (dev, &sun_disk_type); + if (!disk) + goto error; + + disk->disk_specific = (SunDiskData*) ped_malloc (sizeof (SunDiskData)); + if (!disk->disk_specific) + goto error_free_disk; + sun_specific = (SunDiskData*) disk->disk_specific; + + PED_ASSERT (bios_geom->cylinders == (PedSector) (dev->length / cyl_size)); + sun_specific->length = ped_round_down_to (dev->length, cyl_size); + + label = &sun_specific->raw_label; + memset(label, 0, sizeof(SunRawLabel)); + + /* #gentoo-sparc people agree that nacyl = 0 is the best option */ + label->magic = PED_CPU_TO_BE16 (SUN_DISK_MAGIC); + label->nacyl = 0; + label->pcylcount = PED_CPU_TO_BE16 (bios_geom->cylinders); + label->rspeed = PED_CPU_TO_BE16 (5400); + label->ilfact = PED_CPU_TO_BE16 (1); + label->sparecyl = 0; + label->ntrks = PED_CPU_TO_BE16 (bios_geom->heads); + label->nsect = PED_CPU_TO_BE16 (bios_geom->sectors); + label->ncyl = PED_CPU_TO_BE16 (dev->length / cyl_size); + + label->sanity = PED_CPU_TO_BE32 (SUN_VTOC_SANITY); + label->version = PED_CPU_TO_BE32 (SUN_VTOC_VERSION); + label->nparts = PED_CPU_TO_BE16 (SUN_DISK_MAXPARTITIONS); + + /* Add a whole disk partition at a minimum */ + label->infos[WHOLE_DISK_PART].id = WHOLE_DISK_ID; + label->partitions[WHOLE_DISK_PART].start_cylinder = 0; + label->partitions[WHOLE_DISK_PART].num_sectors = + PED_CPU_TO_BE32(sun_specific->length); + + /* Now a neato string to describe this label */ + snprintf(label->info, sizeof(label->info) - 1, + "GNU Parted Custom cyl %d alt %d hd %d sec %d", + PED_BE16_TO_CPU(label->ncyl), + PED_BE16_TO_CPU(label->nacyl), + PED_BE16_TO_CPU(label->ntrks), + PED_BE16_TO_CPU(label->nsect)); + + sun_compute_checksum(label); + return disk; + +error_free_disk: + _ped_disk_free (disk); +error: + return NULL; +} + +static PedDisk* +sun_duplicate (const PedDisk* disk) +{ + PedDisk* new_disk; + SunDiskData* new_sun_data; + SunDiskData* old_sun_data = (SunDiskData*) disk->disk_specific; + + new_disk = ped_disk_new_fresh (disk->dev, &sun_disk_type); + if (!new_disk) + return NULL; + + new_sun_data = (SunDiskData*) new_disk->disk_specific; + memcpy (new_sun_data, old_sun_data, sizeof (SunDiskData)); + return new_disk; +} + +static void +sun_free (PedDisk *disk) +{ + free (disk->disk_specific); + _ped_disk_free (disk); +} + +static int +_check_geometry_sanity (PedDisk* disk, SunRawLabel* label) +{ + PedDevice* dev = disk->dev; + + if (PED_BE16_TO_CPU(label->nsect) == dev->hw_geom.sectors && + PED_BE16_TO_CPU(label->ntrks) == dev->hw_geom.heads) + dev->bios_geom = dev->hw_geom; + + if (!!PED_BE16_TO_CPU(label->pcylcount) + * !!PED_BE16_TO_CPU(label->ntrks) + * !!PED_BE16_TO_CPU(label->nsect) == 0) + return 0; + + if (PED_BE16_TO_CPU(label->nsect) != dev->bios_geom.sectors || + PED_BE16_TO_CPU(label->ntrks) != dev->bios_geom.heads) { +#ifndef DISCOVER_ONLY + if (ped_exception_throw ( + PED_EXCEPTION_WARNING, + PED_EXCEPTION_IGNORE_CANCEL, + _("The disk CHS geometry (%d,%d,%d) reported " + "by the operating system does not match " + "the geometry stored on the disk label " + "(%d,%d,%d)."), + dev->bios_geom.cylinders, + dev->bios_geom.heads, + dev->bios_geom.sectors, + PED_BE16_TO_CPU(label->pcylcount), + PED_BE16_TO_CPU(label->ntrks), + PED_BE16_TO_CPU(label->nsect)) + == PED_EXCEPTION_CANCEL) + return 0; +#endif + dev->bios_geom.sectors = PED_BE16_TO_CPU(label->nsect); + dev->bios_geom.heads = PED_BE16_TO_CPU(label->ntrks); + dev->bios_geom.cylinders = PED_BE16_TO_CPU(label->pcylcount); + + if (dev->bios_geom.sectors * dev->bios_geom.heads + * dev->bios_geom.cylinders > dev->length) { + if (ped_exception_throw ( + PED_EXCEPTION_WARNING, + PED_EXCEPTION_IGNORE_CANCEL, + _("The disk label describes a disk bigger than " + "%s."), + dev->path) + != PED_EXCEPTION_IGNORE) + return 0; + } + } + return 1; +} + +static int +sun_read (PedDisk* disk) +{ + SunPartitionData* sun_data; + SunDiskData* disk_data; + int i; + PedPartition* part; + PedSector end, start, block; + + PED_ASSERT (disk != NULL); + PED_ASSERT (disk->dev != NULL); + PED_ASSERT (disk->disk_specific != NULL); + + disk_data = (SunDiskData*) disk->disk_specific; + + ped_disk_delete_all (disk); + + void *s0; + if (!ptt_read_sector (disk->dev, 0, &s0)) + goto error; + + SunRawLabel *label = &disk_data->raw_label; + verify (sizeof (*label) == 512); + memcpy (label, s0, sizeof (*label)); + free (s0); + + if (!_check_geometry_sanity (disk, label)) + goto error; + + block = disk->dev->bios_geom.sectors * disk->dev->bios_geom.heads; + disk_data->length = block * disk->dev->bios_geom.cylinders; + + for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { + if (!PED_BE32_TO_CPU(label->partitions[i].num_sectors)) + continue; + if (!label->infos[i].id) + continue; + if (label->infos[i].id == WHOLE_DISK_ID) + continue; + + start = PED_BE32_TO_CPU(label->partitions[i].start_cylinder) + * block; + end = start + + PED_BE32_TO_CPU(label->partitions[i].num_sectors) - 1; + + part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL, + start, end); + if (!part) + goto error; + + sun_data = part->disk_specific; + sun_data->type = label->infos[i].id; + sun_data->is_boot = sun_data->type == 0x1; + sun_data->is_root = sun_data->type == 0x2; + sun_data->is_lvm = sun_data->type == 0x8e; + sun_data->is_raid = sun_data->type == 0xfd; + + part->num = i + 1; + 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; +} + +#ifndef DISCOVER_ONLY +static int +_use_old_info (const PedDisk* disk, const void *sector_0) +{ + SunRawLabel const *old_label = sector_0; + + if (old_label->info[0] + && PED_BE16_TO_CPU (old_label->magic) == SUN_DISK_MAGIC) { + SunDiskData *sun_specific = disk->disk_specific; + memcpy (&sun_specific->raw_label, sector_0, + sizeof (sun_specific->raw_label)); + verify (sizeof (sun_specific->raw_label) == 512); + } + + return 1; +} + +static int +sun_write (const PedDisk* disk) +{ + SunRawLabel* label; + SunPartitionData* sun_data; + SunDiskData* disk_data; + PedPartition* part; + int i; + + PED_ASSERT (disk != NULL); + PED_ASSERT (disk->dev != NULL); + + void *s0; + if (!ptt_read_sector (disk->dev, 0, &s0)) + return 0; + + /* Calling _use_old_info here in sun_write + above seems wrong, because it modifies *DISK. + FIXME: maybe later. */ + if (!_use_old_info (disk, s0)) { + free (s0); + return 0; + } + + disk_data = (SunDiskData*) disk->disk_specific; + label = &disk_data->raw_label; + + memset (label->partitions, 0, + sizeof (SunRawPartition) * SUN_DISK_MAXPARTITIONS); + memset (label->infos, 0, + sizeof (SunPartitionInfo) * SUN_DISK_MAXPARTITIONS); + + for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) { + part = ped_disk_get_partition (disk, i + 1); + + if (!part && i == WHOLE_DISK_PART) { + /* Ok, nothing explicitly in the whole disk + partition, so let's put it there for safety + sake. */ + + label->infos[i].id = WHOLE_DISK_ID; + label->partitions[i].start_cylinder = 0; + label->partitions[i].num_sectors = + PED_CPU_TO_BE32(disk_data->length); + continue; + } + if (!part) + continue; + + sun_data = part->disk_specific; + label->infos[i].id = sun_data->type; + label->partitions[i].start_cylinder + = PED_CPU_TO_BE32 (part->geom.start + / (disk->dev->bios_geom.sectors + * disk->dev->bios_geom.heads)); + label->partitions[i].num_sectors + = PED_CPU_TO_BE32 (part->geom.end + - part->geom.start + 1); + } + + /* We assume the harddrive is always right, and that the label may + be wrong. I don't think this will cause any problems, since the + cylinder count is always enforced by our alignment, and we + sanity checked the sectors/heads when we detected the device. The + worst that could happen here is that the drive seems bigger or + smaller than it really is, but we'll have that problem even if we + don't do this. */ + + if (disk->dev->bios_geom.cylinders > 65536) { + ped_exception_throw ( + PED_EXCEPTION_WARNING, + PED_EXCEPTION_IGNORE, + _("The disk has %d cylinders, which is greater than " + "the maximum of 65536."), + disk->dev->bios_geom.cylinders); + } + + label->pcylcount = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders); + label->ncyl = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders + - PED_BE16_TO_CPU (label->nacyl)); + + sun_compute_checksum (label); + + verify (sizeof *label == 512); + memcpy (s0, label, sizeof *label); + int write_ok = ped_device_write (disk->dev, s0, 0, 1); + free (s0); + + if (write_ok) + return ped_device_sync (disk->dev); + + return 0; +} +#endif /* !DISCOVER_ONLY */ + +static PedPartition* +sun_partition_new (const PedDisk* disk, PedPartitionType part_type, + const PedFileSystemType* fs_type, + PedSector start, PedSector end) +{ + PedPartition* part; + SunPartitionData* sun_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 + = sun_data = ped_malloc (sizeof (SunPartitionData)); + if (!sun_data) + goto error_free_part; + sun_data->type = 0; + sun_data->is_boot = 0; + sun_data->is_root = 0; + sun_data->is_lvm = 0; + sun_data->is_raid = 0; + } else { + part->disk_specific = NULL; + } + + return part; + +error_free_part: + free (part); +error: + return NULL; +} + +static PedPartition* +sun_partition_duplicate (const PedPartition* part) +{ + PedPartition* new_part; + SunPartitionData* new_sun_data; + SunPartitionData* old_sun_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_sun_data = (SunPartitionData*) part->disk_specific; + new_sun_data = (SunPartitionData*) new_part->disk_specific; + new_sun_data->type = old_sun_data->type; + new_sun_data->is_boot = old_sun_data->is_boot; + new_sun_data->is_root = old_sun_data->is_root; + new_sun_data->is_lvm = old_sun_data->is_lvm; + new_sun_data->is_raid = old_sun_data->is_raid; + return new_part; +} + +static void +sun_partition_destroy (PedPartition* part) +{ + PED_ASSERT (part != NULL); + + if (ped_partition_is_active (part)) + free (part->disk_specific); + free (part); +} + +static int +sun_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) +{ + SunPartitionData* sun_data = part->disk_specific; + + part->fs_type = fs_type; + + if (sun_data->is_boot) { + sun_data->type = 0x1; + return 1; + } + if (sun_data->is_root) { + sun_data->type = 0x2; + return 1; + } + if (sun_data->is_lvm) { + sun_data->type = 0x8e; + return 1; + } + if (sun_data->is_raid) { + sun_data->type = 0xfd; + return 1; + } + + sun_data->type = 0x83; + if (fs_type) { + if (is_linux_swap (fs_type->name)) + sun_data->type = 0x82; + else if (!strcmp (fs_type->name, "ufs")) + sun_data->type = 0x6; + } + + return 1; +} + +static int +sun_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) +{ + SunPartitionData* sun_data; + + PED_ASSERT (part != NULL); + PED_ASSERT (part->disk_specific != NULL); + PED_ASSERT (ped_partition_is_flag_available (part, flag)); + + sun_data = part->disk_specific; + + switch (flag) { + case PED_PARTITION_BOOT: + sun_data->is_boot = state; + if (state) { + sun_data->is_lvm = 0; + sun_data->is_raid = 0; + sun_data->is_root = 0; + } + return ped_partition_set_system (part, part->fs_type); + + case PED_PARTITION_ROOT: + sun_data->is_root = state; + if (state) { + sun_data->is_boot = 0; + sun_data->is_lvm = 0; + sun_data->is_raid = 0; + } + return ped_partition_set_system (part, part->fs_type); + + case PED_PARTITION_LVM: + sun_data->is_lvm = state; + if (state) { + sun_data->is_boot = 0; + sun_data->is_raid = 0; + sun_data->is_root = 0; + } + return ped_partition_set_system (part, part->fs_type); + + case PED_PARTITION_RAID: + sun_data->is_raid = state; + if (state) { + sun_data->is_boot = 0; + sun_data->is_lvm = 0; + sun_data->is_root = 0; + } + return ped_partition_set_system (part, part->fs_type); + + default: + return 0; + } +} + + +static int _GL_ATTRIBUTE_PURE +sun_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) +{ + SunPartitionData* sun_data; + + PED_ASSERT (part != NULL); + PED_ASSERT (part->disk_specific != NULL); + + sun_data = part->disk_specific; + + switch (flag) { + case PED_PARTITION_BOOT: + return sun_data->is_boot; + case PED_PARTITION_ROOT: + return sun_data->is_root; + case PED_PARTITION_LVM: + return sun_data->is_lvm; + case PED_PARTITION_RAID: + return sun_data->is_raid; + + default: + return 0; + } +} + + +static int +sun_partition_is_flag_available (const PedPartition* part, + PedPartitionFlag flag) +{ + switch (flag) { + case PED_PARTITION_BOOT: + case PED_PARTITION_ROOT: + case PED_PARTITION_LVM: + case PED_PARTITION_RAID: + return 1; + + default: + return 0; + } +} + +static bool +sun_get_max_supported_partition_count (const PedDisk* disk, int *max_n) +{ + *max_n = SUN_DISK_MAXPARTITIONS; + return true; +} + +static int +sun_get_max_primary_partition_count (const PedDisk* disk) +{ + return SUN_DISK_MAXPARTITIONS; +} + +static PedAlignment* +sun_get_partition_alignment(const PedDisk *disk) +{ + PedSector block = + disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads; + + return ped_alignment_new(0, block); +} + +static PedConstraint* +_get_strict_constraint (PedDisk* disk) +{ + PedDevice* dev = disk->dev; + PedAlignment start_align; + PedAlignment end_align; + PedGeometry max_geom; + SunDiskData* disk_data = disk->disk_specific; + PedSector block = dev->bios_geom.sectors * dev->bios_geom.heads; + + if (!ped_alignment_init (&start_align, 0, block)) + return NULL; + if (!ped_alignment_init (&end_align, -1, block)) + return NULL; + if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length)) + return NULL; + + return ped_constraint_new (&start_align, &end_align, &max_geom, + &max_geom, 1, dev->length); +} + +static PedConstraint* +_get_lax_constraint (PedDisk* disk) +{ + PedDevice* dev = disk->dev; + PedAlignment start_align; + PedGeometry max_geom; + SunDiskData* disk_data = disk->disk_specific; + PedSector block = dev->bios_geom.sectors * dev->bios_geom.heads; + + if (!ped_alignment_init (&start_align, 0, block)) + return NULL; + if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length)) + return NULL; + + return ped_constraint_new (&start_align, ped_alignment_any, &max_geom, + &max_geom, 1, dev->length); +} + +/* _get_strict_constraint() will align the partition to the end of the cylinder. + * This isn't required, but since partitions must start at the start of the + * cylinder, space between the end of a partition and the end of a cylinder + * is unusable, so there's no point wasting space! + * However, if they really insist (via constraint)... which they will + * if they're reading a weird table of the disk... then we allow the end to + * be anywhere, with _get_lax_constraint() + */ +static int +sun_partition_align (PedPartition* part, const PedConstraint* constraint) +{ + PED_ASSERT (part != NULL); + + if (_ped_partition_attempt_align (part, constraint, + _get_strict_constraint (part->disk))) + return 1; + if (_ped_partition_attempt_align (part, constraint, + _get_lax_constraint (part->disk))) + 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 +sun_partition_enumerate (PedPartition* part) +{ + int i; + PedPartition* p; + + /* never change the partition numbers */ + if (part->num != -1) + return 1; + for (i = 1; i <= SUN_DISK_MAXPARTITIONS; i++) { + /* skip the Whole Disk partition for now */ + if (i == WHOLE_DISK_PART + 1) + continue; + p = ped_disk_get_partition (part->disk, i); + if (!p) { + part->num = i; + return 1; + } + } + +#ifndef DISCOVER_ONLY + /* Ok, now allocate the Whole disk if it isn't already */ + p = ped_disk_get_partition (part->disk, WHOLE_DISK_PART + 1); + if (!p) { + int j = ped_exception_throw ( + PED_EXCEPTION_WARNING, + PED_EXCEPTION_IGNORE_CANCEL, + _("The Whole Disk partition is the only " + "available one left. Generally, it is not a " + "good idea to overwrite this partition with " + "a real one. Solaris may not be able to " + "boot without it, and SILO (the sparc boot " + "loader) appreciates it as well.")); + if (j == PED_EXCEPTION_IGNORE) { + /* bad bad bad...you will suffer your own fate */ + part->num = WHOLE_DISK_PART + 1; + return 1; + } + } + + /* failed to allocate a number, this means we are full */ + ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, + _("Sun disk label is full.")); +#endif + return 0; +} + +static int +sun_alloc_metadata (PedDisk* disk) +{ + PedPartition* new_part; + SunDiskData* disk_data; + PedConstraint* constraint_any; + + PED_ASSERT (disk != NULL); + PED_ASSERT (disk->disk_specific != NULL); + PED_ASSERT (disk->dev != NULL); + + constraint_any = ped_constraint_any (disk->dev); + + /* Sun disk label does not need to allocate a sector. The disk + label is contained within the first 512 bytes, which should not + be overwritten by any boot loader or superblock. It is safe for + most partitions to start at sector 0. We do however, allocate + the space used by alt-cyl's, since we cannot use those. Put them + at the end of the disk. */ + + disk_data = disk->disk_specific; + + if (disk->dev->length <= 0 || + disk_data->length <= 0 || + disk->dev->length == disk_data->length) + goto error; + + new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, + disk_data->length, disk->dev->length - 1); + 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 (sun) + +static PedDiskOps sun_disk_ops = { + clobber: NULL, + write: NULL_IF_DISCOVER_ONLY (sun_write), + + get_partition_alignment: sun_get_partition_alignment, + + partition_set_name: NULL, + partition_get_name: NULL, + + PT_op_function_initializers (sun) +}; + +static PedDiskType sun_disk_type = { + next: NULL, + name: "sun", + ops: &sun_disk_ops, + features: 0 +}; + +void +ped_disk_sun_init () +{ + PED_ASSERT (sizeof (SunRawLabel) == 512); + ped_disk_type_register (&sun_disk_type); +} + +void +ped_disk_sun_done () +{ + ped_disk_type_unregister (&sun_disk_type); +} |