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