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