/* -*- 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;
}