OSDN Git Service

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