OSDN Git Service

s390: avoid warnings
[android-x86/external-parted.git] / libparted / labels / dasd.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, 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:  Phil Knirsch <phil@redhat.de>
20                   Harald Hoyer <harald@redhat.de>
21 */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <time.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdbool.h>
32
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <parted/parted.h>
36 #include <parted/endian.h>
37 #include <parted/debug.h>
38
39 #include <parted/vtoc.h>
40 #include <parted/fdasd.h>
41 #include <arch/linux.h>
42
43 #include <libintl.h>
44 #if ENABLE_NLS
45 #  define _(String) dgettext (PACKAGE, String)
46 #else
47 #  define _(String) (String)
48 #endif /* ENABLE_NLS */
49
50 #include "misc.h"
51 #include "pt-tools.h"
52
53 #define PARTITION_LINUX_SWAP 0x82
54 #define PARTITION_LINUX 0x83
55 #define PARTITION_LINUX_EXT 0x85
56 #define PARTITION_LINUX_LVM 0x8e
57 #define PARTITION_LINUX_RAID 0xfd
58 #define PARTITION_LINUX_LVM_OLD 0xfe
59
60 extern void ped_disk_dasd_init ();
61 extern void ped_disk_dasd_done ();
62
63 #define DASD_NAME "dasd"
64
65 typedef struct {
66         int type;
67         int system;
68         int     raid;
69         int     lvm;
70 } DasdPartitionData;
71
72 typedef struct {
73         unsigned int format_type;
74         volume_label_t vlabel;
75 } DasdDiskSpecific;
76
77 static int dasd_probe (const PedDevice *dev);
78 static int dasd_read (PedDisk* disk);
79 static int dasd_write (const PedDisk* disk);
80
81 static PedPartition* dasd_partition_new (const PedDisk* disk,
82                                                                                  PedPartitionType part_type,
83                                                                                  const PedFileSystemType* fs_type,
84                                                                                  PedSector start,
85                                                                                  PedSector end);
86 static PedPartition* dasd_partition_duplicate (const PedPartition *part);
87 static void dasd_partition_destroy (PedPartition* part);
88 static int dasd_partition_set_flag (PedPartition* part,
89                                                                         PedPartitionFlag flag,
90                                                                         int state);
91 static int dasd_partition_get_flag (const PedPartition* part,
92                                                                         PedPartitionFlag flag);
93 static int dasd_partition_is_flag_available (const PedPartition* part,
94                                                                                          PedPartitionFlag flag);
95 static int dasd_partition_align (PedPartition* part,
96                                                                  const PedConstraint* constraint);
97 static int dasd_partition_enumerate (PedPartition* part);
98 static int dasd_get_max_primary_partition_count (const PedDisk* disk);
99 static bool dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n);
100 static PedAlignment *dasd_get_partition_alignment(const PedDisk *disk);
101
102 static PedDisk* dasd_alloc (const PedDevice* dev);
103 static PedDisk* dasd_duplicate (const PedDisk* disk);
104 static void dasd_free (PedDisk* disk);
105 static int dasd_partition_set_system (PedPartition* part,
106                                                                           const PedFileSystemType* fs_type);
107 static int dasd_alloc_metadata (PedDisk* disk);
108
109 #include "pt-common.h"
110 PT_define_limit_functions (dasd)
111
112 static PedDiskOps dasd_disk_ops = {
113         clobber:                NULL,
114         write:                  NULL_IF_DISCOVER_ONLY (dasd_write),
115
116         partition_set_name:     NULL,
117         partition_get_name:     NULL,
118
119         get_partition_alignment: dasd_get_partition_alignment,
120
121         PT_op_function_initializers (dasd)
122 };
123
124 static PedDiskType dasd_disk_type = {
125         next: NULL,
126         name: "dasd",
127         ops: &dasd_disk_ops,
128         features: 0
129 };
130
131 static PedDisk*
132 dasd_alloc (const PedDevice* dev)
133 {
134         PedDisk* disk;
135         LinuxSpecific* arch_specific;
136         DasdDiskSpecific *disk_specific;
137         char volser[7];
138
139         PED_ASSERT (dev != NULL, return NULL);
140
141         arch_specific = LINUX_SPECIFIC (dev);
142         disk = _ped_disk_alloc (dev, &dasd_disk_type);
143         if (!disk)
144                 return NULL;
145
146         disk->disk_specific = disk_specific = ped_malloc(sizeof(DasdDiskSpecific));
147         if (!disk->disk_specific) {
148                 free (disk);
149                 return NULL;
150         }
151
152         /* CDL format, newer */
153         disk_specific->format_type = 2;
154
155         /* Setup volume label (for fresh disks) */
156         snprintf(volser, sizeof(volser), "0X%04X", arch_specific->devno);
157         vtoc_volume_label_init(&disk_specific->vlabel);
158         vtoc_volume_label_set_key(&disk_specific->vlabel, "VOL1");
159         vtoc_volume_label_set_label(&disk_specific->vlabel, "VOL1");
160         vtoc_volume_label_set_volser(&disk_specific->vlabel, volser);
161         vtoc_set_cchhb(&disk_specific->vlabel.vtoc,
162                        VTOC_START_CC, VTOC_START_HH, 0x01);
163
164         return disk;
165 }
166
167 static PedDisk*
168 dasd_duplicate (const PedDisk* disk)
169 {
170         PedDisk* new_disk;
171
172         new_disk = ped_disk_new_fresh(disk->dev, &dasd_disk_type);
173
174         if (!new_disk)
175                 return NULL;
176
177         memcpy(new_disk->disk_specific, disk->disk_specific,
178                sizeof(DasdDiskSpecific));
179
180         return new_disk;
181 }
182
183 static void
184 dasd_free (PedDisk* disk)
185 {
186         PED_ASSERT(disk != NULL, return);
187         /* Don't free disk->disk_specific first, in case _ped_disk_free
188            or one of its eventual callees ever accesses it.  */
189         void *p = disk->disk_specific;
190         _ped_disk_free(disk);
191         free(p);
192 }
193
194
195 void
196 ped_disk_dasd_init ()
197 {
198         ped_disk_type_register(&dasd_disk_type);
199 }
200
201 void
202 ped_disk_dasd_done ()
203 {
204         ped_disk_type_unregister(&dasd_disk_type);
205 }
206
207 static int
208 dasd_probe (const PedDevice *dev)
209 {
210         LinuxSpecific* arch_specific;
211         struct fdasd_anchor anchor;
212
213         PED_ASSERT(dev != NULL, return 0);
214
215         if (!(dev->type == PED_DEVICE_DASD
216               || dev->type == PED_DEVICE_VIODASD
217               || dev->type == PED_DEVICE_FILE))
218                 return 0;
219
220         arch_specific = LINUX_SPECIFIC(dev);
221
222         /* add partition test here */
223         fdasd_initialize_anchor(&anchor);
224
225         fdasd_get_geometry(dev, &anchor, arch_specific->fd);
226
227         fdasd_check_api_version(&anchor, arch_specific->fd);
228
229         if (fdasd_check_volume(&anchor, arch_specific->fd))
230                 goto error_cleanup;
231
232         fdasd_cleanup(&anchor);
233
234         return 1;
235
236  error_cleanup:
237         fdasd_cleanup(&anchor);
238         ped_exception_throw(PED_EXCEPTION_ERROR,PED_EXCEPTION_IGNORE_CANCEL,
239                             "Error while probing device %s.", dev->path);
240
241         return 0;
242 }
243
244 static int
245 dasd_read (PedDisk* disk)
246 {
247         int i;
248         char str[20];
249         PedDevice* dev;
250         PedPartition* part;
251         PedFileSystemType *fs;
252         PedSector start, end;
253         PedConstraint* constraint_exact;
254         partition_info_t *p;
255         LinuxSpecific* arch_specific;
256         DasdDiskSpecific* disk_specific;
257         struct fdasd_anchor anchor;
258
259         PDEBUG;
260
261         PED_ASSERT (disk != NULL, return 0);
262         PDEBUG;
263         PED_ASSERT (disk->dev != NULL, return 0);
264         PDEBUG;
265
266         dev = disk->dev;
267
268         arch_specific = LINUX_SPECIFIC(dev);
269         disk_specific = disk->disk_specific;
270
271         PDEBUG;
272
273         fdasd_initialize_anchor(&anchor);
274
275         fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd);
276
277         /* check dasd for labels and vtoc */
278         if (fdasd_check_volume(&anchor, arch_specific->fd))
279                 goto error_close_dev;
280
281         /* Save volume label (read by fdasd_check_volume) for writing */
282         memcpy(&disk_specific->vlabel, anchor.vlabel, sizeof(volume_label_t));
283
284         if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
285                 anchor.big_disk++;
286
287         ped_disk_delete_all (disk);
288
289         bool is_ldl = strncmp(anchor.vlabel->volkey,
290                          vtoc_ebcdic_enc("LNX1", str, 4), 4) == 0;
291         bool is_cms = strncmp(anchor.vlabel->volkey,
292                          vtoc_ebcdic_enc("CMS1", str, 4), 4) == 0;
293         if (is_ldl || is_cms) {
294                 DasdPartitionData* dasd_data;
295
296                 union vollabel {
297                         volume_label_t unused;
298                         ldl_volume_label_t ldl;
299                         cms_volume_label_t cms;
300                 };
301                 union vollabel *cms_ptr1 = (union vollabel *) anchor.vlabel;
302                 cms_volume_label_t *cms_ptr = &cms_ptr1->cms;
303                 ldl_volume_label_t *ldl_ptr = &cms_ptr1->ldl;
304                 int partition_start_block;
305
306                 disk_specific->format_type = 1;
307
308                 if (is_cms && cms_ptr->usable_count >= cms_ptr->block_count)
309                         partition_start_block = 2;   /* FBA DASD */
310                 else
311                         partition_start_block = 3;   /* CKD DASD */
312
313                 if (is_ldl)
314                         start = (long long) arch_specific->real_sector_size
315                                 / (long long) disk->dev->sector_size
316                                 * (long long) partition_start_block;
317                 else if (cms_ptr->disk_offset == 0)
318                         start = (long long) cms_ptr->block_size
319                                 / (long long) disk->dev->sector_size
320                                 * (long long) partition_start_block;
321                 else
322                         start = (long long) cms_ptr->block_size
323                                 / (long long) disk->dev->sector_size
324                                 * (long long) cms_ptr->disk_offset;
325
326                 if (is_ldl)
327                    if (strncmp(ldl_ptr->ldl_version,
328                                vtoc_ebcdic_enc("2", str, 1), 1) >= 0)
329                       end = (long long) arch_specific->real_sector_size
330                             / (long long) disk->dev->sector_size
331                             * (long long) ldl_ptr->formatted_blocks - 1;
332                    else
333                       end = disk->dev->length - 1;
334                 else
335                    if (cms_ptr->disk_offset == 0)
336                       end = (long long) cms_ptr->block_size
337                             / (long long) disk->dev->sector_size
338                             * (long long) cms_ptr->block_count - 1;
339                    else
340                       /*
341                          Frankly, I do not understand why the last block
342                          of the CMS reserved file is not included in the
343                          partition; but this is the algorithm used by the
344                          Linux kernel.  See fs/partitions/ibm.c in the
345                          Linux kernel source code.
346                       */
347                       end = (long long) cms_ptr->block_size
348                             / (long long) disk->dev->sector_size
349                             * (long long) (cms_ptr->block_count - 1) - 1;
350
351                 part = ped_partition_new (disk, PED_PARTITION_PROTECTED, NULL, start, end);
352                 if (!part)
353                         goto error_close_dev;
354
355                 part->num = 1;
356                 part->fs_type = ped_file_system_probe (&part->geom);
357                 dasd_data = part->disk_specific;
358                 dasd_data->raid = 0;
359                 dasd_data->lvm = 0;
360                 dasd_data->type = 0;
361
362                 if (!ped_disk_add_partition (disk, part, NULL))
363                         goto error_close_dev;
364
365                 fdasd_cleanup(&anchor);
366
367                 return 1;
368         }
369
370         /* CDL format, newer */
371         disk_specific->format_type = 2;
372
373         p = anchor.first;
374         PDEBUG;
375
376         for (i = 1 ; i <= USABLE_PARTITIONS; i++) {
377                 char *ch = p->f1->DS1DSNAM;
378                 DasdPartitionData* dasd_data;
379
380
381                 if (p->used != 0x01)
382                         continue;
383
384         PDEBUG;
385
386                 start = (long long)(long long) p->start_trk
387                                 * (long long) disk->dev->hw_geom.sectors
388                                 * (long long) arch_specific->real_sector_size
389                                 / (long long) disk->dev->sector_size;
390                 end   = (long long)((long long) p->end_trk + 1)
391                                 * (long long) disk->dev->hw_geom.sectors
392                                 * (long long) arch_specific->real_sector_size
393                                 / (long long) disk->dev->sector_size - 1;
394                 part = ped_partition_new(disk, PED_PARTITION_NORMAL, NULL,
395                                          start, end);
396         PDEBUG;
397
398                 if (!part)
399                         goto error_close_dev;
400
401         PDEBUG;
402
403                 part->num = i;
404                 part->fs_type = ped_file_system_probe(&part->geom);
405
406                 vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
407                 ch = strstr(p->f1->DS1DSNAM, "PART");
408
409                 if (ch != NULL) {
410                         strncpy(str, ch+9, 6);
411                         str[6] = '\0';
412                 }
413
414                 dasd_data = part->disk_specific;
415
416                 if ((strncmp(PART_TYPE_RAID, str, 6) == 0) &&
417                     (ped_file_system_probe(&part->geom) == NULL))
418                         ped_partition_set_flag(part, PED_PARTITION_RAID, 1);
419                 else
420                         ped_partition_set_flag(part, PED_PARTITION_RAID, 0);
421
422                 if ((strncmp(PART_TYPE_LVM, str, 6) == 0) &&
423                     (ped_file_system_probe(&part->geom) == NULL))
424                         ped_partition_set_flag(part, PED_PARTITION_LVM, 1);
425                 else
426                         ped_partition_set_flag(part, PED_PARTITION_LVM, 0);
427
428                 if (strncmp(PART_TYPE_SWAP, str, 6) == 0) {
429                         fs = ped_file_system_probe(&part->geom);
430                         if (fs && is_linux_swap(fs->name)) {
431                                 dasd_data->system = PARTITION_LINUX_SWAP;
432                                 PDEBUG;
433                         }
434                 }
435
436                 vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
437
438                 dasd_data->type = 0;
439
440                 constraint_exact = ped_constraint_exact (&part->geom);
441                 if (!constraint_exact)
442                         goto error_close_dev;
443                 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
444                         ped_constraint_destroy(constraint_exact);
445                         goto error_close_dev;
446                 }
447                 ped_constraint_destroy(constraint_exact);
448
449                 if (p->fspace_trk > 0) {
450                         start = (long long)((long long) p->end_trk + 1)
451                                         * (long long) disk->dev->hw_geom.sectors
452                                         * (long long) arch_specific->real_sector_size
453                                         / (long long) disk->dev->sector_size;
454                         end   = (long long)((long long) p->end_trk + 1 + p->fspace_trk)
455                                         * (long long) disk->dev->hw_geom.sectors
456                                         * (long long) arch_specific->real_sector_size
457                                         / (long long) disk->dev->sector_size - 1;
458                         part = ped_partition_new (disk, PED_PARTITION_NORMAL,
459                                                   NULL, start, end);
460
461                         if (!part)
462                                 goto error_close_dev;
463
464                         part->type = PED_PARTITION_FREESPACE;
465                         constraint_exact = ped_constraint_exact(&part->geom);
466
467                         if (!constraint_exact)
468                                 goto error_close_dev;
469                         if (!ped_disk_add_partition(disk, part, constraint_exact)) {
470                                 ped_constraint_destroy(constraint_exact);
471                                 goto error_close_dev;
472                         }
473
474                         ped_constraint_destroy (constraint_exact);
475                 }
476
477                 p = p->next;
478         }
479
480         PDEBUG;
481         fdasd_cleanup(&anchor);
482         return 1;
483
484 error_close_dev:
485         PDEBUG;
486         fdasd_cleanup(&anchor);
487         return 0;
488 }
489
490 static int
491 dasd_update_type (const PedDisk* disk, struct fdasd_anchor *anchor,
492                   partition_info_t *part_info[USABLE_PARTITIONS])
493 {
494         PedPartition* part;
495         LinuxSpecific* arch_specific;
496         DasdDiskSpecific* disk_specific;
497
498         arch_specific = LINUX_SPECIFIC(disk->dev);
499         disk_specific = disk->disk_specific;
500
501         PDEBUG;
502
503         unsigned int i;
504         for (i = 1; i <= USABLE_PARTITIONS; i++) {
505                 partition_info_t *p;
506                 char *ch = NULL;
507                 DasdPartitionData* dasd_data;
508
509                 PDEBUG;
510
511                 part = ped_disk_get_partition(disk, i);
512                 if (!part)
513                         continue;
514
515                 PDEBUG;
516
517                 dasd_data = part->disk_specific;
518                 p = part_info[i - 1];
519
520                 if (!p ) {
521                         PDEBUG;
522                         continue;
523                 }
524
525                 vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
526                 ch = strstr(p->f1->DS1DSNAM, "PART");
527
528                 PDEBUG;
529                 if (ch == NULL) {
530                         vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
531                         PDEBUG;
532                         continue;
533                 }
534
535                 ch += 9;
536
537                 switch (dasd_data->system) {
538                         case PARTITION_LINUX_LVM:
539                                 PDEBUG;
540                                 strncpy(ch, PART_TYPE_LVM, 6);
541                                 break;
542                         case PARTITION_LINUX_RAID:
543                                 PDEBUG;
544                                 strncpy(ch, PART_TYPE_RAID, 6);
545                                 break;
546                         case PARTITION_LINUX:
547                                 PDEBUG;
548                                 strncpy(ch, PART_TYPE_NATIVE, 6);
549                                 break;
550                         case PARTITION_LINUX_SWAP:
551                                 PDEBUG;
552                                 strncpy(ch, PART_TYPE_SWAP, 6);
553                                 break;
554                         default:
555                                 PDEBUG;
556                                 strncpy(ch, PART_TYPE_NATIVE, 6);
557                                 break;
558                 }
559
560                 anchor->vtoc_changed++;
561                 vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
562         }
563
564         return 1;
565 }
566
567 static int
568 dasd_write (const PedDisk* disk)
569 {
570         DasdPartitionData* dasd_data;
571         PedPartition* part;
572         int i;
573         partition_info_t *p;
574         LinuxSpecific* arch_specific;
575         DasdDiskSpecific* disk_specific;
576         struct fdasd_anchor anchor;
577         partition_info_t *part_info[USABLE_PARTITIONS];
578
579         PED_ASSERT(disk != NULL, return 0);
580         PED_ASSERT(disk->dev != NULL, return 0);
581
582         arch_specific = LINUX_SPECIFIC (disk->dev);
583         disk_specific = disk->disk_specific;
584
585         PDEBUG;
586
587         /* If not formated in CDL, don't write anything. */
588         if (disk_specific->format_type == 1)
589                 return 1;
590
591         /* initialize the anchor */
592         fdasd_initialize_anchor(&anchor);
593         fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd);
594         memcpy(anchor.vlabel, &disk_specific->vlabel, sizeof(volume_label_t));
595         anchor.vlabel_changed++;
596
597         if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
598                 anchor.big_disk++;
599
600         fdasd_recreate_vtoc(&anchor);
601
602         for (i = 1; i <= USABLE_PARTITIONS; i++) {
603                 unsigned int start, stop;
604
605                 PDEBUG;
606                 part = ped_disk_get_partition(disk, i);
607                 if (!part)
608                         continue;
609
610                 PDEBUG;
611
612                 start = part->geom.start * disk->dev->sector_size
613                                 / arch_specific->real_sector_size / disk->dev->hw_geom.sectors;
614                 stop = (part->geom.end + 1)
615                            * disk->dev->sector_size / arch_specific->real_sector_size
616                            / disk->dev->hw_geom.sectors - 1;
617
618                 PDEBUG;
619                 dasd_data = part->disk_specific;
620
621                 p = fdasd_add_partition(&anchor, start, stop);
622                 if (!p) {
623                         PDEBUG;
624                         goto error;
625                 }
626                 part_info[i - 1] = p;
627                 p->type = dasd_data->system;
628         }
629
630         PDEBUG;
631
632         if (!fdasd_prepare_labels(&anchor, arch_specific->fd))
633                 goto error;
634
635         dasd_update_type(disk, &anchor, part_info);
636         PDEBUG;
637
638         if (!fdasd_write_labels(&anchor, arch_specific->fd))
639                 goto error;
640
641         fdasd_cleanup(&anchor);
642         return 1;
643
644 error:
645         PDEBUG;
646         fdasd_cleanup(&anchor);
647         return 0;
648 }
649
650 static PedPartition*
651 dasd_partition_new (const PedDisk* disk, PedPartitionType part_type,
652                     const PedFileSystemType* fs_type,
653                     PedSector start, PedSector end)
654 {
655         PedPartition* part;
656
657         part = _ped_partition_alloc(disk, part_type, fs_type, start, end);
658         if (!part)
659                 goto error;
660
661         part->disk_specific = ped_malloc (sizeof (DasdPartitionData));
662         return part;
663
664 error:
665         return 0;
666 }
667
668 static PedPartition*
669 dasd_partition_duplicate (const PedPartition *part)
670 {
671         PedPartition *new_part;
672
673         new_part = ped_partition_new (part->disk, part->type, part->fs_type,
674                                       part->geom.start, part->geom.end);
675         if (!new_part)
676                 return NULL;
677         new_part->num = part->num;
678
679         memcpy(new_part->disk_specific, part->disk_specific,
680                sizeof(DasdPartitionData));
681
682         return new_part;
683 }
684
685 static void
686 dasd_partition_destroy (PedPartition* part)
687 {
688         PED_ASSERT(part != NULL, return);
689
690         if (ped_partition_is_active(part))
691                 free(part->disk_specific);
692         free(part);
693 }
694
695 static int
696 dasd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
697 {
698         DasdPartitionData* dasd_data;
699
700         PED_ASSERT(part != NULL, return 0);
701         PED_ASSERT(part->disk_specific != NULL, return 0);
702         dasd_data = part->disk_specific;
703
704         switch (flag) {
705                 case PED_PARTITION_RAID:
706                         if (state)
707                                 dasd_data->lvm = 0;
708                         dasd_data->raid = state;
709                         return ped_partition_set_system(part, part->fs_type);
710                 case PED_PARTITION_LVM:
711                         if (state)
712                                 dasd_data->raid = 0;
713                         dasd_data->lvm = state;
714                         return ped_partition_set_system(part, part->fs_type);
715                 default:
716                         return 0;
717         }
718 }
719
720 static int
721 dasd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
722 {
723         DasdPartitionData* dasd_data;
724
725         PED_ASSERT (part != NULL, return 0);
726         PED_ASSERT (part->disk_specific != NULL, return 0);
727         dasd_data = part->disk_specific;
728
729         switch (flag) {
730                 case PED_PARTITION_RAID:
731                         return dasd_data->raid;
732                 case PED_PARTITION_LVM:
733                         return dasd_data->lvm;
734                 default:
735                         return 0;
736         }
737 }
738
739 static int
740 dasd_partition_is_flag_available (const PedPartition* part,
741                                   PedPartitionFlag flag)
742 {
743         switch (flag) {
744                 case PED_PARTITION_RAID:
745                         return 1;
746                 case PED_PARTITION_LVM:
747                         return 1;
748                 default:
749                         return 0;
750         }
751 }
752
753
754 static int
755 dasd_get_max_primary_partition_count (const PedDisk* disk)
756 {
757         DasdDiskSpecific* disk_specific;
758
759         disk_specific = disk->disk_specific;
760         /* If formated in LDL, maximum partition number is 1 */
761         if (disk_specific->format_type == 1)
762                 return 1;
763
764         return USABLE_PARTITIONS;
765 }
766
767 static bool
768 dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
769 {
770         *max_n = dasd_get_max_primary_partition_count(disk);
771         return true;
772 }
773
774 static PedAlignment*
775 dasd_get_partition_alignment(const PedDisk *disk)
776 {
777         LinuxSpecific *arch_specific = LINUX_SPECIFIC(disk->dev);
778         PedSector sector_size =
779                 arch_specific->real_sector_size / disk->dev->sector_size;
780
781         return ped_alignment_new(0, disk->dev->hw_geom.sectors * sector_size);
782 }
783
784 static PedConstraint*
785 _primary_constraint (PedDisk* disk)
786 {
787         PedAlignment start_align;
788         PedAlignment end_align;
789         PedGeometry     max_geom;
790         PedSector sector_size;
791         LinuxSpecific* arch_specific;
792         DasdDiskSpecific* disk_specific;
793
794         PDEBUG;
795
796         arch_specific = LINUX_SPECIFIC (disk->dev);
797         disk_specific = disk->disk_specific;
798         sector_size = arch_specific->real_sector_size / disk->dev->sector_size;
799
800         if (!ped_alignment_init (&start_align, 0,
801                                                          disk->dev->hw_geom.sectors * sector_size))
802                 return NULL;
803         if (!ped_alignment_init (&end_align, -1,
804                                                      disk->dev->hw_geom.sectors * sector_size))
805                 return NULL;
806         if (!ped_geometry_init (&max_geom, disk->dev, 0, disk->dev->length))
807                 return NULL;
808
809         return ped_constraint_new(&start_align, &end_align, &max_geom,
810                                                           &max_geom, 1, disk->dev->length);
811 }
812
813 static int
814 dasd_partition_align (PedPartition* part, const PedConstraint* constraint)
815 {
816         DasdDiskSpecific* disk_specific;
817
818         PED_ASSERT (part != NULL, return 0);
819
820         disk_specific = part->disk->disk_specific;
821         /* If formated in LDL, ignore metadata partition */
822         if (disk_specific->format_type == 1)
823                 return 1;
824
825         if (_ped_partition_attempt_align(part, constraint,
826                                                                      _primary_constraint(part->disk)))
827                 return 1;
828
829 #ifndef DISCOVER_ONLY
830         ped_exception_throw (
831                 PED_EXCEPTION_ERROR,
832                 PED_EXCEPTION_CANCEL,
833                 _("Unable to satisfy all constraints on the partition."));
834 #endif
835
836         return 0;
837 }
838
839 static int
840 dasd_partition_enumerate (PedPartition* part)
841 {
842         int i;
843         PedPartition* p;
844
845         /* never change the partition numbers */
846         if (part->num != -1)
847                 return 1;
848
849         for (i = 1; i <= USABLE_PARTITIONS; i++) {
850                 p = ped_disk_get_partition (part->disk, i);
851                 if (!p) {
852                         part->num = i;
853                         return 1;
854                 }
855         }
856
857         /* failed to allocate a number */
858         ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
859                                                 _("Unable to allocate a dasd disklabel slot"));
860         return 0;
861 }
862
863 static int
864 dasd_partition_set_system (PedPartition* part,
865                            const PedFileSystemType* fs_type)
866 {
867         DasdPartitionData* dasd_data = part->disk_specific;
868         PedSector cyl_size;
869
870         cyl_size=part->disk->dev->hw_geom.sectors * part->disk->dev->hw_geom.heads;
871         PDEBUG;
872
873         part->fs_type = fs_type;
874
875         if (dasd_data->lvm) {
876                 dasd_data->system = PARTITION_LINUX_LVM;
877         PDEBUG;
878                 return 1;
879         }
880
881         if (dasd_data->raid) {
882                 dasd_data->system = PARTITION_LINUX_RAID;
883         PDEBUG;
884                 return 1;
885         }
886
887         if (!fs_type) {
888                 dasd_data->system = PARTITION_LINUX;
889         PDEBUG;
890         } else if (is_linux_swap (fs_type->name)) {
891                 dasd_data->system = PARTITION_LINUX_SWAP;
892         PDEBUG;
893         } else {
894                 dasd_data->system = PARTITION_LINUX;
895         PDEBUG;
896         }
897
898         return 1;
899 }
900
901 static int
902 dasd_alloc_metadata (PedDisk* disk)
903 {
904         PedPartition* new_part;
905         PedConstraint* constraint_any = NULL;
906         PedSector vtoc_end;
907         LinuxSpecific* arch_specific;
908         DasdDiskSpecific* disk_specific;
909         PedPartition* part = NULL; /* initialize solely to placate gcc */
910         PedPartition* new_part2;
911         PedSector trailing_meta_start, trailing_meta_end;
912         struct fdasd_anchor anchor;
913
914         PED_ASSERT (disk != NULL, goto error);
915         PED_ASSERT (disk->dev != NULL, goto error);
916
917         arch_specific = LINUX_SPECIFIC (disk->dev);
918         disk_specific = disk->disk_specific;
919
920         constraint_any = ped_constraint_any (disk->dev);
921
922         /* For LDL or CMS, the leading metadata ends at the sector before
923            the start of the first partition */
924         if (disk_specific->format_type == 1) {
925                 part = ped_disk_get_partition(disk, 1);
926                 vtoc_end = part->geom.start - 1;
927         }
928         else {
929                 if (disk->dev->type == PED_DEVICE_FILE)
930                         arch_specific->real_sector_size = disk->dev->sector_size;
931         /* Mark the start of the disk as metadata. */
932                 vtoc_end = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
933                                    * (long long) arch_specific->real_sector_size
934                                    / (long long) disk->dev->sector_size) - 1;
935         }
936
937         new_part = ped_partition_new (disk,PED_PARTITION_METADATA,NULL,0,vtoc_end);
938         if (!new_part)
939                 goto error;
940
941         if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
942                 ped_partition_destroy (new_part);
943                 goto error;
944         }
945
946         if (disk_specific->format_type == 1) {
947            /*
948               For LDL or CMS there may be trailing metadata as well.
949               For example: the last block of a CMS reserved file,
950               the "recomp" area of a CMS minidisk that has been
951               formatted and then formatted again with the RECOMP
952               option specifying fewer than the maximum number of
953               cylinders, a disk that was formatted at one size,
954               backed up, then restored to a larger size disk, etc.
955            */
956            trailing_meta_start = part->geom.end + 1;
957            fdasd_initialize_anchor(&anchor);
958            fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd);
959            trailing_meta_end = (long long) disk->dev->length - 1;
960            fdasd_cleanup(&anchor);
961            if (trailing_meta_end >= trailing_meta_start) {
962                 new_part2 = ped_partition_new (disk,PED_PARTITION_METADATA,
963                    NULL, trailing_meta_start, trailing_meta_end);
964                 if (!new_part2) {
965                    ped_partition_destroy (new_part);
966                    goto error;
967                 }
968                 if (!ped_disk_add_partition (disk, new_part2,
969                    constraint_any)) {
970                    ped_partition_destroy (new_part2);
971                    ped_partition_destroy (new_part);
972                    goto error;
973                 }
974            }
975         }
976
977         ped_constraint_destroy (constraint_any);
978         return 1;
979
980 error:
981         ped_constraint_destroy (constraint_any);
982         return 0;
983 }