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#define FREEBSD_PARTITION 0xa5 60#define NETBSD_PARTITION 0xa9 61#define DKTYPENAMES 62#include "fdiskbsdlabel.h" 63#include "fdiskdoslabel.h" 64 65/* 66 * in-memory fdisk BSD stuff 67 */ 68struct fdisk_bsd_label { 69 struct fdisk_label head; /* generic part */ 70}; 71 72 73static int xbsd_delete_part (struct fdisk_context *cxt, size_t partnum); 74static void xbsd_edit_disklabel (struct fdisk_context *cxt); 75static void xbsd_write_bootstrap (struct fdisk_context *cxt); 76static void xbsd_change_fstype (struct fdisk_context *cxt); 77static int xbsd_get_part_index (struct fdisk_context *cxt, int max); 78static int xbsd_check_new_partition (struct fdisk_context *cxt, int *i); 79static unsigned short xbsd_dkcksum (struct xbsd_disklabel *lp); 80static int xbsd_initlabel (struct fdisk_context *cxt, 81 struct partition *p, struct xbsd_disklabel *d, 82 int pindex); 83static int xbsd_readlabel (struct fdisk_context *cxt, 84 struct partition *p, struct xbsd_disklabel *d); 85static int xbsd_writelabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d); 86static void sync_disks (void); 87 88#if defined (__alpha__) 89void alpha_bootblock_checksum (char *boot); 90#endif 91 92#if !defined (__alpha__) 93static int xbsd_translate_fstype (int linux_type); 94static void xbsd_link_part (struct fdisk_context *cxt); 95static struct partition *xbsd_part; 96static int xbsd_part_index; 97#endif 98 99#if defined (__alpha__) 100/* We access this through a u_int64_t * when checksumming */ 101static char disklabelbuffer[BSD_BBSIZE] __attribute__((aligned(8))); 102#else 103static char disklabelbuffer[BSD_BBSIZE]; 104#endif 105 106static struct xbsd_disklabel xbsd_dlabel; 107 108#define bsd_cround(c, n) \ 109 (fdisk_context_use_cylinders(c) ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n)) 110 111/* 112 * Test whether the whole disk has BSD disk label magic. 113 * 114 * Note: often reformatting with DOS-type label leaves the BSD magic, 115 * so this does not mean that there is a BSD disk label. 116 */ 117static int 118osf_probe_label(struct fdisk_context *cxt) 119{ 120 assert(cxt); 121 assert(cxt->label); 122 assert(fdisk_is_disklabel(cxt, OSF)); 123 124 if (xbsd_readlabel (cxt, NULL, &xbsd_dlabel) == 0) 125 return 0; 126 return 1; 127} 128 129#if !defined (__alpha__) 130static int hidden(int type) 131{ 132 return type ^ 0x10; 133} 134 135static int is_bsd_partition_type(int type) 136{ 137 return (type == FREEBSD_PARTITION || 138 type == hidden(FREEBSD_PARTITION) || 139 type == NETBSD_PARTITION || 140 type == hidden(NETBSD_PARTITION)); 141} 142#endif 143 144static int xbsd_write_disklabel (struct fdisk_context *cxt) 145{ 146 printf (_("Writing disklabel to %s.\n"), cxt->dev_path); 147#if defined (__alpha__) 148 xbsd_writelabel (cxt, NULL, &xbsd_dlabel); 149#else 150 xbsd_writelabel (cxt, xbsd_part, &xbsd_dlabel); 151#endif 152 reread_partition_table(cxt, 0); /* no exit yet */ 153 154 return 0; 155} 156 157static int xbsd_add_part (struct fdisk_context *cxt, 158 size_t partnum __attribute__((__unused__)), 159 struct fdisk_parttype *t __attribute__((__unused__))) 160{ 161 unsigned int begin, end; 162 char mesg[256]; 163 int i, rc; 164 165 assert(cxt); 166 assert(cxt->label); 167 assert(fdisk_is_disklabel(cxt, OSF)); 168 169 rc = xbsd_check_new_partition(cxt, &i); 170 if (rc) 171 return rc; 172 173#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__) 174 begin = get_start_sect(xbsd_part); 175 end = begin + get_nr_sects(xbsd_part) - 1; 176#else 177 begin = 0; 178 end = xbsd_dlabel.d_secperunit - 1; 179#endif 180 181 snprintf (mesg, sizeof(mesg), _("First %s"), 182 fdisk_context_get_unit(cxt, SINGULAR)); 183 begin = read_int(cxt, bsd_cround (cxt, begin), 184 bsd_cround (cxt, begin), 185 bsd_cround (cxt, end), 186 0, mesg); 187 188 if (fdisk_context_use_cylinders(cxt)) 189 begin = (begin - 1) * xbsd_dlabel.d_secpercyl; 190 191 snprintf (mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"), 192 fdisk_context_get_unit(cxt, SINGULAR)); 193 end = read_int (cxt, bsd_cround (cxt, begin), 194 bsd_cround (cxt, end), 195 bsd_cround (cxt, end), 196 bsd_cround (cxt, begin), mesg); 197 198 if (fdisk_context_use_cylinders(cxt)) 199 end = end * xbsd_dlabel.d_secpercyl - 1; 200 201 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1; 202 xbsd_dlabel.d_partitions[i].p_offset = begin; 203 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; 204 205 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions; 206 fdisk_label_set_changed(cxt->label, 1); 207 208 return 0; 209} 210 211static int xbsd_create_disklabel(struct fdisk_context *cxt) 212{ 213 char c; 214 215 assert(cxt); 216 assert(cxt->label); 217 assert(fdisk_is_disklabel(cxt, OSF)); 218 219 fprintf (stderr, _("%s contains no disklabel.\n"), cxt->dev_path); 220 221 while (1) { 222 c = read_char(cxt, _("Do you want to create a disklabel? (y/n) ")); 223 if (tolower(c) == 'y') { 224 if (xbsd_initlabel (cxt, 225#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \ 226 defined (__s390__) || defined (__s390x__) 227 NULL, &xbsd_dlabel, 0 228#else 229 xbsd_part, &xbsd_dlabel, xbsd_part_index 230#endif 231 ) == 1) { 232 xbsd_print_disklabel (cxt, 1); 233 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions; 234 cxt->label->nparts_max = BSD_MAXPARTITIONS; 235 return 1; 236 } else 237 return 0; 238 } else if (c == 'n') 239 return 0; 240 } 241} 242 243void 244bsd_command_prompt (struct fdisk_context *cxt) 245{ 246#if !defined (__alpha__) 247 int t, ss; 248 struct partition *p; 249 250 assert(cxt); 251 assert(cxt->parent); 252 253 for (t=0; t<4; t++) { 254 p = get_part_table(t); 255 if (p && is_bsd_partition_type(p->sys_ind)) { 256 xbsd_part = p; 257 xbsd_part_index = t; 258 ss = get_start_sect(xbsd_part); 259 260 /* TODO - partname uses static buffer!!! */ 261 cxt->dev_path = partname(cxt->parent->dev_path, t+1, 0); 262 if (cxt->dev_path) 263 cxt->dev_path = strdup(cxt->dev_path); 264 265 if (ss == 0) { 266 fprintf (stderr, _("Partition %s has invalid starting sector 0.\n"), 267 cxt->dev_path); 268 return; 269 } 270 printf (_("Reading disklabel of %s at sector %d.\n"), 271 cxt->dev_path, ss + BSD_LABELSECTOR); 272 if (xbsd_readlabel (cxt, xbsd_part, &xbsd_dlabel) == 0) 273 if (xbsd_create_disklabel (cxt) == 0) 274 return; 275 break; 276 } 277 } 278 279 if (t == 4) { 280 printf (_("There is no *BSD partition on %s.\n"), cxt->dev_path); 281 return; 282 } 283 284#elif defined (__alpha__) 285 286 if (xbsd_readlabel (cxt, NULL, &xbsd_dlabel) == 0) 287 if (xbsd_create_disklabel (cxt) == 0) 288 exit ( EXIT_SUCCESS ); 289 290#endif 291 292 while (1) { 293 putchar ('\n'); 294 switch (tolower (read_char(cxt, _("BSD disklabel command (m for help): ")))) { 295 case 'd': 296 xbsd_delete_part(cxt, xbsd_get_part_index(cxt, xbsd_dlabel.d_npartitions)); 297 break; 298 case 'e': 299 xbsd_edit_disklabel (cxt); 300 break; 301 case 'i': 302 xbsd_write_bootstrap (cxt); 303 break; 304 case 'l': 305 list_partition_types (cxt); 306 break; 307 case 'n': 308 xbsd_add_part (cxt, 0, 0); 309 break; 310 case 'p': 311 xbsd_print_disklabel (cxt, 0); 312 break; 313 case 'q': 314 close (cxt->dev_fd); 315 exit ( EXIT_SUCCESS ); 316 case 'r': 317 return; 318 case 's': 319 xbsd_print_disklabel (cxt, 1); 320 break; 321 case 't': 322 xbsd_change_fstype (cxt); 323 break; 324 case 'u': 325 toggle_units(cxt); 326 break; 327 case 'w': 328 xbsd_write_disklabel (cxt); 329 break; 330#if !defined (__alpha__) 331 case 'x': 332 xbsd_link_part (cxt); 333 break; 334#endif 335 default: 336 print_menu(cxt, MAIN_MENU); 337 break; 338 } 339 } 340} 341 342static int xbsd_delete_part( 343 struct fdisk_context *cxt, 344 size_t partnum) 345{ 346 assert(cxt); 347 assert(cxt->label); 348 assert(fdisk_is_disklabel(cxt, OSF)); 349 350 xbsd_dlabel.d_partitions[partnum].p_size = 0; 351 xbsd_dlabel.d_partitions[partnum].p_offset = 0; 352 xbsd_dlabel.d_partitions[partnum].p_fstype = BSD_FS_UNUSED; 353 if (xbsd_dlabel.d_npartitions == partnum + 1) 354 while (!xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size) 355 xbsd_dlabel.d_npartitions--; 356 357 cxt->label->nparts_cur = xbsd_dlabel.d_npartitions; 358 fdisk_label_set_changed(cxt->label, 1); 359 return 0; 360} 361 362void 363xbsd_print_disklabel (struct fdisk_context *cxt, int show_all) 364{ 365 struct xbsd_disklabel *lp = &xbsd_dlabel; 366 struct xbsd_partition *pp; 367 FILE *f = stdout; 368 int i, j; 369 370 if (show_all) { 371 fprintf(f, "# %s:\n", cxt->dev_path); 372 if ((unsigned) lp->d_type < BSD_DKMAXTYPES) 373 fprintf(f, _("type: %s\n"), xbsd_dktypenames[lp->d_type]); 374 else 375 fprintf(f, _("type: %d\n"), lp->d_type); 376 fprintf(f, _("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename); 377 fprintf(f, _("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname); 378 fprintf(f, _("flags:")); 379 if (lp->d_flags & BSD_D_REMOVABLE) 380 fprintf(f, _(" removable")); 381 if (lp->d_flags & BSD_D_ECC) 382 fprintf(f, _(" ecc")); 383 if (lp->d_flags & BSD_D_BADSECT) 384 fprintf(f, _(" badsect")); 385 fprintf(f, "\n"); 386 /* On various machines the fields of *lp are short/int/long */ 387 /* In order to avoid problems, we cast them all to long. */ 388 fprintf(f, _("bytes/sector: %ld\n"), (long) lp->d_secsize); 389 fprintf(f, _("sectors/track: %ld\n"), (long) lp->d_nsectors); 390 fprintf(f, _("tracks/cylinder: %ld\n"), (long) lp->d_ntracks); 391 fprintf(f, _("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl); 392 fprintf(f, _("cylinders: %ld\n"), (long) lp->d_ncylinders); 393 fprintf(f, _("rpm: %d\n"), lp->d_rpm); 394 fprintf(f, _("interleave: %d\n"), lp->d_interleave); 395 fprintf(f, _("trackskew: %d\n"), lp->d_trackskew); 396 fprintf(f, _("cylinderskew: %d\n"), lp->d_cylskew); 397 fprintf(f, _("headswitch: %ld\t\t# milliseconds\n"), 398 (long) lp->d_headswitch); 399 fprintf(f, _("track-to-track seek: %ld\t# milliseconds\n"), 400 (long) lp->d_trkseek); 401 fprintf(f, _("drivedata: ")); 402 for (i = NDDATA - 1; i >= 0; i--) 403 if (lp->d_drivedata[i]) 404 break; 405 if (i < 0) 406 i = 0; 407 for (j = 0; j <= i; j++) 408 fprintf(f, "%ld ", (long) lp->d_drivedata[j]); 409 } 410 fprintf (f, _("\n%d partitions:\n"), lp->d_npartitions); 411 fprintf (f, _("# start end size fstype [fsize bsize cpg]\n")); 412 pp = lp->d_partitions; 413 for (i = 0; i < lp->d_npartitions; i++, pp++) { 414 if (pp->p_size) { 415 if (fdisk_context_use_cylinders(cxt) && lp->d_secpercyl) { 416 fprintf(f, " %c: %8ld%c %8ld%c %8ld%c ", 417 'a' + i, 418 (long) pp->p_offset / lp->d_secpercyl + 1, 419 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ', 420 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) 421 / lp->d_secpercyl, 422 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ', 423 (long) pp->p_size / lp->d_secpercyl, 424 (pp->p_size % lp->d_secpercyl) ? '*' : ' '); 425 } else { 426 fprintf(f, " %c: %8ld %8ld %8ld ", 427 'a' + i, 428 (long) pp->p_offset, 429 (long) pp->p_offset + pp->p_size - 1, 430 (long) pp->p_size); 431 } 432 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) 433 fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name); 434 else 435 fprintf(f, "%8x", pp->p_fstype); 436 switch (pp->p_fstype) { 437 case BSD_FS_UNUSED: 438 fprintf(f, " %5ld %5ld %5.5s ", 439 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, ""); 440 break; 441 442 case BSD_FS_BSDFFS: 443 fprintf(f, " %5ld %5ld %5d ", 444 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, 445 pp->p_cpg); 446 break; 447 448 default: 449 fprintf(f, "%22.22s", ""); 450 break; 451 } 452 fprintf(f, "\n"); 453 } 454 } 455} 456 457static unsigned long 458edit_int(struct fdisk_context *cxt, unsigned long def, char *mesg) 459{ 460 do { 461 fputs (mesg, stdout); 462 printf (" (%lu): ", def); 463 if (!read_line(cxt, NULL)) 464 return def; 465 } while (!isdigit (*line_ptr)); 466 467 return strtoul(line_ptr, NULL, 10); /* TODO check it! */ 468} 469 470static void 471xbsd_edit_disklabel(struct fdisk_context *cxt) 472{ 473 struct xbsd_disklabel *d; 474 475 d = &xbsd_dlabel; 476 477#if defined (__alpha__) || defined (__ia64__) 478 d -> d_secsize = edit_int(cxt, d->d_secsize ,_("bytes/sector")); 479 d -> d_nsectors = edit_int(cxt, d->d_nsectors ,_("sectors/track")); 480 d -> d_ntracks = edit_int(cxt, d->d_ntracks ,_("tracks/cylinder")); 481 d -> d_ncylinders = edit_int(cxt, d->d_ncylinders ,_("cylinders")); 482#endif 483 484 /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */ 485 while (1) 486 { 487 d -> d_secpercyl = edit_int(cxt, (unsigned long) d->d_nsectors * d -> d_ntracks, 488 _("sectors/cylinder")); 489 if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks) 490 break; 491 492 printf (_("Must be <= sectors/track * tracks/cylinder (default).\n")); 493 } 494 d -> d_rpm = (unsigned short) edit_int(cxt, d->d_rpm ,_("rpm")); 495 d -> d_interleave = (unsigned short) edit_int(cxt, d->d_interleave,_("interleave")); 496 d -> d_trackskew = (unsigned short) edit_int(cxt, d->d_trackskew ,_("trackskew")); 497 d -> d_cylskew = (unsigned short) edit_int(cxt, d->d_cylskew ,_("cylinderskew")); 498 d -> d_headswitch = edit_int(cxt, d->d_headswitch ,_("headswitch")); 499 d -> d_trkseek = edit_int(cxt, d->d_trkseek ,_("track-to-track seek")); 500 501 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; 502} 503 504static int 505xbsd_get_bootstrap (char *path, void *ptr, int size) 506{ 507 int fd; 508 509 if ((fd = open (path, O_RDONLY)) < 0) 510 { 511 perror (path); 512 return 0; 513 } 514 if (read (fd, ptr, size) < 0) 515 { 516 perror (path); 517 close (fd); 518 return 0; 519 } 520 printf (" ... %s\n", path); 521 close (fd); 522 return 1; 523} 524 525static void 526xbsd_write_bootstrap (struct fdisk_context *cxt) 527{ 528 char *bootdir = BSD_LINUX_BOOTDIR; 529 char path[sizeof(BSD_LINUX_BOOTDIR) + 1 + 2 + 4]; /* BSD_LINUX_BOOTDIR + / + {sd,wd} + boot */ 530 char *dkbasename; 531 struct xbsd_disklabel dl; 532 char *d, *p, *e; 533 int sector; 534 535 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI) 536 dkbasename = "sd"; 537 else 538 dkbasename = "wd"; 539 540 printf (_("Bootstrap: %sboot -> boot%s (%s): "), 541 dkbasename, dkbasename, dkbasename); 542 if (read_line(cxt, NULL)) { 543 line_ptr[strlen (line_ptr)-1] = '\0'; 544 dkbasename = line_ptr; 545 } 546 snprintf (path, sizeof(path), "%s/%sboot", bootdir, dkbasename); 547 if (!xbsd_get_bootstrap (path, disklabelbuffer, (int) xbsd_dlabel.d_secsize)) 548 return; 549 550 /* We need a backup of the disklabel (xbsd_dlabel might have changed). */ 551 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE]; 552 memmove (&dl, d, sizeof (struct xbsd_disklabel)); 553 554 /* The disklabel will be overwritten by 0's from bootxx anyway */ 555 memset (d, 0, sizeof (struct xbsd_disklabel)); 556 557 snprintf (path, sizeof(path), "%s/boot%s", bootdir, dkbasename); 558 if (!xbsd_get_bootstrap (path, &disklabelbuffer[xbsd_dlabel.d_secsize], 559 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize)) 560 return; 561 562 e = d + sizeof (struct xbsd_disklabel); 563 for (p=d; p < e; p++) 564 if (*p) { 565 fprintf (stderr, _("Bootstrap overlaps with disk label!\n")); 566 exit ( EXIT_FAILURE ); 567 } 568 569 memmove (d, &dl, sizeof (struct xbsd_disklabel)); 570 571#if defined (__powerpc__) || defined (__hppa__) 572 sector = 0; 573#elif defined (__alpha__) 574 sector = 0; 575 alpha_bootblock_checksum (disklabelbuffer); 576#else 577 sector = get_start_sect(xbsd_part); 578#endif 579 580 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1) 581 fatal (cxt, unable_to_seek); 582 if (BSD_BBSIZE != write (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) 583 fatal (cxt, unable_to_write); 584 585 printf (_("Bootstrap installed on %s.\n"), cxt->dev_path); 586 587 sync_disks (); 588} 589 590/* TODO: remove this, use regular change_partition_type() in fdisk.c */ 591static void xbsd_change_fstype (struct fdisk_context *cxt) 592{ 593 int i; 594 struct fdisk_parttype *t; 595 596 assert(cxt); 597 assert(cxt->label); 598 assert(fdisk_is_disklabel(cxt, OSF)); 599 600 i = xbsd_get_part_index (cxt, xbsd_dlabel.d_npartitions); 601 t = read_partition_type(cxt); 602 603 if (t) { 604 xbsd_dlabel.d_partitions[i].p_fstype = t->type; 605 fdisk_free_parttype(t); 606 fdisk_label_set_changed(cxt->label, 1); 607 } 608} 609 610static int 611xbsd_get_part_index(struct fdisk_context *cxt, int max) 612{ 613 char prompt[256]; 614 char l; 615 616 snprintf (prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1); 617 do 618 l = tolower(read_char(cxt, prompt)); 619 while (l < 'a' || l > 'a' + max - 1); 620 return l - 'a'; 621} 622 623static int 624xbsd_check_new_partition(struct fdisk_context *cxt, int *i) 625{ 626 /* room for more? various BSD flavours have different maxima */ 627 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) { 628 int t; 629 630 for (t = 0; t < BSD_MAXPARTITIONS; t++) 631 if (xbsd_dlabel.d_partitions[t].p_size == 0) 632 break; 633 634 if (t == BSD_MAXPARTITIONS) { 635 fprintf (stderr, _("The maximum number of partitions " 636 "has been created\n")); 637 return -EINVAL; 638 } 639 } 640 641 *i = xbsd_get_part_index(cxt, BSD_MAXPARTITIONS); 642 643 if (*i >= xbsd_dlabel.d_npartitions) 644 xbsd_dlabel.d_npartitions = (*i) + 1; 645 646 if (xbsd_dlabel.d_partitions[*i].p_size != 0) { 647 fprintf (stderr, _("This partition already exists.\n")); 648 return -EINVAL; 649 } 650 651 return 0; 652} 653 654static unsigned short 655xbsd_dkcksum (struct xbsd_disklabel *lp) { 656 unsigned short *start, *end; 657 unsigned short sum = 0; 658 659 start = (unsigned short *) lp; 660 end = (unsigned short *) &lp->d_partitions[lp->d_npartitions]; 661 while (start < end) 662 sum ^= *start++; 663 return sum; 664} 665 666static int 667xbsd_initlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d, 668 int pindex __attribute__((__unused__))) { 669 struct xbsd_partition *pp; 670 671 memset (d, 0, sizeof (struct xbsd_disklabel)); 672 673 d -> d_magic = BSD_DISKMAGIC; 674 675 if (strncmp (cxt->dev_path, "/dev/sd", 7) == 0) 676 d -> d_type = BSD_DTYPE_SCSI; 677 else 678 d -> d_type = BSD_DTYPE_ST506; 679 680#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */ 681 d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; 682#endif 683 684#if !defined (__alpha__) 685 d -> d_flags = BSD_D_DOSPART; 686#else 687 d -> d_flags = 0; 688#endif 689 d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ 690 d -> d_nsectors = cxt->geom.sectors; /* sectors/track */ 691 d -> d_ntracks = cxt->geom.heads; /* tracks/cylinder (heads) */ 692 d -> d_ncylinders = cxt->geom.cylinders; 693 d -> d_secpercyl = cxt->geom.sectors * cxt->geom.heads;/* sectors/cylinder */ 694 if (d -> d_secpercyl == 0) 695 d -> d_secpercyl = 1; /* avoid segfaults */ 696 d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; 697 698 d -> d_rpm = 3600; 699 d -> d_interleave = 1; 700 d -> d_trackskew = 0; 701 d -> d_cylskew = 0; 702 d -> d_headswitch = 0; 703 d -> d_trkseek = 0; 704 705 d -> d_magic2 = BSD_DISKMAGIC; 706 d -> d_bbsize = BSD_BBSIZE; 707 d -> d_sbsize = BSD_SBSIZE; 708 709#if !defined (__alpha__) 710 d -> d_npartitions = 4; 711 pp = &d -> d_partitions[2]; /* Partition C should be 712 the NetBSD partition */ 713 pp -> p_offset = get_start_sect(p); 714 pp -> p_size = get_nr_sects(p); 715 pp -> p_fstype = BSD_FS_UNUSED; 716 pp = &d -> d_partitions[3]; /* Partition D should be 717 the whole disk */ 718 pp -> p_offset = 0; 719 pp -> p_size = d -> d_secperunit; 720 pp -> p_fstype = BSD_FS_UNUSED; 721#elif defined (__alpha__) 722 d -> d_npartitions = 3; 723 pp = &d -> d_partitions[2]; /* Partition C should be 724 the whole disk */ 725 pp -> p_offset = 0; 726 pp -> p_size = d -> d_secperunit; 727 pp -> p_fstype = BSD_FS_UNUSED; 728#endif 729 730 return 1; 731} 732 733/* 734 * Read a xbsd_disklabel from sector 0 or from the starting sector of p. 735 * If it has the right magic, return 1. 736 */ 737static int 738xbsd_readlabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d) 739{ 740 int t, sector; 741 742 assert(cxt); 743 assert(cxt->label); 744 745 /* p is used only to get the starting sector */ 746#if !defined (__alpha__) 747 sector = (p ? get_start_sect(p) : 0); 748#elif defined (__alpha__) 749 sector = 0; 750#endif 751 752 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE, SEEK_SET) == -1) 753 return 0; 754 if (BSD_BBSIZE != read (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) 755 return 0; 756 757 memmove (d, 758 &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], 759 sizeof (struct xbsd_disklabel)); 760 761 if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC) 762 return 0; 763 764 for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) { 765 d -> d_partitions[t].p_size = 0; 766 d -> d_partitions[t].p_offset = 0; 767 d -> d_partitions[t].p_fstype = BSD_FS_UNUSED; 768 } 769 770 if (d -> d_npartitions > BSD_MAXPARTITIONS) 771 fprintf (stderr, _("Warning: too many partitions " 772 "(%d, maximum is %d).\n"), 773 d -> d_npartitions, BSD_MAXPARTITIONS); 774 775 cxt->label->nparts_cur = d->d_npartitions; 776 cxt->label->nparts_max = BSD_MAXPARTITIONS; 777 return 1; 778} 779 780static int 781xbsd_writelabel (struct fdisk_context *cxt, struct partition *p, struct xbsd_disklabel *d) 782{ 783 unsigned int sector; 784 785#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__) 786 sector = get_start_sect(p) + BSD_LABELSECTOR; 787#else 788 sector = BSD_LABELSECTOR; 789#endif 790 791 d -> d_checksum = 0; 792 d -> d_checksum = xbsd_dkcksum (d); 793 794 /* This is necessary if we want to write the bootstrap later, 795 otherwise we'd write the old disklabel with the bootstrap. 796 */ 797 memmove (&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], d, 798 sizeof (struct xbsd_disklabel)); 799 800#if defined (__alpha__) && BSD_LABELSECTOR == 0 801 alpha_bootblock_checksum (disklabelbuffer); 802 if (lseek (cxt->dev_fd, (off_t) 0, SEEK_SET) == -1) 803 fatal (cxt, unable_to_seek); 804 if (BSD_BBSIZE != write (cxt->dev_fd, disklabelbuffer, BSD_BBSIZE)) 805 fatal (cxt, unable_to_write); 806#else 807 if (lseek (cxt->dev_fd, (off_t) sector * SECTOR_SIZE + BSD_LABELOFFSET, 808 SEEK_SET) == -1) 809 fatal (cxt, unable_to_seek); 810 if (sizeof (struct xbsd_disklabel) != write (cxt->dev_fd, d, sizeof (struct xbsd_disklabel))) 811 fatal (cxt, unable_to_write); 812#endif 813 814 sync_disks (); 815 816 return 1; 817} 818 819static void 820sync_disks (void) 821{ 822 printf (_("\nSyncing disks.\n")); 823 sync (); 824 sleep (4); 825} 826 827#if !defined (__alpha__) 828static int 829xbsd_translate_fstype (int linux_type) 830{ 831 switch (linux_type) 832 { 833 case 0x01: /* DOS 12-bit FAT */ 834 case 0x04: /* DOS 16-bit <32M */ 835 case 0x06: /* DOS 16-bit >=32M */ 836 case 0xe1: /* DOS access */ 837 case 0xe3: /* DOS R/O */ 838 case 0xf2: /* DOS secondary */ 839 return BSD_FS_MSDOS; 840 case 0x07: /* OS/2 HPFS */ 841 return BSD_FS_HPFS; 842 default: 843 return BSD_FS_OTHER; 844 } 845} 846 847/* 848 * link partition from parent (DOS) to nested BSD partition table 849 */ 850static void 851xbsd_link_part (struct fdisk_context *cxt) 852{ 853 size_t k; 854 int i; 855 struct partition *p; 856 857 if (!cxt->parent) 858 return; /* not nested PT */ 859 860 if (fdisk_ask_partnum(cxt->parent, &k, FALSE)) 861 return; 862 863 if (xbsd_check_new_partition(cxt, &i)) 864 return; 865 866 p = get_part_table(k); 867 868 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p); 869 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p); 870 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind); 871} 872#endif 873 874#if defined (__alpha__) 875 876#if !defined(__GLIBC__) 877typedef unsigned long long u_int64_t; 878#endif 879 880void 881alpha_bootblock_checksum (char *boot) 882{ 883 u_int64_t *dp, sum; 884 int i; 885 886 dp = (u_int64_t *)boot; 887 sum = 0; 888 for (i = 0; i < 63; i++) 889 sum += dp[i]; 890 dp[63] = sum; 891} 892#endif /* __alpha__ */ 893 894static struct fdisk_parttype *xbsd_get_parttype( 895 struct fdisk_context *cxt, 896 size_t n) 897{ 898 struct fdisk_parttype *t; 899 900 assert(cxt); 901 assert(cxt->label); 902 assert(fdisk_is_disklabel(cxt, OSF)); 903 904 if (n >= xbsd_dlabel.d_npartitions) 905 return NULL; 906 907 t = fdisk_get_parttype_from_code(cxt, xbsd_dlabel.d_partitions[n].p_fstype); 908 if (!t) 909 t = fdisk_new_unknown_parttype(xbsd_dlabel.d_partitions[n].p_fstype, NULL); 910 return t; 911} 912 913static int xbsd_set_parttype( 914 struct fdisk_context *cxt, 915 size_t partnum, 916 struct fdisk_parttype *t) 917{ 918 struct xbsd_partition *p; 919 920 assert(cxt); 921 assert(cxt->label); 922 assert(fdisk_is_disklabel(cxt, OSF)); 923 924 if (partnum >= xbsd_dlabel.d_npartitions || !t || t->type > UINT8_MAX) 925 return -EINVAL; 926 927 p = &xbsd_dlabel.d_partitions[partnum]; 928 if (t->type == p->p_fstype) 929 return 0; 930 931 p->p_fstype = t->type; 932 fdisk_label_set_changed(cxt->label, 1); 933 return 0; 934} 935 936static const struct fdisk_label_operations bsd_operations = 937{ 938 .probe = osf_probe_label, 939 .write = xbsd_write_disklabel, 940 .create = xbsd_create_disklabel, 941 .part_add = xbsd_add_part, 942 .part_delete = xbsd_delete_part, 943 .part_get_type = xbsd_get_parttype, 944 .part_set_type = xbsd_set_parttype 945}; 946 947 948/* 949 * allocates BSD label driver 950 */ 951struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) 952{ 953 struct fdisk_label *lb; 954 struct fdisk_bsd_label *bsd; 955 956 assert(cxt); 957 958 bsd = calloc(1, sizeof(*bsd)); 959 if (!bsd) 960 return NULL; 961 962 /* initialize generic part of the driver */ 963 lb = (struct fdisk_label *) bsd; 964 lb->name = "bsd"; 965 lb->id = FDISK_DISKLABEL_OSF; 966 lb->op = &bsd_operations; 967 lb->parttypes = xbsd_fstypes; 968 lb->nparttypes = ARRAY_SIZE(xbsd_fstypes); 969 970 /* don't ask for partition number for op->part_add() */ 971 lb->flags = FDISK_LABEL_FL_ADDPART_NOPARTNO; 972 973 return lb; 974} 975