1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3 libparted - a library for manipulating disk partitions
4 Copyright (C) 2000-2001, 2007-2009 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 Contributor: Phil Knirsch <phil@redhat.de>
20 Harald Hoyer <harald@redhat.de>
34 #include <sys/ioctl.h>
35 #include <parted/parted.h>
36 #include <parted/endian.h>
37 #include <parted/debug.h>
39 #include <parted/vtoc.h>
40 #include <parted/fdasd.h>
41 #include <arch/linux.h>
45 # define _(String) dgettext (PACKAGE, String)
47 # define _(String) (String)
48 #endif /* ENABLE_NLS */
52 #define PARTITION_LINUX_SWAP 0x82
53 #define PARTITION_LINUX 0x83
54 #define PARTITION_LINUX_EXT 0x85
55 #define PARTITION_LINUX_LVM 0x8e
56 #define PARTITION_LINUX_RAID 0xfd
57 #define PARTITION_LINUX_LVM_OLD 0xfe
59 extern void ped_disk_dasd_init ();
60 extern void ped_disk_dasd_done ();
62 #define DASD_NAME "dasd"
73 unsigned int real_sector_size;
74 unsigned int format_type;
75 /* IBM internal dasd structure (i guess ;), required. */
76 struct fdasd_anchor *anchor;
79 static int dasd_probe (const PedDevice *dev);
80 static int dasd_clobber (PedDevice* dev);
81 static int dasd_read (PedDisk* disk);
82 static int dasd_write (const PedDisk* disk);
84 static PedPartition* dasd_partition_new (const PedDisk* disk,
85 PedPartitionType part_type,
86 const PedFileSystemType* fs_type,
89 static void dasd_partition_destroy (PedPartition* part);
90 static int dasd_partition_set_flag (PedPartition* part,
91 PedPartitionFlag flag,
93 static int dasd_partition_get_flag (const PedPartition* part,
94 PedPartitionFlag flag);
95 static int dasd_partition_is_flag_available (const PedPartition* part,
96 PedPartitionFlag flag);
97 static int dasd_partition_align (PedPartition* part,
98 const PedConstraint* constraint);
99 static int dasd_partition_enumerate (PedPartition* part);
100 static int dasd_get_max_primary_partition_count (const PedDisk* disk);
101 static bool dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n);
103 static PedDisk* dasd_alloc (const PedDevice* dev);
104 static PedDisk* dasd_duplicate (const PedDisk* disk);
105 static void dasd_free (PedDisk* disk);
106 static int dasd_partition_set_system (PedPartition* part,
107 const PedFileSystemType* fs_type);
108 static int dasd_alloc_metadata (PedDisk* disk);
110 static PedDiskOps dasd_disk_ops = {
112 clobber: dasd_clobber,
117 duplicate: dasd_duplicate,
119 partition_set_system: dasd_partition_set_system,
121 partition_new: dasd_partition_new,
122 partition_destroy: dasd_partition_destroy,
123 partition_set_flag: dasd_partition_set_flag,
124 partition_get_flag: dasd_partition_get_flag,
125 partition_is_flag_available: dasd_partition_is_flag_available,
126 partition_set_name: NULL,
127 partition_get_name: NULL,
128 partition_align: dasd_partition_align,
129 partition_enumerate: dasd_partition_enumerate,
131 alloc_metadata: dasd_alloc_metadata,
132 get_max_primary_partition_count: dasd_get_max_primary_partition_count,
133 get_max_supported_partition_count: dasd_get_max_supported_partition_count,
135 partition_duplicate: NULL
138 static PedDiskType dasd_disk_type = {
146 dasd_alloc (const PedDevice* dev)
149 LinuxSpecific* arch_specific;
150 DasdDiskSpecific *disk_specific;
152 PED_ASSERT (dev != NULL, return NULL);
154 arch_specific = LINUX_SPECIFIC (dev);
155 disk = _ped_disk_alloc (dev, &dasd_disk_type);
159 disk->disk_specific = disk_specific = ped_malloc(sizeof(DasdDiskSpecific));
160 if (!disk->disk_specific) {
165 /* because we lie to parted we have to compensate with the
166 real sector size. Record that now. */
167 if (ioctl(arch_specific->fd, BLKSSZGET,
168 &disk_specific->real_sector_size) == -1) {
169 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
170 _("Unable to determine the block "
171 "size of this dasd"));
181 dasd_duplicate (const PedDisk* disk)
185 new_disk = ped_disk_new_fresh(disk->dev, &dasd_disk_type);
190 new_disk->disk_specific = NULL;
196 dasd_free (PedDisk* disk)
198 PED_ASSERT(disk != NULL, return);
200 _ped_disk_free(disk);
205 ped_disk_dasd_init ()
207 ped_disk_type_register(&dasd_disk_type);
211 ped_disk_dasd_done ()
213 ped_disk_type_unregister(&dasd_disk_type);
217 dasd_probe (const PedDevice *dev)
219 LinuxSpecific* arch_specific;
220 struct fdasd_anchor anchor;
222 PED_ASSERT(dev != NULL, return 0);
224 if (!(dev->type == PED_DEVICE_DASD || dev->type == PED_DEVICE_VIODASD))
227 arch_specific = LINUX_SPECIFIC(dev);
229 /* add partition test here */
230 fdasd_initialize_anchor(&anchor);
232 fdasd_get_geometry(&anchor, arch_specific->fd);
234 fdasd_check_api_version(&anchor, arch_specific->fd);
236 if (fdasd_check_volume(&anchor, arch_specific->fd))
239 fdasd_cleanup(&anchor);
244 fdasd_cleanup(&anchor);
245 ped_exception_throw(PED_EXCEPTION_ERROR,PED_EXCEPTION_IGNORE_CANCEL,
246 "Error while probing device %s.", dev->path);
252 dasd_clobber (PedDevice* dev)
254 LinuxSpecific* arch_specific;
255 struct fdasd_anchor anchor;
257 PED_ASSERT(dev != NULL, return 0);
259 arch_specific = LINUX_SPECIFIC(dev);
261 fdasd_initialize_anchor(&anchor);
262 fdasd_get_geometry(&anchor, arch_specific->fd);
264 fdasd_recreate_vtoc(&anchor);
265 fdasd_write_labels(&anchor, arch_specific->fd);
271 dasd_read (PedDisk* disk)
277 PedFileSystemType *fs;
278 PedSector start, end;
279 PedConstraint* constraint_exact;
281 LinuxSpecific* arch_specific;
282 DasdDiskSpecific* disk_specific;
286 PED_ASSERT (disk != NULL, return 0);
288 PED_ASSERT (disk->dev != NULL, return 0);
293 arch_specific = LINUX_SPECIFIC(dev);
294 disk_specific = disk->disk_specific;
296 disk_specific->anchor = ped_malloc(sizeof(fdasd_anchor_t));
300 fdasd_initialize_anchor(disk_specific->anchor);
302 fdasd_get_geometry(disk_specific->anchor, arch_specific->fd);
304 /* check dasd for labels and vtoc */
305 if (fdasd_check_volume(disk_specific->anchor, arch_specific->fd))
306 goto error_close_dev;
308 if ((disk_specific->anchor->geo.cylinders
309 * disk_specific->anchor->geo.heads) > BIG_DISK_SIZE)
310 disk_specific->anchor->big_disk++;
312 ped_disk_delete_all (disk);
314 if (strncmp(disk_specific->anchor->vlabel->volkey,
315 vtoc_ebcdic_enc ("LNX1", str, 4), 4) == 0) {
316 DasdPartitionData* dasd_data;
318 /* LDL format, old one */
319 disk_specific->format_type = 1;
321 end = (long long)(long long) disk_specific->anchor->geo.cylinders
322 * (long long)disk_specific->anchor->geo.heads
323 * (long long)disk->dev->hw_geom.sectors
324 * (long long)disk_specific->real_sector_size
325 / (long long)disk->dev->sector_size - 1;
326 part = ped_partition_new (disk, PED_PARTITION_PROTECTED, NULL, start, end);
328 goto error_close_dev;
331 part->fs_type = ped_file_system_probe (&part->geom);
332 dasd_data = part->disk_specific;
337 if (!ped_disk_add_partition (disk, part, NULL))
338 goto error_close_dev;
343 /* CDL format, newer */
344 disk_specific->format_type = 2;
346 p = disk_specific->anchor->first;
349 for (i = 1 ; i <= USABLE_PARTITIONS; i++) {
350 char *ch = p->f1->DS1DSNAM;
351 DasdPartitionData* dasd_data;
359 start = (long long)(long long) p->start_trk
360 * (long long) disk->dev->hw_geom.sectors
361 * (long long) disk_specific->real_sector_size
362 / (long long) disk->dev->sector_size;
363 end = (long long)((long long) p->end_trk + 1)
364 * (long long) disk->dev->hw_geom.sectors
365 * (long long) disk_specific->real_sector_size
366 / (long long) disk->dev->sector_size - 1;
367 part = ped_partition_new(disk, PED_PARTITION_NORMAL, NULL,
372 goto error_close_dev;
377 part->fs_type = ped_file_system_probe(&part->geom);
379 vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
380 ch = strstr(p->f1->DS1DSNAM, "PART");
383 strncpy(str, ch+9, 6);
387 dasd_data = part->disk_specific;
389 if ((strncmp(PART_TYPE_RAID, str, 6) == 0) &&
390 (ped_file_system_probe(&part->geom) == NULL))
391 ped_partition_set_flag(part, PED_PARTITION_RAID, 1);
393 ped_partition_set_flag(part, PED_PARTITION_RAID, 0);
395 if ((strncmp(PART_TYPE_LVM, str, 6) == 0) &&
396 (ped_file_system_probe(&part->geom) == NULL))
397 ped_partition_set_flag(part, PED_PARTITION_LVM, 1);
399 ped_partition_set_flag(part, PED_PARTITION_LVM, 0);
401 if (strncmp(PART_TYPE_SWAP, str, 6) == 0) {
402 fs = ped_file_system_probe(&part->geom);
403 if (is_linux_swap(fs->name)) {
404 dasd_data->system = PARTITION_LINUX_SWAP;
409 vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
411 dasd_data->part_info = (void *) p;
414 constraint_exact = ped_constraint_exact (&part->geom);
415 if (!constraint_exact)
416 goto error_close_dev;
417 if (!ped_disk_add_partition(disk, part, constraint_exact))
418 goto error_close_dev;
419 ped_constraint_destroy(constraint_exact);
421 if (p->fspace_trk > 0) {
422 start = (long long)((long long) p->end_trk + 1)
423 * (long long) disk->dev->hw_geom.sectors
424 * (long long) disk_specific->real_sector_size
425 / (long long) disk->dev->sector_size;
426 end = (long long)((long long) p->end_trk + 1 + p->fspace_trk)
427 * (long long) disk->dev->hw_geom.sectors
428 * (long long) disk_specific->real_sector_size
429 / (long long) disk->dev->sector_size - 1;
430 part = ped_partition_new (disk, PED_PARTITION_NORMAL,
434 goto error_close_dev;
436 part->type = PED_PARTITION_FREESPACE;
437 constraint_exact = ped_constraint_exact(&part->geom);
439 if (!constraint_exact)
440 goto error_close_dev;
441 if (!ped_disk_add_partition(disk, part, constraint_exact))
442 goto error_close_dev;
444 ped_constraint_destroy (constraint_exact);
459 dasd_update_type (const PedDisk* disk)
462 LinuxSpecific* arch_specific;
463 DasdDiskSpecific* disk_specific;
465 arch_specific = LINUX_SPECIFIC(disk->dev);
466 disk_specific = disk->disk_specific;
470 for (part = ped_disk_next_partition(disk, NULL); part;
471 part = ped_disk_next_partition(disk, part)) {
474 DasdPartitionData* dasd_data;
478 if (part->type & PED_PARTITION_FREESPACE
479 || part->type & PED_PARTITION_METADATA)
484 dasd_data = part->disk_specific;
485 p = dasd_data->part_info;
492 vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
493 ch = strstr(p->f1->DS1DSNAM, "PART");
497 vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
504 switch (dasd_data->system) {
505 case PARTITION_LINUX_LVM:
507 strncpy(ch, PART_TYPE_LVM, 6);
509 case PARTITION_LINUX_RAID:
511 strncpy(ch, PART_TYPE_RAID, 6);
513 case PARTITION_LINUX:
515 strncpy(ch, PART_TYPE_NATIVE, 6);
517 case PARTITION_LINUX_SWAP:
519 strncpy(ch, PART_TYPE_SWAP, 6);
523 strncpy(ch, PART_TYPE_NATIVE, 6);
527 disk_specific->anchor->vtoc_changed++;
528 vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
535 dasd_write (const PedDisk* disk)
537 DasdPartitionData* dasd_data;
541 LinuxSpecific* arch_specific;
542 DasdDiskSpecific* disk_specific;
543 PED_ASSERT(disk != NULL, return 0);
544 PED_ASSERT(disk->dev != NULL, return 0);
546 arch_specific = LINUX_SPECIFIC (disk->dev);
547 disk_specific = disk->disk_specific;
551 /* If formated in LDL, don't write anything. */
552 if (disk_specific->format_type == 1)
555 /* XXX re-initialize anchor? */
556 fdasd_initialize_anchor(disk_specific->anchor);
557 fdasd_get_geometry(disk_specific->anchor, arch_specific->fd);
559 /* check dasd for labels and vtoc */
560 if (fdasd_check_volume(disk_specific->anchor, arch_specific->fd))
563 if ((disk_specific->anchor->geo.cylinders
564 * disk_specific->anchor->geo.heads) > BIG_DISK_SIZE)
565 disk_specific->anchor->big_disk++;
567 fdasd_recreate_vtoc(disk_specific->anchor);
569 for (i = 1; i <= USABLE_PARTITIONS; i++) {
570 unsigned int start, stop;
574 part = ped_disk_get_partition(disk, i);
580 start = part->geom.start * disk->dev->sector_size
581 / disk_specific->real_sector_size / disk->dev->hw_geom.sectors;
582 stop = (part->geom.end + 1)
583 * disk->dev->sector_size / disk_specific->real_sector_size
584 / disk->dev->hw_geom.sectors - 1;
587 dasd_data = part->disk_specific;
589 type = dasd_data->type;
592 p = fdasd_add_partition(disk_specific->anchor, start, stop);
597 dasd_data->part_info = (void *) p;
598 p->type = dasd_data->system;
603 if (!fdasd_prepare_labels(disk_specific->anchor, arch_specific->fd))
606 dasd_update_type(disk);
609 if (!fdasd_write_labels(disk_specific->anchor, arch_specific->fd))
620 dasd_partition_new (const PedDisk* disk, PedPartitionType part_type,
621 const PedFileSystemType* fs_type,
622 PedSector start, PedSector end)
626 part = _ped_partition_alloc(disk, part_type, fs_type, start, end);
630 part->disk_specific = ped_malloc (sizeof (DasdPartitionData));
638 dasd_partition_destroy (PedPartition* part)
640 PED_ASSERT(part != NULL, return);
642 if (ped_partition_is_active(part))
643 free(part->disk_specific);
648 dasd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
650 DasdPartitionData* dasd_data;
652 PED_ASSERT(part != NULL, return 0);
653 PED_ASSERT(part->disk_specific != NULL, return 0);
654 dasd_data = part->disk_specific;
657 case PED_PARTITION_RAID:
660 dasd_data->raid = state;
661 return ped_partition_set_system(part, part->fs_type);
662 case PED_PARTITION_LVM:
665 dasd_data->lvm = state;
666 return ped_partition_set_system(part, part->fs_type);
673 dasd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
675 DasdPartitionData* dasd_data;
677 PED_ASSERT (part != NULL, return 0);
678 PED_ASSERT (part->disk_specific != NULL, return 0);
679 dasd_data = part->disk_specific;
682 case PED_PARTITION_RAID:
683 return dasd_data->raid;
684 case PED_PARTITION_LVM:
685 return dasd_data->lvm;
692 dasd_partition_is_flag_available (const PedPartition* part,
693 PedPartitionFlag flag)
696 case PED_PARTITION_RAID:
698 case PED_PARTITION_LVM:
707 dasd_get_max_primary_partition_count (const PedDisk* disk)
709 DasdDiskSpecific* disk_specific;
711 disk_specific = disk->disk_specific;
712 /* If formated in LDL, maximum partition number is 1 */
713 if (disk_specific->format_type == 1)
716 return USABLE_PARTITIONS;
720 dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
722 *max_n = dasd_get_max_primary_partition_count(disk);
726 static PedConstraint*
727 _primary_constraint (PedDisk* disk)
729 PedAlignment start_align;
730 PedAlignment end_align;
731 PedGeometry max_geom;
732 PedSector sector_size;
733 LinuxSpecific* arch_specific;
734 DasdDiskSpecific* disk_specific;
738 arch_specific = LINUX_SPECIFIC (disk->dev);
739 disk_specific = disk->disk_specific;
740 sector_size = disk_specific->real_sector_size / disk->dev->sector_size;
742 if (!ped_alignment_init (&start_align, 0,
743 disk->dev->hw_geom.sectors * sector_size))
745 if (!ped_alignment_init (&end_align, -1,
746 disk->dev->hw_geom.sectors * sector_size))
748 if (!ped_geometry_init (&max_geom, disk->dev, 0, disk->dev->length))
751 return ped_constraint_new(&start_align, &end_align, &max_geom,
752 &max_geom, 1, disk->dev->length);
756 dasd_partition_align (PedPartition* part, const PedConstraint* constraint)
758 DasdDiskSpecific* disk_specific;
760 PED_ASSERT (part != NULL, return 0);
762 disk_specific = part->disk->disk_specific;
763 /* If formated in LDL, ignore metadata partition */
764 if (disk_specific->format_type == 1)
767 if (_ped_partition_attempt_align(part, constraint,
768 _primary_constraint(part->disk)))
771 #ifndef DISCOVER_ONLY
772 ped_exception_throw (
774 PED_EXCEPTION_CANCEL,
775 _("Unable to satisfy all constraints on the partition."));
782 dasd_partition_enumerate (PedPartition* part)
787 /* never change the partition numbers */
791 for (i = 1; i <= USABLE_PARTITIONS; i++) {
792 p = ped_disk_get_partition (part->disk, i);
799 /* failed to allocate a number */
800 ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
801 _("Unable to allocate a dasd disklabel slot"));
806 dasd_partition_set_system (PedPartition* part,
807 const PedFileSystemType* fs_type)
809 DasdPartitionData* dasd_data = part->disk_specific;
812 cyl_size=part->disk->dev->hw_geom.sectors * part->disk->dev->hw_geom.heads;
815 part->fs_type = fs_type;
817 if (dasd_data->lvm) {
818 dasd_data->system = PARTITION_LINUX_LVM;
823 if (dasd_data->raid) {
824 dasd_data->system = PARTITION_LINUX_RAID;
830 dasd_data->system = PARTITION_LINUX;
832 } else if (is_linux_swap (fs_type->name)) {
833 dasd_data->system = PARTITION_LINUX_SWAP;
836 dasd_data->system = PARTITION_LINUX;
844 dasd_alloc_metadata (PedDisk* disk)
846 PedPartition* new_part;
847 PedConstraint* constraint_any = NULL;
849 LinuxSpecific* arch_specific;
850 DasdDiskSpecific* disk_specific;
852 PED_ASSERT (disk != NULL, goto error);
853 PED_ASSERT (disk->dev != NULL, goto error);
855 arch_specific = LINUX_SPECIFIC (disk->dev);
856 disk_specific = disk->disk_specific;
858 constraint_any = ped_constraint_any (disk->dev);
860 /* If formated in LDL, the real partition starts at sector 24. */
861 if (disk_specific->format_type == 1)
864 /* Mark the start of the disk as metadata. */
865 vtoc_end = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
866 * (long long) disk_specific->real_sector_size
867 / (long long) disk->dev->sector_size) - 1;
869 new_part = ped_partition_new (disk,PED_PARTITION_METADATA,NULL,0,vtoc_end);
873 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
874 ped_partition_destroy (new_part);
878 ped_constraint_destroy (constraint_any);
882 ped_constraint_destroy (constraint_any);