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