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