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