1 /* 2 * Copyright (c) 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Symmetric Computer Systems. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#) Copyright (c) 1987, 1993 The Regents of the University of California. All rights reserved. 37 * @(#)disklabel.c 1.2 (Symmetric) 11/28/85 38 * @(#)disklabel.c 8.2 (Berkeley) 1/7/94 39 * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/file.h> 44 #include <sys/stat.h> 45 #include <sys/wait.h> 46 #define DKTYPENAMES 47 #include <sys/disklabel32.h> 48 #include <sys/disklabel64.h> 49 #include <sys/diskslice.h> 50 #include <sys/diskmbr.h> 51 #include <sys/dtype.h> 52 #include <sys/sysctl.h> 53 #include <disktab.h> 54 #include <fstab.h> 55 56 #include <vfs/ufs/dinode.h> 57 #include <vfs/ufs/fs.h> 58 59 #include <unistd.h> 60 #include <string.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <signal.h> 64 #include <stdarg.h> 65 #include <ctype.h> 66 #include <err.h> 67 #include <errno.h> 68 #include "pathnames.h" 69 70 /* 71 * Disklabel32: read and write 32 bit disklabels. 72 * The label is usually placed on one of the first sectors of the disk. 73 * Many machines also place a bootstrap in the same area, 74 * in which case the label is embedded in the bootstrap. 75 * The bootstrap source must leave space at the proper offset 76 * for the label on such machines. 77 */ 78 79 #ifndef BBSIZE 80 #define BBSIZE 8192 /* size of boot area, with label */ 81 #endif 82 83 /* FIX! These are too low, but are traditional */ 84 #define DEFAULT_NEWFS_BLOCK 8192U 85 #define DEFAULT_NEWFS_FRAG 1024U 86 #define DEFAULT_NEWFS_CPG 16U 87 88 #define BIG_NEWFS_BLOCK 16384U 89 #define BIG_NEWFS_FRAG 2048U 90 #define BIG_NEWFS_CPG 64U 91 92 #define NUMBOOT 2 93 94 void makelabel(const char *, const char *, struct disklabel32 *); 95 int writelabel(int, const char *, struct disklabel32 *); 96 void l_perror(const char *); 97 struct disklabel32 *readlabel(int); 98 struct disklabel32 *makebootarea(char *, struct disklabel32 *, int); 99 void display(FILE *, const struct disklabel32 *); 100 int edit(struct disklabel32 *, int); 101 int editit(void); 102 char *skip(char *); 103 char *word(char *); 104 int getasciilabel(FILE *, struct disklabel32 *); 105 int getasciipartspec(char *, struct disklabel32 *, int, int); 106 int checklabel(struct disklabel32 *); 107 void setbootflag(struct disklabel32 *); 108 void Warning(const char *, ...) __printflike(1, 2); 109 void usage(void); 110 int checkoldboot(int, const char *); 111 const char *fixlabel(int, struct disklabel32 *, int); 112 struct disklabel32 *getvirginlabel(void); 113 struct disklabel32 *getdisklabelfromdisktab(const char *name); 114 115 #define DEFEDITOR _PATH_VI 116 #define streq(a,b) (strcmp(a,b) == 0) 117 118 char *dkname; 119 char *specname; 120 char tmpfil[] = PATH_TMPFILE; 121 122 char namebuf[BBSIZE]; 123 struct disklabel32 lab; 124 char bootarea[BBSIZE]; 125 126 #define MAX_PART ('z') 127 #define MAX_NUM_PARTS (1 + MAX_PART - 'a') 128 char part_size_type[MAX_NUM_PARTS]; 129 char part_offset_type[MAX_NUM_PARTS]; 130 int part_set[MAX_NUM_PARTS]; 131 132 #if NUMBOOT > 0 133 int installboot; /* non-zero if we should install a boot program */ 134 char *bootbuf; /* pointer to buffer with remainder of boot prog */ 135 int bootsize; /* size of remaining boot program */ 136 char *xxboot; /* primary boot */ 137 char *bootxx; /* secondary boot */ 138 char boot0[MAXPATHLEN]; 139 char boot1[MAXPATHLEN]; 140 #endif 141 142 enum { 143 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 144 } op = UNSPEC; 145 146 int rflag; 147 int disable_write; /* set to disable writing to disk label */ 148 int forceflag; 149 u_int32_t slice_start_lba; 150 151 #ifdef DEBUG 152 int debug; 153 #define OPTIONS "BNRWb:def:nrs:w" 154 #else 155 #define OPTIONS "BNRWb:ef:nrs:w" 156 #endif 157 158 int 159 main(int argc, char *argv[]) 160 { 161 struct disklabel32 *lp; 162 FILE *t; 163 int ch, f = 0, flag, error = 0; 164 char *name = NULL; 165 166 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 167 switch (ch) { 168 #if NUMBOOT > 0 169 case 'B': 170 ++installboot; 171 break; 172 case 'b': 173 xxboot = optarg; 174 break; 175 176 case 'f': 177 forceflag = 1; 178 slice_start_lba = strtoul(optarg, NULL, 0); 179 break; 180 #if NUMBOOT > 1 181 case 's': 182 bootxx = optarg; 183 break; 184 #endif 185 #endif 186 case 'N': 187 if (op != UNSPEC) 188 usage(); 189 op = NOWRITE; 190 break; 191 case 'n': 192 disable_write = 1; 193 break; 194 case 'R': 195 if (op != UNSPEC) 196 usage(); 197 op = RESTORE; 198 break; 199 case 'W': 200 if (op != UNSPEC) 201 usage(); 202 op = WRITEABLE; 203 break; 204 case 'e': 205 if (op != UNSPEC) 206 usage(); 207 op = EDIT; 208 break; 209 case 'r': 210 ++rflag; 211 break; 212 case 'w': 213 if (op != UNSPEC) 214 usage(); 215 op = WRITE; 216 break; 217 #ifdef DEBUG 218 case 'd': 219 debug++; 220 break; 221 #endif 222 case '?': 223 default: 224 usage(); 225 } 226 argc -= optind; 227 argv += optind; 228 #if NUMBOOT > 0 229 if (installboot) { 230 rflag++; 231 if (op == UNSPEC) 232 op = WRITEBOOT; 233 } else { 234 if (op == UNSPEC) 235 op = READ; 236 xxboot = bootxx = NULL; 237 } 238 #else 239 if (op == UNSPEC) 240 op = READ; 241 #endif 242 if (argc < 1) 243 usage(); 244 245 dkname = getdevpath(argv[0], 0); 246 specname = dkname; 247 f = open(specname, op == READ ? O_RDONLY : O_RDWR); 248 if (f < 0) 249 err(4, "%s", specname); 250 251 switch(op) { 252 253 case UNSPEC: 254 break; 255 256 case EDIT: 257 if (argc != 1) 258 usage(); 259 lp = readlabel(f); 260 error = edit(lp, f); 261 break; 262 263 case NOWRITE: 264 flag = 0; 265 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 266 err(4, "ioctl DIOCWLABEL"); 267 break; 268 269 case READ: 270 if (argc != 1) 271 usage(); 272 lp = readlabel(f); 273 display(stdout, lp); 274 error = checklabel(lp); 275 if (checkoldboot(f, NULL)) 276 warnx("Warning, old bootblocks detected, install new bootblocks & reinstall the disklabel"); 277 break; 278 279 case RESTORE: 280 #if NUMBOOT > 0 281 if (installboot && argc == 3) { 282 makelabel(argv[2], 0, &lab); 283 argc--; 284 285 /* 286 * We only called makelabel() for its side effect 287 * of setting the bootstrap file names. Discard 288 * all changes to `lab' so that all values in the 289 * final label come from the ASCII label. 290 */ 291 bzero((char *)&lab, sizeof(lab)); 292 } 293 #endif 294 if (argc != 2) 295 usage(); 296 if (!(t = fopen(argv[1], "r"))) 297 err(4, "%s", argv[1]); 298 if (!getasciilabel(t, &lab)) 299 exit(1); 300 lp = makebootarea(bootarea, &lab, f); 301 *lp = lab; 302 error = writelabel(f, bootarea, lp); 303 break; 304 305 case WRITE: 306 if (argc == 3) { 307 name = argv[2]; 308 argc--; 309 } 310 if (argc != 2) 311 usage(); 312 makelabel(argv[1], name, &lab); 313 lp = makebootarea(bootarea, &lab, f); 314 *lp = lab; 315 if (checklabel(lp) == 0) 316 error = writelabel(f, bootarea, lp); 317 break; 318 319 case WRITEABLE: 320 flag = 1; 321 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 322 err(4, "ioctl DIOCWLABEL"); 323 break; 324 325 #if NUMBOOT > 0 326 case WRITEBOOT: 327 { 328 struct disklabel32 tlab; 329 330 lp = readlabel(f); 331 tlab = *lp; 332 if (argc == 2) 333 makelabel(argv[1], 0, &lab); 334 lp = makebootarea(bootarea, &lab, f); 335 *lp = tlab; 336 if (checklabel(lp) == 0) 337 error = writelabel(f, bootarea, lp); 338 break; 339 } 340 #endif 341 } 342 exit(error); 343 } 344 345 /* 346 * Construct a prototype disklabel from /etc/disktab. As a side 347 * effect, set the names of the primary and secondary boot files 348 * if specified. 349 */ 350 void 351 makelabel(const char *type, const char *name, struct disklabel32 *lp) 352 { 353 struct disklabel32 *dp; 354 355 if (strcmp(type, "auto") == 0) 356 dp = getvirginlabel(); 357 else 358 dp = getdisklabelfromdisktab(type); 359 if (dp == NULL) 360 errx(1, "%s: unknown disk type", type); 361 *lp = *dp; 362 363 /* 364 * NOTE: boot control files may no longer be specified in disktab. 365 */ 366 if (name) 367 strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 368 } 369 370 int 371 writelabel(int f, const char *boot, struct disklabel32 *lp) 372 { 373 const char *msg; 374 int flag; 375 int r; 376 377 if (disable_write) { 378 Warning("write to disk label suppressed - label was as follows:"); 379 display(stdout, lp); 380 return (0); 381 } else { 382 /* make sure we are not overwriting our boot code */ 383 if (checkoldboot(f, boot)) 384 errx(4, "Will not overwrite old bootblocks w/ label, install new boot blocks first!"); 385 setbootflag(lp); 386 lp->d_magic = DISKMAGIC32; 387 lp->d_magic2 = DISKMAGIC32; 388 lp->d_checksum = 0; 389 lp->d_checksum = dkcksum32(lp); 390 if (rflag) { 391 /* 392 * First set the kernel disk label, 393 * then write a label to the raw disk. 394 * If the SDINFO ioctl fails because it is unimplemented, 395 * keep going; otherwise, the kernel consistency checks 396 * may prevent us from changing the current (in-core) 397 * label. 398 */ 399 if (ioctl(f, DIOCSDINFO32, lp) < 0 && 400 errno != ENODEV && errno != ENOTTY) { 401 l_perror("ioctl DIOCSDINFO32"); 402 return (1); 403 } 404 lseek(f, (off_t)0, SEEK_SET); 405 406 /* 407 * write enable label sector before write 408 * (if necessary), disable after writing. 409 */ 410 flag = 1; 411 if (ioctl(f, DIOCWLABEL, &flag) < 0) 412 warn("ioctl DIOCWLABEL"); 413 msg = fixlabel(f, lp, 1); 414 if (msg) { 415 warn(msg); 416 return (1); 417 } 418 r = write(f, boot, lp->d_bbsize); 419 fixlabel(f, lp, 0); 420 if (r != ((ssize_t)lp->d_bbsize)) { 421 warn("write"); 422 return (1); 423 } 424 #if NUMBOOT > 0 425 /* 426 * Output the remainder of the disklabel 427 */ 428 if (bootbuf) { 429 fixlabel(f, lp, 1); 430 r = write(f, bootbuf, bootsize); 431 fixlabel(f, lp, 0); 432 if (r != bootsize) { 433 warn("write"); 434 return(1); 435 } 436 } 437 #endif 438 flag = 0; 439 ioctl(f, DIOCWLABEL, &flag); 440 } else if (ioctl(f, DIOCWDINFO32, lp) < 0) { 441 l_perror("ioctl DIOCWDINFO32"); 442 return (1); 443 } 444 } 445 return (0); 446 } 447 448 void 449 l_perror(const char *s) 450 { 451 switch (errno) { 452 453 case ESRCH: 454 warnx("%s: no disk label on disk;", s); 455 fprintf(stderr, "add \"-r\" to install initial label\n"); 456 break; 457 458 case EINVAL: 459 warnx("%s: label magic number or checksum is wrong!", s); 460 fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 461 break; 462 463 case EBUSY: 464 warnx("%s: open partition would move or shrink", s); 465 break; 466 467 case EXDEV: 468 warnx("%s: '%c' partition must start at beginning of disk", 469 s, 'a' + RAW_PART); 470 break; 471 472 case ENOATTR: 473 warnx("%s: the disk already has a label of a different type,\n" 474 "probably a 64 bit disklabel. It must be cleaned out " 475 "first.\n", s); 476 break; 477 478 default: 479 warn(NULL); 480 break; 481 } 482 } 483 484 /* 485 * Fetch disklabel for disk. 486 * Use ioctl to get label unless -r flag is given. 487 */ 488 struct disklabel32 * 489 readlabel(int f) 490 { 491 const char *msg; 492 struct disklabel32 *lp; 493 int r; 494 495 if (rflag) { 496 r = read(f, bootarea, BBSIZE); 497 if (r < BBSIZE) 498 err(4, "%s", specname); 499 for (lp = (struct disklabel32 *)bootarea; 500 lp <= (struct disklabel32 *)(bootarea + BBSIZE - sizeof(*lp)); 501 lp = (struct disklabel32 *)((char *)lp + 16)) { 502 if (lp->d_magic == DISKMAGIC32 && 503 lp->d_magic2 == DISKMAGIC32) 504 break; 505 } 506 if (lp > (struct disklabel32 *)(bootarea+BBSIZE-sizeof(*lp)) || 507 lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32 || 508 dkcksum32(lp) != 0) { 509 errx(1, "bad pack magic number (label is damaged, " 510 "or pack is unlabeled)"); 511 } 512 if ((msg = fixlabel(f, lp, 0)) != NULL) 513 errx(1, msg); 514 } else { 515 lp = &lab; 516 if (ioctl(f, DIOCGDINFO32, lp) < 0) { 517 l_perror("ioctl DIOCGDINFO32"); 518 exit(4); 519 } 520 } 521 return (lp); 522 } 523 524 /* 525 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 526 * Returns a pointer to the disklabel portion of the bootarea. 527 */ 528 struct disklabel32 * 529 makebootarea(char *boot, struct disklabel32 *dp, int f) 530 { 531 struct disklabel32 *lp; 532 char *p; 533 int b; 534 #if NUMBOOT > 0 535 struct stat sb; 536 #endif 537 #ifdef __i386__ 538 char *tmpbuf; 539 unsigned int i, found; 540 #endif 541 542 /* XXX */ 543 if (dp->d_secsize == 0) { 544 dp->d_secsize = DEV_BSIZE; 545 dp->d_bbsize = BBSIZE; 546 } 547 lp = (struct disklabel32 *) 548 (boot + (LABELSECTOR32 * dp->d_secsize) + LABELOFFSET32); 549 bzero((char *)lp, sizeof *lp); 550 #if NUMBOOT > 0 551 /* 552 * If we are not installing a boot program but we are installing a 553 * label on disk then we must read the current bootarea so we don't 554 * clobber the existing boot. 555 */ 556 if (!installboot) { 557 if (rflag) { 558 if (read(f, boot, BBSIZE) < BBSIZE) 559 err(4, "%s", specname); 560 bzero((char *)lp, sizeof *lp); 561 } 562 return (lp); 563 } 564 /* 565 * We are installing a boot program. Determine the name(s) and 566 * read them into the appropriate places in the boot area. 567 */ 568 if (!xxboot || !bootxx) { 569 if (!xxboot) { 570 sprintf(boot0, "%s/boot1", _PATH_BOOTDIR); 571 xxboot = boot0; 572 } 573 #if NUMBOOT > 1 574 if (!bootxx) { 575 sprintf(boot1, "%s/boot2", _PATH_BOOTDIR); 576 bootxx = boot1; 577 } 578 #endif 579 } 580 #ifdef DEBUG 581 if (debug) 582 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n", 583 xxboot, bootxx ? bootxx : "NONE"); 584 #endif 585 586 /* 587 * Strange rules: 588 * 1. One-piece bootstrap (hp300/hp800) 589 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest 590 * is remembered and written later following the bootarea. 591 * 2. Two-piece bootstraps (vax/i386?/mips?) 592 * up to d_secsize bytes of ``xxboot'' go in first d_secsize 593 * bytes of bootarea, remaining d_bbsize-d_secsize filled 594 * from ``bootxx''. 595 */ 596 b = open(xxboot, O_RDONLY); 597 if (b < 0) 598 err(4, "%s", xxboot); 599 #if NUMBOOT > 1 600 #ifdef __i386__ 601 /* 602 * XXX Botch alert. 603 * The i386 has the so-called fdisk table embedded into the 604 * primary bootstrap. We take care to not clobber it, but 605 * only if it does already contain some data. (Otherwise, 606 * the xxboot provides a template.) 607 */ 608 if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == NULL) 609 err(4, "%s", xxboot); 610 memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize); 611 #endif /* i386 */ 612 if (read(b, boot, (int)dp->d_secsize) < 0) 613 err(4, "%s", xxboot); 614 close(b); 615 #ifdef __i386__ 616 for (i = DOSPARTOFF, found = 0; 617 !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition); 618 i++) 619 found = tmpbuf[i] != 0; 620 if (found) 621 memcpy((void *)&boot[DOSPARTOFF], 622 (void *)&tmpbuf[DOSPARTOFF], 623 NDOSPART * sizeof(struct dos_partition)); 624 free(tmpbuf); 625 #endif /* i386 */ 626 b = open(bootxx, O_RDONLY); 627 if (b < 0) 628 err(4, "%s", bootxx); 629 if (fstat(b, &sb) != 0) 630 err(4, "%s", bootxx); 631 if (dp->d_secsize + sb.st_size > dp->d_bbsize) 632 errx(4, "%s too large", bootxx); 633 if (read(b, &boot[dp->d_secsize], 634 (int)(dp->d_bbsize-dp->d_secsize)) < 0) 635 err(4, "%s", bootxx); 636 #else /* !(NUMBOOT > 1) */ 637 if (read(b, boot, (int)dp->d_bbsize) < 0) 638 err(4, "%s", xxboot); 639 if (fstat(b, &sb) != 0) 640 err(4, "%s", xxboot); 641 bootsize = (int)sb.st_size - dp->d_bbsize; 642 if (bootsize > 0) { 643 /* XXX assume d_secsize is a power of two */ 644 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); 645 bootbuf = (char *)malloc((size_t)bootsize); 646 if (bootbuf == NULL) 647 err(4, "%s", xxboot); 648 if (read(b, bootbuf, bootsize) < 0) { 649 free(bootbuf); 650 err(4, "%s", xxboot); 651 } 652 } 653 #endif /* NUMBOOT > 1 */ 654 close(b); 655 #endif /* NUMBOOT > 0 */ 656 /* 657 * Make sure no part of the bootstrap is written in the area 658 * reserved for the label. 659 */ 660 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel32); p++) 661 if (*p) 662 errx(2, "bootstrap doesn't leave room for disk label"); 663 return (lp); 664 } 665 666 void 667 display(FILE *f, const struct disklabel32 *lp) 668 { 669 int i, j; 670 const struct partition32 *pp; 671 672 fprintf(f, "# %s:\n", specname); 673 if (lp->d_type < DKMAXTYPES) 674 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 675 else 676 fprintf(f, "type: %u\n", lp->d_type); 677 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), 678 lp->d_typename); 679 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 680 lp->d_packname); 681 fprintf(f, "flags:"); 682 fprintf(f, "\n"); 683 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize); 684 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors); 685 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks); 686 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl); 687 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders); 688 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit); 689 fprintf(f, "rpm: %u\n", lp->d_rpm); 690 fprintf(f, "interleave: %u\n", lp->d_interleave); 691 fprintf(f, "trackskew: %u\n", lp->d_trackskew); 692 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew); 693 fprintf(f, "headswitch: %lu\t\t# milliseconds\n", 694 (u_long)lp->d_headswitch); 695 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", 696 (u_long)lp->d_trkseek); 697 fprintf(f, "drivedata: "); 698 for (i = NDDATA32 - 1; i >= 0; i--) { 699 if (lp->d_drivedata[i]) 700 break; 701 } 702 if (i < 0) 703 i = 0; 704 for (j = 0; j <= i; j++) 705 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]); 706 fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions); 707 fprintf(f, 708 "# size offset fstype\n"); 709 pp = lp->d_partitions; 710 for (i = 0; i < lp->d_npartitions; i++, pp++) { 711 if (pp->p_size) { 712 u_long onemeg = 1024 * 1024 / lp->d_secsize; 713 fprintf(f, " %c: ", 'a' + i); 714 715 fprintf(f, "%10lu ", (u_long)pp->p_size); 716 fprintf(f, "%10lu ", (u_long)pp->p_offset); 717 if (pp->p_fstype < FSMAXTYPES) 718 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 719 else 720 fprintf(f, "%8d", pp->p_fstype); 721 722 fprintf(f, "\t# %11.3fMB", (double)pp->p_size / onemeg); 723 fprintf(f, "\n"); 724 } 725 } 726 fflush(f); 727 } 728 729 int 730 edit(struct disklabel32 *lp, int f) 731 { 732 int c, fd; 733 struct disklabel32 label; 734 FILE *fp; 735 736 if ((fd = mkstemp(tmpfil)) == -1 || 737 (fp = fdopen(fd, "w")) == NULL) { 738 warnx("can't create %s", tmpfil); 739 return (1); 740 } 741 display(fp, lp); 742 fclose(fp); 743 for (;;) { 744 if (!editit()) 745 break; 746 fp = fopen(tmpfil, "r"); 747 if (fp == NULL) { 748 warnx("can't reopen %s for reading", tmpfil); 749 break; 750 } 751 bzero((char *)&label, sizeof(label)); 752 if (getasciilabel(fp, &label)) { 753 *lp = label; 754 if (writelabel(f, bootarea, lp) == 0) { 755 fclose(fp); 756 unlink(tmpfil); 757 return (0); 758 } 759 } 760 fclose(fp); 761 printf("re-edit the label? [y]: "); fflush(stdout); 762 c = getchar(); 763 if (c != EOF && c != (int)'\n') 764 while (getchar() != (int)'\n') 765 ; 766 if (c == (int)'n') 767 break; 768 } 769 unlink(tmpfil); 770 return (1); 771 } 772 773 int 774 editit(void) 775 { 776 int pid, xpid; 777 int status, omask; 778 const char *ed; 779 780 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 781 while ((pid = fork()) < 0) { 782 if (errno == EPROCLIM) { 783 warnx("you have too many processes"); 784 return(0); 785 } 786 if (errno != EAGAIN) { 787 warn("fork"); 788 return(0); 789 } 790 sleep(1); 791 } 792 if (pid == 0) { 793 sigsetmask(omask); 794 setgid(getgid()); 795 setuid(getuid()); 796 if ((ed = getenv("EDITOR")) == NULL) 797 ed = DEFEDITOR; 798 execlp(ed, ed, tmpfil, NULL); 799 err(1, "%s", ed); 800 } 801 while ((xpid = wait(&status)) >= 0) 802 if (xpid == pid) 803 break; 804 sigsetmask(omask); 805 return(!status); 806 } 807 808 char * 809 skip(char *cp) 810 { 811 812 while (*cp != '\0' && isspace(*cp)) 813 cp++; 814 if (*cp == '\0' || *cp == '#') 815 return (NULL); 816 return (cp); 817 } 818 819 char * 820 word(char *cp) 821 { 822 char c; 823 824 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 825 cp++; 826 if ((c = *cp) != '\0') { 827 *cp++ = '\0'; 828 if (c != '#') 829 return (skip(cp)); 830 } 831 return (NULL); 832 } 833 834 /* 835 * Read an ascii label in from fd f, 836 * in the same format as that put out by display(), 837 * and fill in lp. 838 */ 839 int 840 getasciilabel(FILE *f, struct disklabel32 *lp) 841 { 842 char *cp; 843 const char **cpp; 844 u_int part; 845 char *tp, line[BUFSIZ]; 846 u_long v; 847 int lineno = 0, errors = 0; 848 int i; 849 char empty[] = ""; 850 char unknown[] = "unknown"; 851 852 bzero(&part_set, sizeof(part_set)); 853 bzero(&part_size_type, sizeof(part_size_type)); 854 bzero(&part_offset_type, sizeof(part_offset_type)); 855 lp->d_bbsize = BBSIZE; /* XXX */ 856 lp->d_sbsize = SBSIZE; /* XXX */ 857 while (fgets(line, sizeof(line) - 1, f)) { 858 lineno++; 859 if ((cp = strchr(line,'\n')) != NULL) 860 *cp = '\0'; 861 cp = skip(line); 862 if (cp == NULL) 863 continue; 864 tp = strchr(cp, ':'); 865 if (tp == NULL) { 866 fprintf(stderr, "line %d: syntax error\n", lineno); 867 errors++; 868 continue; 869 } 870 *tp++ = '\0', tp = skip(tp); 871 if (streq(cp, "type")) { 872 if (tp == NULL) 873 tp = unknown; 874 cpp = dktypenames; 875 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) { 876 if (*cpp && strcasecmp(*cpp, tp) == 0) { 877 lp->d_type = cpp - dktypenames; 878 break; 879 } 880 } 881 if (cpp < &dktypenames[DKMAXTYPES]) 882 continue; 883 v = strtoul(tp, NULL, 10); 884 if (v >= DKMAXTYPES) { 885 fprintf(stderr, "line %d:%s %lu\n", lineno, 886 "Warning, unknown disk type", v); 887 } 888 lp->d_type = v; 889 continue; 890 } 891 if (streq(cp, "flags")) { 892 for (v = 0; (cp = tp) && *cp != '\0';) { 893 tp = word(cp); 894 if (streq(cp, "removeable")) 895 v |= 0; /* obsolete */ 896 else if (streq(cp, "ecc")) 897 v |= 0; /* obsolete */ 898 else if (streq(cp, "badsect")) 899 v |= 0; /* obsolete */ 900 else { 901 fprintf(stderr, 902 "line %d: %s: bad flag\n", 903 lineno, cp); 904 errors++; 905 } 906 } 907 lp->d_flags = v; 908 continue; 909 } 910 if (streq(cp, "drivedata")) { 911 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA32;) { 912 lp->d_drivedata[i++] = strtoul(cp, NULL, 10); 913 tp = word(cp); 914 } 915 continue; 916 } 917 if (sscanf(cp, "%lu partitions", &v) == 1) { 918 if (v == 0 || v > MAXPARTITIONS32) { 919 fprintf(stderr, 920 "line %d: bad # of partitions\n", lineno); 921 lp->d_npartitions = MAXPARTITIONS32; 922 errors++; 923 } else 924 lp->d_npartitions = v; 925 continue; 926 } 927 if (tp == NULL) 928 tp = empty; 929 if (streq(cp, "disk")) { 930 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 931 continue; 932 } 933 if (streq(cp, "label")) { 934 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 935 continue; 936 } 937 if (streq(cp, "bytes/sector")) { 938 v = strtoul(tp, NULL, 10); 939 if (v == 0 || (v % DEV_BSIZE) != 0) { 940 fprintf(stderr, 941 "line %d: %s: bad sector size\n", 942 lineno, tp); 943 errors++; 944 } else 945 lp->d_secsize = v; 946 continue; 947 } 948 if (streq(cp, "sectors/track")) { 949 v = strtoul(tp, NULL, 10); 950 #if (ULONG_MAX != 0xffffffffUL) 951 if (v == 0 || v > 0xffffffff) { 952 #else 953 if (v == 0) { 954 #endif 955 fprintf(stderr, "line %d: %s: bad %s\n", 956 lineno, tp, cp); 957 errors++; 958 } else 959 lp->d_nsectors = v; 960 continue; 961 } 962 if (streq(cp, "sectors/cylinder")) { 963 v = strtoul(tp, NULL, 10); 964 if (v == 0) { 965 fprintf(stderr, "line %d: %s: bad %s\n", 966 lineno, tp, cp); 967 errors++; 968 } else 969 lp->d_secpercyl = v; 970 continue; 971 } 972 if (streq(cp, "tracks/cylinder")) { 973 v = strtoul(tp, NULL, 10); 974 if (v == 0) { 975 fprintf(stderr, "line %d: %s: bad %s\n", 976 lineno, tp, cp); 977 errors++; 978 } else 979 lp->d_ntracks = v; 980 continue; 981 } 982 if (streq(cp, "cylinders")) { 983 v = strtoul(tp, NULL, 10); 984 if (v == 0) { 985 fprintf(stderr, "line %d: %s: bad %s\n", 986 lineno, tp, cp); 987 errors++; 988 } else 989 lp->d_ncylinders = v; 990 continue; 991 } 992 if (streq(cp, "sectors/unit")) { 993 v = strtoul(tp, NULL, 10); 994 if (v == 0) { 995 fprintf(stderr, "line %d: %s: bad %s\n", 996 lineno, tp, cp); 997 errors++; 998 } else 999 lp->d_secperunit = v; 1000 continue; 1001 } 1002 if (streq(cp, "rpm")) { 1003 v = strtoul(tp, NULL, 10); 1004 if (v == 0 || v > USHRT_MAX) { 1005 fprintf(stderr, "line %d: %s: bad %s\n", 1006 lineno, tp, cp); 1007 errors++; 1008 } else 1009 lp->d_rpm = v; 1010 continue; 1011 } 1012 if (streq(cp, "interleave")) { 1013 v = strtoul(tp, NULL, 10); 1014 if (v == 0 || v > USHRT_MAX) { 1015 fprintf(stderr, "line %d: %s: bad %s\n", 1016 lineno, tp, cp); 1017 errors++; 1018 } else 1019 lp->d_interleave = v; 1020 continue; 1021 } 1022 if (streq(cp, "trackskew")) { 1023 v = strtoul(tp, NULL, 10); 1024 if (v > USHRT_MAX) { 1025 fprintf(stderr, "line %d: %s: bad %s\n", 1026 lineno, tp, cp); 1027 errors++; 1028 } else 1029 lp->d_trackskew = v; 1030 continue; 1031 } 1032 if (streq(cp, "cylinderskew")) { 1033 v = strtoul(tp, NULL, 10); 1034 if (v > USHRT_MAX) { 1035 fprintf(stderr, "line %d: %s: bad %s\n", 1036 lineno, tp, cp); 1037 errors++; 1038 } else 1039 lp->d_cylskew = v; 1040 continue; 1041 } 1042 if (streq(cp, "headswitch")) { 1043 v = strtoul(tp, NULL, 10); 1044 lp->d_headswitch = v; 1045 continue; 1046 } 1047 if (streq(cp, "track-to-track seek")) { 1048 v = strtoul(tp, NULL, 10); 1049 lp->d_trkseek = v; 1050 continue; 1051 } 1052 /* the ':' was removed above */ 1053 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') { 1054 fprintf(stderr, 1055 "line %d: %s: Unknown disklabel field\n", lineno, 1056 cp); 1057 errors++; 1058 continue; 1059 } 1060 1061 /* Process a partition specification line. */ 1062 part = *cp - 'a'; 1063 if (part >= lp->d_npartitions) { 1064 fprintf(stderr, 1065 "line %d: partition name out of range a-%c: %s\n", 1066 lineno, 'a' + lp->d_npartitions - 1, cp); 1067 errors++; 1068 continue; 1069 } 1070 part_set[part] = 1; 1071 1072 if (getasciipartspec(tp, lp, part, lineno) != 0) { 1073 errors++; 1074 break; 1075 } 1076 } 1077 errors += checklabel(lp); 1078 return (errors == 0); 1079 } 1080 1081 #define NXTNUM(n) do { \ 1082 if (tp == NULL) { \ 1083 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 1084 return (1); \ 1085 } else { \ 1086 cp = tp, tp = word(cp); \ 1087 (n) = strtoul(cp, NULL, 10); \ 1088 } \ 1089 } while (0) 1090 1091 /* retain 1 character following number */ 1092 #define NXTWORD(w,n) do { \ 1093 if (tp == NULL) { \ 1094 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ 1095 return (1); \ 1096 } else { \ 1097 char *tmp; \ 1098 cp = tp, tp = word(cp); \ 1099 (n) = strtoul(cp, &tmp, 10); \ 1100 if (tmp) (w) = *tmp; \ 1101 } \ 1102 } while (0) 1103 1104 /* 1105 * Read a partition line into partition `part' in the specified disklabel. 1106 * Return 0 on success, 1 on failure. 1107 */ 1108 int 1109 getasciipartspec(char *tp, struct disklabel32 *lp, int part, int lineno) 1110 { 1111 struct partition32 *pp; 1112 char *cp; 1113 const char **cpp; 1114 u_long v; 1115 1116 pp = &lp->d_partitions[part]; 1117 cp = NULL; 1118 1119 /* 1120 * size 1121 */ 1122 v = 0; 1123 NXTWORD(part_size_type[part],v); 1124 if (v == 0 && part_size_type[part] != '*') { 1125 fprintf(stderr, 1126 "line %d: %s: bad partition size\n", lineno, cp); 1127 return (1); 1128 } 1129 pp->p_size = v; 1130 1131 /* 1132 * offset 1133 */ 1134 v = 0; 1135 NXTWORD(part_offset_type[part],v); 1136 if (v == 0 && part_offset_type[part] != '*' && 1137 part_offset_type[part] != '\0') { 1138 fprintf(stderr, 1139 "line %d: %s: bad partition offset\n", lineno, cp); 1140 return (1); 1141 } 1142 pp->p_offset = v; 1143 1144 /* 1145 * fstype 1146 */ 1147 if (tp == NULL) { 1148 fprintf(stderr, 1149 "line %d: no filesystem type was specified\n", lineno); 1150 return(1); 1151 } 1152 cp = tp; 1153 tp = word(cp); 1154 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 1155 if (*cpp && strcasecmp(*cpp, cp) == 0) 1156 break; 1157 } 1158 if (*cpp != NULL) { 1159 pp->p_fstype = cpp - fstypenames; 1160 } else { 1161 if (isdigit(*cp)) 1162 v = strtoul(cp, NULL, 10); 1163 else 1164 v = FSMAXTYPES; 1165 if (v >= FSMAXTYPES) { 1166 fprintf(stderr, 1167 "line %d: Warning, unknown filesystem type %s\n", 1168 lineno, cp); 1169 v = FS_UNUSED; 1170 } 1171 pp->p_fstype = v; 1172 } 1173 1174 pp->p_fsize = 0; 1175 pp->p_frag = 0; 1176 pp->p_cpg = 0; 1177 1178 cp = tp; 1179 if (tp) { 1180 fprintf(stderr, "line %d: Warning, fragment, block, " 1181 "and bps/cpg fields are no\n" 1182 "longer supported and must be specified " 1183 "via newfs options instead.\n", 1184 lineno); 1185 } 1186 return(0); 1187 } 1188 1189 /* 1190 * Check disklabel for errors and fill in 1191 * derived fields according to supplied values. 1192 */ 1193 int 1194 checklabel(struct disklabel32 *lp) 1195 { 1196 struct partition32 *pp; 1197 int i, errors = 0; 1198 char part; 1199 u_long base_offset, needed, total_size, total_percent, current_offset; 1200 long free_space; 1201 int seen_default_offset; 1202 int hog_part; 1203 int j; 1204 struct partition32 *pp2; 1205 1206 if (lp->d_secsize == 0) { 1207 fprintf(stderr, "sector size 0\n"); 1208 return (1); 1209 } 1210 if (lp->d_nsectors == 0) { 1211 fprintf(stderr, "sectors/track 0\n"); 1212 return (1); 1213 } 1214 if (lp->d_ntracks == 0) { 1215 fprintf(stderr, "tracks/cylinder 0\n"); 1216 return (1); 1217 } 1218 if (lp->d_ncylinders == 0) { 1219 fprintf(stderr, "cylinders/unit 0\n"); 1220 errors++; 1221 } 1222 if (lp->d_rpm == 0) 1223 Warning("revolutions/minute 0"); 1224 if (lp->d_secpercyl == 0) 1225 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1226 if (lp->d_secperunit == 0) 1227 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1228 if (lp->d_bbsize == 0) { 1229 fprintf(stderr, "boot block size 0\n"); 1230 errors++; 1231 } else if (lp->d_bbsize % lp->d_secsize) 1232 Warning("boot block size %% sector-size != 0"); 1233 if (lp->d_sbsize == 0) { 1234 fprintf(stderr, "super block size 0\n"); 1235 errors++; 1236 } else if (lp->d_sbsize % lp->d_secsize) 1237 Warning("super block size %% sector-size != 0"); 1238 if (lp->d_npartitions > MAXPARTITIONS32) 1239 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)", 1240 (u_long)lp->d_npartitions, MAXPARTITIONS32); 1241 1242 /* first allocate space to the partitions, then offsets */ 1243 total_size = 0; /* in sectors */ 1244 total_percent = 0; /* in percent */ 1245 hog_part = -1; 1246 /* find all fixed partitions */ 1247 for (i = 0; i < lp->d_npartitions; i++) { 1248 pp = &lp->d_partitions[i]; 1249 if (part_set[i]) { 1250 1251 if (part_size_type[i] == '*') { 1252 if (i == RAW_PART) { 1253 pp->p_size = lp->d_secperunit; 1254 } else { 1255 if (part_offset_type[i] != '*') { 1256 if (total_size < pp->p_offset) 1257 total_size = pp->p_offset; 1258 } 1259 if (hog_part != -1) 1260 Warning("Too many '*' partitions (%c and %c)", 1261 hog_part + 'a',i + 'a'); 1262 else 1263 hog_part = i; 1264 } 1265 } else { 1266 off_t size; 1267 1268 size = pp->p_size; 1269 switch (part_size_type[i]) { 1270 case '%': 1271 total_percent += size; 1272 break; 1273 case 't': 1274 case 'T': 1275 size *= 1024ULL; 1276 /* FALLTHROUGH */ 1277 case 'g': 1278 case 'G': 1279 size *= 1024ULL; 1280 /* FALLTHROUGH */ 1281 case 'm': 1282 case 'M': 1283 size *= 1024ULL; 1284 /* FALLTHROUGH */ 1285 case 'k': 1286 case 'K': 1287 size *= 1024ULL; 1288 break; 1289 case '\0': 1290 break; 1291 default: 1292 Warning("unknown size specifier '%c' (K/M/G/T are valid)",part_size_type[i]); 1293 break; 1294 } 1295 /* don't count %'s yet */ 1296 if (part_size_type[i] != '%') { 1297 /* 1298 * for all not in sectors, convert to 1299 * sectors 1300 */ 1301 if (part_size_type[i] != '\0') { 1302 if (size % lp->d_secsize != 0) 1303 Warning("partition %c not an integer number of sectors", 1304 i + 'a'); 1305 size /= lp->d_secsize; 1306 pp->p_size = size; 1307 } 1308 /* else already in sectors */ 1309 if (i != RAW_PART) 1310 total_size += size; 1311 } 1312 } 1313 } 1314 } 1315 1316 /* Find out the total free space, excluding the boot block area. */ 1317 base_offset = BBSIZE / lp->d_secsize; 1318 free_space = 0; 1319 for (i = 0; i < lp->d_npartitions; i++) { 1320 pp = &lp->d_partitions[i]; 1321 if (!part_set[i] || i == RAW_PART || 1322 part_size_type[i] == '%' || part_size_type[i] == '*') 1323 continue; 1324 if (pp->p_offset > base_offset) 1325 free_space += pp->p_offset - base_offset; 1326 if (pp->p_offset + pp->p_size > base_offset) 1327 base_offset = pp->p_offset + pp->p_size; 1328 } 1329 if (base_offset < lp->d_secperunit) 1330 free_space += lp->d_secperunit - base_offset; 1331 1332 /* handle % partitions - note %'s don't need to add up to 100! */ 1333 if (total_percent != 0) { 1334 if (total_percent > 100) { 1335 fprintf(stderr,"total percentage %lu is greater than 100\n", 1336 total_percent); 1337 errors++; 1338 } 1339 1340 if (free_space > 0) { 1341 for (i = 0; i < lp->d_npartitions; i++) { 1342 pp = &lp->d_partitions[i]; 1343 if (part_set[i] && part_size_type[i] == '%') { 1344 /* careful of overflows! and integer roundoff */ 1345 pp->p_size = ((double)pp->p_size/100) * free_space; 1346 total_size += pp->p_size; 1347 1348 /* FIX we can lose a sector or so due to roundoff per 1349 partition. A more complex algorithm could avoid that */ 1350 } 1351 } 1352 } else { 1353 fprintf(stderr, 1354 "%ld sectors available to give to '*' and '%%' partitions\n", 1355 free_space); 1356 errors++; 1357 /* fix? set all % partitions to size 0? */ 1358 } 1359 } 1360 /* give anything remaining to the hog partition */ 1361 if (hog_part != -1) { 1362 /* 1363 * Find the range of offsets usable by '*' partitions around 1364 * the hog partition and how much space they need. 1365 */ 1366 needed = 0; 1367 base_offset = BBSIZE / lp->d_secsize; 1368 for (i = hog_part - 1; i >= 0; i--) { 1369 pp = &lp->d_partitions[i]; 1370 if (!part_set[i] || i == RAW_PART) 1371 continue; 1372 if (part_offset_type[i] == '*') { 1373 needed += pp->p_size; 1374 continue; 1375 } 1376 base_offset = pp->p_offset + pp->p_size; 1377 break; 1378 } 1379 current_offset = lp->d_secperunit; 1380 for (i = lp->d_npartitions - 1; i > hog_part; i--) { 1381 pp = &lp->d_partitions[i]; 1382 if (!part_set[i] || i == RAW_PART) 1383 continue; 1384 if (part_offset_type[i] == '*') { 1385 needed += pp->p_size; 1386 continue; 1387 } 1388 current_offset = pp->p_offset; 1389 } 1390 1391 if (current_offset - base_offset <= needed) { 1392 fprintf(stderr, "Cannot find space for partition %c\n", 1393 hog_part + 'a'); 1394 fprintf(stderr, 1395 "Need more than %lu sectors between %lu and %lu\n", 1396 needed, base_offset, current_offset); 1397 errors++; 1398 lp->d_partitions[hog_part].p_size = 0; 1399 } else { 1400 lp->d_partitions[hog_part].p_size = current_offset - 1401 base_offset - needed; 1402 total_size += lp->d_partitions[hog_part].p_size; 1403 } 1404 } 1405 1406 /* Now set the offsets for each partition */ 1407 current_offset = BBSIZE / lp->d_secsize; /* in sectors */ 1408 seen_default_offset = 0; 1409 for (i = 0; i < lp->d_npartitions; i++) { 1410 part = 'a' + i; 1411 pp = &lp->d_partitions[i]; 1412 if (part_set[i]) { 1413 if (part_offset_type[i] == '*') { 1414 if (i == RAW_PART) { 1415 pp->p_offset = 0; 1416 } else { 1417 pp->p_offset = current_offset; 1418 seen_default_offset = 1; 1419 } 1420 } else { 1421 /* allow them to be out of order for old-style tables */ 1422 if (pp->p_offset < current_offset && 1423 seen_default_offset && i != RAW_PART && 1424 pp->p_fstype != FS_VINUM) { 1425 fprintf(stderr, 1426 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n", 1427 (long)pp->p_offset,i+'a',current_offset); 1428 fprintf(stderr, 1429 "Labels with any *'s for offset must be in ascending order by sector\n"); 1430 errors++; 1431 } else if (pp->p_offset != current_offset && 1432 i != RAW_PART && seen_default_offset) { 1433 /* 1434 * this may give unneeded warnings if 1435 * partitions are out-of-order 1436 */ 1437 Warning( 1438 "Offset %ld for partition %c doesn't match expected value %ld", 1439 (long)pp->p_offset, i + 'a', current_offset); 1440 } 1441 } 1442 if (i != RAW_PART) 1443 current_offset = pp->p_offset + pp->p_size; 1444 } 1445 } 1446 1447 for (i = 0; i < lp->d_npartitions; i++) { 1448 part = 'a' + i; 1449 pp = &lp->d_partitions[i]; 1450 if (pp->p_size == 0 && pp->p_offset != 0) 1451 Warning("partition %c: size 0, but offset %lu", 1452 part, (u_long)pp->p_offset); 1453 #ifdef notdef 1454 if (pp->p_size % lp->d_secpercyl) 1455 Warning("partition %c: size %% cylinder-size != 0", 1456 part); 1457 if (pp->p_offset % lp->d_secpercyl) 1458 Warning("partition %c: offset %% cylinder-size != 0", 1459 part); 1460 #endif 1461 if (pp->p_offset > lp->d_secperunit) { 1462 fprintf(stderr, 1463 "partition %c: offset past end of unit\n", part); 1464 errors++; 1465 } 1466 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1467 fprintf(stderr, 1468 "partition %c: partition extends past end of unit\n", 1469 part); 1470 errors++; 1471 } 1472 if (i == RAW_PART) 1473 { 1474 if (pp->p_fstype != FS_UNUSED) 1475 Warning("partition %c is not marked as unused!",part); 1476 if (pp->p_offset != 0) 1477 Warning("partition %c doesn't start at 0!",part); 1478 if (pp->p_size != lp->d_secperunit) 1479 Warning("partition %c doesn't cover the whole unit!",part); 1480 1481 if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) || 1482 (pp->p_size != lp->d_secperunit)) { 1483 Warning("An incorrect partition %c may cause problems for " 1484 "standard system utilities",part); 1485 } 1486 } 1487 1488 /* check for overlaps */ 1489 /* this will check for all possible overlaps once and only once */ 1490 for (j = 0; j < i; j++) { 1491 pp2 = &lp->d_partitions[j]; 1492 if (j != RAW_PART && i != RAW_PART && 1493 pp->p_fstype != FS_VINUM && 1494 pp2->p_fstype != FS_VINUM && 1495 part_set[i] && part_set[j]) { 1496 if (pp2->p_offset < pp->p_offset + pp->p_size && 1497 (pp2->p_offset + pp2->p_size > pp->p_offset || 1498 pp2->p_offset >= pp->p_offset)) { 1499 fprintf(stderr,"partitions %c and %c overlap!\n", 1500 j + 'a', i + 'a'); 1501 errors++; 1502 } 1503 } 1504 } 1505 } 1506 for (; i < 8 || i < lp->d_npartitions; i++) { 1507 part = 'a' + i; 1508 pp = &lp->d_partitions[i]; 1509 if (pp->p_size || pp->p_offset) 1510 Warning("unused partition %c: size %d offset %lu", 1511 'a' + i, pp->p_size, (u_long)pp->p_offset); 1512 } 1513 return (errors); 1514 } 1515 1516 /* 1517 * When operating on a "virgin" disk, try getting an initial label 1518 * from the associated device driver. This might work for all device 1519 * drivers that are able to fetch some initial device parameters 1520 * without even having access to a (BSD) disklabel, like SCSI disks, 1521 * most IDE drives, or vn devices. 1522 */ 1523 static struct disklabel32 dlab; 1524 1525 struct disklabel32 * 1526 getvirginlabel(void) 1527 { 1528 struct partinfo info; 1529 struct disklabel32 *dl = &dlab; 1530 int f; 1531 1532 if ((f = open(dkname, O_RDONLY)) == -1) { 1533 warn("cannot open %s", dkname); 1534 return (NULL); 1535 } 1536 1537 /* 1538 * Check to see if the media is too big for a 32 bit disklabel. 1539 */ 1540 if (ioctl(f, DIOCGPART, &info) == 0) { 1541 if (info.media_size >= 0x100000000ULL * 512) { 1542 warnx("The media is too large for a 32 bit disklabel," 1543 " please use disklabel64."); 1544 return (NULL); 1545 } 1546 } 1547 1548 /* 1549 * Generate a virgin disklabel via ioctl 1550 */ 1551 if (ioctl(f, DIOCGDVIRGIN32, dl) < 0) { 1552 l_perror("ioctl DIOCGDVIRGIN32"); 1553 close(f); 1554 return(NULL); 1555 } 1556 close(f); 1557 return (dl); 1558 } 1559 1560 struct disklabel32 * 1561 getdisklabelfromdisktab(const char *name) 1562 { 1563 struct disktab *dt; 1564 struct disklabel32 *dl = &dlab; 1565 int i; 1566 1567 if ((dt = getdisktabbyname(name)) == NULL) 1568 return(NULL); 1569 dl->d_magic = DISKMAGIC32; 1570 dl->d_type = dt->d_typeid; 1571 dl->d_subtype = 0; 1572 dl->d_secsize = dt->d_media_blksize; 1573 dl->d_nsectors = dt->d_secpertrack; 1574 dl->d_ntracks = dt->d_nheads; 1575 dl->d_ncylinders = dt->d_ncylinders; 1576 dl->d_secpercyl = dt->d_secpercyl; 1577 dl->d_secperunit = dt->d_media_blocks; 1578 dl->d_rpm = dt->d_rpm; 1579 dl->d_interleave = dt->d_interleave; 1580 dl->d_trackskew = dt->d_trackskew; 1581 dl->d_cylskew = dt->d_cylskew; 1582 dl->d_headswitch = dt->d_headswitch; 1583 dl->d_trkseek = dt->d_trkseek; 1584 dl->d_magic2 = DISKMAGIC32; 1585 dl->d_npartitions = dt->d_npartitions; 1586 dl->d_bbsize = dt->d_bbsize; 1587 dl->d_sbsize = dt->d_sbsize; 1588 for (i = 0; i < dt->d_npartitions; ++i) { 1589 struct partition32 *dlp = &dl->d_partitions[i]; 1590 struct dt_partition *dtp = &dt->d_partitions[i]; 1591 1592 dlp->p_size = dtp->p_size; 1593 dlp->p_offset = dtp->p_offset; 1594 dlp->p_fsize = dtp->p_fsize; 1595 dlp->p_fstype = dtp->p_fstype; 1596 dlp->p_frag = dtp->p_fsize; 1597 } 1598 return(dl); 1599 } 1600 1601 /* 1602 * If we are installing a boot program that doesn't fit in d_bbsize 1603 * we need to mark those partitions that the boot overflows into. 1604 * This allows newfs to prevent creation of a filesystem where it might 1605 * clobber bootstrap code. 1606 */ 1607 void 1608 setbootflag(struct disklabel32 *lp) 1609 { 1610 struct partition32 *pp; 1611 int i, errors = 0; 1612 char part; 1613 u_long boffset; 1614 1615 if (bootbuf == NULL) 1616 return; 1617 boffset = bootsize / lp->d_secsize; 1618 for (i = 0; i < lp->d_npartitions; i++) { 1619 part = 'a' + i; 1620 pp = &lp->d_partitions[i]; 1621 if (pp->p_size == 0) 1622 continue; 1623 if (boffset <= pp->p_offset) { 1624 if (pp->p_fstype == FS_BOOT) 1625 pp->p_fstype = FS_UNUSED; 1626 } else if (pp->p_fstype != FS_BOOT) { 1627 if (pp->p_fstype != FS_UNUSED) { 1628 fprintf(stderr, 1629 "boot overlaps used partition %c\n", 1630 part); 1631 errors++; 1632 } else { 1633 pp->p_fstype = FS_BOOT; 1634 Warning("boot overlaps partition %c, %s", 1635 part, "marked as FS_BOOT"); 1636 } 1637 } 1638 } 1639 if (errors) 1640 errx(4, "cannot install boot program"); 1641 } 1642 1643 /*VARARGS1*/ 1644 void 1645 Warning(const char *fmt, ...) 1646 { 1647 va_list ap; 1648 1649 fprintf(stderr, "Warning, "); 1650 va_start(ap, fmt); 1651 vfprintf(stderr, fmt, ap); 1652 fprintf(stderr, "\n"); 1653 va_end(ap); 1654 } 1655 1656 /* 1657 * Check to see if the bootblocks are in the wrong place. FBsd5 bootblocks 1658 * and earlier DFly bb's are packed against the old disklabel and a new 1659 * disklabel would blow them up. This is a hack that should be removed 1660 * in 2006 sometime (if ever). 1661 */ 1662 1663 int 1664 checkoldboot(int f, const char *bootbuffer) 1665 { 1666 char buf[BBSIZE]; 1667 1668 if (bootbuffer && strncmp(bootbuffer + 0x402, "BTX", 3) == 0) 1669 return(0); 1670 lseek(f, (off_t)0, SEEK_SET); 1671 if (read(f, buf, sizeof(buf)) != sizeof(buf)) 1672 return(0); 1673 if (strncmp(buf + 0x402, "BTX", 3) == 0) /* new location */ 1674 return(0); 1675 if (strncmp(buf + 0x316, "BTX", 3) == 0) /* old location */ 1676 return(1); 1677 return(0); 1678 } 1679 1680 /* 1681 * Traditional 32 bit disklabels actually use absolute sector numbers on 1682 * disk, NOT slice relative sector numbres. The OS hides this from us 1683 * when we use DIOC ioctls to access the label, but newer versions of 1684 * Dragonfly no longer adjusts the disklabel when snooping reads or writes 1685 * so we have to figure it out ourselves. 1686 */ 1687 const char * 1688 fixlabel(int f, struct disklabel32 *lp, int writeadj) 1689 { 1690 const char *msg = NULL; 1691 struct partinfo info; 1692 struct partition32 *pp; 1693 u_int64_t start; 1694 u_int64_t end; 1695 u_int64_t offset; 1696 int part; 1697 int rev; 1698 size_t rev_len = sizeof(rev); 1699 1700 if (sysctlbyname("kern.osrevision", &rev, &rev_len, NULL, 0) < 0) { 1701 errx(1, "Cannot use raw mode on non-DragonFly systems\n"); 1702 } 1703 if (rev < 200701) { 1704 warnx("Warning running new disklabel on old DragonFly systems,\n" 1705 "assuming the disk layer will fixup the label.\n"); 1706 sleep(3); 1707 return(NULL); 1708 } 1709 1710 pp = &lp->d_partitions[RAW_PART]; 1711 1712 if (forceflag) { 1713 info.media_offset = slice_start_lba * lp->d_secsize; 1714 info.media_blocks = pp->p_size; 1715 info.media_blksize = lp->d_secsize; 1716 } else if (ioctl(f, DIOCGPART, &info) < 0) { 1717 msg = "Unable to extract the slice starting LBA, " 1718 "you must use the -f <slice_start_lba> option\n" 1719 "to specify it manually, or perhaps try without " 1720 "using -r and let the kernel deal with it\n"; 1721 return(msg); 1722 } 1723 1724 if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32) 1725 return ("fixlabel: invalid magic"); 1726 if (dkcksum32(lp) != 0) 1727 return ("fixlabel: invalid checksum"); 1728 1729 /* 1730 * What a mess. For ages old backwards compatibility the disklabel 1731 * on-disk stores absolute offsets instead of slice-relative offsets. 1732 * So fix it up when reading, writing, or snooping. 1733 * 1734 * The in-core label is always slice-relative. 1735 */ 1736 if (writeadj) { 1737 /* 1738 * incore -> disk 1739 */ 1740 start = 0; 1741 offset = info.media_offset / info.media_blksize; 1742 } else { 1743 /* 1744 * disk -> incore 1745 */ 1746 start = info.media_offset / info.media_blksize; 1747 offset = -info.media_offset / info.media_blksize; 1748 } 1749 if (pp->p_offset != start) 1750 return ("fixlabel: raw partition offset != slice offset"); 1751 if (pp->p_size != info.media_blocks) { 1752 if (pp->p_size > info.media_blocks) 1753 return ("fixlabel: raw partition size > slice size"); 1754 } 1755 end = start + info.media_blocks; 1756 if (start > end) 1757 return ("fixlabel: slice wraps"); 1758 if (lp->d_secpercyl <= 0) 1759 return ("fixlabel: d_secpercyl <= 0"); 1760 pp -= RAW_PART; 1761 for (part = 0; part < lp->d_npartitions; part++, pp++) { 1762 if (pp->p_offset != 0 || pp->p_size != 0) { 1763 if (pp->p_offset < start 1764 || pp->p_offset + pp->p_size > end 1765 || pp->p_offset + pp->p_size < pp->p_offset) { 1766 /* XXX else silently discard junk. */ 1767 bzero(pp, sizeof *pp); 1768 } else { 1769 pp->p_offset += offset; 1770 } 1771 } 1772 } 1773 lp->d_checksum = 0; 1774 lp->d_checksum = dkcksum32(lp); 1775 return (NULL); 1776 } 1777 1778 void 1779 usage(void) 1780 { 1781 #if NUMBOOT > 0 1782 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", 1783 "usage: disklabel32 [-r] disk", 1784 "\t\t(to read label)", 1785 " disklabel32 -w [-r] [-n] disk type [packid]", 1786 "\t\t(to write label with existing boot program)", 1787 " disklabel32 -e [-r] [-n] disk", 1788 "\t\t(to edit label)", 1789 " disklabel32 -R [-r] [-n] disk protofile", 1790 "\t\t(to restore label with existing boot program)", 1791 #if NUMBOOT > 1 1792 " disklabel32 -B [-n] [-b boot1 -s boot2] disk [type]", 1793 "\t\t(to install boot program with existing label)", 1794 " disklabel32 -w -B [-n] [-b boot1 -s boot2] disk type [packid]", 1795 "\t\t(to write label and boot program)", 1796 " disklabel32 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]", 1797 "\t\t(to restore label and boot program)", 1798 #else 1799 " disklabel32 -B [-n] [-b bootprog] disk [type]", 1800 "\t\t(to install boot program with existing on-disk label)", 1801 " disklabel32 -w -B [-n] [-b bootprog] disk type [packid]", 1802 "\t\t(to write label and install boot program)", 1803 " disklabel32 -R -B [-n] [-b bootprog] disk protofile [type]", 1804 "\t\t(to restore label and install boot program)", 1805 #endif 1806 " disklabel32 [-NW] disk", 1807 "\t\t(to write disable/enable label)"); 1808 #else 1809 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 1810 "usage: disklabel32 [-r] disk", "(to read label)", 1811 " disklabel32 -w [-r] [-n] disk type [packid]", 1812 "\t\t(to write label)", 1813 " disklabel32 -e [-r] [-n] disk", 1814 "\t\t(to edit label)", 1815 " disklabel32 -R [-r] [-n] disk protofile", 1816 "\t\t(to restore label)", 1817 " disklabel32 [-NW] disk", 1818 "\t\t(to write disable/enable label)"); 1819 #endif 1820 fprintf(stderr, "%s\n%s\n", 1821 " disklabel32 [-f slice_start_lba] [options]", 1822 "\t\t(to force using manual offset)"); 1823 exit(1); 1824 } 1825