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