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