/* -*- 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 . Contributor: Phil Knirsch Harald Hoyer */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }