1 /* $OpenBSD: disklabel.c,v 1.136 2008/08/11 19:03:05 reyk 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 #ifndef lint 36 static const char copyright[] = 37 "@(#) Copyright (c) 1987, 1993\n\ 38 The Regents of the University of California. All rights reserved.\n"; 39 #endif /* not lint */ 40 41 #ifndef lint 42 static const char rcsid[] = "$OpenBSD: disklabel.c,v 1.136 2008/08/11 19:03:05 reyk Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/ioctl.h> 47 #include <sys/stat.h> 48 #include <sys/wait.h> 49 #define DKTYPENAMES 50 #include <sys/disklabel.h> 51 52 #include <ufs/ffs/fs.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <limits.h> 59 #include <signal.h> 60 #include <string.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <unistd.h> 64 #include <util.h> 65 #include "pathnames.h" 66 #include "extern.h" 67 68 /* 69 * Disklabel: read and write disklabels. 70 * The label is usually placed on one of the first sectors of the disk. 71 * Many machines also place a bootstrap in the same area, 72 * in which case the label is embedded in the bootstrap. 73 * The bootstrap source must leave space at the proper offset 74 * for the label on such machines. 75 */ 76 77 #ifndef BBSIZE 78 #define BBSIZE 8192 /* size of boot area, with label */ 79 #endif 80 81 #ifndef NUMBOOT 82 #define NUMBOOT 0 83 #endif 84 85 char *dkname, *specname; 86 char tmpfil[] = _PATH_TMPFILE; 87 char namebuf[BBSIZE], *np = namebuf; 88 struct disklabel lab; 89 char bootarea[BBSIZE]; 90 91 #if NUMBOOT > 0 92 int installboot; /* non-zero if we should install a boot program */ 93 char *bootbuf; /* pointer to buffer with remainder of boot prog */ 94 int bootsize; /* size of remaining boot program */ 95 char *xxboot; /* primary boot */ 96 char *bootxx; /* secondary boot */ 97 char boot0[MAXPATHLEN]; 98 void setbootflag(struct disklabel *); 99 #if NUMBOOT > 1 100 char boot1[MAXPATHLEN]; 101 #endif 102 #endif 103 104 enum { 105 UNSPEC, EDIT, EDITOR, READ, RESTORE, SETWRITEABLE, WRITE, WRITEBOOT 106 } op = UNSPEC; 107 108 int cflag; 109 int dflag; 110 int tflag; 111 int verbose; 112 int donothing; 113 114 #ifdef DOSLABEL 115 struct dos_partition *dosdp; /* DOS partition, if found */ 116 struct dos_partition *findopenbsd(int, off_t, struct dos_partition **, int *); 117 struct dos_partition *readmbr(int); 118 #endif 119 120 void makedisktab(FILE *, struct disklabel *); 121 void makelabel(char *, char *, struct disklabel *); 122 int writelabel(int, char *, struct disklabel *); 123 void l_perror(char *); 124 int edit(struct disklabel *, int); 125 int editit(const char *); 126 char *skip(char *); 127 char *word(char *); 128 int getasciilabel(FILE *, struct disklabel *); 129 int cmplabel(struct disklabel *, struct disklabel *); 130 void usage(void); 131 u_int64_t getnum(char *, u_int64_t, u_int64_t, const char **); 132 133 int 134 main(int argc, char *argv[]) 135 { 136 int ch, f, writeable, error = 0; 137 char *fstabfile = NULL; 138 struct disklabel *lp; 139 char print_unit = 0; 140 FILE *t; 141 142 while ((ch = getopt(argc, argv, "BEf:NRWb:cdenp:s:tvw")) != -1) 143 switch (ch) { 144 #if NUMBOOT > 0 145 case 'B': 146 ++installboot; 147 break; 148 case 'b': 149 xxboot = optarg; 150 break; 151 #if NUMBOOT > 1 152 case 's': 153 bootxx = optarg; 154 break; 155 #endif 156 #endif 157 case 'N': 158 if (op != UNSPEC) 159 usage(); 160 writeable = 0; 161 op = SETWRITEABLE; 162 break; 163 case 'R': 164 if (op != UNSPEC) 165 usage(); 166 op = RESTORE; 167 break; 168 case 'W': 169 if (op != UNSPEC) 170 usage(); 171 writeable = 1; 172 op = SETWRITEABLE; 173 break; 174 case 'c': 175 ++cflag; 176 break; 177 case 'd': 178 ++dflag; 179 break; 180 case 'e': 181 if (op != UNSPEC) 182 usage(); 183 op = EDIT; 184 break; 185 case 'E': 186 if (op != UNSPEC) 187 usage(); 188 op = EDITOR; 189 break; 190 case 'f': 191 fstabfile = optarg; 192 break; 193 case 't': 194 ++tflag; 195 break; 196 case 'w': 197 if (op != UNSPEC) 198 usage(); 199 op = WRITE; 200 break; 201 case 'p': 202 if (strchr("bckmgt", optarg[0]) == NULL || 203 optarg[1] != '\0') 204 usage(); 205 print_unit = optarg[0]; 206 break; 207 case 'n': 208 donothing++; 209 break; 210 case 'v': 211 verbose++; 212 break; 213 case '?': 214 default: 215 usage(); 216 } 217 argc -= optind; 218 argv += optind; 219 220 #if NUMBOOT > 0 221 if (installboot) { 222 if (op == UNSPEC) 223 op = WRITEBOOT; 224 } else { 225 if (op == UNSPEC) 226 op = READ; 227 } 228 #else 229 if (op == UNSPEC) 230 op = READ; 231 #endif 232 233 if (argc < 1 || (fstabfile && op != EDITOR)) 234 usage(); 235 236 dkname = argv[0]; 237 f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART, 238 &specname); 239 if (f < 0) 240 err(4, "%s", specname); 241 242 #ifdef DOSLABEL 243 /* 244 * Check for presence of DOS partition table in 245 * master boot record. Return pointer to OpenBSD 246 * partition, if present. If no valid partition table, 247 * return NULL. If valid partition table present, but no 248 * partition to use, return a pointer to a non-386bsd 249 * partition. 250 */ 251 dosdp = readmbr(f); 252 #endif 253 254 switch (op) { 255 case EDIT: 256 if (argc != 1) 257 usage(); 258 if ((lp = readlabel(f)) == NULL) 259 exit(1); 260 error = edit(lp, f); 261 break; 262 case EDITOR: 263 if (argc != 1) 264 usage(); 265 if ((lp = readlabel(f)) == NULL) 266 exit(1); 267 error = editor(lp, f, specname, fstabfile); 268 break; 269 case READ: 270 if (argc != 1) 271 usage(); 272 if ((lp = readlabel(f)) == NULL) 273 exit(1); 274 if (tflag) 275 makedisktab(stdout, lp); 276 else 277 display(stdout, lp, NULL, print_unit, 1); 278 error = checklabel(lp); 279 break; 280 case RESTORE: 281 if (argc < 2 || argc > 3) 282 usage(); 283 #if NUMBOOT > 0 284 if (installboot && argc == 3) 285 makelabel(argv[2], NULL, &lab); 286 #endif 287 lp = makebootarea(bootarea, &lab, f); 288 if (!(t = fopen(argv[1], "r"))) 289 err(4, "%s", argv[1]); 290 if (getasciilabel(t, lp)) 291 error = writelabel(f, bootarea, lp); 292 else 293 error = 1; 294 fclose(t); 295 break; 296 case SETWRITEABLE: 297 if (!donothing) { 298 if (ioctl(f, DIOCWLABEL, (char *)&writeable) < 0) 299 err(4, "ioctl DIOCWLABEL"); 300 } 301 break; 302 case WRITE: 303 if (dflag) { 304 if (readlabel(f) == NULL) 305 exit(1); 306 } else if (argc < 2 || argc > 3) 307 usage(); 308 else 309 makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab); 310 lp = makebootarea(bootarea, &lab, f); 311 *lp = lab; 312 if (checklabel(lp) == 0) 313 error = writelabel(f, bootarea, lp); 314 break; 315 #if NUMBOOT > 0 316 case WRITEBOOT: 317 { 318 struct disklabel tlab; 319 320 if ((lp = readlabel(f)) == NULL) 321 exit(1); 322 tlab = *lp; 323 if (argc == 2) 324 makelabel(argv[1], NULL, &lab); 325 lp = makebootarea(bootarea, &lab, f); 326 *lp = tlab; 327 if (checklabel(lp) == 0) 328 error = writelabel(f, bootarea, lp); 329 break; 330 } 331 #endif 332 default: 333 break; 334 } 335 exit(error); 336 } 337 338 /* 339 * Construct a prototype disklabel from /etc/disktab. As a side 340 * effect, set the names of the primary and secondary boot files 341 * if specified. 342 */ 343 void 344 makelabel(char *type, char *name, struct disklabel *lp) 345 { 346 struct disklabel *dp; 347 348 dp = getdiskbyname(type); 349 if (dp == NULL) 350 errx(1, "unknown disk type: %s", type); 351 *lp = *dp; 352 #if NUMBOOT > 0 353 /* 354 * Set bootstrap name(s). 355 * 1. If set from command line, use those, 356 * 2. otherwise, check if disktab specifies them (b0 or b1), 357 * 3. otherwise, makebootarea() will choose ones based on the name 358 * of the disk special file. E.g. /dev/ra0 -> raboot, bootra 359 */ 360 if (!xxboot && lp->d_boot0) { 361 if (*lp->d_boot0 != '/') 362 (void)snprintf(boot0, sizeof boot0, "%s%s", 363 _PATH_BOOTDIR, lp->d_boot0); 364 else 365 (void)strlcpy(boot0, lp->d_boot0, sizeof boot0); 366 xxboot = boot0; 367 } 368 #if NUMBOOT > 1 369 if (!bootxx && lp->d_boot1) { 370 if (*lp->d_boot1 != '/') 371 (void)snprintf(boot1, sizeof boot1, "%s%s", 372 _PATH_BOOTDIR, lp->d_boot1); 373 else 374 (void)strlcpy(boot1, lp->d_boot1, sizeof boot1); 375 bootxx = boot1; 376 } 377 #endif 378 #endif 379 /* d_packname is union d_boot[01], so zero */ 380 memset(lp->d_packname, 0, sizeof(lp->d_packname)); 381 if (name) 382 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 383 } 384 385 386 int 387 writelabel(int f, char *boot, struct disklabel *lp) 388 { 389 int writeable; 390 off_t sectoffset = 0; 391 392 #if NUMBOOT > 0 393 setbootflag(lp); 394 #endif 395 lp->d_magic = DISKMAGIC; 396 lp->d_magic2 = DISKMAGIC; 397 lp->d_checksum = 0; 398 lp->d_checksum = dkcksum(lp); 399 #if NUMBOOT > 0 400 if (installboot) { 401 #ifdef DOSLABEL 402 struct partition *pp = &lp->d_partitions[2]; 403 404 /* 405 * If OpenBSD DOS partition is missing, or if 406 * the label to be written is not within partition, 407 * prompt first. Need to allow this in case operator 408 * wants to convert the drive for dedicated use. 409 * In this case, partition 'a' had better start at 0, 410 * otherwise we reject the request as meaningless. -wfj 411 */ 412 if (dosdp && DL_GETPSIZE(pp) && (dosdp->dp_typ == DOSPTYP_OPENBSD)) { 413 sectoffset = (off_t)letoh32(dosdp->dp_start) * 414 lp->d_secsize; 415 } else { 416 if (dosdp) { 417 int first, ch; 418 419 printf("Erase the previous contents of the disk? [n]: "); 420 fflush(stdout); 421 first = ch = getchar(); 422 while (ch != '\n' && ch != EOF) 423 ch = getchar(); 424 if (first != 'y' && first != 'Y') 425 exit(0); 426 } 427 sectoffset = 0; 428 } 429 #endif 430 /* 431 * First set the kernel disk label, 432 * then write a label to the raw disk. 433 * If the SDINFO ioctl fails because it is unimplemented, 434 * keep going; otherwise, the kernel consistency checks 435 * may prevent us from changing the current (in-core) 436 * label. 437 */ 438 if (!donothing) { 439 if (ioctl(f, DIOCSDINFO, lp) < 0 && 440 errno != ENODEV && errno != ENOTTY) { 441 l_perror("ioctl DIOCSDINFO"); 442 return (1); 443 } 444 } 445 if (verbose) 446 printf("writing label to block %lld (0x%qx)\n", 447 (long long)sectoffset/DEV_BSIZE, 448 (long long)sectoffset/DEV_BSIZE); 449 if (!donothing) { 450 if (lseek(f, sectoffset, SEEK_SET) < 0) { 451 perror("lseek"); 452 return (1); 453 } 454 /* 455 * write enable label sector before write (if necessary), 456 * disable after writing. 457 */ 458 writeable = 1; 459 460 if (ioctl(f, DIOCWLABEL, &writeable) < 0) 461 perror("ioctl DIOCWLABEL"); 462 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { 463 perror("write"); 464 return (1); 465 } 466 } 467 /* 468 * Output the remainder of the disklabel 469 */ 470 if (!donothing && bootbuf && write(f, bootbuf, bootsize) != bootsize) { 471 perror("write"); 472 return(1); 473 } 474 writeable = 0; 475 if (!donothing) 476 if (ioctl(f, DIOCWLABEL, &writeable) < 0) 477 perror("ioctl DIOCWLABEL"); 478 } else 479 #endif /* NUMBOOT > 0 */ 480 if (!donothing) { 481 if (ioctl(f, DIOCWDINFO, lp) < 0) { 482 l_perror("ioctl DIOCWDINFO"); 483 return (1); 484 } 485 } 486 #ifdef __vax__ 487 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 488 off_t alt; 489 int i; 490 491 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 492 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 493 (void)lseek(f, (alt + i) * lp->d_secsize, SEEK_SET); 494 if (!donothing) 495 if (write(f, boot, lp->d_secsize) != lp->d_secsize) 496 warn("alternate label %d write", i/2); 497 } 498 } 499 #endif 500 return (0); 501 } 502 503 void 504 l_perror(char *s) 505 { 506 507 switch (errno) { 508 case ESRCH: 509 warnx("%s: No disk label on disk", s); 510 break; 511 case EINVAL: 512 warnx("%s: Label magic number or checksum is wrong!\n" 513 "(disklabel or kernel is out of date?)", s); 514 break; 515 case EBUSY: 516 warnx("%s: Open partition would move or shrink", s); 517 break; 518 case EXDEV: 519 warnx("%s: Labeled partition or 'a' partition must start " 520 "at beginning of disk", s); 521 break; 522 default: 523 warn("%s", s); 524 break; 525 } 526 } 527 528 #ifdef DOSLABEL 529 struct dos_partition * 530 findopenbsd(int f, off_t mbroff, struct dos_partition **first, int *n) 531 { 532 static struct dos_partition res; 533 int mbr[DEV_BSIZE / sizeof(int)]; 534 struct dos_partition *dp, *p; 535 u_int16_t signature; 536 u_int32_t start = 0; 537 int part; 538 539 /* Limit the number of recursions */ 540 if (!(*n)--) 541 return (NULL); 542 543 /* 544 * This must be done this way due to alignment restrictions 545 * in for example mips processors. 546 */ 547 dp = (struct dos_partition *)mbr; 548 if (lseek(f, (off_t)mbroff * DEV_BSIZE, SEEK_SET) < 0 || 549 read(f, mbr, sizeof(mbr)) != sizeof(mbr)) 550 return (NULL); 551 signature = *((u_char *)mbr + DOSMBR_SIGNATURE_OFF) | 552 (*((u_char *)mbr + DOSMBR_SIGNATURE_OFF + 1) << 8); 553 bcopy((char *)mbr+DOSPARTOFF, (char *)mbr, sizeof(*dp) * NDOSPART); 554 555 /* 556 * If there is no signature and no OpenBSD partition this is probably 557 * not an MBR. 558 */ 559 if (signature != DOSMBR_SIGNATURE) 560 return (NULL); 561 562 /* 563 * Don't (yet) know disk geometry, use partition table to find OpenBSD 564 * partition, and obtain disklabel from there. 565 */ 566 /* Check if table is valid. */ 567 for (part = 0; part < NDOSPART; part++) { 568 if ((dp[part].dp_flag & ~0x80) != 0) 569 return (NULL); 570 } 571 /* Find OpenBSD partition. */ 572 for (part = 0; part < NDOSPART; part++) { 573 if (!letoh32(dp[part].dp_size)) 574 continue; 575 if (first && *first == NULL) { 576 bcopy(&dp[part], &res, sizeof(struct dos_partition)); 577 *first = &res; 578 } 579 switch (dp[part].dp_typ) { 580 case DOSPTYP_OPENBSD: 581 fprintf(stderr, "# Inside MBR partition %d: " 582 "type %02X start %u size %u\n", 583 part, dp[part].dp_typ, 584 letoh32(dp[part].dp_start), letoh32(dp[part].dp_size)); 585 bcopy(&dp[part], &res, sizeof(struct dos_partition)); 586 res.dp_start = 587 htole32((off_t)letoh32(res.dp_start) + mbroff); 588 return (&res); 589 case DOSPTYP_EXTEND: 590 case DOSPTYP_EXTENDL: 591 fprintf(stderr, "# Extended partition %d: " 592 "type %02X start %u size %u\n", 593 part, dp[part].dp_typ, 594 letoh32(dp[part].dp_start), letoh32(dp[part].dp_size)); 595 start = letoh32(dp[part].dp_start) + mbroff; 596 p = findopenbsd(f, start, NULL, n); 597 if (p != NULL) 598 return (p); 599 break; 600 } 601 } 602 603 return (NULL); 604 } 605 606 /* 607 * Fetch DOS partition table from disk. 608 */ 609 struct dos_partition * 610 readmbr(int f) 611 { 612 struct dos_partition *dp, *first = NULL; 613 int part, n = 8; 614 615 dp = findopenbsd(f, DOSBBSECTOR, &first, &n); 616 if (dp != NULL) 617 return (dp); 618 619 /* If no OpenBSD partition, find first used partition. */ 620 if (first != NULL) { 621 warnx("warning, DOS partition table with no valid OpenBSD partition"); 622 return (first); 623 } 624 625 /* Table appears to be empty. */ 626 return (NULL); 627 } 628 #endif 629 630 /* 631 * Fetch disklabel for disk using ioctl. 632 */ 633 struct disklabel * 634 readlabel(int f) 635 { 636 struct disklabel *lp = NULL; 637 638 if (cflag && ioctl(f, DIOCRLDINFO) < 0) 639 err(4, "ioctl DIOCRLDINFO"); 640 if (dflag) { 641 lp = &lab; 642 if (ioctl(f, DIOCGPDINFO, lp) < 0) 643 err(4, "ioctl DIOCGPDINFO"); 644 } else { 645 lp = &lab; 646 if (ioctl(f, DIOCGDINFO, lp) < 0) 647 err(4, "ioctl DIOCGDINFO"); 648 } 649 650 return (lp); 651 } 652 653 /* 654 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 655 * Returns a pointer to the disklabel portion of the bootarea. 656 */ 657 struct disklabel * 658 makebootarea(char *boot, struct disklabel *dp, int f) 659 { 660 struct disklabel *lp; 661 char *p; 662 #if NUMBOOT > 0 663 char *dkbasename; 664 int b; 665 #if NUMBOOT == 1 666 struct stat sb; 667 #endif 668 #endif 669 670 /* XXX */ 671 if (dp->d_secsize == 0) { 672 dp->d_secsize = DEV_BSIZE; 673 dp->d_bbsize = BBSIZE; 674 } 675 lp = (struct disklabel *) 676 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); 677 memset(lp, 0, sizeof *lp); 678 #if NUMBOOT > 0 679 /* 680 * If we are not installing a boot program but we are installing a 681 * label on disk then we must read the current bootarea so we don't 682 * clobber the existing boot. 683 */ 684 if (!installboot) 685 return (lp); 686 /* 687 * We are installing a boot program. Determine the name(s) and 688 * read them into the appropriate places in the boot area. 689 */ 690 if (!xxboot || !bootxx) { 691 dkbasename = np; 692 if ((p = strrchr(dkname, '/')) == NULL) 693 p = dkname; 694 else 695 p++; 696 while (*p && !isdigit(*p)) 697 *np++ = *p++; 698 *np++ = '\0'; 699 700 if (!xxboot) { 701 (void)snprintf(np, namebuf + sizeof namebuf - np, 702 "%s%sboot", _PATH_BOOTDIR, dkbasename); 703 if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 704 dkbasename++; 705 xxboot = np; 706 (void)snprintf(xxboot, 707 namebuf + sizeof namebuf - np, 708 "%s%sboot", _PATH_BOOTDIR, dkbasename); 709 np += strlen(xxboot) + 1; 710 } 711 #if NUMBOOT > 1 712 if (!bootxx) { 713 (void)snprintf(np, namebuf + sizeof namebuf - np, 714 "%sboot%s", _PATH_BOOTDIR, dkbasename); 715 if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 716 dkbasename++; 717 bootxx = np; 718 (void)snprintf(bootxx, namebuf + sizeof namebuf - bootxx, 719 "%sboot%s", _PATH_BOOTDIR, dkbasename); 720 np += strlen(bootxx) + 1; 721 } 722 #endif 723 } 724 if (verbose) 725 warnx("bootstraps: xxboot = %s, bootxx = %s", xxboot, 726 bootxx ? bootxx : "NONE"); 727 728 /* 729 * Strange rules: 730 * 1. One-piece bootstrap (hp300/hp800) 731 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest 732 * is remembered and written later following the bootarea. 733 * 2. Two-piece bootstraps (vax/i386?/mips?) 734 * up to d_secsize bytes of ``xxboot'' go in first d_secsize 735 * bytes of bootarea, remaining d_bbsize-d_secsize filled 736 * from ``bootxx''. 737 */ 738 b = open(xxboot, O_RDONLY); 739 if (b < 0) 740 err(4, "%s", xxboot); 741 #if NUMBOOT > 1 742 if (read(b, boot, (int)dp->d_secsize) < 0) 743 err(4, "%s", xxboot); 744 (void)close(b); 745 b = open(bootxx, O_RDONLY); 746 if (b < 0) 747 err(4, "%s", bootxx); 748 if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0) 749 err(4, "%s", bootxx); 750 #else 751 if (read(b, boot, (int)dp->d_bbsize) < 0) 752 err(4, "%s", xxboot); 753 (void)fstat(b, &sb); 754 bootsize = (int)sb.st_size - dp->d_bbsize; 755 if (bootsize > 0) { 756 /* XXX assume d_secsize is a power of two */ 757 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); 758 bootbuf = (char *)malloc((size_t)bootsize); 759 if (bootbuf == NULL) 760 err(4, "%s", xxboot); 761 if (read(b, bootbuf, bootsize) < 0) { 762 free(bootbuf); 763 err(4, "%s", xxboot); 764 } 765 } 766 #endif 767 (void)close(b); 768 #endif 769 /* 770 * Make sure no part of the bootstrap is written in the area 771 * reserved for the label. 772 */ 773 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 774 if (*p) 775 errx(2, "Bootstrap doesn't leave room for disk label"); 776 return (lp); 777 } 778 779 void 780 makedisktab(FILE *f, struct disklabel *lp) 781 { 782 int i; 783 char *did = "\\\n\t:"; 784 struct partition *pp; 785 786 if (lp->d_packname[0]) 787 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_packname), 788 lp->d_packname); 789 if (lp->d_typename[0]) 790 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_typename), 791 lp->d_typename); 792 (void)fputs("Automatically generated label:\\\n\t:dt=", f); 793 if ((unsigned) lp->d_type < DKMAXTYPES) 794 (void)fprintf(f, "%s:", dktypenames[lp->d_type]); 795 else 796 (void)fprintf(f, "unknown%d:", lp->d_type); 797 798 (void)fprintf(f, "se#%u:", lp->d_secsize); 799 (void)fprintf(f, "ns#%u:", lp->d_nsectors); 800 (void)fprintf(f, "nt#%u:", lp->d_ntracks); 801 (void)fprintf(f, "nc#%u:", lp->d_ncylinders); 802 (void)fprintf(f, "sc#%u:", lp->d_secpercyl); 803 (void)fprintf(f, "su#%llu:", DL_GETDSIZE(lp)); 804 805 if (lp->d_rpm != 3600) { 806 (void)fprintf(f, "%srm#%hu:", did, lp->d_rpm); 807 did = ""; 808 } 809 if (lp->d_interleave != 1) { 810 (void)fprintf(f, "%sil#%hu:", did, lp->d_interleave); 811 did = ""; 812 } 813 if (lp->d_trackskew != 0) { 814 (void)fprintf(f, "%ssk#%hu:", did, lp->d_trackskew); 815 did = ""; 816 } 817 if (lp->d_cylskew != 0) { 818 (void)fprintf(f, "%scs#%hu:", did, lp->d_cylskew); 819 did = ""; 820 } 821 if (lp->d_headswitch != 0) { 822 (void)fprintf(f, "%shs#%u:", did, lp->d_headswitch); 823 did = ""; 824 } 825 if (lp->d_trkseek != 0) { 826 (void)fprintf(f, "%sts#%u:", did, lp->d_trkseek); 827 did = ""; 828 } 829 for (i = 0; i < NDDATA; i++) 830 if (lp->d_drivedata[i]) 831 (void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]); 832 pp = lp->d_partitions; 833 for (i = 0; i < lp->d_npartitions; i++, pp++) { 834 if (DL_GETPSIZE(pp)) { 835 char c = 'a' + i; 836 837 (void)fprintf(f, "\\\n\t:"); 838 (void)fprintf(f, "p%c#%llu:", c, DL_GETPSIZE(pp)); 839 (void)fprintf(f, "o%c#%llu:", c, DL_GETPOFFSET(pp)); 840 if (pp->p_fstype != FS_UNUSED) { 841 if ((unsigned) pp->p_fstype < FSMAXTYPES) 842 (void)fprintf(f, "t%c=%s:", c, 843 fstypenames[pp->p_fstype]); 844 else 845 (void)fprintf(f, "t%c=unknown%d:", 846 c, pp->p_fstype); 847 } 848 switch (pp->p_fstype) { 849 850 case FS_UNUSED: 851 break; 852 853 case FS_BSDFFS: 854 (void)fprintf(f, "b%c#%u:", c, 855 DISKLABELV1_FFS_BSIZE(pp->p_fragblock)); 856 (void)fprintf(f, "f%c#%u:", c, 857 DISKLABELV1_FFS_FSIZE(pp->p_fragblock)); 858 break; 859 860 default: 861 break; 862 } 863 } 864 } 865 (void)fputc('\n', f); 866 (void)fflush(f); 867 } 868 869 double 870 scale(u_int64_t sz, char unit, struct disklabel *lp) 871 { 872 double fsz; 873 874 fsz = (double)sz * lp->d_secsize; 875 876 switch (unit) { 877 case 'B': 878 return fsz; 879 case 'C': 880 return fsz / lp->d_secsize / lp->d_secpercyl; 881 case 'K': 882 return fsz / 1024; 883 case 'M': 884 return fsz / (1024 * 1024); 885 case 'G': 886 return fsz / (1024 * 1024 * 1024); 887 case 'T': 888 return fsz / (1024ULL * 1024 * 1024 * 1024); 889 default: 890 return -1.0; 891 } 892 } 893 894 /* 895 * Display a particular partition. 896 */ 897 void 898 display_partition(FILE *f, struct disklabel *lp, char **mp, int i, 899 char unit) 900 { 901 volatile struct partition *pp = &lp->d_partitions[i]; 902 double p_size, p_offset; 903 904 p_size = scale(DL_GETPSIZE(pp), unit, lp); 905 p_offset = scale(DL_GETPOFFSET(pp), unit, lp); 906 if (DL_GETPSIZE(pp)) { 907 u_int32_t frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 908 u_int32_t fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 909 910 if (p_size < 0) 911 fprintf(f, " %c: %16llu %16llu ", 'a' + i, 912 DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); 913 else 914 fprintf(f, " %c: %15.*f%c %15.*f%c ", 'a' + i, 915 unit == 'B' ? 0 : 1, p_size, unit, 916 unit == 'B' ? 0 : 1, p_offset, unit); 917 if ((unsigned) pp->p_fstype < FSMAXTYPES) 918 fprintf(f, "%7.7s", fstypenames[pp->p_fstype]); 919 else 920 fprintf(f, "%7d", pp->p_fstype); 921 switch (pp->p_fstype) { 922 923 case FS_UNUSED: /* XXX */ 924 fprintf(f, " %5u %5u %4.4s ", 925 fsize, fsize * frag, ""); 926 break; 927 928 case FS_BSDFFS: 929 fprintf(f, " %5u %5u %4hu ", 930 fsize, fsize * frag, 931 pp->p_cpg); 932 break; 933 934 default: 935 fprintf(f, "%19.19s", ""); 936 break; 937 } 938 if (mp != NULL) { 939 if (mp[i] != NULL) 940 fprintf(f, "# %s", mp[i]); 941 } 942 putc('\n', f); 943 } 944 } 945 946 void 947 display(FILE *f, struct disklabel *lp, char **mp, char unit, int all) 948 { 949 int i, j; 950 double d; 951 952 unit = toupper(unit); 953 fprintf(f, "# %s:\n", specname); 954 955 if ((unsigned) lp->d_type < DKMAXTYPES) 956 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 957 else 958 fprintf(f, "type: %d\n", lp->d_type); 959 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 960 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 961 fprintf(f, "flags:"); 962 if (lp->d_flags & D_BADSECT) 963 fprintf(f, " badsect"); 964 if (lp->d_flags & D_VENDOR) 965 fprintf(f, " vendor"); 966 putc('\n', f); 967 968 fprintf(f, "bytes/sector: %u\n", lp->d_secsize); 969 fprintf(f, "sectors/track: %u\n", lp->d_nsectors); 970 fprintf(f, "tracks/cylinder: %u\n", lp->d_ntracks); 971 fprintf(f, "sectors/cylinder: %u\n", lp->d_secpercyl); 972 fprintf(f, "cylinders: %u\n", lp->d_ncylinders); 973 d = scale(DL_GETDSIZE(lp), unit, lp); 974 if (d < 0) 975 fprintf(f, "total sectors: %llu\n", DL_GETDSIZE(lp)); 976 else 977 fprintf(f, "total bytes: %.*f%c\n", unit == 'B' ? 0 : 1, 978 d, unit); 979 980 fprintf(f, "rpm: %hu\n", lp->d_rpm); 981 fprintf(f, "interleave: %hu\n", lp->d_interleave); 982 fprintf(f, "trackskew: %hu\n", lp->d_trackskew); 983 fprintf(f, "cylinderskew: %hu\n", lp->d_cylskew); 984 fprintf(f, "headswitch: %u\t\t# microseconds\n", 985 lp->d_headswitch); 986 fprintf(f, "track-to-track seek: %u\t# microseconds\n", 987 lp->d_trkseek); 988 fprintf(f, "drivedata: "); 989 for (i = NDDATA - 1; i >= 0; i--) 990 if (lp->d_drivedata[i]) 991 break; 992 if (i < 0) 993 i = 0; 994 for (j = 0; j <= i; j++) 995 fprintf(f, "%d ", lp->d_drivedata[j]); 996 fprintf(f, "\n"); 997 if (all) { 998 fprintf(f, "\n%hu partitions:\n", lp->d_npartitions); 999 fprintf(f, "# %16.16s %16.16s fstype [fsize bsize cpg]\n", 1000 "size", "offset"); 1001 for (i = 0; i < lp->d_npartitions; i++) 1002 display_partition(f, lp, mp, i, unit); 1003 } 1004 fflush(f); 1005 } 1006 1007 int 1008 edit(struct disklabel *lp, int f) 1009 { 1010 int first, ch, fd; 1011 struct disklabel label; 1012 FILE *fp; 1013 1014 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 1015 if (fd != -1) 1016 close(fd); 1017 warn("%s", tmpfil); 1018 return (1); 1019 } 1020 display(fp, lp, NULL, 0, 1); 1021 fprintf(fp, "\n# Notes:\n"); 1022 fprintf(fp, 1023 "# Up to 16 partitions are valid, named from 'a' to 'p'. Partition 'a' is\n" 1024 "# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n" 1025 "# disk. Any other partition is free for any use. 'size' and 'offset' are\n" 1026 "# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n" 1027 "# other values. fsize/bsize/cpg should typically be '2048 16384 16' for a\n" 1028 "# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, ...)\n"); 1029 fclose(fp); 1030 for (;;) { 1031 if (editit(tmpfil) == -1) 1032 break; 1033 fp = fopen(tmpfil, "r"); 1034 if (fp == NULL) { 1035 warn("%s", tmpfil); 1036 break; 1037 } 1038 memset(&label, 0, sizeof(label)); 1039 if (getasciilabel(fp, &label)) { 1040 if (cmplabel(lp, &label) == 0) { 1041 puts("No changes."); 1042 fclose(fp); 1043 (void) unlink(tmpfil); 1044 return (0); 1045 } 1046 *lp = label; 1047 if (writelabel(f, bootarea, lp) == 0) { 1048 fclose(fp); 1049 (void) unlink(tmpfil); 1050 return (0); 1051 } 1052 } 1053 fclose(fp); 1054 printf("re-edit the label? [y]: "); 1055 fflush(stdout); 1056 first = ch = getchar(); 1057 while (ch != '\n' && ch != EOF) 1058 ch = getchar(); 1059 if (first == 'n' || first == 'N') 1060 break; 1061 } 1062 (void)unlink(tmpfil); 1063 return (1); 1064 } 1065 1066 /* 1067 * Execute an editor on the specified pathname, which is interpreted 1068 * from the shell. This means flags may be included. 1069 * 1070 * Returns -1 on error, or the exit value on success. 1071 */ 1072 int 1073 editit(const char *pathname) 1074 { 1075 char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; 1076 sig_t sighup, sigint, sigquit, sigchld; 1077 pid_t pid; 1078 int saved_errno, st, ret = -1; 1079 1080 ed = getenv("VISUAL"); 1081 if (ed == NULL || ed[0] == '\0') 1082 ed = getenv("EDITOR"); 1083 if (ed == NULL || ed[0] == '\0') 1084 ed = _PATH_VI; 1085 if (asprintf(&p, "%s %s", ed, pathname) == -1) 1086 return (-1); 1087 argp[2] = p; 1088 1089 sighup = signal(SIGHUP, SIG_IGN); 1090 sigint = signal(SIGINT, SIG_IGN); 1091 sigquit = signal(SIGQUIT, SIG_IGN); 1092 sigchld = signal(SIGCHLD, SIG_DFL); 1093 if ((pid = fork()) == -1) 1094 goto fail; 1095 if (pid == 0) { 1096 execv(_PATH_BSHELL, argp); 1097 _exit(127); 1098 } 1099 while (waitpid(pid, &st, 0) == -1) 1100 if (errno != EINTR) 1101 goto fail; 1102 if (!WIFEXITED(st)) 1103 errno = EINTR; 1104 else 1105 ret = WEXITSTATUS(st); 1106 1107 fail: 1108 saved_errno = errno; 1109 (void)signal(SIGHUP, sighup); 1110 (void)signal(SIGINT, sigint); 1111 (void)signal(SIGQUIT, sigquit); 1112 (void)signal(SIGCHLD, sigchld); 1113 free(p); 1114 errno = saved_errno; 1115 return (ret); 1116 } 1117 1118 char * 1119 skip(char *cp) 1120 { 1121 1122 cp += strspn(cp, " \t"); 1123 if (*cp == '\0') 1124 return (NULL); 1125 return (cp); 1126 } 1127 1128 char * 1129 word(char *cp) 1130 { 1131 1132 cp += strcspn(cp, " \t"); 1133 if (*cp == '\0') 1134 return (NULL); 1135 *cp++ = '\0'; 1136 cp += strspn(cp, " \t"); 1137 if (*cp == '\0') 1138 return (NULL); 1139 return (cp); 1140 } 1141 1142 /* Base the max value on the sizeof of the value we are reading */ 1143 #define GETNUM(field, nptr, min, errstr) \ 1144 getnum((nptr), (min), \ 1145 sizeof(field) == 8 ? LLONG_MAX : \ 1146 (sizeof(field) == 4 ? UINT_MAX : \ 1147 (sizeof(field) == 2 ? USHRT_MAX : UCHAR_MAX)), (errstr)) 1148 1149 u_int64_t 1150 getnum(char *nptr, u_int64_t min, u_int64_t max, const char **errstr) 1151 { 1152 char *p, c; 1153 u_int64_t ret; 1154 1155 for (p = nptr; *p != '\0' && !isspace(*p); p++) 1156 ; 1157 c = *p; 1158 *p = '\0'; 1159 ret = strtonum(nptr, min, max, errstr); 1160 *p = c; 1161 return (ret); 1162 } 1163 1164 /* 1165 * Read an ascii label in from FILE f, 1166 * in the same format as that put out by display(), 1167 * and fill in lp. 1168 */ 1169 int 1170 getasciilabel(FILE *f, struct disklabel *lp) 1171 { 1172 char **cpp, *cp; 1173 const char *errstr; 1174 struct partition *pp; 1175 char *tp, *s, line[BUFSIZ]; 1176 int lineno = 0, errors = 0; 1177 u_int32_t v, fsize; 1178 u_int64_t lv; 1179 1180 lp->d_version = 1; 1181 lp->d_bbsize = BBSIZE; /* XXX */ 1182 lp->d_sbsize = SBSIZE; /* XXX */ 1183 while (fgets(line, sizeof(line), f)) { 1184 lineno++; 1185 if ((cp = strpbrk(line, "#\r\n"))) 1186 *cp = '\0'; 1187 cp = skip(line); 1188 if (cp == NULL) 1189 continue; 1190 tp = strchr(cp, ':'); 1191 if (tp == NULL) { 1192 warnx("line %d: syntax error", lineno); 1193 errors++; 1194 continue; 1195 } 1196 *tp++ = '\0', tp = skip(tp); 1197 if (!strcmp(cp, "type")) { 1198 if (tp == NULL) 1199 tp = "unknown"; 1200 else if (strcasecmp(tp, "IDE") == 0) 1201 tp = "ESDI"; 1202 cpp = dktypenames; 1203 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 1204 if ((s = *cpp) && !strcasecmp(s, tp)) { 1205 lp->d_type = cpp - dktypenames; 1206 goto next; 1207 } 1208 v = GETNUM(lp->d_type, tp, 0, &errstr); 1209 if (errstr || v >= DKMAXTYPES) 1210 warnx("line %d: warning, unknown disk type: %s", 1211 lineno, tp); 1212 lp->d_type = v; 1213 continue; 1214 } 1215 if (!strcmp(cp, "flags")) { 1216 for (v = 0; (cp = tp) && *cp != '\0';) { 1217 tp = word(cp); 1218 if (!strcmp(cp, "badsect")) 1219 v |= D_BADSECT; 1220 else if (!strcmp(cp, "vendor")) 1221 v |= D_VENDOR; 1222 else { 1223 warnx("line %d: bad flag: %s", 1224 lineno, cp); 1225 errors++; 1226 } 1227 } 1228 lp->d_flags = v; 1229 continue; 1230 } 1231 if (!strcmp(cp, "drivedata")) { 1232 int i; 1233 1234 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 1235 v = GETNUM(lp->d_drivedata[i], cp, 0, &errstr); 1236 if (errstr) 1237 warnx("line %d: bad drivedata %s", 1238 lineno, cp); 1239 lp->d_drivedata[i++] = v; 1240 tp = word(cp); 1241 } 1242 continue; 1243 } 1244 if (sscanf(cp, "%d partitions", &v) == 1) { 1245 if (v == 0 || v > MAXPARTITIONS) { 1246 warnx("line %d: bad # of partitions", lineno); 1247 lp->d_npartitions = MAXPARTITIONS; 1248 errors++; 1249 } else 1250 lp->d_npartitions = v; 1251 continue; 1252 } 1253 if (tp == NULL) 1254 tp = ""; 1255 if (!strcmp(cp, "disk")) { 1256 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 1257 continue; 1258 } 1259 if (!strcmp(cp, "label")) { 1260 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 1261 continue; 1262 } 1263 if (!strcmp(cp, "bytes/sector")) { 1264 v = GETNUM(lp->d_secsize, tp, 1, &errstr); 1265 if (errstr || (v % 512) != 0) { 1266 warnx("line %d: bad %s: %s", lineno, cp, tp); 1267 errors++; 1268 } else 1269 lp->d_secsize = v; 1270 continue; 1271 } 1272 if (!strcmp(cp, "sectors/track")) { 1273 v = GETNUM(lp->d_nsectors, tp, 1, &errstr); 1274 if (errstr) { 1275 warnx("line %d: bad %s: %s", lineno, cp, tp); 1276 errors++; 1277 } else 1278 lp->d_nsectors = v; 1279 continue; 1280 } 1281 if (!strcmp(cp, "sectors/cylinder")) { 1282 v = GETNUM(lp->d_secpercyl, tp, 1, &errstr); 1283 if (errstr) { 1284 warnx("line %d: bad %s: %s", lineno, cp, tp); 1285 errors++; 1286 } else 1287 lp->d_secpercyl = v; 1288 continue; 1289 } 1290 if (!strcmp(cp, "tracks/cylinder")) { 1291 v = GETNUM(lp->d_ntracks, tp, 1, &errstr); 1292 if (errstr) { 1293 warnx("line %d: bad %s: %s", lineno, cp, tp); 1294 errors++; 1295 } else 1296 lp->d_ntracks = v; 1297 continue; 1298 } 1299 if (!strcmp(cp, "cylinders")) { 1300 v = GETNUM(lp->d_ncylinders, tp, 1, &errstr); 1301 if (errstr) { 1302 warnx("line %d: bad %s: %s", lineno, cp, tp); 1303 errors++; 1304 } else 1305 lp->d_ncylinders = v; 1306 continue; 1307 } 1308 if (!strcmp(cp, "total sectors")) { 1309 lv = GETNUM(lv, tp, 1, &errstr); 1310 if (errstr) { 1311 warnx("line %d: bad %s: %s", lineno, cp, tp); 1312 errors++; 1313 } else { 1314 DL_SETDSIZE(lp, lv); 1315 } 1316 continue; 1317 } 1318 if (!strcmp(cp, "rpm")) { 1319 v = GETNUM(lp->d_rpm, tp, 1, &errstr); 1320 if (errstr) { 1321 warnx("line %d: bad %s: %s", lineno, cp, tp); 1322 errors++; 1323 } else 1324 lp->d_rpm = v; 1325 continue; 1326 } 1327 if (!strcmp(cp, "interleave")) { 1328 v = GETNUM(lp->d_interleave, tp, 1, &errstr); 1329 if (errstr) { 1330 warnx("line %d: bad %s: %s", lineno, cp, tp); 1331 errors++; 1332 } else 1333 lp->d_interleave = v; 1334 continue; 1335 } 1336 if (!strcmp(cp, "trackskew")) { 1337 v = GETNUM(lp->d_trackskew, tp, 0, &errstr); 1338 if (errstr) { 1339 warnx("line %d: bad %s: %s", lineno, cp, tp); 1340 errors++; 1341 } else 1342 lp->d_trackskew = v; 1343 continue; 1344 } 1345 if (!strcmp(cp, "cylinderskew")) { 1346 v = GETNUM(lp->d_cylskew, tp, 0, &errstr); 1347 if (errstr) { 1348 warnx("line %d: bad %s: %s", lineno, cp, tp); 1349 errors++; 1350 } else 1351 lp->d_cylskew = v; 1352 continue; 1353 } 1354 if (!strcmp(cp, "headswitch")) { 1355 v = GETNUM(lp->d_headswitch, tp, 0, &errstr); 1356 if (errstr) { 1357 warnx("line %d: bad %s: %s", lineno, cp, tp); 1358 errors++; 1359 } else 1360 lp->d_headswitch = v; 1361 continue; 1362 } 1363 if (!strcmp(cp, "track-to-track seek")) { 1364 v = GETNUM(lp->d_trkseek, tp, 0, &errstr); 1365 if (errstr) { 1366 warnx("line %d: bad %s: %s", lineno, cp, tp); 1367 errors++; 1368 } else 1369 lp->d_trkseek = v; 1370 continue; 1371 } 1372 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 1373 unsigned int part = *cp - 'a'; 1374 1375 if (part >= lp->d_npartitions) { 1376 if (part >= MAXPARTITIONS) { 1377 warnx("line %d: bad partition name: %s", 1378 lineno, cp); 1379 errors++; 1380 continue; 1381 } else { 1382 lp->d_npartitions = part + 1; 1383 } 1384 } 1385 pp = &lp->d_partitions[part]; 1386 #define NXTNUM(n, field, errstr) { \ 1387 if (tp == NULL) { \ 1388 warnx("line %d: too few fields", lineno); \ 1389 errors++; \ 1390 break; \ 1391 } else \ 1392 cp = tp, tp = word(cp), (n) = GETNUM(field, cp, 0, errstr); \ 1393 } 1394 NXTNUM(lv, lv, &errstr); 1395 if (errstr) { 1396 warnx("line %d: bad partition size: %s", 1397 lineno, cp); 1398 errors++; 1399 } else { 1400 DL_SETPSIZE(pp, lv); 1401 } 1402 NXTNUM(lv, lv, &errstr); 1403 if (errstr) { 1404 warnx("line %d: bad partition offset: %s", 1405 lineno, cp); 1406 errors++; 1407 } else { 1408 DL_SETPOFFSET(pp, lv); 1409 } 1410 if (tp == NULL) { 1411 pp->p_fstype = FS_UNUSED; 1412 goto gottype; 1413 } 1414 cp = tp, tp = word(cp); 1415 cpp = fstypenames; 1416 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 1417 if ((s = *cpp) && !strcasecmp(s, cp)) { 1418 pp->p_fstype = cpp - fstypenames; 1419 goto gottype; 1420 } 1421 if (isdigit(*cp)) 1422 v = GETNUM(pp->p_fstype, cp, 0, &errstr); 1423 else 1424 v = FSMAXTYPES; 1425 if (errstr || v >= FSMAXTYPES) { 1426 warnx("line %d: warning, unknown filesystem type: %s", 1427 lineno, cp); 1428 v = FS_UNUSED; 1429 } 1430 pp->p_fstype = v; 1431 gottype: 1432 switch (pp->p_fstype) { 1433 1434 case FS_UNUSED: /* XXX */ 1435 if (tp == NULL) /* ok to skip fsize/bsize */ 1436 break; 1437 NXTNUM(fsize, fsize, &errstr); 1438 if (fsize == 0) 1439 break; 1440 NXTNUM(v, v, &errstr); 1441 pp->p_fragblock = 1442 DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); 1443 break; 1444 1445 case FS_BSDFFS: 1446 NXTNUM(fsize, fsize, &errstr); 1447 if (fsize == 0) 1448 break; 1449 NXTNUM(v, v, &errstr); 1450 pp->p_fragblock = 1451 DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); 1452 NXTNUM(pp->p_cpg, pp->p_cpg, &errstr); 1453 break; 1454 1455 default: 1456 break; 1457 } 1458 continue; 1459 } 1460 warnx("line %d: unknown field: %s", lineno, cp); 1461 errors++; 1462 next: 1463 ; 1464 } 1465 errors += checklabel(lp); 1466 return (errors == 0); 1467 } 1468 1469 /* 1470 * Check disklabel for errors and fill in 1471 * derived fields according to supplied values. 1472 */ 1473 int 1474 checklabel(struct disklabel *lp) 1475 { 1476 struct partition *pp; 1477 int i, errors = 0; 1478 char part; 1479 1480 if (lp->d_secsize == 0) { 1481 warnx("sector size %d", lp->d_secsize); 1482 return (1); 1483 } 1484 if (lp->d_nsectors == 0) { 1485 warnx("sectors/track %d", lp->d_nsectors); 1486 return (1); 1487 } 1488 if (lp->d_ntracks == 0) { 1489 warnx("tracks/cylinder %d", lp->d_ntracks); 1490 return (1); 1491 } 1492 if (lp->d_ncylinders == 0) { 1493 warnx("cylinders/unit %d", lp->d_ncylinders); 1494 errors++; 1495 } 1496 if (lp->d_rpm == 0) 1497 warnx("warning, revolutions/minute %d", lp->d_rpm); 1498 if (lp->d_secpercyl == 0) 1499 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1500 if (DL_GETDSIZE(lp) == 0) 1501 DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); 1502 #ifdef i386__notyet 1503 if (dosdp && dosdp->dp_size && 1504 (dosdp->dp_typ == DOSPTYP_OPENBSD)) { 1505 && DL_GETDSIZE(lp) > dosdp->dp_start + dosdp->dp_size) { 1506 warnx("exceeds DOS partition size"); 1507 errors++; 1508 DL_SETDSIZE(lp, dosdp->dp_start + dosdp->dp_size); 1509 } 1510 #endif 1511 if (lp->d_bbsize == 0) { 1512 warnx("boot block size %d", lp->d_bbsize); 1513 errors++; 1514 } else if (lp->d_bbsize % lp->d_secsize) 1515 warnx("warning, boot block size %% sector-size != 0"); 1516 if (lp->d_sbsize == 0) { 1517 warnx("super block size %d", lp->d_sbsize); 1518 errors++; 1519 } else if (lp->d_sbsize % lp->d_secsize) 1520 warnx("warning, super block size %% sector-size != 0"); 1521 if (lp->d_npartitions > MAXPARTITIONS) 1522 warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", 1523 lp->d_npartitions, MAXPARTITIONS); 1524 for (i = 0; i < lp->d_npartitions; i++) { 1525 part = 'a' + i; 1526 pp = &lp->d_partitions[i]; 1527 if (DL_GETPSIZE(pp) == 0 && DL_GETPOFFSET(pp) != 0) 1528 warnx("warning, partition %c: size 0, but offset %lld", 1529 part, DL_GETPSIZE(pp)); 1530 #ifdef SUN_CYLCHECK 1531 if (lp->d_flags & D_VENDOR) { 1532 if (i != RAW_PART && DL_GETPSIZE(pp) % lp->d_secpercyl) 1533 warnx("warning, partition %c: size %% " 1534 "cylinder-size != 0", part); 1535 if (i != RAW_PART && DL_GETPOFFSET(pp) % lp->d_secpercyl) 1536 warnx("warning, partition %c: offset %% " 1537 "cylinder-size != 0", part); 1538 } 1539 #endif 1540 #ifdef SUN_AAT0 1541 if ((lp->d_flags & D_VENDOR) && 1542 i == 0 && DL_GETPSIZE(pp) != 0 && DL_GETPOFFSET(pp) != 0) { 1543 warnx("this architecture requires partition 'a' to " 1544 "start at sector 0"); 1545 errors++; 1546 } 1547 #endif 1548 if (DL_GETPOFFSET(pp) > DL_GETDSIZE(lp)) { 1549 warnx("partition %c: offset past end of unit", part); 1550 errors++; 1551 } 1552 if (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp) > DL_GETDSIZE(lp)) { 1553 warnx("partition %c: partition extends past end of unit", 1554 part); 1555 errors++; 1556 } 1557 #if 0 1558 if (pp->p_frag == 0 && pp->p_fsize != 0) { 1559 warnx("partition %c: block size < fragment size", part); 1560 errors++; 1561 } 1562 #endif 1563 } 1564 for (; i < MAXPARTITIONS; i++) { 1565 part = 'a' + i; 1566 pp = &lp->d_partitions[i]; 1567 if (DL_GETPSIZE(pp) || DL_GETPOFFSET(pp)) 1568 warnx("warning, unused partition %c: size %lld offset %lld", 1569 'a' + i, DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); 1570 } 1571 return (errors); 1572 } 1573 1574 #if NUMBOOT > 0 1575 /* 1576 * If we are installing a boot program that doesn't fit in d_bbsize 1577 * we need to mark those partitions that the boot overflows into. 1578 * This allows newfs to prevent creation of a filesystem where it might 1579 * clobber bootstrap code. 1580 */ 1581 void 1582 setbootflag(struct disklabel *lp) 1583 { 1584 struct partition *pp; 1585 int i, errors = 0; 1586 daddr64_t bend; 1587 char part; 1588 1589 if (bootbuf == NULL) 1590 return; 1591 1592 bend = bootsize / lp->d_secsize; 1593 for (i = 0; i < lp->d_npartitions; i++) { 1594 if (i == RAW_PART) 1595 /* It will *ALWAYS* overlap 'c'. */ 1596 continue; 1597 pp = &lp->d_partitions[i]; 1598 if (DL_GETPSIZE(pp) == 0) 1599 /* Partition is unused. */ 1600 continue; 1601 if (bend <= DL_GETPOFFSET(pp)) { 1602 /* Boot blocks end before this partition starts. */ 1603 if (pp->p_fstype == FS_BOOT) 1604 pp->p_fstype = FS_UNUSED; 1605 continue; 1606 } 1607 1608 part = 'a' + i; 1609 switch (pp->p_fstype) { 1610 case FS_BOOT: /* Already marked. */ 1611 break; 1612 case FS_UNUSED: /* Mark. */ 1613 pp->p_fstype = FS_BOOT; 1614 warnx("warning, boot overlaps partition %c, %s", 1615 part, "marked as FS_BOOT"); 1616 break; 1617 default: 1618 warnx("boot overlaps used partition %c", part); 1619 errors++; 1620 break; 1621 } 1622 } 1623 if (errors) 1624 errx(4, "cannot install boot program"); 1625 } 1626 #endif 1627 1628 int 1629 cmplabel(struct disklabel *lp1, struct disklabel *lp2) 1630 { 1631 struct disklabel lab1 = *lp1; 1632 struct disklabel lab2 = *lp2; 1633 1634 /* We don't compare these fields */ 1635 lab1.d_magic = lab2.d_magic; 1636 lab1.d_magic2 = lab2.d_magic2; 1637 lab1.d_checksum = lab2.d_checksum; 1638 lab1.d_bbsize = lab2.d_bbsize; 1639 lab1.d_sbsize = lab2.d_sbsize; 1640 1641 return (memcmp(&lab1, &lab2, sizeof(struct disklabel))); 1642 } 1643 1644 void 1645 usage(void) 1646 { 1647 char *boot = ""; 1648 char *blank = " "; 1649 1650 #if NUMBOOT == 1 1651 boot = " [-b boot1]"; 1652 #elif NUMBOOT == 2 1653 boot = " [-b boot1] [-s boot2]"; 1654 blank = " "; 1655 #endif 1656 1657 fprintf(stderr, 1658 "usage: disklabel [-c | -d | -t] [-v] [-p unit] disk\t\t(read)\n"); 1659 fprintf(stderr, 1660 " disklabel -w [-c | -d] [-nv] disk disktype [packid]\t(write)\n"); 1661 fprintf(stderr, 1662 " disklabel -e [-c | -d] [-nv] disk\t\t\t(edit)\n"); 1663 fprintf(stderr, 1664 " disklabel -E [-c | -d] [-nv] [-f tempfile] disk\t\t(simple editor)\n"); 1665 fprintf(stderr, 1666 " disklabel -R [-nv] disk protofile\t\t\t(restore)\n"); 1667 fprintf(stderr, 1668 " disklabel -N | -W [-nv] disk\t\t\t\t(protect)\n\n"); 1669 fprintf(stderr, 1670 "%sdisklabel -B [-nv]%s disk [disktype] (boot)\n", 1671 blank, boot); 1672 fprintf(stderr, 1673 "%sdisklabel -Bw [-nv]%s disk disktype [packid] (write)\n", 1674 blank, boot); 1675 fprintf(stderr, 1676 "%sdisklabel -BR [-nv]%s disk protofile [disktype] (restore)\n\n", 1677 blank, boot); 1678 fprintf(stderr, 1679 "`disk' may be of the form: sd0 or /dev/rsd0%c.\n", 'a'+RAW_PART); 1680 fprintf(stderr, 1681 "`disktype' is an entry from %s, see disktab(5) for more info.\n", 1682 DISKTAB); 1683 fprintf(stderr, 1684 "`packid' is an identification string for the device.\n"); 1685 fprintf(stderr, 1686 "`protofile' is the output from the read cmd form; -R is powerful.\n"); 1687 #ifdef SEEALSO 1688 fprintf(stderr, 1689 "For procedures specific to this architecture see: %s\n", SEEALSO); 1690 #endif 1691 exit(1); 1692 } 1693