bsdlabel.c revision 5393
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 38static 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 44static 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 95char *dkname; 96char *specname; 97char tmpfil[] = _PATH_TMP; 98 99extern int errno; 100char namebuf[BBSIZE], *np = namebuf; 101struct disklabel lab; 102struct disklabel *readlabel(), *makebootarea(); 103char bootarea[BBSIZE]; 104 105#if NUMBOOT > 0 106int installboot; /* non-zero if we should install a boot program */ 107char *bootbuf; /* pointer to buffer with remainder of boot prog */ 108int bootsize; /* size of remaining boot program */ 109char *xxboot; /* primary boot */ 110char *bootxx; /* secondary boot */ 111char boot0[MAXPATHLEN]; 112char boot1[MAXPATHLEN]; 113#endif 114 115enum { 116 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 117} op = UNSPEC; 118 119int rflag; 120 121#ifdef DEBUG 122int debug; 123#define OPTIONS "BNRWb:ders:w" 124#else 125#define OPTIONS "BNRWb:ers:w" 126#endif 127 128 129main(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 */ 311makelabel(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 357writelabel(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 431l_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 */ 471struct disklabel * 472readlabel(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 */ 506struct disklabel * 507makebootarea(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 639display(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, "rpm: %d\n", lp->d_rpm); 667 fprintf(f, "interleave: %d\n", lp->d_interleave); 668 fprintf(f, "trackskew: %d\n", lp->d_trackskew); 669 fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); 670 fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); 671 fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); 672 fprintf(f, "drivedata: "); 673 for (i = NDDATA - 1; i >= 0; i--) 674 if (lp->d_drivedata[i]) 675 break; 676 if (i < 0) 677 i = 0; 678 for (j = 0; j <= i; j++) 679 fprintf(f, "%d ", lp->d_drivedata[j]); 680 fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); 681 fprintf(f, 682 "# size offset fstype [fsize bsize bps/cpg]\n"); 683 pp = lp->d_partitions; 684 for (i = 0; i < lp->d_npartitions; i++, pp++) { 685 if (pp->p_size) { 686 fprintf(f, " %c: %8d %8d ", 'a' + i, 687 pp->p_size, pp->p_offset); 688 if ((unsigned) pp->p_fstype < FSMAXTYPES) 689 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 690 else 691 fprintf(f, "%8d", pp->p_fstype); 692 switch (pp->p_fstype) { 693 694 case FS_UNUSED: /* XXX */ 695 fprintf(f, " %5d %5d %5.5s ", 696 pp->p_fsize, pp->p_fsize * pp->p_frag, ""); 697 break; 698 699 case FS_BSDFFS: 700 fprintf(f, " %5d %5d %5d ", 701 pp->p_fsize, pp->p_fsize * pp->p_frag, 702 pp->p_cpg); 703 break; 704 705 case FS_BSDLFS: 706 fprintf(f, " %5d %5d %5d", 707 pp->p_fsize, pp->p_fsize * pp->p_frag, 708 pp->p_cpg); 709 break; 710 711 default: 712 fprintf(f, "%20.20s", ""); 713 break; 714 } 715 fprintf(f, "\t# (Cyl. %4d", 716 pp->p_offset / lp->d_secpercyl); 717 if (pp->p_offset % lp->d_secpercyl) 718 putc('*', f); 719 else 720 putc(' ', f); 721 fprintf(f, "- %d", 722 (pp->p_offset + 723 pp->p_size + lp->d_secpercyl - 1) / 724 lp->d_secpercyl - 1); 725 if (pp->p_size % lp->d_secpercyl) 726 putc('*', f); 727 fprintf(f, ")\n"); 728 } 729 } 730 fflush(f); 731} 732 733edit(lp, f) 734 struct disklabel *lp; 735 int f; 736{ 737 register int c; 738 struct disklabel label; 739 FILE *fd; 740 char *mktemp(); 741 742 (void) mktemp(tmpfil); 743 fd = fopen(tmpfil, "w"); 744 if (fd == NULL) { 745 fprintf(stderr, "%s: Can't create\n", tmpfil); 746 return (1); 747 } 748 (void)fchmod(fileno(fd), 0600); 749 display(fd, lp); 750 fclose(fd); 751 for (;;) { 752 if (!editit()) 753 break; 754 fd = fopen(tmpfil, "r"); 755 if (fd == NULL) { 756 fprintf(stderr, "%s: Can't reopen for reading\n", 757 tmpfil); 758 break; 759 } 760 bzero((char *)&label, sizeof(label)); 761 if (getasciilabel(fd, &label)) { 762 *lp = label; 763 if (writelabel(f, bootarea, lp) == 0) { 764 (void) unlink(tmpfil); 765 return (0); 766 } 767 } 768 printf("re-edit the label? [y]: "); fflush(stdout); 769 c = getchar(); 770 if (c != EOF && c != (int)'\n') 771 while (getchar() != (int)'\n') 772 ; 773 if (c == (int)'n') 774 break; 775 } 776 (void) unlink(tmpfil); 777 return (1); 778} 779 780editit() 781{ 782 register int pid, xpid; 783 int stat, omask; 784 extern char *getenv(); 785 786 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 787 while ((pid = fork()) < 0) { 788 extern int errno; 789 790 if (errno == EPROCLIM) { 791 fprintf(stderr, "You have too many processes\n"); 792 return(0); 793 } 794 if (errno != EAGAIN) { 795 perror("fork"); 796 return(0); 797 } 798 sleep(1); 799 } 800 if (pid == 0) { 801 register char *ed; 802 803 sigsetmask(omask); 804 setgid(getgid()); 805 setuid(getuid()); 806 if ((ed = getenv("EDITOR")) == (char *)0) 807 ed = DEFEDITOR; 808 execlp(ed, ed, tmpfil, 0); 809 perror(ed); 810 exit(1); 811 } 812 while ((xpid = wait(&stat)) >= 0) 813 if (xpid == pid) 814 break; 815 sigsetmask(omask); 816 return(!stat); 817} 818 819char * 820skip(cp) 821 register char *cp; 822{ 823 824 while (*cp != '\0' && isspace(*cp)) 825 cp++; 826 if (*cp == '\0' || *cp == '#') 827 return ((char *)NULL); 828 return (cp); 829} 830 831char * 832word(cp) 833 register char *cp; 834{ 835 register char c; 836 837 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 838 cp++; 839 if ((c = *cp) != '\0') { 840 *cp++ = '\0'; 841 if (c != '#') 842 return (skip(cp)); 843 } 844 return ((char *)NULL); 845} 846 847/* 848 * Read an ascii label in from fd f, 849 * in the same format as that put out by display(), 850 * and fill in lp. 851 */ 852getasciilabel(f, lp) 853 FILE *f; 854 register struct disklabel *lp; 855{ 856 register char **cpp, *cp; 857 register struct partition *pp; 858 char *tp, *s, line[BUFSIZ]; 859 int v, lineno = 0, errors = 0; 860 861 lp->d_bbsize = BBSIZE; /* XXX */ 862 lp->d_sbsize = SBSIZE; /* XXX */ 863 while (fgets(line, sizeof(line) - 1, f)) { 864 lineno++; 865 if (cp = index(line,'\n')) 866 *cp = '\0'; 867 cp = skip(line); 868 if (cp == NULL) 869 continue; 870 tp = index(cp, ':'); 871 if (tp == NULL) { 872 fprintf(stderr, "line %d: syntax error\n", lineno); 873 errors++; 874 continue; 875 } 876 *tp++ = '\0', tp = skip(tp); 877 if (streq(cp, "type")) { 878 if (tp == NULL) 879 tp = "unknown"; 880 cpp = dktypenames; 881 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 882 if ((s = *cpp) && streq(s, tp)) { 883 lp->d_type = cpp - dktypenames; 884 goto next; 885 } 886 v = atoi(tp); 887 if ((unsigned)v >= DKMAXTYPES) 888 fprintf(stderr, "line %d:%s %d\n", lineno, 889 "Warning, unknown disk type", v); 890 lp->d_type = v; 891 continue; 892 } 893 if (streq(cp, "flags")) { 894 for (v = 0; (cp = tp) && *cp != '\0';) { 895 tp = word(cp); 896 if (streq(cp, "removeable")) 897 v |= D_REMOVABLE; 898 else if (streq(cp, "ecc")) 899 v |= D_ECC; 900 else if (streq(cp, "badsect")) 901 v |= D_BADSECT; 902 else { 903 fprintf(stderr, 904 "line %d: %s: bad flag\n", 905 lineno, cp); 906 errors++; 907 } 908 } 909 lp->d_flags = v; 910 continue; 911 } 912 if (streq(cp, "drivedata")) { 913 register int i; 914 915 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 916 lp->d_drivedata[i++] = atoi(cp); 917 tp = word(cp); 918 } 919 continue; 920 } 921 if (sscanf(cp, "%d partitions", &v) == 1) { 922 if (v == 0 || (unsigned)v > MAXPARTITIONS) { 923 fprintf(stderr, 924 "line %d: bad # of partitions\n", lineno); 925 lp->d_npartitions = MAXPARTITIONS; 926 errors++; 927 } else 928 lp->d_npartitions = v; 929 continue; 930 } 931 if (tp == NULL) 932 tp = ""; 933 if (streq(cp, "disk")) { 934 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 935 continue; 936 } 937 if (streq(cp, "label")) { 938 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 939 continue; 940 } 941 if (streq(cp, "bytes/sector")) { 942 v = atoi(tp); 943 if (v <= 0 || (v % 512) != 0) { 944 fprintf(stderr, 945 "line %d: %s: bad sector size\n", 946 lineno, tp); 947 errors++; 948 } else 949 lp->d_secsize = v; 950 continue; 951 } 952 if (streq(cp, "sectors/track")) { 953 v = atoi(tp); 954 if (v <= 0) { 955 fprintf(stderr, "line %d: %s: bad %s\n", 956 lineno, tp, cp); 957 errors++; 958 } else 959 lp->d_nsectors = v; 960 continue; 961 } 962 if (streq(cp, "sectors/cylinder")) { 963 v = atoi(tp); 964 if (v <= 0) { 965 fprintf(stderr, "line %d: %s: bad %s\n", 966 lineno, tp, cp); 967 errors++; 968 } else 969 lp->d_secpercyl = v; 970 continue; 971 } 972 if (streq(cp, "tracks/cylinder")) { 973 v = atoi(tp); 974 if (v <= 0) { 975 fprintf(stderr, "line %d: %s: bad %s\n", 976 lineno, tp, cp); 977 errors++; 978 } else 979 lp->d_ntracks = v; 980 continue; 981 } 982 if (streq(cp, "cylinders")) { 983 v = atoi(tp); 984 if (v <= 0) { 985 fprintf(stderr, "line %d: %s: bad %s\n", 986 lineno, tp, cp); 987 errors++; 988 } else 989 lp->d_ncylinders = v; 990 continue; 991 } 992 if (streq(cp, "rpm")) { 993 v = atoi(tp); 994 if (v <= 0) { 995 fprintf(stderr, "line %d: %s: bad %s\n", 996 lineno, tp, cp); 997 errors++; 998 } else 999 lp->d_rpm = v; 1000 continue; 1001 } 1002 if (streq(cp, "interleave")) { 1003 v = atoi(tp); 1004 if (v <= 0) { 1005 fprintf(stderr, "line %d: %s: bad %s\n", 1006 lineno, tp, cp); 1007 errors++; 1008 } else 1009 lp->d_interleave = v; 1010 continue; 1011 } 1012 if (streq(cp, "trackskew")) { 1013 v = atoi(tp); 1014 if (v < 0) { 1015 fprintf(stderr, "line %d: %s: bad %s\n", 1016 lineno, tp, cp); 1017 errors++; 1018 } else 1019 lp->d_trackskew = v; 1020 continue; 1021 } 1022 if (streq(cp, "cylinderskew")) { 1023 v = atoi(tp); 1024 if (v < 0) { 1025 fprintf(stderr, "line %d: %s: bad %s\n", 1026 lineno, tp, cp); 1027 errors++; 1028 } else 1029 lp->d_cylskew = v; 1030 continue; 1031 } 1032 if (streq(cp, "headswitch")) { 1033 v = atoi(tp); 1034 if (v < 0) { 1035 fprintf(stderr, "line %d: %s: bad %s\n", 1036 lineno, tp, cp); 1037 errors++; 1038 } else 1039 lp->d_headswitch = v; 1040 continue; 1041 } 1042 if (streq(cp, "track-to-track seek")) { 1043 v = atoi(tp); 1044 if (v < 0) { 1045 fprintf(stderr, "line %d: %s: bad %s\n", 1046 lineno, tp, cp); 1047 errors++; 1048 } else 1049 lp->d_trkseek = v; 1050 continue; 1051 } 1052 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 1053 unsigned part = *cp - 'a'; 1054 1055 if (part > lp->d_npartitions) { 1056 fprintf(stderr, 1057 "line %d: bad partition name\n", lineno); 1058 errors++; 1059 continue; 1060 } 1061 pp = &lp->d_partitions[part]; 1062#define NXTNUM(n) { \ 1063 if (tp == NULL) { \ 1064 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 1065 errors++; \ 1066 break; \ 1067 } else { \ 1068 cp = tp, tp = word(cp); \ 1069 if (tp == NULL) \ 1070 tp = cp; \ 1071 (n) = atoi(cp); \ 1072 } \ 1073 } 1074 1075 NXTNUM(v); 1076 if (v < 0) { 1077 fprintf(stderr, 1078 "line %d: %s: bad partition size\n", 1079 lineno, cp); 1080 errors++; 1081 } else 1082 pp->p_size = v; 1083 NXTNUM(v); 1084 if (v < 0) { 1085 fprintf(stderr, 1086 "line %d: %s: bad partition offset\n", 1087 lineno, cp); 1088 errors++; 1089 } else 1090 pp->p_offset = v; 1091 cp = tp, tp = word(cp); 1092 cpp = fstypenames; 1093 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 1094 if ((s = *cpp) && streq(s, cp)) { 1095 pp->p_fstype = cpp - fstypenames; 1096 goto gottype; 1097 } 1098 if (isdigit(*cp)) 1099 v = atoi(cp); 1100 else 1101 v = FSMAXTYPES; 1102 if ((unsigned)v >= FSMAXTYPES) { 1103 fprintf(stderr, "line %d: %s %s\n", lineno, 1104 "Warning, unknown filesystem type", cp); 1105 v = FS_UNUSED; 1106 } 1107 pp->p_fstype = v; 1108 gottype: 1109 1110 switch (pp->p_fstype) { 1111 1112 case FS_UNUSED: /* XXX */ 1113 NXTNUM(pp->p_fsize); 1114 if (pp->p_fsize == 0) 1115 break; 1116 NXTNUM(v); 1117 pp->p_frag = v / pp->p_fsize; 1118 break; 1119 1120 case FS_BSDFFS: 1121 NXTNUM(pp->p_fsize); 1122 if (pp->p_fsize == 0) 1123 break; 1124 NXTNUM(v); 1125 pp->p_frag = v / pp->p_fsize; 1126 NXTNUM(pp->p_cpg); 1127 break; 1128 1129 case FS_BSDLFS: 1130 NXTNUM(pp->p_fsize); 1131 if (pp->p_fsize == 0) 1132 break; 1133 NXTNUM(v); 1134 pp->p_frag = v / pp->p_fsize; 1135 NXTNUM(pp->p_cpg); 1136 break; 1137 1138 default: 1139 break; 1140 } 1141 continue; 1142 } 1143 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1144 lineno, cp); 1145 errors++; 1146 next: 1147 ; 1148 } 1149 errors += checklabel(lp); 1150 return (errors == 0); 1151} 1152 1153/* 1154 * Check disklabel for errors and fill in 1155 * derived fields according to supplied values. 1156 */ 1157checklabel(lp) 1158 register struct disklabel *lp; 1159{ 1160 register struct partition *pp; 1161 int i, errors = 0; 1162 char part; 1163 1164 if (lp->d_secsize == 0) { 1165 fprintf(stderr, "sector size %d\n", lp->d_secsize); 1166 return (1); 1167 } 1168 if (lp->d_nsectors == 0) { 1169 fprintf(stderr, "sectors/track %d\n", lp->d_nsectors); 1170 return (1); 1171 } 1172 if (lp->d_ntracks == 0) { 1173 fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks); 1174 return (1); 1175 } 1176 if (lp->d_ncylinders == 0) { 1177 fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders); 1178 errors++; 1179 } 1180 if (lp->d_rpm == 0) 1181 Warning("revolutions/minute %d", lp->d_rpm); 1182 if (lp->d_secpercyl == 0) 1183 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1184 if (lp->d_secperunit == 0) 1185 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1186 if (lp->d_bbsize == 0) { 1187 fprintf(stderr, "boot block size %d\n", lp->d_bbsize); 1188 errors++; 1189 } else if (lp->d_bbsize % lp->d_secsize) 1190 Warning("boot block size %% sector-size != 0"); 1191 if (lp->d_sbsize == 0) { 1192 fprintf(stderr, "super block size %d\n", lp->d_sbsize); 1193 errors++; 1194 } else if (lp->d_sbsize % lp->d_secsize) 1195 Warning("super block size %% sector-size != 0"); 1196 if (lp->d_npartitions > MAXPARTITIONS) 1197 Warning("number of partitions (%d) > MAXPARTITIONS (%d)", 1198 lp->d_npartitions, MAXPARTITIONS); 1199 for (i = 0; i < lp->d_npartitions; i++) { 1200 part = 'a' + i; 1201 pp = &lp->d_partitions[i]; 1202 if (pp->p_size == 0 && pp->p_offset != 0) 1203 Warning("partition %c: size 0, but offset %d", 1204 part, pp->p_offset); 1205#ifdef notdef 1206 if (pp->p_size % lp->d_secpercyl) 1207 Warning("partition %c: size %% cylinder-size != 0", 1208 part); 1209 if (pp->p_offset % lp->d_secpercyl) 1210 Warning("partition %c: offset %% cylinder-size != 0", 1211 part); 1212#endif 1213 if (pp->p_offset > lp->d_secperunit) { 1214 fprintf(stderr, 1215 "partition %c: offset past end of unit\n", part); 1216 errors++; 1217 } 1218 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1219 fprintf(stderr, 1220 "partition %c: partition extends past end of unit\n", 1221 part); 1222 errors++; 1223 } 1224 } 1225 for (; i < MAXPARTITIONS; i++) { 1226 part = 'a' + i; 1227 pp = &lp->d_partitions[i]; 1228 if (pp->p_size || pp->p_offset) 1229 Warning("unused partition %c: size %d offset %d", 1230 'a' + i, pp->p_size, pp->p_offset); 1231 } 1232 return (errors); 1233} 1234 1235/* 1236 * If we are installing a boot program that doesn't fit in d_bbsize 1237 * we need to mark those partitions that the boot overflows into. 1238 * This allows newfs to prevent creation of a filesystem where it might 1239 * clobber bootstrap code. 1240 */ 1241setbootflag(lp) 1242 register struct disklabel *lp; 1243{ 1244 register struct partition *pp; 1245 int i, errors = 0; 1246 char part; 1247 u_long boffset; 1248 1249 if (bootbuf == 0) 1250 return; 1251 boffset = bootsize / lp->d_secsize; 1252 for (i = 0; i < lp->d_npartitions; i++) { 1253 part = 'a' + i; 1254 pp = &lp->d_partitions[i]; 1255 if (pp->p_size == 0) 1256 continue; 1257 if (boffset <= pp->p_offset) { 1258 if (pp->p_fstype == FS_BOOT) 1259 pp->p_fstype = FS_UNUSED; 1260 } else if (pp->p_fstype != FS_BOOT) { 1261 if (pp->p_fstype != FS_UNUSED) { 1262 fprintf(stderr, 1263 "boot overlaps used partition %c\n", 1264 part); 1265 errors++; 1266 } else { 1267 pp->p_fstype = FS_BOOT; 1268 Warning("boot overlaps partition %c, %s", 1269 part, "marked as FS_BOOT"); 1270 } 1271 } 1272 } 1273 if (errors) { 1274 fprintf(stderr, "Cannot install boot program\n"); 1275 exit(4); 1276 } 1277} 1278 1279/*VARARGS1*/ 1280Warning(fmt, a1, a2, a3, a4, a5) 1281 char *fmt; 1282{ 1283 1284 fprintf(stderr, "Warning, "); 1285 fprintf(stderr, fmt, a1, a2, a3, a4, a5); 1286 fprintf(stderr, "\n"); 1287} 1288 1289Perror(str) 1290 char *str; 1291{ 1292 fputs("disklabel: ", stderr); perror(str); 1293 exit(4); 1294} 1295 1296usage() 1297{ 1298#if NUMBOOT > 0 1299 fprintf(stderr, 1300"%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", 1301"usage: disklabel [-r] disk", 1302 "(to read label)", 1303"or disklabel -w [-r] disk type [ packid ]", 1304 "(to write label with existing boot program)", 1305"or disklabel -e [-r] disk", 1306 "(to edit label)", 1307"or disklabel -R [-r] disk protofile", 1308 "(to restore label with existing boot program)", 1309#if NUMBOOT > 1 1310"or disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]", 1311 "(to install boot program with existing label)", 1312"or disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]", 1313 "(to write label and boot program)", 1314"or disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]", 1315 "(to restore label and boot program)", 1316#else 1317"or disklabel -B [ -b bootprog ] disk [ type ]", 1318 "(to install boot program with existing on-disk label)", 1319"or disklabel -w -B [ -b bootprog ] disk type [ packid ]", 1320 "(to write label and install boot program)", 1321"or disklabel -R -B [ -b bootprog ] disk protofile [ type ]", 1322 "(to restore label and install boot program)", 1323#endif 1324"or disklabel [-NW] disk", 1325 "(to write disable/enable label)"); 1326#else 1327 fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n", 1328"usage: disklabel [-r] disk", "(to read label)", 1329"or disklabel -w [-r] disk type [ packid ]", "(to write label)", 1330"or disklabel -e [-r] disk", "(to edit label)", 1331"or disklabel -R [-r] disk protofile", "(to restore label)", 1332"or disklabel [-NW] disk", "(to write disable/enable label)"); 1333#endif 1334 exit(1); 1335} 1336