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