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