]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libfdisk/src/bsd.c
libfdisk: (bsd) improve checksum calculation [-Waddress-of-packed-member]
[thirdparty/util-linux.git] / libfdisk / src / bsd.c
CommitLineData
726f69e2 1/*
d5b2b8db
KZ
2 * Copyright (C) 2007-2013 Karel Zak <kzak@redhat.com>
3 *
4 * Based on the original code from fdisk
5 * written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
6 * with code from the NetBSD disklabel command.
7 *
8 * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, March 1999
9 * David Huggins-Daines <dhuggins@linuxcare.com>, January 2000
10 */
726f69e2
KZ
11#include <unistd.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <fcntl.h>
726f69e2 16#include <errno.h>
726f69e2
KZ
17#include <sys/param.h>
18
d5b2b8db
KZ
19#include "blkdev.h"
20#include "fdiskP.h"
bb58112e 21#include "pt-mbr.h"
d5b2b8db 22#include "pt-bsd.h"
9e346a02 23#include "all-io.h"
726f69e2 24
a4e6a45e
KZ
25
26/**
27 * SECTION: bsd
705854f3
KZ
28 * @title: BSD
29 * @short_description: disk label specific functions
a4e6a45e
KZ
30 *
31 */
32
19c2cc4e 33static const char *bsd_dktypenames[] = {
e11858e2
KZ
34 "unknown",
35 "SMD",
36 "MSCP",
37 "old DEC",
38 "SCSI",
39 "ESDI",
40 "ST506",
41 "HP-IB",
42 "HP-FL",
43 "type 9",
44 "floppy",
87918040 45 NULL
e11858e2 46};
2872ffa0 47#define BSD_DKMAXTYPES (ARRAY_SIZE(bsd_dktypenames) - 1)
e11858e2 48
2872ffa0 49static struct fdisk_parttype bsd_fstypes[] = {
e11858e2
KZ
50 {BSD_FS_UNUSED, "unused"},
51 {BSD_FS_SWAP, "swap"},
52 {BSD_FS_V6, "Version 6"},
53 {BSD_FS_V7, "Version 7"},
54 {BSD_FS_SYSV, "System V"},
55 {BSD_FS_V71K, "4.1BSD"},
56 {BSD_FS_V8, "Eighth Edition"},
57 {BSD_FS_BSDFFS, "4.2BSD"},
58#ifdef __alpha__
59 {BSD_FS_EXT2, "ext2"},
60#else
61 {BSD_FS_MSDOS, "MS-DOS"},
62#endif
63 {BSD_FS_BSDLFS, "4.4LFS"},
64 {BSD_FS_OTHER, "unknown"},
65 {BSD_FS_HPFS, "HPFS"},
66 {BSD_FS_ISO9660,"ISO-9660"},
67 {BSD_FS_BOOT, "boot"},
68 {BSD_FS_ADOS, "ADOS"},
69 {BSD_FS_HFS, "HFS"},
70 {BSD_FS_ADVFS, "AdvFS"},
71 { 0, NULL }
72};
2872ffa0 73#define BSD_FSMAXTYPES (ARRAY_SIZE(bsd_fstypes)-1)
e11858e2 74
0c5d095e
KZ
75/*
76 * in-memory fdisk BSD stuff
77 */
78struct fdisk_bsd_label {
79 struct fdisk_label head; /* generic part */
0efc6c57
KZ
80
81 struct dos_partition *dos_part; /* parent */
82 struct bsd_disklabel bsd; /* on disk label */
87ed95ff
KZ
83#if defined (__alpha__)
84 /* We access this through a u_int64_t * when checksumming */
85 char bsdbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
86#else
87 char bsdbuffer[BSD_BBSIZE];
88#endif
0c5d095e
KZ
89};
90
2872ffa0
KZ
91static int bsd_initlabel(struct fdisk_context *cxt);
92static int bsd_readlabel(struct fdisk_context *cxt);
296b856d 93static void sync_disks(struct fdisk_context *cxt);
0efc6c57 94
0efc6c57
KZ
95static inline struct fdisk_bsd_label *self_label(struct fdisk_context *cxt)
96{
97 assert(cxt);
98 assert(cxt->label);
aa36c2cf 99 assert(fdisk_is_label(cxt, BSD));
0efc6c57
KZ
100
101 return (struct fdisk_bsd_label *) cxt->label;
102}
103
104static inline struct bsd_disklabel *self_disklabel(struct fdisk_context *cxt)
105{
106 assert(cxt);
107 assert(cxt->label);
aa36c2cf 108 assert(fdisk_is_label(cxt, BSD));
0efc6c57
KZ
109
110 return &((struct fdisk_bsd_label *) cxt->label)->bsd;
111}
22853e4a 112
a699b27d
KZ
113static struct fdisk_parttype *bsd_partition_parttype(
114 struct fdisk_context *cxt,
115 struct bsd_partition *p)
116{
117 struct fdisk_parttype *t
a745611d 118 = fdisk_label_get_parttype_from_code(cxt->label, p->p_fstype);
a699b27d
KZ
119 return t ? : fdisk_new_unknown_parttype(p->p_fstype, NULL);
120}
121
122
0bf367ed 123#if defined (__alpha__)
19c2cc4e 124static void alpha_bootblock_checksum (char *boot)
0bf367ed
KZ
125{
126 uint64_t *dp = (uint64_t *) boot, sum = 0;
127 int i;
128
129 for (i = 0; i < 63; i++)
130 sum += dp[i];
131 dp[63] = sum;
132}
133#endif /* __alpha__ */
134
818d7924
KZ
135#define HIDDEN_MASK 0x10
136
137static int is_bsd_partition_type(int type)
138{
139 return (type == MBR_FREEBSD_PARTITION ||
140 type == (MBR_FREEBSD_PARTITION ^ HIDDEN_MASK) ||
141 type == MBR_NETBSD_PARTITION ||
142 type == (MBR_NETBSD_PARTITION ^ HIDDEN_MASK) ||
143 type == MBR_OPENBSD_PARTITION ||
144 type == (MBR_OPENBSD_PARTITION ^ HIDDEN_MASK));
145}
146
63cccae4 147/*
818d7924 148 * look for DOS partition usable for nested BSD partition table
63cccae4 149 */
0efc6c57 150static int bsd_assign_dos_partition(struct fdisk_context *cxt)
8a95621d 151{
0efc6c57 152 struct fdisk_bsd_label *l = self_label(cxt);
818d7924
KZ
153 size_t i;
154
818d7924 155 for (i = 0; i < 4; i++) {
0073a4cf 156 fdisk_sector_t ss;
818d7924 157
0efc6c57 158 l->dos_part = fdisk_dos_get_partition(cxt->parent, i);
0dd3dfb8 159
0efc6c57 160 if (!l->dos_part || !is_bsd_partition_type(l->dos_part->sys_ind))
818d7924
KZ
161 continue;
162
0efc6c57 163 ss = dos_partition_get_start(l->dos_part);
818d7924 164 if (!ss) {
296b856d
KZ
165 fdisk_warnx(cxt, _("Partition %zd: has invalid starting "
166 "sector 0."), i + 1);
818d7924
KZ
167 return -1;
168 }
169
170 if (cxt->parent->dev_path) {
171 free(cxt->dev_path);
172 cxt->dev_path = fdisk_partname(
173 cxt->parent->dev_path, i + 1);
174 }
175
88141067 176 DBG(LABEL, ul_debug("partition %zu assigned to BSD", i + 1));
63cccae4 177 return 0;
818d7924
KZ
178 }
179
296b856d
KZ
180 fdisk_warnx(cxt, _("There is no *BSD partition on %s."),
181 cxt->parent->dev_path);
0efc6c57
KZ
182 free(cxt->dev_path);
183 cxt->dev_path = NULL;
184 l->dos_part = NULL;
63cccae4 185 return 1;
22853e4a
KZ
186}
187
818d7924
KZ
188static int bsd_probe_label(struct fdisk_context *cxt)
189{
190 int rc = 0;
818d7924
KZ
191
192 if (cxt->parent)
9e930041 193 rc = bsd_assign_dos_partition(cxt); /* nested BSD partition table */
818d7924 194 if (!rc)
2872ffa0 195 rc = bsd_readlabel(cxt);
818d7924
KZ
196 if (!rc)
197 return 1; /* found BSD */
198 return 0; /* not found */
199}
200
7f63194a
KZ
201static int set_parttype(
202 struct fdisk_context *cxt,
203 size_t partnum,
204 struct fdisk_parttype *t)
205{
206 struct bsd_partition *p;
207 struct bsd_disklabel *d = self_disklabel(cxt);
208
209 if (partnum >= d->d_npartitions || !t || t->code > UINT8_MAX)
210 return -EINVAL;
211
212 p = &d->d_partitions[partnum];
213 if (t->code == p->p_fstype)
214 return 0;
215
216 p->p_fstype = t->code;
217 fdisk_label_set_changed(cxt->label, 1);
218 return 0;
219}
220
77d6a70a 221static int bsd_add_partition(struct fdisk_context *cxt,
c3bc7483
KZ
222 struct fdisk_partition *pa,
223 size_t *partno)
0f639e54 224{
0efc6c57
KZ
225 struct fdisk_bsd_label *l = self_label(cxt);
226 struct bsd_disklabel *d = self_disklabel(cxt);
77d6a70a 227 size_t i;
0efc6c57 228 unsigned int begin = 0, end;
77d6a70a 229 int rc = 0;
0f639e54 230
6c89f750 231 rc = fdisk_partition_next_partno(pa, cxt, &i);
77d6a70a
KZ
232 if (rc)
233 return rc;
0b08fb07 234 if (i >= BSD_MAXPARTITIONS)
77d6a70a 235 return -ERANGE;
0efc6c57
KZ
236 if (l->dos_part) {
237 begin = dos_partition_get_start(l->dos_part);
238 end = begin + dos_partition_get_size(l->dos_part) - 1;
239 } else
240 end = d->d_secperunit - 1;
9ffeb235 241
682802db
KZ
242 /*
243 * First sector
244 */
77d6a70a
KZ
245 if (pa && pa->start_follow_default)
246 ;
ecf40cda 247 else if (pa && fdisk_partition_has_start(pa)) {
77d6a70a
KZ
248 if (pa->start < begin || pa->start > end)
249 return -ERANGE;
250 begin = pa->start;
251 } else {
252 struct fdisk_ask *ask = fdisk_new_ask();
253
254 if (!ask)
255 return -ENOMEM;
256 fdisk_ask_set_query(ask,
6a632136 257 fdisk_use_cylinders(cxt) ?
77d6a70a
KZ
258 _("First cylinder") : _("First sector"));
259 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
260 fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
261 fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin));
262 fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));
263
264 rc = fdisk_do_ask(cxt, ask);
265 begin = fdisk_ask_number_get_result(ask);
a3d83488 266 fdisk_unref_ask(ask);
77d6a70a
KZ
267 if (rc)
268 return rc;
6a632136 269 if (fdisk_use_cylinders(cxt))
77d6a70a 270 begin = (begin - 1) * d->d_secpercyl;
682802db 271 }
682802db
KZ
272
273 /*
274 * Last sector
275 */
77d6a70a
KZ
276 if (pa && pa->end_follow_default)
277 ;
ecf40cda 278 else if (pa && fdisk_partition_has_size(pa)) {
77d6a70a
KZ
279 if (begin + pa->size > end)
280 return -ERANGE;
7f63194a 281 end = begin + pa->size - 1ULL;
682802db 282 } else {
77d6a70a
KZ
283 /* ask user by dialog */
284 struct fdisk_ask *ask = fdisk_new_ask();
285
286 if (!ask)
287 return -ENOMEM;
288 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
289
6a632136 290 if (fdisk_use_cylinders(cxt)) {
757cefbb 291 fdisk_ask_set_query(ask, _("Last cylinder, +/-cylinders or +/-size{K,M,G,T,P}"));
77d6a70a
KZ
292 fdisk_ask_number_set_unit(ask,
293 cxt->sector_size *
6a632136 294 fdisk_get_units_per_sector(cxt));
77d6a70a 295 } else {
757cefbb 296 fdisk_ask_set_query(ask, _("Last sector, +/-sectors or +/-size{K,M,G,T,P}"));
77d6a70a
KZ
297 fdisk_ask_number_set_unit(ask,cxt->sector_size);
298 }
682802db 299
77d6a70a
KZ
300 fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin));
301 fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end));
302 fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end));
303 fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin));
757cefbb 304 fdisk_ask_number_set_wrap_negative(ask, 1); /* wrap negative around high */
0f639e54 305
77d6a70a
KZ
306 rc = fdisk_do_ask(cxt, ask);
307 end = fdisk_ask_number_get_result(ask);
a3d83488 308 fdisk_unref_ask(ask);
77d6a70a
KZ
309 if (rc)
310 return rc;
6a632136 311 if (fdisk_use_cylinders(cxt))
77d6a70a
KZ
312 end = end * d->d_secpercyl - 1;
313 }
0f639e54 314
0efc6c57
KZ
315 d->d_partitions[i].p_size = end - begin + 1;
316 d->d_partitions[i].p_offset = begin;
317 d->d_partitions[i].p_fstype = BSD_FS_UNUSED;
8254c3a5 318
0b08fb07
KZ
319 if (i >= d->d_npartitions)
320 d->d_npartitions = i + 1;
0efc6c57 321 cxt->label->nparts_cur = d->d_npartitions;
acf263d5 322
77d6a70a 323 if (pa && pa->type)
7f63194a 324 set_parttype(cxt, i, pa->type);
77d6a70a 325
0b08fb07 326 fdisk_label_set_changed(cxt->label, 1);
c3bc7483
KZ
327 if (partno)
328 *partno = i;
8254c3a5 329 return 0;
0f639e54
DB
330}
331
7f63194a
KZ
332static int bsd_set_partition(struct fdisk_context *cxt, size_t n,
333 struct fdisk_partition *pa)
334{
335 struct bsd_partition *p;
336 struct fdisk_bsd_label *l = self_label(cxt);
337 struct bsd_disklabel *d = self_disklabel(cxt);
338
339 if (n >= d->d_npartitions)
340 return -EINVAL;
341
342 p = &d->d_partitions[n];
343
344 /* we have to stay within parental DOS partition */
ecf40cda
KZ
345 if (l->dos_part && (fdisk_partition_has_start(pa) ||
346 fdisk_partition_has_size(pa))) {
347
0073a4cf
KZ
348 fdisk_sector_t dosbegin = dos_partition_get_start(l->dos_part);
349 fdisk_sector_t dosend = dosbegin + dos_partition_get_size(l->dos_part) - 1;
350 fdisk_sector_t begin = fdisk_partition_has_start(pa) ? pa->start : p->p_offset;
351 fdisk_sector_t end = begin + (fdisk_partition_has_size(pa) ? pa->size : p->p_size) - 1;
7f63194a
KZ
352
353 if (begin < dosbegin || begin > dosend)
354 return -ERANGE;
355 if (end < dosbegin || end > dosend)
356 return -ERANGE;
357 }
358
359 if (pa->type) {
360 int rc = set_parttype(cxt, n, pa->type);
361 if (rc)
362 return rc;
363 }
364
ecf40cda 365 if (fdisk_partition_has_start(pa))
7f63194a 366 d->d_partitions[n].p_offset = pa->start;
ecf40cda 367 if (fdisk_partition_has_size(pa))
7f63194a
KZ
368 d->d_partitions[n].p_size = pa->size;
369
370 fdisk_label_set_changed(cxt->label, 1);
371 return 0;
372}
373
374
75d059ef 375/* Returns 0 on success, < 0 on error. */
2872ffa0 376static int bsd_create_disklabel(struct fdisk_context *cxt)
639f1d56 377{
75d059ef 378 int rc, yes = 0;
0efc6c57 379 struct bsd_disklabel *d = self_disklabel(cxt);
9ffeb235 380
818d7924 381 fdisk_info(cxt, _("The device %s does not contain BSD disklabel."), cxt->dev_path);
75d059ef
KZ
382 rc = fdisk_ask_yesno(cxt,
383 _("Do you want to create a BSD disklabel?"),
384 &yes);
243631e7 385 if (rc)
818d7924 386 return rc;
243631e7
KZ
387 if (!yes)
388 return 1;
818d7924 389 if (cxt->parent) {
0efc6c57 390 rc = bsd_assign_dos_partition(cxt);
818d7924
KZ
391 if (rc == 1)
392 /* not found DOS partition usable for BSD label */
393 rc = -EINVAL;
394 }
395 if (rc)
396 return rc;
397
2872ffa0 398 rc = bsd_initlabel(cxt);
818d7924 399 if (!rc) {
0efc6c57 400 cxt->label->nparts_cur = d->d_npartitions;
818d7924 401 cxt->label->nparts_max = BSD_MAXPARTITIONS;
639f1d56 402 }
75d059ef
KZ
403
404 return rc;
639f1d56
DB
405}
406
2872ffa0 407static int bsd_delete_part(
9ffeb235
KZ
408 struct fdisk_context *cxt,
409 size_t partnum)
726f69e2 410{
0efc6c57
KZ
411 struct bsd_disklabel *d = self_disklabel(cxt);
412
413 d->d_partitions[partnum].p_size = 0;
414 d->d_partitions[partnum].p_offset = 0;
415 d->d_partitions[partnum].p_fstype = BSD_FS_UNUSED;
9ffeb235 416
0efc6c57
KZ
417 if (d->d_npartitions == partnum + 1)
418 while (!d->d_partitions[d->d_npartitions - 1].p_size)
419 d->d_npartitions--;
1f5eb51b 420
0efc6c57 421 cxt->label->nparts_cur = d->d_npartitions;
9ffeb235 422 fdisk_label_set_changed(cxt->label, 1);
1f5eb51b 423 return 0;
726f69e2
KZ
424}
425
5989556a 426static int bsd_get_disklabel_item(struct fdisk_context *cxt, struct fdisk_labelitem *item)
9ffeb235 427{
5989556a
KZ
428 struct bsd_disklabel *d;
429 int rc = 0;
50ea6795 430
e563f055
KZ
431 assert(cxt);
432 assert(cxt->label);
aa36c2cf 433 assert(fdisk_is_label(cxt, BSD));
e563f055 434
5989556a 435 d = self_disklabel(cxt);
e563f055 436
5989556a
KZ
437 switch (item->id) {
438 case BSD_LABELITEM_TYPE:
439 item->name = _("Type");
440 item->type = 's';
441 if ((unsigned) d->d_type < BSD_DKMAXTYPES) {
442 item->data.str = strdup(bsd_dktypenames[d->d_type]);
443 if (!item->data.str)
444 rc = -ENOMEM;
445 } else if (asprintf(&item->data.str, "%d", d->d_type) < 0)
446 rc = -ENOMEM;
447 break;
448 case BSD_LABELITEM_DISK:
449 item->name = _("Disk");
450 item->type = 's';
451 item->data.str = strndup(d->d_typename, sizeof(d->d_typename));
452 if (!item->data.str)
453 rc = -ENOMEM;
454 break;
455 case BSD_LABELITEM_PACKNAME:
456 item->name = _("Packname");
457 item->type = 's';
458 item->data.str = strndup(d->d_packname, sizeof(d->d_packname));
459 if (!item->data.str)
460 rc = -ENOMEM;
461 break;
462 case BSD_LABELITEM_FLAGS:
463 item->name = _("Flags");
464 item->type = 's';
465 item->data.str = strdup(
e563f055
KZ
466 d->d_flags & BSD_D_REMOVABLE ? _(" removable") :
467 d->d_flags & BSD_D_ECC ? _(" ecc") :
468 d->d_flags & BSD_D_BADSECT ? _(" badsect") : "");
5989556a
KZ
469 if (!item->data.str)
470 rc = -ENOMEM;
471 break;
e563f055 472
5989556a
KZ
473 /* On various machines the fields of *lp are short/int/long */
474 /* In order to avoid problems, we cast them all uint64. */
475 case BSD_LABELITEM_SECSIZE:
476 item->name = _("Bytes/Sector");
477 item->type = 'j';
478 item->data.num64 = (uint64_t) d->d_secsize;
479 break;
480 case BSD_LABELITEM_NTRACKS:
481 item->name = _("Tracks/Cylinder");
482 item->type = 'j';
483 item->data.num64 = (uint64_t) d->d_ntracks;
484 break;
485 case BSD_LABELITEM_SECPERCYL:
486 item->name = _("Sectors/Cylinder");
487 item->data.num64 = (uint64_t) d->d_secpercyl;
488 item->type = 'j';
489 break;
490 case BSD_LABELITEM_CYLINDERS:
491 item->name = _("Cylinders");
492 item->data.num64 = (uint64_t) d->d_ncylinders;
493 item->type = 'j';
494 break;
495 case BSD_LABELITEM_RPM:
496 item->name = _("Rpm");
497 item->data.num64 = (uint64_t) d->d_rpm;
498 item->type = 'j';
499 break;
500 case BSD_LABELITEM_INTERLEAVE:
501 item->name = _("Interleave");
502 item->data.num64 = (uint64_t) d->d_interleave;
503 item->type = 'j';
504 break;
505 case BSD_LABELITEM_TRACKSKEW:
506 item->name = _("Trackskew");
507 item->data.num64 = (uint64_t) d->d_trackskew;
508 item->type = 'j';
509 break;
510 case BSD_LABELITEM_CYLINDERSKEW:
511 item->name = _("Cylinderskew");
512 item->data.num64 = (uint64_t) d->d_cylskew;
513 item->type = 'j';
514 break;
515 case BSD_LABELITEM_HEADSWITCH:
516 item->name = _("Headswitch");
517 item->data.num64 = (uint64_t) d->d_headswitch;
518 item->type = 'j';
519 break;
520 case BSD_LABELITEM_TRKSEEK:
521 item->name = _("Track-to-track seek");
522 item->data.num64 = (uint64_t) d->d_trkseek;
523 item->type = 'j';
524 break;
525 default:
526 if (item->id < __FDISK_NLABELITEMS)
9e930041 527 rc = 1; /* unsupported generic item */
5989556a
KZ
528 else
529 rc = 2; /* out of range */
530 break;
e563f055
KZ
531 }
532
5989556a 533 return rc;
d48419f3 534}
e563f055 535
d48419f3
KZ
536static int bsd_get_partition(struct fdisk_context *cxt, size_t n,
537 struct fdisk_partition *pa)
538{
539 struct bsd_partition *p;
540 struct bsd_disklabel *d = self_disklabel(cxt);
e563f055 541
d48419f3
KZ
542 assert(cxt);
543 assert(cxt->label);
aa36c2cf 544 assert(fdisk_is_label(cxt, BSD));
e563f055 545
d48419f3
KZ
546 if (n >= d->d_npartitions)
547 return -EINVAL;
e563f055 548
d48419f3 549 p = &d->d_partitions[n];
e563f055 550
d48419f3
KZ
551 pa->used = p->p_size ? 1 : 0;
552 if (!pa->used)
553 return 0;
e563f055 554
6a632136 555 if (fdisk_use_cylinders(cxt) && d->d_secpercyl) {
d48419f3 556 pa->start_post = p->p_offset % d->d_secpercyl ? '*' : ' ';
d48419f3 557 pa->end_post = (p->p_offset + p->p_size) % d->d_secpercyl ? '*' : ' ';
e563f055
KZ
558 }
559
41050b7e 560 pa->start = p->p_offset;
77d6a70a 561 pa->size = p->p_size;
a699b27d 562 pa->type = bsd_partition_parttype(cxt, p);
e563f055 563
d48419f3
KZ
564 if (p->p_fstype == BSD_FS_UNUSED || p->p_fstype == BSD_FS_BSDFFS) {
565 pa->fsize = p->p_fsize;
566 pa->bsize = p->p_fsize * p->p_frag;
567 }
568 if (p->p_fstype == BSD_FS_BSDFFS)
569 pa->cpg = p->p_cpg;
570
571 return 0;
726f69e2
KZ
572}
573
6a0b468f
KZ
574static uint32_t ask_uint32(struct fdisk_context *cxt,
575 uint32_t dflt, char *mesg)
576{
577 uintmax_t res;
578
579 if (fdisk_ask_number(cxt, min(dflt, (uint32_t) 1), dflt,
580 UINT32_MAX, mesg, &res) == 0)
581 return res;
582 return dflt;
583}
584
585static uint16_t ask_uint16(struct fdisk_context *cxt,
586 uint16_t dflt, char *mesg)
726f69e2 587{
6a0b468f
KZ
588 uintmax_t res;
589
590 if (fdisk_ask_number(cxt, min(dflt, (uint16_t) 1),
591 dflt, UINT16_MAX, mesg, &res) == 0)
592 return res;
593 return dflt;
50ea6795 594}
726f69e2 595
a4e6a45e
KZ
596/**
597 * fdisk_bsd_edit_disklabel:
598 * @cxt: context
599 *
600 * Edits fields in BSD disk label.
601 *
602 * Returns: 0 on success, <0 on error
603 */
b529ea2a 604int fdisk_bsd_edit_disklabel(struct fdisk_context *cxt)
726f69e2 605{
0efc6c57 606 struct bsd_disklabel *d = self_disklabel(cxt);
6a0b468f 607 uintmax_t res;
726f69e2 608
22853e4a 609#if defined (__alpha__) || defined (__ia64__)
6a0b468f
KZ
610 if (fdisk_ask_number(cxt, DEFAULT_SECTOR_SIZE, d->d_secsize,
611 UINT32_MAX, _("bytes/sector"), &res) == 0)
612 d->d_secsize = res;
613
614 d->d_nsectors = ask_uint32(cxt, d->d_nsectors, _("sectors/track"));
615 d->d_ntracks = ask_uint32(cxt, d->d_ntracks, _("tracks/cylinder"));
616 d->d_ncylinders = ask_uint32(cxt, d->d_ncylinders ,_("cylinders"));
726f69e2 617#endif
6a0b468f
KZ
618 if (fdisk_ask_number(cxt, 1, d->d_nsectors * d->d_ntracks,
619 d->d_nsectors * d->d_ntracks,
620 _("sectors/cylinder"), &res) == 0)
621 d->d_secpercyl = res;
726f69e2 622
6a0b468f
KZ
623 d->d_rpm = ask_uint16(cxt, d->d_rpm, _("rpm"));
624 d->d_interleave = ask_uint16(cxt, d->d_interleave, _("interleave"));
625 d->d_trackskew = ask_uint16(cxt, d->d_trackskew, _("trackskew"));
626 d->d_cylskew = ask_uint16(cxt, d->d_cylskew, _("cylinderskew"));
627
628 d->d_headswitch = ask_uint32(cxt, d->d_headswitch, _("headswitch"));
629 d->d_trkseek = ask_uint32(cxt, d->d_trkseek, _("track-to-track seek"));
630
631 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
b529ea2a 632 return 0;
726f69e2
KZ
633}
634
2872ffa0 635static int bsd_get_bootstrap(struct fdisk_context *cxt,
9e346a02 636 char *path, void *ptr, int size)
726f69e2 637{
9e346a02 638 int fd;
726f69e2 639
9e346a02 640 if ((fd = open(path, O_RDONLY)) < 0) {
77274f88 641 fdisk_warn(cxt, _("cannot open %s"), path);
9e346a02
KZ
642 return -errno;
643 }
644
645 if (read_all(fd, ptr, size) != size) {
77274f88 646 fdisk_warn(cxt, _("cannot read %s"), path);
9e346a02
KZ
647 close(fd);
648 return -errno;
649 }
650
0477369a 651 fdisk_info(cxt, _("The bootstrap file %s successfully loaded."), path);
9e346a02
KZ
652 close (fd);
653 return 0;
726f69e2
KZ
654}
655
a4e6a45e
KZ
656/**
657 * fdisk_bsd_write_bootstrap:
658 * @cxt: context
659 *
660 * Install bootstrap file to the BSD device
661 */
b529ea2a 662int fdisk_bsd_write_bootstrap(struct fdisk_context *cxt)
726f69e2 663{
0efc6c57
KZ
664 struct bsd_disklabel dl, *d = self_disklabel(cxt);
665 struct fdisk_bsd_label *l = self_label(cxt);
666 char *name = d->d_type == BSD_DTYPE_SCSI ? "sd" : "wd";
9e346a02 667 char buf[BUFSIZ];
0efc6c57 668 char *res, *dp, *p;
9e346a02 669 int rc;
0073a4cf 670 fdisk_sector_t sector;
9e346a02
KZ
671
672 snprintf(buf, sizeof(buf),
673 _("Bootstrap: %1$sboot -> boot%1$s (default %1$s)"),
674 name);
675 rc = fdisk_ask_string(cxt, buf, &res);
676 if (rc)
677 goto done;
678 if (res && *res)
679 name = res;
680
681 snprintf(buf, sizeof(buf), "%s/%sboot", BSD_LINUX_BOOTDIR, name);
2872ffa0 682 rc = bsd_get_bootstrap(cxt, buf, l->bsdbuffer, (int) d->d_secsize);
9e346a02
KZ
683 if (rc)
684 goto done;
685
0efc6c57 686 /* We need a backup of the disklabel (might have changed). */
87ed95ff 687 dp = &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE];
0efc6c57 688 memmove(&dl, dp, sizeof(struct bsd_disklabel));
9e346a02
KZ
689
690 /* The disklabel will be overwritten by 0's from bootxx anyway */
0efc6c57 691 memset(dp, 0, sizeof(struct bsd_disklabel));
9e346a02
KZ
692
693 snprintf(buf, sizeof(buf), "%s/boot%s", BSD_LINUX_BOOTDIR, name);
2872ffa0 694 rc = bsd_get_bootstrap(cxt, buf,
87ed95ff 695 &l->bsdbuffer[d->d_secsize],
0efc6c57 696 (int) d->d_bbsize - d->d_secsize);
9e346a02
KZ
697 if (rc)
698 goto done;
699
700 /* check end of the bootstrap */
0efc6c57 701 for (p = dp; p < dp + sizeof(struct bsd_disklabel); p++) {
9e346a02
KZ
702 if (!*p)
703 continue;
fd56121a 704 fdisk_warnx(cxt, _("Bootstrap overlaps with disklabel!"));
9e346a02
KZ
705 return -EINVAL;
706 }
726f69e2 707
9e346a02 708 /* move disklabel back */
0efc6c57 709 memmove(dp, &dl, sizeof(struct bsd_disklabel));
726f69e2 710
9e346a02 711 sector = 0;
0efc6c57
KZ
712 if (l->dos_part)
713 sector = dos_partition_get_start(l->dos_part);
714#if defined (__alpha__)
87ed95ff 715 alpha_bootblock_checksum(l->bsdbuffer);
726f69e2 716#endif
bb58112e 717 if (lseek(cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1) {
77274f88 718 fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
9e346a02
KZ
719 rc = -errno;
720 goto done;
721 }
87ed95ff 722 if (write_all(cxt->dev_fd, l->bsdbuffer, BSD_BBSIZE)) {
77274f88 723 fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
9e346a02
KZ
724 rc = -errno;
725 goto done;
726 }
726f69e2 727
0477369a 728 fdisk_info(cxt, _("Bootstrap installed on %s."), cxt->dev_path);
296b856d 729 sync_disks(cxt);
726f69e2 730
9e346a02
KZ
731 rc = 0;
732done:
733 free(res);
734 return rc;
726f69e2
KZ
735}
736
2872ffa0 737static unsigned short bsd_dkcksum (struct bsd_disklabel *lp)
0bf367ed 738{
04d0701e 739 unsigned char *ptr, *end;
95961ee2 740 unsigned short sum = 0;
50ea6795 741
04d0701e
KZ
742 ptr = (unsigned char *) lp;
743 end = (unsigned char *) &lp->d_partitions[lp->d_npartitions];
744
745 while (ptr < end) {
746 unsigned short val;
747
748 memcpy(&val, ptr, sizeof(unsigned short));
749 sum ^= val;
750
751 ptr += sizeof(unsigned short);
752 }
63cccae4 753 return sum;
726f69e2
KZ
754}
755
2872ffa0 756static int bsd_initlabel (struct fdisk_context *cxt)
75d059ef 757{
0efc6c57
KZ
758 struct fdisk_bsd_label *l = self_label(cxt);
759 struct bsd_disklabel *d = self_disklabel(cxt);
66ea9847 760 struct bsd_partition *pp;
726f69e2 761
66ea9847 762 memset (d, 0, sizeof (struct bsd_disklabel));
726f69e2 763
63cccae4 764 d -> d_magic = BSD_DISKMAGIC;
726f69e2 765
823f0fd1 766 if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0)
63cccae4
KZ
767 d -> d_type = BSD_DTYPE_SCSI;
768 else
769 d -> d_type = BSD_DTYPE_ST506;
726f69e2 770
22853e4a 771#if !defined (__alpha__)
63cccae4 772 d -> d_flags = BSD_D_DOSPART;
726f69e2 773#else
63cccae4 774 d -> d_flags = 0;
726f69e2 775#endif
bb58112e 776 d -> d_secsize = DEFAULT_SECTOR_SIZE; /* bytes/sector */
24cd580b
DB
777 d -> d_nsectors = cxt->geom.sectors; /* sectors/track */
778 d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */
779 d -> d_ncylinders = cxt->geom.cylinders;
780 d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */
63cccae4
KZ
781 if (d -> d_secpercyl == 0)
782 d -> d_secpercyl = 1; /* avoid segfaults */
783 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
784
785 d -> d_rpm = 3600;
786 d -> d_interleave = 1;
787 d -> d_trackskew = 0;
788 d -> d_cylskew = 0;
789 d -> d_headswitch = 0;
790 d -> d_trkseek = 0;
791
792 d -> d_magic2 = BSD_DISKMAGIC;
793 d -> d_bbsize = BSD_BBSIZE;
794 d -> d_sbsize = BSD_SBSIZE;
726f69e2 795
0efc6c57
KZ
796 if (l->dos_part) {
797 d->d_npartitions = 4;
d48419f3
KZ
798
799 pp = &d->d_partitions[2]; /* Partition C should be the NetBSD partition */
0efc6c57
KZ
800 pp->p_offset = dos_partition_get_start(l->dos_part);
801 pp->p_size = dos_partition_get_size(l->dos_part);
802 pp->p_fstype = BSD_FS_UNUSED;
d48419f3
KZ
803
804 pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */
0efc6c57
KZ
805 pp->p_offset = 0;
806 pp->p_size = d->d_secperunit;
807 pp->p_fstype = BSD_FS_UNUSED;
808 } else {
809 d->d_npartitions = 3;
d48419f3
KZ
810
811 pp = &d->d_partitions[2]; /* Partition C should be the whole disk */
0efc6c57
KZ
812 pp->p_offset = 0;
813 pp->p_size = d->d_secperunit;
814 pp->p_fstype = BSD_FS_UNUSED;
815 }
726f69e2 816
75d059ef 817 return 0;
726f69e2
KZ
818}
819
63cccae4 820/*
2872ffa0 821 * Read a bsd_disklabel from sector 0 or from the starting sector of p.
818d7924 822 * If it has the right magic, return 0.
63cccae4 823 */
2872ffa0 824static int bsd_readlabel(struct fdisk_context *cxt)
726f69e2 825{
0efc6c57
KZ
826 struct fdisk_bsd_label *l;
827 struct bsd_disklabel *d;
0dd3dfb8
KZ
828 int t;
829 off_t offset = 0;
726f69e2 830
0efc6c57
KZ
831 l = self_label(cxt);
832 d = self_disklabel(cxt);
acf263d5 833
0efc6c57 834 if (l->dos_part)
0dd3dfb8
KZ
835 /* BSD is nested within DOS partition, get the begin of the
836 * partition. Note that DOS uses native sector size. */
0efc6c57 837 offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;
726f69e2 838
0dd3dfb8 839 if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1)
818d7924 840 return -1;
87ed95ff 841 if (read_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer)) < 0)
0dd3dfb8 842 return errno ? -errno : -1;
726f69e2 843
0dd3dfb8
KZ
844 /* The offset to begin of the disk label. Note that BSD uses
845 * 512-byte (default) sectors. */
87ed95ff 846 memmove(d, &l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
0efc6c57 847 + BSD_LABELOFFSET], sizeof(*d));
726f69e2 848
0dd3dfb8 849 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC) {
88141067 850 DBG(LABEL, ul_debug("not found magic"));
818d7924 851 return -1;
e36e1631 852 }
726f69e2 853
0dd3dfb8
KZ
854 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
855 d->d_partitions[t].p_size = 0;
856 d->d_partitions[t].p_offset = 0;
857 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
63cccae4
KZ
858 }
859
0dd3dfb8
KZ
860 if (d->d_npartitions > BSD_MAXPARTITIONS)
861 fdisk_warnx(cxt, ("Too many partitions (%d, maximum is %d)."),
862 d->d_npartitions, BSD_MAXPARTITIONS);
acf263d5 863
77d6a70a
KZ
864 /* let's follow in-PT geometry */
865 cxt->geom.sectors = d->d_nsectors;
866 cxt->geom.heads = d->d_ntracks;
867 cxt->geom.cylinders = d->d_ncylinders;
868
502dd53c
KZ
869 if (fdisk_has_user_device_geometry(cxt))
870 fdisk_apply_user_device_properties(cxt);
871
acf263d5
KZ
872 cxt->label->nparts_cur = d->d_npartitions;
873 cxt->label->nparts_max = BSD_MAXPARTITIONS;
88141067 874 DBG(LABEL, ul_debug("read BSD label"));
818d7924 875 return 0;
726f69e2
KZ
876}
877
d5b2b8db 878static int bsd_write_disklabel(struct fdisk_context *cxt)
726f69e2 879{
0dd3dfb8 880 off_t offset = 0;
d5b2b8db
KZ
881 struct fdisk_bsd_label *l = self_label(cxt);
882 struct bsd_disklabel *d = self_disklabel(cxt);
0efc6c57 883
726f69e2 884
0efc6c57
KZ
885 if (l->dos_part)
886 offset = dos_partition_get_start(l->dos_part) * cxt->sector_size;
726f69e2 887
0dd3dfb8 888 d->d_checksum = 0;
2872ffa0 889 d->d_checksum = bsd_dkcksum(d);
726f69e2 890
88f91eb4 891 /* Update label within boot block. */
87ed95ff 892 memmove(&l->bsdbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE
0efc6c57 893 + BSD_LABELOFFSET], d, sizeof(*d));
726f69e2
KZ
894
895#if defined (__alpha__) && BSD_LABELSECTOR == 0
88f91eb4 896 /* Write the checksum to the end of the first sector. */
87ed95ff 897 alpha_bootblock_checksum(l->bsdbuffer);
726f69e2 898#endif
0dd3dfb8 899 if (lseek(cxt->dev_fd, offset, SEEK_SET) == -1) {
77274f88 900 fdisk_warn(cxt, _("seek on %s failed"), cxt->dev_path);
0dd3dfb8
KZ
901 return -errno;
902 }
87ed95ff 903 if (write_all(cxt->dev_fd, l->bsdbuffer, sizeof(l->bsdbuffer))) {
77274f88 904 fdisk_warn(cxt, _("cannot write %s"), cxt->dev_path);
0dd3dfb8
KZ
905 return -errno;
906 }
296b856d 907 sync_disks(cxt);
ac1a559a 908
5cea5be0 909 if (cxt->parent && fdisk_label_is_changed(cxt->parent->label))
e906ab3c 910 fdisk_info(cxt, _("Disklabel written to %s. (Don't forget to write the %s disklabel too.)"),
5cea5be0
KZ
911 cxt->dev_path, cxt->parent->dev_path);
912 else
913 fdisk_info(cxt, _("Disklabel written to %s."), cxt->dev_path);
0dd3dfb8 914 return 0;
726f69e2
KZ
915}
916
296b856d 917static void sync_disks(struct fdisk_context *cxt)
726f69e2 918{
296b856d
KZ
919 fdisk_info(cxt, _("Syncing disks."));
920 sync();
726f69e2
KZ
921}
922
2872ffa0 923static int bsd_translate_fstype (int linux_type)
726f69e2 924{
bcef4db4
KZ
925 switch (linux_type) {
926 case 0x01: /* DOS 12-bit FAT */
927 case 0x04: /* DOS 16-bit <32M */
928 case 0x06: /* DOS 16-bit >=32M */
929 case 0xe1: /* DOS access */
930 case 0xe3: /* DOS R/O */
0b166f24 931#if !defined (__alpha__)
bcef4db4
KZ
932 case 0xf2: /* DOS secondary */
933 return BSD_FS_MSDOS;
0b166f24 934#endif
bcef4db4
KZ
935 case 0x07: /* OS/2 HPFS */
936 return BSD_FS_HPFS;
937 default:
19c2cc4e 938 break;
bcef4db4 939 }
19c2cc4e
KZ
940
941 return BSD_FS_OTHER;
726f69e2
KZ
942}
943
a4e6a45e
KZ
944/**
945 * fdisk_bsd_link_partition:
946 * @cxt: context
947 *
948 * Links partition from parent (DOS) to nested BSD partition table.
949 *
950 * Returns: 0 on success, <0 on error
e09435aa 951 */
b529ea2a 952int fdisk_bsd_link_partition(struct fdisk_context *cxt)
726f69e2 953{
0b08fb07
KZ
954 size_t k, i;
955 int rc;
f540fe15 956 struct dos_partition *p;
0efc6c57 957 struct bsd_disklabel *d = self_disklabel(cxt);
726f69e2 958
aa36c2cf 959 if (!cxt->parent || !fdisk_is_label(cxt->parent, DOS)) {
09af3db4 960 fdisk_warnx(cxt, _("BSD label is not nested within a DOS partition."));
b529ea2a
KZ
961 return -EINVAL;
962 }
b4fb2a61 963
0b08fb07 964 /* ask for DOS partition */
b529ea2a
KZ
965 rc = fdisk_ask_partnum(cxt->parent, &k, FALSE);
966 if (rc)
967 return rc;
0b08fb07
KZ
968 /* ask for BSD partition */
969 rc = fdisk_ask_partnum(cxt, &i, TRUE);
b529ea2a
KZ
970 if (rc)
971 return rc;
726f69e2 972
0b08fb07
KZ
973 if (i >= BSD_MAXPARTITIONS)
974 return -EINVAL;
975
af0df606 976 p = fdisk_dos_get_partition(cxt->parent, k);
22853e4a 977
0efc6c57
KZ
978 d->d_partitions[i].p_size = dos_partition_get_size(p);
979 d->d_partitions[i].p_offset = dos_partition_get_start(p);
2872ffa0 980 d->d_partitions[i].p_fstype = bsd_translate_fstype(p->sys_ind);
b529ea2a 981
0b08fb07
KZ
982 if (i >= d->d_npartitions)
983 d->d_npartitions = i + 1;
984
985 cxt->label->nparts_cur = d->d_npartitions;
986 fdisk_label_set_changed(cxt->label, 1);
987
0477369a 988 fdisk_info(cxt, _("BSD partition '%c' linked to DOS partition %zu."),
829f4206 989 'a' + (int) i, k + 1);
b529ea2a 990 return 0;
726f69e2 991}
726f69e2 992
02460b8a 993
8c0a7f91 994static int bsd_partition_is_used(
e36e1631 995 struct fdisk_context *cxt,
8c0a7f91 996 size_t partnum)
e36e1631 997{
0efc6c57 998 struct bsd_disklabel *d = self_disklabel(cxt);
e36e1631 999
8c0a7f91
KZ
1000 if (partnum >= BSD_MAXPARTITIONS)
1001 return 0;
e36e1631 1002
8c0a7f91 1003 return d->d_partitions[partnum].p_size ? 1 : 0;
e36e1631
KZ
1004}
1005
1006
0c5d095e 1007static const struct fdisk_label_operations bsd_operations =
b8855c86 1008{
818d7924 1009 .probe = bsd_probe_label,
5989556a 1010 .get_item = bsd_get_disklabel_item,
2872ffa0
KZ
1011 .write = bsd_write_disklabel,
1012 .create = bsd_create_disklabel,
d48419f3 1013
e11c6684 1014 .del_part = bsd_delete_part,
d48419f3 1015 .get_part = bsd_get_partition,
7f63194a 1016 .set_part = bsd_set_partition,
77d6a70a 1017 .add_part = bsd_add_partition,
d48419f3 1018
8c0a7f91 1019 .part_is_used = bsd_partition_is_used,
b8855c86 1020};
0c5d095e 1021
bd85d11f 1022static const struct fdisk_field bsd_fields[] =
d48419f3 1023{
bd85d11f
KZ
1024 { FDISK_FIELD_DEVICE, N_("Slice"), 1, 0 },
1025 { FDISK_FIELD_START, N_("Start"), 5, FDISK_FIELDFL_NUMBER },
1026 { FDISK_FIELD_END, N_("End"), 5, FDISK_FIELDFL_NUMBER },
1027 { FDISK_FIELD_SECTORS, N_("Sectors"), 5, FDISK_FIELDFL_NUMBER },
1028 { FDISK_FIELD_CYLINDERS,N_("Cylinders"), 5, FDISK_FIELDFL_NUMBER },
1029 { FDISK_FIELD_SIZE, N_("Size"), 5, FDISK_FIELDFL_NUMBER },
1030 { FDISK_FIELD_TYPE, N_("Type"), 8, 0 },
1031 { FDISK_FIELD_FSIZE, N_("Fsize"), 5, FDISK_FIELDFL_NUMBER },
1032 { FDISK_FIELD_BSIZE, N_("Bsize"), 5, FDISK_FIELDFL_NUMBER },
1033 { FDISK_FIELD_CPG, N_("Cpg"), 5, FDISK_FIELDFL_NUMBER }
d48419f3 1034};
0c5d095e
KZ
1035
1036/*
1037 * allocates BSD label driver
1038 */
01aec449 1039struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt __attribute__ ((__unused__)))
0c5d095e
KZ
1040{
1041 struct fdisk_label *lb;
1042 struct fdisk_bsd_label *bsd;
1043
0c5d095e
KZ
1044 bsd = calloc(1, sizeof(*bsd));
1045 if (!bsd)
1046 return NULL;
1047
1048 /* initialize generic part of the driver */
1049 lb = (struct fdisk_label *) bsd;
1050 lb->name = "bsd";
22ddf547 1051 lb->id = FDISK_DISKLABEL_BSD;
0c5d095e 1052 lb->op = &bsd_operations;
2872ffa0 1053 lb->parttypes = bsd_fstypes;
a745611d 1054 lb->nparttypes = ARRAY_SIZE(bsd_fstypes) - 1;
0c5d095e 1055
bd85d11f
KZ
1056 lb->fields = bsd_fields;
1057 lb->nfields = ARRAY_SIZE(bsd_fields);
d48419f3 1058
e36e1631 1059 lb->flags |= FDISK_LABEL_FL_INCHARS_PARTNO;
caad8583 1060 lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
baa7cccc 1061
0c5d095e
KZ
1062 return lb;
1063}