]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/sun.c
taskset: Accept 0 pid for current process
[thirdparty/util-linux.git] / libfdisk / src / sun.c
CommitLineData
2b6fc908 1/*
b4bfbadd 2 * Copyright (C) 2013 Karel Zak <kzak@redhat.com>
2b6fc908 3 *
b4bfbadd
KZ
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
2b6fc908 8 */
2b6fc908 9#include <stdio.h> /* stderr */
df1dddf9 10#include <stdlib.h> /* qsort */
2b6fc908
KZ
11#include <string.h> /* strstr */
12#include <unistd.h> /* write */
13#include <sys/ioctl.h> /* ioctl */
95f1bdee 14
810f986b 15#include "blkdev.h"
a1ac3a0c 16#include "bitops.h"
2b6fc908 17
b4bfbadd
KZ
18#include "fdiskP.h"
19#include "pt-sun.h"
20#include "all-io.h"
2b6fc908 21
fd979f5b
KZ
22
23/**
24 * SECTION: sun
705854f3
KZ
25 * @title: SUN
26 * @short_description: disk label specific functions
fd979f5b
KZ
27 *
28 */
29
0c5d095e
KZ
30/*
31 * in-memory fdisk SUN stuff
32 */
33struct fdisk_sun_label {
34 struct fdisk_label head; /* generic part */
cfebc465 35 struct sun_disklabel *header; /* on-disk data (pointer to cxt->firstsector) */
0c5d095e
KZ
36};
37
3ca03d59 38static const struct fdisk_parttype sun_parttypes[] = {
899736f1
DM
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")},
cfebc465 44 {SUN_TAG_WHOLEDISK, N_("Whole disk")},
899736f1
DM
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")},
2b6fc908
KZ
55 { 0, NULL }
56};
57
9e930041 58/* return pointer buffer with on-disk data */
cfebc465 59static inline struct sun_disklabel *self_disklabel(struct fdisk_context *cxt)
d6ab93f1 60{
9ffeb235
KZ
61 assert(cxt);
62 assert(cxt->label);
aa36c2cf 63 assert(fdisk_is_label(cxt, SUN));
d6ab93f1 64
9ffeb235 65 return ((struct fdisk_sun_label *) cxt->label)->header;
d6ab93f1
KZ
66}
67
9ffeb235
KZ
68/* return in-memory sun fdisk data */
69static inline struct fdisk_sun_label *self_label(struct fdisk_context *cxt)
70{
71 assert(cxt);
72 assert(cxt->label);
aa36c2cf 73 assert(fdisk_is_label(cxt, SUN));
9ffeb235
KZ
74
75 return (struct fdisk_sun_label *) cxt->label;
76}
d6ab93f1 77
ea50ba5b 78static void set_partition(struct fdisk_context *cxt, size_t i,
b4251e51 79 uint64_t start, uint64_t stop, uint16_t sysid)
899736f1 80{
cfebc465 81 struct sun_disklabel *sunlabel = self_disklabel(cxt);
a745611d
KZ
82 struct fdisk_parttype *t =
83 fdisk_label_get_parttype_from_code(cxt->label, sysid);
137b57e5 84
b4251e51 85 if (start / (cxt->geom.heads * cxt->geom.sectors) > UINT32_MAX)
fbae1442 86 fdisk_warnx(cxt, _("#%zu: start cylinder overflows Sun label limits"), i+1);
b4251e51
KZ
87
88 if (stop - start > UINT32_MAX)
fbae1442 89 fdisk_warnx(cxt, _("#%zu: number of sectors overflow Sun label limits"), i+1);
b4251e51 90
cfebc465
KZ
91 sunlabel->vtoc.infos[i].id = cpu_to_be16(sysid);
92 sunlabel->vtoc.infos[i].flags = cpu_to_be16(0);
2b6fc908 93 sunlabel->partitions[i].start_cylinder =
a1ac3a0c
KZ
94 cpu_to_be32(start / (cxt->geom.heads * cxt->geom.sectors));
95 sunlabel->partitions[i].num_sectors = cpu_to_be32(stop - start);
bddd84e7 96 fdisk_label_set_changed(cxt->label, 1);
b4bfbadd
KZ
97
98 fdisk_info_new_partition(cxt, i + 1, start, stop, t);
2b6fc908
KZ
99}
100
9ffeb235 101static size_t count_used_partitions(struct fdisk_context *cxt)
ad30333e 102{
cfebc465 103 struct sun_disklabel *sunlabel = self_disklabel(cxt);
137b57e5
KZ
104 size_t ct = 0, i;
105
d6ab93f1 106 assert(sunlabel);
137b57e5 107
9ffeb235 108 for (i = 0; i < cxt->label->nparts_max; i++) {
137b57e5
KZ
109 if (sunlabel->partitions[i].num_sectors)
110 ct++;
111 }
112 return ct;
ad30333e
FC
113}
114
9ffeb235 115static int sun_probe_label(struct fdisk_context *cxt)
899736f1 116{
d6ab93f1 117 struct fdisk_sun_label *sun;
cfebc465 118 struct sun_disklabel *sunlabel;
d6ab93f1 119 int need_fixing = 0;
24f4bbff 120
137b57e5 121 assert(cxt);
9ffeb235 122 assert(cxt->label);
aa36c2cf 123 assert(fdisk_is_label(cxt, SUN));
137b57e5 124
aace6e9d 125 /* map first sector to header */
e213a8e5 126 sun = self_label(cxt);
cfebc465 127 sun->header = (struct sun_disklabel *) cxt->firstsector;
aace6e9d 128 sunlabel = sun->header;
d6ab93f1 129
a1ac3a0c 130 if (be16_to_cpu(sunlabel->magic) != SUN_LABEL_MAGIC) {
aace6e9d 131 sun->header = NULL;
d6ab93f1 132 return 0; /* failed */
2b6fc908 133 }
ad30333e 134
7f387c5c 135 if (sun_pt_checksum(sunlabel)) {
ac1a559a
KZ
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 "
9eac213c 139 "or force a fresh label (s command in main menu)"));
d6ab93f1
KZ
140 return 1;
141 }
142
cfebc465 143 cxt->label->nparts_max = SUN_MAXPARTITIONS;
a1ac3a0c
KZ
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);
d6ab93f1 147
502dd53c
KZ
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);
151
cfebc465 152 if (be32_to_cpu(sunlabel->vtoc.version) != SUN_VTOC_VERSION) {
9eac213c 153 fdisk_warnx(cxt, _("Detected sun disklabel with wrong version [%d]."),
cfebc465 154 be32_to_cpu(sunlabel->vtoc.version));
d6ab93f1 155 need_fixing = 1;
2b6fc908 156 }
cfebc465 157 if (be32_to_cpu(sunlabel->vtoc.sanity) != SUN_VTOC_SANITY) {
9eac213c 158 fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.sanity [0x%08x]."),
cfebc465 159 be32_to_cpu(sunlabel->vtoc.sanity));
d6ab93f1
KZ
160 need_fixing = 1;
161 }
cfebc465 162 if (be16_to_cpu(sunlabel->vtoc.nparts) != SUN_MAXPARTITIONS) {
9eac213c 163 fdisk_warnx(cxt, _("Detected sun disklabel with wrong vtoc.nparts [%u]."),
cfebc465 164 be16_to_cpu(sunlabel->vtoc.nparts));
d6ab93f1
KZ
165 need_fixing = 1;
166 }
167 if (need_fixing) {
9eac213c
KZ
168 fdisk_warnx(cxt, _("Warning: Wrong values need to be fixed up and "
169 "will be corrected by w(rite)"));
a1ac3a0c 170
cfebc465
KZ
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);
7f387c5c
RM
174 sunlabel->csum = 0;
175 sunlabel->csum = sun_pt_checksum(sunlabel);
d6ab93f1 176
9ffeb235 177 fdisk_label_set_changed(cxt->label, 1);
d6ab93f1
KZ
178 }
179
9ffeb235 180 cxt->label->nparts_cur = count_used_partitions(cxt);
d6ab93f1 181
2b6fc908
KZ
182 return 1;
183}
184
9eac213c
KZ
185static void ask_geom(struct fdisk_context *cxt)
186{
187 uintmax_t res;
188
189 assert(cxt);
190
2dd2880f
KZ
191 if (fdisk_ask_number(cxt, cxt->label->geom_min.heads, 1,
192 cxt->label->geom_max.heads,
193 _("Heads"), &res) == 0)
9eac213c 194 cxt->geom.heads = res;
2dd2880f
KZ
195
196 if (fdisk_ask_number(cxt, cxt->label->geom_min.sectors, 1,
197 cxt->label->geom_max.sectors,
198 _("Sectors/track"), &res) == 0)
9eac213c 199 cxt->geom.sectors = res;
2dd2880f
KZ
200
201 if (fdisk_ask_number(cxt, cxt->label->geom_min.cylinders, 1,
202 cxt->label->geom_max.cylinders,
203 _("Cylinders"), &res) == 0)
9eac213c
KZ
204 cxt->geom.cylinders = res;
205}
206
9ffeb235 207static int sun_create_disklabel(struct fdisk_context *cxt)
2b6fc908 208{
e5b5a349 209 unsigned int ndiv;
d6ab93f1 210 struct fdisk_sun_label *sun; /* libfdisk sun handler */
cfebc465 211 struct sun_disklabel *sunlabel; /* on disk data */
7c2cfb18 212 int rc = 0;
d6ab93f1 213
137b57e5 214 assert(cxt);
9ffeb235 215 assert(cxt->label);
aa36c2cf 216 assert(fdisk_is_label(cxt, SUN));
137b57e5 217
d6ab93f1 218 /* map first sector to header */
3457d90e 219 rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
7c2cfb18
KZ
220 if (rc)
221 return rc;
222
e213a8e5 223 sun = self_label(cxt);
cfebc465 224 sun->header = (struct sun_disklabel *) cxt->firstsector;
d6ab93f1
KZ
225
226 sunlabel = sun->header;
227
cfebc465 228 cxt->label->nparts_max = SUN_MAXPARTITIONS;
ad30333e 229
a1ac3a0c 230 sunlabel->magic = cpu_to_be16(SUN_LABEL_MAGIC);
cfebc465
KZ
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);
899736f1 234
e5b5a349 235 if (cxt->geom.heads && cxt->geom.sectors) {
0073a4cf 236 fdisk_sector_t llsectors;
e5b5a349 237
0073a4cf 238 if (blkdev_get_sectors(cxt->dev_fd, (unsigned long long *) &llsectors) == 0) {
e5b5a349 239 int sec_fac = cxt->sector_size / 512;
0073a4cf 240 fdisk_sector_t llcyls;
5dd9251f 241
24cd580b
DB
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;
899736f1 246 } else {
9eac213c 247 fdisk_warnx(cxt,
ac1a559a 248 _("BLKGETSIZE ioctl failed on %s. "
fbae1442 249 "Using geometry cylinder value of %ju. "
ac1a559a
KZ
250 "This value may be truncated for devices "
251 "> 33.8 GB."),
fbae1442 252 cxt->dev_path, (uintmax_t) cxt->geom.cylinders);
899736f1 253 }
6b0054a2 254 } else
9eac213c 255 ask_geom(cxt);
22853e4a 256
4170ae9c 257 sunlabel->acyl = cpu_to_be16(0);
a1ac3a0c 258 sunlabel->pcyl = cpu_to_be16(cxt->geom.cylinders);
a1ac3a0c
KZ
259 sunlabel->rpm = cpu_to_be16(5400);
260 sunlabel->intrlv = cpu_to_be16(1);
261 sunlabel->apc = cpu_to_be16(0);
22853e4a 262
a1ac3a0c
KZ
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);
899736f1 266
cfebc465 267 snprintf((char *) sunlabel->label_id, sizeof(sunlabel->label_id),
0073a4cf
KZ
268 "Linux cyl %ju alt %u hd %u sec %ju",
269 (uintmax_t) cxt->geom.cylinders,
270 be16_to_cpu(sunlabel->acyl),
271 cxt->geom.heads,
272 (uintmax_t) cxt->geom.sectors);
899736f1 273
24cd580b
DB
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 */
899736f1 276 } else
24cd580b 277 ndiv = cxt->geom.cylinders * 2 / 3;
899736f1 278
a8a4887b
KZ
279 /* create the default layout only if no-script defined */
280 if (!cxt->script) {
b4251e51
KZ
281 set_partition(cxt, 0, 0,
282 (uint64_t) ndiv * cxt->geom.heads * cxt->geom.sectors,
899736f1 283 SUN_TAG_LINUX_NATIVE);
b4251e51
KZ
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,
899736f1 287 SUN_TAG_LINUX_SWAP);
a8a4887b 288 sunlabel->vtoc.infos[1].flags |= cpu_to_be16(SUN_FLAG_UNMNT);
899736f1 289
a8a4887b 290 set_partition(cxt, 2, 0,
b4251e51 291 (uint64_t) cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors,
cfebc465 292 SUN_TAG_WHOLEDISK);
a8a4887b 293 }
899736f1 294
7f387c5c
RM
295 sunlabel->csum = 0;
296 sunlabel->csum = sun_pt_checksum(sunlabel);
22853e4a 297
9ffeb235
KZ
298 fdisk_label_set_changed(cxt->label, 1);
299 cxt->label->nparts_cur = count_used_partitions(cxt);
a71601af 300
0477369a 301 fdisk_info(cxt, _("Created a new Sun disklabel."));
a71601af 302 return 0;
2b6fc908
KZ
303}
304
fb1caca7 305static int sun_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
899736f1 306{
fb1caca7
KZ
307 struct sun_disklabel *sunlabel;
308 struct sun_info *p;
309
310 assert(cxt);
311 assert(cxt->label);
aa36c2cf 312 assert(fdisk_is_label(cxt, SUN));
899736f1 313
46e7eac1 314 if (i >= cxt->label->nparts_max)
fb1caca7 315 return -EINVAL;
899736f1 316
fb1caca7
KZ
317 sunlabel = self_disklabel(cxt);
318 p = &sunlabel->vtoc.infos[i];
319
320 switch (flag) {
321 case SUN_FLAG_UNMNT:
322 p->flags ^= cpu_to_be16(SUN_FLAG_UNMNT);
323 fdisk_label_set_changed(cxt->label, 1);
324 break;
325 case SUN_FLAG_RONLY:
326 p->flags ^= cpu_to_be16(SUN_FLAG_RONLY);
327 fdisk_label_set_changed(cxt->label, 1);
328 break;
329 default:
330 return 1;
331 }
332
333 return 0;
2b6fc908
KZ
334}
335
137b57e5 336static void fetch_sun(struct fdisk_context *cxt,
137b57e5
KZ
337 uint32_t *starts,
338 uint32_t *lens,
339 uint32_t *start,
340 uint32_t *stop)
899736f1 341{
cfebc465 342 struct sun_disklabel *sunlabel;
137b57e5
KZ
343 int continuous = 1;
344 size_t i;
9e6ccaab 345 int sectors_per_cylinder = cxt->geom.heads * cxt->geom.sectors;
137b57e5
KZ
346
347 assert(cxt);
9ffeb235
KZ
348 assert(cxt);
349 assert(cxt->label);
aa36c2cf 350 assert(fdisk_is_label(cxt, SUN));
899736f1 351
9ffeb235 352 sunlabel = self_disklabel(cxt);
d6ab93f1 353
899736f1 354 *start = 0;
9e6ccaab 355 *stop = cxt->geom.cylinders * sectors_per_cylinder;
899736f1 356
9ffeb235 357 for (i = 0; i < cxt->label->nparts_max; i++) {
899736f1 358 struct sun_partition *part = &sunlabel->partitions[i];
cfebc465 359 struct sun_info *info = &sunlabel->vtoc.infos[i];
899736f1
DM
360
361 if (part->num_sectors &&
cfebc465
KZ
362 be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED &&
363 be16_to_cpu(info->id) != SUN_TAG_WHOLEDISK) {
a1ac3a0c 364 starts[i] = be32_to_cpu(part->start_cylinder) *
9e6ccaab 365 sectors_per_cylinder;
a1ac3a0c 366 lens[i] = be32_to_cpu(part->num_sectors);
2b6fc908 367 if (continuous) {
9e6ccaab 368 if (starts[i] == *start) {
2b6fc908 369 *start += lens[i];
9e6ccaab
MV
370 int remained_sectors = *start % sectors_per_cylinder;
371 if (remained_sectors) {
372 *start += sectors_per_cylinder - remained_sectors;
373 }
374 } else if (starts[i] + lens[i] >= *stop)
2b6fc908
KZ
375 *stop = starts[i];
376 else
22853e4a
KZ
377 continuous = 0;
378 /* There will be probably more gaps
379 than one, so lets check afterwards */
2b6fc908
KZ
380 }
381 } else {
382 starts[i] = 0;
383 lens[i] = 0;
384 }
385 }
5672ba4f
TW
386 for (i = cxt->label->nparts_max; i < SUN_MAXPARTITIONS; i++) {
387 starts[i] = 0;
388 lens[i] = 0;
389 }
2b6fc908
KZ
390}
391
7a11adde
RM
392/* non-Linux qsort_r(3) has usually differently ordered arguments */
393#if !defined (__linux__) || !defined (__GLIBC__)
394# undef HAVE_QSORT_R
395#endif
396
9c7955da 397#ifdef HAVE_QSORT_R
c69bbca9 398static int verify_sun_cmp(int *a, int *b, void *data)
899736f1 399{
c69bbca9
KZ
400 unsigned int *verify_sun_starts = (unsigned int *) data;
401
899736f1
DM
402 if (*a == -1)
403 return 1;
404 if (*b == -1)
405 return -1;
406 if (verify_sun_starts[*a] > verify_sun_starts[*b])
407 return 1;
2b6fc908
KZ
408 return -1;
409}
9c7955da 410#endif
2b6fc908 411
9ffeb235 412static int sun_verify_disklabel(struct fdisk_context *cxt)
899736f1 413{
cfebc465 414 uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS], start, stop;
e99da659 415 uint32_t i,j,k,starto,endo;
9c7955da 416#ifdef HAVE_QSORT_R
cfebc465 417 int array[SUN_MAXPARTITIONS];
c69bbca9 418 unsigned int *verify_sun_starts;
9c7955da 419#endif
137b57e5 420 assert(cxt);
9ffeb235 421 assert(cxt->label);
aa36c2cf 422 assert(fdisk_is_label(cxt, SUN));
137b57e5 423
9ffeb235 424 fetch_sun(cxt, starts, lens, &start, &stop);
899736f1 425
2b6fc908 426 for (k = 0; k < 7; k++) {
cfebc465 427 for (i = 0; i < SUN_MAXPARTITIONS; i++) {
829f4206
KZ
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);
2b6fc908
KZ
430 if (lens[i]) {
431 for (j = 0; j < i; j++)
432 if (lens[j]) {
433 if (starts[j] == starts[i]+lens[i]) {
434 starts[j] = starts[i]; lens[j] += lens[i];
435 lens[i] = 0;
436 } else if (starts[i] == starts[j]+lens[j]){
437 lens[j] += lens[i];
438 lens[i] = 0;
439 } else if (!k) {
440 if (starts[i] < starts[j]+lens[j] &&
441 starts[j] < starts[i]+lens[i]) {
442 starto = starts[i];
443 if (starts[j] > starto)
444 starto = starts[j];
445 endo = starts[i]+lens[i];
446 if (starts[j]+lens[j] < endo)
447 endo = starts[j]+lens[j];
829f4206
KZ
448 fdisk_warnx(cxt, _("Partition %u overlaps with others in "
449 "sectors %u-%u."), i+1, starto, endo);
2b6fc908
KZ
450 }
451 }
452 }
453 }
454 }
455 }
c69bbca9 456
9c7955da 457#ifdef HAVE_QSORT_R
cfebc465 458 for (i = 0; i < SUN_MAXPARTITIONS; i++) {
2b6fc908
KZ
459 if (lens[i])
460 array[i] = i;
461 else
462 array[i] = -1;
463 }
9c7955da
KZ
464 verify_sun_starts = starts;
465
c69bbca9
KZ
466 qsort_r(array,ARRAY_SIZE(array),sizeof(array[0]),
467 (int (*)(const void *,const void *,void *)) verify_sun_cmp,
468 verify_sun_starts);
38b36353 469
2b6fc908 470 if (array[0] == -1) {
ac1a559a 471 fdisk_info(cxt, _("No partitions defined."));
2ca61a61 472 return 0;
2b6fc908 473 }
24cd580b 474 stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors;
2b6fc908 475 if (starts[array[0]])
829f4206 476 fdisk_warnx(cxt, _("Unused gap - sectors 0-%u."), starts[array[0]]);
2b6fc908 477 for (i = 0; i < 7 && array[i+1] != -1; i++) {
829f4206 478 fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."),
899736f1
DM
479 (starts[array[i]] + lens[array[i]]),
480 starts[array[i+1]]);
2b6fc908 481 }
899736f1 482 start = (starts[array[i]] + lens[array[i]]);
2b6fc908 483 if (start < stop)
829f4206 484 fdisk_warnx(cxt, _("Unused gap - sectors %u-%u."), start, stop);
9c7955da 485#endif
2ca61a61 486 return 0;
2b6fc908
KZ
487}
488
77d6a70a
KZ
489
490static int is_free_sector(struct fdisk_context *cxt,
0073a4cf 491 fdisk_sector_t s, uint32_t starts[], uint32_t lens[])
77d6a70a
KZ
492{
493 size_t i;
494
495 for (i = 0; i < cxt->label->nparts_max; i++) {
496 if (lens[i] && starts[i] <= s
497 && starts[i] + lens[i] > s)
498 return 0;
499 }
500 return 1;
501}
502
8a95621d
KZ
503static int sun_add_partition(
504 struct fdisk_context *cxt,
c3bc7483
KZ
505 struct fdisk_partition *pa,
506 size_t *partno)
899736f1 507{
cfebc465
KZ
508 struct sun_disklabel *sunlabel = self_disklabel(cxt);
509 uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS];
77d6a70a
KZ
510 struct sun_partition *part;
511 struct sun_info *info;
65fb3668 512 uint32_t start, stop, stop2;
77d6a70a 513 int whole_disk = 0;
a745611d 514 int sys = pa && pa->type ? pa->type->code : SUN_TAG_LINUX_NATIVE;
9ff2ce0a 515 int rc;
77d6a70a 516 size_t n;
50ea6795 517
eb63b9b8 518 char mesg[256];
137b57e5 519 size_t i;
e99da659 520 unsigned int first, last;
2b6fc908 521
9c76f85f
KZ
522 DBG(LABEL, ul_debug("SUN adding partition"));
523
6c89f750 524 rc = fdisk_partition_next_partno(pa, cxt, &n);
77d6a70a
KZ
525 if (rc)
526 return rc;
527
528 part = &sunlabel->partitions[n];
529 info = &sunlabel->vtoc.infos[n];
530
cfebc465 531 if (part->num_sectors && be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED) {
829f4206 532 fdisk_info(cxt, _("Partition %zu is already defined. Delete "
9eac213c 533 "it before re-adding it."), n + 1);
8254c3a5 534 return -EINVAL;
2b6fc908 535 }
50ea6795 536
9ffeb235 537 fetch_sun(cxt, starts, lens, &start, &stop);
50ea6795 538
f7606d2d
KZ
539 if (pa && pa->type && pa->type->code == SUN_TAG_WHOLEDISK)
540 whole_disk = 1;
541
2b6fc908
KZ
542 if (stop <= start) {
543 if (n == 2)
544 whole_disk = 1;
545 else {
9eac213c
KZ
546 fdisk_info(cxt, _("Other partitions already cover the "
547 "whole disk. Delete some/shrink them before retry."));
8254c3a5 548 return -EINVAL;
2b6fc908
KZ
549 }
550 }
9ff2ce0a 551
77d6a70a
KZ
552 if (pa && pa->start_follow_default)
553 first = start;
ecf40cda 554 else if (pa && fdisk_partition_has_start(pa)) {
77d6a70a 555 first = pa->start;
9ff2ce0a 556
77d6a70a
KZ
557 if (!whole_disk && !is_free_sector(cxt, first, starts, lens))
558 return -ERANGE;
559 } else {
560 struct fdisk_ask *ask;
561
27895be2
MV
562 if (n == 2)
563 fdisk_info(cxt, _("It is highly recommended that the "
564 "third partition covers the whole disk "
565 "and is of type `Whole disk'"));
566
77d6a70a 567 snprintf(mesg, sizeof(mesg), _("First %s"),
385810d2 568 fdisk_get_unit(cxt, FDISK_SINGULAR));
77d6a70a
KZ
569 for (;;) {
570 ask = fdisk_new_ask();
571 if (!ask)
572 return -ENOMEM;
573
574 fdisk_ask_set_query(ask, mesg);
575 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
576
577 if (whole_disk) {
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 */
27895be2
MV
581 } else if (n == 2) {
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 */
77d6a70a
KZ
585 } else {
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 */
589 }
590 rc = fdisk_do_ask(cxt, ask);
591 first = fdisk_ask_number_get_result(ask);
a3d83488 592 fdisk_unref_ask(ask);
77d6a70a
KZ
593 if (rc)
594 return rc;
595
6a632136
KZ
596 if (fdisk_use_cylinders(cxt))
597 first *= fdisk_get_units_per_sector(cxt);
77d6a70a 598
45ce1487
MV
599 if (!fdisk_use_cylinders(cxt)) {
600 /* Starting sector has to be properly aligned */
601 int cs = cxt->geom.heads * cxt->geom.sectors;
602 int x = first % cs;
603
604 if (x) {
605 fdisk_info(cxt, _("Aligning the first sector from %u to %u "
606 "to be on cylinder boundary."),
607 first, first + cs - x);
608 first += cs - x;
609 }
610 }
611
77d6a70a
KZ
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
627 be trashed. */
628 if (!is_free_sector(cxt, first, starts, lens) && !whole_disk) {
629 if (n == 2 && !first) {
630 whole_disk = 1;
631 break;
632 }
633 fdisk_warnx(cxt, _("Sector %d is already allocated"), first);
634 } else
635 break;
9ff2ce0a 636 }
77d6a70a 637 }
9ff2ce0a 638
24cd580b 639 stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; /* ancient */
2b6fc908 640 stop2 = stop;
9ffeb235 641 for (i = 0; i < cxt->label->nparts_max; i++) {
2b6fc908
KZ
642 if (starts[i] > first && starts[i] < stop)
643 stop = starts[i];
644 }
77d6a70a
KZ
645
646 /* last */
647 if (pa && pa->end_follow_default)
648 last = whole_disk || (n == 2 && !first) ? stop2 : stop;
f7606d2d 649
ecf40cda 650 else if (pa && fdisk_partition_has_size(pa)) {
f7606d2d 651 last = first + pa->size;
77d6a70a
KZ
652
653 if (!whole_disk && last > stop)
654 return -ERANGE;
9ff2ce0a 655 } else {
77d6a70a 656 struct fdisk_ask *ask = fdisk_new_ask();
9ff2ce0a 657
77d6a70a
KZ
658 if (!ask)
659 return -ENOMEM;
9ff2ce0a 660
77d6a70a 661 snprintf(mesg, sizeof(mesg),
757cefbb 662 _("Last %s or +/-%s or +/-size{K,M,G,T,P}"),
385810d2
KZ
663 fdisk_get_unit(cxt, FDISK_SINGULAR),
664 fdisk_get_unit(cxt, FDISK_PLURAL));
77d6a70a
KZ
665 fdisk_ask_set_query(ask, mesg);
666 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
9ff2ce0a 667
77d6a70a
KZ
668 if (whole_disk) {
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));
678 } else {
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));
683 }
684
757cefbb
AG
685 fdisk_ask_number_set_wrap_negative(ask, 1); /* wrap negative around high */
686
6a632136 687 if (fdisk_use_cylinders(cxt))
77d6a70a
KZ
688 fdisk_ask_number_set_unit(ask,
689 cxt->sector_size *
6a632136 690 fdisk_get_units_per_sector(cxt));
77d6a70a
KZ
691 else
692 fdisk_ask_number_set_unit(ask, cxt->sector_size);
9ff2ce0a 693
77d6a70a
KZ
694 rc = fdisk_do_ask(cxt, ask);
695 last = fdisk_ask_number_get_result(ask);
696
a3d83488 697 fdisk_unref_ask(ask);
77d6a70a
KZ
698 if (rc)
699 return rc;
6a632136
KZ
700 if (fdisk_use_cylinders(cxt))
701 last *= fdisk_get_units_per_sector(cxt);
77d6a70a 702 }
80063996 703
2b6fc908
KZ
704 if (n == 2 && !first) {
705 if (last >= stop2) {
706 whole_disk = 1;
707 last = stop2;
708 } else if (last > stop) {
9eac213c 709 fdisk_warnx(cxt,
7eda085c 710 _("You haven't covered the whole disk with the 3rd partition, but your value\n"
829f4206
KZ
711 "%lu %s covers some other partition. Your entry has been changed\n"
712 "to %lu %s"),
385810d2
KZ
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));
2b6fc908
KZ
715 last = stop;
716 }
717 } else if (!whole_disk && last > stop)
718 last = stop;
719
899736f1 720 if (whole_disk)
cfebc465 721 sys = SUN_TAG_WHOLEDISK;
899736f1 722
9c76f85f
KZ
723 DBG(LABEL, ul_debug("SUN new partition #%zu: first=%u, last=%u, sys=%d", n, first, last, sys));
724
ea50ba5b 725 set_partition(cxt, n, first, last, sys);
9ffeb235 726 cxt->label->nparts_cur = count_used_partitions(cxt);
c3bc7483
KZ
727 if (partno)
728 *partno = n;
8254c3a5 729 return 0;
2b6fc908
KZ
730}
731
8a95621d 732static int sun_delete_partition(struct fdisk_context *cxt,
9ffeb235 733 size_t partnum)
899736f1 734{
cfebc465 735 struct sun_disklabel *sunlabel;
d6ab93f1 736 struct sun_partition *part;
cfebc465 737 struct sun_info *info;
df1dddf9
KZ
738 unsigned int nsec;
739
137b57e5 740 assert(cxt);
9ffeb235 741 assert(cxt->label);
aa36c2cf 742 assert(fdisk_is_label(cxt, SUN));
137b57e5 743
9ffeb235 744 sunlabel = self_disklabel(cxt);
d6ab93f1 745 part = &sunlabel->partitions[partnum];
cfebc465 746 info = &sunlabel->vtoc.infos[partnum];
d6ab93f1 747
61c4cb85 748 if (partnum == 2 &&
cfebc465 749 be16_to_cpu(info->id) == SUN_TAG_WHOLEDISK &&
899736f1 750 !part->start_cylinder &&
a1ac3a0c 751 (nsec = be32_to_cpu(part->num_sectors))
1f5eb51b 752 == cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders)
9eac213c
KZ
753 fdisk_info(cxt, _("If you want to maintain SunOS/Solaris compatibility, "
754 "consider leaving this "
1f5eb51b 755 "partition as Whole disk (5), starting at 0, with %u "
9eac213c 756 "sectors"), nsec);
cfebc465 757 info->id = cpu_to_be16(SUN_TAG_UNASSIGNED);
899736f1 758 part->num_sectors = 0;
9ffeb235
KZ
759 cxt->label->nparts_cur = count_used_partitions(cxt);
760 fdisk_label_set_changed(cxt->label, 1);
1f5eb51b 761 return 0;
2b6fc908
KZ
762}
763
5989556a 764static int sun_get_disklabel_item(struct fdisk_context *cxt, struct fdisk_labelitem *item)
899736f1 765{
cfebc465 766 struct sun_disklabel *sunlabel;
5989556a 767 int rc = 0;
137b57e5
KZ
768
769 assert(cxt);
770 assert(cxt->label);
aa36c2cf 771 assert(fdisk_is_label(cxt, SUN));
2b6fc908 772
9ffeb235 773 sunlabel = self_disklabel(cxt);
d6ab93f1 774
5989556a
KZ
775 switch (item->id) {
776 case SUN_LABELITEM_LABELID:
777 item->name =_("Label ID");
778 item->type = 's';
779 item->data.str = *sunlabel->label_id ? strndup((char *)sunlabel->label_id, sizeof(sunlabel->label_id)) : NULL;
780 break;
781 case SUN_LABELITEM_VTOCID:
782 item->name =_("Volume ID");
783 item->type = 's';
784 item->data.str = *sunlabel->vtoc.volume_id ? strndup((char *)sunlabel->vtoc.volume_id, sizeof(sunlabel->vtoc.volume_id)) : NULL;
785 break;
786 case SUN_LABELITEM_RPM:
787 item->name =_("Rpm");
788 item->type = 'j';
789 item->data.num64 = be16_to_cpu(sunlabel->rpm);
790 break;
791 case SUN_LABELITEM_ACYL:
792 item->name =_("Alternate cylinders");
793 item->type = 'j';
794 item->data.num64 = be16_to_cpu(sunlabel->acyl);
795 break;
796 case SUN_LABELITEM_PCYL:
797 item->name =_("Physical cylinders");
798 item->type = 'j';
799 item->data.num64 = be16_to_cpu(sunlabel->pcyl);
800 break;
801 case SUN_LABELITEM_APC:
802 item->name =_("Extra sects/cyl");
803 item->type = 'j';
804 item->data.num64 = be16_to_cpu(sunlabel->apc);
805 break;
806 case SUN_LABELITEM_INTRLV:
807 item->name =_("Interleave");
808 item->type = 'j';
809 item->data.num64 = be16_to_cpu(sunlabel->intrlv);
810 break;
811 default:
812 if (item->id < __FDISK_NLABELITEMS)
9e930041 813 rc = 1; /* unsupported generic item */
5989556a
KZ
814 else
815 rc = 2; /* out of range */
816 break;
ac1a559a 817 }
2b6fc908 818
5989556a 819 return rc;
0a2aedf0 820}
0e5bafbe 821
27d4d072
KZ
822static struct fdisk_parttype *sun_get_parttype(
823 struct fdisk_context *cxt,
824 size_t n)
825{
826 struct sun_disklabel *sunlabel = self_disklabel(cxt);
827 struct fdisk_parttype *t;
828
829 if (n >= cxt->label->nparts_max)
830 return NULL;
831
a745611d
KZ
832 t = fdisk_label_get_parttype_from_code(cxt->label,
833 be16_to_cpu(sunlabel->vtoc.infos[n].id));
27d4d072
KZ
834 return t ? : fdisk_new_unknown_parttype(be16_to_cpu(sunlabel->vtoc.infos[n].id), NULL);
835}
836
837
0a2aedf0
KZ
838static int sun_get_partition(struct fdisk_context *cxt, size_t n,
839 struct fdisk_partition *pa)
840{
841 struct sun_disklabel *sunlabel;
842 struct sun_partition *part;
843 uint16_t flags;
b4251e51 844 uint64_t start, len;
0e5bafbe 845
0a2aedf0
KZ
846 assert(cxt);
847 assert(cxt->label);
aa36c2cf 848 assert(fdisk_is_label(cxt, SUN));
0a2aedf0
KZ
849
850 if (n >= cxt->label->nparts_max)
851 return -EINVAL;
852
853 sunlabel = self_disklabel(cxt);
854 part = &sunlabel->partitions[n];
855
856 pa->used = part->num_sectors ? 1 : 0;
857 if (!pa->used)
858 return 0;
859
860 flags = be16_to_cpu(sunlabel->vtoc.infos[n].flags);
b4251e51 861 start = (uint64_t) be32_to_cpu(part->start_cylinder)
0a2aedf0
KZ
862 * cxt->geom.heads * cxt->geom.sectors;
863 len = be32_to_cpu(part->num_sectors);
864
27d4d072 865 pa->type = sun_get_parttype(cxt, n);
a745611d 866 if (pa->type && pa->type->code == SUN_TAG_WHOLEDISK)
ef97e92b 867 pa->wholedisk = 1;
0a2aedf0
KZ
868
869 if (flags & SUN_FLAG_UNMNT || flags & SUN_FLAG_RONLY) {
870 if (asprintf(&pa->attrs, "%c%c",
0e5bafbe 871 flags & SUN_FLAG_UNMNT ? 'u' : ' ',
0a2aedf0
KZ
872 flags & SUN_FLAG_RONLY ? 'r' : ' ') < 0)
873 return -ENOMEM;
2b6fc908 874 }
b1b1a7b7 875
77d6a70a 876 pa->start = start;
77d6a70a 877 pa->size = len;
0e5bafbe 878
0a2aedf0 879 return 0;
2b6fc908
KZ
880}
881
fd979f5b
KZ
882/**
883 * fdisk_sun_set_alt_cyl:
884 * @cxt: context
885 *
886 * Sets number of alternative cylinders. This function uses libfdisk Ask API
887 * for dialog with user.
888 *
889 * Returns: 0 on success, <0 on error.
890 */
4170ae9c 891int fdisk_sun_set_alt_cyl(struct fdisk_context *cxt)
899736f1 892{
cfebc465 893 struct sun_disklabel *sunlabel = self_disklabel(cxt);
c69bbca9
KZ
894 uintmax_t res;
895 int rc = fdisk_ask_number(cxt, 0, /* low */
896 be16_to_cpu(sunlabel->acyl), /* default */
897 65535, /* high */
898 _("Number of alternate cylinders"), /* query */
899 &res); /* result */
4170ae9c
KZ
900 if (rc)
901 return rc;
2b6fc908 902
4170ae9c
KZ
903 sunlabel->acyl = cpu_to_be16(res);
904 return 0;
2b6fc908
KZ
905}
906
fd979f5b
KZ
907/**
908 * fdisk_sun_set_xcyl:
909 * @cxt: context
910 *
911 * Sets number of extra sectors per cylinder. This function uses libfdisk Ask API
912 * for dialog with user.
913 *
914 * Returns: 0 on success, <0 on error.
915 */
4170ae9c 916int fdisk_sun_set_xcyl(struct fdisk_context *cxt)
899736f1 917{
cfebc465 918 struct sun_disklabel *sunlabel = self_disklabel(cxt);
c69bbca9
KZ
919 uintmax_t res;
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 */
924 &res); /* result */
4170ae9c
KZ
925 if (rc)
926 return rc;
927 sunlabel->apc = cpu_to_be16(res);
928 return 0;
2b6fc908
KZ
929}
930
fd979f5b
KZ
931/**
932 * fdisk_sun_set_ilfact:
933 * @cxt: context
934 *
935 * Sets interleave factor. This function uses libfdisk Ask API for dialog with
936 * user.
937 *
938 * Returns: 0 on success, <0 on error.
939 */
4170ae9c 940int fdisk_sun_set_ilfact(struct fdisk_context *cxt)
899736f1 941{
cfebc465 942 struct sun_disklabel *sunlabel = self_disklabel(cxt);
c69bbca9
KZ
943 uintmax_t res;
944 int rc = fdisk_ask_number(cxt, 1, /* low */
945 be16_to_cpu(sunlabel->intrlv), /* default */
946 32, /* high */
947 _("Interleave factor"), /* query */
948 &res); /* result */
4170ae9c
KZ
949 if (rc)
950 return rc;
951 sunlabel->intrlv = cpu_to_be16(res);
952 return 0;
2b6fc908
KZ
953}
954
fd979f5b
KZ
955/**
956 * fdisk_sun_set_rspeed
957 * @cxt: context
958 *
959 * Sets rotation speed. This function uses libfdisk Ask API for dialog with
960 * user.
961 *
962 * Returns: 0 on success, <0 on error.
963 */
4170ae9c 964int fdisk_sun_set_rspeed(struct fdisk_context *cxt)
899736f1 965{
cfebc465 966 struct sun_disklabel *sunlabel = self_disklabel(cxt);
c69bbca9
KZ
967 uintmax_t res;
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 */
972 &res); /* result */
4170ae9c
KZ
973 if (rc)
974 return rc;
975 sunlabel->rpm = cpu_to_be16(res);
976 return 0;
2b6fc908
KZ
977}
978
fd979f5b
KZ
979/**
980 * fdisk_sun_set_pcylcount
981 * @cxt: context
982 *
983 * Sets number of physical cylinders. This function uses libfdisk Ask API for
984 * dialog with user.
985 *
986 * Returns: 0 on success, <0 on error.
987 */
4170ae9c 988int fdisk_sun_set_pcylcount(struct fdisk_context *cxt)
899736f1 989{
cfebc465 990 struct sun_disklabel *sunlabel = self_disklabel(cxt);
c69bbca9
KZ
991 uintmax_t res;
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 */
996 &res); /* result */
997 if (!rc)
4170ae9c
KZ
998 return rc;
999 sunlabel->pcyl = cpu_to_be16(res);
1000 return 0;
2b6fc908
KZ
1001}
1002
9ffeb235 1003static int sun_write_disklabel(struct fdisk_context *cxt)
899736f1 1004{
cfebc465 1005 struct sun_disklabel *sunlabel;
b4bfbadd 1006 const size_t sz = sizeof(struct sun_disklabel);
2b6fc908 1007
137b57e5 1008 assert(cxt);
9ffeb235 1009 assert(cxt->label);
aa36c2cf 1010 assert(fdisk_is_label(cxt, SUN));
d6ab93f1 1011
9ffeb235 1012 sunlabel = self_disklabel(cxt);
4170ae9c
KZ
1013
1014 /* Maybe geometry has been modified */
1015 sunlabel->nhead = cpu_to_be16(cxt->geom.heads);
1016 sunlabel->nsect = cpu_to_be16(cxt->geom.sectors);
1017
7ee26cbf
SK
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;
1022 }
4170ae9c 1023
7f387c5c
RM
1024 sunlabel->csum = 0;
1025 sunlabel->csum = sun_pt_checksum(sunlabel);
137b57e5 1026
823f0fd1 1027 if (lseek(cxt->dev_fd, 0, SEEK_SET) < 0)
fae7b1bc 1028 return -errno;
b4bfbadd 1029 if (write_all(cxt->dev_fd, sunlabel, sz) != 0)
fae7b1bc
DB
1030 return -errno;
1031
1032 return 0;
2b6fc908 1033}
899736f1 1034
ea50ba5b 1035static int sun_set_partition(
8a95621d 1036 struct fdisk_context *cxt,
9ffeb235 1037 size_t i,
ea50ba5b 1038 struct fdisk_partition *pa)
02460b8a 1039{
cfebc465 1040 struct sun_disklabel *sunlabel;
02460b8a 1041 struct sun_partition *part;
cfebc465 1042 struct sun_info *info;
02460b8a 1043
137b57e5 1044 assert(cxt);
9ffeb235 1045 assert(cxt->label);
aa36c2cf 1046 assert(fdisk_is_label(cxt, SUN));
137b57e5 1047
9ffeb235 1048 sunlabel = self_disklabel(cxt);
d6ab93f1 1049
ea50ba5b 1050 if (i >= cxt->label->nparts_max)
02460b8a
KZ
1051 return -EINVAL;
1052
ea50ba5b
KZ
1053 if (pa->type) {
1054 struct fdisk_parttype *t = pa->type;
02460b8a 1055
ea50ba5b
KZ
1056 if (t->code > UINT16_MAX)
1057 return -EINVAL;
1058
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"));
1062
1063 part = &sunlabel->partitions[i];
1064 info = &sunlabel->vtoc.infos[i];
1065
1066 if (cxt->script == NULL &&
1067 t->code == SUN_TAG_LINUX_SWAP && !part->start_cylinder) {
1068 int yes, rc;
1069
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);
1075 if (rc)
1076 return rc;
1077 if (!yes)
1078 return 1;
1079 }
1080
1081 switch (t->code) {
1082 case SUN_TAG_SWAP:
1083 case SUN_TAG_LINUX_SWAP:
1084 /* swaps are not mountable by default */
1085 info->flags |= cpu_to_be16(SUN_FLAG_UNMNT);
1086 break;
1087 default:
1088 /* assume other types are mountable;
1089 user can change it anyway */
1090 info->flags &= ~cpu_to_be16(SUN_FLAG_UNMNT);
1091 break;
1092 }
1093 info->id = cpu_to_be16(t->code);
02460b8a 1094 }
ea50ba5b 1095
ecf40cda 1096 if (fdisk_partition_has_start(pa))
ea50ba5b
KZ
1097 sunlabel->partitions[i].start_cylinder =
1098 cpu_to_be32(pa->start / (cxt->geom.heads * cxt->geom.sectors));
ecf40cda 1099 if (fdisk_partition_has_size(pa))
ea50ba5b
KZ
1100 sunlabel->partitions[i].num_sectors = cpu_to_be32(pa->size);
1101
1102 fdisk_label_set_changed(cxt->label, 1);
02460b8a
KZ
1103 return 0;
1104}
1105
3c88fb56 1106
ec10aa67 1107static int sun_reset_alignment(struct fdisk_context *cxt __attribute__((__unused__)))
3c88fb56 1108{
9c76f85f 1109 fdisk_set_first_lba(cxt, 0);
3c88fb56
KZ
1110 return 0;
1111}
1112
47b8e7c0 1113
8c0a7f91 1114static int sun_partition_is_used(
47b8e7c0 1115 struct fdisk_context *cxt,
8c0a7f91 1116 size_t i)
47b8e7c0 1117{
cfebc465 1118 struct sun_disklabel *sunlabel;
9ffeb235
KZ
1119
1120 assert(cxt);
1121 assert(cxt->label);
aa36c2cf 1122 assert(fdisk_is_label(cxt, SUN));
47b8e7c0 1123
8c0a7f91
KZ
1124 if (i >= cxt->label->nparts_max)
1125 return 0;
47b8e7c0 1126
9ffeb235 1127 sunlabel = self_disklabel(cxt);
8c0a7f91 1128 return sunlabel->partitions[i].num_sectors ? 1 : 0;
47b8e7c0
KZ
1129}
1130
bd85d11f 1131static const struct fdisk_field sun_fields[] =
0a2aedf0 1132{
bd85d11f
KZ
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 }
0a2aedf0
KZ
1142};
1143
2ba641e5 1144static const struct fdisk_label_operations sun_operations =
b8855c86 1145{
0c5d095e
KZ
1146 .probe = sun_probe_label,
1147 .write = sun_write_disklabel,
1148 .verify = sun_verify_disklabel,
1149 .create = sun_create_disklabel,
5989556a 1150 .get_item = sun_get_disklabel_item,
0a2aedf0
KZ
1151
1152 .get_part = sun_get_partition,
ea50ba5b 1153 .set_part = sun_set_partition,
77d6a70a 1154 .add_part = sun_add_partition,
e11c6684 1155 .del_part = sun_delete_partition,
0a2aedf0 1156
8c0a7f91 1157 .part_is_used = sun_partition_is_used,
fb1caca7 1158 .part_toggle_flag = sun_toggle_partition_flag,
47b8e7c0
KZ
1159
1160 .reset_alignment = sun_reset_alignment,
b8855c86 1161};
0c5d095e
KZ
1162
1163/*
1164 * allocates SUN label driver
1165 */
01aec449 1166struct fdisk_label *fdisk_new_sun_label(struct fdisk_context *cxt __attribute__ ((__unused__)))
0c5d095e
KZ
1167{
1168 struct fdisk_label *lb;
1169 struct fdisk_sun_label *sun;
1170
0c5d095e
KZ
1171 sun = calloc(1, sizeof(*sun));
1172 if (!sun)
1173 return NULL;
1174
1175 /* initialize generic part of the driver */
1176 lb = (struct fdisk_label *) sun;
1177 lb->name = "sun";
53b422ab 1178 lb->id = FDISK_DISKLABEL_SUN;
0c5d095e
KZ
1179 lb->op = &sun_operations;
1180 lb->parttypes = sun_parttypes;
a745611d 1181 lb->nparttypes = ARRAY_SIZE(sun_parttypes) - 1;
bd85d11f
KZ
1182 lb->fields = sun_fields;
1183 lb->nfields = ARRAY_SIZE(sun_fields);
caad8583
KZ
1184 lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
1185
2dd2880f
KZ
1186 lb->geom_min.sectors = 1;
1187 lb->geom_min.heads = 1;
1188 lb->geom_min.cylinders = 1;
1189
1190 lb->geom_max.sectors = 1024;
1191 lb->geom_max.heads = 1024;
1192 lb->geom_max.cylinders = USHRT_MAX;
fe7ef272
KZ
1193
1194 /* return calloc() result to keep static anaylizers happy */
1195 return (struct fdisk_label *) sun;
0c5d095e 1196}