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