1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
   2 
   3     libparted - a library for manipulating disk partitions
   4     Copyright (C) 2000, 2001, 2007 Free Software Foundation, Inc.
   5 
   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.
  10 
  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.
  15 
  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/>.
  18 
  19     Contributor:  Matt Wilson <msw@redhat.com>
  20 */
  21 
  22 #include <config.h>
  23 
  24 #include <parted/parted.h>
  25 #include <parted/debug.h>
  26 #include <parted/endian.h>
  27 
  28 #if ENABLE_NLS
  29 #  include <libintl.h>
  30 #  define _(String) dgettext (PACKAGE, String)
  31 #else
  32 #  define _(String) (String)
  33 #endif /* ENABLE_NLS */
  34 
  35 /* struct's & #define's stolen from libfdisk, which probably came from
  36  * Linux...
  37  */
  38 
  39 #define BSD_DISKMAGIC   (0x82564557UL)  /* The disk magic number */
  40 #define BSD_MAXPARTITIONS       8
  41 #define BSD_FS_UNUSED           0       /* disklabel unused partition entry ID */
  42 #define BSD_LABEL_OFFSET        64
  43 
  44 #define BSD_DTYPE_SMD           1               /* SMD, XSMD; VAX hp/up */
  45 #define BSD_DTYPE_MSCP          2               /* MSCP */
  46 #define BSD_DTYPE_DEC           3               /* other DEC (rk, rl) */
  47 #define BSD_DTYPE_SCSI          4               /* SCSI */
  48 #define BSD_DTYPE_ESDI          5               /* ESDI interface */
  49 #define BSD_DTYPE_ST506         6               /* ST506 etc. */
  50 #define BSD_DTYPE_HPIB          7               /* CS/80 on HP-IB */
  51 #define BSD_DTYPE_HPFL          8               /* HP Fiber-link */
  52 #define BSD_DTYPE_FLOPPY        10              /* floppy */
  53 
  54 #define BSD_BBSIZE      8192            /* size of boot area, with label */
  55 #define BSD_SBSIZE      8192            /* max size of fs superblock */
  56 
  57 typedef struct _BSDRawPartition         BSDRawPartition;
  58 typedef struct _BSDRawLabel             BSDRawLabel;
  59 
  60 #ifdef __sun
  61 #define __attribute__(X)        /*nothing*/
  62 #endif /* __sun */
  63 
  64 #ifdef __sun
  65 #pragma pack(1)
  66 #endif
  67 struct _BSDRawPartition {               /* the partition table */
  68         uint32_t        p_size;         /* number of sectors in partition */
  69         uint32_t        p_offset;       /* starting sector */
  70         uint32_t        p_fsize;        /* file system basic fragment size */
  71         uint8_t         p_fstype;       /* file system type, see below */
  72         uint8_t         p_frag;         /* file system fragments per block */
  73         uint16_t        p_cpg;          /* file system cylinders per group */
  74 } __attribute__((packed));
  75 #ifdef __sun
  76 #pragma pack()
  77 #endif
  78 
  79 #ifdef __sun
  80 #pragma pack(1)
  81 #endif
  82 struct _BSDRawLabel {
  83         uint32_t        d_magic;                /* the magic number */
  84         int16_t         d_type;                 /* drive type */
  85         int16_t         d_subtype;              /* controller/d_type specific */
  86         int8_t          d_typename[16];         /* type name, e.g. "eagle" */
  87         int8_t          d_packname[16];         /* pack identifier */ 
  88         uint32_t        d_secsize;              /* # of bytes per sector */
  89         uint32_t        d_nsectors;             /* # of data sectors per track */
  90         uint32_t        d_ntracks;              /* # of tracks per cylinder */
  91         uint32_t        d_ncylinders;           /* # of data cylinders per unit */
  92         uint32_t        d_secpercyl;            /* # of data sectors per cylinder */
  93         uint32_t        d_secperunit;           /* # of data sectors per unit */
  94         uint16_t        d_sparespertrack;       /* # of spare sectors per track */
  95         uint16_t        d_sparespercyl;         /* # of spare sectors per cylinder */
  96         uint32_t        d_acylinders;           /* # of alt. cylinders per unit */
  97         uint16_t        d_rpm;                  /* rotational speed */
  98         uint16_t        d_interleave;           /* hardware sector interleave */
  99         uint16_t        d_trackskew;            /* sector 0 skew, per track */
 100         uint16_t        d_cylskew;              /* sector 0 skew, per cylinder */
 101         uint32_t        d_headswitch;           /* head switch time, usec */
 102         uint32_t        d_trkseek;              /* track-to-track seek, usec */
 103         uint32_t        d_flags;                /* generic flags */
 104 #define NDDATA 5
 105         uint32_t        d_drivedata[NDDATA];    /* drive-type specific information */
 106 #define NSPARE 5
 107         uint32_t        d_spare[NSPARE];        /* reserved for future use */
 108         uint32_t        d_magic2;               /* the magic number (again) */
 109         uint16_t        d_checksum;             /* xor of data incl. partitions */
 110         
 111         /* file system and partition information: */
 112         uint16_t        d_npartitions;          /* number of partitions in following */
 113         uint32_t        d_bbsize;               /* size of boot area at sn0, bytes */
 114         uint32_t        d_sbsize;               /* max size of fs superblock, bytes */
 115         BSDRawPartition d_partitions[BSD_MAXPARTITIONS];        /* actually may be more */
 116 } __attribute__((packed));
 117 #ifdef __sun
 118 #pragma pack()
 119 #endif
 120 
 121 typedef struct {
 122         char            boot_code [512];
 123 } BSDDiskData;
 124 
 125 typedef struct {
 126         uint8_t         type;
 127 } BSDPartitionData;
 128 
 129 static PedDiskType bsd_disk_type;
 130 
 131 /* XXX fixme: endian? */
 132 static unsigned short
 133 xbsd_dkcksum (BSDRawLabel *lp) {
 134         unsigned short *start, *end;
 135         unsigned short sum = 0;
 136         
 137         lp->d_checksum = 0;
 138         start = (u_short*) lp;
 139         end = (u_short*) &lp->d_partitions [
 140                                 PED_LE16_TO_CPU (lp->d_npartitions)];
 141         while (start < end)
 142                 sum ^= *start++;
 143         return sum;
 144 }
 145 
 146 /* XXX fixme: endian? */
 147 static void
 148 alpha_bootblock_checksum (char *boot) {
 149         uint64_t *dp, sum;
 150         int i;
 151         
 152         dp = (uint64_t *)boot;
 153         sum = 0;
 154         for (i = 0; i < 63; i++)
 155                 sum += dp[i];
 156         dp[63] = sum;
 157 }
 158 
 159 
 160 static int
 161 bsd_probe (const PedDevice *dev)
 162 {
 163         char            boot[512];
 164         BSDRawLabel     *label;
 165 
 166         PED_ASSERT (dev != NULL, return 0);
 167 
 168         if (dev->sector_size != 512)
 169                 return 0;
 170 
 171         if (!ped_device_read (dev, boot, 0, 1))
 172                 return 0;
 173 
 174         label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);
 175 
 176         alpha_bootblock_checksum(boot);
 177         
 178         /* check magic */
 179         if (PED_LE32_TO_CPU (label->d_magic) != BSD_DISKMAGIC)
 180                 return 0;
 181 
 182         return 1;
 183 }
 184 
 185 static PedDisk*
 186 bsd_alloc (const PedDevice* dev)
 187 {
 188         PedDisk*        disk;
 189         BSDDiskData*    bsd_specific;
 190         BSDRawLabel*    label;
 191 
 192         PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return 0);
 193 
 194         disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type);
 195         if (!disk)
 196                 goto error;
 197         disk->disk_specific = bsd_specific = ped_malloc (sizeof (BSDDiskData));
 198         if (!bsd_specific)
 199                 goto error_free_disk;
 200         /* Initialize the first byte to zero, so that the code in bsd_write
 201            knows to call _probe_and_add_boot_code.  Initializing all of the
 202            remaining buffer is a little wasteful, but the alternative is to
 203            figure out why a block at offset 340 would otherwise be used
 204            uninitialized.  */
 205         memset(bsd_specific->boot_code, 0, sizeof (bsd_specific->boot_code));
 206 
 207         label = (BSDRawLabel*) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
 208 
 209         label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
 210         label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
 211         label->d_flags = 0;
 212         label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size);
 213         label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
 214         label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
 215         label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
 216         label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
 217                                                 * dev->bios_geom.heads);
 218         label->d_secperunit
 219                 = PED_CPU_TO_LE32 (dev->bios_geom.sectors
 220                                    * dev->bios_geom.heads
 221                                    * dev->bios_geom.cylinders);
 222         
 223         label->d_rpm = PED_CPU_TO_LE16 (3600);
 224         label->d_interleave = PED_CPU_TO_LE16 (1);;
 225         label->d_trackskew = 0;
 226         label->d_cylskew = 0;
 227         label->d_headswitch = 0;
 228         label->d_trkseek = 0;
 229         
 230         label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
 231         label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
 232         label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
 233         
 234         label->d_npartitions = 0;
 235         label->d_checksum = xbsd_dkcksum (label);
 236         return disk;
 237 
 238 error_free_disk:
 239         ped_free (disk);
 240 error:
 241         return NULL;
 242 }
 243 
 244 static PedDisk*
 245 bsd_duplicate (const PedDisk* disk)
 246 {
 247         PedDisk*        new_disk;
 248         BSDDiskData*    new_bsd_data;
 249         BSDDiskData*    old_bsd_data = (BSDDiskData*) disk->disk_specific;
 250        
 251         new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
 252         if (!new_disk)
 253                 return NULL;
 254 
 255         new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
 256         memcpy (new_bsd_data->boot_code, old_bsd_data->boot_code, 512);
 257         return new_disk;
 258 }
 259 
 260 static void
 261 bsd_free (PedDisk* disk)
 262 {
 263         ped_free (disk->disk_specific);
 264         _ped_disk_free (disk);
 265 }
 266 
 267 #ifndef DISCOVER_ONLY
 268 static int
 269 bsd_clobber (PedDevice* dev)
 270 {
 271         char            boot [512];
 272         BSDRawLabel*    label = (BSDRawLabel *) (boot + BSD_LABEL_OFFSET);
 273 
 274         if (!ped_device_read (dev, boot, 0, 1))
 275                 return 0;
 276         label->d_magic = 0;
 277         return ped_device_write (dev, (void*) boot, 0, 1);
 278 }
 279 #endif /* !DISCOVER_ONLY */
 280 
 281 static int
 282 bsd_read (PedDisk* disk)
 283 {
 284         BSDDiskData*    bsd_specific = (BSDDiskData*) disk->disk_specific;
 285         BSDRawLabel*    label;
 286         int             i;
 287         
 288         ped_disk_delete_all (disk);
 289 
 290         if (!ped_device_read (disk->dev, bsd_specific->boot_code, 0, 1))
 291                 goto error;
 292         label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
 293 
 294         for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
 295                 PedPartition*           part;
 296                 BSDPartitionData*       bsd_part_data;
 297                 PedSector               start;
 298                 PedSector               end;
 299                 PedConstraint*          constraint_exact;
 300 
 301                 if (!label->d_partitions[i - 1].p_size
 302                     || !label->d_partitions[i - 1].p_fstype)
 303                         continue;
 304                 start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
 305                 end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
 306                       + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
 307                 part = ped_partition_new (disk, 0, NULL, start, end);
 308                 if (!part)
 309                         goto error;
 310                 bsd_part_data = part->disk_specific;
 311                 bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
 312                 part->num = i;
 313                 part->fs_type = ped_file_system_probe (&part->geom);
 314                 
 315                 constraint_exact = ped_constraint_exact (&part->geom);
 316                 if (!ped_disk_add_partition (disk, part, constraint_exact))
 317                         goto error;
 318                 ped_constraint_destroy (constraint_exact);
 319         }
 320 
 321         return 1;
 322 
 323 error:
 324         return 0;
 325 }
 326 
 327 static void
 328 _probe_and_add_boot_code (const PedDisk* disk)
 329 {
 330         BSDDiskData*            bsd_specific;
 331         BSDRawLabel*            old_label;
 332         char                    old_boot_code [512];
 333 
 334         bsd_specific = (BSDDiskData*) disk->disk_specific;
 335         old_label = (BSDRawLabel*) (old_boot_code + BSD_LABEL_OFFSET);
 336 
 337         if (!ped_device_read (disk->dev, old_boot_code, 0, 1))
 338                 return;
 339         if (old_boot_code [0]
 340             && old_label->d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC))
 341                 memcpy (bsd_specific->boot_code, old_boot_code, 512);
 342 }
 343 
 344 #ifndef DISCOVER_ONLY
 345 static int
 346 bsd_write (const PedDisk* disk)
 347 {
 348         BSDDiskData*            bsd_specific;
 349         BSDRawLabel*            label;
 350         BSDPartitionData*       bsd_data;
 351         PedPartition*           part;
 352         int                     i;
 353         int                     max_part = 0;
 354 
 355         PED_ASSERT (disk != NULL, return 0);
 356         PED_ASSERT (disk->dev != NULL, return 0);
 357 
 358         bsd_specific = (BSDDiskData*) disk->disk_specific;
 359         label = (BSDRawLabel *) (bsd_specific->boot_code + BSD_LABEL_OFFSET);
 360 
 361         if (!bsd_specific->boot_code [0])
 362                 _probe_and_add_boot_code (disk);
 363 
 364         memset (label->d_partitions, 0,
 365                 sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);
 366 
 367         for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
 368                 part = ped_disk_get_partition (disk, i);
 369                 if (!part)
 370                         continue;
 371                 bsd_data = part->disk_specific;
 372                 label->d_partitions[i - 1].p_fstype = bsd_data->type;
 373                 label->d_partitions[i - 1].p_offset
 374                         = PED_CPU_TO_LE32 (part->geom.start);
 375                 label->d_partitions[i - 1].p_size
 376                         = PED_CPU_TO_LE32 (part->geom.length);
 377                 max_part = i;
 378         }
 379 
 380         label->d_npartitions = PED_CPU_TO_LE16 (max_part) + 1;
 381         label->d_checksum = xbsd_dkcksum (label);
 382 
 383         alpha_bootblock_checksum (bsd_specific->boot_code);
 384 
 385         if (!ped_device_write (disk->dev, (void*) bsd_specific->boot_code,
 386                                0, 1))
 387                 goto error;
 388         return ped_device_sync (disk->dev);
 389 
 390 error:
 391         return 0;
 392 }
 393 #endif /* !DISCOVER_ONLY */
 394 
 395 static PedPartition*
 396 bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
 397                    const PedFileSystemType* fs_type,
 398                    PedSector start, PedSector end)
 399 {
 400         PedPartition*           part;
 401         BSDPartitionData*       bsd_data;
 402 
 403         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
 404         if (!part)
 405                 goto error;
 406 
 407         if (ped_partition_is_active (part)) {
 408                 part->disk_specific
 409                         = bsd_data = ped_malloc (sizeof (BSDPartitionData));
 410                 if (!bsd_data)
 411                         goto error_free_part;
 412                 bsd_data->type = 0;
 413         } else {
 414                 part->disk_specific = NULL;
 415         }
 416         return part;
 417 
 418         ped_free (bsd_data);
 419 error_free_part:
 420         ped_free (part);
 421 error:
 422         return 0;
 423 }
 424 
 425 static PedPartition*
 426 bsd_partition_duplicate (const PedPartition* part)
 427 {
 428         PedPartition*           new_part;
 429         BSDPartitionData*       new_bsd_data;
 430         BSDPartitionData*       old_bsd_data;
 431 
 432         new_part = ped_partition_new (part->disk, part->type,
 433                                       part->fs_type, part->geom.start,
 434                                       part->geom.end);
 435         if (!new_part)
 436                 return NULL;
 437         new_part->num = part->num;
 438 
 439         old_bsd_data = (BSDPartitionData*) part->disk_specific;
 440         new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
 441         new_bsd_data->type = old_bsd_data->type;
 442         return new_part;
 443 }
 444 
 445 static void
 446 bsd_partition_destroy (PedPartition* part)
 447 {
 448         PED_ASSERT (part != NULL, return);
 449 
 450         if (ped_partition_is_active (part))
 451                 ped_free (part->disk_specific);
 452         _ped_partition_free (part);
 453 }
 454 
 455 static int
 456 bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
 457 {
 458         BSDPartitionData* bsd_data = part->disk_specific;
 459 
 460         part->fs_type = fs_type;
 461 
 462         if (!fs_type)
 463                 bsd_data->type = 0x8;
 464         else if (!strcmp (fs_type->name, "linux-swap"))
 465                 bsd_data->type = 0x1;
 466         else
 467                 bsd_data->type = 0x8;
 468 
 469         return 1;
 470 }
 471 
 472 static int
 473 bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
 474 {
 475         /* no flags for bsd */
 476         return 0;
 477 }
 478 
 479 static int
 480 bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
 481 {
 482         /* no flags for bsd */
 483         return 0;
 484 }
 485 
 486 static int
 487 bsd_partition_is_flag_available (const PedPartition* part,
 488                                  PedPartitionFlag flag)
 489 {
 490         /* no flags for bsd */
 491         return 0;
 492 }
 493 
 494 
 495 static int
 496 bsd_get_max_primary_partition_count (const PedDisk* disk)
 497 {
 498         return BSD_MAXPARTITIONS;
 499 }
 500 
 501 static PedConstraint*
 502 _get_constraint (const PedDevice* dev)
 503 {
 504         PedGeometry     max;
 505 
 506         ped_geometry_init (&max, dev, 1, dev->length - 1);
 507         return ped_constraint_new_from_max (&max);
 508 }
 509 
 510 static int
 511 bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
 512 {
 513         if (_ped_partition_attempt_align (part, constraint,
 514                                           _get_constraint (part->disk->dev)))
 515                 return 1;
 516 
 517 #ifndef DISCOVER_ONLY
 518         ped_exception_throw (
 519                 PED_EXCEPTION_ERROR,
 520                 PED_EXCEPTION_CANCEL,
 521                 _("Unable to satisfy all constraints on the partition."));
 522 #endif
 523         return 0;
 524 }
 525 
 526 static int
 527 bsd_partition_enumerate (PedPartition* part)
 528 {
 529         int i;
 530         PedPartition* p;
 531         
 532         /* never change the partition numbers */
 533         if (part->num != -1)
 534                 return 1;
 535         for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
 536                 p = ped_disk_get_partition (part->disk, i);
 537                 if (!p) {
 538                         part->num = i;
 539                         return 1;
 540                 }
 541         }
 542 
 543         /* failed to allocate a number */
 544 #ifndef DISCOVER_ONLY
 545         ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 546                              _("Unable to allocate a bsd disklabel slot."));
 547 #endif
 548         return 0;
 549 }
 550 
 551 static int
 552 bsd_alloc_metadata (PedDisk* disk)
 553 {
 554         PedPartition*           new_part;
 555         PedConstraint*          constraint_any = NULL;
 556 
 557         PED_ASSERT (disk != NULL, goto error);
 558         PED_ASSERT (disk->dev != NULL, goto error);
 559 
 560         constraint_any = ped_constraint_any (disk->dev);
 561 
 562         /* allocate 1 sector for the disk label at the start */
 563         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
 564         if (!new_part)
 565                 goto error;
 566 
 567         if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
 568                 ped_partition_destroy (new_part);
 569                 goto error;
 570         }
 571 
 572         ped_constraint_destroy (constraint_any);
 573         return 1;
 574 error:
 575         ped_constraint_destroy (constraint_any);
 576         return 0;
 577 }
 578 
 579 static PedDiskOps bsd_disk_ops = {
 580         .probe =                bsd_probe,
 581 #ifndef DISCOVER_ONLY
 582         .clobber =              bsd_clobber,
 583 #else
 584         .clobber =              NULL,
 585 #endif
 586         .alloc =                bsd_alloc,
 587         .duplicate =            bsd_duplicate,
 588         .free =                 bsd_free,
 589         .read =                 bsd_read,
 590 #ifndef DISCOVER_ONLY
 591         .write =                bsd_write,
 592 #else
 593         .write =                NULL,
 594 #endif
 595 
 596         .partition_new =        bsd_partition_new,
 597         .partition_duplicate =  bsd_partition_duplicate,
 598         .partition_destroy =    bsd_partition_destroy,
 599         .partition_set_system = bsd_partition_set_system,
 600         .partition_set_flag =   bsd_partition_set_flag,
 601         .partition_get_flag =   bsd_partition_get_flag,
 602         .partition_is_flag_available =  bsd_partition_is_flag_available,
 603         .partition_set_name =   NULL,
 604         .partition_get_name =   NULL,
 605         .partition_align =      bsd_partition_align,
 606         .partition_enumerate =  bsd_partition_enumerate,
 607 
 608         .alloc_metadata =       bsd_alloc_metadata,
 609         .get_max_primary_partition_count =
 610                                 bsd_get_max_primary_partition_count
 611 };
 612 
 613 static PedDiskType bsd_disk_type = {
 614         .next =                 NULL,
 615         .name =                 "bsd",
 616         .ops =                  &bsd_disk_ops,
 617         .features =             0
 618 };
 619 
 620 void
 621 ped_disk_bsd_init ()
 622 {
 623         PED_ASSERT (sizeof (BSDRawPartition) == 16, return);
 624         PED_ASSERT (sizeof (BSDRawLabel) == 276, return);
 625 
 626         ped_disk_type_register (&bsd_disk_type);
 627 }
 628 
 629 void
 630 ped_disk_bsd_done ()
 631 {
 632         ped_disk_type_unregister (&bsd_disk_type);
 633 }