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