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 */
26 * @short_description: disk label specific functions
31 * in-memory fdisk SUN stuff
33 struct fdisk_sun_label
{
34 struct fdisk_label head
; /* generic part */
35 struct sun_disklabel
*header
; /* on-disk data (pointer to cxt->firstsector) */
38 static struct fdisk_parttype sun_parttypes
[] = {
39 {SUN_TAG_UNASSIGNED
, N_("Unassigned")},
40 {SUN_TAG_BOOT
, N_("Boot")},
41 {SUN_TAG_ROOT
, N_("SunOS root")},
42 {SUN_TAG_SWAP
, N_("SunOS swap")},
43 {SUN_TAG_USR
, N_("SunOS usr")},
44 {SUN_TAG_WHOLEDISK
, N_("Whole disk")},
45 {SUN_TAG_STAND
, N_("SunOS stand")},
46 {SUN_TAG_VAR
, N_("SunOS var")},
47 {SUN_TAG_HOME
, N_("SunOS home")},
48 {SUN_TAG_ALTSCTR
, N_("SunOS alt sectors")},
49 {SUN_TAG_CACHE
, N_("SunOS cachefs")},
50 {SUN_TAG_RESERVED
, N_("SunOS reserved")},
51 {SUN_TAG_LINUX_SWAP
, N_("Linux swap")},
52 {SUN_TAG_LINUX_NATIVE
, N_("Linux native")},
53 {SUN_TAG_LINUX_LVM
, N_("Linux LVM")},
54 {SUN_TAG_LINUX_RAID
, N_("Linux raid autodetect")},
58 /* return pointer buffer with on-disk data */
59 static inline struct sun_disklabel
*self_disklabel(struct fdisk_context
*cxt
)
63 assert(fdisk_is_label(cxt
, SUN
));
65 return ((struct fdisk_sun_label
*) cxt
->label
)->header
;
68 /* return in-memory sun fdisk data */
69 static inline struct fdisk_sun_label
*self_label(struct fdisk_context
*cxt
)
73 assert(fdisk_is_label(cxt
, SUN
));
75 return (struct fdisk_sun_label
*) cxt
->label
;
78 static void set_partition(struct fdisk_context
*cxt
, size_t i
,
79 uint32_t start
,uint32_t stop
, uint16_t sysid
)
81 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
82 struct fdisk_parttype
*t
=
83 fdisk_label_get_parttype_from_code(cxt
->label
, sysid
);
85 sunlabel
->vtoc
.infos
[i
].id
= cpu_to_be16(sysid
);
86 sunlabel
->vtoc
.infos
[i
].flags
= cpu_to_be16(0);
87 sunlabel
->partitions
[i
].start_cylinder
=
88 cpu_to_be32(start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
89 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(stop
- start
);
90 fdisk_label_set_changed(cxt
->label
, 1);
92 fdisk_info_new_partition(cxt
, i
+ 1, start
, stop
, t
);
95 static size_t count_used_partitions(struct fdisk_context
*cxt
)
97 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
102 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
103 if (sunlabel
->partitions
[i
].num_sectors
)
109 static int sun_probe_label(struct fdisk_context
*cxt
)
111 struct fdisk_sun_label
*sun
;
112 struct sun_disklabel
*sunlabel
;
117 assert(fdisk_is_label(cxt
, SUN
));
119 /* map first sector to header */
120 sun
= self_label(cxt
);
121 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
122 sunlabel
= sun
->header
;
124 if (be16_to_cpu(sunlabel
->magic
) != SUN_LABEL_MAGIC
) {
126 return 0; /* failed */
129 if (sun_pt_checksum(sunlabel
)) {
130 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong checksum. "
131 "Probably you'll have to set all the values, "
132 "e.g. heads, sectors, cylinders and partitions "
133 "or force a fresh label (s command in main menu)"));
137 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
138 cxt
->geom
.heads
= be16_to_cpu(sunlabel
->nhead
);
139 cxt
->geom
.cylinders
= be16_to_cpu(sunlabel
->ncyl
);
140 cxt
->geom
.sectors
= be16_to_cpu(sunlabel
->nsect
);
142 /* we have on label geom, but user has to win */
143 if (fdisk_has_user_device_geometry(cxt
))
144 fdisk_apply_user_device_properties(cxt
);
146 if (be32_to_cpu(sunlabel
->vtoc
.version
) != SUN_VTOC_VERSION
) {
147 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong version [%d]."),
148 be32_to_cpu(sunlabel
->vtoc
.version
));
151 if (be32_to_cpu(sunlabel
->vtoc
.sanity
) != SUN_VTOC_SANITY
) {
152 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
153 be32_to_cpu(sunlabel
->vtoc
.sanity
));
156 if (be16_to_cpu(sunlabel
->vtoc
.nparts
) != SUN_MAXPARTITIONS
) {
157 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
158 be16_to_cpu(sunlabel
->vtoc
.nparts
));
162 fdisk_warnx(cxt
, _("Warning: Wrong values need to be fixed up and "
163 "will be corrected by w(rite)"));
165 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
166 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
167 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
169 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
171 fdisk_label_set_changed(cxt
->label
, 1);
174 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
179 static void ask_geom(struct fdisk_context
*cxt
)
185 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.heads
, 1,
186 cxt
->label
->geom_max
.heads
,
187 _("Heads"), &res
) == 0)
188 cxt
->geom
.heads
= res
;
190 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.sectors
, 1,
191 cxt
->label
->geom_max
.sectors
,
192 _("Sectors/track"), &res
) == 0)
193 cxt
->geom
.sectors
= res
;
195 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.cylinders
, 1,
196 cxt
->label
->geom_max
.cylinders
,
197 _("Cylinders"), &res
) == 0)
198 cxt
->geom
.cylinders
= res
;
201 static int sun_create_disklabel(struct fdisk_context
*cxt
)
204 struct fdisk_sun_label
*sun
; /* libfdisk sun handler */
205 struct sun_disklabel
*sunlabel
; /* on disk data */
210 assert(fdisk_is_label(cxt
, SUN
));
212 /* map first sector to header */
213 rc
= fdisk_init_firstsector_buffer(cxt
, 0, 0);
217 sun
= self_label(cxt
);
218 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
220 sunlabel
= sun
->header
;
222 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
224 sunlabel
->magic
= cpu_to_be16(SUN_LABEL_MAGIC
);
225 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
226 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
227 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
229 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
230 fdisk_sector_t llsectors
;
232 if (blkdev_get_sectors(cxt
->dev_fd
, (unsigned long long *) &llsectors
) == 0) {
233 int sec_fac
= cxt
->sector_size
/ 512;
234 fdisk_sector_t llcyls
;
236 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
237 cxt
->geom
.cylinders
= llcyls
;
238 if (cxt
->geom
.cylinders
!= llcyls
)
239 cxt
->geom
.cylinders
= ~0;
242 _("BLKGETSIZE ioctl failed on %s. "
243 "Using geometry cylinder value of %llu. "
244 "This value may be truncated for devices "
246 cxt
->dev_path
, cxt
->geom
.cylinders
);
251 sunlabel
->acyl
= cpu_to_be16(0);
252 sunlabel
->pcyl
= cpu_to_be16(cxt
->geom
.cylinders
);
253 sunlabel
->rpm
= cpu_to_be16(5400);
254 sunlabel
->intrlv
= cpu_to_be16(1);
255 sunlabel
->apc
= cpu_to_be16(0);
257 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
258 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
259 sunlabel
->ncyl
= cpu_to_be16(cxt
->geom
.cylinders
);
261 snprintf((char *) sunlabel
->label_id
, sizeof(sunlabel
->label_id
),
262 "Linux cyl %ju alt %u hd %u sec %ju",
263 (uintmax_t) cxt
->geom
.cylinders
,
264 be16_to_cpu(sunlabel
->acyl
),
266 (uintmax_t) cxt
->geom
.sectors
);
268 if (cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
>= 150 * 2048) {
269 ndiv
= cxt
->geom
.cylinders
- (50 * 2048 / (cxt
->geom
.heads
* cxt
->geom
.sectors
)); /* 50M swap */
271 ndiv
= cxt
->geom
.cylinders
* 2 / 3;
273 /* create the default layout only if no-script defined */
275 set_partition(cxt
, 0, 0, ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
276 SUN_TAG_LINUX_NATIVE
);
277 set_partition(cxt
, 1, ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
278 cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
280 sunlabel
->vtoc
.infos
[1].flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
282 set_partition(cxt
, 2, 0,
283 cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
288 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
290 fdisk_label_set_changed(cxt
->label
, 1);
291 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
293 fdisk_info(cxt
, _("Created a new Sun disklabel."));
297 static int sun_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
299 struct sun_disklabel
*sunlabel
;
304 assert(fdisk_is_label(cxt
, SUN
));
306 if (i
>= cxt
->label
->nparts_max
)
309 sunlabel
= self_disklabel(cxt
);
310 p
= &sunlabel
->vtoc
.infos
[i
];
314 p
->flags
^= cpu_to_be16(SUN_FLAG_UNMNT
);
315 fdisk_label_set_changed(cxt
->label
, 1);
318 p
->flags
^= cpu_to_be16(SUN_FLAG_RONLY
);
319 fdisk_label_set_changed(cxt
->label
, 1);
328 static void fetch_sun(struct fdisk_context
*cxt
,
334 struct sun_disklabel
*sunlabel
;
337 int sectors_per_cylinder
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
342 assert(fdisk_is_label(cxt
, SUN
));
344 sunlabel
= self_disklabel(cxt
);
347 *stop
= cxt
->geom
.cylinders
* sectors_per_cylinder
;
349 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
350 struct sun_partition
*part
= &sunlabel
->partitions
[i
];
351 struct sun_info
*info
= &sunlabel
->vtoc
.infos
[i
];
353 if (part
->num_sectors
&&
354 be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
&&
355 be16_to_cpu(info
->id
) != SUN_TAG_WHOLEDISK
) {
356 starts
[i
] = be32_to_cpu(part
->start_cylinder
) *
357 sectors_per_cylinder
;
358 lens
[i
] = be32_to_cpu(part
->num_sectors
);
360 if (starts
[i
] == *start
) {
362 int remained_sectors
= *start
% sectors_per_cylinder
;
363 if (remained_sectors
) {
364 *start
+= sectors_per_cylinder
- remained_sectors
;
366 } else if (starts
[i
] + lens
[i
] >= *stop
)
370 /* There will be probably more gaps
371 than one, so lets check afterwards */
380 /* non-Linux qsort_r(3) has usually differently ordered arguments */
381 #if !defined (__linux__) || !defined (__GLIBC__)
386 static int verify_sun_cmp(int *a
, int *b
, void *data
)
388 unsigned int *verify_sun_starts
= (unsigned int *) data
;
394 if (verify_sun_starts
[*a
] > verify_sun_starts
[*b
])
400 static int sun_verify_disklabel(struct fdisk_context
*cxt
)
402 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
], start
, stop
;
403 uint32_t i
,j
,k
,starto
,endo
;
405 int array
[SUN_MAXPARTITIONS
];
406 unsigned int *verify_sun_starts
;
410 assert(fdisk_is_label(cxt
, SUN
));
412 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
414 for (k
= 0; k
< 7; k
++) {
415 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
416 if (k
&& (lens
[i
] % (cxt
->geom
.heads
* cxt
->geom
.sectors
)))
417 fdisk_warnx(cxt
, _("Partition %u doesn't end on cylinder boundary."), i
+1);
419 for (j
= 0; j
< i
; j
++)
421 if (starts
[j
] == starts
[i
]+lens
[i
]) {
422 starts
[j
] = starts
[i
]; lens
[j
] += lens
[i
];
424 } else if (starts
[i
] == starts
[j
]+lens
[j
]){
428 if (starts
[i
] < starts
[j
]+lens
[j
] &&
429 starts
[j
] < starts
[i
]+lens
[i
]) {
431 if (starts
[j
] > starto
)
433 endo
= starts
[i
]+lens
[i
];
434 if (starts
[j
]+lens
[j
] < endo
)
435 endo
= starts
[j
]+lens
[j
];
436 fdisk_warnx(cxt
, _("Partition %u overlaps with others in "
437 "sectors %u-%u."), i
+1, starto
, endo
);
446 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
452 verify_sun_starts
= starts
;
454 qsort_r(array
,ARRAY_SIZE(array
),sizeof(array
[0]),
455 (int (*)(const void *,const void *,void *)) verify_sun_cmp
,
458 if (array
[0] == -1) {
459 fdisk_info(cxt
, _("No partitions defined."));
462 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
;
463 if (starts
[array
[0]])
464 fdisk_warnx(cxt
, _("Unused gap - sectors 0-%u."), starts
[array
[0]]);
465 for (i
= 0; i
< 7 && array
[i
+1] != -1; i
++) {
466 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."),
467 (starts
[array
[i
]] + lens
[array
[i
]]),
470 start
= (starts
[array
[i
]] + lens
[array
[i
]]);
472 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."), start
, stop
);
478 static int is_free_sector(struct fdisk_context
*cxt
,
479 fdisk_sector_t s
, uint32_t starts
[], uint32_t lens
[])
483 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
484 if (lens
[i
] && starts
[i
] <= s
485 && starts
[i
] + lens
[i
] > s
)
491 static int sun_add_partition(
492 struct fdisk_context
*cxt
,
493 struct fdisk_partition
*pa
,
496 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
497 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
];
498 struct sun_partition
*part
;
499 struct sun_info
*info
;
500 uint32_t start
, stop
, stop2
;
502 int sys
= pa
&& pa
->type
? pa
->type
->code
: SUN_TAG_LINUX_NATIVE
;
508 unsigned int first
, last
;
510 DBG(LABEL
, ul_debug("SUN adding partition"));
512 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
516 part
= &sunlabel
->partitions
[n
];
517 info
= &sunlabel
->vtoc
.infos
[n
];
519 if (part
->num_sectors
&& be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
) {
520 fdisk_info(cxt
, _("Partition %zu is already defined. Delete "
521 "it before re-adding it."), n
+ 1);
525 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
527 if (pa
&& pa
->type
&& pa
->type
->code
== SUN_TAG_WHOLEDISK
)
534 fdisk_info(cxt
, _("Other partitions already cover the "
535 "whole disk. Delete some/shrink them before retry."));
540 if (pa
&& pa
->start_follow_default
)
542 else if (pa
&& fdisk_partition_has_start(pa
)) {
545 if (!whole_disk
&& !is_free_sector(cxt
, first
, starts
, lens
))
548 struct fdisk_ask
*ask
;
551 fdisk_info(cxt
, _("It is highly recommended that the "
552 "third partition covers the whole disk "
553 "and is of type `Whole disk'"));
555 snprintf(mesg
, sizeof(mesg
), _("First %s"),
556 fdisk_get_unit(cxt
, FDISK_SINGULAR
));
558 ask
= fdisk_new_ask();
562 fdisk_ask_set_query(ask
, mesg
);
563 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
566 fdisk_ask_number_set_low(ask
, 0); /* minimal */
567 fdisk_ask_number_set_default(ask
, 0); /* default */
568 fdisk_ask_number_set_high(ask
, 0); /* maximal */
570 fdisk_ask_number_set_low(ask
, 0); /* minimal */
571 fdisk_ask_number_set_default(ask
, 0); /* default */
572 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
574 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, start
)); /* minimal */
575 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, start
)); /* default */
576 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
578 rc
= fdisk_do_ask(cxt
, ask
);
579 first
= fdisk_ask_number_get_result(ask
);
580 fdisk_unref_ask(ask
);
584 if (fdisk_use_cylinders(cxt
))
585 first
*= fdisk_get_units_per_sector(cxt
);
587 if (!fdisk_use_cylinders(cxt
)) {
588 /* Starting sector has to be properly aligned */
589 int cs
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
593 fdisk_info(cxt
, _("Aligning the first sector from %u to %u "
594 "to be on cylinder boundary."),
595 first
, first
+ cs
- x
);
600 /* ewt asks to add: "don't start a partition at cyl 0"
601 However, edmundo@rano.demon.co.uk writes:
602 "In addition to having a Sun partition table, to be able to
603 boot from the disc, the first partition, /dev/sdX1, must
604 start at cylinder 0. This means that /dev/sdX1 contains
605 the partition table and the boot block, as these are the
606 first two sectors of the disc. Therefore you must be
607 careful what you use /dev/sdX1 for. In particular, you must
608 not use a partition starting at cylinder 0 for Linux swap,
609 as that would overwrite the partition table and the boot
610 block. You may, however, use such a partition for a UFS
611 or EXT2 file system, as these file systems leave the first
612 1024 bytes undisturbed. */
613 /* On the other hand, one should not use partitions
614 starting at block 0 in an md, or the label will
616 if (!is_free_sector(cxt
, first
, starts
, lens
) && !whole_disk
) {
617 if (n
== 2 && !first
) {
621 fdisk_warnx(cxt
, _("Sector %d is already allocated"), first
);
627 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
; /* ancient */
629 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
630 if (starts
[i
] > first
&& starts
[i
] < stop
)
635 if (pa
&& pa
->end_follow_default
)
636 last
= whole_disk
|| (n
== 2 && !first
) ? stop2
: stop
;
638 else if (pa
&& fdisk_partition_has_size(pa
)) {
639 last
= first
+ pa
->size
;
641 if (!whole_disk
&& last
> stop
)
644 struct fdisk_ask
*ask
= fdisk_new_ask();
649 snprintf(mesg
, sizeof(mesg
),
650 _("Last %s or +/-%s or +/-size{K,M,G,T,P}"),
651 fdisk_get_unit(cxt
, FDISK_SINGULAR
),
652 fdisk_get_unit(cxt
, FDISK_PLURAL
));
653 fdisk_ask_set_query(ask
, mesg
);
654 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
657 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, stop2
)); /* minimal */
658 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
659 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
660 fdisk_ask_number_set_base(ask
, 0);
661 } else if (n
== 2 && !first
) {
662 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
663 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
664 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
665 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
667 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
668 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop
)); /* default */
669 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
670 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
673 fdisk_ask_number_set_wrap_negative(ask
, 1); /* wrap negative around high */
675 if (fdisk_use_cylinders(cxt
))
676 fdisk_ask_number_set_unit(ask
,
678 fdisk_get_units_per_sector(cxt
));
680 fdisk_ask_number_set_unit(ask
, cxt
->sector_size
);
682 rc
= fdisk_do_ask(cxt
, ask
);
683 last
= fdisk_ask_number_get_result(ask
);
685 fdisk_unref_ask(ask
);
688 if (fdisk_use_cylinders(cxt
))
689 last
*= fdisk_get_units_per_sector(cxt
);
692 if (n
== 2 && !first
) {
696 } else if (last
> stop
) {
698 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
699 "%lu %s covers some other partition. Your entry has been changed\n"
701 (unsigned long) fdisk_scround(cxt
, last
), fdisk_get_unit(cxt
, FDISK_SINGULAR
),
702 (unsigned long) fdisk_scround(cxt
, stop
), fdisk_get_unit(cxt
, FDISK_SINGULAR
));
705 } else if (!whole_disk
&& last
> stop
)
709 sys
= SUN_TAG_WHOLEDISK
;
711 DBG(LABEL
, ul_debug("SUN new partition #%zu: first=%u, last=%u, sys=%d", n
, first
, last
, sys
));
713 set_partition(cxt
, n
, first
, last
, sys
);
714 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
720 static int sun_delete_partition(struct fdisk_context
*cxt
,
723 struct sun_disklabel
*sunlabel
;
724 struct sun_partition
*part
;
725 struct sun_info
*info
;
730 assert(fdisk_is_label(cxt
, SUN
));
732 sunlabel
= self_disklabel(cxt
);
733 part
= &sunlabel
->partitions
[partnum
];
734 info
= &sunlabel
->vtoc
.infos
[partnum
];
737 be16_to_cpu(info
->id
) == SUN_TAG_WHOLEDISK
&&
738 !part
->start_cylinder
&&
739 (nsec
= be32_to_cpu(part
->num_sectors
))
740 == cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
)
741 fdisk_info(cxt
, _("If you want to maintain SunOS/Solaris compatibility, "
742 "consider leaving this "
743 "partition as Whole disk (5), starting at 0, with %u "
745 info
->id
= cpu_to_be16(SUN_TAG_UNASSIGNED
);
746 part
->num_sectors
= 0;
747 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
748 fdisk_label_set_changed(cxt
->label
, 1);
752 static int sun_get_disklabel_item(struct fdisk_context
*cxt
, struct fdisk_labelitem
*item
)
754 struct sun_disklabel
*sunlabel
;
759 assert(fdisk_is_label(cxt
, SUN
));
761 sunlabel
= self_disklabel(cxt
);
764 case SUN_LABELITEM_LABELID
:
765 item
->name
=_("Label ID");
767 item
->data
.str
= *sunlabel
->label_id
? strndup((char *)sunlabel
->label_id
, sizeof(sunlabel
->label_id
)) : NULL
;
769 case SUN_LABELITEM_VTOCID
:
770 item
->name
=_("Volume ID");
772 item
->data
.str
= *sunlabel
->vtoc
.volume_id
? strndup((char *)sunlabel
->vtoc
.volume_id
, sizeof(sunlabel
->vtoc
.volume_id
)) : NULL
;
774 case SUN_LABELITEM_RPM
:
775 item
->name
=_("Rpm");
777 item
->data
.num64
= be16_to_cpu(sunlabel
->rpm
);
779 case SUN_LABELITEM_ACYL
:
780 item
->name
=_("Alternate cylinders");
782 item
->data
.num64
= be16_to_cpu(sunlabel
->acyl
);
784 case SUN_LABELITEM_PCYL
:
785 item
->name
=_("Physical cylinders");
787 item
->data
.num64
= be16_to_cpu(sunlabel
->pcyl
);
789 case SUN_LABELITEM_APC
:
790 item
->name
=_("Extra sects/cyl");
792 item
->data
.num64
= be16_to_cpu(sunlabel
->apc
);
794 case SUN_LABELITEM_INTRLV
:
795 item
->name
=_("Interleave");
797 item
->data
.num64
= be16_to_cpu(sunlabel
->intrlv
);
800 if (item
->id
< __FDISK_NLABELITEMS
)
801 rc
= 1; /* unsupported generic item */
803 rc
= 2; /* out of range */
810 static struct fdisk_parttype
*sun_get_parttype(
811 struct fdisk_context
*cxt
,
814 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
815 struct fdisk_parttype
*t
;
817 if (n
>= cxt
->label
->nparts_max
)
820 t
= fdisk_label_get_parttype_from_code(cxt
->label
,
821 be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
));
822 return t
? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
), NULL
);
826 static int sun_get_partition(struct fdisk_context
*cxt
, size_t n
,
827 struct fdisk_partition
*pa
)
829 struct sun_disklabel
*sunlabel
;
830 struct sun_partition
*part
;
836 assert(fdisk_is_label(cxt
, SUN
));
838 if (n
>= cxt
->label
->nparts_max
)
841 sunlabel
= self_disklabel(cxt
);
842 part
= &sunlabel
->partitions
[n
];
844 pa
->used
= part
->num_sectors
? 1 : 0;
848 flags
= be16_to_cpu(sunlabel
->vtoc
.infos
[n
].flags
);
849 start
= be32_to_cpu(part
->start_cylinder
)
850 * cxt
->geom
.heads
* cxt
->geom
.sectors
;
851 len
= be32_to_cpu(part
->num_sectors
);
853 pa
->type
= sun_get_parttype(cxt
, n
);
854 if (pa
->type
&& pa
->type
->code
== SUN_TAG_WHOLEDISK
)
857 if (flags
& SUN_FLAG_UNMNT
|| flags
& SUN_FLAG_RONLY
) {
858 if (asprintf(&pa
->attrs
, "%c%c",
859 flags
& SUN_FLAG_UNMNT
? 'u' : ' ',
860 flags
& SUN_FLAG_RONLY
? 'r' : ' ') < 0)
871 * fdisk_sun_set_alt_cyl:
874 * Sets number of alternative cylinders. This function uses libfdisk Ask API
875 * for dialog with user.
877 * Returns: 0 on success, <0 on error.
879 int fdisk_sun_set_alt_cyl(struct fdisk_context
*cxt
)
881 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
883 int rc
= fdisk_ask_number(cxt
, 0, /* low */
884 be16_to_cpu(sunlabel
->acyl
), /* default */
886 _("Number of alternate cylinders"), /* query */
891 sunlabel
->acyl
= cpu_to_be16(res
);
896 * fdisk_sun_set_xcyl:
899 * Sets number of extra sectors per cylinder. This function uses libfdisk Ask API
900 * for dialog with user.
902 * Returns: 0 on success, <0 on error.
904 int fdisk_sun_set_xcyl(struct fdisk_context
*cxt
)
906 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
908 int rc
= fdisk_ask_number(cxt
, 0, /* low */
909 be16_to_cpu(sunlabel
->apc
), /* default */
910 cxt
->geom
.sectors
, /* high */
911 _("Extra sectors per cylinder"), /* query */
915 sunlabel
->apc
= cpu_to_be16(res
);
920 * fdisk_sun_set_ilfact:
923 * Sets interleave factor. This function uses libfdisk Ask API for dialog with
926 * Returns: 0 on success, <0 on error.
928 int fdisk_sun_set_ilfact(struct fdisk_context
*cxt
)
930 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
932 int rc
= fdisk_ask_number(cxt
, 1, /* low */
933 be16_to_cpu(sunlabel
->intrlv
), /* default */
935 _("Interleave factor"), /* query */
939 sunlabel
->intrlv
= cpu_to_be16(res
);
944 * fdisk_sun_set_rspeed
947 * Sets rotation speed. This function uses libfdisk Ask API for dialog with
950 * Returns: 0 on success, <0 on error.
952 int fdisk_sun_set_rspeed(struct fdisk_context
*cxt
)
954 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
956 int rc
= fdisk_ask_number(cxt
, 1, /* low */
957 be16_to_cpu(sunlabel
->rpm
), /* default */
958 USHRT_MAX
, /* high */
959 _("Rotation speed (rpm)"), /* query */
963 sunlabel
->rpm
= cpu_to_be16(res
);
968 * fdisk_sun_set_pcylcount
971 * Sets number of physical cylinders. This function uses libfdisk Ask API for
974 * Returns: 0 on success, <0 on error.
976 int fdisk_sun_set_pcylcount(struct fdisk_context
*cxt
)
978 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
980 int rc
= fdisk_ask_number(cxt
, 0, /* low */
981 be16_to_cpu(sunlabel
->pcyl
), /* default */
982 USHRT_MAX
, /* high */
983 _("Number of physical cylinders"), /* query */
987 sunlabel
->pcyl
= cpu_to_be16(res
);
991 static int sun_write_disklabel(struct fdisk_context
*cxt
)
993 struct sun_disklabel
*sunlabel
;
994 const size_t sz
= sizeof(struct sun_disklabel
);
998 assert(fdisk_is_label(cxt
, SUN
));
1000 sunlabel
= self_disklabel(cxt
);
1002 /* Maybe geometry has been modified */
1003 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
1004 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
1006 if (cxt
->geom
.cylinders
!= be16_to_cpu(sunlabel
->ncyl
)) {
1007 int a
= cpu_to_be16(cxt
->geom
.cylinders
);
1008 int b
= be16_to_cpu(sunlabel
->acyl
);
1009 sunlabel
->ncyl
= a
- b
;
1013 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
1015 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
1017 if (write_all(cxt
->dev_fd
, sunlabel
, sz
) != 0)
1023 static int sun_set_partition(
1024 struct fdisk_context
*cxt
,
1026 struct fdisk_partition
*pa
)
1028 struct sun_disklabel
*sunlabel
;
1029 struct sun_partition
*part
;
1030 struct sun_info
*info
;
1034 assert(fdisk_is_label(cxt
, SUN
));
1036 sunlabel
= self_disklabel(cxt
);
1038 if (i
>= cxt
->label
->nparts_max
)
1042 struct fdisk_parttype
*t
= pa
->type
;
1044 if (t
->code
> UINT16_MAX
)
1047 if (i
== 2 && t
->code
!= SUN_TAG_WHOLEDISK
)
1048 fdisk_info(cxt
, _("Consider leaving partition 3 as Whole disk (5),\n"
1049 "as SunOS/Solaris expects it and even Linux likes it.\n"));
1051 part
= &sunlabel
->partitions
[i
];
1052 info
= &sunlabel
->vtoc
.infos
[i
];
1054 if (cxt
->script
== NULL
&&
1055 t
->code
== SUN_TAG_LINUX_SWAP
&& !part
->start_cylinder
) {
1058 rc
= fdisk_ask_yesno(cxt
,
1059 _("It is highly recommended that the partition at offset 0\n"
1060 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
1061 "there may destroy your partition table and bootblock.\n"
1062 "Are you sure you want to tag the partition as Linux swap?"), &yes
);
1071 case SUN_TAG_LINUX_SWAP
:
1072 /* swaps are not mountable by default */
1073 info
->flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
1076 /* assume other types are mountable;
1077 user can change it anyway */
1078 info
->flags
&= ~cpu_to_be16(SUN_FLAG_UNMNT
);
1081 info
->id
= cpu_to_be16(t
->code
);
1084 if (fdisk_partition_has_start(pa
))
1085 sunlabel
->partitions
[i
].start_cylinder
=
1086 cpu_to_be32(pa
->start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
1087 if (fdisk_partition_has_size(pa
))
1088 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(pa
->size
);
1090 fdisk_label_set_changed(cxt
->label
, 1);
1095 static int sun_reset_alignment(struct fdisk_context
*cxt
__attribute__((__unused__
)))
1097 fdisk_set_first_lba(cxt
, 0);
1102 static int sun_partition_is_used(
1103 struct fdisk_context
*cxt
,
1106 struct sun_disklabel
*sunlabel
;
1110 assert(fdisk_is_label(cxt
, SUN
));
1112 if (i
>= cxt
->label
->nparts_max
)
1115 sunlabel
= self_disklabel(cxt
);
1116 return sunlabel
->partitions
[i
].num_sectors
? 1 : 0;
1119 static const struct fdisk_field sun_fields
[] =
1121 { FDISK_FIELD_DEVICE
, N_("Device"), 10, 0 },
1122 { FDISK_FIELD_START
, N_("Start"), 5, FDISK_FIELDFL_NUMBER
},
1123 { FDISK_FIELD_END
, N_("End"), 5, FDISK_FIELDFL_NUMBER
},
1124 { FDISK_FIELD_SECTORS
, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER
},
1125 { FDISK_FIELD_CYLINDERS
,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER
},
1126 { FDISK_FIELD_SIZE
, N_("Size"), 5, FDISK_FIELDFL_NUMBER
},
1127 { FDISK_FIELD_TYPEID
, N_("Id"), 2, FDISK_FIELDFL_NUMBER
},
1128 { FDISK_FIELD_TYPE
, N_("Type"), 0.1, 0 },
1129 { FDISK_FIELD_ATTR
, N_("Flags"), 0, FDISK_FIELDFL_NUMBER
}
1132 static const struct fdisk_label_operations sun_operations
=
1134 .probe
= sun_probe_label
,
1135 .write
= sun_write_disklabel
,
1136 .verify
= sun_verify_disklabel
,
1137 .create
= sun_create_disklabel
,
1138 .get_item
= sun_get_disklabel_item
,
1140 .get_part
= sun_get_partition
,
1141 .set_part
= sun_set_partition
,
1142 .add_part
= sun_add_partition
,
1143 .del_part
= sun_delete_partition
,
1145 .part_is_used
= sun_partition_is_used
,
1146 .part_toggle_flag
= sun_toggle_partition_flag
,
1148 .reset_alignment
= sun_reset_alignment
,
1152 * allocates SUN label driver
1154 struct fdisk_label
*fdisk_new_sun_label(struct fdisk_context
*cxt
__attribute__ ((__unused__
)))
1156 struct fdisk_label
*lb
;
1157 struct fdisk_sun_label
*sun
;
1159 sun
= calloc(1, sizeof(*sun
));
1163 /* initialize generic part of the driver */
1164 lb
= (struct fdisk_label
*) sun
;
1166 lb
->id
= FDISK_DISKLABEL_SUN
;
1167 lb
->op
= &sun_operations
;
1168 lb
->parttypes
= sun_parttypes
;
1169 lb
->nparttypes
= ARRAY_SIZE(sun_parttypes
) - 1;
1170 lb
->fields
= sun_fields
;
1171 lb
->nfields
= ARRAY_SIZE(sun_fields
);
1172 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;
1174 lb
->geom_min
.sectors
= 1;
1175 lb
->geom_min
.heads
= 1;
1176 lb
->geom_min
.cylinders
= 1;
1178 lb
->geom_max
.sectors
= 1024;
1179 lb
->geom_max
.heads
= 1024;
1180 lb
->geom_max
.cylinders
= USHRT_MAX
;