1 /* $NetBSD: main.c,v 1.4 2005/06/17 21:20:18 dsl Exp $ */ 2 3 /* 4 * Copyright (c) 1987, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Symmetric Computer Systems. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #if HAVE_NBTOOL_CONFIG_H 36 #include "nbtool_config.h" 37 #endif 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"); 43 #endif /* not lint */ 44 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "@(#)disklabel.c 8.4 (Berkeley) 5/4/95"; 48 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 49 #else 50 __RCSID("$NetBSD: main.c,v 1.4 2005/06/17 21:20:18 dsl Exp $"); 51 #endif 52 #endif /* not lint */ 53 54 #include <sys/param.h> 55 #include <sys/file.h> 56 #include <sys/stat.h> 57 #include <sys/wait.h> 58 #define DKTYPENAMES 59 #define FSTYPENAMES 60 61 #include <ctype.h> 62 #include <err.h> 63 #include <errno.h> 64 #include <unistd.h> 65 #include <signal.h> 66 #include <string.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <unistd.h> 70 71 #include <ufs/ufs/dinode.h> 72 #include <ufs/ffs/fs.h> 73 74 #if HAVE_NBTOOL_CONFIG_H 75 #include <nbinclude/sys/disklabel.h> 76 #include <nbinclude/sys/bootblock.h> 77 #include "../../include/util.h" 78 #include "../../include/disktab.h" 79 #else 80 #include <sys/ioctl.h> 81 #include <sys/disklabel.h> 82 #include <sys/bootblock.h> 83 #include <util.h> 84 #include <disktab.h> 85 #endif /* HAVE_NBTOOL_CONFIG_H */ 86 87 #include "pathnames.h" 88 #include "extern.h" 89 #include "dkcksum.h" 90 91 /* 92 * Disklabel: read and write disklabels. 93 * The label is usually placed on one of the first sectors of the disk. 94 * Many machines also place a bootstrap in the same area, 95 * in which case the label is embedded in the bootstrap. 96 * The bootstrap source must leave space at the proper offset 97 * for the label on such machines. 98 */ 99 100 #ifndef BBSIZE 101 #define BBSIZE 8192 /* size of boot area, with label */ 102 #endif 103 104 #define DEFEDITOR _PATH_VI 105 106 static char *dkname; 107 static char tmpfil[MAXPATHLEN]; 108 109 static char namebuf[BBSIZE], *np = namebuf; 110 static struct disklabel lab; 111 112 char bootarea[BBSIZE]; 113 char *specname; 114 115 static enum { 116 UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, WRITE, INTERACT 117 } op = UNSPEC; 118 119 static int Fflag; 120 static int rflag; 121 static int tflag; 122 int Cflag; 123 static int Iflag; 124 125 #define COMMON_OPTIONS "BCFINRWb:ef:irs:tw" 126 127 #ifdef DEBUG 128 static int debug; 129 #define OPTIONS COMMON_OPTIONS "d" 130 #else /* ! DEBUG */ 131 #define OPTIONS COMMON_OPTIONS 132 #endif /* ! DEBUG */ 133 134 #ifdef USE_MBR 135 static struct mbr_partition *dosdp; /* i386 DOS partition, if found */ 136 static struct mbr_partition *readmbr(int); 137 #endif /* USE_MBR */ 138 139 #ifdef USE_ACORN 140 static u_int filecore_partition_offset; 141 static u_int get_filecore_partition(int); 142 static int filecore_checksum(u_char *); 143 #endif /* USE_ACORN */ 144 145 #if defined(USE_MBR) || (defined(USE_ACORN) && defined(notyet)) 146 static void confirm(const char *); 147 #endif 148 149 int main(int, char *[]); 150 151 static void makedisktab(FILE *, struct disklabel *); 152 static void makelabel(const char *, const char *, 153 struct disklabel *); 154 static void l_perror(const char *); 155 static struct disklabel *readlabel(int); 156 static struct disklabel *makebootarea(char *, struct disklabel *, int); 157 static int edit(struct disklabel *, int); 158 static int editit(void); 159 static char *skip(char *); 160 static char *word(char *); 161 static int getasciilabel(FILE *, struct disklabel *); 162 static void usage(void); 163 static int getulong(const char *, char, char **, 164 unsigned long *, unsigned long); 165 #define GETNUM32(a, v) getulong(a, '\0', NULL, v, UINT32_MAX) 166 #define GETNUM16(a, v) getulong(a, '\0', NULL, v, UINT16_MAX) 167 #define GETNUM8(a, v) getulong(a, '\0', NULL, v, UINT8_MAX) 168 169 #if HAVE_NBTOOL_CONFIG_H 170 #define GETLABELOFFSET() LABELOFFSET 171 #define GETLABELSECTOR() LABELSECTOR 172 #else /* HAVE_NBTOOL_CONFIG_H */ 173 #define GETLABELOFFSET() getlabeloffset() 174 #define GETLABELSECTOR() getlabelsector() 175 #endif 176 177 int 178 main(int argc, char *argv[]) 179 { 180 struct disklabel *lp; 181 FILE *t; 182 int ch, f, writable, error; 183 184 error = 0; 185 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 186 switch (ch) { 187 case 'C': 188 ++Cflag; 189 break; 190 case 'F': 191 ++Fflag; 192 break; 193 case 'I': 194 ++Iflag; 195 break; 196 case 'R': 197 if (op != UNSPEC) 198 usage(); 199 op = RESTORE; 200 break; 201 #if !HAVE_NBTOOL_CONFIG_H 202 case 'N': 203 if (op != UNSPEC) 204 usage(); 205 writable = 0; 206 op = SETWRITABLE; 207 break; 208 case 'W': 209 if (op != UNSPEC) 210 usage(); 211 writable = 1; 212 op = SETWRITABLE; 213 break; 214 #endif /* !HAVE_NBTOOL_CONFIG_H */ 215 case 'e': 216 if (op != UNSPEC) 217 usage(); 218 op = EDIT; 219 break; 220 case 'f': 221 if (setdisktab(optarg) == -1) 222 usage(); 223 break; 224 case 'i': 225 if (op != UNSPEC) 226 usage(); 227 op = INTERACT; 228 break; 229 case 't': 230 ++tflag; 231 break; 232 case 'r': 233 ++rflag; 234 break; 235 case 'w': 236 if (op != UNSPEC) 237 usage(); 238 op = WRITE; 239 break; 240 #ifdef DEBUG 241 case 'd': 242 debug++; 243 break; 244 #endif 245 case '?': 246 default: 247 usage(); 248 } 249 argc -= optind; 250 argv += optind; 251 252 if (op == UNSPEC) 253 op = READ; 254 255 if (argc < 1) 256 usage(); 257 258 if (Iflag && op != EDIT && op != INTERACT) 259 usage(); 260 261 dkname = argv[0]; 262 #if HAVE_NBTOOL_CONFIG_H 263 f = open(dkname, op == READ ? O_RDONLY : O_RDWR, 0); 264 strlcpy(np, dkname, MAXPATHLEN); 265 #else 266 f = opendisk(dkname, op == READ ? O_RDONLY : O_RDWR, np, MAXPATHLEN, 0); 267 #endif /* HAVE_NBTOOL_CONFIG_H */ 268 specname = np; 269 np += strlen(specname) + 1; 270 if (f < 0) 271 err(4, "%s", specname); 272 273 #ifdef USE_MBR 274 /* 275 * Check for presence of DOS partition table in 276 * master boot record. Return pointer to NetBSD/i386 277 * partition, if present. 278 */ 279 dosdp = readmbr(f); 280 #endif /* USE_MBR */ 281 282 #ifdef USE_ACORN 283 /* 284 * Check for the presence of a RiscOS filecore boot block 285 * indicating an ADFS file system on the disc. 286 * Return the offset to the NetBSD part of the disc if 287 * this can be determined. 288 * This routine will terminate disklabel if the disc 289 * is found to be ADFS only. 290 */ 291 filecore_partition_offset = get_filecore_partition(f); 292 #endif /* USE_ACORN */ 293 294 switch (op) { 295 296 case EDIT: 297 if (argc != 1) 298 usage(); 299 lp = readlabel(f); 300 error = edit(lp, f); 301 break; 302 303 case INTERACT: 304 if (argc != 1) 305 usage(); 306 lp = readlabel(f); 307 /* 308 * XXX: Fill some default values so checklabel does not fail 309 */ 310 if (lp->d_bbsize == 0) 311 lp->d_bbsize = BBSIZE; 312 if (lp->d_sbsize == 0) 313 lp->d_sbsize = SBLOCKSIZE; 314 interact(lp, f); 315 break; 316 317 case READ: 318 if (argc != 1) 319 usage(); 320 lp = readlabel(f); 321 if (tflag) 322 makedisktab(stdout, lp); 323 else { 324 showinfo(stdout, lp, specname); 325 showpartitions(stdout, lp, Cflag); 326 } 327 error = checklabel(lp); 328 if (error) 329 error += 100; 330 break; 331 332 case RESTORE: 333 if (argc < 2 || argc > 3) 334 usage(); 335 lp = makebootarea(bootarea, &lab, f); 336 if (!(t = fopen(argv[1], "r"))) 337 err(4, "%s", argv[1]); 338 if (getasciilabel(t, lp)) 339 error = writelabel(f, bootarea, lp); 340 else 341 error = 1; 342 break; 343 344 #if !HAVE_NBTOOL_CONFIG_H 345 case SETWRITABLE: 346 if (ioctl(f, DIOCWLABEL, (char *)&writable) < 0) 347 err(4, "ioctl DIOCWLABEL"); 348 break; 349 #endif /* !HAVE_NBTOOL_CONFIG_H */ 350 351 case WRITE: 352 if (argc < 2 || argc > 3) 353 usage(); 354 makelabel(argv[1], argc == 3 ? argv[2] : (char *)0, &lab); 355 lp = makebootarea(bootarea, &lab, f); 356 *lp = lab; 357 if (checklabel(lp) == 0) 358 error = writelabel(f, bootarea, lp); 359 else 360 error = 1; 361 break; 362 363 case UNSPEC: 364 usage(); 365 366 } 367 exit(error); 368 } 369 370 /* 371 * Construct a prototype disklabel from /etc/disktab. As a side 372 * effect, set the names of the primary and secondary boot files 373 * if specified. 374 */ 375 static void 376 makelabel(const char *type, const char *name, struct disklabel *lp) 377 { 378 struct disklabel *dp; 379 380 dp = getdiskbyname(type); 381 if (dp == NULL) 382 errx(1, "unknown disk type: %s", type); 383 *lp = *dp; 384 385 /* d_packname is union d_boot[01], so zero */ 386 (void) memset(lp->d_packname, 0, sizeof(lp->d_packname)); 387 if (name) 388 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 389 } 390 391 #if defined(USE_MBR) || (defined(USE_ACORN) && defined(notyet)) 392 static void 393 confirm(const char *txt) 394 { 395 int first, ch; 396 397 (void) printf("%s? [n]: ", txt); 398 (void) fflush(stdout); 399 first = ch = getchar(); 400 while (ch != '\n' && ch != EOF) 401 ch = getchar(); 402 if (first != 'y' && first != 'Y') 403 exit(0); 404 } 405 #endif /* USE_MBR || USE_ACORN && notyet */ 406 407 int 408 writelabel(int f, char *boot, struct disklabel *lp) 409 { 410 int writable; 411 off_t sectoffset; 412 413 sectoffset = 0; 414 lp->d_magic = DISKMAGIC; 415 lp->d_magic2 = DISKMAGIC; 416 lp->d_checksum = 0; 417 lp->d_checksum = dkcksum(lp); 418 419 if (Fflag || rflag || Iflag) 420 { 421 #ifdef USE_MBR 422 struct partition *pp = &lp->d_partitions[2]; 423 424 /* 425 * If NetBSD/i386 DOS partition is missing, or if 426 * the label to be written is not within partition, 427 * prompt first. Need to allow this in case operator 428 * wants to convert the drive for dedicated use. 429 */ 430 if (dosdp) { 431 if (dosdp->mbrp_start != pp->p_offset) { 432 printf("NetBSD slice at %u, " 433 "partition C at %u\n", dosdp->mbrp_start, 434 pp->p_offset); 435 confirm("Write outside MBR partition"); 436 } 437 sectoffset = (off_t)pp->p_offset * lp->d_secsize; 438 } else { 439 sectoffset = 0; 440 } 441 #endif /* USE_MBR */ 442 443 #ifdef USE_ACORN 444 /* XXX */ 445 sectoffset = (off_t)filecore_partition_offset * DEV_BSIZE; 446 #endif /* USE_ACORN */ 447 448 /* 449 * First set the kernel disk label, 450 * then write a label to the raw disk. 451 * If the SDINFO ioctl fails because it is unimplemented, 452 * keep going; otherwise, the kernel consistency checks 453 * may prevent us from changing the current (in-core) 454 * label. 455 */ 456 #if !HAVE_NBTOOL_CONFIG_H 457 if (!Fflag && ioctl(f, DIOCSDINFO, lp) < 0 && 458 errno != ENODEV && errno != ENOTTY) { 459 l_perror("ioctl DIOCSDINFO"); 460 return (1); 461 } 462 #endif /* HAVE_NBTOOL_CONFIG_H */ 463 if (lseek(f, sectoffset, SEEK_SET) < 0) { 464 perror("lseek"); 465 return (1); 466 } 467 /* 468 * write enable label sector before write (if necessary), 469 * disable after writing. 470 */ 471 writable = 1; 472 #if !HAVE_NBTOOL_CONFIG_H 473 if (!Fflag && ioctl(f, DIOCWLABEL, &writable) < 0) 474 perror("ioctl DIOCWLABEL"); 475 #endif /* HAVE_NBTOOL_CONFIG_H */ 476 477 #ifdef __alpha__ 478 /* 479 * The Alpha requires that the boot block be checksummed. 480 * The NetBSD/alpha disklabel.h provides a macro to do it. 481 */ 482 { 483 struct alpha_boot_block *bb; 484 485 bb = (struct alpha_boot_block *)boot; 486 ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 487 } 488 #endif /* __alpha__ */ 489 490 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { 491 perror("write"); 492 return (1); 493 } 494 495 writable = 0; 496 #if !HAVE_NBTOOL_CONFIG_H 497 if (!Fflag && ioctl(f, DIOCWLABEL, &writable) < 0) 498 perror("ioctl DIOCWLABEL"); 499 /* 500 * Now issue a DIOCWDINFO. This will let the kernel convert the 501 * disklabel to some machdep format if needed. 502 */ 503 if (!Fflag && ioctl(f, DIOCWDINFO, lp) < 0) { 504 l_perror("ioctl DIOCWDINFO"); 505 return (1); 506 } 507 #endif /* !HAVE_NBTOOL_CONFIG_H */ 508 } else { 509 #if !HAVE_NBTOOL_CONFIG_H 510 if (ioctl(f, DIOCWDINFO, lp) < 0) { 511 l_perror("ioctl DIOCWDINFO"); 512 return (1); 513 } 514 #else 515 errx(1, "use -F, -r, or -I"); 516 #endif /* HAVE_NBTOOL_CONFIG_H */ 517 } 518 519 #ifdef __vax__ 520 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 521 daddr_t alt; 522 int i; 523 524 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 525 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 526 (void)lseek(f, (off_t)(alt + i) * lp->d_secsize, 527 SEEK_SET); 528 if (write(f, boot, lp->d_secsize) < lp->d_secsize) 529 warn("alternate label %d write", i/2); 530 } 531 } 532 #endif /* __vax__ */ 533 534 return (0); 535 } 536 537 static void 538 l_perror(const char *s) 539 { 540 541 switch (errno) { 542 543 case ESRCH: 544 warnx("%s: No disk label on disk;\n" 545 "use \"disklabel -I\" to install initial label", s); 546 break; 547 548 case EINVAL: 549 warnx("%s: Label magic number or checksum is wrong!\n" 550 "(disklabel or kernel is out of date?)", s); 551 break; 552 553 case EBUSY: 554 warnx("%s: Open partition would move or shrink", s); 555 break; 556 557 case EXDEV: 558 warnx("%s: Labeled partition or 'a' partition must start" 559 " at beginning of disk", s); 560 break; 561 562 default: 563 warn("%s", s); 564 break; 565 } 566 } 567 568 #ifdef USE_MBR 569 /* 570 * Fetch DOS partition table from disk. 571 */ 572 static struct mbr_partition * 573 readmbr(int f) 574 { 575 struct mbr_partition *dp; 576 struct mbr_sector mbr; 577 int part; 578 u_int ext_base, next_ext, this_ext; 579 static struct mbr_partition netbsd_part; 580 581 /* 582 * Don't (yet) know disk geometry (BIOS), use 583 * partition table to find NetBSD/i386 partition, and obtain 584 * disklabel from there. 585 */ 586 587 ext_base = 0; 588 next_ext = 0; 589 for (;;) { 590 this_ext = next_ext; 591 next_ext = 0; 592 if (pread(f, &mbr, sizeof mbr, this_ext * (off_t)DEV_BSIZE) 593 != sizeof(mbr)) { 594 warn("Can't read master boot record %d", this_ext); 595 return 0; 596 } 597 598 /* Check if table is valid. */ 599 if (mbr.mbr_magic != htole16(MBR_MAGIC)) { 600 warnx("Invalid signature in mbr record %d", this_ext); 601 return 0; 602 } 603 604 dp = &mbr.mbr_parts[0]; 605 #if defined(_no_longer_needed) && !defined(__i386__) && !defined(__x86_64__) 606 /* avoid alignment error */ 607 memcpy(mbr, dp, MBR_PART_COUNT * sizeof(*dp)); 608 dp = (struct mbr_partition *)mbr; 609 #endif /* ! __i386__ */ 610 611 /* Find NetBSD partition. */ 612 for (part = 0; part < MBR_PART_COUNT; dp++, part++) { 613 dp->mbrp_start = le32toh(dp->mbrp_start); 614 dp->mbrp_size = le32toh(dp->mbrp_size); 615 switch (dp->mbrp_type) { 616 case MBR_PTYPE_NETBSD: 617 netbsd_part = *dp; 618 break; 619 case MBR_PTYPE_EXT: 620 case MBR_PTYPE_EXT_LBA: 621 case MBR_PTYPE_EXT_LNX: 622 next_ext = dp->mbrp_start; 623 continue; 624 #ifdef COMPAT_386BSD_MBRPART 625 case MBR_PTYPE_386BSD: 626 if (ext_base == 0) 627 netbsd_part = *dp; 628 continue; 629 #endif /* COMPAT_386BSD_MBRPART */ 630 default: 631 continue; 632 } 633 break; 634 } 635 if (part < MBR_PART_COUNT) 636 /* We found a netbsd partition */ 637 break; 638 if (next_ext == 0) 639 /* No more extended partitions */ 640 break; 641 next_ext += ext_base; 642 if (ext_base == 0) 643 ext_base = next_ext; 644 645 if (next_ext <= this_ext) { 646 warnx("Invalid extended chain %x <= %x", 647 next_ext, this_ext); 648 break; 649 } 650 } 651 652 if (netbsd_part.mbrp_type == 0) 653 return 0; 654 655 netbsd_part.mbrp_start += this_ext; 656 return &netbsd_part; 657 } 658 #endif /* USE_MBR */ 659 660 #ifdef USE_ACORN 661 /* 662 * static int filecore_checksum(u_char *bootblock) 663 * 664 * Calculates the filecore boot block checksum. This is used to validate 665 * a filecore boot block on the disk. If a boot block is validated then 666 * it is used to locate the partition table. If the boot block is not 667 * validated, it is assumed that the whole disk is NetBSD. 668 * 669 * The basic algorithm is: 670 * 671 * for (each byte in block, excluding checksum) { 672 * sum += byte; 673 * if (sum > 255) 674 * sum -= 255; 675 * } 676 * 677 * That's equivalent to summing all of the bytes in the block 678 * (excluding the checksum byte, of course), then calculating the 679 * checksum as "cksum = sum - ((sum - 1) / 255) * 255)". That 680 * expression may or may not yield a faster checksum function, 681 * but it's easier to reason about. 682 * 683 * Note that if you have a block filled with bytes of a single 684 * value "X" (regardless of that value!) and calculate the cksum 685 * of the block (excluding the checksum byte), you will _always_ 686 * end up with a checksum of X. (Do the math; that can be derived 687 * from the checksum calculation function!) That means that 688 * blocks which contain bytes which all have the same value will 689 * always checksum properly. That's a _very_ unlikely occurence 690 * (probably impossible, actually) for a valid filecore boot block, 691 * so we treat such blocks as invalid. 692 */ 693 static int 694 filecore_checksum(u_char *bootblock) 695 { 696 u_char byte0, accum_diff; 697 u_int sum; 698 int i; 699 700 sum = 0; 701 accum_diff = 0; 702 byte0 = bootblock[0]; 703 704 /* 705 * Sum the contents of the block, keeping track of whether 706 * or not all bytes are the same. If 'accum_diff' ends up 707 * being zero, all of the bytes are, in fact, the same. 708 */ 709 for (i = 0; i < 511; ++i) { 710 sum += bootblock[i]; 711 accum_diff |= bootblock[i] ^ byte0; 712 } 713 714 /* 715 * Check to see if the checksum byte is the same as the 716 * rest of the bytes, too. (Note that if all of the bytes 717 * are the same except the checksum, a checksum compare 718 * won't succeed, but that's not our problem.) 719 */ 720 accum_diff |= bootblock[i] ^ byte0; 721 722 /* All bytes in block are the same; call it invalid. */ 723 if (accum_diff == 0) 724 return (-1); 725 726 return (sum - ((sum - 1) / 255) * 255); 727 } 728 729 /* 730 * Fetch filecore bootblock from disk and analyse it 731 */ 732 static u_int 733 get_filecore_partition(int f) 734 { 735 struct filecore_bootblock *fcbb; 736 static char bb[DEV_BSIZE]; 737 u_int offset; 738 739 if (lseek(f, (off_t)FILECORE_BOOT_SECTOR * DEV_BSIZE, SEEK_SET) < 0 || 740 read(f, bb, sizeof(bb)) != sizeof(bb)) 741 err(4, "can't read filecore boot block"); 742 fcbb = (struct filecore_bootblock *)bb; 743 744 /* Check if table is valid. */ 745 if (filecore_checksum(bb) != fcbb->checksum) 746 return (0); 747 748 /* 749 * Check for NetBSD/arm32 (RiscBSD) partition marker. 750 * If found the NetBSD disklabel location is easy. 751 */ 752 offset = (fcbb->partition_cyl_low + (fcbb->partition_cyl_high << 8)) 753 * fcbb->heads * fcbb->secspertrack; 754 if (fcbb->partition_type == PARTITION_FORMAT_RISCBSD) 755 return (offset); 756 else if (fcbb->partition_type == PARTITION_FORMAT_RISCIX) { 757 struct riscix_partition_table *riscix_part; 758 int loop; 759 760 /* 761 * Read the RISCiX partition table and search for the 762 * first partition named "RiscBSD", "NetBSD", or "Empty:" 763 * 764 * XXX is use of 'Empty:' really desirable?! -- cgd 765 */ 766 767 if (lseek(f, (off_t)offset * DEV_BSIZE, SEEK_SET) < 0 || 768 read(f, bb, sizeof(bb)) != sizeof(bb)) 769 err(4, "can't read riscix partition table"); 770 riscix_part = (struct riscix_partition_table *)bb; 771 772 for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) { 773 if (strcmp(riscix_part->partitions[loop].rp_name, 774 "RiscBSD") == 0 || 775 strcmp(riscix_part->partitions[loop].rp_name, 776 "NetBSD") == 0 || 777 strcmp(riscix_part->partitions[loop].rp_name, 778 "Empty:") == 0) { 779 offset = riscix_part->partitions[loop].rp_start; 780 break; 781 } 782 } 783 if (loop == NRISCIX_PARTITIONS) { 784 /* 785 * Valid filecore boot block, RISCiX partition table 786 * but no NetBSD partition. We should leave this 787 * disc alone. 788 */ 789 errx(4, "cannot label: no NetBSD partition found" 790 " in RISCiX partition table"); 791 } 792 return (offset); 793 } else { 794 /* 795 * Valid filecore boot block and no non-ADFS partition. 796 * This means that the whole disc is allocated for ADFS 797 * so do not trash ! If the user really wants to put a 798 * NetBSD disklabel on the disc then they should remove 799 * the filecore boot block first with dd. 800 */ 801 errx(4, "cannot label: filecore-only disk" 802 " (no non-ADFS partition)"); 803 } 804 return (0); 805 } 806 #endif /* USE_ACORN */ 807 808 /* 809 * Fetch disklabel for disk. 810 * Use ioctl to get label unless -r flag is given. 811 */ 812 static struct disklabel * 813 readlabel(int f) 814 { 815 struct disklabel *lp; 816 817 if (Fflag || rflag || Iflag) { 818 const char *msg; 819 off_t sectoffset; 820 821 msg = NULL; 822 sectoffset = 0; 823 824 #ifdef USE_MBR 825 if (dosdp) 826 sectoffset = (off_t)dosdp->mbrp_start * DEV_BSIZE; 827 #endif /* USE_MBR */ 828 829 #ifdef USE_ACORN 830 /* XXX */ 831 sectoffset = (off_t)filecore_partition_offset * DEV_BSIZE; 832 #endif /* USE_ACORN */ 833 834 if (lseek(f, sectoffset, SEEK_SET) < 0 || 835 read(f, bootarea, BBSIZE) != BBSIZE) 836 err(4, "%s", specname); 837 838 msg = "no disklabel"; 839 for (lp = (struct disklabel *)bootarea; 840 lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); 841 lp = (struct disklabel *)((char *)lp + sizeof(long))) { 842 if (lp->d_magic == DISKMAGIC && 843 lp->d_magic2 == DISKMAGIC) { 844 if (lp->d_npartitions <= MAXPARTITIONS && 845 dkcksum(lp) == 0) 846 return (lp); 847 msg = "disk label corrupted"; 848 } 849 } 850 if (msg != NULL && !Iflag) 851 errx(1, "%s", msg); 852 #if HAVE_NBTOOL_CONFIG_H 853 goto err; 854 #else 855 /* 856 * There was no label on the disk. Get the fictious one 857 * as a basis for initialisation. 858 */ 859 lp = makebootarea(bootarea, &lab, f); 860 if (ioctl(f, DIOCGDINFO, lp) < 0 && 861 ioctl(f, DIOCGDEFLABEL, lp) < 0) 862 goto err; 863 #endif /* HAVE_NBTOOL_CONFIG_H */ 864 } else { 865 #ifdef HAVE_NBTOOL_CONFIG_H 866 goto err; 867 #else 868 lp = &lab; 869 if (ioctl(f, DIOCGDINFO, lp) < 0) 870 err(4, "ioctl DIOCGDINFO"); 871 #endif /* HAVE_NBTOOL_CONFIG_H */ 872 } 873 return (lp); 874 err: 875 errx(1, "could not get initial label"); 876 } 877 878 /* 879 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 880 * Returns a pointer to the disklabel portion of the bootarea. 881 */ 882 static struct disklabel * 883 makebootarea(char *boot, struct disklabel *dp, int f) 884 { 885 struct disklabel *lp; 886 char *p; 887 daddr_t lsec; 888 off_t loff; 889 890 if ((lsec = GETLABELSECTOR()) < 0) 891 err(4, "getlabelsector()"); 892 if ((loff = GETLABELOFFSET()) < 0) 893 err(4, "getlabeloffset()"); 894 895 /* XXX */ 896 if (dp->d_secsize == 0) { 897 dp->d_secsize = DEV_BSIZE; 898 dp->d_bbsize = BBSIZE; 899 } 900 lp = (struct disklabel *) (boot + (lsec * dp->d_secsize) + loff); 901 (void) memset(lp, 0, sizeof(*lp)); 902 903 #ifdef SAVEBOOTAREA 904 /* 905 * We must read the current bootarea so we don't clobber the 906 * existing boot block, if any. 907 */ 908 if (rflag || Iflag) { 909 off_t sectoffset; 910 911 sectoffset = 0; 912 if (lseek(f, sectoffset, SEEK_SET) < 0 || 913 read(f, boot, BBSIZE) != BBSIZE) 914 err(4, "%s", specname); 915 (void) memset(lp, 0, sizeof(*lp)); 916 } 917 #endif /* SAVEBOOTAREA */ 918 919 /* 920 * Make sure no part of the bootstrap is written in the area 921 * reserved for the label. 922 */ 923 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 924 if (*p) 925 errx(2, "Bootstrap doesn't leave room for disk label"); 926 return (lp); 927 } 928 929 static void 930 makedisktab(FILE *f, struct disklabel *lp) 931 { 932 int i; 933 const char *did; 934 struct partition *pp; 935 936 did = "\\\n\t:"; 937 (void) fprintf(f, "%.*s|Automatically generated label:\\\n\t:dt=", 938 (int) sizeof(lp->d_typename), lp->d_typename); 939 if ((unsigned) lp->d_type < DKMAXTYPES) 940 (void) fprintf(f, "%s:", dktypenames[lp->d_type]); 941 else 942 (void) fprintf(f, "unknown%d:", lp->d_type); 943 944 (void) fprintf(f, "se#%d:", lp->d_secsize); 945 (void) fprintf(f, "ns#%d:", lp->d_nsectors); 946 (void) fprintf(f, "nt#%d:", lp->d_ntracks); 947 (void) fprintf(f, "sc#%d:", lp->d_secpercyl); 948 (void) fprintf(f, "nc#%d:", lp->d_ncylinders); 949 950 if ((lp->d_secpercyl * lp->d_ncylinders) != lp->d_secperunit) { 951 (void) fprintf(f, "%ssu#%d:", did, lp->d_secperunit); 952 did = ""; 953 } 954 if (lp->d_rpm != 3600) { 955 (void) fprintf(f, "%srm#%d:", did, lp->d_rpm); 956 did = ""; 957 } 958 if (lp->d_interleave != 1) { 959 (void) fprintf(f, "%sil#%d:", did, lp->d_interleave); 960 did = ""; 961 } 962 if (lp->d_trackskew != 0) { 963 (void) fprintf(f, "%ssk#%d:", did, lp->d_trackskew); 964 did = ""; 965 } 966 if (lp->d_cylskew != 0) { 967 (void) fprintf(f, "%scs#%d:", did, lp->d_cylskew); 968 did = ""; 969 } 970 if (lp->d_headswitch != 0) { 971 (void) fprintf(f, "%shs#%d:", did, lp->d_headswitch); 972 did = ""; 973 } 974 if (lp->d_trkseek != 0) { 975 (void) fprintf(f, "%sts#%d:", did, lp->d_trkseek); 976 did = ""; 977 } 978 #ifdef notyet 979 (void) fprintf(f, "drivedata: "); 980 for (i = NDDATA - 1; i >= 0; i--) 981 if (lp->d_drivedata[i]) 982 break; 983 if (i < 0) 984 i = 0; 985 for (j = 0; j <= i; j++) 986 (void) fprintf(f, "%d ", lp->d_drivedata[j]); 987 #endif /* notyet */ 988 pp = lp->d_partitions; 989 for (i = 0; i < lp->d_npartitions; i++, pp++) { 990 if (pp->p_size) { 991 char c = 'a' + i; 992 (void) fprintf(f, "\\\n\t:"); 993 (void) fprintf(f, "p%c#%d:", c, pp->p_size); 994 (void) fprintf(f, "o%c#%d:", c, pp->p_offset); 995 if (pp->p_fstype != FS_UNUSED) { 996 if ((unsigned) pp->p_fstype < FSMAXTYPES) 997 (void) fprintf(f, "t%c=%s:", c, 998 fstypenames[pp->p_fstype]); 999 else 1000 (void) fprintf(f, "t%c=unknown%d:", 1001 c, pp->p_fstype); 1002 } 1003 switch (pp->p_fstype) { 1004 1005 case FS_UNUSED: 1006 break; 1007 1008 case FS_BSDFFS: 1009 case FS_BSDLFS: 1010 case FS_EX2FS: 1011 case FS_ADOS: 1012 case FS_APPLEUFS: 1013 (void) fprintf(f, "b%c#%d:", c, 1014 pp->p_fsize * pp->p_frag); 1015 (void) fprintf(f, "f%c#%d:", c, pp->p_fsize); 1016 break; 1017 default: 1018 break; 1019 } 1020 } 1021 } 1022 (void) fprintf(f, "\n"); 1023 (void) fflush(f); 1024 } 1025 1026 static int 1027 edit(struct disklabel *lp, int f) 1028 { 1029 struct disklabel label; 1030 const char *tmpdir; 1031 int first, ch, fd; 1032 FILE *fp; 1033 1034 if ((tmpdir = getenv("TMPDIR")) == NULL) 1035 tmpdir = _PATH_TMP; 1036 (void)snprintf(tmpfil, sizeof(tmpfil), "%s/%s", tmpdir, TMPFILE); 1037 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 1038 warn("%s", tmpfil); 1039 return (1); 1040 } 1041 (void)fchmod(fd, 0600); 1042 showinfo(fp, lp, specname); 1043 showpartitions(fp, lp, Cflag); 1044 (void) fclose(fp); 1045 for (;;) { 1046 if (!editit()) 1047 break; 1048 fp = fopen(tmpfil, "r"); 1049 if (fp == NULL) { 1050 warn("%s", tmpfil); 1051 break; 1052 } 1053 (void) memset(&label, 0, sizeof(label)); 1054 if (getasciilabel(fp, &label)) { 1055 *lp = label; 1056 if (writelabel(f, bootarea, lp) == 0) { 1057 (void) unlink(tmpfil); 1058 return (0); 1059 } 1060 } 1061 (void) printf("re-edit the label? [y]: "); 1062 (void) fflush(stdout); 1063 first = ch = getchar(); 1064 while (ch != '\n' && ch != EOF) 1065 ch = getchar(); 1066 if (first == 'n' || first == 'N') 1067 break; 1068 } 1069 (void)unlink(tmpfil); 1070 return (1); 1071 } 1072 1073 static int 1074 editit(void) 1075 { 1076 int pid, xpid; 1077 int status; 1078 sigset_t nsigset, osigset; 1079 1080 sigemptyset(&nsigset); 1081 sigaddset(&nsigset, SIGINT); 1082 sigaddset(&nsigset, SIGQUIT); 1083 sigaddset(&nsigset, SIGHUP); 1084 sigprocmask(SIG_BLOCK, &nsigset, &osigset); 1085 while ((pid = fork()) < 0) { 1086 if (errno != EAGAIN) { 1087 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1088 warn("fork"); 1089 return (0); 1090 } 1091 sleep(1); 1092 } 1093 if (pid == 0) { 1094 const char *ed; 1095 char *buf; 1096 int retval; 1097 1098 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1099 setgid(getgid()); 1100 setuid(getuid()); 1101 if ((ed = getenv("EDITOR")) == (char *)0) 1102 ed = DEFEDITOR; 1103 /* 1104 * Jump through a few extra hoops in case someone's editor 1105 * is "editor arg1 arg2". 1106 */ 1107 asprintf(&buf, "%s %s", ed, tmpfil); 1108 if (!buf) 1109 err(1, "malloc"); 1110 retval = execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", buf, NULL); 1111 if (retval == -1) 1112 perror(ed); 1113 exit(retval); 1114 } 1115 while ((xpid = wait(&status)) >= 0) 1116 if (xpid == pid) 1117 break; 1118 sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); 1119 return (!status); 1120 } 1121 1122 static char * 1123 skip(char *cp) 1124 { 1125 1126 cp += strspn(cp, " \t"); 1127 if (*cp == '\0') 1128 return (NULL); 1129 return (cp); 1130 } 1131 1132 static char * 1133 word(char *cp) 1134 { 1135 1136 if (cp == NULL || *cp == '\0') 1137 return (NULL); 1138 1139 cp += strcspn(cp, " \t"); 1140 if (*cp == '\0') 1141 return (NULL); 1142 *cp++ = '\0'; 1143 cp += strspn(cp, " \t"); 1144 if (*cp == '\0') 1145 return (NULL); 1146 return (cp); 1147 } 1148 1149 #define _CHECKLINE \ 1150 if (tp == NULL || *tp == '\0') { \ 1151 warnx("line %d: too few fields", lineno); \ 1152 errors++; \ 1153 break; \ 1154 } 1155 1156 #define __CHECKLINE \ 1157 if (*tp == NULL || **tp == '\0') { \ 1158 warnx("line %d: too few fields", lineno); \ 1159 *tp = _error_; \ 1160 return 0; \ 1161 } 1162 1163 static char _error_[] = ""; 1164 #define NXTNUM(n) if ((n = nxtnum(&tp, lineno),0) + tp != _error_) \ 1165 ; else goto error 1166 #define NXTXNUM(n) if ((n = nxtxnum(&tp, lp, lineno),0) + tp != _error_) \ 1167 ; else goto error 1168 1169 static unsigned long 1170 nxtnum(char **tp, int lineno) 1171 { 1172 char *cp; 1173 unsigned long v; 1174 1175 __CHECKLINE 1176 if (getulong(*tp, '\0', &cp, &v, UINT32_MAX) != 0) { 1177 warnx("line %d: syntax error", lineno); 1178 *tp = _error_; 1179 return 0; 1180 } 1181 *tp = cp; 1182 return v; 1183 } 1184 1185 static unsigned long 1186 nxtxnum(char **tp, struct disklabel *lp, int lineno) 1187 { 1188 char *cp, *ncp; 1189 unsigned long n, v; 1190 1191 __CHECKLINE 1192 cp = *tp; 1193 if (getulong(cp, '/', &ncp, &n, UINT32_MAX) != 0) 1194 goto bad; 1195 1196 if (*ncp == '/') { 1197 n *= lp->d_secpercyl; 1198 cp = ncp + 1; 1199 if (getulong(cp, '/', &ncp, &v, UINT32_MAX) != 0) 1200 goto bad; 1201 n += v * lp->d_nsectors; 1202 cp = ncp + 1; 1203 if (getulong(cp, '\0', &ncp, &v, UINT32_MAX) != 0) 1204 goto bad; 1205 n += v; 1206 } 1207 *tp = ncp; 1208 return n; 1209 bad: 1210 warnx("line %d: invalid format", lineno); 1211 *tp = _error_; 1212 return 0; 1213 } 1214 1215 /* 1216 * Read an ascii label in from fd f, 1217 * in the same format as that put out by showinfo() and showpartitions(), 1218 * and fill in lp. 1219 */ 1220 static int 1221 getasciilabel(FILE *f, struct disklabel *lp) 1222 { 1223 const char *const *cpp, *s; 1224 struct partition *pp; 1225 char *cp, *tp, line[BUFSIZ], tbuf[15]; 1226 int lineno, errors; 1227 unsigned long v; 1228 unsigned int part; 1229 1230 lineno = 0; 1231 errors = 0; 1232 lp->d_bbsize = BBSIZE; /* XXX */ 1233 lp->d_sbsize = SBLOCKSIZE; /* XXX */ 1234 while (fgets(line, sizeof(line) - 1, f)) { 1235 lineno++; 1236 if ((cp = strpbrk(line, "#\r\n")) != NULL) 1237 *cp = '\0'; 1238 cp = skip(line); 1239 if (cp == NULL) /* blank line or comment line */ 1240 continue; 1241 tp = strchr(cp, ':'); /* everything has a colon in it */ 1242 if (tp == NULL) { 1243 warnx("line %d: syntax error", lineno); 1244 errors++; 1245 continue; 1246 } 1247 *tp++ = '\0', tp = skip(tp); 1248 if (!strcmp(cp, "type")) { 1249 if (tp == NULL) { 1250 strlcpy(tbuf, "unknown", sizeof(tbuf)); 1251 tp = tbuf; 1252 } 1253 cpp = dktypenames; 1254 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 1255 if ((s = *cpp) && !strcasecmp(s, tp)) { 1256 lp->d_type = cpp - dktypenames; 1257 goto next; 1258 } 1259 if (GETNUM16(tp, &v) != 0) { 1260 warnx("line %d: syntax error", lineno); 1261 errors++; 1262 continue; 1263 } 1264 if (v >= DKMAXTYPES) 1265 warnx("line %d: warning, unknown disk type: %s", 1266 lineno, tp); 1267 lp->d_type = v; 1268 continue; 1269 } 1270 if (!strcmp(cp, "flags")) { 1271 for (v = 0; (cp = tp) && *cp != '\0';) { 1272 tp = word(cp); 1273 if (!strcasecmp(cp, "removable")) 1274 v |= D_REMOVABLE; 1275 else if (!strcasecmp(cp, "ecc")) 1276 v |= D_ECC; 1277 else if (!strcasecmp(cp, "badsect")) 1278 v |= D_BADSECT; 1279 else { 1280 warnx("line %d: bad flag: %s", 1281 lineno, cp); 1282 errors++; 1283 } 1284 } 1285 lp->d_flags = v; 1286 continue; 1287 } 1288 if (!strcmp(cp, "drivedata")) { 1289 int i; 1290 1291 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 1292 if (GETNUM32(cp, &v) != 0) { 1293 warnx("line %d: bad drive data", 1294 lineno); 1295 errors++; 1296 } else 1297 lp->d_drivedata[i] = v; 1298 i++; 1299 tp = word(cp); 1300 } 1301 continue; 1302 } 1303 if (sscanf(cp, "%lu partitions", &v) == 1) { 1304 if (v == 0 || v > MAXPARTITIONS) { 1305 warnx("line %d: bad # of partitions", lineno); 1306 lp->d_npartitions = MAXPARTITIONS; 1307 errors++; 1308 } else 1309 lp->d_npartitions = v; 1310 continue; 1311 } 1312 if (tp == NULL) { 1313 tbuf[0] = '\0'; 1314 tp = tbuf; 1315 } 1316 if (!strcmp(cp, "disk")) { 1317 strncpy(lp->d_typename, tp, sizeof(lp->d_typename)); 1318 continue; 1319 } 1320 if (!strcmp(cp, "label")) { 1321 strncpy(lp->d_packname, tp, sizeof(lp->d_packname)); 1322 continue; 1323 } 1324 if (!strcmp(cp, "bytes/sector")) { 1325 if (GETNUM32(tp, &v) != 0 || v <= 0 || (v % 512) != 0) { 1326 warnx("line %d: bad %s: %s", lineno, cp, tp); 1327 errors++; 1328 } else 1329 lp->d_secsize = v; 1330 continue; 1331 } 1332 if (!strcmp(cp, "sectors/track")) { 1333 if (GETNUM32(tp, &v) != 0) { 1334 warnx("line %d: bad %s: %s", lineno, cp, tp); 1335 errors++; 1336 } else 1337 lp->d_nsectors = v; 1338 continue; 1339 } 1340 if (!strcmp(cp, "sectors/cylinder")) { 1341 if (GETNUM32(tp, &v) != 0) { 1342 warnx("line %d: bad %s: %s", lineno, cp, tp); 1343 errors++; 1344 } else 1345 lp->d_secpercyl = v; 1346 continue; 1347 } 1348 if (!strcmp(cp, "tracks/cylinder")) { 1349 if (GETNUM32(tp, &v) != 0) { 1350 warnx("line %d: bad %s: %s", lineno, cp, tp); 1351 errors++; 1352 } else 1353 lp->d_ntracks = v; 1354 continue; 1355 } 1356 if (!strcmp(cp, "cylinders")) { 1357 if (GETNUM32(tp, &v) != 0) { 1358 warnx("line %d: bad %s: %s", lineno, cp, tp); 1359 errors++; 1360 } else 1361 lp->d_ncylinders = v; 1362 continue; 1363 } 1364 if (!strcmp(cp, "total sectors")) { 1365 if (GETNUM32(tp, &v) != 0) { 1366 warnx("line %d: bad %s: %s", lineno, cp, tp); 1367 errors++; 1368 } else 1369 lp->d_secperunit = v; 1370 continue; 1371 } 1372 if (!strcmp(cp, "rpm")) { 1373 if (GETNUM16(tp, &v) != 0) { 1374 warnx("line %d: bad %s: %s", lineno, cp, tp); 1375 errors++; 1376 } else 1377 lp->d_rpm = v; 1378 continue; 1379 } 1380 if (!strcmp(cp, "interleave")) { 1381 if (GETNUM16(tp, &v) != 0) { 1382 warnx("line %d: bad %s: %s", lineno, cp, tp); 1383 errors++; 1384 } else 1385 lp->d_interleave = v; 1386 continue; 1387 } 1388 if (!strcmp(cp, "trackskew")) { 1389 if (GETNUM16(tp, &v) != 0) { 1390 warnx("line %d: bad %s: %s", lineno, cp, tp); 1391 errors++; 1392 } else 1393 lp->d_trackskew = v; 1394 continue; 1395 } 1396 if (!strcmp(cp, "cylinderskew")) { 1397 if (GETNUM16(tp, &v) != 0) { 1398 warnx("line %d: bad %s: %s", lineno, cp, tp); 1399 errors++; 1400 } else 1401 lp->d_cylskew = v; 1402 continue; 1403 } 1404 if (!strcmp(cp, "headswitch")) { 1405 if (GETNUM32(tp, &v) != 0) { 1406 warnx("line %d: bad %s: %s", lineno, cp, tp); 1407 errors++; 1408 } else 1409 lp->d_headswitch = v; 1410 continue; 1411 } 1412 if (!strcmp(cp, "track-to-track seek")) { 1413 if (GETNUM32(tp, &v) != 0) { 1414 warnx("line %d: bad %s: %s", lineno, cp, tp); 1415 errors++; 1416 } else 1417 lp->d_trkseek = v; 1418 continue; 1419 } 1420 if ('a' > *cp || *cp > 'z' || cp[1] != '\0') { 1421 warnx("line %d: unknown field: %s", lineno, cp); 1422 errors++; 1423 continue; 1424 } 1425 1426 /* We have a partition entry */ 1427 part = *cp - 'a'; 1428 1429 if (part >= MAXPARTITIONS) { 1430 warnx("line %d: bad partition name: %s", lineno, cp); 1431 errors++; 1432 continue; 1433 } 1434 pp = &lp->d_partitions[part]; 1435 1436 NXTXNUM(pp->p_size); 1437 NXTXNUM(pp->p_offset); 1438 /* can't use word() here because of blanks in fstypenames[] */ 1439 tp += strspn(tp, " \t"); 1440 _CHECKLINE 1441 cp = tp; 1442 cpp = fstypenames; 1443 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 1444 s = *cpp; 1445 if (s == NULL || 1446 (cp[strlen(s)] != ' ' && 1447 cp[strlen(s)] != '\t' && 1448 cp[strlen(s)] != '\0')) 1449 continue; 1450 if (!memcmp(s, cp, strlen(s))) { 1451 pp->p_fstype = cpp - fstypenames; 1452 tp += strlen(s); 1453 if (*tp == '\0') 1454 tp = NULL; 1455 else { 1456 tp += strspn(tp, " \t"); 1457 if (*tp == '\0') 1458 tp = NULL; 1459 } 1460 goto gottype; 1461 } 1462 } 1463 tp = word(cp); 1464 if (isdigit(*cp & 0xff)) { 1465 if (GETNUM8(cp, &v) != 0) { 1466 warnx("line %d: syntax error", lineno); 1467 errors++; 1468 } 1469 } else 1470 v = FSMAXTYPES; 1471 if ((unsigned)v >= FSMAXTYPES) { 1472 warnx("line %d: warning, unknown filesystem type: %s", 1473 lineno, cp); 1474 v = FS_UNUSED; 1475 } 1476 pp->p_fstype = v; 1477 gottype: 1478 switch (pp->p_fstype) { 1479 1480 case FS_UNUSED: /* XXX */ 1481 NXTNUM(pp->p_fsize); 1482 if (pp->p_fsize == 0) 1483 break; 1484 NXTNUM(v); 1485 pp->p_frag = v / pp->p_fsize; 1486 break; 1487 1488 case FS_BSDFFS: 1489 case FS_ADOS: 1490 case FS_APPLEUFS: 1491 NXTNUM(pp->p_fsize); 1492 if (pp->p_fsize == 0) 1493 break; 1494 NXTNUM(v); 1495 pp->p_frag = v / pp->p_fsize; 1496 NXTNUM(pp->p_cpg); 1497 break; 1498 case FS_BSDLFS: 1499 NXTNUM(pp->p_fsize); 1500 if (pp->p_fsize == 0) 1501 break; 1502 NXTNUM(v); 1503 pp->p_frag = v / pp->p_fsize; 1504 NXTNUM(pp->p_sgs); 1505 break; 1506 case FS_EX2FS: 1507 NXTNUM(pp->p_fsize); 1508 if (pp->p_fsize == 0) 1509 break; 1510 NXTNUM(v); 1511 pp->p_frag = v / pp->p_fsize; 1512 break; 1513 case FS_ISO9660: 1514 NXTNUM(pp->p_cdsession); 1515 break; 1516 default: 1517 break; 1518 } 1519 continue; 1520 error: 1521 errors++; 1522 next: 1523 ; 1524 } 1525 errors += checklabel(lp); 1526 return (errors == 0); 1527 } 1528 1529 /* 1530 * Check disklabel for errors and fill in 1531 * derived fields according to supplied values. 1532 */ 1533 int 1534 checklabel(struct disklabel *lp) 1535 { 1536 struct partition *pp, *qp; 1537 int i, j, errors; 1538 char part; 1539 1540 errors = 0; 1541 if (lp->d_secsize == 0) { 1542 warnx("sector size %d", lp->d_secsize); 1543 return (1); 1544 } 1545 if (lp->d_nsectors == 0) { 1546 warnx("sectors/track %d", lp->d_nsectors); 1547 return (1); 1548 } 1549 if (lp->d_ntracks == 0) { 1550 warnx("tracks/cylinder %d", lp->d_ntracks); 1551 return (1); 1552 } 1553 if (lp->d_ncylinders == 0) { 1554 warnx("cylinders/unit %d", lp->d_ncylinders); 1555 errors++; 1556 } 1557 if (lp->d_rpm == 0) 1558 warnx("warning, revolutions/minute %d", lp->d_rpm); 1559 if (lp->d_secpercyl == 0) 1560 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1561 if (lp->d_secperunit == 0) 1562 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1563 #ifdef __i386__notyet__ 1564 if (dosdp && lp->d_secperunit > dosdp->mbrp_start + dosdp->mbrp_size) { 1565 warnx("exceeds DOS partition size"); 1566 errors++; 1567 lp->d_secperunit = dosdp->mbrp_start + dosdp->mbrp_size; 1568 } 1569 /* XXX should also check geometry against BIOS's idea */ 1570 #endif /* __i386__notyet__ */ 1571 #ifdef __arm32__notyet__ 1572 /* XXX similar code as for i386 */ 1573 #endif /* __arm32__notyet__ */ 1574 if (lp->d_bbsize == 0) { 1575 warnx("boot block size %d", lp->d_bbsize); 1576 errors++; 1577 } else if (lp->d_bbsize % lp->d_secsize) 1578 warnx("warning, boot block size %% sector-size != 0"); 1579 if (lp->d_sbsize == 0) { 1580 warnx("super block size %d", lp->d_sbsize); 1581 errors++; 1582 } else if (lp->d_sbsize % lp->d_secsize) 1583 warnx("warning, super block size %% sector-size != 0"); 1584 if (lp->d_npartitions > MAXPARTITIONS) 1585 warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", 1586 lp->d_npartitions, MAXPARTITIONS); 1587 else 1588 for (i = MAXPARTITIONS - 1; i >= lp->d_npartitions; i--) { 1589 part = 'a' + i; 1590 pp = &lp->d_partitions[i]; 1591 if (pp->p_size || pp->p_offset) { 1592 warnx("warning, partition %c increased " 1593 "number of partitions from %d to %d", 1594 part, lp->d_npartitions, i + 1); 1595 lp->d_npartitions = i + 1; 1596 break; 1597 } 1598 } 1599 for (i = 0; i < lp->d_npartitions; i++) { 1600 part = 'a' + i; 1601 pp = &lp->d_partitions[i]; 1602 if (pp->p_size == 0 && pp->p_offset != 0) 1603 warnx("warning, partition %c: size 0, but offset %d", 1604 part, pp->p_offset); 1605 #ifdef STRICT_CYLINDER_ALIGNMENT 1606 if (pp->p_offset % lp->d_secpercyl) { 1607 warnx("warning, partition %c:" 1608 " not starting on cylinder boundary", 1609 part); 1610 errors++; 1611 } 1612 #endif /* STRICT_CYLINDER_ALIGNMENT */ 1613 if (pp->p_offset > lp->d_secperunit) { 1614 warnx("partition %c: offset past end of unit", part); 1615 errors++; 1616 } 1617 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1618 warnx("partition %c: partition extends" 1619 " past end of unit", 1620 part); 1621 errors++; 1622 } 1623 if (pp->p_fstype != FS_UNUSED) 1624 for (j = i + 1; j < lp->d_npartitions; j++) { 1625 qp = &lp->d_partitions[j]; 1626 if (qp->p_fstype == FS_UNUSED) 1627 continue; 1628 if (pp->p_offset < qp->p_offset + qp->p_size && 1629 qp->p_offset < pp->p_offset + pp->p_size) 1630 warnx("partitions %c and %c overlap", 1631 part, 'a' + j); 1632 } 1633 } 1634 return (errors); 1635 } 1636 1637 static void 1638 usage(void) 1639 { 1640 static const struct { 1641 const char *name; 1642 const char *expn; 1643 } usages[] = { 1644 { "[-CFrt] disk", "(to read label)" }, 1645 { "-w [-Fr] [-f disktab] disk disktype [packid]", "(to write label)" }, 1646 { "-e [-CFIr] disk", "(to edit label)" }, 1647 { "-i [-FIr] disk", "(to create a label interactively)" }, 1648 { "-R [-Fr] disk protofile", "(to restore label)" }, 1649 { "[-NW] disk", "(to write disable/enable label)" }, 1650 { NULL, NULL } 1651 }; 1652 int i; 1653 const char *pn = getprogname(); 1654 const char *t = "usage:"; 1655 1656 for (i = 0; usages[i].name != NULL; i++) { 1657 (void)fprintf(stderr, "%s %s %s\n\t%s\n", 1658 t, pn, usages[i].name, usages[i].expn); 1659 t = "or"; 1660 } 1661 exit(1); 1662 } 1663 1664 static int 1665 getulong(const char *str, char sep, char **epp, unsigned long *ul, 1666 unsigned long max) 1667 { 1668 char *ep; 1669 1670 if (epp == NULL) 1671 epp = &ep; 1672 1673 *ul = strtoul(str, epp, 10); 1674 1675 if ((*ul == ULONG_MAX && errno == ERANGE) || *ul > max) 1676 return ERANGE; 1677 1678 if (*str == '\0' || (**epp != '\0' && **epp != sep && 1679 !isspace((unsigned char)**epp))) 1680 return EFTYPE; 1681 1682 return 0; 1683 } 1684