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