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 const 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 uint64_t start
, uint64_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 if (start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
) > UINT32_MAX
)
86 fdisk_warnx(cxt
, _("#%zu: start cylinder overflows Sun label limits"), i
+1);
88 if (stop
- start
> UINT32_MAX
)
89 fdisk_warnx(cxt
, _("#%zu: number of sectors overflow Sun label limits"), i
+1);
91 sunlabel
->vtoc
.infos
[i
].id
= cpu_to_be16(sysid
);
92 sunlabel
->vtoc
.infos
[i
].flags
= cpu_to_be16(0);
93 sunlabel
->partitions
[i
].start_cylinder
=
94 cpu_to_be32(start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
95 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(stop
- start
);
96 fdisk_label_set_changed(cxt
->label
, 1);
98 fdisk_info_new_partition(cxt
, i
+ 1, start
, stop
, t
);
101 static size_t count_used_partitions(struct fdisk_context
*cxt
)
103 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
108 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
109 if (sunlabel
->partitions
[i
].num_sectors
)
115 static int sun_probe_label(struct fdisk_context
*cxt
)
117 struct fdisk_sun_label
*sun
;
118 struct sun_disklabel
*sunlabel
;
123 assert(fdisk_is_label(cxt
, SUN
));
125 /* map first sector to header */
126 sun
= self_label(cxt
);
127 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
128 sunlabel
= sun
->header
;
130 if (be16_to_cpu(sunlabel
->magic
) != SUN_LABEL_MAGIC
) {
132 return 0; /* failed */
135 if (sun_pt_checksum(sunlabel
)) {
136 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong checksum. "
137 "Probably you'll have to set all the values, "
138 "e.g. heads, sectors, cylinders and partitions "
139 "or force a fresh label (s command in main menu)"));
143 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
144 cxt
->geom
.heads
= be16_to_cpu(sunlabel
->nhead
);
145 cxt
->geom
.cylinders
= be16_to_cpu(sunlabel
->ncyl
);
146 cxt
->geom
.sectors
= be16_to_cpu(sunlabel
->nsect
);
148 /* we have on label geom, but user has to win */
149 if (fdisk_has_user_device_geometry(cxt
))
150 fdisk_apply_user_device_properties(cxt
);
152 if (be32_to_cpu(sunlabel
->vtoc
.version
) != SUN_VTOC_VERSION
) {
153 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong version [%d]."),
154 be32_to_cpu(sunlabel
->vtoc
.version
));
157 if (be32_to_cpu(sunlabel
->vtoc
.sanity
) != SUN_VTOC_SANITY
) {
158 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
159 be32_to_cpu(sunlabel
->vtoc
.sanity
));
162 if (be16_to_cpu(sunlabel
->vtoc
.nparts
) != SUN_MAXPARTITIONS
) {
163 fdisk_warnx(cxt
, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
164 be16_to_cpu(sunlabel
->vtoc
.nparts
));
168 fdisk_warnx(cxt
, _("Warning: Wrong values need to be fixed up and "
169 "will be corrected by w(rite)"));
171 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
172 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
173 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
175 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
177 fdisk_label_set_changed(cxt
->label
, 1);
180 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
185 static void ask_geom(struct fdisk_context
*cxt
)
191 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.heads
, 1,
192 cxt
->label
->geom_max
.heads
,
193 _("Heads"), &res
) == 0)
194 cxt
->geom
.heads
= res
;
196 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.sectors
, 1,
197 cxt
->label
->geom_max
.sectors
,
198 _("Sectors/track"), &res
) == 0)
199 cxt
->geom
.sectors
= res
;
201 if (fdisk_ask_number(cxt
, cxt
->label
->geom_min
.cylinders
, 1,
202 cxt
->label
->geom_max
.cylinders
,
203 _("Cylinders"), &res
) == 0)
204 cxt
->geom
.cylinders
= res
;
207 static int sun_create_disklabel(struct fdisk_context
*cxt
)
210 struct fdisk_sun_label
*sun
; /* libfdisk sun handler */
211 struct sun_disklabel
*sunlabel
; /* on disk data */
216 assert(fdisk_is_label(cxt
, SUN
));
218 /* map first sector to header */
219 rc
= fdisk_init_firstsector_buffer(cxt
, 0, 0);
223 sun
= self_label(cxt
);
224 sun
->header
= (struct sun_disklabel
*) cxt
->firstsector
;
226 sunlabel
= sun
->header
;
228 cxt
->label
->nparts_max
= SUN_MAXPARTITIONS
;
230 sunlabel
->magic
= cpu_to_be16(SUN_LABEL_MAGIC
);
231 sunlabel
->vtoc
.version
= cpu_to_be32(SUN_VTOC_VERSION
);
232 sunlabel
->vtoc
.sanity
= cpu_to_be32(SUN_VTOC_SANITY
);
233 sunlabel
->vtoc
.nparts
= cpu_to_be16(SUN_MAXPARTITIONS
);
235 if (cxt
->geom
.heads
&& cxt
->geom
.sectors
) {
236 fdisk_sector_t llsectors
;
238 if (blkdev_get_sectors(cxt
->dev_fd
, (unsigned long long *) &llsectors
) == 0) {
239 int sec_fac
= cxt
->sector_size
/ 512;
240 fdisk_sector_t llcyls
;
242 llcyls
= llsectors
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
* sec_fac
);
243 cxt
->geom
.cylinders
= llcyls
;
244 if (cxt
->geom
.cylinders
!= llcyls
)
245 cxt
->geom
.cylinders
= ~0;
248 _("BLKGETSIZE ioctl failed on %s. "
249 "Using geometry cylinder value of %ju. "
250 "This value may be truncated for devices "
252 cxt
->dev_path
, (uintmax_t) cxt
->geom
.cylinders
);
257 sunlabel
->acyl
= cpu_to_be16(0);
258 sunlabel
->pcyl
= cpu_to_be16(cxt
->geom
.cylinders
);
259 sunlabel
->rpm
= cpu_to_be16(5400);
260 sunlabel
->intrlv
= cpu_to_be16(1);
261 sunlabel
->apc
= cpu_to_be16(0);
263 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
264 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
265 sunlabel
->ncyl
= cpu_to_be16(cxt
->geom
.cylinders
);
267 snprintf((char *) sunlabel
->label_id
, sizeof(sunlabel
->label_id
),
268 "Linux cyl %ju alt %u hd %u sec %ju",
269 (uintmax_t) cxt
->geom
.cylinders
,
270 be16_to_cpu(sunlabel
->acyl
),
272 (uintmax_t) cxt
->geom
.sectors
);
274 if (cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
>= 150 * 2048) {
275 ndiv
= cxt
->geom
.cylinders
- (50 * 2048 / (cxt
->geom
.heads
* cxt
->geom
.sectors
)); /* 50M swap */
277 ndiv
= cxt
->geom
.cylinders
* 2 / 3;
279 /* create the default layout only if no-script defined */
281 set_partition(cxt
, 0, 0,
282 (uint64_t) ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
283 SUN_TAG_LINUX_NATIVE
);
284 set_partition(cxt
, 1,
285 (uint64_t) ndiv
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
286 (uint64_t) cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
288 sunlabel
->vtoc
.infos
[1].flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
290 set_partition(cxt
, 2, 0,
291 (uint64_t) cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
,
296 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
298 fdisk_label_set_changed(cxt
->label
, 1);
299 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
301 fdisk_info(cxt
, _("Created a new Sun disklabel."));
305 static int sun_toggle_partition_flag(struct fdisk_context
*cxt
, size_t i
, unsigned long flag
)
307 struct sun_disklabel
*sunlabel
;
312 assert(fdisk_is_label(cxt
, SUN
));
314 if (i
>= cxt
->label
->nparts_max
)
317 sunlabel
= self_disklabel(cxt
);
318 p
= &sunlabel
->vtoc
.infos
[i
];
322 p
->flags
^= cpu_to_be16(SUN_FLAG_UNMNT
);
323 fdisk_label_set_changed(cxt
->label
, 1);
326 p
->flags
^= cpu_to_be16(SUN_FLAG_RONLY
);
327 fdisk_label_set_changed(cxt
->label
, 1);
336 static void fetch_sun(struct fdisk_context
*cxt
,
342 struct sun_disklabel
*sunlabel
;
345 int sectors_per_cylinder
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
350 assert(fdisk_is_label(cxt
, SUN
));
352 sunlabel
= self_disklabel(cxt
);
355 *stop
= cxt
->geom
.cylinders
* sectors_per_cylinder
;
357 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
358 struct sun_partition
*part
= &sunlabel
->partitions
[i
];
359 struct sun_info
*info
= &sunlabel
->vtoc
.infos
[i
];
361 if (part
->num_sectors
&&
362 be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
&&
363 be16_to_cpu(info
->id
) != SUN_TAG_WHOLEDISK
) {
364 starts
[i
] = be32_to_cpu(part
->start_cylinder
) *
365 sectors_per_cylinder
;
366 lens
[i
] = be32_to_cpu(part
->num_sectors
);
368 if (starts
[i
] == *start
) {
370 int remained_sectors
= *start
% sectors_per_cylinder
;
371 if (remained_sectors
) {
372 *start
+= sectors_per_cylinder
- remained_sectors
;
374 } else if (starts
[i
] + lens
[i
] >= *stop
)
378 /* There will be probably more gaps
379 than one, so lets check afterwards */
386 for (i
= cxt
->label
->nparts_max
; i
< SUN_MAXPARTITIONS
; i
++) {
392 /* non-Linux qsort_r(3) has usually differently ordered arguments */
393 #if !defined (__linux__) || !defined (__GLIBC__)
398 static int verify_sun_cmp(int *a
, int *b
, void *data
)
400 unsigned int *verify_sun_starts
= (unsigned int *) data
;
406 if (verify_sun_starts
[*a
] > verify_sun_starts
[*b
])
412 static int sun_verify_disklabel(struct fdisk_context
*cxt
)
414 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
], start
, stop
;
415 uint32_t i
,j
,k
,starto
,endo
;
417 int array
[SUN_MAXPARTITIONS
];
418 unsigned int *verify_sun_starts
;
422 assert(fdisk_is_label(cxt
, SUN
));
424 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
426 for (k
= 0; k
< 7; k
++) {
427 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
428 if (k
&& (lens
[i
] % (cxt
->geom
.heads
* cxt
->geom
.sectors
)))
429 fdisk_warnx(cxt
, _("Partition %u doesn't end on cylinder boundary."), i
+1);
431 for (j
= 0; j
< i
; j
++)
433 if (starts
[j
] == starts
[i
]+lens
[i
]) {
434 starts
[j
] = starts
[i
]; lens
[j
] += lens
[i
];
436 } else if (starts
[i
] == starts
[j
]+lens
[j
]){
440 if (starts
[i
] < starts
[j
]+lens
[j
] &&
441 starts
[j
] < starts
[i
]+lens
[i
]) {
443 if (starts
[j
] > starto
)
445 endo
= starts
[i
]+lens
[i
];
446 if (starts
[j
]+lens
[j
] < endo
)
447 endo
= starts
[j
]+lens
[j
];
448 fdisk_warnx(cxt
, _("Partition %u overlaps with others in "
449 "sectors %u-%u."), i
+1, starto
, endo
);
458 for (i
= 0; i
< SUN_MAXPARTITIONS
; i
++) {
464 verify_sun_starts
= starts
;
466 qsort_r(array
,ARRAY_SIZE(array
),sizeof(array
[0]),
467 (int (*)(const void *,const void *,void *)) verify_sun_cmp
,
470 if (array
[0] == -1) {
471 fdisk_info(cxt
, _("No partitions defined."));
474 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
;
475 if (starts
[array
[0]])
476 fdisk_warnx(cxt
, _("Unused gap - sectors 0-%u."), starts
[array
[0]]);
477 for (i
= 0; i
< 7 && array
[i
+1] != -1; i
++) {
478 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."),
479 (starts
[array
[i
]] + lens
[array
[i
]]),
482 start
= (starts
[array
[i
]] + lens
[array
[i
]]);
484 fdisk_warnx(cxt
, _("Unused gap - sectors %u-%u."), start
, stop
);
490 static int is_free_sector(struct fdisk_context
*cxt
,
491 fdisk_sector_t s
, uint32_t starts
[], uint32_t lens
[])
495 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
496 if (lens
[i
] && starts
[i
] <= s
497 && starts
[i
] + lens
[i
] > s
)
503 static int sun_add_partition(
504 struct fdisk_context
*cxt
,
505 struct fdisk_partition
*pa
,
508 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
509 uint32_t starts
[SUN_MAXPARTITIONS
], lens
[SUN_MAXPARTITIONS
];
510 struct sun_partition
*part
;
511 struct sun_info
*info
;
512 uint32_t start
, stop
, stop2
;
514 int sys
= pa
&& pa
->type
? pa
->type
->code
: SUN_TAG_LINUX_NATIVE
;
520 unsigned int first
, last
;
522 DBG(LABEL
, ul_debug("SUN adding partition"));
524 rc
= fdisk_partition_next_partno(pa
, cxt
, &n
);
528 part
= &sunlabel
->partitions
[n
];
529 info
= &sunlabel
->vtoc
.infos
[n
];
531 if (part
->num_sectors
&& be16_to_cpu(info
->id
) != SUN_TAG_UNASSIGNED
) {
532 fdisk_info(cxt
, _("Partition %zu is already defined. Delete "
533 "it before re-adding it."), n
+ 1);
537 fetch_sun(cxt
, starts
, lens
, &start
, &stop
);
539 if (pa
&& pa
->type
&& pa
->type
->code
== SUN_TAG_WHOLEDISK
)
546 fdisk_info(cxt
, _("Other partitions already cover the "
547 "whole disk. Delete some/shrink them before retry."));
552 if (pa
&& pa
->start_follow_default
)
554 else if (pa
&& fdisk_partition_has_start(pa
)) {
557 if (!whole_disk
&& !is_free_sector(cxt
, first
, starts
, lens
))
560 struct fdisk_ask
*ask
;
563 fdisk_info(cxt
, _("It is highly recommended that the "
564 "third partition covers the whole disk "
565 "and is of type `Whole disk'"));
567 snprintf(mesg
, sizeof(mesg
), _("First %s"),
568 fdisk_get_unit(cxt
, FDISK_SINGULAR
));
570 ask
= fdisk_new_ask();
574 fdisk_ask_set_query(ask
, mesg
);
575 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_NUMBER
);
578 fdisk_ask_number_set_low(ask
, 0); /* minimal */
579 fdisk_ask_number_set_default(ask
, 0); /* default */
580 fdisk_ask_number_set_high(ask
, 0); /* maximal */
582 fdisk_ask_number_set_low(ask
, 0); /* minimal */
583 fdisk_ask_number_set_default(ask
, 0); /* default */
584 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
586 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, start
)); /* minimal */
587 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, start
)); /* default */
588 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
590 rc
= fdisk_do_ask(cxt
, ask
);
591 first
= fdisk_ask_number_get_result(ask
);
592 fdisk_unref_ask(ask
);
596 if (fdisk_use_cylinders(cxt
))
597 first
*= fdisk_get_units_per_sector(cxt
);
599 if (!fdisk_use_cylinders(cxt
)) {
600 /* Starting sector has to be properly aligned */
601 int cs
= cxt
->geom
.heads
* cxt
->geom
.sectors
;
605 fdisk_info(cxt
, _("Aligning the first sector from %u to %u "
606 "to be on cylinder boundary."),
607 first
, first
+ cs
- x
);
612 /* ewt asks to add: "don't start a partition at cyl 0"
613 However, edmundo@rano.demon.co.uk writes:
614 "In addition to having a Sun partition table, to be able to
615 boot from the disc, the first partition, /dev/sdX1, must
616 start at cylinder 0. This means that /dev/sdX1 contains
617 the partition table and the boot block, as these are the
618 first two sectors of the disc. Therefore you must be
619 careful what you use /dev/sdX1 for. In particular, you must
620 not use a partition starting at cylinder 0 for Linux swap,
621 as that would overwrite the partition table and the boot
622 block. You may, however, use such a partition for a UFS
623 or EXT2 file system, as these file systems leave the first
624 1024 bytes undisturbed. */
625 /* On the other hand, one should not use partitions
626 starting at block 0 in an md, or the label will
628 if (!is_free_sector(cxt
, first
, starts
, lens
) && !whole_disk
) {
629 if (n
== 2 && !first
) {
633 fdisk_warnx(cxt
, _("Sector %d is already allocated"), first
);
639 stop
= cxt
->geom
.cylinders
* cxt
->geom
.heads
* cxt
->geom
.sectors
; /* ancient */
641 for (i
= 0; i
< cxt
->label
->nparts_max
; i
++) {
642 if (starts
[i
] > first
&& starts
[i
] < stop
)
647 if (pa
&& pa
->end_follow_default
)
648 last
= whole_disk
|| (n
== 2 && !first
) ? stop2
: stop
;
650 else if (pa
&& fdisk_partition_has_size(pa
)) {
651 last
= first
+ pa
->size
;
653 if (!whole_disk
&& last
> stop
)
656 struct fdisk_ask
*ask
= fdisk_new_ask();
661 snprintf(mesg
, sizeof(mesg
),
662 _("Last %s or +/-%s or +/-size{K,M,G,T,P}"),
663 fdisk_get_unit(cxt
, FDISK_SINGULAR
),
664 fdisk_get_unit(cxt
, FDISK_PLURAL
));
665 fdisk_ask_set_query(ask
, mesg
);
666 fdisk_ask_set_type(ask
, FDISK_ASKTYPE_OFFSET
);
669 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, stop2
)); /* minimal */
670 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
671 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
672 fdisk_ask_number_set_base(ask
, 0);
673 } else if (n
== 2 && !first
) {
674 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
675 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop2
)); /* default */
676 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop2
)); /* maximal */
677 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
679 fdisk_ask_number_set_low(ask
, fdisk_scround(cxt
, first
)); /* minimal */
680 fdisk_ask_number_set_default(ask
, fdisk_scround(cxt
, stop
)); /* default */
681 fdisk_ask_number_set_high(ask
, fdisk_scround(cxt
, stop
)); /* maximal */
682 fdisk_ask_number_set_base(ask
, fdisk_scround(cxt
, first
));
685 fdisk_ask_number_set_wrap_negative(ask
, 1); /* wrap negative around high */
687 if (fdisk_use_cylinders(cxt
))
688 fdisk_ask_number_set_unit(ask
,
690 fdisk_get_units_per_sector(cxt
));
692 fdisk_ask_number_set_unit(ask
, cxt
->sector_size
);
694 rc
= fdisk_do_ask(cxt
, ask
);
695 last
= fdisk_ask_number_get_result(ask
);
697 fdisk_unref_ask(ask
);
700 if (fdisk_use_cylinders(cxt
))
701 last
*= fdisk_get_units_per_sector(cxt
);
704 if (n
== 2 && !first
) {
708 } else if (last
> stop
) {
710 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
711 "%lu %s covers some other partition. Your entry has been changed\n"
713 (unsigned long) fdisk_scround(cxt
, last
), fdisk_get_unit(cxt
, FDISK_SINGULAR
),
714 (unsigned long) fdisk_scround(cxt
, stop
), fdisk_get_unit(cxt
, FDISK_SINGULAR
));
717 } else if (!whole_disk
&& last
> stop
)
721 sys
= SUN_TAG_WHOLEDISK
;
723 DBG(LABEL
, ul_debug("SUN new partition #%zu: first=%u, last=%u, sys=%d", n
, first
, last
, sys
));
725 set_partition(cxt
, n
, first
, last
, sys
);
726 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
732 static int sun_delete_partition(struct fdisk_context
*cxt
,
735 struct sun_disklabel
*sunlabel
;
736 struct sun_partition
*part
;
737 struct sun_info
*info
;
742 assert(fdisk_is_label(cxt
, SUN
));
744 sunlabel
= self_disklabel(cxt
);
745 part
= &sunlabel
->partitions
[partnum
];
746 info
= &sunlabel
->vtoc
.infos
[partnum
];
749 be16_to_cpu(info
->id
) == SUN_TAG_WHOLEDISK
&&
750 !part
->start_cylinder
&&
751 (nsec
= be32_to_cpu(part
->num_sectors
))
752 == cxt
->geom
.heads
* cxt
->geom
.sectors
* cxt
->geom
.cylinders
)
753 fdisk_info(cxt
, _("If you want to maintain SunOS/Solaris compatibility, "
754 "consider leaving this "
755 "partition as Whole disk (5), starting at 0, with %u "
757 info
->id
= cpu_to_be16(SUN_TAG_UNASSIGNED
);
758 part
->num_sectors
= 0;
759 cxt
->label
->nparts_cur
= count_used_partitions(cxt
);
760 fdisk_label_set_changed(cxt
->label
, 1);
764 static int sun_get_disklabel_item(struct fdisk_context
*cxt
, struct fdisk_labelitem
*item
)
766 struct sun_disklabel
*sunlabel
;
771 assert(fdisk_is_label(cxt
, SUN
));
773 sunlabel
= self_disklabel(cxt
);
776 case SUN_LABELITEM_LABELID
:
777 item
->name
=_("Label ID");
779 item
->data
.str
= *sunlabel
->label_id
? strndup((char *)sunlabel
->label_id
, sizeof(sunlabel
->label_id
)) : NULL
;
781 case SUN_LABELITEM_VTOCID
:
782 item
->name
=_("Volume ID");
784 item
->data
.str
= *sunlabel
->vtoc
.volume_id
? strndup((char *)sunlabel
->vtoc
.volume_id
, sizeof(sunlabel
->vtoc
.volume_id
)) : NULL
;
786 case SUN_LABELITEM_RPM
:
787 item
->name
=_("Rpm");
789 item
->data
.num64
= be16_to_cpu(sunlabel
->rpm
);
791 case SUN_LABELITEM_ACYL
:
792 item
->name
=_("Alternate cylinders");
794 item
->data
.num64
= be16_to_cpu(sunlabel
->acyl
);
796 case SUN_LABELITEM_PCYL
:
797 item
->name
=_("Physical cylinders");
799 item
->data
.num64
= be16_to_cpu(sunlabel
->pcyl
);
801 case SUN_LABELITEM_APC
:
802 item
->name
=_("Extra sects/cyl");
804 item
->data
.num64
= be16_to_cpu(sunlabel
->apc
);
806 case SUN_LABELITEM_INTRLV
:
807 item
->name
=_("Interleave");
809 item
->data
.num64
= be16_to_cpu(sunlabel
->intrlv
);
812 if (item
->id
< __FDISK_NLABELITEMS
)
813 rc
= 1; /* unsupported generic item */
815 rc
= 2; /* out of range */
822 static struct fdisk_parttype
*sun_get_parttype(
823 struct fdisk_context
*cxt
,
826 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
827 struct fdisk_parttype
*t
;
829 if (n
>= cxt
->label
->nparts_max
)
832 t
= fdisk_label_get_parttype_from_code(cxt
->label
,
833 be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
));
834 return t
? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel
->vtoc
.infos
[n
].id
), NULL
);
838 static int sun_get_partition(struct fdisk_context
*cxt
, size_t n
,
839 struct fdisk_partition
*pa
)
841 struct sun_disklabel
*sunlabel
;
842 struct sun_partition
*part
;
848 assert(fdisk_is_label(cxt
, SUN
));
850 if (n
>= cxt
->label
->nparts_max
)
853 sunlabel
= self_disklabel(cxt
);
854 part
= &sunlabel
->partitions
[n
];
856 pa
->used
= part
->num_sectors
? 1 : 0;
860 flags
= be16_to_cpu(sunlabel
->vtoc
.infos
[n
].flags
);
861 start
= (uint64_t) be32_to_cpu(part
->start_cylinder
)
862 * cxt
->geom
.heads
* cxt
->geom
.sectors
;
863 len
= be32_to_cpu(part
->num_sectors
);
865 pa
->type
= sun_get_parttype(cxt
, n
);
866 if (pa
->type
&& pa
->type
->code
== SUN_TAG_WHOLEDISK
)
869 if (flags
& SUN_FLAG_UNMNT
|| flags
& SUN_FLAG_RONLY
) {
870 if (asprintf(&pa
->attrs
, "%c%c",
871 flags
& SUN_FLAG_UNMNT
? 'u' : ' ',
872 flags
& SUN_FLAG_RONLY
? 'r' : ' ') < 0)
883 * fdisk_sun_set_alt_cyl:
886 * Sets number of alternative cylinders. This function uses libfdisk Ask API
887 * for dialog with user.
889 * Returns: 0 on success, <0 on error.
891 int fdisk_sun_set_alt_cyl(struct fdisk_context
*cxt
)
893 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
895 int rc
= fdisk_ask_number(cxt
, 0, /* low */
896 be16_to_cpu(sunlabel
->acyl
), /* default */
898 _("Number of alternate cylinders"), /* query */
903 sunlabel
->acyl
= cpu_to_be16(res
);
908 * fdisk_sun_set_xcyl:
911 * Sets number of extra sectors per cylinder. This function uses libfdisk Ask API
912 * for dialog with user.
914 * Returns: 0 on success, <0 on error.
916 int fdisk_sun_set_xcyl(struct fdisk_context
*cxt
)
918 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
920 int rc
= fdisk_ask_number(cxt
, 0, /* low */
921 be16_to_cpu(sunlabel
->apc
), /* default */
922 cxt
->geom
.sectors
, /* high */
923 _("Extra sectors per cylinder"), /* query */
927 sunlabel
->apc
= cpu_to_be16(res
);
932 * fdisk_sun_set_ilfact:
935 * Sets interleave factor. This function uses libfdisk Ask API for dialog with
938 * Returns: 0 on success, <0 on error.
940 int fdisk_sun_set_ilfact(struct fdisk_context
*cxt
)
942 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
944 int rc
= fdisk_ask_number(cxt
, 1, /* low */
945 be16_to_cpu(sunlabel
->intrlv
), /* default */
947 _("Interleave factor"), /* query */
951 sunlabel
->intrlv
= cpu_to_be16(res
);
956 * fdisk_sun_set_rspeed
959 * Sets rotation speed. This function uses libfdisk Ask API for dialog with
962 * Returns: 0 on success, <0 on error.
964 int fdisk_sun_set_rspeed(struct fdisk_context
*cxt
)
966 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
968 int rc
= fdisk_ask_number(cxt
, 1, /* low */
969 be16_to_cpu(sunlabel
->rpm
), /* default */
970 USHRT_MAX
, /* high */
971 _("Rotation speed (rpm)"), /* query */
975 sunlabel
->rpm
= cpu_to_be16(res
);
980 * fdisk_sun_set_pcylcount
983 * Sets number of physical cylinders. This function uses libfdisk Ask API for
986 * Returns: 0 on success, <0 on error.
988 int fdisk_sun_set_pcylcount(struct fdisk_context
*cxt
)
990 struct sun_disklabel
*sunlabel
= self_disklabel(cxt
);
992 int rc
= fdisk_ask_number(cxt
, 0, /* low */
993 be16_to_cpu(sunlabel
->pcyl
), /* default */
994 USHRT_MAX
, /* high */
995 _("Number of physical cylinders"), /* query */
999 sunlabel
->pcyl
= cpu_to_be16(res
);
1003 static int sun_write_disklabel(struct fdisk_context
*cxt
)
1005 struct sun_disklabel
*sunlabel
;
1006 const size_t sz
= sizeof(struct sun_disklabel
);
1010 assert(fdisk_is_label(cxt
, SUN
));
1012 sunlabel
= self_disklabel(cxt
);
1014 /* Maybe geometry has been modified */
1015 sunlabel
->nhead
= cpu_to_be16(cxt
->geom
.heads
);
1016 sunlabel
->nsect
= cpu_to_be16(cxt
->geom
.sectors
);
1018 if (cxt
->geom
.cylinders
!= be16_to_cpu(sunlabel
->ncyl
)) {
1019 int a
= cpu_to_be16(cxt
->geom
.cylinders
);
1020 int b
= be16_to_cpu(sunlabel
->acyl
);
1021 sunlabel
->ncyl
= a
- b
;
1025 sunlabel
->csum
= sun_pt_checksum(sunlabel
);
1027 if (lseek(cxt
->dev_fd
, 0, SEEK_SET
) < 0)
1029 if (write_all(cxt
->dev_fd
, sunlabel
, sz
) != 0)
1035 static int sun_set_partition(
1036 struct fdisk_context
*cxt
,
1038 struct fdisk_partition
*pa
)
1040 struct sun_disklabel
*sunlabel
;
1041 struct sun_partition
*part
;
1042 struct sun_info
*info
;
1046 assert(fdisk_is_label(cxt
, SUN
));
1048 sunlabel
= self_disklabel(cxt
);
1050 if (i
>= cxt
->label
->nparts_max
)
1054 struct fdisk_parttype
*t
= pa
->type
;
1056 if (t
->code
> UINT16_MAX
)
1059 if (i
== 2 && t
->code
!= SUN_TAG_WHOLEDISK
)
1060 fdisk_info(cxt
, _("Consider leaving partition 3 as Whole disk (5),\n"
1061 "as SunOS/Solaris expects it and even Linux likes it.\n"));
1063 part
= &sunlabel
->partitions
[i
];
1064 info
= &sunlabel
->vtoc
.infos
[i
];
1066 if (cxt
->script
== NULL
&&
1067 t
->code
== SUN_TAG_LINUX_SWAP
&& !part
->start_cylinder
) {
1070 rc
= fdisk_ask_yesno(cxt
,
1071 _("It is highly recommended that the partition at offset 0\n"
1072 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
1073 "there may destroy your partition table and bootblock.\n"
1074 "Are you sure you want to tag the partition as Linux swap?"), &yes
);
1083 case SUN_TAG_LINUX_SWAP
:
1084 /* swaps are not mountable by default */
1085 info
->flags
|= cpu_to_be16(SUN_FLAG_UNMNT
);
1088 /* assume other types are mountable;
1089 user can change it anyway */
1090 info
->flags
&= ~cpu_to_be16(SUN_FLAG_UNMNT
);
1093 info
->id
= cpu_to_be16(t
->code
);
1096 if (fdisk_partition_has_start(pa
))
1097 sunlabel
->partitions
[i
].start_cylinder
=
1098 cpu_to_be32(pa
->start
/ (cxt
->geom
.heads
* cxt
->geom
.sectors
));
1099 if (fdisk_partition_has_size(pa
))
1100 sunlabel
->partitions
[i
].num_sectors
= cpu_to_be32(pa
->size
);
1102 fdisk_label_set_changed(cxt
->label
, 1);
1107 static int sun_reset_alignment(struct fdisk_context
*cxt
__attribute__((__unused__
)))
1109 fdisk_set_first_lba(cxt
, 0);
1114 static int sun_partition_is_used(
1115 struct fdisk_context
*cxt
,
1118 struct sun_disklabel
*sunlabel
;
1122 assert(fdisk_is_label(cxt
, SUN
));
1124 if (i
>= cxt
->label
->nparts_max
)
1127 sunlabel
= self_disklabel(cxt
);
1128 return sunlabel
->partitions
[i
].num_sectors
? 1 : 0;
1131 static const struct fdisk_field sun_fields
[] =
1133 { FDISK_FIELD_DEVICE
, N_("Device"), 10, 0 },
1134 { FDISK_FIELD_START
, N_("Start"), 5, FDISK_FIELDFL_NUMBER
},
1135 { FDISK_FIELD_END
, N_("End"), 5, FDISK_FIELDFL_NUMBER
},
1136 { FDISK_FIELD_SECTORS
, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER
},
1137 { FDISK_FIELD_CYLINDERS
,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER
},
1138 { FDISK_FIELD_SIZE
, N_("Size"), 5, FDISK_FIELDFL_NUMBER
},
1139 { FDISK_FIELD_TYPEID
, N_("Id"), 2, FDISK_FIELDFL_NUMBER
},
1140 { FDISK_FIELD_TYPE
, N_("Type"), 0.1, 0 },
1141 { FDISK_FIELD_ATTR
, N_("Flags"), 0, FDISK_FIELDFL_NUMBER
}
1144 static const struct fdisk_label_operations sun_operations
=
1146 .probe
= sun_probe_label
,
1147 .write
= sun_write_disklabel
,
1148 .verify
= sun_verify_disklabel
,
1149 .create
= sun_create_disklabel
,
1150 .get_item
= sun_get_disklabel_item
,
1152 .get_part
= sun_get_partition
,
1153 .set_part
= sun_set_partition
,
1154 .add_part
= sun_add_partition
,
1155 .del_part
= sun_delete_partition
,
1157 .part_is_used
= sun_partition_is_used
,
1158 .part_toggle_flag
= sun_toggle_partition_flag
,
1160 .reset_alignment
= sun_reset_alignment
,
1164 * allocates SUN label driver
1166 struct fdisk_label
*fdisk_new_sun_label(struct fdisk_context
*cxt
__attribute__ ((__unused__
)))
1168 struct fdisk_label
*lb
;
1169 struct fdisk_sun_label
*sun
;
1171 sun
= calloc(1, sizeof(*sun
));
1175 /* initialize generic part of the driver */
1176 lb
= (struct fdisk_label
*) sun
;
1178 lb
->id
= FDISK_DISKLABEL_SUN
;
1179 lb
->op
= &sun_operations
;
1180 lb
->parttypes
= sun_parttypes
;
1181 lb
->nparttypes
= ARRAY_SIZE(sun_parttypes
) - 1;
1182 lb
->fields
= sun_fields
;
1183 lb
->nfields
= ARRAY_SIZE(sun_fields
);
1184 lb
->flags
|= FDISK_LABEL_FL_REQUIRE_GEOMETRY
;
1186 lb
->geom_min
.sectors
= 1;
1187 lb
->geom_min
.heads
= 1;
1188 lb
->geom_min
.cylinders
= 1;
1190 lb
->geom_max
.sectors
= 1024;
1191 lb
->geom_max
.heads
= 1024;
1192 lb
->geom_max
.cylinders
= USHRT_MAX
;
1194 /* return calloc() result to keep static anaylizers happy */
1195 return (struct fdisk_label
*) sun
;