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