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