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