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