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