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