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