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, 2005, 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:  Ben Collins <bcollins@debian.org>
  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 /* Most of this came from util-linux's sun support, which was mostly done
  36    by Jakub Jelinek.  */
  37 
  38 #define SUN_DISK_MAGIC          0xDABE  /* Disk magic number */
  39 #define SUN_DISK_MAXPARTITIONS  8
  40 
  41 #define WHOLE_DISK_ID           0x05
  42 #define WHOLE_DISK_PART         2       /* as in 0, 1, 2 (3rd partition) */
  43 #define LINUX_SWAP_ID           0x82
  44 
  45 typedef struct _SunRawPartition     SunRawPartition;
  46 typedef struct _SunPartitionInfo    SunPartitionInfo;
  47 typedef struct _SunRawLabel         SunRawLabel;
  48 typedef struct _SunPartitionData    SunPartitionData;
  49 typedef struct _SunDiskData         SunDiskData;
  50 
  51 #if defined(__sun)
  52 typedef uint8_t u_int8_t;
  53 typedef uint16_t u_int16_t;
  54 typedef uint32_t u_int32_t;
  55 #endif
  56 
  57 #ifdef __sun
  58 #define __attribute__(X)        /*nothing*/
  59 #endif /* __sun */
  60 
  61 #ifdef __sun
  62 #pragma pack(1)
  63 #endif
  64 struct __attribute__ ((packed)) _SunRawPartition {
  65         u_int32_t       start_cylinder; /* where the part starts... */
  66         u_int32_t       num_sectors;    /* ...and it's length */
  67 };
  68 
  69 struct __attribute__ ((packed)) _SunPartitionInfo {
  70         u_int8_t        spare1;
  71         u_int8_t        id;             /* Partition type */
  72         u_int8_t        spare2;
  73         u_int8_t        flags;          /* Partition flags */
  74 };
  75 
  76 struct __attribute__ ((packed)) _SunRawLabel {
  77         char            info[128];      /* Informative text string */
  78         u_int8_t        spare0[14];
  79         SunPartitionInfo infos[SUN_DISK_MAXPARTITIONS];
  80         u_int8_t        spare1[246];    /* Boot information etc. */
  81         u_int16_t       rspeed;         /* Disk rotational speed */
  82         u_int16_t       pcylcount;      /* Physical cylinder count */
  83         u_int16_t       sparecyl;       /* extra sects per cylinder */
  84         u_int8_t        spare2[4];      /* More magic... */
  85         u_int16_t       ilfact;         /* Interleave factor */
  86         u_int16_t       ncyl;           /* Data cylinder count */
  87         u_int16_t       nacyl;          /* Alt. cylinder count */
  88         u_int16_t       ntrks;          /* Tracks per cylinder */
  89         u_int16_t       nsect;          /* Sectors per track */
  90         u_int8_t        spare3[4];      /* Even more magic... */
  91         SunRawPartition partitions[SUN_DISK_MAXPARTITIONS];
  92         u_int16_t       magic;          /* Magic number */
  93         u_int16_t       csum;           /* Label xor'd checksum */
  94 };
  95 #ifdef __sun
  96 #pragma pack()
  97 #endif
  98 
  99 struct _SunPartitionData {
 100         u_int8_t                type;
 101         int                     is_boot;
 102         int                     is_root;
 103         int                     is_lvm;
 104 };
 105 
 106 struct _SunDiskData {
 107         PedSector               length; /* This is based on cyl - alt-cyl */
 108         SunRawLabel             raw_label;
 109 };
 110 
 111 static PedDiskType sun_disk_type;
 112 
 113 /* Checksum computation */
 114 static void
 115 sun_compute_checksum (SunRawLabel *label)
 116 {
 117         u_int16_t *ush = (u_int16_t *)label;
 118         u_int16_t csum = 0;
 119 
 120         while(ush < (u_int16_t *)(&label->csum))
 121                 csum ^= *ush++;
 122         label->csum = csum;
 123 }
 124 
 125 /* Checksum Verification */
 126 static int
 127 sun_verify_checksum (SunRawLabel *label)
 128 {
 129         u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
 130         u_int16_t csum = 0;
 131 
 132         while (ush >= (u_int16_t *)label)
 133                 csum ^= *ush--;
 134 
 135         return !csum;
 136 }
 137 
 138 static int
 139 sun_probe (const PedDevice *dev)
 140 {
 141         SunRawLabel     label;
 142 
 143         PED_ASSERT (dev != NULL, return 0);
 144 
 145         if (dev->sector_size != 512)
 146                 return 0;
 147 
 148         if (!ped_device_read (dev, &label, 0, 1))
 149                 return 0;
 150 
 151         /* check magic */
 152         if (PED_BE16_TO_CPU (label.magic) != SUN_DISK_MAGIC)
 153                 return 0;
 154 
 155 #ifndef DISCOVER_ONLY
 156         if (!sun_verify_checksum(&label)) {
 157                 ped_exception_throw (
 158                         PED_EXCEPTION_ERROR,
 159                         PED_EXCEPTION_CANCEL,
 160                         _("Corrupted Sun disk label detected."));
 161                 return 0;
 162         }
 163 #endif
 164 
 165         return 1;
 166 }
 167 
 168 #ifndef DISCOVER_ONLY
 169 static int
 170 sun_clobber (PedDevice* dev)
 171 {
 172         SunRawLabel label;
 173 
 174         PED_ASSERT (dev != NULL, return 0);
 175         PED_ASSERT (sun_probe (dev), return 0);
 176 
 177         if (!ped_device_read (dev, &label, 0, 1))
 178                 return 0;
 179         
 180         label.magic = 0;
 181         return ped_device_write (dev, &label, 0, 1);
 182 }
 183 #endif /* !DISCOVER_ONLY */
 184 
 185 static PedDisk*
 186 sun_alloc (const PedDevice* dev)
 187 {
 188         PedDisk*        disk;
 189         SunRawLabel*    label;
 190         SunDiskData*    sun_specific;
 191         PedCHSGeometry* bios_geom = &((PedDevice*)dev)->bios_geom;
 192         PedSector       cyl_size = bios_geom->sectors * bios_geom->heads;
 193 
 194         disk = _ped_disk_alloc (dev, &sun_disk_type);
 195         if (!disk)
 196                 goto error;
 197 
 198         disk->disk_specific = (SunDiskData*) ped_malloc (sizeof (SunDiskData));
 199         if (!disk->disk_specific)
 200                 goto error_free_disk;
 201         sun_specific = (SunDiskData*) disk->disk_specific;
 202 
 203         bios_geom->cylinders = dev->length / cyl_size;
 204         sun_specific->length = bios_geom->cylinders * cyl_size;
 205 
 206         label = &sun_specific->raw_label;
 207         memset(label, 0, sizeof(SunRawLabel));
 208 
 209         /* #gentoo-sparc people agree that nacyl = 0 is the best option */
 210         label->magic = PED_CPU_TO_BE16 (SUN_DISK_MAGIC);
 211         label->nacyl = 0;
 212         label->pcylcount     = PED_CPU_TO_BE16 (bios_geom->cylinders);
 213         label->rspeed        = PED_CPU_TO_BE16 (5400);
 214         label->ilfact        = PED_CPU_TO_BE16 (1);
 215         label->sparecyl      = 0;
 216         label->ntrks = PED_CPU_TO_BE16 (bios_geom->heads);
 217         label->nsect = PED_CPU_TO_BE16 (bios_geom->sectors);
 218         label->ncyl  = PED_CPU_TO_BE16 (bios_geom->cylinders - 0);
 219 
 220         /* Add a whole disk partition at a minimum */
 221         label->infos[WHOLE_DISK_PART].id = WHOLE_DISK_ID;
 222         label->partitions[WHOLE_DISK_PART].start_cylinder = 0;
 223         label->partitions[WHOLE_DISK_PART].num_sectors =
 224                 PED_CPU_TO_BE32(bios_geom->cylinders * cyl_size);
 225 
 226         /* Now a neato string to describe this label */
 227         snprintf(label->info, sizeof(label->info) - 1,
 228                  "GNU Parted Custom cyl %d alt %d hd %d sec %d",
 229                  PED_BE16_TO_CPU(label->ncyl),
 230                  PED_BE16_TO_CPU(label->nacyl),
 231                  PED_BE16_TO_CPU(label->ntrks),
 232                  PED_BE16_TO_CPU(label->nsect));
 233 
 234         sun_compute_checksum(label);
 235         return disk;
 236 
 237 error_free_disk:
 238         _ped_disk_free (disk);
 239 error:
 240         return NULL;
 241 }
 242 
 243 static PedDisk*
 244 sun_duplicate (const PedDisk* disk)
 245 {
 246         PedDisk*        new_disk;
 247         SunDiskData*    new_sun_data;
 248         SunDiskData*    old_sun_data = (SunDiskData*) disk->disk_specific;
 249        
 250         new_disk = ped_disk_new_fresh (disk->dev, &sun_disk_type);
 251         if (!new_disk)
 252                 return NULL;
 253 
 254         new_sun_data = (SunDiskData*) new_disk->disk_specific;
 255         memcpy (new_sun_data, old_sun_data, sizeof (SunDiskData));
 256         return new_disk;
 257 }
 258 
 259 static void
 260 sun_free (PedDisk *disk)
 261 {
 262         ped_free (disk->disk_specific);
 263         _ped_disk_free (disk);
 264 }
 265 
 266 static int
 267 _check_geometry_sanity (PedDisk* disk, SunRawLabel* label)
 268 {
 269         PedDevice*      dev = disk->dev;
 270 
 271         if (PED_BE16_TO_CPU(label->nsect) == dev->hw_geom.sectors &&
 272             PED_BE16_TO_CPU(label->ntrks) == dev->hw_geom.heads)
 273                 dev->bios_geom = dev->hw_geom;
 274 
 275         if (PED_BE16_TO_CPU(label->nsect) != dev->bios_geom.sectors ||
 276             PED_BE16_TO_CPU(label->ntrks) != dev->bios_geom.heads) {
 277 #ifndef DISCOVER_ONLY
 278                 if (ped_exception_throw (
 279                                 PED_EXCEPTION_WARNING,
 280                                 PED_EXCEPTION_IGNORE_CANCEL,
 281                                 _("The disk CHS geometry (%d,%d,%d) reported "
 282                                   "by the operating system does not match "
 283                                   "the geometry stored on the disk label "
 284                                   "(%d,%d,%d)."),
 285                                 dev->bios_geom.cylinders,
 286                                 dev->bios_geom.heads,
 287                                 dev->bios_geom.sectors,
 288                                 PED_BE16_TO_CPU(label->pcylcount),
 289                                 PED_BE16_TO_CPU(label->ntrks),
 290                                 PED_BE16_TO_CPU(label->nsect))
 291                         == PED_EXCEPTION_CANCEL)
 292                         return 0;
 293 #endif
 294                 dev->bios_geom.sectors = PED_BE16_TO_CPU(label->nsect);
 295                 dev->bios_geom.heads = PED_BE16_TO_CPU(label->ntrks);
 296                 dev->bios_geom.cylinders = PED_BE16_TO_CPU(label->pcylcount);
 297 
 298                 if (dev->bios_geom.sectors * dev->bios_geom.heads
 299                                 * dev->bios_geom.cylinders > dev->length) {
 300                         if (ped_exception_throw (
 301                                 PED_EXCEPTION_WARNING,
 302                                 PED_EXCEPTION_IGNORE_CANCEL,
 303                                 _("The disk label describes a disk bigger than "
 304                                   "%s."),
 305                                 dev->path)
 306                                 != PED_EXCEPTION_IGNORE)
 307                                 return 0;
 308                 }
 309         }
 310         return 1;
 311 }
 312 
 313 static int
 314 sun_read (PedDisk* disk)
 315 {
 316         SunRawLabel* label;
 317         SunPartitionData* sun_data;
 318         SunDiskData* disk_data;
 319         int i;
 320         PedPartition* part;
 321         PedSector end, start, block;
 322         PedConstraint* constraint_exact;
 323         
 324         PED_ASSERT (disk != NULL, return 0);
 325         PED_ASSERT (disk->dev != NULL, return 0);
 326         PED_ASSERT (disk->disk_specific != NULL, return 0);
 327         
 328         disk_data = (SunDiskData*) disk->disk_specific;
 329         label = &disk_data->raw_label;
 330 
 331         ped_disk_delete_all (disk);
 332 
 333         if (!ped_device_read (disk->dev, label, 0, 1))
 334                 goto error;
 335         if (!_check_geometry_sanity (disk, label))
 336                 goto error;
 337 
 338         block = disk->dev->bios_geom.sectors * disk->dev->bios_geom.heads;
 339         disk_data->length = block * disk->dev->bios_geom.cylinders;
 340 
 341         for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
 342                 if (!PED_BE32_TO_CPU(label->partitions[i].num_sectors))
 343                         continue;
 344                 if (!label->infos[i].id)
 345                         continue;
 346                 if (label->infos[i].id == WHOLE_DISK_ID)
 347                         continue;
 348 
 349                 start = PED_BE32_TO_CPU(label->partitions[i].start_cylinder)
 350                                     * block;
 351                 end = start
 352                       + PED_BE32_TO_CPU(label->partitions[i].num_sectors) - 1;
 353 
 354                 part = ped_partition_new (disk, 0, NULL, start, end);
 355                 if (!part)
 356                         goto error;
 357 
 358                 sun_data = part->disk_specific;
 359                 sun_data->type = label->infos[i].id;
 360                 sun_data->is_boot = sun_data->type == 0x1;
 361                 sun_data->is_root = sun_data->type == 0x2;
 362                 sun_data->is_lvm = sun_data->type == 0x8e;
 363 
 364                 part->num = i + 1;
 365                 part->fs_type = ped_file_system_probe (&part->geom);
 366         
 367                 constraint_exact = ped_constraint_exact (&part->geom);
 368                 if (!ped_disk_add_partition (disk, part, constraint_exact))
 369                         goto error;
 370                 ped_constraint_destroy (constraint_exact);
 371         }
 372 
 373         return 1;
 374 
 375  error:
 376         return 0;
 377 }
 378 
 379 #ifndef DISCOVER_ONLY
 380 static void
 381 _probe_and_use_old_info (const PedDisk* disk)
 382 {
 383         SunDiskData*            sun_specific;
 384         SunRawLabel             old_label;
 385 
 386         sun_specific = (SunDiskData*) disk->disk_specific;
 387 
 388         if (!ped_device_read (disk->dev, &old_label, 0, 1))
 389                 return;
 390         if (old_label.info [0]
 391             && PED_BE16_TO_CPU (old_label.magic) == SUN_DISK_MAGIC)
 392                 memcpy (&sun_specific->raw_label, &old_label, 512);
 393 }
 394 
 395 static int
 396 sun_write (const PedDisk* disk)
 397 {
 398         SunRawLabel*            label;
 399         SunPartitionData*       sun_data;
 400         SunDiskData*            disk_data;
 401         PedPartition*           part;
 402         int                     i;
 403 
 404         PED_ASSERT (disk != NULL, return 0);
 405         PED_ASSERT (disk->dev != NULL, return 0);
 406 
 407         _probe_and_use_old_info (disk);
 408 
 409         disk_data = (SunDiskData*) disk->disk_specific;
 410         label = &disk_data->raw_label;
 411 
 412         memset (label->partitions, 0,
 413                 sizeof (SunRawPartition) * SUN_DISK_MAXPARTITIONS);
 414         memset (label->infos, 0,
 415                 sizeof (SunPartitionInfo) * SUN_DISK_MAXPARTITIONS);
 416 
 417         for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
 418                 part = ped_disk_get_partition (disk, i + 1);
 419 
 420                 if (!part && i == WHOLE_DISK_PART) {
 421                         /* Ok, nothing explicitly in the whole disk
 422                            partition, so let's put it there for safety
 423                            sake.  */
 424 
 425                         label->infos[i].id = WHOLE_DISK_ID;
 426                         label->partitions[i].start_cylinder = 0;
 427                         label->partitions[i].num_sectors = 
 428                                 PED_CPU_TO_BE32(disk_data->length);
 429                         continue;
 430                 }
 431                 if (!part)
 432                         continue;
 433 
 434                 sun_data = part->disk_specific;
 435                 label->infos[i].id = sun_data->type;
 436                 label->partitions[i].start_cylinder
 437                         = PED_CPU_TO_BE32 (part->geom.start
 438                                 / (disk->dev->bios_geom.sectors
 439                                         * disk->dev->bios_geom.heads));
 440                 label->partitions[i].num_sectors
 441                         = PED_CPU_TO_BE32 (part->geom.end
 442                                            - part->geom.start + 1);
 443         }
 444 
 445         /* We assume the harddrive is always right, and that the label may
 446            be wrong. I don't think this will cause any problems, since the
 447            cylinder count is always enforced by our alignment, and we
 448            sanity checked the sectors/heads when we detected the device. The
 449            worst that could happen here is that the drive seems bigger or
 450            smaller than it really is, but we'll have that problem even if we
 451            don't do this.  */
 452 
 453         if (disk->dev->bios_geom.cylinders > 65536) {
 454                 ped_exception_throw (
 455                         PED_EXCEPTION_WARNING,
 456                         PED_EXCEPTION_IGNORE,
 457                         _("The disk has %d cylinders, which is greater than "
 458                           "the maximum of 65536."),
 459                         disk->dev->bios_geom.cylinders);
 460         }
 461 
 462         label->pcylcount = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders);
 463         label->ncyl = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders
 464                         - PED_BE16_TO_CPU (label->nacyl));
 465 
 466         sun_compute_checksum (label);
 467 
 468         if (!ped_device_write (disk->dev, label, 0, 1))
 469                 goto error;
 470         return ped_device_sync (disk->dev);
 471 
 472 error:
 473         return 0;
 474 }
 475 #endif /* !DISCOVER_ONLY */
 476 
 477 static PedPartition*
 478 sun_partition_new (const PedDisk* disk, PedPartitionType part_type,
 479                    const PedFileSystemType* fs_type,
 480                    PedSector start, PedSector end)
 481 {
 482         PedPartition*           part;
 483         SunPartitionData*       sun_data;
 484 
 485         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
 486         if (!part)
 487                 goto error;
 488 
 489         if (ped_partition_is_active (part)) {
 490                 part->disk_specific
 491                         = sun_data = ped_malloc (sizeof (SunPartitionData));
 492                 if (!sun_data)
 493                         goto error_free_part;
 494                 sun_data->type = 0;
 495                 sun_data->is_boot = 0;
 496                 sun_data->is_root = 0;
 497                 sun_data->is_lvm = 0;
 498         } else {
 499                 part->disk_specific = NULL;
 500         }
 501 
 502         return part;
 503 
 504         ped_free (sun_data);
 505 error_free_part:
 506         ped_free (part);
 507 error:
 508         return NULL;
 509 }
 510 
 511 static PedPartition*
 512 sun_partition_duplicate (const PedPartition* part)
 513 {
 514         PedPartition*           new_part;
 515         SunPartitionData*       new_sun_data;
 516         SunPartitionData*       old_sun_data;
 517 
 518         new_part = ped_partition_new (part->disk, part->type,
 519                                       part->fs_type, part->geom.start,
 520                                       part->geom.end);
 521         if (!new_part)
 522                 return NULL;
 523         new_part->num = part->num;
 524 
 525         old_sun_data = (SunPartitionData*) part->disk_specific;
 526         new_sun_data = (SunPartitionData*) new_part->disk_specific;
 527         new_sun_data->type = old_sun_data->type;
 528         new_sun_data->is_boot = old_sun_data->is_boot;
 529         new_sun_data->is_root = old_sun_data->is_root;
 530         new_sun_data->is_lvm = old_sun_data->is_lvm;
 531         return new_part;
 532 }
 533 
 534 static void
 535 sun_partition_destroy (PedPartition* part)
 536 {
 537         PED_ASSERT (part != NULL, return);
 538 
 539         if (ped_partition_is_active (part))
 540                 ped_free (part->disk_specific);
 541         ped_free (part);
 542 }
 543 
 544 static int
 545 sun_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
 546 {
 547         SunPartitionData*               sun_data = part->disk_specific;
 548 
 549         part->fs_type = fs_type;
 550 
 551         if (sun_data->is_boot) {
 552                 sun_data->type = 0x1;
 553                 return 1;
 554         }
 555         if (sun_data->is_root) {
 556                 sun_data->type = 0x2;
 557                 return 1;
 558         }
 559         if (sun_data->is_lvm) {
 560                 sun_data->type = 0x8e;
 561                 return 1;
 562         }
 563 
 564         sun_data->type = 0x83;
 565         if (fs_type) {
 566                 if (!strcmp (fs_type->name, "linux-swap"))
 567                         sun_data->type = 0x82;
 568                 else if (!strcmp (fs_type->name, "ufs"))
 569                         sun_data->type = 0x6;
 570         }
 571 
 572         return 1;
 573 }
 574 
 575 static int
 576 sun_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
 577 {
 578         SunPartitionData*               sun_data;
 579 
 580         PED_ASSERT (part != NULL, return 0);
 581         PED_ASSERT (part->disk_specific != NULL, return 0);
 582         PED_ASSERT (ped_partition_is_flag_available (part, flag), return 0);
 583 
 584         sun_data = part->disk_specific;
 585 
 586         switch (flag) {
 587                 case PED_PARTITION_BOOT:
 588                         sun_data->is_boot = state;
 589                         if (state)
 590                                 sun_data->is_root = sun_data->is_lvm = 0;
 591                         return ped_partition_set_system (part, part->fs_type);
 592 
 593                 case PED_PARTITION_ROOT:
 594                         sun_data->is_root = state;
 595                         if (state)
 596                                 sun_data->is_boot = sun_data->is_lvm = 0;
 597                         return ped_partition_set_system (part, part->fs_type);
 598 
 599                 case PED_PARTITION_LVM:
 600                         sun_data->is_lvm = state;
 601                         if (state)
 602                                 sun_data->is_root = sun_data->is_boot = 0;
 603                         return ped_partition_set_system (part, part->fs_type);
 604 
 605                 default:
 606                         return 0;
 607         }
 608 }
 609 
 610 
 611 static int
 612 sun_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
 613 {
 614         SunPartitionData*       sun_data;
 615 
 616         PED_ASSERT (part != NULL, return 0);
 617         PED_ASSERT (part->disk_specific != NULL, return 0);
 618 
 619         sun_data = part->disk_specific;
 620 
 621         switch (flag) {
 622                 case PED_PARTITION_BOOT:
 623                         return sun_data->is_boot;
 624                 case PED_PARTITION_ROOT:
 625                         return sun_data->is_root;
 626                 case PED_PARTITION_LVM:
 627                         return sun_data->is_lvm;
 628 
 629                 default:
 630                         return 0;
 631         }
 632 }
 633 
 634 
 635 static int
 636 sun_partition_is_flag_available (const PedPartition* part,
 637                                  PedPartitionFlag flag)
 638 {
 639         switch (flag) {
 640                 case PED_PARTITION_BOOT:
 641                 case PED_PARTITION_ROOT:
 642                 case PED_PARTITION_LVM:
 643                         return 1;
 644 
 645                 default:
 646                         return 0;
 647         }
 648 }
 649 
 650 
 651 static int
 652 sun_get_max_primary_partition_count (const PedDisk* disk)
 653 {
 654         return SUN_DISK_MAXPARTITIONS;
 655 }
 656 
 657 static PedConstraint*
 658 _get_strict_constraint (PedDisk* disk)
 659 {
 660         PedDevice*      dev = disk->dev;
 661         PedAlignment    start_align;
 662         PedAlignment    end_align;
 663         PedGeometry     max_geom;
 664         SunDiskData*    disk_data = disk->disk_specific;
 665         PedSector       block = dev->bios_geom.sectors * dev->bios_geom.heads;
 666 
 667         if (!ped_alignment_init (&start_align, 0, block))
 668                 return NULL;
 669         if (!ped_alignment_init (&end_align, -1, block))
 670                 return NULL;
 671         if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length))
 672                 return NULL;
 673 
 674         return ped_constraint_new (&start_align, &end_align, &max_geom,
 675                                    &max_geom, 1, dev->length);
 676 }
 677 
 678 static PedConstraint*
 679 _get_lax_constraint (PedDisk* disk)
 680 {
 681         PedDevice*      dev = disk->dev;
 682         PedAlignment    start_align;
 683         PedGeometry     max_geom;
 684         SunDiskData*    disk_data = disk->disk_specific;
 685         PedSector       block = dev->bios_geom.sectors * dev->bios_geom.heads;
 686 
 687         if (!ped_alignment_init (&start_align, 0, block))
 688                 return NULL;
 689         if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length))
 690                 return NULL;
 691 
 692         return ped_constraint_new (&start_align, ped_alignment_any, &max_geom,
 693                                    &max_geom, 1, dev->length);
 694 }
 695 
 696 /* _get_strict_constraint() will align the partition to the end of the cylinder.
 697  * This isn't required, but since partitions must start at the start of the
 698  * cylinder, space between the end of a partition and the end of a cylinder
 699  * is unusable, so there's no point wasting space!
 700  *      However, if they really insist (via constraint)... which they will
 701  * if they're reading a weird table of the disk... then we allow the end to
 702  * be anywhere, with _get_lax_constraint()
 703  */
 704 static int
 705 sun_partition_align (PedPartition* part, const PedConstraint* constraint)
 706 {
 707         PED_ASSERT (part != NULL, return 0);
 708 
 709         if (_ped_partition_attempt_align (part, constraint,
 710                                           _get_strict_constraint (part->disk)))
 711                 return 1;
 712         if (_ped_partition_attempt_align (part, constraint,
 713                                           _get_lax_constraint (part->disk)))
 714                 return 1;
 715 
 716 #ifndef DISCOVER_ONLY
 717         ped_exception_throw (
 718                 PED_EXCEPTION_ERROR,
 719                 PED_EXCEPTION_CANCEL,
 720                 _("Unable to satisfy all constraints on the partition."));
 721 #endif
 722         return 0;
 723 }
 724 
 725 static int
 726 sun_partition_enumerate (PedPartition* part)
 727 {
 728         int i;
 729         PedPartition* p;
 730         
 731         /* never change the partition numbers */
 732         if (part->num != -1)
 733                 return 1;
 734         for (i = 1; i <= SUN_DISK_MAXPARTITIONS; i++) {
 735                 /* skip the Whole Disk partition for now */
 736                 if (i == WHOLE_DISK_PART + 1)
 737                         continue;
 738                 p = ped_disk_get_partition (part->disk, i);
 739                 if (!p) {
 740                         part->num = i;
 741                         return 1;
 742                 }
 743         }
 744 
 745 #ifndef DISCOVER_ONLY
 746         /* Ok, now allocate the Whole disk if it isn't already */
 747         p = ped_disk_get_partition (part->disk, WHOLE_DISK_PART + 1);
 748         if (!p) {
 749                 int j = ped_exception_throw (
 750                                 PED_EXCEPTION_WARNING,
 751                                 PED_EXCEPTION_IGNORE_CANCEL,
 752                                 _("The Whole Disk partition is the only "
 753                                   "available one left.  Generally, it is not a "
 754                                   "good idea to overwrite this partition with "
 755                                   "a real one.  Solaris may not be able to "
 756                                   "boot without it, and SILO (the sparc boot "
 757                                   "loader) appreciates it as well."));
 758                 if (j == PED_EXCEPTION_IGNORE) {
 759                         /* bad bad bad...you will suffer your own fate */
 760                         part->num = WHOLE_DISK_PART + 1;
 761                         return 1;
 762                 }
 763         }
 764 
 765         /* failed to allocate a number, this means we are full */
 766         ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
 767                              _("Sun disk label is full."));
 768 #endif
 769         return 0;
 770 }
 771 
 772 static int
 773 sun_alloc_metadata (PedDisk* disk)
 774 {
 775         PedPartition*   new_part;
 776         SunDiskData*    disk_data;
 777         PedConstraint*  constraint_any;
 778 
 779         PED_ASSERT (disk != NULL, return 0);
 780         PED_ASSERT (disk->disk_specific != NULL, return 0);
 781         PED_ASSERT (disk->dev != NULL, return 0);
 782 
 783         constraint_any = ped_constraint_any (disk->dev);
 784 
 785         /* Sun disk label does not need to allocate a sector. The disk
 786            label is contained within the first 512 bytes, which should not
 787            be overwritten by any boot loader or superblock. It is safe for
 788            most partitions to start at sector 0. We do however, allocate
 789            the space used by alt-cyl's, since we cannot use those. Put them
 790            at the end of the disk.  */
 791 
 792         disk_data = disk->disk_specific;
 793 
 794         if (disk->dev->length <= 0 ||
 795             disk_data->length <= 0 ||
 796             disk->dev->length == disk_data->length)
 797                 goto error;
 798 
 799         new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
 800                         disk_data->length, disk->dev->length - 1);
 801         if (!new_part)
 802                 goto error;
 803 
 804         if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
 805                 ped_partition_destroy (new_part);
 806                 goto error;
 807         }
 808 
 809         ped_constraint_destroy (constraint_any);
 810         return 1;
 811 error:
 812         ped_constraint_destroy (constraint_any);
 813         return 0;
 814 }
 815 
 816 static PedDiskOps sun_disk_ops = {
 817         .probe =                sun_probe,
 818 #ifndef DISCOVER_ONLY
 819         .clobber =              sun_clobber,
 820 #else
 821         .clobber =              NULL,
 822 #endif
 823         .alloc =                sun_alloc,
 824         .duplicate =            sun_duplicate,
 825         .free =                 sun_free,
 826         .read =                 sun_read,
 827 #ifndef DISCOVER_ONLY
 828         .write =                sun_write,
 829 #else
 830         .write =                NULL,
 831 #endif
 832 
 833         .partition_new =        sun_partition_new,
 834         .partition_duplicate =  sun_partition_duplicate,
 835         .partition_destroy =    sun_partition_destroy,
 836         .partition_set_system = sun_partition_set_system,
 837         .partition_set_flag =   sun_partition_set_flag,
 838         .partition_get_flag =   sun_partition_get_flag,
 839         .partition_is_flag_available =  sun_partition_is_flag_available,
 840         .partition_align =      sun_partition_align,
 841         .partition_enumerate =  sun_partition_enumerate,
 842         .alloc_metadata =       sun_alloc_metadata,
 843         .get_max_primary_partition_count =
 844                                 sun_get_max_primary_partition_count,
 845 
 846         .partition_set_name =   NULL,
 847         .partition_get_name =   NULL,
 848 };
 849 
 850 static PedDiskType sun_disk_type = {
 851         .next =         NULL,
 852         .name =         "sun",
 853         .ops =          &sun_disk_ops,
 854         .features =     0
 855 };
 856 
 857 void
 858 ped_disk_sun_init ()
 859 {
 860         PED_ASSERT (sizeof (SunRawLabel) == 512, return);
 861         ped_disk_type_register (&sun_disk_type);
 862 }
 863 
 864 void
 865 ped_disk_sun_done ()
 866 {
 867         ped_disk_type_unregister (&sun_disk_type);
 868 }