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