1 /* 2 * Copyright (c) 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Symmetric Computer Systems. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1987, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94"; 45 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/signal.h> 50 #include <sys/errno.h> 51 #include <sys/file.h> 52 #include <sys/ioctl.h> 53 #include <sys/stat.h> 54 #define DKTYPENAMES 55 #include <sys/disklabel.h> 56 #include <ufs/ffs/fs.h> 57 #include <unistd.h> 58 #include <string.h> 59 #include <stdio.h> 60 #include <ctype.h> 61 #include "pathnames.h" 62 63 /* 64 * Disklabel: read and write disklabels. 65 * The label is usually placed on one of the first sectors of the disk. 66 * Many machines also place a bootstrap in the same area, 67 * in which case the label is embedded in the bootstrap. 68 * The bootstrap source must leave space at the proper offset 69 * for the label on such machines. 70 */ 71 72 #ifdef tahoe 73 #define RAWPARTITION 'a' 74 #else 75 #define RAWPARTITION 'c' 76 #endif 77 78 #ifndef BBSIZE 79 #define BBSIZE 8192 /* size of boot area, with label */ 80 #endif 81 82 #ifdef tahoe 83 #define NUMBOOT 0 84 #else 85 #if defined(hp300) || defined(hp800) 86 #define NUMBOOT 1 87 #else 88 #define NUMBOOT 2 89 #endif 90 #endif 91 92 #define DEFEDITOR _PATH_VI 93 #define streq(a,b) (strcmp(a,b) == 0) 94 95 char *dkname; 96 char *specname; 97 char tmpfil[] = _PATH_TMP; 98 99 extern int errno; 100 char namebuf[BBSIZE], *np = namebuf; 101 struct disklabel lab; 102 struct disklabel *readlabel(), *makebootarea(); 103 char bootarea[BBSIZE]; 104 105 #if NUMBOOT > 0 106 int installboot; /* non-zero if we should install a boot program */ 107 char *bootbuf; /* pointer to buffer with remainder of boot prog */ 108 int bootsize; /* size of remaining boot program */ 109 char *xxboot; /* primary boot */ 110 char *bootxx; /* secondary boot */ 111 char boot0[MAXPATHLEN]; 112 char boot1[MAXPATHLEN]; 113 #endif 114 115 enum { 116 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 117 } op = UNSPEC; 118 119 int rflag; 120 121 #ifdef DEBUG 122 int debug; 123 #define OPTIONS "BNRWb:ders:w" 124 #else 125 #define OPTIONS "BNRWb:ers:w" 126 #endif 127 128 129 main(argc, argv) 130 int argc; 131 char *argv[]; 132 { 133 extern char *optarg; 134 extern int optind; 135 register struct disklabel *lp; 136 FILE *t; 137 int ch, f, flag, error = 0; 138 char *name = 0; 139 140 while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 141 switch (ch) { 142 #if NUMBOOT > 0 143 case 'B': 144 ++installboot; 145 break; 146 case 'b': 147 xxboot = optarg; 148 break; 149 #if NUMBOOT > 1 150 case 's': 151 bootxx = optarg; 152 break; 153 #endif 154 #endif 155 case 'N': 156 if (op != UNSPEC) 157 usage(); 158 op = NOWRITE; 159 break; 160 case 'R': 161 if (op != UNSPEC) 162 usage(); 163 op = RESTORE; 164 break; 165 case 'W': 166 if (op != UNSPEC) 167 usage(); 168 op = WRITEABLE; 169 break; 170 case 'e': 171 if (op != UNSPEC) 172 usage(); 173 op = EDIT; 174 break; 175 case 'r': 176 ++rflag; 177 break; 178 case 'w': 179 if (op != UNSPEC) 180 usage(); 181 op = WRITE; 182 break; 183 #ifdef DEBUG 184 case 'd': 185 debug++; 186 break; 187 #endif 188 case '?': 189 default: 190 usage(); 191 } 192 argc -= optind; 193 argv += optind; 194 #if NUMBOOT > 0 195 if (installboot) { 196 rflag++; 197 if (op == UNSPEC) 198 op = WRITEBOOT; 199 } else { 200 if (op == UNSPEC) 201 op = READ; 202 xxboot = bootxx = 0; 203 } 204 #else 205 if (op == UNSPEC) 206 op = READ; 207 #endif 208 if (argc < 1) 209 usage(); 210 211 dkname = argv[0]; 212 if (dkname[0] != '/') { 213 (void)sprintf(np, "%sr%s%c", _PATH_DEV, dkname, RAWPARTITION); 214 specname = np; 215 np += strlen(specname) + 1; 216 } else 217 specname = dkname; 218 f = open(specname, op == READ ? O_RDONLY : O_RDWR); 219 if (f < 0 && errno == ENOENT && dkname[0] != '/') { 220 (void)sprintf(specname, "%sr%s", _PATH_DEV, dkname); 221 np = namebuf + strlen(specname) + 1; 222 f = open(specname, op == READ ? O_RDONLY : O_RDWR); 223 } 224 if (f < 0) 225 Perror(specname); 226 227 switch(op) { 228 229 case EDIT: 230 if (argc != 1) 231 usage(); 232 lp = readlabel(f); 233 error = edit(lp, f); 234 break; 235 236 case NOWRITE: 237 flag = 0; 238 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 239 Perror("ioctl DIOCWLABEL"); 240 break; 241 242 case READ: 243 if (argc != 1) 244 usage(); 245 lp = readlabel(f); 246 display(stdout, lp); 247 error = checklabel(lp); 248 break; 249 250 case RESTORE: 251 #if NUMBOOT > 0 252 if (installboot && argc == 3) { 253 makelabel(argv[2], 0, &lab); 254 argc--; 255 } 256 #endif 257 if (argc != 2) 258 usage(); 259 lp = makebootarea(bootarea, &lab, f); 260 if (!(t = fopen(argv[1], "r"))) 261 Perror(argv[1]); 262 if (getasciilabel(t, lp)) 263 error = writelabel(f, bootarea, lp); 264 break; 265 266 case WRITE: 267 if (argc == 3) { 268 name = argv[2]; 269 argc--; 270 } 271 if (argc != 2) 272 usage(); 273 makelabel(argv[1], name, &lab); 274 lp = makebootarea(bootarea, &lab, f); 275 *lp = lab; 276 if (checklabel(lp) == 0) 277 error = writelabel(f, bootarea, lp); 278 break; 279 280 case WRITEABLE: 281 flag = 1; 282 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 283 Perror("ioctl DIOCWLABEL"); 284 break; 285 286 #if NUMBOOT > 0 287 case WRITEBOOT: 288 { 289 struct disklabel tlab; 290 291 lp = readlabel(f); 292 tlab = *lp; 293 if (argc == 2) 294 makelabel(argv[1], 0, &lab); 295 lp = makebootarea(bootarea, &lab, f); 296 *lp = tlab; 297 if (checklabel(lp) == 0) 298 error = writelabel(f, bootarea, lp); 299 break; 300 } 301 #endif 302 } 303 exit(error); 304 } 305 306 /* 307 * Construct a prototype disklabel from /etc/disktab. As a side 308 * effect, set the names of the primary and secondary boot files 309 * if specified. 310 */ 311 makelabel(type, name, lp) 312 char *type, *name; 313 register struct disklabel *lp; 314 { 315 register struct disklabel *dp; 316 char *strcpy(); 317 318 dp = getdiskbyname(type); 319 if (dp == NULL) { 320 fprintf(stderr, "%s: unknown disk type\n", type); 321 exit(1); 322 } 323 *lp = *dp; 324 #if NUMBOOT > 0 325 /* 326 * Set bootstrap name(s). 327 * 1. If set from command line, use those, 328 * 2. otherwise, check if disktab specifies them (b0 or b1), 329 * 3. otherwise, makebootarea() will choose ones based on the name 330 * of the disk special file. E.g. /dev/ra0 -> raboot, bootra 331 */ 332 if (!xxboot && lp->d_boot0) { 333 if (*lp->d_boot0 != '/') 334 (void)sprintf(boot0, "%s/%s", 335 _PATH_BOOTDIR, lp->d_boot0); 336 else 337 (void)strcpy(boot0, lp->d_boot0); 338 xxboot = boot0; 339 } 340 #if NUMBOOT > 1 341 if (!bootxx && lp->d_boot1) { 342 if (*lp->d_boot1 != '/') 343 (void)sprintf(boot1, "%s/%s", 344 _PATH_BOOTDIR, lp->d_boot1); 345 else 346 (void)strcpy(boot1, lp->d_boot1); 347 bootxx = boot1; 348 } 349 #endif 350 #endif 351 /* d_packname is union d_boot[01], so zero */ 352 bzero(lp->d_packname, sizeof(lp->d_packname)); 353 if (name) 354 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 355 } 356 357 writelabel(f, boot, lp) 358 int f; 359 char *boot; 360 register struct disklabel *lp; 361 { 362 register int i; 363 int flag; 364 365 setbootflag(lp); 366 lp->d_magic = DISKMAGIC; 367 lp->d_magic2 = DISKMAGIC; 368 lp->d_checksum = 0; 369 lp->d_checksum = dkcksum(lp); 370 if (rflag) { 371 /* 372 * First set the kernel disk label, 373 * then write a label to the raw disk. 374 * If the SDINFO ioctl fails because it is unimplemented, 375 * keep going; otherwise, the kernel consistency checks 376 * may prevent us from changing the current (in-core) 377 * label. 378 */ 379 if (ioctl(f, DIOCSDINFO, lp) < 0 && 380 errno != ENODEV && errno != ENOTTY) { 381 l_perror("ioctl DIOCSDINFO"); 382 return (1); 383 } 384 (void)lseek(f, (off_t)0, SEEK_SET); 385 /* 386 * write enable label sector before write (if necessary), 387 * disable after writing. 388 */ 389 flag = 1; 390 if (ioctl(f, DIOCWLABEL, &flag) < 0) 391 perror("ioctl DIOCWLABEL"); 392 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { 393 perror("write"); 394 return (1); 395 } 396 #if NUMBOOT > 0 397 /* 398 * Output the remainder of the disklabel 399 */ 400 if (bootbuf && write(f, bootbuf, bootsize) != bootsize) { 401 perror("write"); 402 return(1); 403 } 404 #endif 405 flag = 0; 406 (void) ioctl(f, DIOCWLABEL, &flag); 407 } else if (ioctl(f, DIOCWDINFO, lp) < 0) { 408 l_perror("ioctl DIOCWDINFO"); 409 return (1); 410 } 411 #ifdef vax 412 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 413 daddr_t alt; 414 415 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 416 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 417 (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), 418 SEEK_SET); 419 if (write(f, boot, lp->d_secsize) < lp->d_secsize) { 420 int oerrno = errno; 421 fprintf(stderr, "alternate label %d ", i/2); 422 errno = oerrno; 423 perror("write"); 424 } 425 } 426 } 427 #endif 428 return (0); 429 } 430 431 l_perror(s) 432 char *s; 433 { 434 int saverrno = errno; 435 436 fprintf(stderr, "disklabel: %s: ", s); 437 438 switch (saverrno) { 439 440 case ESRCH: 441 fprintf(stderr, "No disk label on disk;\n"); 442 fprintf(stderr, 443 "use \"disklabel -r\" to install initial label\n"); 444 break; 445 446 case EINVAL: 447 fprintf(stderr, "Label magic number or checksum is wrong!\n"); 448 fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 449 break; 450 451 case EBUSY: 452 fprintf(stderr, "Open partition would move or shrink\n"); 453 break; 454 455 case EXDEV: 456 fprintf(stderr, 457 "Labeled partition or 'a' partition must start at beginning of disk\n"); 458 break; 459 460 default: 461 errno = saverrno; 462 perror((char *)NULL); 463 break; 464 } 465 } 466 467 /* 468 * Fetch disklabel for disk. 469 * Use ioctl to get label unless -r flag is given. 470 */ 471 struct disklabel * 472 readlabel(f) 473 int f; 474 { 475 register struct disklabel *lp; 476 477 if (rflag) { 478 if (read(f, bootarea, BBSIZE) < BBSIZE) 479 Perror(specname); 480 for (lp = (struct disklabel *)bootarea; 481 lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); 482 lp = (struct disklabel *)((char *)lp + 16)) 483 if (lp->d_magic == DISKMAGIC && 484 lp->d_magic2 == DISKMAGIC) 485 break; 486 if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) || 487 lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC || 488 dkcksum(lp) != 0) { 489 fprintf(stderr, 490 "Bad pack magic number (label is damaged, or pack is unlabeled)\n"); 491 /* lp = (struct disklabel *)(bootarea + LABELOFFSET); */ 492 exit (1); 493 } 494 } else { 495 lp = &lab; 496 if (ioctl(f, DIOCGDINFO, lp) < 0) 497 Perror("ioctl DIOCGDINFO"); 498 } 499 return (lp); 500 } 501 502 /* 503 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 504 * Returns a pointer to the disklabel portion of the bootarea. 505 */ 506 struct disklabel * 507 makebootarea(boot, dp, f) 508 char *boot; 509 register struct disklabel *dp; 510 int f; 511 { 512 struct disklabel *lp; 513 register char *p; 514 int b; 515 #if NUMBOOT > 0 516 char *dkbasename; 517 struct stat sb; 518 #endif 519 520 /* XXX */ 521 if (dp->d_secsize == 0) { 522 dp->d_secsize = DEV_BSIZE; 523 dp->d_bbsize = BBSIZE; 524 } 525 lp = (struct disklabel *) 526 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); 527 bzero((char *)lp, sizeof *lp); 528 #if NUMBOOT > 0 529 /* 530 * If we are not installing a boot program but we are installing a 531 * label on disk then we must read the current bootarea so we don't 532 * clobber the existing boot. 533 */ 534 if (!installboot) { 535 if (rflag) { 536 if (read(f, boot, BBSIZE) < BBSIZE) 537 Perror(specname); 538 bzero((char *)lp, sizeof *lp); 539 } 540 return (lp); 541 } 542 /* 543 * We are installing a boot program. Determine the name(s) and 544 * read them into the appropriate places in the boot area. 545 */ 546 if (!xxboot || !bootxx) { 547 dkbasename = np; 548 if ((p = rindex(dkname, '/')) == NULL) 549 p = dkname; 550 else 551 p++; 552 while (*p && !isdigit(*p)) 553 *np++ = *p++; 554 *np++ = '\0'; 555 556 if (!xxboot) { 557 (void)sprintf(np, "%s/%sboot", 558 _PATH_BOOTDIR, dkbasename); 559 if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 560 dkbasename++; 561 xxboot = np; 562 (void)sprintf(xxboot, "%s/%sboot", 563 _PATH_BOOTDIR, dkbasename); 564 np += strlen(xxboot) + 1; 565 } 566 #if NUMBOOT > 1 567 if (!bootxx) { 568 (void)sprintf(np, "%s/boot%s", 569 _PATH_BOOTDIR, dkbasename); 570 if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 571 dkbasename++; 572 bootxx = np; 573 (void)sprintf(bootxx, "%s/boot%s", 574 _PATH_BOOTDIR, dkbasename); 575 np += strlen(bootxx) + 1; 576 } 577 #endif 578 } 579 #ifdef DEBUG 580 if (debug) 581 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n", 582 xxboot, bootxx ? bootxx : "NONE"); 583 #endif 584 585 /* 586 * Strange rules: 587 * 1. One-piece bootstrap (hp300/hp800) 588 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest 589 * is remembered and written later following the bootarea. 590 * 2. Two-piece bootstraps (vax/i386?/mips?) 591 * up to d_secsize bytes of ``xxboot'' go in first d_secsize 592 * bytes of bootarea, remaining d_bbsize-d_secsize filled 593 * from ``bootxx''. 594 */ 595 b = open(xxboot, O_RDONLY); 596 if (b < 0) 597 Perror(xxboot); 598 #if NUMBOOT > 1 599 if (read(b, boot, (int)dp->d_secsize) < 0) 600 Perror(xxboot); 601 (void)close(b); 602 b = open(bootxx, O_RDONLY); 603 if (b < 0) 604 Perror(bootxx); 605 if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0) 606 Perror(bootxx); 607 #else 608 if (read(b, boot, (int)dp->d_bbsize) < 0) 609 Perror(xxboot); 610 (void)fstat(b, &sb); 611 bootsize = (int)sb.st_size - dp->d_bbsize; 612 if (bootsize > 0) { 613 /* XXX assume d_secsize is a power of two */ 614 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); 615 bootbuf = (char *)malloc((size_t)bootsize); 616 if (bootbuf == 0) 617 Perror(xxboot); 618 if (read(b, bootbuf, bootsize) < 0) { 619 free(bootbuf); 620 Perror(xxboot); 621 } 622 } 623 #endif 624 (void)close(b); 625 #endif 626 /* 627 * Make sure no part of the bootstrap is written in the area 628 * reserved for the label. 629 */ 630 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 631 if (*p) { 632 fprintf(stderr, 633 "Bootstrap doesn't leave room for disk label\n"); 634 exit(2); 635 } 636 return (lp); 637 } 638 639 display(f, lp) 640 FILE *f; 641 register struct disklabel *lp; 642 { 643 register int i, j; 644 register struct partition *pp; 645 646 fprintf(f, "# %s:\n", specname); 647 if ((unsigned) lp->d_type < DKMAXTYPES) 648 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 649 else 650 fprintf(f, "type: %d\n", lp->d_type); 651 fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename); 652 fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname); 653 fprintf(f, "flags:"); 654 if (lp->d_flags & D_REMOVABLE) 655 fprintf(f, " removeable"); 656 if (lp->d_flags & D_ECC) 657 fprintf(f, " ecc"); 658 if (lp->d_flags & D_BADSECT) 659 fprintf(f, " badsect"); 660 fprintf(f, "\n"); 661 fprintf(f, "bytes/sector: %d\n", lp->d_secsize); 662 fprintf(f, "sectors/track: %d\n", lp->d_nsectors); 663 fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks); 664 fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl); 665 fprintf(f, "cylinders: %d\n", lp->d_ncylinders); 666 fprintf(f, "sectors/unit: %d\n", lp->d_secperunit); 667 fprintf(f, "rpm: %d\n", lp->d_rpm); 668 fprintf(f, "interleave: %d\n", lp->d_interleave); 669 fprintf(f, "trackskew: %d\n", lp->d_trackskew); 670 fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); 671 fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); 672 fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); 673 fprintf(f, "drivedata: "); 674 for (i = NDDATA - 1; i >= 0; i--) 675 if (lp->d_drivedata[i]) 676 break; 677 if (i < 0) 678 i = 0; 679 for (j = 0; j <= i; j++) 680 fprintf(f, "%d ", lp->d_drivedata[j]); 681 fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); 682 fprintf(f, 683 "# size offset fstype [fsize bsize bps/cpg]\n"); 684 pp = lp->d_partitions; 685 for (i = 0; i < lp->d_npartitions; i++, pp++) { 686 if (pp->p_size) { 687 fprintf(f, " %c: %8d %8d ", 'a' + i, 688 pp->p_size, pp->p_offset); 689 if ((unsigned) pp->p_fstype < FSMAXTYPES) 690 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 691 else 692 fprintf(f, "%8d", pp->p_fstype); 693 switch (pp->p_fstype) { 694 695 case FS_UNUSED: /* XXX */ 696 fprintf(f, " %5d %5d %5.5s ", 697 pp->p_fsize, pp->p_fsize * pp->p_frag, ""); 698 break; 699 700 case FS_BSDFFS: 701 fprintf(f, " %5d %5d %5d ", 702 pp->p_fsize, pp->p_fsize * pp->p_frag, 703 pp->p_cpg); 704 break; 705 706 case FS_BSDLFS: 707 fprintf(f, " %5d %5d %5d", 708 pp->p_fsize, pp->p_fsize * pp->p_frag, 709 pp->p_cpg); 710 break; 711 712 default: 713 fprintf(f, "%20.20s", ""); 714 break; 715 } 716 fprintf(f, "\t# (Cyl. %4d", 717 pp->p_offset / lp->d_secpercyl); 718 if (pp->p_offset % lp->d_secpercyl) 719 putc('*', f); 720 else 721 putc(' ', f); 722 fprintf(f, "- %d", 723 (pp->p_offset + 724 pp->p_size + lp->d_secpercyl - 1) / 725 lp->d_secpercyl - 1); 726 if (pp->p_size % lp->d_secpercyl) 727 putc('*', f); 728 fprintf(f, ")\n"); 729 } 730 } 731 fflush(f); 732 } 733 734 edit(lp, f) 735 struct disklabel *lp; 736 int f; 737 { 738 register int c; 739 struct disklabel label; 740 FILE *fd; 741 char *mktemp(); 742 743 (void) mktemp(tmpfil); 744 fd = fopen(tmpfil, "w"); 745 if (fd == NULL) { 746 fprintf(stderr, "%s: Can't create\n", tmpfil); 747 return (1); 748 } 749 (void)fchmod(fileno(fd), 0600); 750 display(fd, lp); 751 fclose(fd); 752 for (;;) { 753 if (!editit()) 754 break; 755 fd = fopen(tmpfil, "r"); 756 if (fd == NULL) { 757 fprintf(stderr, "%s: Can't reopen for reading\n", 758 tmpfil); 759 break; 760 } 761 bzero((char *)&label, sizeof(label)); 762 if (getasciilabel(fd, &label)) { 763 *lp = label; 764 if (writelabel(f, bootarea, lp) == 0) { 765 (void) unlink(tmpfil); 766 return (0); 767 } 768 } 769 printf("re-edit the label? [y]: "); fflush(stdout); 770 c = getchar(); 771 if (c != EOF && c != (int)'\n') 772 while (getchar() != (int)'\n') 773 ; 774 if (c == (int)'n') 775 break; 776 } 777 (void) unlink(tmpfil); 778 return (1); 779 } 780 781 editit() 782 { 783 register int pid, xpid; 784 int stat, omask; 785 extern char *getenv(); 786 787 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 788 while ((pid = fork()) < 0) { 789 extern int errno; 790 791 if (errno == EPROCLIM) { 792 fprintf(stderr, "You have too many processes\n"); 793 return(0); 794 } 795 if (errno != EAGAIN) { 796 perror("fork"); 797 return(0); 798 } 799 sleep(1); 800 } 801 if (pid == 0) { 802 register char *ed; 803 804 sigsetmask(omask); 805 setgid(getgid()); 806 setuid(getuid()); 807 if ((ed = getenv("EDITOR")) == (char *)0) 808 ed = DEFEDITOR; 809 execlp(ed, ed, tmpfil, 0); 810 perror(ed); 811 exit(1); 812 } 813 while ((xpid = wait(&stat)) >= 0) 814 if (xpid == pid) 815 break; 816 sigsetmask(omask); 817 return(!stat); 818 } 819 820 char * 821 skip(cp) 822 register char *cp; 823 { 824 825 while (*cp != '\0' && isspace(*cp)) 826 cp++; 827 if (*cp == '\0' || *cp == '#') 828 return ((char *)NULL); 829 return (cp); 830 } 831 832 char * 833 word(cp) 834 register char *cp; 835 { 836 register char c; 837 838 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 839 cp++; 840 if ((c = *cp) != '\0') { 841 *cp++ = '\0'; 842 if (c != '#') 843 return (skip(cp)); 844 } 845 return ((char *)NULL); 846 } 847 848 /* 849 * Read an ascii label in from fd f, 850 * in the same format as that put out by display(), 851 * and fill in lp. 852 */ 853 getasciilabel(f, lp) 854 FILE *f; 855 register struct disklabel *lp; 856 { 857 register char **cpp, *cp; 858 register struct partition *pp; 859 char *tp, *s, line[BUFSIZ]; 860 int v, lineno = 0, errors = 0; 861 862 lp->d_bbsize = BBSIZE; /* XXX */ 863 lp->d_sbsize = SBSIZE; /* XXX */ 864 while (fgets(line, sizeof(line) - 1, f)) { 865 lineno++; 866 if (cp = index(line,'\n')) 867 *cp = '\0'; 868 cp = skip(line); 869 if (cp == NULL) 870 continue; 871 tp = index(cp, ':'); 872 if (tp == NULL) { 873 fprintf(stderr, "line %d: syntax error\n", lineno); 874 errors++; 875 continue; 876 } 877 *tp++ = '\0', tp = skip(tp); 878 if (streq(cp, "type")) { 879 if (tp == NULL) 880 tp = "unknown"; 881 cpp = dktypenames; 882 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 883 if ((s = *cpp) && streq(s, tp)) { 884 lp->d_type = cpp - dktypenames; 885 goto next; 886 } 887 v = atoi(tp); 888 if ((unsigned)v >= DKMAXTYPES) 889 fprintf(stderr, "line %d:%s %d\n", lineno, 890 "Warning, unknown disk type", v); 891 lp->d_type = v; 892 continue; 893 } 894 if (streq(cp, "flags")) { 895 for (v = 0; (cp = tp) && *cp != '\0';) { 896 tp = word(cp); 897 if (streq(cp, "removeable")) 898 v |= D_REMOVABLE; 899 else if (streq(cp, "ecc")) 900 v |= D_ECC; 901 else if (streq(cp, "badsect")) 902 v |= D_BADSECT; 903 else { 904 fprintf(stderr, 905 "line %d: %s: bad flag\n", 906 lineno, cp); 907 errors++; 908 } 909 } 910 lp->d_flags = v; 911 continue; 912 } 913 if (streq(cp, "drivedata")) { 914 register int i; 915 916 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 917 lp->d_drivedata[i++] = atoi(cp); 918 tp = word(cp); 919 } 920 continue; 921 } 922 if (sscanf(cp, "%d partitions", &v) == 1) { 923 if (v == 0 || (unsigned)v > MAXPARTITIONS) { 924 fprintf(stderr, 925 "line %d: bad # of partitions\n", lineno); 926 lp->d_npartitions = MAXPARTITIONS; 927 errors++; 928 } else 929 lp->d_npartitions = v; 930 continue; 931 } 932 if (tp == NULL) 933 tp = ""; 934 if (streq(cp, "disk")) { 935 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 936 continue; 937 } 938 if (streq(cp, "label")) { 939 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 940 continue; 941 } 942 if (streq(cp, "bytes/sector")) { 943 v = atoi(tp); 944 if (v <= 0 || (v % 512) != 0) { 945 fprintf(stderr, 946 "line %d: %s: bad sector size\n", 947 lineno, tp); 948 errors++; 949 } else 950 lp->d_secsize = v; 951 continue; 952 } 953 if (streq(cp, "sectors/track")) { 954 v = atoi(tp); 955 if (v <= 0) { 956 fprintf(stderr, "line %d: %s: bad %s\n", 957 lineno, tp, cp); 958 errors++; 959 } else 960 lp->d_nsectors = v; 961 continue; 962 } 963 if (streq(cp, "sectors/cylinder")) { 964 v = atoi(tp); 965 if (v <= 0) { 966 fprintf(stderr, "line %d: %s: bad %s\n", 967 lineno, tp, cp); 968 errors++; 969 } else 970 lp->d_secpercyl = v; 971 continue; 972 } 973 if (streq(cp, "tracks/cylinder")) { 974 v = atoi(tp); 975 if (v <= 0) { 976 fprintf(stderr, "line %d: %s: bad %s\n", 977 lineno, tp, cp); 978 errors++; 979 } else 980 lp->d_ntracks = v; 981 continue; 982 } 983 if (streq(cp, "cylinders")) { 984 v = atoi(tp); 985 if (v <= 0) { 986 fprintf(stderr, "line %d: %s: bad %s\n", 987 lineno, tp, cp); 988 errors++; 989 } else 990 lp->d_ncylinders = v; 991 continue; 992 } 993 if (streq(cp, "sectors/unit")) { 994 v = atoi(tp); 995 if (v <= 0) { 996 fprintf(stderr, "line %d: %s: bad %s\n", 997 lineno, tp, cp); 998 errors++; 999 } else 1000 lp->d_secperunit = v; 1001 continue; 1002 } 1003 if (streq(cp, "rpm")) { 1004 v = atoi(tp); 1005 if (v <= 0) { 1006 fprintf(stderr, "line %d: %s: bad %s\n", 1007 lineno, tp, cp); 1008 errors++; 1009 } else 1010 lp->d_rpm = v; 1011 continue; 1012 } 1013 if (streq(cp, "interleave")) { 1014 v = atoi(tp); 1015 if (v <= 0) { 1016 fprintf(stderr, "line %d: %s: bad %s\n", 1017 lineno, tp, cp); 1018 errors++; 1019 } else 1020 lp->d_interleave = v; 1021 continue; 1022 } 1023 if (streq(cp, "trackskew")) { 1024 v = atoi(tp); 1025 if (v < 0) { 1026 fprintf(stderr, "line %d: %s: bad %s\n", 1027 lineno, tp, cp); 1028 errors++; 1029 } else 1030 lp->d_trackskew = v; 1031 continue; 1032 } 1033 if (streq(cp, "cylinderskew")) { 1034 v = atoi(tp); 1035 if (v < 0) { 1036 fprintf(stderr, "line %d: %s: bad %s\n", 1037 lineno, tp, cp); 1038 errors++; 1039 } else 1040 lp->d_cylskew = v; 1041 continue; 1042 } 1043 if (streq(cp, "headswitch")) { 1044 v = atoi(tp); 1045 if (v < 0) { 1046 fprintf(stderr, "line %d: %s: bad %s\n", 1047 lineno, tp, cp); 1048 errors++; 1049 } else 1050 lp->d_headswitch = v; 1051 continue; 1052 } 1053 if (streq(cp, "track-to-track seek")) { 1054 v = atoi(tp); 1055 if (v < 0) { 1056 fprintf(stderr, "line %d: %s: bad %s\n", 1057 lineno, tp, cp); 1058 errors++; 1059 } else 1060 lp->d_trkseek = v; 1061 continue; 1062 } 1063 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 1064 unsigned part = *cp - 'a'; 1065 1066 if (part > lp->d_npartitions) { 1067 fprintf(stderr, 1068 "line %d: bad partition name\n", lineno); 1069 errors++; 1070 continue; 1071 } 1072 pp = &lp->d_partitions[part]; 1073 #define NXTNUM(n) { \ 1074 if (tp == NULL) { \ 1075 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 1076 errors++; \ 1077 break; \ 1078 } else { \ 1079 cp = tp, tp = word(cp); \ 1080 if (tp == NULL) \ 1081 tp = cp; \ 1082 (n) = atoi(cp); \ 1083 } \ 1084 } 1085 1086 NXTNUM(v); 1087 if (v < 0) { 1088 fprintf(stderr, 1089 "line %d: %s: bad partition size\n", 1090 lineno, cp); 1091 errors++; 1092 } else 1093 pp->p_size = v; 1094 NXTNUM(v); 1095 if (v < 0) { 1096 fprintf(stderr, 1097 "line %d: %s: bad partition offset\n", 1098 lineno, cp); 1099 errors++; 1100 } else 1101 pp->p_offset = v; 1102 cp = tp, tp = word(cp); 1103 cpp = fstypenames; 1104 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 1105 if ((s = *cpp) && streq(s, cp)) { 1106 pp->p_fstype = cpp - fstypenames; 1107 goto gottype; 1108 } 1109 if (isdigit(*cp)) 1110 v = atoi(cp); 1111 else 1112 v = FSMAXTYPES; 1113 if ((unsigned)v >= FSMAXTYPES) { 1114 fprintf(stderr, "line %d: %s %s\n", lineno, 1115 "Warning, unknown filesystem type", cp); 1116 v = FS_UNUSED; 1117 } 1118 pp->p_fstype = v; 1119 gottype: 1120 1121 switch (pp->p_fstype) { 1122 1123 case FS_UNUSED: /* XXX */ 1124 NXTNUM(pp->p_fsize); 1125 if (pp->p_fsize == 0) 1126 break; 1127 NXTNUM(v); 1128 pp->p_frag = v / pp->p_fsize; 1129 break; 1130 1131 case FS_BSDFFS: 1132 NXTNUM(pp->p_fsize); 1133 if (pp->p_fsize == 0) 1134 break; 1135 NXTNUM(v); 1136 pp->p_frag = v / pp->p_fsize; 1137 NXTNUM(pp->p_cpg); 1138 break; 1139 1140 case FS_BSDLFS: 1141 NXTNUM(pp->p_fsize); 1142 if (pp->p_fsize == 0) 1143 break; 1144 NXTNUM(v); 1145 pp->p_frag = v / pp->p_fsize; 1146 NXTNUM(pp->p_cpg); 1147 break; 1148 1149 default: 1150 break; 1151 } 1152 continue; 1153 } 1154 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1155 lineno, cp); 1156 errors++; 1157 next: 1158 ; 1159 } 1160 errors += checklabel(lp); 1161 return (errors == 0); 1162 } 1163 1164 /* 1165 * Check disklabel for errors and fill in 1166 * derived fields according to supplied values. 1167 */ 1168 checklabel(lp) 1169 register struct disklabel *lp; 1170 { 1171 register struct partition *pp; 1172 int i, errors = 0; 1173 char part; 1174 1175 if (lp->d_secsize == 0) { 1176 fprintf(stderr, "sector size %d\n", lp->d_secsize); 1177 return (1); 1178 } 1179 if (lp->d_nsectors == 0) { 1180 fprintf(stderr, "sectors/track %d\n", lp->d_nsectors); 1181 return (1); 1182 } 1183 if (lp->d_ntracks == 0) { 1184 fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks); 1185 return (1); 1186 } 1187 if (lp->d_ncylinders == 0) { 1188 fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders); 1189 errors++; 1190 } 1191 if (lp->d_rpm == 0) 1192 Warning("revolutions/minute %d", lp->d_rpm); 1193 if (lp->d_secpercyl == 0) 1194 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1195 if (lp->d_secperunit == 0) 1196 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1197 if (lp->d_bbsize == 0) { 1198 fprintf(stderr, "boot block size %d\n", lp->d_bbsize); 1199 errors++; 1200 } else if (lp->d_bbsize % lp->d_secsize) 1201 Warning("boot block size %% sector-size != 0"); 1202 if (lp->d_sbsize == 0) { 1203 fprintf(stderr, "super block size %d\n", lp->d_sbsize); 1204 errors++; 1205 } else if (lp->d_sbsize % lp->d_secsize) 1206 Warning("super block size %% sector-size != 0"); 1207 if (lp->d_npartitions > MAXPARTITIONS) 1208 Warning("number of partitions (%d) > MAXPARTITIONS (%d)", 1209 lp->d_npartitions, MAXPARTITIONS); 1210 for (i = 0; i < lp->d_npartitions; i++) { 1211 part = 'a' + i; 1212 pp = &lp->d_partitions[i]; 1213 if (pp->p_size == 0 && pp->p_offset != 0) 1214 Warning("partition %c: size 0, but offset %d", 1215 part, pp->p_offset); 1216 #ifdef notdef 1217 if (pp->p_size % lp->d_secpercyl) 1218 Warning("partition %c: size %% cylinder-size != 0", 1219 part); 1220 if (pp->p_offset % lp->d_secpercyl) 1221 Warning("partition %c: offset %% cylinder-size != 0", 1222 part); 1223 #endif 1224 if (pp->p_offset > lp->d_secperunit) { 1225 fprintf(stderr, 1226 "partition %c: offset past end of unit\n", part); 1227 errors++; 1228 } 1229 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1230 fprintf(stderr, 1231 "partition %c: partition extends past end of unit\n", 1232 part); 1233 errors++; 1234 } 1235 } 1236 for (; i < MAXPARTITIONS; i++) { 1237 part = 'a' + i; 1238 pp = &lp->d_partitions[i]; 1239 if (pp->p_size || pp->p_offset) 1240 Warning("unused partition %c: size %d offset %d", 1241 'a' + i, pp->p_size, pp->p_offset); 1242 } 1243 return (errors); 1244 } 1245 1246 /* 1247 * If we are installing a boot program that doesn't fit in d_bbsize 1248 * we need to mark those partitions that the boot overflows into. 1249 * This allows newfs to prevent creation of a filesystem where it might 1250 * clobber bootstrap code. 1251 */ 1252 setbootflag(lp) 1253 register struct disklabel *lp; 1254 { 1255 register struct partition *pp; 1256 int i, errors = 0; 1257 char part; 1258 u_long boffset; 1259 1260 if (bootbuf == 0) 1261 return; 1262 boffset = bootsize / lp->d_secsize; 1263 for (i = 0; i < lp->d_npartitions; i++) { 1264 part = 'a' + i; 1265 pp = &lp->d_partitions[i]; 1266 if (pp->p_size == 0) 1267 continue; 1268 if (boffset <= pp->p_offset) { 1269 if (pp->p_fstype == FS_BOOT) 1270 pp->p_fstype = FS_UNUSED; 1271 } else if (pp->p_fstype != FS_BOOT) { 1272 if (pp->p_fstype != FS_UNUSED) { 1273 fprintf(stderr, 1274 "boot overlaps used partition %c\n", 1275 part); 1276 errors++; 1277 } else { 1278 pp->p_fstype = FS_BOOT; 1279 Warning("boot overlaps partition %c, %s", 1280 part, "marked as FS_BOOT"); 1281 } 1282 } 1283 } 1284 if (errors) { 1285 fprintf(stderr, "Cannot install boot program\n"); 1286 exit(4); 1287 } 1288 } 1289 1290 /*VARARGS1*/ 1291 Warning(fmt, a1, a2, a3, a4, a5) 1292 char *fmt; 1293 { 1294 1295 fprintf(stderr, "Warning, "); 1296 fprintf(stderr, fmt, a1, a2, a3, a4, a5); 1297 fprintf(stderr, "\n"); 1298 } 1299 1300 Perror(str) 1301 char *str; 1302 { 1303 fputs("disklabel: ", stderr); perror(str); 1304 exit(4); 1305 } 1306 1307 usage() 1308 { 1309 #if NUMBOOT > 0 1310 fprintf(stderr, 1311 "%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n", 1312 "usage: disklabel [-r] disk", 1313 "(to read label)", 1314 "or disklabel -w [-r] disk type [ packid ]", 1315 "(to write label with existing boot program)", 1316 "or disklabel -e [-r] disk", 1317 "(to edit label)", 1318 "or disklabel -R [-r] disk protofile", 1319 "(to restore label with existing boot program)", 1320 #if NUMBOOT > 1 1321 "or disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]", 1322 "(to install boot program with existing label)", 1323 "or disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", 1324 "(to write label and boot program)", 1325 "or disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", 1326 "(to restore label and boot program)", 1327 #else 1328 "or disklabel -B [ -b bootprog ] disk [ type ]", 1329 "(to install boot program with existing on-disk label)", 1330 "or disklabel -w -B [ -b bootprog ] disk type [ packid ]", 1331 "(to write label and install boot program)", 1332 "or disklabel -R -B [ -b bootprog ] disk protofile [ type ]", 1333 "(to restore label and install boot program)", 1334 #endif 1335 "or disklabel [-NW] disk", 1336 "(to write disable/enable label)"); 1337 #else 1338 fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n", 1339 "usage: disklabel [-r] disk", "(to read label)", 1340 "or disklabel -w [-r] disk type [ packid ]", "(to write label)", 1341 "or disklabel -e [-r] disk", "(to edit label)", 1342 "or disklabel -R [-r] disk protofile", "(to restore label)", 1343 "or disklabel [-NW] disk", "(to write disable/enable label)"); 1344 #endif 1345 exit(1); 1346 } 1347