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