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: Matt Wilson <msw@redhat.com>
25 #include <parted/parted.h>
26 #include <parted/debug.h>
27 #include <parted/endian.h>
32 # define _(String) dgettext (PACKAGE, String)
34 # define _(String) (String)
35 #endif /* ENABLE_NLS */
40 /* struct's & #define's stolen from libfdisk, which probably came from
44 #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
45 #define BSD_MAXPARTITIONS 8
46 #define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
47 #define BSD_LABEL_OFFSET 64
49 #define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
50 #define BSD_DTYPE_MSCP 2 /* MSCP */
51 #define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
52 #define BSD_DTYPE_SCSI 4 /* SCSI */
53 #define BSD_DTYPE_ESDI 5 /* ESDI interface */
54 #define BSD_DTYPE_ST506 6 /* ST506 etc. */
55 #define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
56 #define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
57 #define BSD_DTYPE_FLOPPY 10 /* floppy */
59 #define BSD_BBSIZE 8192 /* size of boot area, with label */
60 #define BSD_SBSIZE 8192 /* max size of fs superblock */
62 typedef struct _BSDRawPartition BSDRawPartition;
63 typedef struct _BSDRawLabel BSDRawLabel;
65 struct _BSDRawPartition { /* the partition table */
66 uint32_t p_size; /* number of sectors in partition */
67 uint32_t p_offset; /* starting sector */
68 uint32_t p_fsize; /* file system basic fragment size */
69 uint8_t p_fstype; /* file system type, see below */
70 uint8_t p_frag; /* file system fragments per block */
71 uint16_t p_cpg; /* file system cylinders per group */
72 } __attribute__((packed));
75 uint32_t d_magic; /* the magic number */
76 int16_t d_type; /* drive type */
77 int16_t d_subtype; /* controller/d_type specific */
78 int8_t d_typename[16]; /* type name, e.g. "eagle" */
79 int8_t d_packname[16]; /* pack identifier */
80 uint32_t d_secsize; /* # of bytes per sector */
81 uint32_t d_nsectors; /* # of data sectors per track */
82 uint32_t d_ntracks; /* # of tracks per cylinder */
83 uint32_t d_ncylinders; /* # of data cylinders per unit */
84 uint32_t d_secpercyl; /* # of data sectors per cylinder */
85 uint32_t d_secperunit; /* # of data sectors per unit */
86 uint16_t d_sparespertrack; /* # of spare sectors per track */
87 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
88 uint32_t d_acylinders; /* # of alt. cylinders per unit */
89 uint16_t d_rpm; /* rotational speed */
90 uint16_t d_interleave; /* hardware sector interleave */
91 uint16_t d_trackskew; /* sector 0 skew, per track */
92 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
93 uint32_t d_headswitch; /* head switch time, usec */
94 uint32_t d_trkseek; /* track-to-track seek, usec */
95 uint32_t d_flags; /* generic flags */
97 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
99 uint32_t d_spare[NSPARE]; /* reserved for future use */
100 uint32_t d_magic2; /* the magic number (again) */
101 uint16_t d_checksum; /* xor of data incl. partitions */
103 /* file system and partition information: */
104 uint16_t d_npartitions; /* number of partitions in following */
105 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
106 uint32_t d_sbsize; /* max size of fs superblock, bytes */
107 BSDRawPartition d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
108 } __attribute__((packed));
111 char boot_code [512];
121 static PedDiskType bsd_disk_type;
123 /* XXX fixme: endian? */
124 static unsigned short
125 xbsd_dkcksum (BSDRawLabel *lp) {
126 unsigned short *start, *end;
127 unsigned short sum = 0;
130 start = (u_short*) lp;
131 end = (u_short*) &lp->d_partitions [
132 PED_LE16_TO_CPU (lp->d_npartitions)];
138 /* XXX fixme: endian? */
140 alpha_bootblock_checksum (char *boot) {
144 dp = (uint64_t *)boot;
146 for (i = 0; i < 63; i++)
152 bsd_probe (const PedDevice *dev)
154 BSDRawLabel *partition;
156 PED_ASSERT (dev != NULL, return 0);
158 if (dev->sector_size < 512)
162 if (!ptt_read_sector (dev, 0, &label))
165 partition = (BSDRawLabel *) ((char *) label + BSD_LABEL_OFFSET);
167 alpha_bootblock_checksum(label);
170 bool found = PED_LE32_TO_CPU (partition->d_magic) == BSD_DISKMAGIC;
176 bsd_alloc (const PedDevice* dev)
179 BSDDiskData* bsd_specific;
182 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
184 disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type);
187 disk->disk_specific = bsd_specific = ped_malloc (sizeof (BSDDiskData));
189 goto error_free_disk;
190 /* Initialize the first byte to zero, so that the code in bsd_write
191 knows to call _probe_and_add_boot_code. Initializing all of the
192 remaining buffer is a little wasteful, but the alternative is to
193 figure out why a block at offset 340 would otherwise be used
195 memset(bsd_specific->boot_code, 0, sizeof (bsd_specific->boot_code));
197 label = (BSDRawLabel*) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
199 label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
200 label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
202 label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size);
203 label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
204 label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
205 label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
206 label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
207 * dev->bios_geom.heads);
209 = PED_CPU_TO_LE32 (dev->bios_geom.sectors
210 * dev->bios_geom.heads
211 * dev->bios_geom.cylinders);
213 label->d_rpm = PED_CPU_TO_LE16 (3600);
214 label->d_interleave = PED_CPU_TO_LE16 (1);;
215 label->d_trackskew = 0;
216 label->d_cylskew = 0;
217 label->d_headswitch = 0;
218 label->d_trkseek = 0;
220 label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
221 label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
222 label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
224 label->d_npartitions = 0;
225 label->d_checksum = xbsd_dkcksum (label);
235 bsd_duplicate (const PedDisk* disk)
238 BSDDiskData* new_bsd_data;
239 BSDDiskData* old_bsd_data = (BSDDiskData*) disk->disk_specific;
241 new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
245 new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
246 memcpy (new_bsd_data->boot_code, old_bsd_data->boot_code, 512);
251 bsd_free (PedDisk* disk)
253 free (disk->disk_specific);
254 _ped_disk_free (disk);
257 #ifndef DISCOVER_ONLY
259 bsd_clobber (PedDevice* dev)
262 if (!ptt_read_sector (dev, 0, &label))
264 BSDRawLabel *rawlabel
265 = (BSDRawLabel *) ((char *) label + BSD_LABEL_OFFSET);
266 rawlabel->d_magic = 0;
267 return ped_device_write (dev, label, 0, 1);
269 #endif /* !DISCOVER_ONLY */
272 bsd_read (PedDisk* disk)
274 BSDDiskData* bsd_specific = (BSDDiskData*) disk->disk_specific;
278 ped_disk_delete_all (disk);
281 if (!ptt_read_sector (disk->dev, 0, &s0))
284 memcpy (bsd_specific->boot_code, s0, sizeof (bsd_specific->boot_code));
287 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
289 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
291 BSDPartitionData* bsd_part_data;
294 PedConstraint* constraint_exact;
296 if (!label->d_partitions[i - 1].p_size
297 || !label->d_partitions[i - 1].p_fstype)
299 start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
300 end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
301 + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
302 part = ped_partition_new (disk, PED_PARTITION_NORMAL,
306 bsd_part_data = part->disk_specific;
307 bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
309 part->fs_type = ped_file_system_probe (&part->geom);
311 constraint_exact = ped_constraint_exact (&part->geom);
312 if (!ped_disk_add_partition (disk, part, constraint_exact))
314 ped_constraint_destroy (constraint_exact);
324 _probe_and_add_boot_code (const PedDisk* disk)
327 if (!ptt_read_sector (disk->dev, 0, &s0))
329 char *old_boot_code = s0;
330 BSDRawLabel *old_label
331 = (BSDRawLabel*) (old_boot_code + BSD_LABEL_OFFSET);
333 if (old_boot_code [0]
334 && old_label->d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC)) {
335 BSDDiskData *bsd_specific = (BSDDiskData*) disk->disk_specific;
336 memcpy (bsd_specific->boot_code, old_boot_code,
337 sizeof (BSDDiskData));
342 #ifndef DISCOVER_ONLY
344 bsd_write (const PedDisk* disk)
346 BSDDiskData* bsd_specific;
348 BSDPartitionData* bsd_data;
353 PED_ASSERT (disk != NULL, return 0);
354 PED_ASSERT (disk->dev != NULL, return 0);
356 bsd_specific = (BSDDiskData*) disk->disk_specific;
357 label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
359 if (!bsd_specific->boot_code [0])
360 _probe_and_add_boot_code (disk);
362 memset (label->d_partitions, 0,
363 sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);
365 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
366 part = ped_disk_get_partition (disk, i);
369 bsd_data = part->disk_specific;
370 label->d_partitions[i - 1].p_fstype = bsd_data->type;
371 label->d_partitions[i - 1].p_offset
372 = PED_CPU_TO_LE32 (part->geom.start);
373 label->d_partitions[i - 1].p_size
374 = PED_CPU_TO_LE32 (part->geom.length);
378 label->d_npartitions = PED_CPU_TO_LE16 (max_part) + 1;
379 label->d_checksum = xbsd_dkcksum (label);
381 alpha_bootblock_checksum (bsd_specific->boot_code);
383 if (!ptt_write_sector (disk, bsd_specific->boot_code,
384 sizeof (BSDDiskData)))
386 return ped_device_sync (disk->dev);
391 #endif /* !DISCOVER_ONLY */
394 bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
395 const PedFileSystemType* fs_type,
396 PedSector start, PedSector end)
399 BSDPartitionData* bsd_data;
401 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
405 if (ped_partition_is_active (part)) {
407 = bsd_data = ped_malloc (sizeof (BSDPartitionData));
409 goto error_free_part;
415 part->disk_specific = NULL;
427 bsd_partition_duplicate (const PedPartition* part)
429 PedPartition* new_part;
430 BSDPartitionData* new_bsd_data;
431 BSDPartitionData* old_bsd_data;
433 new_part = ped_partition_new (part->disk, part->type,
434 part->fs_type, part->geom.start,
438 new_part->num = part->num;
440 old_bsd_data = (BSDPartitionData*) part->disk_specific;
441 new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
442 new_bsd_data->type = old_bsd_data->type;
443 new_bsd_data->boot = old_bsd_data->boot;
444 new_bsd_data->raid = old_bsd_data->raid;
445 new_bsd_data->lvm = old_bsd_data->lvm;
450 bsd_partition_destroy (PedPartition* part)
452 PED_ASSERT (part != NULL, return);
454 if (ped_partition_is_active (part))
455 free (part->disk_specific);
456 _ped_partition_free (part);
460 bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
462 BSDPartitionData* bsd_data = part->disk_specific;
464 part->fs_type = fs_type;
467 bsd_data->type = 0x8;
468 else if (is_linux_swap (fs_type->name))
469 bsd_data->type = 0x1;
471 bsd_data->type = 0x8;
477 bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
479 // PedPartition* walk; // since -Werror, this unused variable would break build
480 BSDPartitionData* bsd_data;
482 PED_ASSERT (part != NULL, return 0);
483 PED_ASSERT (part->disk_specific != NULL, return 0);
484 PED_ASSERT (part->disk != NULL, return 0);
486 bsd_data = part->disk_specific;
489 case PED_PARTITION_BOOT:
490 bsd_data->boot = state;
492 case PED_PARTITION_RAID:
496 bsd_data->raid = state;
498 case PED_PARTITION_LVM:
502 bsd_data->lvm = state;
510 bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
512 BSDPartitionData* bsd_data;
514 PED_ASSERT (part != NULL, return 0);
515 PED_ASSERT (part->disk_specific != NULL, return 0);
517 bsd_data = part->disk_specific;
519 case PED_PARTITION_BOOT:
520 return bsd_data->boot;
522 case PED_PARTITION_RAID:
523 return bsd_data->raid;
525 case PED_PARTITION_LVM:
526 return bsd_data->lvm;
535 bsd_partition_is_flag_available (const PedPartition* part,
536 PedPartitionFlag flag)
539 case PED_PARTITION_BOOT:
540 case PED_PARTITION_RAID:
541 case PED_PARTITION_LVM:
551 bsd_get_max_primary_partition_count (const PedDisk* disk)
553 return BSD_MAXPARTITIONS;
557 bsd_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
559 *max_n = BSD_MAXPARTITIONS;
563 static PedConstraint*
564 _get_constraint (const PedDevice* dev)
568 ped_geometry_init (&max, dev, 1, dev->length - 1);
569 return ped_constraint_new_from_max (&max);
573 bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
575 if (_ped_partition_attempt_align (part, constraint,
576 _get_constraint (part->disk->dev)))
579 #ifndef DISCOVER_ONLY
580 ped_exception_throw (
582 PED_EXCEPTION_CANCEL,
583 _("Unable to satisfy all constraints on the partition."));
589 bsd_partition_enumerate (PedPartition* part)
594 /* never change the partition numbers */
597 for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
598 p = ped_disk_get_partition (part->disk, i);
605 /* failed to allocate a number */
606 #ifndef DISCOVER_ONLY
607 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
608 _("Unable to allocate a bsd disklabel slot."));
614 bsd_alloc_metadata (PedDisk* disk)
616 PedPartition* new_part;
617 PedConstraint* constraint_any = NULL;
619 PED_ASSERT (disk != NULL, goto error);
620 PED_ASSERT (disk->dev != NULL, goto error);
622 constraint_any = ped_constraint_any (disk->dev);
624 /* allocate 1 sector for the disk label at the start */
625 new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
629 if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
630 ped_partition_destroy (new_part);
634 ped_constraint_destroy (constraint_any);
637 ped_constraint_destroy (constraint_any);
642 bsd_partition_check (const PedPartition* part)
647 static PedDiskOps bsd_disk_ops = {
649 #ifndef DISCOVER_ONLY
650 clobber: bsd_clobber,
655 duplicate: bsd_duplicate,
658 #ifndef DISCOVER_ONLY
664 partition_new: bsd_partition_new,
665 partition_duplicate: bsd_partition_duplicate,
666 partition_destroy: bsd_partition_destroy,
667 partition_set_system: bsd_partition_set_system,
668 partition_set_flag: bsd_partition_set_flag,
669 partition_get_flag: bsd_partition_get_flag,
670 partition_is_flag_available: bsd_partition_is_flag_available,
671 partition_set_name: NULL,
672 partition_get_name: NULL,
673 partition_align: bsd_partition_align,
674 partition_enumerate: bsd_partition_enumerate,
675 partition_check: bsd_partition_check,
677 alloc_metadata: bsd_alloc_metadata,
678 get_max_primary_partition_count:
679 bsd_get_max_primary_partition_count,
680 get_max_supported_partition_count:
681 bsd_get_max_supported_partition_count
684 static PedDiskType bsd_disk_type = {
694 PED_ASSERT (sizeof (BSDRawPartition) == 16, return);
695 PED_ASSERT (sizeof (BSDRawLabel) == 276, return);
697 ped_disk_type_register (&bsd_disk_type);
703 ped_disk_type_unregister (&bsd_disk_type);