]> git.ipfire.org Git - thirdparty/util-linux.git/blob - fdisks/fdiskbsdlabel.c
fdisk: (bsd) cleanup driver initialization
[thirdparty/util-linux.git] / fdisks / fdiskbsdlabel.c
1 /*
2 NetBSD disklabel editor for Linux fdisk
3 Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
4 with code from the NetBSD disklabel command:
5
6 Copyright (c) 1987, 1988 Regents of the University of California.
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17 3. All advertising materials mentioning features or use of this software
18 must display the following acknowledgement:
19 This product includes software developed by the University of
20 California, Berkeley and its contributors.
21 4. Neither the name of the University nor the names of its contributors
22 may be used to endorse or promote products derived from this software
23 without specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 SUCH DAMAGE.
36
37 Changes:
38 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
39
40 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
41 support for OSF/1 disklabels on Alpha.
42 Also fixed unaligned accesses in alpha_bootblock_checksum()
43 */
44
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <fcntl.h>
50 #include <ctype.h>
51 #include <setjmp.h>
52 #include <errno.h>
53 #include "nls.h"
54
55 #include <sys/param.h>
56
57 #include "common.h"
58 #include "fdisk.h"
59 #include "pt-mbr.h"
60
61 #include "fdiskbsdlabel.h"
62 #include "all-io.h"
63
64 static char *xbsd_dktypenames[] = {
65 "unknown",
66 "SMD",
67 "MSCP",
68 "old DEC",
69 "SCSI",
70 "ESDI",
71 "ST506",
72 "HP-IB",
73 "HP-FL",
74 "type 9",
75 "floppy",
76 0
77 };
78 #define BSD_DKMAXTYPES (ARRAY_SIZE(xbsd_dktypenames) - 1)
79
80 static struct fdisk_parttype xbsd_fstypes[] = {
81 {BSD_FS_UNUSED, "unused"},
82 {BSD_FS_SWAP, "swap"},
83 {BSD_FS_V6, "Version 6"},
84 {BSD_FS_V7, "Version 7"},
85 {BSD_FS_SYSV, "System V"},
86 {BSD_FS_V71K, "4.1BSD"},
87 {BSD_FS_V8, "Eighth Edition"},
88 {BSD_FS_BSDFFS, "4.2BSD"},
89 #ifdef __alpha__
90 {BSD_FS_EXT2, "ext2"},
91 #else
92 {BSD_FS_MSDOS, "MS-DOS"},
93 #endif
94 {BSD_FS_BSDLFS, "4.4LFS"},
95 {BSD_FS_OTHER, "unknown"},
96 {BSD_FS_HPFS, "HPFS"},
97 {BSD_FS_ISO9660,"ISO-9660"},
98 {BSD_FS_BOOT, "boot"},
99 {BSD_FS_ADOS, "ADOS"},
100 {BSD_FS_HFS, "HFS"},
101 {BSD_FS_ADVFS, "AdvFS"},
102 { 0, NULL }
103 };
104 #define BSD_FSMAXTYPES (ARRAY_SIZE(xbsd_fstypes)-1)
105
106 /*
107 * in-memory fdisk BSD stuff
108 */
109 struct fdisk_bsd_label {
110 struct fdisk_label head; /* generic part */
111 };
112
113
114 static int xbsd_delete_part (struct fdisk_context *cxt, size_t partnum);
115 static void xbsd_edit_disklabel (struct fdisk_context *cxt);
116 static int xbsd_write_bootstrap (struct fdisk_context *cxt);
117 static void xbsd_change_fstype (struct fdisk_context *cxt);
118 static int xbsd_get_part_index (struct fdisk_context *cxt, int max, int *n);
119 static int xbsd_check_new_partition (struct fdisk_context *cxt, int *i);
120 static unsigned short xbsd_dkcksum (struct bsd_disklabel *lp);
121 static int xbsd_initlabel (struct fdisk_context *cxt,
122 struct dos_partition *p, struct bsd_disklabel *d);
123 static int xbsd_readlabel (struct fdisk_context *cxt,
124 struct dos_partition *p, struct bsd_disklabel *d);
125 static int xbsd_writelabel (struct fdisk_context *cxt, struct dos_partition *p, struct bsd_disklabel *d);
126 static void sync_disks (void);
127
128 #if defined (__alpha__)
129 void alpha_bootblock_checksum (char *boot);
130 #endif
131
132 #if !defined (__alpha__)
133 static int xbsd_translate_fstype (int linux_type);
134 static void xbsd_link_part (struct fdisk_context *cxt);
135 static struct dos_partition *xbsd_part;
136 static int xbsd_part_index;
137 #endif
138
139 #if defined (__alpha__)
140 /* We access this through a u_int64_t * when checksumming */
141 static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8)));
142 #else
143 static char disklabelbuffer[BSD_BBSIZE];
144 #endif
145
146 static struct bsd_disklabel xbsd_dlabel;
147
148 #define bsd_cround(c, n) \
149 (fdisk_context_use_cylinders(c) ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
150
151 #define HIDDEN_MASK 0x10
152
153 static int is_bsd_partition_type(int type)
154 {
155 return (type == MBR_FREEBSD_PARTITION ||
156 type == (MBR_FREEBSD_PARTITION ^ HIDDEN_MASK) ||
157 type == MBR_NETBSD_PARTITION ||
158 type == (MBR_NETBSD_PARTITION ^ HIDDEN_MASK) ||
159 type == MBR_OPENBSD_PARTITION ||
160 type == (MBR_OPENBSD_PARTITION ^ HIDDEN_MASK));
161 }
162
163 /*
164 * look for DOS partition usable for nested BSD partition table
165 */
166 static int bsd_assign_dos_partition(struct fdisk_context *cxt)
167 {
168 size_t i;
169
170 assert(cxt);
171 assert(cxt->parent);
172 assert(cxt->label);
173 assert(fdisk_is_disklabel(cxt, OSF));
174
175 for (i = 0; i < 4; i++) {
176 sector_t ss;
177 struct dos_partition *p =
178 fdisk_dos_get_partition(cxt->parent, i);
179
180 if (!p || !is_bsd_partition_type(p->sys_ind))
181 continue;
182
183 xbsd_part = p;
184 xbsd_part_index = i;
185 ss = dos_partition_get_start(p);
186
187 if (!ss) {
188 fprintf (stderr, _("Partition %zd: has invalid starting sector 0.\n"), i + 1);
189 return -1;
190 }
191
192 if (cxt->parent->dev_path) {
193 free(cxt->dev_path);
194 cxt->dev_path = fdisk_partname(
195 cxt->parent->dev_path, i + 1);
196 }
197
198 DBG(LABEL, dbgprint("partition %zu assigned to BSD", i + 1));
199 return 0;
200 }
201
202 printf (_("There is no *BSD partition on %s.\n"), cxt->parent->dev_path);
203 return 1;
204 }
205
206 static int bsd_probe_label(struct fdisk_context *cxt)
207 {
208 int rc = 0;
209
210 assert(cxt);
211 assert(cxt->label);
212 assert(fdisk_is_disklabel(cxt, OSF));
213
214 if (cxt->parent)
215 /* nested BSD partiotn table */
216 rc = bsd_assign_dos_partition(cxt);
217 if (!rc)
218 rc = xbsd_readlabel(cxt, NULL, &xbsd_dlabel);
219 if (!rc)
220 return 1; /* found BSD */
221 return 0; /* not found */
222 }
223
224 static int xbsd_write_disklabel (struct fdisk_context *cxt)
225 {
226 printf (_("Writing disklabel to %s.\n"), cxt->dev_path);
227 #if defined (__alpha__)
228 xbsd_writelabel (cxt, NULL, &xbsd_dlabel);
229 #else
230 xbsd_writelabel (cxt, xbsd_part, &xbsd_dlabel);
231 #endif
232 reread_partition_table(cxt, 0); /* no exit yet */
233
234 return 0;
235 }
236
237 static int xbsd_add_part (struct fdisk_context *cxt,
238 size_t partnum __attribute__((__unused__)),
239 struct fdisk_parttype *t __attribute__((__unused__)))
240 {
241 struct fdisk_ask *ask;
242 unsigned int begin, end;
243 int i, rc;
244
245 assert(cxt);
246 assert(cxt->label);
247 assert(fdisk_is_disklabel(cxt, OSF));
248
249 rc = xbsd_check_new_partition(cxt, &i);
250 if (rc)
251 return rc;
252
253 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
254 begin = dos_partition_get_start(xbsd_part);
255 end = begin + dos_partition_get_size(xbsd_part) - 1;
256 #else
257 begin = 0;
258 end = xbsd_dlabel.d_secperunit - 1;
259 #endif
260 ask = fdisk_new_ask();
261
262 /*
263 * First sector
264 */
265 if (fdisk_context_use_cylinders(cxt))
266 fdisk_ask_set_query(ask, _("First cylinder"));
267 else
268 fdisk_ask_set_query(ask, _("First sector"));
269
270 fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER);
271 fdisk_ask_number_set_low(ask, bsd_cround(cxt, begin));
272 fdisk_ask_number_set_default(ask, bsd_cround(cxt, begin));
273 fdisk_ask_number_set_high(ask, bsd_cround(cxt, end));
274
275 rc = fdisk_do_ask(cxt, ask);
276 if (rc) {
277 fdisk_free_ask(ask);
278 return rc;
279 }
280 begin = fdisk_ask_number_get_result(ask);
281
282 if (fdisk_context_use_cylinders(cxt))
283 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
284
285 fdisk_reset_ask(ask);
286
287 /*
288 * Last sector
289 */
290 fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET);
291
292 if (fdisk_context_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_context_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, bsd_cround(cxt, begin));
303 fdisk_ask_number_set_default(ask, bsd_cround(cxt, end));
304 fdisk_ask_number_set_high(ask, bsd_cround(cxt, end));
305 fdisk_ask_number_set_base(ask, bsd_cround(cxt, begin));
306
307 rc = fdisk_do_ask(cxt, ask);
308 end = fdisk_ask_number_get_result(ask);
309 fdisk_free_ask(ask);
310 if (rc)
311 return rc;
312
313 if (fdisk_context_use_cylinders(cxt))
314 end = end * xbsd_dlabel.d_secpercyl - 1;
315
316 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
317 xbsd_dlabel.d_partitions[i].p_offset = begin;
318 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
319
320 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
321 fdisk_label_set_changed(cxt->label, 1);
322
323 return 0;
324 }
325
326 /* Returns 0 on success, < 0 on error. */
327 static int xbsd_create_disklabel(struct fdisk_context *cxt)
328 {
329 int rc, yes = 0;
330
331 assert(cxt);
332 assert(cxt->label);
333 assert(fdisk_is_disklabel(cxt, OSF));
334
335 fdisk_info(cxt, _("The device %s does not contain BSD disklabel."), cxt->dev_path);
336 rc = fdisk_ask_yesno(cxt,
337 _("Do you want to create a BSD disklabel?"),
338 &yes);
339
340 if (rc || !yes)
341 return rc;
342 if (cxt->parent) {
343 rc = bsd_assign_dos_partition(cxt);
344 if (rc == 1)
345 /* not found DOS partition usable for BSD label */
346 rc = -EINVAL;
347 }
348 if (rc)
349 return rc;
350
351 #if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
352 defined (__s390__) || defined (__s390x__)
353 rc = xbsd_initlabel(cxt, NULL, &xbsd_dlabel);
354 #else
355 rc = xbsd_initlabel(cxt, xbsd_part, &xbsd_dlabel);
356 #endif
357 if (!rc) {
358 xbsd_print_disklabel (cxt, 1);
359 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
360 cxt->label->nparts_max = BSD_MAXPARTITIONS;
361 }
362
363 return rc;
364 }
365
366
367 void
368 bsd_command_prompt (struct fdisk_context *cxt)
369 {
370
371 while (1) {
372 char buf[16];
373 int rc, n;
374
375 /*
376 * BIG-FAT-TODO: don't use bsd_command_prompt(), just initialialize BSD
377 * stuff by label probe() libfdisk function, and use standard fdisk.c
378 * menu code.
379 */
380 putchar ('\n');
381 rc = get_user_reply(cxt, _("BSD disklabel command (m for help): "),
382 buf, sizeof(buf));
383 if (rc)
384 return;
385
386 switch (tolower(buf[0])) {
387 case 'd':
388 rc = xbsd_get_part_index(cxt, xbsd_dlabel.d_npartitions, &n);
389 if (rc)
390 return;
391 xbsd_delete_part(cxt, n);
392 break;
393 case 'e':
394 xbsd_edit_disklabel (cxt);
395 break;
396 case 'i':
397 xbsd_write_bootstrap (cxt);
398 break;
399 case 'l':
400 list_partition_types (cxt);
401 break;
402 case 'n':
403 xbsd_add_part (cxt, 0, 0);
404 break;
405 case 'p':
406 xbsd_print_disklabel (cxt, 0);
407 break;
408 case 'q':
409 close (cxt->dev_fd);
410 exit ( EXIT_SUCCESS );
411 case 'r':
412 return;
413 case 's':
414 xbsd_print_disklabel (cxt, 1);
415 break;
416 case 't':
417 xbsd_change_fstype (cxt);
418 break;
419 case 'u':
420 toggle_units(cxt);
421 break;
422 case 'w':
423 xbsd_write_disklabel (cxt);
424 break;
425 #if !defined (__alpha__)
426 case 'x':
427 xbsd_link_part (cxt);
428 break;
429 #endif
430 default:
431 print_fdisk_menu(cxt);
432 break;
433 }
434 }
435 }
436
437 static int xbsd_delete_part(
438 struct fdisk_context *cxt,
439 size_t partnum)
440 {
441 assert(cxt);
442 assert(cxt->label);
443 assert(fdisk_is_disklabel(cxt, OSF));
444
445 xbsd_dlabel.d_partitions[partnum].p_size = 0;
446 xbsd_dlabel.d_partitions[partnum].p_offset = 0;
447 xbsd_dlabel.d_partitions[partnum].p_fstype = BSD_FS_UNUSED;
448 if (xbsd_dlabel.d_npartitions == partnum + 1)
449 while (!xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size)
450 xbsd_dlabel.d_npartitions--;
451
452 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions;
453 fdisk_label_set_changed(cxt->label, 1);
454 return 0;
455 }
456
457 void
458 xbsd_print_disklabel (struct fdisk_context *cxt, int show_all)
459 {
460 struct bsd_disklabel *lp = &xbsd_dlabel;
461 struct bsd_partition *pp;
462 FILE *f = stdout;
463 int i, j;
464
465 if (show_all) {
466 fprintf(f, "# %s:\n", cxt->dev_path);
467 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
468 fprintf(f, _("type: %s\n"), xbsd_dktypenames[lp->d_type]);
469 else
470 fprintf(f, _("type: %d\n"), lp->d_type);
471 fprintf(f, _("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
472 fprintf(f, _("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
473 fprintf(f, _("flags:"));
474 if (lp->d_flags & BSD_D_REMOVABLE)
475 fprintf(f, _(" removable"));
476 if (lp->d_flags & BSD_D_ECC)
477 fprintf(f, _(" ecc"));
478 if (lp->d_flags & BSD_D_BADSECT)
479 fprintf(f, _(" badsect"));
480 fprintf(f, "\n");
481 /* On various machines the fields of *lp are short/int/long */
482 /* In order to avoid problems, we cast them all to long. */
483 fprintf(f, _("bytes/sector: %ld\n"), (long) lp->d_secsize);
484 fprintf(f, _("sectors/track: %ld\n"), (long) lp->d_nsectors);
485 fprintf(f, _("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
486 fprintf(f, _("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
487 fprintf(f, _("cylinders: %ld\n"), (long) lp->d_ncylinders);
488 fprintf(f, _("rpm: %d\n"), lp->d_rpm);
489 fprintf(f, _("interleave: %d\n"), lp->d_interleave);
490 fprintf(f, _("trackskew: %d\n"), lp->d_trackskew);
491 fprintf(f, _("cylinderskew: %d\n"), lp->d_cylskew);
492 fprintf(f, _("headswitch: %ld\t\t# milliseconds\n"),
493 (long) lp->d_headswitch);
494 fprintf(f, _("track-to-track seek: %ld\t# milliseconds\n"),
495 (long) lp->d_trkseek);
496 fprintf(f, _("drivedata: "));
497 for (i = ARRAY_SIZE(lp->d_drivedata)- 1; i >= 0; i--)
498 if (lp->d_drivedata[i])
499 break;
500 if (i < 0)
501 i = 0;
502 for (j = 0; j <= i; j++)
503 fprintf(f, "%ld ", (long) lp->d_drivedata[j]);
504 }
505 fprintf (f, _("\n%d partitions:\n"), lp->d_npartitions);
506 fprintf (f, _("# start end size fstype [fsize bsize cpg]\n"));
507 pp = lp->d_partitions;
508 for (i = 0; i < lp->d_npartitions; i++, pp++) {
509 if (pp->p_size) {
510 if (fdisk_context_use_cylinders(cxt) && lp->d_secpercyl) {
511 fprintf(f, " %c: %8ld%c %8ld%c %8ld%c ",
512 'a' + i,
513 (long) pp->p_offset / lp->d_secpercyl + 1,
514 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
515 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1)
516 / lp->d_secpercyl,
517 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
518 (long) pp->p_size / lp->d_secpercyl,
519 (pp->p_size % lp->d_secpercyl) ? '*' : ' ');
520 } else {
521 fprintf(f, " %c: %8ld %8ld %8ld ",
522 'a' + i,
523 (long) pp->p_offset,
524 (long) pp->p_offset + pp->p_size - 1,
525 (long) pp->p_size);
526 }
527 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
528 fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name);
529 else
530 fprintf(f, "%8x", pp->p_fstype);
531 switch (pp->p_fstype) {
532 case BSD_FS_UNUSED:
533 fprintf(f, " %5ld %5ld %5.5s ",
534 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
535 break;
536
537 case BSD_FS_BSDFFS:
538 fprintf(f, " %5ld %5ld %5d ",
539 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag,
540 pp->p_cpg);
541 break;
542
543 default:
544 fprintf(f, "%22.22s", "");
545 break;
546 }
547 fprintf(f, "\n");
548 }
549 }
550 }
551
552 static uint32_t ask_uint32(struct fdisk_context *cxt,
553 uint32_t dflt, char *mesg)
554 {
555 uintmax_t res;
556
557 if (fdisk_ask_number(cxt, min(dflt, (uint32_t) 1), dflt,
558 UINT32_MAX, mesg, &res) == 0)
559 return res;
560 return dflt;
561 }
562
563 static uint16_t ask_uint16(struct fdisk_context *cxt,
564 uint16_t dflt, char *mesg)
565 {
566 uintmax_t res;
567
568 if (fdisk_ask_number(cxt, min(dflt, (uint16_t) 1),
569 dflt, UINT16_MAX, mesg, &res) == 0)
570 return res;
571 return dflt;
572 }
573
574 static void xbsd_edit_disklabel(struct fdisk_context *cxt)
575 {
576 struct bsd_disklabel *d;
577 uintmax_t res;
578
579 d = &xbsd_dlabel;
580
581 #if defined (__alpha__) || defined (__ia64__)
582 if (fdisk_ask_number(cxt, DEFAULT_SECTOR_SIZE, d->d_secsize,
583 UINT32_MAX, _("bytes/sector"), &res) == 0)
584 d->d_secsize = res;
585
586 d->d_nsectors = ask_uint32(cxt, d->d_nsectors, _("sectors/track"));
587 d->d_ntracks = ask_uint32(cxt, d->d_ntracks, _("tracks/cylinder"));
588 d->d_ncylinders = ask_uint32(cxt, d->d_ncylinders ,_("cylinders"));
589 #endif
590
591 if (fdisk_ask_number(cxt, 1, d->d_nsectors * d->d_ntracks,
592 d->d_nsectors * d->d_ntracks,
593 _("sectors/cylinder"), &res) == 0)
594 d->d_secpercyl = res;
595
596 d->d_rpm = ask_uint16(cxt, d->d_rpm, _("rpm"));
597 d->d_interleave = ask_uint16(cxt, d->d_interleave, _("interleave"));
598 d->d_trackskew = ask_uint16(cxt, d->d_trackskew, _("trackskew"));
599 d->d_cylskew = ask_uint16(cxt, d->d_cylskew, _("cylinderskew"));
600
601 d->d_headswitch = ask_uint32(cxt, d->d_headswitch, _("headswitch"));
602 d->d_trkseek = ask_uint32(cxt, d->d_trkseek, _("track-to-track seek"));
603
604 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
605 }
606
607 static int xbsd_get_bootstrap(struct fdisk_context *cxt,
608 char *path, void *ptr, int size)
609 {
610 int fd;
611
612 if ((fd = open(path, O_RDONLY)) < 0) {
613 fdisk_warn(cxt, _("open failed %s"), path);
614 return -errno;
615 }
616
617 if (read_all(fd, ptr, size) != size) {
618 fdisk_warn(cxt, _("read failed %s"), path);
619 close(fd);
620 return -errno;
621 }
622
623 fdisk_info(cxt, "bootstrap file %s successfully loaded", path);
624 close (fd);
625 return 0;
626 }
627
628 static int xbsd_write_bootstrap (struct fdisk_context *cxt)
629 {
630 char *name = xbsd_dlabel.d_type == BSD_DTYPE_SCSI ? "sd" : "wd";
631 char buf[BUFSIZ];
632 char *res, *d, *p;
633 int rc;
634 sector_t sector;
635 struct bsd_disklabel dl;
636
637 snprintf(buf, sizeof(buf),
638 _("Bootstrap: %1$sboot -> boot%1$s (default %1$s)"),
639 name);
640 rc = fdisk_ask_string(cxt, buf, &res);
641 if (rc)
642 goto done;
643 if (res && *res)
644 name = res;
645
646 snprintf(buf, sizeof(buf), "%s/%sboot", BSD_LINUX_BOOTDIR, name);
647 rc = xbsd_get_bootstrap(cxt, buf,
648 disklabelbuffer,
649 (int) xbsd_dlabel.d_secsize);
650 if (rc)
651 goto done;
652
653 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */
654 d = &disklabelbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE];
655 memmove(&dl, d, sizeof(struct bsd_disklabel));
656
657 /* The disklabel will be overwritten by 0's from bootxx anyway */
658 memset(d, 0, sizeof(struct bsd_disklabel));
659
660 snprintf(buf, sizeof(buf), "%s/boot%s", BSD_LINUX_BOOTDIR, name);
661 rc = xbsd_get_bootstrap(cxt, buf,
662 &disklabelbuffer[xbsd_dlabel.d_secsize],
663 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize);
664 if (rc)
665 goto done;
666
667 /* check end of the bootstrap */
668 for (p = d; p < d + sizeof(struct bsd_disklabel); p++) {
669 if (!*p)
670 continue;
671 fdisk_warnx(cxt, _("Bootstrap overlaps with disk label!"));
672 return -EINVAL;
673 }
674
675 /* move disklabel back */
676 memmove(d, &dl, sizeof(struct bsd_disklabel));
677
678 #if defined (__powerpc__) || defined (__hppa__)
679 sector = 0;
680 #elif defined (__alpha__)
681 sector = 0;
682 alpha_bootblock_checksum(disklabelbuffer);
683 #else
684 sector = dos_partition_get_start(xbsd_part);
685 #endif
686 if (lseek(cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1) {
687 fdisk_warn(cxt, _("seek failed %s"), cxt->dev_path);
688 rc = -errno;
689 goto done;
690 }
691 if (write_all(cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) {
692 fdisk_warn(cxt, _("write failed %s"), cxt->dev_path);
693 rc = -errno;
694 goto done;
695 }
696
697 fdisk_info(cxt, _("Bootstrap installed on %s."), cxt->dev_path);
698 sync_disks ();
699
700 rc = 0;
701 done:
702 free(res);
703 return rc;
704 }
705
706 /* TODO: remove this, use regular change_partition_type() in fdisk.c */
707 static void xbsd_change_fstype (struct fdisk_context *cxt)
708 {
709 int i;
710 struct fdisk_parttype *t;
711
712 assert(cxt);
713 assert(cxt->label);
714 assert(fdisk_is_disklabel(cxt, OSF));
715
716 if (xbsd_get_part_index(cxt, xbsd_dlabel.d_npartitions, &i))
717 return;
718 t = ask_partition_type(cxt);
719
720 if (t) {
721 xbsd_dlabel.d_partitions[i].p_fstype = t->type;
722 fdisk_free_parttype(t);
723 fdisk_label_set_changed(cxt->label, 1);
724 }
725 }
726
727 static int xbsd_get_part_index(struct fdisk_context *cxt, int max, int *n)
728 {
729 int c;
730 char prompt[256];
731
732 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
733 do {
734 char *res;
735 int rc = fdisk_ask_string(cxt, prompt, &res);
736
737 if (rc)
738 return rc;
739 c = tolower(*res);
740 free(res);
741 } while (c < 'a' || c > 'a' + max - 1);
742
743 *n = c - 'a';
744 return 0;
745 }
746
747 static int
748 xbsd_check_new_partition(struct fdisk_context *cxt, int *i)
749 {
750 int rc;
751
752 /* room for more? various BSD flavours have different maxima */
753 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
754 int t;
755
756 for (t = 0; t < BSD_MAXPARTITIONS; t++)
757 if (xbsd_dlabel.d_partitions[t].p_size == 0)
758 break;
759
760 if (t == BSD_MAXPARTITIONS) {
761 fprintf (stderr, _("The maximum number of partitions "
762 "has been created\n"));
763 return -EINVAL;
764 }
765 }
766
767 rc = xbsd_get_part_index(cxt, BSD_MAXPARTITIONS, i);
768 if (rc)
769 return rc;
770
771 if (*i >= xbsd_dlabel.d_npartitions)
772 xbsd_dlabel.d_npartitions = (*i) + 1;
773
774 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
775 fprintf (stderr, _("This partition already exists.\n"));
776 return -EINVAL;
777 }
778
779 return 0;
780 }
781
782 static unsigned short
783 xbsd_dkcksum (struct bsd_disklabel *lp) {
784 unsigned short *start, *end;
785 unsigned short sum = 0;
786
787 start = (unsigned short *) lp;
788 end = (unsigned short *) &lp->d_partitions[lp->d_npartitions];
789 while (start < end)
790 sum ^= *start++;
791 return sum;
792 }
793
794 static int xbsd_initlabel (struct fdisk_context *cxt,
795 struct dos_partition *p,
796 struct bsd_disklabel *d)
797 {
798 struct bsd_partition *pp;
799
800 memset (d, 0, sizeof (struct bsd_disklabel));
801
802 d -> d_magic = BSD_DISKMAGIC;
803
804 if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0)
805 d -> d_type = BSD_DTYPE_SCSI;
806 else
807 d -> d_type = BSD_DTYPE_ST506;
808
809 #if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */
810 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex;
811 #endif
812
813 #if !defined (__alpha__)
814 d -> d_flags = BSD_D_DOSPART;
815 #else
816 d -> d_flags = 0;
817 #endif
818 d -> d_secsize = DEFAULT_SECTOR_SIZE; /* bytes/sector */
819 d -> d_nsectors = cxt->geom.sectors; /* sectors/track */
820 d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */
821 d -> d_ncylinders = cxt->geom.cylinders;
822 d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */
823 if (d -> d_secpercyl == 0)
824 d -> d_secpercyl = 1; /* avoid segfaults */
825 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders;
826
827 d -> d_rpm = 3600;
828 d -> d_interleave = 1;
829 d -> d_trackskew = 0;
830 d -> d_cylskew = 0;
831 d -> d_headswitch = 0;
832 d -> d_trkseek = 0;
833
834 d -> d_magic2 = BSD_DISKMAGIC;
835 d -> d_bbsize = BSD_BBSIZE;
836 d -> d_sbsize = BSD_SBSIZE;
837
838 #if !defined (__alpha__)
839 d -> d_npartitions = 4;
840 pp = &d -> d_partitions[2]; /* Partition C should be
841 the NetBSD partition */
842 pp -> p_offset = dos_partition_get_start(p);
843 pp -> p_size = dos_partition_get_size(p);
844 pp -> p_fstype = BSD_FS_UNUSED;
845 pp = &d -> d_partitions[3]; /* Partition D should be
846 the whole disk */
847 pp -> p_offset = 0;
848 pp -> p_size = d -> d_secperunit;
849 pp -> p_fstype = BSD_FS_UNUSED;
850 #elif defined (__alpha__)
851 d -> d_npartitions = 3;
852 pp = &d -> d_partitions[2]; /* Partition C should be
853 the whole disk */
854 pp -> p_offset = 0;
855 pp -> p_size = d -> d_secperunit;
856 pp -> p_fstype = BSD_FS_UNUSED;
857 #endif
858
859 return 0;
860 }
861
862 /*
863 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
864 * If it has the right magic, return 0.
865 */
866 static int
867 xbsd_readlabel (struct fdisk_context *cxt, struct dos_partition *p, struct bsd_disklabel *d)
868 {
869 int t, sector;
870
871 assert(cxt);
872 assert(cxt->label);
873
874 /* p is used only to get the starting sector */
875 #if !defined (__alpha__)
876 sector = (p ? dos_partition_get_start(p) : 0);
877 #elif defined (__alpha__)
878 sector = 0;
879 #endif
880
881 if (lseek (cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE, SEEK_SET) == -1)
882 return -1;
883 if (BSD_BBSIZE != read (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE))
884 return -1;
885
886 memmove (d,
887 &disklabelbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE + BSD_LABELOFFSET],
888 sizeof (struct bsd_disklabel));
889
890 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC)
891 return -1;
892
893 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) {
894 d -> d_partitions[t].p_size = 0;
895 d -> d_partitions[t].p_offset = 0;
896 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED;
897 }
898
899 if (d -> d_npartitions > BSD_MAXPARTITIONS)
900 fprintf (stderr, _("Warning: too many partitions "
901 "(%d, maximum is %d).\n"),
902 d -> d_npartitions, BSD_MAXPARTITIONS);
903
904 cxt->label->nparts_cur = d->d_npartitions;
905 cxt->label->nparts_max = BSD_MAXPARTITIONS;
906 return 0;
907 }
908
909 static int
910 xbsd_writelabel (struct fdisk_context *cxt, struct dos_partition *p, struct bsd_disklabel *d)
911 {
912 unsigned int sector;
913
914 #if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
915 sector = dos_partition_get_start(p) + BSD_LABELSECTOR;
916 #else
917 sector = BSD_LABELSECTOR;
918 #endif
919
920 d -> d_checksum = 0;
921 d -> d_checksum = xbsd_dkcksum (d);
922
923 /* This is necessary if we want to write the bootstrap later,
924 otherwise we'd write the old disklabel with the bootstrap.
925 */
926 memmove (&disklabelbuffer[BSD_LABELSECTOR * DEFAULT_SECTOR_SIZE + BSD_LABELOFFSET], d,
927 sizeof (struct bsd_disklabel));
928
929 #if defined (__alpha__) && BSD_LABELSECTOR == 0
930 alpha_bootblock_checksum (disklabelbuffer);
931 if (lseek (cxt->dev_fd, (off_t) 0, SEEK_SET) == -1) {
932 fdisk_warn(cxt, _("seek failed: %d"), cxt->dev_path);
933 return -errno;
934 }
935 if (BSD_BBSIZE != write (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) {
936 fdisk_warn(cxt, _("write failed: %d"), cxt->dev_path);
937 return -errno;
938 }
939 #else
940 if (lseek (cxt->dev_fd, (off_t) sector * DEFAULT_SECTOR_SIZE + BSD_LABELOFFSET,
941 SEEK_SET) == -1) {
942 fdisk_warn(cxt, _("seek failed: %d"), cxt->dev_path);
943 return -errno;
944 }
945 if (sizeof (struct bsd_disklabel) != write (cxt->dev_fd, d, sizeof (struct bsd_disklabel))) {
946 fdisk_warn(cxt, _("write failed: %d"), cxt->dev_path);
947 return -errno;
948 }
949 #endif
950
951 sync_disks ();
952 return 0;
953 }
954
955 static void
956 sync_disks (void)
957 {
958 printf (_("\nSyncing disks.\n"));
959 sync ();
960 sleep (4);
961 }
962
963 #if !defined (__alpha__)
964 static int
965 xbsd_translate_fstype (int linux_type)
966 {
967 switch (linux_type)
968 {
969 case 0x01: /* DOS 12-bit FAT */
970 case 0x04: /* DOS 16-bit <32M */
971 case 0x06: /* DOS 16-bit >=32M */
972 case 0xe1: /* DOS access */
973 case 0xe3: /* DOS R/O */
974 case 0xf2: /* DOS secondary */
975 return BSD_FS_MSDOS;
976 case 0x07: /* OS/2 HPFS */
977 return BSD_FS_HPFS;
978 default:
979 return BSD_FS_OTHER;
980 }
981 }
982
983 /*
984 * link partition from parent (DOS) to nested BSD partition table
985 */
986 static void
987 xbsd_link_part (struct fdisk_context *cxt)
988 {
989 size_t k;
990 int i;
991 struct dos_partition *p;
992
993 if (!cxt->parent || !fdisk_is_disklabel(cxt->parent, DOS))
994 return; /* not nested PT */
995
996 if (fdisk_ask_partnum(cxt->parent, &k, FALSE))
997 return;
998
999 if (xbsd_check_new_partition(cxt, &i))
1000 return;
1001
1002 p = fdisk_dos_get_partition(cxt->parent, k);
1003
1004 xbsd_dlabel.d_partitions[i].p_size = dos_partition_get_size(p);
1005 xbsd_dlabel.d_partitions[i].p_offset = dos_partition_get_start(p);
1006 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1007 }
1008 #endif
1009
1010 #if defined (__alpha__)
1011
1012 #if !defined(__GLIBC__)
1013 typedef unsigned long long u_int64_t;
1014 #endif
1015
1016 void
1017 alpha_bootblock_checksum (char *boot)
1018 {
1019 u_int64_t *dp, sum;
1020 int i;
1021
1022 dp = (u_int64_t *)boot;
1023 sum = 0;
1024 for (i = 0; i < 63; i++)
1025 sum += dp[i];
1026 dp[63] = sum;
1027 }
1028 #endif /* __alpha__ */
1029
1030 static struct fdisk_parttype *xbsd_get_parttype(
1031 struct fdisk_context *cxt,
1032 size_t n)
1033 {
1034 struct fdisk_parttype *t;
1035
1036 assert(cxt);
1037 assert(cxt->label);
1038 assert(fdisk_is_disklabel(cxt, OSF));
1039
1040 if (n >= xbsd_dlabel.d_npartitions)
1041 return NULL;
1042
1043 t = fdisk_get_parttype_from_code(cxt, xbsd_dlabel.d_partitions[n].p_fstype);
1044 if (!t)
1045 t = fdisk_new_unknown_parttype(xbsd_dlabel.d_partitions[n].p_fstype, NULL);
1046 return t;
1047 }
1048
1049 static int xbsd_set_parttype(
1050 struct fdisk_context *cxt,
1051 size_t partnum,
1052 struct fdisk_parttype *t)
1053 {
1054 struct bsd_partition *p;
1055
1056 assert(cxt);
1057 assert(cxt->label);
1058 assert(fdisk_is_disklabel(cxt, OSF));
1059
1060 if (partnum >= xbsd_dlabel.d_npartitions || !t || t->type > UINT8_MAX)
1061 return -EINVAL;
1062
1063 p = &xbsd_dlabel.d_partitions[partnum];
1064 if (t->type == p->p_fstype)
1065 return 0;
1066
1067 p->p_fstype = t->type;
1068 fdisk_label_set_changed(cxt->label, 1);
1069 return 0;
1070 }
1071
1072 static const struct fdisk_label_operations bsd_operations =
1073 {
1074 .probe = bsd_probe_label,
1075 .write = xbsd_write_disklabel,
1076 .create = xbsd_create_disklabel,
1077 .part_add = xbsd_add_part,
1078 .part_delete = xbsd_delete_part,
1079 .part_get_type = xbsd_get_parttype,
1080 .part_set_type = xbsd_set_parttype
1081 };
1082
1083
1084 /*
1085 * allocates BSD label driver
1086 */
1087 struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt)
1088 {
1089 struct fdisk_label *lb;
1090 struct fdisk_bsd_label *bsd;
1091
1092 assert(cxt);
1093
1094 bsd = calloc(1, sizeof(*bsd));
1095 if (!bsd)
1096 return NULL;
1097
1098 /* initialize generic part of the driver */
1099 lb = (struct fdisk_label *) bsd;
1100 lb->name = "bsd";
1101 lb->id = FDISK_DISKLABEL_OSF;
1102 lb->op = &bsd_operations;
1103 lb->parttypes = xbsd_fstypes;
1104 lb->nparttypes = ARRAY_SIZE(xbsd_fstypes);
1105
1106 lb->flags |= FDISK_LABEL_FL_ADDPART_NOPARTNO;
1107 lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;
1108
1109 return lb;
1110 }