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