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