summaryrefslogtreecommitdiffstats
path: root/libparted/labels/dasd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libparted/labels/dasd.c1032
1 files changed, 1032 insertions, 0 deletions
diff --git a/libparted/labels/dasd.c b/libparted/labels/dasd.c
new file mode 100644
index 0000000..1d99458
--- /dev/null
+++ b/libparted/labels/dasd.c
@@ -0,0 +1,1032 @@
+/* -*- 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: Phil Knirsch <phil@redhat.de>
+ Harald Hoyer <harald@redhat.de>
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include <parted/vtoc.h>
+#include <parted/fdasd.h>
+#include <arch/linux.h>
+
+#include <libintl.h>
+#if ENABLE_NLS
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+#define PARTITION_LINUX_SWAP 0x82
+#define PARTITION_LINUX 0x83
+#define PARTITION_LINUX_LVM 0x8e
+#define PARTITION_LINUX_RAID 0xfd
+
+extern void ped_disk_dasd_init ();
+extern void ped_disk_dasd_done ();
+
+#define DASD_NAME "dasd"
+
+typedef struct {
+ int type;
+ int system;
+} DasdPartitionData;
+
+typedef struct {
+ unsigned int format_type;
+ unsigned int label_block;
+ volume_label_t vlabel;
+} DasdDiskSpecific;
+
+static int dasd_probe (const PedDevice *dev);
+static int dasd_read (PedDisk* disk);
+static int dasd_write (const PedDisk* disk);
+
+static PedPartition* dasd_partition_new (const PedDisk* disk,
+ PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start,
+ PedSector end);
+static PedPartition* dasd_partition_duplicate (const PedPartition *part);
+static void dasd_partition_destroy (PedPartition* part);
+static int dasd_partition_set_flag (PedPartition* part,
+ PedPartitionFlag flag,
+ int state);
+static int dasd_partition_get_flag (const PedPartition* part,
+ PedPartitionFlag flag);
+static int dasd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag);
+static int dasd_partition_align (PedPartition* part,
+ const PedConstraint* constraint);
+static int dasd_partition_enumerate (PedPartition* part);
+static int dasd_get_max_primary_partition_count (const PedDisk* disk);
+static bool dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n);
+static PedAlignment *dasd_get_partition_alignment(const PedDisk *disk);
+
+static PedDisk* dasd_alloc (const PedDevice* dev);
+static PedDisk* dasd_duplicate (const PedDisk* disk);
+static void dasd_free (PedDisk* disk);
+static int dasd_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type);
+static int dasd_alloc_metadata (PedDisk* disk);
+
+#include "pt-common.h"
+PT_define_limit_functions (dasd)
+
+static PedDiskOps dasd_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (dasd_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+ partition_set_type_id: NULL,
+ partition_get_type_id: NULL,
+ partition_set_type_uuid: NULL,
+ partition_get_type_uuid: NULL,
+
+ get_partition_alignment: dasd_get_partition_alignment,
+
+ PT_op_function_initializers (dasd)
+};
+
+static PedDiskType dasd_disk_type = {
+ next: NULL,
+ name: "dasd",
+ ops: &dasd_disk_ops,
+ features: 0
+};
+
+struct flag_id_mapping_t
+{
+ enum _PedPartitionFlag flag;
+ int type_id;
+};
+
+static const struct flag_id_mapping_t flag_id_mapping[] =
+{
+ { PED_PARTITION_LVM, PARTITION_LINUX_LVM },
+ { PED_PARTITION_RAID, PARTITION_LINUX_RAID },
+ { PED_PARTITION_SWAP, PARTITION_LINUX_SWAP },
+};
+
+static const struct flag_id_mapping_t* _GL_ATTRIBUTE_CONST
+dasd_find_flag_id_mapping (PedPartitionFlag flag)
+{
+ int n = sizeof(flag_id_mapping) / sizeof(flag_id_mapping[0]);
+
+ for (int i = 0; i < n; ++i)
+ if (flag_id_mapping[i].flag == flag)
+ return &flag_id_mapping[i];
+
+ return NULL;
+}
+
+static PedDisk*
+dasd_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific *disk_specific;
+ char volser[7];
+
+ PED_ASSERT (dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (dev);
+ disk = _ped_disk_alloc (dev, &dasd_disk_type);
+ if (!disk)
+ return NULL;
+
+ disk->disk_specific = disk_specific = ped_malloc(sizeof(DasdDiskSpecific));
+ if (!disk->disk_specific) {
+ free (disk);
+ return NULL;
+ }
+
+ /* CDL format, newer */
+ disk_specific->format_type = 2;
+ disk_specific->label_block = 2;
+
+ /* Setup volume label (for fresh disks) */
+ snprintf(volser, sizeof(volser), "0X%04X", arch_specific->devno);
+ vtoc_volume_label_init(&disk_specific->vlabel);
+ vtoc_volume_label_set_key(&disk_specific->vlabel, "VOL1");
+ vtoc_volume_label_set_label(&disk_specific->vlabel, "VOL1");
+ vtoc_volume_label_set_volser(&disk_specific->vlabel, volser);
+ vtoc_set_cchhb(&disk_specific->vlabel.vtoc,
+ VTOC_START_CC, VTOC_START_HH, 0x01);
+
+ return disk;
+}
+
+static PedDisk*
+dasd_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+
+ new_disk = ped_disk_new_fresh(disk->dev, &dasd_disk_type);
+
+ if (!new_disk)
+ return NULL;
+
+ memcpy(new_disk->disk_specific, disk->disk_specific,
+ sizeof(DasdDiskSpecific));
+
+ return new_disk;
+}
+
+static void
+dasd_free (PedDisk* disk)
+{
+ PED_ASSERT(disk != NULL);
+ /* Don't free disk->disk_specific first, in case _ped_disk_free
+ or one of its eventual callees ever accesses it. */
+ void *p = disk->disk_specific;
+ _ped_disk_free(disk);
+ free(p);
+}
+
+
+void
+ped_disk_dasd_init ()
+{
+ ped_disk_type_register(&dasd_disk_type);
+}
+
+void
+ped_disk_dasd_done ()
+{
+ ped_disk_type_unregister(&dasd_disk_type);
+}
+
+static int
+dasd_probe (const PedDevice *dev)
+{
+ LinuxSpecific* arch_specific;
+ struct fdasd_anchor anchor;
+
+ PED_ASSERT(dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC(dev);
+
+ /* add partition test here */
+ fdasd_initialize_anchor(&anchor);
+
+ if (fdasd_get_geometry(dev, &anchor, arch_specific->fd) == 0)
+ goto error_cleanup;
+
+ /* Labels are required on CDL formatted DASDs. */
+ if (fdasd_check_volume(&anchor, arch_specific->fd) &&
+ anchor.FBA_layout == 0)
+ goto error_cleanup;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+
+ error_cleanup:
+ fdasd_cleanup(&anchor);
+ ped_exception_throw(PED_EXCEPTION_ERROR,PED_EXCEPTION_IGNORE_CANCEL,
+ "Error while probing device %s.", dev->path);
+
+ return 0;
+}
+
+static int
+dasd_read (PedDisk* disk)
+{
+ int i;
+ char str[20];
+ PedDevice* dev;
+ PedPartition* part;
+ PedFileSystemType *fs;
+ PedSector start, end;
+ PedConstraint* constraint_exact;
+ partition_info_t *p;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ struct fdasd_anchor anchor;
+
+ PDEBUG;
+
+ PED_ASSERT (disk != NULL);
+ PDEBUG;
+ PED_ASSERT (disk->dev != NULL);
+ PDEBUG;
+
+ dev = disk->dev;
+
+ arch_specific = LINUX_SPECIFIC(dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ fdasd_initialize_anchor(&anchor);
+
+ if (fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd) == 0)
+ goto error_close_dev;
+
+ disk_specific->label_block = anchor.label_block;
+
+ if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
+ anchor.big_disk++;
+
+ /* check dasd for labels and vtoc */
+ if (fdasd_check_volume(&anchor, arch_specific->fd)) {
+ DasdPartitionData* dasd_data;
+
+ /* Kernel partitioning code will report 'implicit' partitions
+ * for non-CDL format DASDs even when there is no
+ * label/VTOC. */
+ if (anchor.FBA_layout == 0)
+ goto error_close_dev;
+
+ disk_specific->format_type = 1;
+
+ /* Register implicit partition */
+ ped_disk_delete_all (disk);
+
+ start = (PedSector) arch_specific->real_sector_size /
+ (PedSector) disk->dev->sector_size *
+ (PedSector) (anchor.label_block + 1);
+ end = disk->dev->length - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ start, end);
+ if (!part)
+ goto error_close_dev;
+
+ part->num = 1;
+ part->fs_type = ped_file_system_probe (&part->geom);
+ dasd_data = part->disk_specific;
+ dasd_data->type = 0;
+
+ if (!ped_disk_add_partition (disk, part, NULL))
+ goto error_close_dev;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+ }
+
+ /* Save volume label (read by fdasd_check_volume) for writing */
+ memcpy(&disk_specific->vlabel, anchor.vlabel, sizeof(volume_label_t));
+
+ ped_disk_delete_all (disk);
+
+ bool is_ldl = strncmp(anchor.vlabel->volkey,
+ vtoc_ebcdic_enc("LNX1", str, 4), 4) == 0;
+ bool is_cms = strncmp(anchor.vlabel->volkey,
+ vtoc_ebcdic_enc("CMS1", str, 4), 4) == 0;
+ if (is_ldl || is_cms) {
+ DasdPartitionData* dasd_data;
+
+ union vollabel {
+ volume_label_t ldl;
+ cms_volume_label_t cms;
+ };
+ union vollabel *cms_ptr1 = (union vollabel *) anchor.vlabel;
+ cms_volume_label_t *cms_ptr = &cms_ptr1->cms;
+ volume_label_t *ldl_ptr = &cms_ptr1->ldl;
+ int partition_start_block;
+
+ disk_specific->format_type = 1;
+
+ if (is_cms && cms_ptr->usable_count >= cms_ptr->block_count)
+ partition_start_block = 2; /* FBA DASD */
+ else
+ partition_start_block = 3; /* CKD DASD */
+
+ if (is_ldl)
+ start = (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size
+ * (long long) partition_start_block;
+ else if (cms_ptr->disk_offset == 0)
+ start = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) partition_start_block;
+ else
+ start = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) cms_ptr->disk_offset;
+
+ if (is_ldl)
+ if (ldl_ptr->ldl_version >= 0xf2)
+ end = (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size
+ * (long long) ldl_ptr->formatted_blocks - 1;
+ else
+ end = disk->dev->length - 1;
+ else
+ if (cms_ptr->disk_offset == 0)
+ end = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) cms_ptr->block_count - 1;
+ else
+ /*
+ Frankly, I do not understand why the last block
+ of the CMS reserved file is not included in the
+ partition; but this is the algorithm used by the
+ Linux kernel. See fs/partitions/ibm.c in the
+ Linux kernel source code.
+ */
+ end = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) (cms_ptr->block_count - 1) - 1;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL, start, end);
+ if (!part)
+ goto error_close_dev;
+
+ part->num = 1;
+ part->fs_type = ped_file_system_probe (&part->geom);
+ dasd_data = part->disk_specific;
+ dasd_data->type = 0;
+
+ if (!ped_disk_add_partition (disk, part, NULL))
+ goto error_close_dev;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+ }
+
+ /* CDL format, newer */
+ disk_specific->format_type = 2;
+
+ p = anchor.first;
+ PDEBUG;
+
+ for (i = 1 ; i <= USABLE_PARTITIONS; i++) {
+ char *ch = p->f1->DS1DSNAM;
+ DasdPartitionData* dasd_data;
+
+
+ if (p->used != 0x01)
+ continue;
+
+ PDEBUG;
+
+ start = (long long)(long long) p->start_trk
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size;
+ end = (long long)((long long) p->end_trk + 1)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size - 1;
+ part = ped_partition_new(disk, PED_PARTITION_NORMAL, NULL,
+ start, end);
+ PDEBUG;
+
+ if (!part)
+ goto error_close_dev;
+
+ PDEBUG;
+
+ part->num = i;
+ part->fs_type = ped_file_system_probe(&part->geom);
+
+ vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ ch = strstr(p->f1->DS1DSNAM, "PART");
+
+ if (ch != NULL) {
+ strncpy(str, ch+9, 6);
+ str[6] = '\0';
+ }
+
+ dasd_data = part->disk_specific;
+
+ if (strncmp(PART_TYPE_RAID, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_RAID;
+ else if (strncmp(PART_TYPE_LVM, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_LVM;
+ else if (strncmp(PART_TYPE_SWAP, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_SWAP;
+
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+
+ dasd_data->type = 0;
+
+ constraint_exact = ped_constraint_exact (&part->geom);
+ if (!constraint_exact)
+ goto error_close_dev;
+ if (!ped_disk_add_partition(disk, part, constraint_exact)) {
+ ped_constraint_destroy(constraint_exact);
+ goto error_close_dev;
+ }
+ ped_constraint_destroy(constraint_exact);
+
+ if (p->fspace_trk > 0) {
+ start = (long long)((long long) p->end_trk + 1)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size;
+ end = (long long)((long long) p->end_trk + 1 + p->fspace_trk)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, start, end);
+
+ if (!part)
+ goto error_close_dev;
+
+ part->type = PED_PARTITION_FREESPACE;
+ constraint_exact = ped_constraint_exact(&part->geom);
+
+ if (!constraint_exact)
+ goto error_close_dev;
+ if (!ped_disk_add_partition(disk, part, constraint_exact)) {
+ ped_constraint_destroy(constraint_exact);
+ goto error_close_dev;
+ }
+
+ ped_constraint_destroy (constraint_exact);
+ }
+
+ p = p->next;
+ }
+
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 1;
+
+error_close_dev:
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 0;
+}
+
+static int
+dasd_update_type (const PedDisk* disk, struct fdasd_anchor *anchor,
+ partition_info_t *part_info[USABLE_PARTITIONS])
+{
+ PedPartition* part;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+
+ arch_specific = LINUX_SPECIFIC(disk->dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ unsigned int i;
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ partition_info_t *p;
+ char *ch = NULL;
+ DasdPartitionData* dasd_data;
+
+ PDEBUG;
+
+ part = ped_disk_get_partition(disk, i);
+ if (!part)
+ continue;
+
+ PDEBUG;
+
+ dasd_data = part->disk_specific;
+ p = part_info[i - 1];
+
+ if (!p ) {
+ PDEBUG;
+ continue;
+ }
+
+ vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ ch = strstr(p->f1->DS1DSNAM, "PART");
+
+ PDEBUG;
+ if (ch == NULL) {
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ PDEBUG;
+ continue;
+ }
+
+ ch += 9;
+
+ switch (dasd_data->system) {
+ case PARTITION_LINUX_LVM:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_LVM, 6);
+ break;
+ case PARTITION_LINUX_RAID:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_RAID, 6);
+ break;
+ case PARTITION_LINUX:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_NATIVE, 6);
+ break;
+ case PARTITION_LINUX_SWAP:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_SWAP, 6);
+ break;
+ default:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_NATIVE, 6);
+ break;
+ }
+
+ anchor->vtoc_changed++;
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ }
+
+ return 1;
+}
+
+static int
+dasd_write (const PedDisk* disk)
+{
+ DasdPartitionData* dasd_data;
+ PedPartition* part;
+ int i;
+ partition_info_t *p;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ struct fdasd_anchor anchor;
+ partition_info_t *part_info[USABLE_PARTITIONS];
+
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ /* If not formated in CDL, don't write anything. */
+ if (disk_specific->format_type == 1) {
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The partition table of DASD-LDL device cannot be changed.\n"));
+ return 1;
+ }
+
+ /* initialize the anchor */
+ fdasd_initialize_anchor(&anchor);
+ if (fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd) == 0)
+ goto error;
+
+ fdasd_check_volume(&anchor, arch_specific->fd);
+ memcpy(anchor.vlabel, &disk_specific->vlabel, sizeof(volume_label_t));
+ anchor.vlabel_changed++;
+
+ if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
+ anchor.big_disk++;
+
+ fdasd_recreate_vtoc(&anchor);
+
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ unsigned int start, stop;
+
+ PDEBUG;
+ part = ped_disk_get_partition(disk, i);
+ if (!part)
+ continue;
+
+ PDEBUG;
+
+ start = part->geom.start * disk->dev->sector_size
+ / arch_specific->real_sector_size / disk->dev->hw_geom.sectors;
+ stop = (part->geom.end + 1)
+ * disk->dev->sector_size / arch_specific->real_sector_size
+ / disk->dev->hw_geom.sectors - 1;
+
+ PDEBUG;
+ dasd_data = part->disk_specific;
+
+ p = fdasd_add_partition(&anchor, start, stop);
+ if (!p) {
+ PDEBUG;
+ goto error;
+ }
+ part_info[i - 1] = p;
+ p->type = dasd_data->system;
+ }
+
+ PDEBUG;
+
+ if (!fdasd_prepare_labels(&anchor, arch_specific->fd))
+ goto error;
+
+ dasd_update_type(disk, &anchor, part_info);
+ PDEBUG;
+
+ if (!fdasd_write_labels(&anchor, arch_specific->fd))
+ goto error;
+
+ fdasd_cleanup(&anchor);
+ return 1;
+
+error:
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 0;
+}
+
+static PedPartition*
+dasd_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+
+ part = _ped_partition_alloc(disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ part->disk_specific = ped_calloc (sizeof (DasdPartitionData));
+ return part;
+
+error:
+ return 0;
+}
+
+static PedPartition*
+dasd_partition_duplicate (const PedPartition *part)
+{
+ PedPartition *new_part;
+
+ 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;
+
+ memcpy(new_part->disk_specific, part->disk_specific,
+ sizeof(DasdPartitionData));
+
+ return new_part;
+}
+
+static void
+dasd_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT(part != NULL);
+
+ if (ped_partition_is_active(part))
+ free(part->disk_specific);
+ free(part);
+}
+
+static int
+dasd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ DasdPartitionData* dasd_data;
+
+ PED_ASSERT(part != NULL);
+ PED_ASSERT(part->disk_specific != NULL);
+ dasd_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dasd_find_flag_id_mapping (flag);
+ if (p)
+ {
+ if (state)
+ dasd_data->system = p->type_id;
+ else if (dasd_data->system == p->type_id)
+ return dasd_partition_set_system (part, part->fs_type);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+dasd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ DasdPartitionData* dasd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ dasd_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dasd_find_flag_id_mapping (flag);
+ if (p)
+ return dasd_data->system == p->type_id;
+
+ return 0;
+}
+
+/*
+ * The DASD-LDL does not support flags now.
+ * So just return 0.
+*/
+static int
+dasd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ DasdDiskSpecific* disk_specific;
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->disk_specific != NULL);
+
+ disk_specific = part->disk->disk_specific;
+
+ if (disk_specific->format_type == 1)
+ return 0;
+
+ if (dasd_find_flag_id_mapping (flag))
+ return 1;
+
+ return 0;
+}
+
+
+static int
+dasd_get_max_primary_partition_count (const PedDisk* disk)
+{
+ DasdDiskSpecific* disk_specific;
+
+ disk_specific = disk->disk_specific;
+ /* If formated in LDL, maximum partition number is 1 */
+ if (disk_specific->format_type == 1)
+ return 1;
+
+ return USABLE_PARTITIONS;
+}
+
+static bool
+dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = dasd_get_max_primary_partition_count(disk);
+ return true;
+}
+
+static PedAlignment*
+dasd_get_partition_alignment(const PedDisk *disk)
+{
+ LinuxSpecific *arch_specific = LINUX_SPECIFIC(disk->dev);
+ PedSector sector_size =
+ arch_specific->real_sector_size / disk->dev->sector_size;
+
+ return ped_alignment_new(0, disk->dev->hw_geom.sectors * sector_size);
+}
+
+static PedConstraint*
+_primary_constraint (PedDisk* disk)
+{
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+ PedSector sector_size;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ PedSector start;
+
+ PDEBUG;
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+ sector_size = arch_specific->real_sector_size / disk->dev->sector_size;
+
+ if (!ped_alignment_init (&start_align, 0,
+ disk->dev->hw_geom.sectors * sector_size))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1,
+ disk->dev->hw_geom.sectors * sector_size))
+ return NULL;
+
+ start = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size);
+
+ if (!ped_geometry_init (&max_geom, disk->dev, start, disk->dev->length))
+ return NULL;
+
+ return ped_constraint_new(&start_align, &end_align, &max_geom,
+ &max_geom, 1, disk->dev->length);
+}
+
+static int
+dasd_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ DasdDiskSpecific* disk_specific;
+
+ PED_ASSERT (part != NULL);
+
+ disk_specific = part->disk->disk_specific;
+ /* If formated in LDL, ignore metadata partition */
+ if (disk_specific->format_type == 1)
+ return 1;
+
+ if (_ped_partition_attempt_align(part, constraint,
+ _primary_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
+dasd_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number */
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a dasd disklabel slot"));
+ return 0;
+}
+
+static int
+dasd_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type)
+{
+ DasdPartitionData* dasd_data = part->disk_specific;
+ PedSector cyl_size;
+
+ cyl_size=part->disk->dev->hw_geom.sectors * part->disk->dev->hw_geom.heads;
+ PDEBUG;
+
+ part->fs_type = fs_type;
+
+ if (!fs_type) {
+ dasd_data->system = PARTITION_LINUX;
+ PDEBUG;
+ } else if (is_linux_swap (fs_type->name)) {
+ dasd_data->system = PARTITION_LINUX_SWAP;
+ PDEBUG;
+ } else {
+ dasd_data->system = PARTITION_LINUX;
+ PDEBUG;
+ }
+
+ return 1;
+}
+
+static int
+dasd_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+ PedSector vtoc_end;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ PedPartition* part = NULL; /* initialize solely to placate gcc */
+ PedPartition* new_part2;
+ PedSector trailing_meta_start, trailing_meta_end;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* For LDL or CMS, the leading metadata ends at the sector before
+ the start of the first partition */
+ if (disk_specific->format_type == 1) {
+ part = ped_disk_get_partition(disk, 1);
+ if (part)
+ vtoc_end = part->geom.start - 1;
+ else
+ vtoc_end = (PedSector) arch_specific->real_sector_size /
+ (PedSector) disk->dev->sector_size *
+ (PedSector) disk_specific->label_block;
+ }
+ else {
+ if (disk->dev->type == PED_DEVICE_FILE)
+ arch_specific->real_sector_size = disk->dev->sector_size;
+ /* Mark the start of the disk as metadata. */
+ vtoc_end = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size) - 1;
+ }
+
+ new_part = ped_partition_new (disk,PED_PARTITION_METADATA,NULL,0,vtoc_end);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ if (disk_specific->format_type == 1 && part) {
+ /*
+ For LDL or CMS there may be trailing metadata as well.
+ For example: the last block of a CMS reserved file,
+ the "recomp" area of a CMS minidisk that has been
+ formatted and then formatted again with the RECOMP
+ option specifying fewer than the maximum number of
+ cylinders, a disk that was formatted at one size,
+ backed up, then restored to a larger size disk, etc.
+ */
+ trailing_meta_start = part->geom.end + 1;
+ trailing_meta_end = (long long) disk->dev->length - 1;
+ if (trailing_meta_end >= trailing_meta_start) {
+ new_part2 = ped_partition_new (disk,PED_PARTITION_METADATA,
+ NULL, trailing_meta_start, trailing_meta_end);
+ if (!new_part2) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+ if (!ped_disk_add_partition (disk, new_part2,
+ constraint_any)) {
+ ped_partition_destroy (new_part2);
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+ }
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}