1 /* 2 * Copyright (c) 1994, 1995 Gordon W. Ross 3 * Copyright (c) 1994 Theo de Raadt 4 * All rights reserved. 5 * Copyright (c) 1987, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Symmetric Computer Systems. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * This product includes software developed by Theo de Raadt. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $ 41 */ 42 43 #if 0 44 #ifndef lint 45 static const char copyright[] = 46 "@(#) Copyright (c) 1987, 1993\n\ 47 The Regents of the University of California. All rights reserved.\n"; 48 #endif /* not lint */ 49 50 #ifndef lint 51 static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94"; 52 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 53 #endif /* not lint */ 54 #endif 55 #include <sys/cdefs.h> 56 __FBSDID("$FreeBSD$"); 57 58 #include <sys/param.h> 59 #include <stdint.h> 60 #include <sys/file.h> 61 #include <sys/stat.h> 62 #include <sys/wait.h> 63 #include <sys/disk.h> 64 #define DKTYPENAMES 65 #define FSTYPENAMES 66 #include <sys/disklabel.h> 67 68 #include <unistd.h> 69 #include <string.h> 70 #include <stdio.h> 71 #include <libgeom.h> 72 #include <stdlib.h> 73 #include <signal.h> 74 #include <stdarg.h> 75 #include <ctype.h> 76 #include <err.h> 77 #include <errno.h> 78 79 #include "pathnames.h" 80 81 /* FIX! These are too low, but are traditional */ 82 #define DEFAULT_NEWFS_BLOCK 8192U 83 #define DEFAULT_NEWFS_FRAG 1024U 84 #define DEFAULT_NEWFS_CPG 16U 85 86 #define BIG_NEWFS_BLOCK 16384U 87 #define BIG_NEWFS_FRAG 2048U 88 #define BIG_NEWFS_CPG 64U 89 90 static void makelabel(const char *, struct disklabel *); 91 static int writelabel(void); 92 static int readlabel(int flag); 93 static void display(FILE *, const struct disklabel *); 94 static int edit(void); 95 static int editit(void); 96 static char *skip(char *); 97 static char *word(char *); 98 static int getasciilabel(FILE *, struct disklabel *); 99 static int getasciipartspec(char *, struct disklabel *, int, int); 100 static int checklabel(struct disklabel *); 101 static void usage(void); 102 static struct disklabel *getvirginlabel(void); 103 104 #define DEFEDITOR _PATH_VI 105 106 static char *dkname; 107 static char *specname; 108 static char tmpfil[] = PATH_TMPFILE; 109 110 static struct disklabel lab; 111 static u_char bootarea[BBSIZE]; 112 static off_t mediasize; 113 static u_int secsize; 114 static char blank[] = ""; 115 static char unknown[] = "unknown"; 116 117 #define MAX_PART ('z') 118 #define MAX_NUM_PARTS (1 + MAX_PART - 'a') 119 static char part_size_type[MAX_NUM_PARTS]; 120 static char part_offset_type[MAX_NUM_PARTS]; 121 static int part_set[MAX_NUM_PARTS]; 122 123 static int installboot; /* non-zero if we should install a boot program */ 124 static int allfields; /* present all fields in edit */ 125 static char const *xxboot; /* primary boot */ 126 127 static off_t mbroffset; 128 #ifndef LABELSECTOR 129 #define LABELSECTOR -1 130 #endif 131 #ifndef LABELOFFSET 132 #define LABELOFFSET -1 133 #endif 134 static int labelsoffset = LABELSECTOR; 135 static int labeloffset = LABELOFFSET; 136 static int bbsize = BBSIZE; 137 static int alphacksum = 138 #if defined(__alpha__) 139 1; 140 #else 141 0; 142 #endif 143 144 enum { 145 UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT 146 } op = UNSPEC; 147 148 149 static int disable_write; /* set to disable writing to disk label */ 150 151 int 152 main(int argc, char *argv[]) 153 { 154 FILE *t; 155 int ch, error = 0; 156 char const *name = 0; 157 158 while ((ch = getopt(argc, argv, "ABb:em:nRrs:w")) != -1) 159 switch (ch) { 160 case 'A': 161 allfields = 1; 162 break; 163 case 'B': 164 ++installboot; 165 break; 166 case 'b': 167 xxboot = optarg; 168 break; 169 case 'm': 170 if (!strcmp(optarg, "i386") || 171 !strcmp(optarg, "amd64") || 172 !strcmp(optarg, "ia64") || 173 !strcmp(optarg, "pc98")) { 174 labelsoffset = 1; 175 labeloffset = 0; 176 bbsize = 8192; 177 alphacksum = 0; 178 } else if (!strcmp(optarg, "alpha")) { 179 labelsoffset = 0; 180 labeloffset = 64; 181 bbsize = 8192; 182 alphacksum = 1; 183 } else { 184 errx(1, "Unsupported architecture"); 185 } 186 break; 187 case 'n': 188 disable_write = 1; 189 break; 190 case 'R': 191 if (op != UNSPEC) 192 usage(); 193 op = RESTORE; 194 break; 195 case 'e': 196 if (op != UNSPEC) 197 usage(); 198 op = EDIT; 199 break; 200 case 'r': 201 /* 202 * We accept and ignode -r for compatibility with 203 * historically disklabel usage. 204 */ 205 break; 206 case 'w': 207 if (op != UNSPEC) 208 usage(); 209 op = WRITE; 210 break; 211 case '?': 212 default: 213 usage(); 214 } 215 argc -= optind; 216 argv += optind; 217 218 if (argc < 1) 219 usage(); 220 if (labelsoffset < 0 || labeloffset < 0) 221 errx(1, "a -m <architecture> option must be specified"); 222 223 /* Figure out the names of the thing we're working on */ 224 if (argv[0][0] != '/') { 225 dkname = argv[0]; 226 asprintf(&specname, "%s%s", _PATH_DEV, argv[0]); 227 } else { 228 dkname = strrchr(argv[0], '/'); 229 dkname++; 230 specname = argv[0]; 231 } 232 233 if (installboot && op == UNSPEC) 234 op = WRITEBOOT; 235 else if (op == UNSPEC) 236 op = READ; 237 238 switch(op) { 239 240 case UNSPEC: 241 break; 242 243 case EDIT: 244 if (argc != 1) 245 usage(); 246 readlabel(1); 247 error = edit(); 248 break; 249 250 case READ: 251 if (argc != 1) 252 usage(); 253 readlabel(1); 254 display(stdout, NULL); 255 error = checklabel(NULL); 256 break; 257 258 case RESTORE: 259 if (argc != 2) 260 usage(); 261 if (!(t = fopen(argv[1], "r"))) 262 err(4, "fopen %s", argv[1]); 263 readlabel(0); 264 if (!getasciilabel(t, &lab)) 265 exit(1); 266 error = writelabel(); 267 break; 268 269 case WRITE: 270 if (argc == 2) 271 name = argv[1]; 272 else if (argc == 1) 273 name = "auto"; 274 else 275 usage(); 276 readlabel(0); 277 makelabel(name, &lab); 278 if (checklabel(NULL) == 0) 279 error = writelabel(); 280 break; 281 282 case WRITEBOOT: 283 284 readlabel(1); 285 if (argc == 2) 286 makelabel(argv[1], &lab); 287 if (checklabel(NULL) == 0) 288 error = writelabel(); 289 break; 290 } 291 exit(error); 292 } 293 294 /* 295 * Construct a prototype disklabel from /etc/disktab. 296 */ 297 static void 298 makelabel(const char *type, struct disklabel *lp) 299 { 300 struct disklabel *dp; 301 302 if (strcmp(type, "auto") == 0) 303 dp = getvirginlabel(); 304 else 305 dp = getdiskbyname(type); 306 if (dp == NULL) 307 errx(1, "%s: unknown disk type", type); 308 *lp = *dp; 309 bzero(lp->d_packname, sizeof(lp->d_packname)); 310 } 311 312 static void 313 readboot(void) 314 { 315 int fd, i; 316 struct stat st; 317 318 if (xxboot == NULL) 319 xxboot = "/boot/boot"; 320 fd = open(xxboot, O_RDONLY); 321 if (fd < 0) 322 err(1, "cannot open %s", xxboot); 323 fstat(fd, &st); 324 if (alphacksum && st.st_size <= BBSIZE - 512) { 325 i = read(fd, bootarea + 512, st.st_size); 326 if (i != st.st_size) 327 err(1, "read error %s", xxboot); 328 return; 329 } else if ((!alphacksum) && st.st_size <= BBSIZE) { 330 i = read(fd, bootarea, st.st_size); 331 if (i != st.st_size) 332 err(1, "read error %s", xxboot); 333 return; 334 } 335 errx(1, "boot code %s is wrong size", xxboot); 336 } 337 338 static int 339 writelabel(void) 340 { 341 uint64_t *p, sum; 342 int i, fd; 343 struct gctl_req *grq; 344 char const *errstr; 345 struct disklabel *lp = &lab; 346 347 if (disable_write) { 348 warnx("write to disk label supressed - label was as follows:"); 349 display(stdout, NULL); 350 return (0); 351 } 352 353 lp->d_magic = DISKMAGIC; 354 lp->d_magic2 = DISKMAGIC; 355 lp->d_checksum = 0; 356 lp->d_checksum = dkcksum(lp); 357 if (installboot) 358 readboot(); 359 for (i = 0; i < lab.d_npartitions; i++) 360 if (lab.d_partitions[i].p_size) 361 lab.d_partitions[i].p_offset += mbroffset; 362 bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize, 363 lp); 364 if (alphacksum) { 365 /* Generate the bootblock checksum for the SRM console. */ 366 for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++) 367 sum += p[i]; 368 p[63] = sum; 369 } 370 371 fd = open(specname, O_RDWR); 372 if (fd < 0) { 373 grq = gctl_get_handle(); 374 gctl_ro_param(grq, "verb", -1, "write label"); 375 gctl_ro_param(grq, "class", -1, "BSD"); 376 gctl_ro_param(grq, "geom", -1, dkname); 377 gctl_ro_param(grq, "label", 148+16*8, 378 bootarea + labeloffset + labelsoffset * secsize); 379 errstr = gctl_issue(grq); 380 if (errstr != NULL) { 381 warnx("%s", errstr); 382 gctl_free(grq); 383 return(1); 384 } 385 gctl_free(grq); 386 if (installboot) { 387 grq = gctl_get_handle(); 388 gctl_ro_param(grq, "verb", -1, "write bootcode"); 389 gctl_ro_param(grq, "class", -1, "BSD"); 390 gctl_ro_param(grq, "geom", -1, dkname); 391 gctl_ro_param(grq, "bootcode", BBSIZE, bootarea); 392 errstr = gctl_issue(grq); 393 if (errstr != NULL) { 394 warnx("%s", errstr); 395 gctl_free(grq); 396 return (1); 397 } 398 gctl_free(grq); 399 } 400 } else { 401 if (write(fd, bootarea, bbsize) != bbsize) { 402 warn("write %s", specname); 403 close (fd); 404 return (1); 405 } 406 close (fd); 407 } 408 return (0); 409 } 410 411 /* 412 * Fetch disklabel for disk. 413 * Use ioctl to get label unless -r flag is given. 414 */ 415 static int 416 readlabel(int flag) 417 { 418 int f, i; 419 int error; 420 struct gctl_req *grq; 421 char const *errstr; 422 423 f = open(specname, O_RDONLY); 424 if (f < 0) 425 err(1, specname); 426 /* New world order */ 427 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) || 428 (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) { 429 err(4, "cannot get disk geometry"); 430 } 431 (void)lseek(f, (off_t)0, SEEK_SET); 432 if (read(f, bootarea, BBSIZE) != BBSIZE) 433 err(4, "%s read", specname); 434 close (f); 435 error = bsd_disklabel_le_dec( 436 bootarea + (labeloffset + labelsoffset * secsize), 437 &lab, MAXPARTITIONS); 438 if (flag && error) 439 errx(1, "%s: no valid label found", specname); 440 441 grq = gctl_get_handle(); 442 gctl_ro_param(grq, "verb", -1, "read mbroffset"); 443 gctl_ro_param(grq, "class", -1, "BSD"); 444 gctl_ro_param(grq, "geom", -1, dkname); 445 gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset); 446 errstr = gctl_issue(grq); 447 if (errstr != NULL) { 448 mbroffset = 0; 449 gctl_free(grq); 450 return (error); 451 } 452 mbroffset /= lab.d_secsize; 453 if (lab.d_partitions[RAW_PART].p_offset == mbroffset) 454 for (i = 0; i < lab.d_npartitions; i++) 455 if (lab.d_partitions[i].p_size) 456 lab.d_partitions[i].p_offset -= mbroffset; 457 return (error); 458 } 459 460 461 static void 462 display(FILE *f, const struct disklabel *lp) 463 { 464 int i, j; 465 const struct partition *pp; 466 467 if (lp == NULL) 468 lp = &lab; 469 470 fprintf(f, "# %s:\n", specname); 471 if (allfields) { 472 if (lp->d_type < DKMAXTYPES) 473 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 474 else 475 fprintf(f, "type: %u\n", lp->d_type); 476 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), 477 lp->d_typename); 478 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 479 lp->d_packname); 480 fprintf(f, "flags:"); 481 if (lp->d_flags & D_REMOVABLE) 482 fprintf(f, " removeable"); 483 if (lp->d_flags & D_ECC) 484 fprintf(f, " ecc"); 485 if (lp->d_flags & D_BADSECT) 486 fprintf(f, " badsect"); 487 fprintf(f, "\n"); 488 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize); 489 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors); 490 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks); 491 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl); 492 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders); 493 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit); 494 fprintf(f, "rpm: %u\n", lp->d_rpm); 495 fprintf(f, "interleave: %u\n", lp->d_interleave); 496 fprintf(f, "trackskew: %u\n", lp->d_trackskew); 497 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew); 498 fprintf(f, "headswitch: %lu\t\t# milliseconds\n", 499 (u_long)lp->d_headswitch); 500 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", 501 (u_long)lp->d_trkseek); 502 fprintf(f, "drivedata: "); 503 for (i = NDDATA - 1; i >= 0; i--) 504 if (lp->d_drivedata[i]) 505 break; 506 if (i < 0) 507 i = 0; 508 for (j = 0; j <= i; j++) 509 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]); 510 fprintf(f, "\n\n"); 511 } 512 fprintf(f, "%u partitions:\n", lp->d_npartitions); 513 fprintf(f, 514 "# size offset fstype [fsize bsize bps/cpg]\n"); 515 pp = lp->d_partitions; 516 for (i = 0; i < lp->d_npartitions; i++, pp++) { 517 if (pp->p_size) { 518 fprintf(f, " %c: %8lu %8lu ", 'a' + i, 519 (u_long)pp->p_size, (u_long)pp->p_offset); 520 if (pp->p_fstype < FSMAXTYPES) 521 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 522 else 523 fprintf(f, "%8d", pp->p_fstype); 524 switch (pp->p_fstype) { 525 526 case FS_UNUSED: /* XXX */ 527 fprintf(f, " %5lu %5lu %5.5s ", 528 (u_long)pp->p_fsize, 529 (u_long)(pp->p_fsize * pp->p_frag), ""); 530 break; 531 532 case FS_BSDFFS: 533 fprintf(f, " %5lu %5lu %5u ", 534 (u_long)pp->p_fsize, 535 (u_long)(pp->p_fsize * pp->p_frag), 536 pp->p_cpg); 537 break; 538 539 case FS_BSDLFS: 540 fprintf(f, " %5lu %5lu %5d", 541 (u_long)pp->p_fsize, 542 (u_long)(pp->p_fsize * pp->p_frag), 543 pp->p_cpg); 544 break; 545 546 default: 547 fprintf(f, "%20.20s", ""); 548 break; 549 } 550 if (i == RAW_PART) { 551 fprintf(f, " # \"raw\" part, don't edit"); 552 } 553 fprintf(f, "\n"); 554 } 555 } 556 fflush(f); 557 } 558 559 static int 560 edit(void) 561 { 562 int c, fd; 563 struct disklabel label; 564 FILE *fp; 565 566 if ((fd = mkstemp(tmpfil)) == -1 || 567 (fp = fdopen(fd, "w")) == NULL) { 568 warnx("can't create %s", tmpfil); 569 return (1); 570 } 571 display(fp, NULL); 572 fclose(fp); 573 for (;;) { 574 if (!editit()) 575 break; 576 fp = fopen(tmpfil, "r"); 577 if (fp == NULL) { 578 warnx("can't reopen %s for reading", tmpfil); 579 break; 580 } 581 bzero((char *)&label, sizeof(label)); 582 c = getasciilabel(fp, &label); 583 fclose(fp); 584 if (c) { 585 lab = label; 586 if (writelabel() == 0) { 587 (void) unlink(tmpfil); 588 return (0); 589 } 590 } 591 printf("re-edit the label? [y]: "); 592 fflush(stdout); 593 c = getchar(); 594 if (c != EOF && c != (int)'\n') 595 while (getchar() != (int)'\n') 596 ; 597 if (c == (int)'n') 598 break; 599 } 600 (void) unlink(tmpfil); 601 return (1); 602 } 603 604 static int 605 editit(void) 606 { 607 int pid, xpid; 608 int locstat, omask; 609 const char *ed; 610 611 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 612 while ((pid = fork()) < 0) { 613 if (errno == EPROCLIM) { 614 warnx("you have too many processes"); 615 return(0); 616 } 617 if (errno != EAGAIN) { 618 warn("fork"); 619 return(0); 620 } 621 sleep(1); 622 } 623 if (pid == 0) { 624 sigsetmask(omask); 625 setgid(getgid()); 626 setuid(getuid()); 627 if ((ed = getenv("EDITOR")) == (char *)0) 628 ed = DEFEDITOR; 629 execlp(ed, ed, tmpfil, (char *)0); 630 err(1, "%s", ed); 631 } 632 while ((xpid = wait(&locstat)) >= 0) 633 if (xpid == pid) 634 break; 635 sigsetmask(omask); 636 return(!locstat); 637 } 638 639 static char * 640 skip(char *cp) 641 { 642 643 while (*cp != '\0' && isspace(*cp)) 644 cp++; 645 if (*cp == '\0' || *cp == '#') 646 return (NULL); 647 return (cp); 648 } 649 650 static char * 651 word(char *cp) 652 { 653 char c; 654 655 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 656 cp++; 657 if ((c = *cp) != '\0') { 658 *cp++ = '\0'; 659 if (c != '#') 660 return (skip(cp)); 661 } 662 return (NULL); 663 } 664 665 /* 666 * Read an ascii label in from fd f, 667 * in the same format as that put out by display(), 668 * and fill in lp. 669 */ 670 static int 671 getasciilabel(FILE *f, struct disklabel *lp) 672 { 673 char *cp; 674 const char **cpp; 675 u_int part; 676 char *tp, line[BUFSIZ]; 677 u_long v; 678 int lineno = 0, errors = 0; 679 int i; 680 681 makelabel("auto", lp); 682 bzero(&part_set, sizeof(part_set)); 683 bzero(&part_size_type, sizeof(part_size_type)); 684 bzero(&part_offset_type, sizeof(part_offset_type)); 685 lp->d_bbsize = BBSIZE; /* XXX */ 686 lp->d_sbsize = 0; /* XXX */ 687 while (fgets(line, sizeof(line) - 1, f)) { 688 lineno++; 689 if ((cp = index(line,'\n')) != 0) 690 *cp = '\0'; 691 cp = skip(line); 692 if (cp == NULL) 693 continue; 694 tp = index(cp, ':'); 695 if (tp == NULL) { 696 fprintf(stderr, "line %d: syntax error\n", lineno); 697 errors++; 698 continue; 699 } 700 *tp++ = '\0', tp = skip(tp); 701 if (!strcmp(cp, "type")) { 702 if (tp == NULL) 703 tp = unknown; 704 cpp = dktypenames; 705 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 706 if (*cpp && !strcmp(*cpp, tp)) { 707 lp->d_type = cpp - dktypenames; 708 break; 709 } 710 if (cpp < &dktypenames[DKMAXTYPES]) 711 continue; 712 v = strtoul(tp, NULL, 10); 713 if (v >= DKMAXTYPES) 714 fprintf(stderr, "line %d:%s %lu\n", lineno, 715 "Warning, unknown disk type", v); 716 lp->d_type = v; 717 continue; 718 } 719 if (!strcmp(cp, "flags")) { 720 for (v = 0; (cp = tp) && *cp != '\0';) { 721 tp = word(cp); 722 if (!strcmp(cp, "removeable")) 723 v |= D_REMOVABLE; 724 else if (!strcmp(cp, "ecc")) 725 v |= D_ECC; 726 else if (!strcmp(cp, "badsect")) 727 v |= D_BADSECT; 728 else { 729 fprintf(stderr, 730 "line %d: %s: bad flag\n", 731 lineno, cp); 732 errors++; 733 } 734 } 735 lp->d_flags = v; 736 continue; 737 } 738 if (!strcmp(cp, "drivedata")) { 739 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 740 lp->d_drivedata[i++] = strtoul(cp, NULL, 10); 741 tp = word(cp); 742 } 743 continue; 744 } 745 if (sscanf(cp, "%lu partitions", &v) == 1) { 746 if (v == 0 || v > MAXPARTITIONS) { 747 fprintf(stderr, 748 "line %d: bad # of partitions\n", lineno); 749 lp->d_npartitions = MAXPARTITIONS; 750 errors++; 751 } else 752 lp->d_npartitions = v; 753 continue; 754 } 755 if (tp == NULL) 756 tp = blank; 757 if (!strcmp(cp, "disk")) { 758 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 759 continue; 760 } 761 if (!strcmp(cp, "label")) { 762 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 763 continue; 764 } 765 if (!strcmp(cp, "bytes/sector")) { 766 v = strtoul(tp, NULL, 10); 767 if (v == 0 || (v % DEV_BSIZE) != 0) { 768 fprintf(stderr, 769 "line %d: %s: bad sector size\n", 770 lineno, tp); 771 errors++; 772 } else 773 lp->d_secsize = v; 774 continue; 775 } 776 if (!strcmp(cp, "sectors/track")) { 777 v = strtoul(tp, NULL, 10); 778 #if (ULONG_MAX != 0xffffffffUL) 779 if (v == 0 || v > 0xffffffff) { 780 #else 781 if (v == 0) { 782 #endif 783 fprintf(stderr, "line %d: %s: bad %s\n", 784 lineno, tp, cp); 785 errors++; 786 } else 787 lp->d_nsectors = v; 788 continue; 789 } 790 if (!strcmp(cp, "sectors/cylinder")) { 791 v = strtoul(tp, NULL, 10); 792 if (v == 0) { 793 fprintf(stderr, "line %d: %s: bad %s\n", 794 lineno, tp, cp); 795 errors++; 796 } else 797 lp->d_secpercyl = v; 798 continue; 799 } 800 if (!strcmp(cp, "tracks/cylinder")) { 801 v = strtoul(tp, NULL, 10); 802 if (v == 0) { 803 fprintf(stderr, "line %d: %s: bad %s\n", 804 lineno, tp, cp); 805 errors++; 806 } else 807 lp->d_ntracks = v; 808 continue; 809 } 810 if (!strcmp(cp, "cylinders")) { 811 v = strtoul(tp, NULL, 10); 812 if (v == 0) { 813 fprintf(stderr, "line %d: %s: bad %s\n", 814 lineno, tp, cp); 815 errors++; 816 } else 817 lp->d_ncylinders = v; 818 continue; 819 } 820 if (!strcmp(cp, "sectors/unit")) { 821 v = strtoul(tp, NULL, 10); 822 if (v == 0) { 823 fprintf(stderr, "line %d: %s: bad %s\n", 824 lineno, tp, cp); 825 errors++; 826 } else 827 lp->d_secperunit = v; 828 continue; 829 } 830 if (!strcmp(cp, "rpm")) { 831 v = strtoul(tp, NULL, 10); 832 if (v == 0 || v > USHRT_MAX) { 833 fprintf(stderr, "line %d: %s: bad %s\n", 834 lineno, tp, cp); 835 errors++; 836 } else 837 lp->d_rpm = v; 838 continue; 839 } 840 if (!strcmp(cp, "interleave")) { 841 v = strtoul(tp, NULL, 10); 842 if (v == 0 || v > USHRT_MAX) { 843 fprintf(stderr, "line %d: %s: bad %s\n", 844 lineno, tp, cp); 845 errors++; 846 } else 847 lp->d_interleave = v; 848 continue; 849 } 850 if (!strcmp(cp, "trackskew")) { 851 v = strtoul(tp, NULL, 10); 852 if (v > USHRT_MAX) { 853 fprintf(stderr, "line %d: %s: bad %s\n", 854 lineno, tp, cp); 855 errors++; 856 } else 857 lp->d_trackskew = v; 858 continue; 859 } 860 if (!strcmp(cp, "cylinderskew")) { 861 v = strtoul(tp, NULL, 10); 862 if (v > USHRT_MAX) { 863 fprintf(stderr, "line %d: %s: bad %s\n", 864 lineno, tp, cp); 865 errors++; 866 } else 867 lp->d_cylskew = v; 868 continue; 869 } 870 if (!strcmp(cp, "headswitch")) { 871 v = strtoul(tp, NULL, 10); 872 lp->d_headswitch = v; 873 continue; 874 } 875 if (!strcmp(cp, "track-to-track seek")) { 876 v = strtoul(tp, NULL, 10); 877 lp->d_trkseek = v; 878 continue; 879 } 880 /* the ':' was removed above */ 881 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') { 882 fprintf(stderr, 883 "line %d: %s: Unknown disklabel field\n", lineno, 884 cp); 885 errors++; 886 continue; 887 } 888 889 /* Process a partition specification line. */ 890 part = *cp - 'a'; 891 if (part >= lp->d_npartitions) { 892 fprintf(stderr, 893 "line %d: partition name out of range a-%c: %s\n", 894 lineno, 'a' + lp->d_npartitions - 1, cp); 895 errors++; 896 continue; 897 } 898 part_set[part] = 1; 899 900 if (getasciipartspec(tp, lp, part, lineno) != 0) { 901 errors++; 902 break; 903 } 904 } 905 errors += checklabel(lp); 906 return (errors == 0); 907 } 908 909 #define NXTNUM(n) do { \ 910 if (tp == NULL) { \ 911 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 912 return (1); \ 913 } else { \ 914 cp = tp, tp = word(cp); \ 915 (n) = strtoul(cp, NULL, 10); \ 916 } \ 917 } while (0) 918 919 /* retain 1 character following number */ 920 #define NXTWORD(w,n) do { \ 921 if (tp == NULL) { \ 922 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 923 return (1); \ 924 } else { \ 925 char *tmp; \ 926 cp = tp, tp = word(cp); \ 927 (n) = strtoul(cp, &tmp, 10); \ 928 if (tmp) (w) = *tmp; \ 929 } \ 930 } while (0) 931 932 /* 933 * Read a partition line into partition `part' in the specified disklabel. 934 * Return 0 on success, 1 on failure. 935 */ 936 static int 937 getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno) 938 { 939 struct partition *pp; 940 char *cp; 941 const char **cpp; 942 u_long v; 943 944 pp = &lp->d_partitions[part]; 945 cp = NULL; 946 947 v = 0; 948 NXTWORD(part_size_type[part],v); 949 if (v == 0 && part_size_type[part] != '*') { 950 fprintf(stderr, 951 "line %d: %s: bad partition size\n", lineno, cp); 952 return (1); 953 } 954 pp->p_size = v; 955 956 v = 0; 957 NXTWORD(part_offset_type[part],v); 958 if (v == 0 && part_offset_type[part] != '*' && 959 part_offset_type[part] != '\0') { 960 fprintf(stderr, 961 "line %d: %s: bad partition offset\n", lineno, cp); 962 return (1); 963 } 964 pp->p_offset = v; 965 if (tp == NULL) { 966 fprintf(stderr, "line %d: missing file system type\n", lineno); 967 return (1); 968 } 969 cp = tp, tp = word(cp); 970 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) 971 if (*cpp && !strcmp(*cpp, cp)) 972 break; 973 if (*cpp != NULL) { 974 pp->p_fstype = cpp - fstypenames; 975 } else { 976 if (isdigit(*cp)) 977 v = strtoul(cp, NULL, 10); 978 else 979 v = FSMAXTYPES; 980 if (v >= FSMAXTYPES) { 981 fprintf(stderr, 982 "line %d: Warning, unknown file system type %s\n", 983 lineno, cp); 984 v = FS_UNUSED; 985 } 986 pp->p_fstype = v; 987 } 988 989 switch (pp->p_fstype) { 990 case FS_UNUSED: 991 /* 992 * allow us to accept defaults for 993 * fsize/frag/cpg 994 */ 995 if (tp) { 996 NXTNUM(pp->p_fsize); 997 if (pp->p_fsize == 0) 998 break; 999 NXTNUM(v); 1000 pp->p_frag = v / pp->p_fsize; 1001 } 1002 /* else default to 0's */ 1003 break; 1004 1005 /* These happen to be the same */ 1006 case FS_BSDFFS: 1007 case FS_BSDLFS: 1008 if (tp) { 1009 NXTNUM(pp->p_fsize); 1010 if (pp->p_fsize == 0) 1011 break; 1012 NXTNUM(v); 1013 pp->p_frag = v / pp->p_fsize; 1014 NXTNUM(pp->p_cpg); 1015 } else { 1016 /* 1017 * FIX! poor attempt at adaptive 1018 */ 1019 /* 1 GB */ 1020 if (pp->p_size < 1024*1024*1024 / lp->d_secsize) { 1021 /* 1022 * FIX! These are too low, but are traditional 1023 */ 1024 pp->p_fsize = DEFAULT_NEWFS_FRAG; 1025 pp->p_frag = DEFAULT_NEWFS_BLOCK / 1026 DEFAULT_NEWFS_FRAG; 1027 pp->p_cpg = DEFAULT_NEWFS_CPG; 1028 } else { 1029 pp->p_fsize = BIG_NEWFS_FRAG; 1030 pp->p_frag = BIG_NEWFS_BLOCK / 1031 BIG_NEWFS_FRAG; 1032 pp->p_cpg = BIG_NEWFS_CPG; 1033 } 1034 } 1035 default: 1036 break; 1037 } 1038 return (0); 1039 } 1040 1041 /* 1042 * Check disklabel for errors and fill in 1043 * derived fields according to supplied values. 1044 */ 1045 static int 1046 checklabel(struct disklabel *lp) 1047 { 1048 struct partition *pp; 1049 int i, errors = 0; 1050 char part; 1051 u_long total_size, total_percent, current_offset; 1052 int seen_default_offset; 1053 int hog_part; 1054 int j; 1055 struct partition *pp2; 1056 1057 if (lp == NULL) 1058 lp = &lab; 1059 1060 if (allfields) { 1061 1062 if (lp->d_secsize == 0) { 1063 fprintf(stderr, "sector size 0\n"); 1064 return (1); 1065 } 1066 if (lp->d_nsectors == 0) { 1067 fprintf(stderr, "sectors/track 0\n"); 1068 return (1); 1069 } 1070 if (lp->d_ntracks == 0) { 1071 fprintf(stderr, "tracks/cylinder 0\n"); 1072 return (1); 1073 } 1074 if (lp->d_ncylinders == 0) { 1075 fprintf(stderr, "cylinders/unit 0\n"); 1076 errors++; 1077 } 1078 if (lp->d_rpm == 0) 1079 warnx("revolutions/minute 0"); 1080 if (lp->d_secpercyl == 0) 1081 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1082 if (lp->d_secperunit == 0) 1083 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1084 if (lp->d_bbsize == 0) { 1085 fprintf(stderr, "boot block size 0\n"); 1086 errors++; 1087 } else if (lp->d_bbsize % lp->d_secsize) 1088 warnx("boot block size %% sector-size != 0"); 1089 if (lp->d_npartitions > MAXPARTITIONS) 1090 warnx("number of partitions (%lu) > MAXPARTITIONS (%d)", 1091 (u_long)lp->d_npartitions, MAXPARTITIONS); 1092 } else { 1093 struct disklabel *vl; 1094 1095 vl = getvirginlabel(); 1096 lp->d_secsize = vl->d_secsize; 1097 lp->d_nsectors = vl->d_nsectors; 1098 lp->d_ntracks = vl->d_ntracks; 1099 lp->d_ncylinders = vl->d_ncylinders; 1100 lp->d_rpm = vl->d_rpm; 1101 lp->d_interleave = vl->d_interleave; 1102 lp->d_secpercyl = vl->d_secpercyl; 1103 lp->d_secperunit = vl->d_secperunit; 1104 lp->d_bbsize = vl->d_bbsize; 1105 lp->d_npartitions = vl->d_npartitions; 1106 } 1107 1108 1109 /* first allocate space to the partitions, then offsets */ 1110 total_size = 0; /* in sectors */ 1111 total_percent = 0; /* in percent */ 1112 hog_part = -1; 1113 /* find all fixed partitions */ 1114 for (i = 0; i < lp->d_npartitions; i++) { 1115 pp = &lp->d_partitions[i]; 1116 if (part_set[i]) { 1117 if (part_size_type[i] == '*') { 1118 if (i == RAW_PART) { 1119 pp->p_size = lp->d_secperunit; 1120 } else { 1121 if (hog_part != -1) 1122 warnx("Too many '*' partitions (%c and %c)", 1123 hog_part + 'a',i + 'a'); 1124 else 1125 hog_part = i; 1126 } 1127 } else { 1128 off_t size; 1129 1130 size = pp->p_size; 1131 switch (part_size_type[i]) { 1132 case '%': 1133 total_percent += size; 1134 break; 1135 case 'k': 1136 case 'K': 1137 size *= 1024ULL; 1138 break; 1139 case 'm': 1140 case 'M': 1141 size *= 1024ULL * 1024ULL; 1142 break; 1143 case 'g': 1144 case 'G': 1145 size *= 1024ULL * 1024ULL * 1024ULL; 1146 break; 1147 case '\0': 1148 break; 1149 default: 1150 warnx("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]); 1151 break; 1152 } 1153 /* don't count %'s yet */ 1154 if (part_size_type[i] != '%') { 1155 /* 1156 * for all not in sectors, convert to 1157 * sectors 1158 */ 1159 if (part_size_type[i] != '\0') { 1160 if (size % lp->d_secsize != 0) 1161 warnx("partition %c not an integer number of sectors", 1162 i + 'a'); 1163 size /= lp->d_secsize; 1164 pp->p_size = size; 1165 } 1166 /* else already in sectors */ 1167 if (i != RAW_PART) 1168 total_size += size; 1169 } 1170 } 1171 } 1172 } 1173 /* handle % partitions - note %'s don't need to add up to 100! */ 1174 if (total_percent != 0) { 1175 long free_space = lp->d_secperunit - total_size; 1176 if (total_percent > 100) { 1177 fprintf(stderr,"total percentage %lu is greater than 100\n", 1178 total_percent); 1179 errors++; 1180 } 1181 1182 if (free_space > 0) { 1183 for (i = 0; i < lp->d_npartitions; i++) { 1184 pp = &lp->d_partitions[i]; 1185 if (part_set[i] && part_size_type[i] == '%') { 1186 /* careful of overflows! and integer roundoff */ 1187 pp->p_size = ((double)pp->p_size/100) * free_space; 1188 total_size += pp->p_size; 1189 1190 /* FIX we can lose a sector or so due to roundoff per 1191 partition. A more complex algorithm could avoid that */ 1192 } 1193 } 1194 } else { 1195 fprintf(stderr, 1196 "%ld sectors available to give to '*' and '%%' partitions\n", 1197 free_space); 1198 errors++; 1199 /* fix? set all % partitions to size 0? */ 1200 } 1201 } 1202 /* give anything remaining to the hog partition */ 1203 if (hog_part != -1) { 1204 lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size; 1205 total_size = lp->d_secperunit; 1206 } 1207 1208 /* Now set the offsets for each partition */ 1209 current_offset = 0; /* in sectors */ 1210 seen_default_offset = 0; 1211 for (i = 0; i < lp->d_npartitions; i++) { 1212 part = 'a' + i; 1213 pp = &lp->d_partitions[i]; 1214 if (part_set[i]) { 1215 if (part_offset_type[i] == '*') { 1216 if (i == RAW_PART) { 1217 pp->p_offset = 0; 1218 } else { 1219 pp->p_offset = current_offset; 1220 seen_default_offset = 1; 1221 } 1222 } else { 1223 /* allow them to be out of order for old-style tables */ 1224 if (pp->p_offset < current_offset && 1225 seen_default_offset && i != RAW_PART && 1226 pp->p_fstype != FS_VINUM) { 1227 fprintf(stderr, 1228 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n", 1229 (long)pp->p_offset,i+'a',current_offset); 1230 fprintf(stderr, 1231 "Labels with any *'s for offset must be in ascending order by sector\n"); 1232 errors++; 1233 } else if (pp->p_offset != current_offset && 1234 i != RAW_PART && seen_default_offset) { 1235 /* 1236 * this may give unneeded warnings if 1237 * partitions are out-of-order 1238 */ 1239 warnx( 1240 "Offset %ld for partition %c doesn't match expected value %ld", 1241 (long)pp->p_offset, i + 'a', current_offset); 1242 } 1243 } 1244 if (i != RAW_PART) 1245 current_offset = pp->p_offset + pp->p_size; 1246 } 1247 } 1248 1249 for (i = 0; i < lp->d_npartitions; i++) { 1250 part = 'a' + i; 1251 pp = &lp->d_partitions[i]; 1252 if (pp->p_size == 0 && pp->p_offset != 0) 1253 warnx("partition %c: size 0, but offset %lu", 1254 part, (u_long)pp->p_offset); 1255 #ifdef notdef 1256 if (pp->p_size % lp->d_secpercyl) 1257 warnx("partition %c: size %% cylinder-size != 0", 1258 part); 1259 if (pp->p_offset % lp->d_secpercyl) 1260 warnx("partition %c: offset %% cylinder-size != 0", 1261 part); 1262 #endif 1263 if (pp->p_offset > lp->d_secperunit) { 1264 fprintf(stderr, 1265 "partition %c: offset past end of unit\n", part); 1266 errors++; 1267 } 1268 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1269 fprintf(stderr, 1270 "partition %c: partition extends past end of unit\n", 1271 part); 1272 errors++; 1273 } 1274 if (i == RAW_PART) { 1275 if (pp->p_fstype != FS_UNUSED) 1276 warnx("partition %c is not marked as unused!",part); 1277 if (pp->p_offset != 0) 1278 warnx("partition %c doesn't start at 0!",part); 1279 if (pp->p_size != lp->d_secperunit) 1280 warnx("partition %c doesn't cover the whole unit!",part); 1281 1282 if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) || 1283 (pp->p_size != lp->d_secperunit)) { 1284 warnx("An incorrect partition %c may cause problems for " 1285 "standard system utilities",part); 1286 } 1287 } 1288 1289 /* check for overlaps */ 1290 /* this will check for all possible overlaps once and only once */ 1291 for (j = 0; j < i; j++) { 1292 pp2 = &lp->d_partitions[j]; 1293 if (j != RAW_PART && i != RAW_PART && 1294 pp->p_fstype != FS_VINUM && 1295 pp2->p_fstype != FS_VINUM && 1296 part_set[i] && part_set[j]) { 1297 if (pp2->p_offset < pp->p_offset + pp->p_size && 1298 (pp2->p_offset + pp2->p_size > pp->p_offset || 1299 pp2->p_offset >= pp->p_offset)) { 1300 fprintf(stderr,"partitions %c and %c overlap!\n", 1301 j + 'a', i + 'a'); 1302 errors++; 1303 } 1304 } 1305 } 1306 } 1307 for (; i < MAXPARTITIONS; i++) { 1308 part = 'a' + i; 1309 pp = &lp->d_partitions[i]; 1310 if (pp->p_size || pp->p_offset) 1311 warnx("unused partition %c: size %d offset %lu", 1312 'a' + i, pp->p_size, (u_long)pp->p_offset); 1313 } 1314 return (errors); 1315 } 1316 1317 /* 1318 * When operating on a "virgin" disk, try getting an initial label 1319 * from the associated device driver. This might work for all device 1320 * drivers that are able to fetch some initial device parameters 1321 * without even having access to a (BSD) disklabel, like SCSI disks, 1322 * most IDE drives, or vn devices. 1323 * 1324 * The device name must be given in its "canonical" form. 1325 */ 1326 static struct disklabel * 1327 getvirginlabel(void) 1328 { 1329 static struct disklabel loclab; 1330 struct partition *dp; 1331 int f; 1332 u_int u; 1333 1334 if ((f = open(specname, O_RDONLY)) == -1) { 1335 warn("cannot open %s", specname); 1336 return (NULL); 1337 } 1338 1339 /* New world order */ 1340 if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) || 1341 (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) { 1342 close (f); 1343 return (NULL); 1344 } 1345 memset(&loclab, 0, sizeof loclab); 1346 loclab.d_magic = DISKMAGIC; 1347 loclab.d_magic2 = DISKMAGIC; 1348 loclab.d_secsize = secsize; 1349 loclab.d_secperunit = mediasize / secsize; 1350 1351 /* 1352 * Nobody in these enligthened days uses the CHS geometry for 1353 * anything, but nontheless try to get it right. If we fail 1354 * to get any good ideas from the device, construct something 1355 * which is IBM-PC friendly. 1356 */ 1357 if (ioctl(f, DIOCGFWSECTORS, &u) == 0) 1358 loclab.d_nsectors = u; 1359 else 1360 loclab.d_nsectors = 63; 1361 if (ioctl(f, DIOCGFWHEADS, &u) == 0) 1362 loclab.d_ntracks = u; 1363 else if (loclab.d_secperunit <= 63*1*1024) 1364 loclab.d_ntracks = 1; 1365 else if (loclab.d_secperunit <= 63*16*1024) 1366 loclab.d_ntracks = 16; 1367 else 1368 loclab.d_ntracks = 255; 1369 loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors; 1370 loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl; 1371 loclab.d_npartitions = MAXPARTITIONS; 1372 1373 /* Various (unneeded) compat stuff */ 1374 loclab.d_rpm = 3600; 1375 loclab.d_bbsize = BBSIZE; 1376 loclab.d_interleave = 1; 1377 strncpy(loclab.d_typename, "amnesiac", 1378 sizeof(loclab.d_typename)); 1379 1380 dp = &loclab.d_partitions[0]; 1381 dp->p_offset = BBSIZE / secsize; 1382 dp->p_size = loclab.d_secperunit - dp->p_offset; 1383 1384 dp = &loclab.d_partitions[RAW_PART]; 1385 dp->p_size = loclab.d_secperunit; 1386 loclab.d_checksum = dkcksum(&loclab); 1387 close (f); 1388 return (&loclab); 1389 } 1390 1391 static void 1392 usage(void) 1393 { 1394 1395 fprintf(stderr, 1396 "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 1397 "usage: bsdlabel disk", 1398 "\t\t(to read label)", 1399 " bsdlabel -w [-n] [-m machine] disk [type]", 1400 "\t\t(to write label with existing boot program)", 1401 " bsdlabel -e [-n] [-m machine] disk", 1402 "\t\t(to edit label)", 1403 " bsdlabel -R [-n] [-m machine] disk protofile", 1404 "\t\t(to restore label with existing boot program)", 1405 " bsdlabel -B [-b boot] [-m machine] disk", 1406 "\t\t(to install boot program with existing on-disk label)", 1407 " bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]", 1408 "\t\t(to write label and install boot program)", 1409 " bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile", 1410 "\t\t(to restore label and install boot program)" 1411 ); 1412 exit(1); 1413 } 1414