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