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