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