2 * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
4 * Based on original code from fdisk:
5 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
6 * Merged with fdisk for other architectures, aeb, June 1998.
7 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> Mar 1999, Internationalization
9 #include <stdio.h> /* stderr */
10 #include <stdlib.h> /* qsort */
11 #include <string.h> /* strstr */
12 #include <unistd.h> /* write */
13 #include <sys/ioctl.h> /* ioctl */
24 * in-memory fdisk SUN stuff
26 struct fdisk_sun_label
{
27 struct fdisk_label head
; /* generic part */
28 struct sun_disklabel
*header
; /* on-disk data (pointer to cxt->firstsector) */
31 static struct fdisk_parttype sun_parttypes
[] = {
32 {SUN_TAG_UNASSIGNED
, N_("Unassigned")},
33 {SUN_TAG_BOOT
, N_("Boot")},
34 {SUN_TAG_ROOT
, N_("SunOS root")},
35 {SUN_TAG_SWAP
, N_("SunOS swap")},
36 {SUN_TAG_USR
, N_("SunOS usr")},
37 {SUN_TAG_WHOLEDISK
, N_("Whole disk")},
38 {SUN_TAG_STAND
, N_("SunOS stand")},
39 {SUN_TAG_VAR
, N_("SunOS var")},
40 {SUN_TAG_HOME
, N_("SunOS home")},
41 {SUN_TAG_ALTSCTR
, N_("SunOS alt sectors")},
42 {SUN_TAG_CACHE
, N_("SunOS cachefs")},
43 {SUN_TAG_RESERVED
, N_("SunOS reserved")},
44 {SUN_TAG_LINUX_SWAP
, N_("Linux swap")},
45 {SUN_TAG_LINUX_NATIVE
, N_("Linux native")},
46 {SUN_TAG_LINUX_LVM
, N_("Linux LVM")},
47 {SUN_TAG_LINUX_RAID
, N_("Linux raid autodetect")},
51 /* return poiter buffer with on-disk data */
52 static inline struct sun_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
56 assert(fdisk_is_label(cxt
, SUN
));
58 return ((struct fdisk_sun_label
*) cxt
->label
)->header
;
61 /* return in-memory sun fdisk data */
62 static inline struct fdisk_sun_label
*self_label(struct fdisk_context
*cxt
)
66 assert(fdisk_is_label(cxt
, SUN
));
68 return (struct fdisk_sun_label
*) cxt
->label
;
71 static void set_partition(struct fdisk_context
*cxt
, size_t i
,
72 uint32_t start
,uint32_t stop
, uint16_t sysid
)
74 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
75 struct fdisk_parttype
*t
=
76 fdisk_label_get_parttype_from_code(cxt
->label
, sysid
);
78 sunlabel
->vtoc
.infos
[i
].id
= cpu_to_be16(sysid
);
79 sunlabel
->vtoc
.infos
[i
].flags
= cpu_to_be16(0);
80 sunlabel
->partitions
[i
].start_cylinder
=
81 cpu_to_be32(start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
82 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(stop
- start
);
83 fdisk_label_set_changed(cxt
->label
, 1);
85 fdisk_info_new_partition(cxt
, i
+ 1, start
, stop
, t
);
88 static size_t count_used_partitions(struct fdisk_context
*cxt
)
90 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
95 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
96 if (sunlabel
->partitions
[i
].num_sectors
)
102 static int sun_probe_label(struct fdisk_context
*cxt
)
104 struct fdisk_sun_label
*sun
;
105 struct sun_disklabel
*sunlabel
;
112 assert(fdisk_is_label(cxt
, SUN
));
114 /* map first sector to header */
115 sun
= (struct fdisk_sun_label
*) cxt
->label
;
116 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
117 sunlabel
= sun
->header
;
119 if (be16_to_cpu(sunlabel
->magic
) != SUN_LABEL_MAGIC
) {
121 return 0; /* failed */
124 ush
= ((unsigned short *) (sunlabel
+ 1)) - 1;
125 for (csum
= 0; ush
>= (unsigned short *)sunlabel
;)
129 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong checksum. "
130 "Probably you'll have to set all the values, "
131 "e.g. heads, sectors, cylinders and partitions "
132 "or force a fresh label (s command in main menu)"));
136 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
137 cxt
->geom
.heads
= be16_to_cpu(sunlabel
->nhead
);
138 cxt
->geom
.cylinders
= be16_to_cpu(sunlabel
->ncyl
);
139 cxt
->geom
.sectors
= be16_to_cpu(sunlabel
->nsect
);
141 if (be32_to_cpu(sunlabel
->vtoc
.version
) != SUN_VTOC_VERSION
) {
142 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong version [%d]."),
143 be32_to_cpu(sunlabel
->vtoc
.version
));
146 if (be32_to_cpu(sunlabel
->vtoc
.sanity
) != SUN_VTOC_SANITY
) {
147 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
148 be32_to_cpu(sunlabel
->vtoc
.sanity
));
151 if (be16_to_cpu(sunlabel
->vtoc
.nparts
) != SUN_MAXPARTITIONS
) {
152 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
153 be16_to_cpu(sunlabel
->vtoc
.nparts
));
157 fdisk_warnx(cxt
, _("Warning: Wrong values need to be fixed up and "
158 "will be corrected by w(rite)"));
160 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
161 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
162 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
164 ush
= (unsigned short *)sunlabel
;
166 while(ush
< (unsigned short *)(&sunlabel
->csum
))
168 sunlabel
->csum
= csum
;
170 fdisk_label_set_changed(cxt
->label
, 1);
173 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
178 static void ask_geom(struct fdisk_context
*cxt
)
184 if (fdisk_ask_number(cxt
, 1, 1, 1024, _("Heads"), &res
) == 0)
185 cxt
->geom
.heads
= res
;
186 if (fdisk_ask_number(cxt
, 1, 1, 1024, _("Sectors/track"), &res
) == 0)
187 cxt
->geom
.sectors
= res
;
188 if (fdisk_ask_number(cxt
, 1, 1, USHRT_MAX
, _("Cylinders"), &res
) == 0)
189 cxt
->geom
.cylinders
= res
;
192 static int sun_create_disklabel(struct fdisk_context
*cxt
)
195 struct fdisk_sun_label
*sun
; /* libfdisk sun handler */
196 struct sun_disklabel
*sunlabel
; /* on disk data */
201 assert(fdisk_is_label(cxt
, SUN
));
203 /* map first sector to header */
204 rc
= fdisk_init_firstsector_buffer(cxt
);
208 sun
= (struct fdisk_sun_label
*) cxt
->label
;
209 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
211 sunlabel
= sun
->header
;
213 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
215 sunlabel
->magic
= cpu_to_be16(SUN_LABEL_MAGIC
);
216 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
217 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
218 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
221 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
224 if (blkdev_get_sectors(cxt
->dev_fd
, &llsectors
) == 0) {
225 int sec_fac
= cxt
->sector_size
/ 512;
228 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
229 cxt
->geom
.cylinders
= llcyls
;
230 if (cxt
->geom
.cylinders
!= llcyls
)
231 cxt
->geom
.cylinders
= ~0;
234 _("BLKGETSIZE ioctl failed on %s. "
235 "Using geometry cylinder value of %llu. "
236 "This value may be truncated for devices "
238 cxt
->dev_path
, cxt
->geom
.cylinders
);
244 sunlabel
->acyl
= cpu_to_be16(0);
245 sunlabel
->pcyl
= cpu_to_be16(cxt
->geom
.cylinders
);
246 sunlabel
->rpm
= cpu_to_be16(5400);
247 sunlabel
->intrlv
= cpu_to_be16(1);
248 sunlabel
->apc
= cpu_to_be16(0);
250 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
251 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
252 sunlabel
->ncyl
= cpu_to_be16(cxt
->geom
.cylinders
);
254 snprintf((char *) sunlabel
->label_id
, sizeof(sunlabel
->label_id
),
255 "Linux cyl %llu alt %u hd %u sec %llu",
256 cxt
->geom
.cylinders
, be16_to_cpu(sunlabel
->acyl
),
257 cxt
->geom
.heads
, cxt
->geom
.sectors
);
259 if (cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
>= 150 * 2048) {
260 ndiv
= cxt
->geom
.cylinders
- (50 * 2048 / (cxt
->geom
.heads
* cxt
->geom
.sectors
)); /* 50M swap */
262 ndiv
= cxt
->geom
.cylinders
* 2 / 3;
264 /* create the default layout only if no-script defined */
266 set_partition(cxt
, 0, 0, ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
267 SUN_TAG_LINUX_NATIVE
);
268 set_partition(cxt
, 1, ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
269 cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
271 sunlabel
->vtoc
.infos
[1].flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
273 set_partition(cxt
, 2, 0,
274 cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
279 unsigned short *ush
= (unsigned short *)sunlabel
;
280 unsigned short csum
= 0;
281 while(ush
< (unsigned short *)(&sunlabel
->csum
))
283 sunlabel
->csum
= csum
;
286 fdisk_label_set_changed(cxt
->label
, 1);
287 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
289 fdisk_sinfo(cxt
, FDISK_INFO_SUCCESS
,
290 _("Created a new Sun disklabel."));
294 static int sun_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
296 struct sun_disklabel
*sunlabel
;
301 assert(fdisk_is_label(cxt
, SUN
));
303 if (i
>= cxt
->label
->nparts_max
)
306 sunlabel
= self_disklabel(cxt
);
307 p
= &sunlabel
->vtoc
.infos
[i
];
311 p
->flags
^= cpu_to_be16(SUN_FLAG_UNMNT
);
312 fdisk_label_set_changed(cxt
->label
, 1);
315 p
->flags
^= cpu_to_be16(SUN_FLAG_RONLY
);
316 fdisk_label_set_changed(cxt
->label
, 1);
325 static void fetch_sun(struct fdisk_context
*cxt
,
331 struct sun_disklabel
*sunlabel
;
338 assert(fdisk_is_label(cxt
, SUN
));
340 sunlabel
= self_disklabel(cxt
);
343 *stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
;
345 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
346 struct sun_partition
*part
= &sunlabel
->partitions
[i
];
347 struct sun_info
*info
= &sunlabel
->vtoc
.infos
[i
];
349 if (part
->num_sectors
&&
350 be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
&&
351 be16_to_cpu(info
->id
) != SUN_TAG_WHOLEDISK
) {
352 starts
[i
] = be32_to_cpu(part
->start_cylinder
) *
353 cxt
->geom
.heads
* cxt
->geom
.sectors
;
354 lens
[i
] = be32_to_cpu(part
->num_sectors
);
356 if (starts
[i
] == *start
)
358 else if (starts
[i
] + lens
[i
] >= *stop
)
362 /* There will be probably more gaps
363 than one, so lets check afterwards */
373 static int verify_sun_cmp(int *a
, int *b
, void *data
)
375 unsigned int *verify_sun_starts
= (unsigned int *) data
;
381 if (verify_sun_starts
[*a
] > verify_sun_starts
[*b
])
387 static int sun_verify_disklabel(struct fdisk_context
*cxt
)
389 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
], start
, stop
;
390 uint32_t i
,j
,k
,starto
,endo
;
392 int array
[SUN_MAXPARTITIONS
];
393 unsigned int *verify_sun_starts
;
397 assert(fdisk_is_label(cxt
, SUN
));
399 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
401 for (k
= 0; k
< 7; k
++) {
402 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
403 if (k
&& (lens
[i
] % (cxt
->geom
.heads
* cxt
->geom
.sectors
)))
404 fdisk_warnx(cxt
, _("Partition %u doesn't end on cylinder boundary."), i
+1);
406 for (j
= 0; j
< i
; j
++)
408 if (starts
[j
] == starts
[i
]+lens
[i
]) {
409 starts
[j
] = starts
[i
]; lens
[j
] += lens
[i
];
411 } else if (starts
[i
] == starts
[j
]+lens
[j
]){
415 if (starts
[i
] < starts
[j
]+lens
[j
] &&
416 starts
[j
] < starts
[i
]+lens
[i
]) {
418 if (starts
[j
] > starto
)
420 endo
= starts
[i
]+lens
[i
];
421 if (starts
[j
]+lens
[j
] < endo
)
422 endo
= starts
[j
]+lens
[j
];
423 fdisk_warnx(cxt
, _("Partition %u overlaps with others in "
424 "sectors %u-%u."), i
+1, starto
, endo
);
433 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
439 verify_sun_starts
= starts
;
441 qsort_r(array
,ARRAY_SIZE(array
),sizeof(array
[0]),
442 (int (*)(const void *,const void *,void *)) verify_sun_cmp
,
445 if (array
[0] == -1) {
446 fdisk_info(cxt
, _("No partitions defined."));
449 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
;
450 if (starts
[array
[0]])
451 fdisk_warnx(cxt
, _("Unused gap - sectors 0-%u."), starts
[array
[0]]);
452 for (i
= 0; i
< 7 && array
[i
+1] != -1; i
++) {
453 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."),
454 (starts
[array
[i
]] + lens
[array
[i
]]),
457 start
= (starts
[array
[i
]] + lens
[array
[i
]]);
459 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."), start
, stop
);
465 static int is_free_sector(struct fdisk_context
*cxt
,
466 sector_t s
, uint32_t starts
[], uint32_t lens
[])
470 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
471 if (lens
[i
] && starts
[i
] <= s
472 && starts
[i
] + lens
[i
] > s
)
478 static int sun_add_partition(
479 struct fdisk_context
*cxt
,
480 struct fdisk_partition
*pa
,
483 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
484 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
];
485 struct sun_partition
*part
;
486 struct sun_info
*info
;
487 uint32_t start
, stop
, stop2
;
489 int sys
= pa
&& pa
->type
? pa
->type
->code
: SUN_TAG_LINUX_NATIVE
;
495 unsigned int first
, last
;
497 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
501 part
= &sunlabel
->partitions
[n
];
502 info
= &sunlabel
->vtoc
.infos
[n
];
504 if (part
->num_sectors
&& be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
) {
505 fdisk_info(cxt
, _("Partition %zu is already defined. Delete "
506 "it before re-adding it."), n
+ 1);
510 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
516 fdisk_info(cxt
, _("Other partitions already cover the "
517 "whole disk. Delete some/shrink them before retry."));
522 if (pa
&& pa
->start_follow_default
)
524 else if (pa
&& fdisk_partition_has_start(pa
)) {
527 if (!whole_disk
&& !is_free_sector(cxt
, first
, starts
, lens
))
530 struct fdisk_ask
*ask
;
532 snprintf(mesg
, sizeof(mesg
), _("First %s"),
533 fdisk_get_unit(cxt
, FDISK_SINGULAR
));
535 ask
= fdisk_new_ask();
539 fdisk_ask_set_query(ask
, mesg
);
540 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
543 fdisk_ask_number_set_low(ask
, 0); /* minimal */
544 fdisk_ask_number_set_default(ask
, 0); /* default */
545 fdisk_ask_number_set_high(ask
, 0); /* maximal */
547 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, start
)); /* minimal */
548 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, start
)); /* default */
549 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
551 rc
= fdisk_do_ask(cxt
, ask
);
552 first
= fdisk_ask_number_get_result(ask
);
557 if (fdisk_use_cylinders(cxt
))
558 first
*= fdisk_get_units_per_sector(cxt
);
560 /* ewt asks to add: "don't start a partition at cyl 0"
561 However, edmundo@rano.demon.co.uk writes:
562 "In addition to having a Sun partition table, to be able to
563 boot from the disc, the first partition, /dev/sdX1, must
564 start at cylinder 0. This means that /dev/sdX1 contains
565 the partition table and the boot block, as these are the
566 first two sectors of the disc. Therefore you must be
567 careful what you use /dev/sdX1 for. In particular, you must
568 not use a partition starting at cylinder 0 for Linux swap,
569 as that would overwrite the partition table and the boot
570 block. You may, however, use such a partition for a UFS
571 or EXT2 file system, as these file systems leave the first
572 1024 bytes undisturbed. */
573 /* On the other hand, one should not use partitions
574 starting at block 0 in an md, or the label will
576 if (!is_free_sector(cxt
, first
, starts
, lens
) && !whole_disk
) {
577 if (n
== 2 && !first
) {
581 fdisk_warnx(cxt
, _("Sector %d is already allocated"), first
);
587 if (n
== 2 && first
!= 0)
588 fdisk_warnx(cxt
, _("It is highly recommended that the "
589 "third partition covers the whole disk "
590 "and is of type `Whole disk'"));
592 if (!fdisk_use_cylinders(cxt
)) {
593 /* Starting sector has to be properly aligned */
594 int cs
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
598 fdisk_info(cxt
, _("Aligning the first sector from %u to %u "
599 "to be on cylinder boundary."),
600 first
, first
+ cs
- x
);
605 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
; /* ancient */
607 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
608 if (starts
[i
] > first
&& starts
[i
] < stop
)
613 if (pa
&& pa
->end_follow_default
)
614 last
= whole_disk
|| (n
== 2 && !first
) ? stop2
: stop
;
615 else if (pa
&& fdisk_partition_has_size(pa
)) {
616 last
= first
+ pa
->size
- 1ULL;
618 if (!whole_disk
&& last
> stop
)
621 struct fdisk_ask
*ask
= fdisk_new_ask();
626 snprintf(mesg
, sizeof(mesg
),
627 _("Last %s or +%s or +size{K,M,G,T,P}"),
628 fdisk_get_unit(cxt
, FDISK_SINGULAR
),
629 fdisk_get_unit(cxt
, FDISK_PLURAL
));
630 fdisk_ask_set_query(ask
, mesg
);
631 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
634 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, stop2
)); /* minimal */
635 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
636 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
637 fdisk_ask_number_set_base(ask
, 0);
638 } else if (n
== 2 && !first
) {
639 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
640 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
641 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
642 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
644 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
645 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop
)); /* default */
646 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
647 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
650 if (fdisk_use_cylinders(cxt
))
651 fdisk_ask_number_set_unit(ask
,
653 fdisk_get_units_per_sector(cxt
));
655 fdisk_ask_number_set_unit(ask
, cxt
->sector_size
);
657 rc
= fdisk_do_ask(cxt
, ask
);
658 last
= fdisk_ask_number_get_result(ask
);
663 if (fdisk_use_cylinders(cxt
))
664 last
*= fdisk_get_units_per_sector(cxt
);
667 if (n
== 2 && !first
) {
671 } else if (last
> stop
) {
673 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
674 "%lu %s covers some other partition. Your entry has been changed\n"
676 (unsigned long) fdisk_scround(cxt
, last
), fdisk_get_unit(cxt
, FDISK_SINGULAR
),
677 (unsigned long) fdisk_scround(cxt
, stop
), fdisk_get_unit(cxt
, FDISK_SINGULAR
));
680 } else if (!whole_disk
&& last
> stop
)
684 sys
= SUN_TAG_WHOLEDISK
;
686 set_partition(cxt
, n
, first
, last
, sys
);
687 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
693 static int sun_delete_partition(struct fdisk_context
*cxt
,
696 struct sun_disklabel
*sunlabel
;
697 struct sun_partition
*part
;
698 struct sun_info
*info
;
703 assert(fdisk_is_label(cxt
, SUN
));
705 sunlabel
= self_disklabel(cxt
);
706 part
= &sunlabel
->partitions
[partnum
];
707 info
= &sunlabel
->vtoc
.infos
[partnum
];
710 be16_to_cpu(info
->id
) == SUN_TAG_WHOLEDISK
&&
711 !part
->start_cylinder
&&
712 (nsec
= be32_to_cpu(part
->num_sectors
))
713 == cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
)
714 fdisk_info(cxt
, _("If you want to maintain SunOS/Solaris compatibility, "
715 "consider leaving this "
716 "partition as Whole disk (5), starting at 0, with %u "
718 info
->id
= cpu_to_be16(SUN_TAG_UNASSIGNED
);
719 part
->num_sectors
= 0;
720 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
721 fdisk_label_set_changed(cxt
->label
, 1);
726 static int sun_list_disklabel(struct fdisk_context
*cxt
)
728 struct sun_disklabel
*sunlabel
;
732 assert(fdisk_is_label(cxt
, SUN
));
734 sunlabel
= self_disklabel(cxt
);
736 if (fdisk_is_details(cxt
)) {
738 _("Label geometry: %d rpm, %d alternate and %d physical cylinders,\n"
739 " %d extra sects/cyl, interleave %d:1"),
740 be16_to_cpu(sunlabel
->rpm
),
741 be16_to_cpu(sunlabel
->acyl
),
742 be16_to_cpu(sunlabel
->pcyl
),
743 be16_to_cpu(sunlabel
->apc
),
744 be16_to_cpu(sunlabel
->intrlv
));
745 fdisk_info(cxt
, _("Label ID: %s"), sunlabel
->label_id
);
746 fdisk_info(cxt
, _("Volume ID: %s"),
747 *sunlabel
->vtoc
.volume_id
? sunlabel
->vtoc
.volume_id
: _("<none>"));
753 static struct fdisk_parttype
*sun_get_parttype(
754 struct fdisk_context
*cxt
,
757 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
758 struct fdisk_parttype
*t
;
760 if (n
>= cxt
->label
->nparts_max
)
763 t
= fdisk_label_get_parttype_from_code(cxt
->label
,
764 be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
));
765 return t
? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
), NULL
);
769 static int sun_get_partition(struct fdisk_context
*cxt
, size_t n
,
770 struct fdisk_partition
*pa
)
772 struct sun_disklabel
*sunlabel
;
773 struct sun_partition
*part
;
779 assert(fdisk_is_label(cxt
, SUN
));
781 if (n
>= cxt
->label
->nparts_max
)
784 sunlabel
= self_disklabel(cxt
);
785 part
= &sunlabel
->partitions
[n
];
787 pa
->used
= part
->num_sectors
? 1 : 0;
791 flags
= be16_to_cpu(sunlabel
->vtoc
.infos
[n
].flags
);
792 start
= be32_to_cpu(part
->start_cylinder
)
793 * cxt
->geom
.heads
* cxt
->geom
.sectors
;
794 len
= be32_to_cpu(part
->num_sectors
);
796 pa
->type
= sun_get_parttype(cxt
, n
);
797 if (pa
->type
&& pa
->type
->code
== SUN_TAG_WHOLEDISK
)
800 if (flags
& SUN_FLAG_UNMNT
|| flags
& SUN_FLAG_RONLY
) {
801 if (asprintf(&pa
->attrs
, "%c%c",
802 flags
& SUN_FLAG_UNMNT
? 'u' : ' ',
803 flags
& SUN_FLAG_RONLY
? 'r' : ' ') < 0)
808 pa
->end
= start
+ len
- (len
? 1 : 0);
815 int fdisk_sun_set_alt_cyl(struct fdisk_context
*cxt
)
817 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
819 int rc
= fdisk_ask_number(cxt
, 0, /* low */
820 be16_to_cpu(sunlabel
->acyl
), /* default */
822 _("Number of alternate cylinders"), /* query */
827 sunlabel
->acyl
= cpu_to_be16(res
);
831 int fdisk_sun_set_xcyl(struct fdisk_context
*cxt
)
833 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
835 int rc
= fdisk_ask_number(cxt
, 0, /* low */
836 be16_to_cpu(sunlabel
->apc
), /* default */
837 cxt
->geom
.sectors
, /* high */
838 _("Extra sectors per cylinder"), /* query */
842 sunlabel
->apc
= cpu_to_be16(res
);
846 int fdisk_sun_set_ilfact(struct fdisk_context
*cxt
)
848 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
850 int rc
= fdisk_ask_number(cxt
, 1, /* low */
851 be16_to_cpu(sunlabel
->intrlv
), /* default */
853 _("Interleave factor"), /* query */
857 sunlabel
->intrlv
= cpu_to_be16(res
);
861 int fdisk_sun_set_rspeed(struct fdisk_context
*cxt
)
863 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
865 int rc
= fdisk_ask_number(cxt
, 1, /* low */
866 be16_to_cpu(sunlabel
->rpm
), /* default */
867 USHRT_MAX
, /* high */
868 _("Rotation speed (rpm)"), /* query */
872 sunlabel
->rpm
= cpu_to_be16(res
);
876 int fdisk_sun_set_pcylcount(struct fdisk_context
*cxt
)
878 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
880 int rc
= fdisk_ask_number(cxt
, 0, /* low */
881 be16_to_cpu(sunlabel
->pcyl
), /* default */
882 USHRT_MAX
, /* high */
883 _("Number of physical cylinders"), /* query */
887 sunlabel
->pcyl
= cpu_to_be16(res
);
891 static int sun_write_disklabel(struct fdisk_context
*cxt
)
893 struct sun_disklabel
*sunlabel
;
895 unsigned short csum
= 0;
896 const size_t sz
= sizeof(struct sun_disklabel
);
900 assert(fdisk_is_label(cxt
, SUN
));
902 sunlabel
= self_disklabel(cxt
);
904 /* Maybe geometry has been modified */
905 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
906 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
908 if (cxt
->geom
.cylinders
!= be16_to_cpu(sunlabel
->ncyl
))
909 sunlabel
->ncyl
= cpu_to_be16( cxt
->geom
.cylinders
910 - be16_to_cpu(sunlabel
->acyl
) );
912 ush
= (unsigned short *) sunlabel
;
914 while(ush
< (unsigned short *)(&sunlabel
->csum
))
916 sunlabel
->csum
= csum
;
917 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
919 if (write_all(cxt
->dev_fd
, sunlabel
, sz
) != 0)
925 static int sun_set_partition(
926 struct fdisk_context
*cxt
,
928 struct fdisk_partition
*pa
)
930 struct sun_disklabel
*sunlabel
;
931 struct sun_partition
*part
;
932 struct sun_info
*info
;
936 assert(fdisk_is_label(cxt
, SUN
));
938 sunlabel
= self_disklabel(cxt
);
940 if (i
>= cxt
->label
->nparts_max
)
944 struct fdisk_parttype
*t
= pa
->type
;
946 if (t
->code
> UINT16_MAX
)
949 if (i
== 2 && t
->code
!= SUN_TAG_WHOLEDISK
)
950 fdisk_info(cxt
, _("Consider leaving partition 3 as Whole disk (5),\n"
951 "as SunOS/Solaris expects it and even Linux likes it.\n"));
953 part
= &sunlabel
->partitions
[i
];
954 info
= &sunlabel
->vtoc
.infos
[i
];
956 if (cxt
->script
== NULL
&&
957 t
->code
== SUN_TAG_LINUX_SWAP
&& !part
->start_cylinder
) {
960 rc
= fdisk_ask_yesno(cxt
,
961 _("It is highly recommended that the partition at offset 0\n"
962 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
963 "there may destroy your partition table and bootblock.\n"
964 "Are you sure you want to tag the partition as Linux swap?"), &yes
);
973 case SUN_TAG_LINUX_SWAP
:
974 /* swaps are not mountable by default */
975 info
->flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
978 /* assume other types are mountable;
979 user can change it anyway */
980 info
->flags
&= ~cpu_to_be16(SUN_FLAG_UNMNT
);
983 info
->id
= cpu_to_be16(t
->code
);
986 if (fdisk_partition_has_start(pa
))
987 sunlabel
->partitions
[i
].start_cylinder
=
988 cpu_to_be32(pa
->start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
989 if (fdisk_partition_has_size(pa
))
990 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(pa
->size
);
992 fdisk_label_set_changed(cxt
->label
, 1);
997 static int sun_reset_alignment(struct fdisk_context
*cxt
__attribute__((__unused__
)))
1003 static int sun_partition_is_used(
1004 struct fdisk_context
*cxt
,
1007 struct sun_disklabel
*sunlabel
;
1011 assert(fdisk_is_label(cxt
, SUN
));
1013 if (i
>= cxt
->label
->nparts_max
)
1016 sunlabel
= self_disklabel(cxt
);
1017 return sunlabel
->partitions
[i
].num_sectors
? 1 : 0;
1020 static const struct fdisk_field sun_fields
[] =
1022 { FDISK_FIELD_DEVICE
, N_("Device"), 10, 0 },
1023 { FDISK_FIELD_START
, N_("Start"), 5, FDISK_FIELDFL_NUMBER
},
1024 { FDISK_FIELD_END
, N_("End"), 5, FDISK_FIELDFL_NUMBER
},
1025 { FDISK_FIELD_SECTORS
, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER
},
1026 { FDISK_FIELD_CYLINDERS
,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER
},
1027 { FDISK_FIELD_SIZE
, N_("Size"), 5, FDISK_FIELDFL_NUMBER
},
1028 { FDISK_FIELD_TYPEID
, N_("Id"), 2, FDISK_FIELDFL_NUMBER
},
1029 { FDISK_FIELD_TYPE
, N_("Type"), 0.1, 0 },
1030 { FDISK_FIELD_ATTR
, N_("Flags"), 0, FDISK_FIELDFL_NUMBER
}
1033 const struct fdisk_label_operations sun_operations
=
1035 .probe
= sun_probe_label
,
1036 .write
= sun_write_disklabel
,
1037 .verify
= sun_verify_disklabel
,
1038 .create
= sun_create_disklabel
,
1039 .list
= sun_list_disklabel
,
1041 .get_part
= sun_get_partition
,
1042 .set_part
= sun_set_partition
,
1043 .add_part
= sun_add_partition
,
1044 .del_part
= sun_delete_partition
,
1046 .part_is_used
= sun_partition_is_used
,
1047 .part_toggle_flag
= sun_toggle_partition_flag
,
1049 .reset_alignment
= sun_reset_alignment
,
1053 * allocates SUN label driver
1055 struct fdisk_label
*fdisk_new_sun_label(struct fdisk_context
*cxt
)
1057 struct fdisk_label
*lb
;
1058 struct fdisk_sun_label
*sun
;
1062 sun
= calloc(1, sizeof(*sun
));
1066 /* initialize generic part of the driver */
1067 lb
= (struct fdisk_label
*) sun
;
1069 lb
->id
= FDISK_DISKLABEL_SUN
;
1070 lb
->op
= &sun_operations
;
1071 lb
->parttypes
= sun_parttypes
;
1072 lb
->nparttypes
= ARRAY_SIZE(sun_parttypes
) - 1;
1073 lb
->fields
= sun_fields
;
1074 lb
->nfields
= ARRAY_SIZE(sun_fields
);
1075 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;