1 /* $OpenBSD: disklabel.c,v 1.151 2009/04/12 01:01:24 krw Exp $ */ 2 3 /* 4 * Copyright (c) 1987, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Symmetric Computer Systems. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifndef lint 36 static const char copyright[] = 37 "@(#) Copyright (c) 1987, 1993\n\ 38 The Regents of the University of California. All rights reserved.\n"; 39 #endif /* not lint */ 40 41 #ifndef lint 42 static const char rcsid[] = "$OpenBSD: disklabel.c,v 1.151 2009/04/12 01:01:24 krw Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/ioctl.h> 47 #include <sys/stat.h> 48 #include <sys/wait.h> 49 #define DKTYPENAMES 50 #include <sys/disklabel.h> 51 52 #include <ufs/ffs/fs.h> 53 54 #include <ctype.h> 55 #include <err.h> 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <limits.h> 59 #include <signal.h> 60 #include <string.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <unistd.h> 64 #include <util.h> 65 #include "pathnames.h" 66 #include "extern.h" 67 68 /* 69 * Disklabel: read and write disklabels. 70 * The label is usually placed on one of the first sectors of the disk. 71 * Many machines also place a bootstrap in the same area, 72 * in which case the label is embedded in the bootstrap. 73 * The bootstrap source must leave space at the proper offset 74 * for the label on such machines. 75 */ 76 77 #ifndef BBSIZE 78 #define BBSIZE 8192 /* size of boot area, with label */ 79 #endif 80 81 #ifndef NUMBOOT 82 #define NUMBOOT 0 83 #endif 84 85 char *dkname, *specname, *fstabfile; 86 char tmpfil[] = _PATH_TMPFILE; 87 char *mountpoints[MAXPARTITIONS]; 88 struct disklabel lab; 89 char bootarea[BBSIZE]; 90 91 #if NUMBOOT > 0 92 char namebuf[BBSIZE], *np = namebuf; 93 int installboot; /* non-zero if we should install a boot program */ 94 char *bootbuf; /* pointer to buffer with remainder of boot prog */ 95 int bootsize; /* size of remaining boot program */ 96 char *xxboot; /* primary boot */ 97 char *bootxx; /* secondary boot */ 98 char boot0[MAXPATHLEN]; 99 void setbootflag(struct disklabel *); 100 #endif 101 102 enum { 103 UNSPEC, EDIT, EDITOR, READ, RESTORE, SETWRITEABLE, WRITE, WRITEBOOT 104 } op = UNSPEC; 105 106 int aflag; 107 int cflag; 108 int dflag; 109 int tflag; 110 int verbose; 111 int donothing; 112 char print_unit; 113 114 #ifdef DOSLABEL 115 struct dos_partition *dosdp; /* DOS partition, if found */ 116 struct dos_partition *findopenbsd(int, off_t, struct dos_partition **, int *); 117 struct dos_partition *readmbr(int); 118 #endif 119 120 #ifdef DPMELABEL 121 int dpme_label = 0; 122 uint32_t dpme_obsd_start, dpme_obsd_size; 123 int check_dpme(int, uint32_t *, uint32_t *); 124 #endif 125 126 void makedisktab(FILE *, struct disklabel *); 127 void makelabel(char *, char *, struct disklabel *); 128 int writelabel(int, char *, struct disklabel *); 129 void l_perror(char *); 130 int edit(struct disklabel *, int); 131 int editit(const char *); 132 char *skip(char *); 133 char *word(char *); 134 int getasciilabel(FILE *, struct disklabel *); 135 int cmplabel(struct disklabel *, struct disklabel *); 136 void usage(void); 137 u_int64_t getnum(char *, u_int64_t, u_int64_t, const char **); 138 139 int 140 main(int argc, char *argv[]) 141 { 142 int ch, f, writeable, error = 0; 143 struct disklabel *lp; 144 FILE *t; 145 146 while ((ch = getopt(argc, argv, "ABEf:NRWb:cdenp:s:tvw")) != -1) 147 switch (ch) { 148 case 'A': 149 ++aflag; 150 break; 151 #if NUMBOOT > 0 152 case 'B': 153 ++installboot; 154 break; 155 case 'b': 156 xxboot = optarg; 157 break; 158 #endif 159 case 'N': 160 if (op != UNSPEC) 161 usage(); 162 writeable = 0; 163 op = SETWRITEABLE; 164 break; 165 case 'R': 166 if (op != UNSPEC) 167 usage(); 168 op = RESTORE; 169 break; 170 case 'W': 171 if (op != UNSPEC) 172 usage(); 173 writeable = 1; 174 op = SETWRITEABLE; 175 break; 176 case 'c': 177 ++cflag; 178 break; 179 case 'd': 180 ++dflag; 181 break; 182 case 'e': 183 if (op != UNSPEC) 184 usage(); 185 op = EDIT; 186 break; 187 case 'E': 188 if (op != UNSPEC) 189 usage(); 190 op = EDITOR; 191 break; 192 case 'f': 193 fstabfile = optarg; 194 break; 195 case 't': 196 ++tflag; 197 break; 198 case 'w': 199 if (op != UNSPEC) 200 usage(); 201 op = WRITE; 202 break; 203 case 'p': 204 if (strchr("bckmgt", optarg[0]) == NULL || 205 optarg[1] != '\0') 206 usage(); 207 print_unit = optarg[0]; 208 break; 209 case 'n': 210 donothing++; 211 break; 212 case 'v': 213 verbose++; 214 break; 215 case '?': 216 default: 217 usage(); 218 } 219 argc -= optind; 220 argv += optind; 221 222 #if NUMBOOT > 0 223 if (installboot) { 224 if (op == UNSPEC) 225 op = WRITEBOOT; 226 } else { 227 if (op == UNSPEC) 228 op = READ; 229 } 230 #else 231 if (op == UNSPEC) 232 op = READ; 233 #endif 234 235 if (argc < 1 || (fstabfile && !(op == EDITOR | aflag))) 236 usage(); 237 238 dkname = argv[0]; 239 f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART, 240 &specname); 241 if (f < 0) 242 err(4, "%s", specname); 243 244 #ifdef DOSLABEL 245 /* 246 * Check for presence of DOS partition table in 247 * master boot record. Return pointer to OpenBSD 248 * partition, if present. If no valid partition table, 249 * return NULL. If valid partition table present, but no 250 * partition to use, return a pointer to a non-386bsd 251 * partition. 252 */ 253 dosdp = readmbr(f); 254 #endif 255 256 #ifdef DPMELABEL 257 /* 258 * Check for a MacOS DPME partition table, and find out the 259 * area of the OpenBSD DPME partition, if any. 260 */ 261 dpme_label = check_dpme(f, &dpme_obsd_start, &dpme_obsd_size); 262 #endif 263 264 switch (op) { 265 case EDIT: 266 if (argc != 1) 267 usage(); 268 readlabel(f); 269 error = edit(&lab, f); 270 break; 271 case EDITOR: 272 if (argc != 1) 273 usage(); 274 readlabel(f); 275 error = editor(&lab, f); 276 break; 277 case READ: 278 if (argc != 1) 279 usage(); 280 readlabel(f); 281 if (tflag) 282 makedisktab(stdout, &lab); 283 else 284 display(stdout, &lab, print_unit, 1); 285 error = checklabel(&lab); 286 break; 287 case RESTORE: 288 if (argc < 2 || argc > 3) 289 usage(); 290 #if NUMBOOT > 0 291 if (installboot && argc == 3) 292 makelabel(argv[2], NULL, &lab); 293 #endif 294 lp = makebootarea(bootarea, &lab, f); 295 if (!(t = fopen(argv[1], "r"))) 296 err(4, "%s", argv[1]); 297 if (getasciilabel(t, lp)) 298 error = writelabel(f, bootarea, lp); 299 else 300 error = 1; 301 fclose(t); 302 break; 303 case SETWRITEABLE: 304 if (!donothing) { 305 if (ioctl(f, DIOCWLABEL, (char *)&writeable) < 0) 306 err(4, "ioctl DIOCWLABEL"); 307 } 308 break; 309 case WRITE: 310 if (dflag | aflag) { 311 readlabel(f); 312 } else if (argc < 2 || argc > 3) 313 usage(); 314 else 315 makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab); 316 lp = makebootarea(bootarea, &lab, f); 317 *lp = lab; 318 if (checklabel(lp) == 0) 319 error = writelabel(f, bootarea, lp); 320 break; 321 #if NUMBOOT > 0 322 case WRITEBOOT: 323 { 324 struct disklabel tlab; 325 326 readlabel(f); 327 tlab = lab; 328 if (argc == 2) 329 makelabel(argv[1], NULL, &lab); 330 lp = makebootarea(bootarea, &lab, f); 331 *lp = tlab; 332 if (checklabel(lp) == 0) 333 error = writelabel(f, bootarea, lp); 334 break; 335 } 336 #endif 337 default: 338 break; 339 } 340 exit(error); 341 } 342 343 /* 344 * Construct a prototype disklabel from /etc/disktab. As a side 345 * effect, set the names of the primary and secondary boot files 346 * if specified. 347 */ 348 void 349 makelabel(char *type, char *name, struct disklabel *lp) 350 { 351 struct disklabel *dp; 352 353 dp = getdiskbyname(type); 354 if (dp == NULL) 355 errx(1, "unknown disk type: %s", type); 356 *lp = *dp; 357 #if NUMBOOT > 0 358 /* 359 * Set bootstrap name(s). 360 * 1. If set from command line, use those, 361 * 2. otherwise, check if disktab specifies them (b0 or b1), 362 * 3. otherwise, makebootarea() will choose ones based on the name 363 * of the disk special file. E.g. /dev/ra0 -> raboot, bootra 364 */ 365 if (!xxboot && lp->d_boot0) { 366 if (*lp->d_boot0 != '/') 367 (void)snprintf(boot0, sizeof boot0, "%s%s", 368 _PATH_BOOTDIR, lp->d_boot0); 369 else 370 (void)strlcpy(boot0, lp->d_boot0, sizeof boot0); 371 xxboot = boot0; 372 } 373 #endif 374 /* d_packname is union d_boot[01], so zero */ 375 memset(lp->d_packname, 0, sizeof(lp->d_packname)); 376 if (name) 377 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 378 } 379 380 381 int 382 writelabel(int f, char *boot, struct disklabel *lp) 383 { 384 #if NUMBOOT > 0 385 int writeable; 386 off_t sectoffset = 0; 387 #endif 388 389 #if NUMBOOT > 0 390 setbootflag(lp); 391 #endif 392 lp->d_magic = DISKMAGIC; 393 lp->d_magic2 = DISKMAGIC; 394 lp->d_checksum = 0; 395 lp->d_checksum = dkcksum(lp); 396 #if NUMBOOT > 0 397 if (installboot) { 398 #ifdef DOSLABEL 399 struct partition *pp = &lp->d_partitions[2]; 400 401 /* 402 * If OpenBSD DOS partition is missing, or if 403 * the label to be written is not within partition, 404 * prompt first. Need to allow this in case operator 405 * wants to convert the drive for dedicated use. 406 * In this case, partition 'a' had better start at 0, 407 * otherwise we reject the request as meaningless. -wfj 408 */ 409 if (dosdp && DL_GETPSIZE(pp) && (dosdp->dp_typ == DOSPTYP_OPENBSD)) { 410 sectoffset = (off_t)letoh32(dosdp->dp_start) * 411 lp->d_secsize; 412 } else { 413 if (dosdp) { 414 int first, ch; 415 416 printf("Erase the previous contents of the disk? [n]: "); 417 fflush(stdout); 418 first = ch = getchar(); 419 while (ch != '\n' && ch != EOF) 420 ch = getchar(); 421 if (first != 'y' && first != 'Y') 422 exit(0); 423 } 424 sectoffset = 0; 425 } 426 #endif 427 /* 428 * First set the kernel disk label, 429 * then write a label to the raw disk. 430 * If the SDINFO ioctl fails because it is unimplemented, 431 * keep going; otherwise, the kernel consistency checks 432 * may prevent us from changing the current (in-core) 433 * label. 434 */ 435 if (!donothing) { 436 if (ioctl(f, DIOCSDINFO, lp) < 0 && 437 errno != ENODEV && errno != ENOTTY) { 438 l_perror("ioctl DIOCSDINFO"); 439 return (1); 440 } 441 } 442 if (verbose) 443 printf("writing label to block %lld (0x%qx)\n", 444 (long long)sectoffset/DEV_BSIZE, 445 (long long)sectoffset/DEV_BSIZE); 446 if (!donothing) { 447 if (lseek(f, sectoffset, SEEK_SET) < 0) { 448 perror("lseek"); 449 return (1); 450 } 451 /* 452 * write enable label sector before write (if necessary), 453 * disable after writing. 454 */ 455 writeable = 1; 456 457 if (ioctl(f, DIOCWLABEL, &writeable) < 0) 458 perror("ioctl DIOCWLABEL"); 459 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) { 460 perror("write"); 461 return (1); 462 } 463 } 464 /* 465 * Output the remainder of the disklabel 466 */ 467 if (!donothing && bootbuf && write(f, bootbuf, bootsize) != bootsize) { 468 perror("write"); 469 return(1); 470 } 471 writeable = 0; 472 if (!donothing) 473 if (ioctl(f, DIOCWLABEL, &writeable) < 0) 474 perror("ioctl DIOCWLABEL"); 475 } else 476 #endif /* NUMBOOT > 0 */ 477 if (!donothing) { 478 if (ioctl(f, DIOCWDINFO, lp) < 0) { 479 l_perror("ioctl DIOCWDINFO"); 480 return (1); 481 } 482 } 483 #ifdef __vax__ 484 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 485 off_t alt; 486 int i; 487 488 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 489 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 490 (void)lseek(f, (alt + i) * lp->d_secsize, SEEK_SET); 491 if (!donothing) 492 if (write(f, boot, lp->d_secsize) != lp->d_secsize) 493 warn("alternate label %d write", i/2); 494 } 495 } 496 #endif 497 return (0); 498 } 499 500 void 501 l_perror(char *s) 502 { 503 504 switch (errno) { 505 case ESRCH: 506 warnx("%s: No disk label on disk", s); 507 break; 508 case EINVAL: 509 warnx("%s: Label magic number or checksum is wrong!\n" 510 "(disklabel or kernel is out of date?)", s); 511 break; 512 case EBUSY: 513 warnx("%s: Open partition would move or shrink", s); 514 break; 515 case EXDEV: 516 warnx("%s: Labeled partition or 'a' partition must start " 517 "at beginning of disk", s); 518 break; 519 default: 520 warn("%s", s); 521 break; 522 } 523 } 524 525 #ifdef DOSLABEL 526 struct dos_partition * 527 findopenbsd(int f, off_t mbroff, struct dos_partition **first, int *n) 528 { 529 static struct dos_partition res; 530 int mbr[DEV_BSIZE / sizeof(int)]; 531 struct dos_partition *dp, *p; 532 u_int16_t signature; 533 u_int32_t start = 0; 534 int part; 535 536 /* Limit the number of recursions */ 537 if (!(*n)--) 538 return (NULL); 539 540 /* 541 * This must be done this way due to alignment restrictions 542 * in for example mips processors. 543 */ 544 dp = (struct dos_partition *)mbr; 545 if (lseek(f, (off_t)mbroff * DEV_BSIZE, SEEK_SET) < 0 || 546 read(f, mbr, sizeof(mbr)) != sizeof(mbr)) 547 return (NULL); 548 signature = *((u_char *)mbr + DOSMBR_SIGNATURE_OFF) | 549 (*((u_char *)mbr + DOSMBR_SIGNATURE_OFF + 1) << 8); 550 bcopy((char *)mbr+DOSPARTOFF, (char *)mbr, sizeof(*dp) * NDOSPART); 551 552 /* 553 * If there is no signature and no OpenBSD partition this is probably 554 * not an MBR. 555 */ 556 if (signature != DOSMBR_SIGNATURE) 557 return (NULL); 558 559 /* 560 * Don't (yet) know disk geometry, use partition table to find OpenBSD 561 * partition, and obtain disklabel from there. 562 */ 563 /* Check if table is valid. */ 564 for (part = 0; part < NDOSPART; part++) { 565 if ((dp[part].dp_flag & ~0x80) != 0) 566 return (NULL); 567 } 568 /* Find OpenBSD partition. */ 569 for (part = 0; part < NDOSPART; part++) { 570 if (!letoh32(dp[part].dp_size)) 571 continue; 572 if (first && *first == NULL) { 573 bcopy(&dp[part], &res, sizeof(struct dos_partition)); 574 *first = &res; 575 } 576 switch (dp[part].dp_typ) { 577 case DOSPTYP_OPENBSD: 578 if (verbose) 579 fprintf(stderr, "# Inside MBR partition %d: " 580 "type %02X start %u size %u\n", part, 581 dp[part].dp_typ, letoh32(dp[part].dp_start), 582 letoh32(dp[part].dp_size)); 583 bcopy(&dp[part], &res, sizeof(struct dos_partition)); 584 res.dp_start = 585 htole32((off_t)letoh32(res.dp_start) + mbroff); 586 return (&res); 587 case DOSPTYP_EXTEND: 588 case DOSPTYP_EXTENDL: 589 fprintf(stderr, "# Extended partition %d: " 590 "type %02X start %u size %u\n", 591 part, dp[part].dp_typ, 592 letoh32(dp[part].dp_start), letoh32(dp[part].dp_size)); 593 start = letoh32(dp[part].dp_start) + mbroff; 594 p = findopenbsd(f, start, NULL, n); 595 if (p != NULL) 596 return (p); 597 break; 598 } 599 } 600 601 return (NULL); 602 } 603 604 /* 605 * Fetch DOS partition table from disk. 606 */ 607 struct dos_partition * 608 readmbr(int f) 609 { 610 struct dos_partition *dp, *first = NULL; 611 int n = 8; 612 613 dp = findopenbsd(f, DOSBBSECTOR, &first, &n); 614 if (dp != NULL) 615 return (dp); 616 617 /* If no OpenBSD partition, find first used partition. */ 618 if (first != NULL) { 619 warnx("warning, DOS partition table with no valid OpenBSD partition"); 620 return (first); 621 } 622 623 /* Table appears to be empty. */ 624 return (NULL); 625 } 626 #endif 627 628 #ifdef DPMELABEL 629 int 630 check_dpme(int f, uint32_t *start, uint32_t *size) 631 { 632 char sector[DEV_BSIZE]; 633 unsigned int partno, partcnt; 634 struct part_map_entry part; 635 636 /* 637 * Read what would be the first DPME partition, and 638 * check for a valid signature. 639 */ 640 641 if (lseek(f, (off_t)DEV_BSIZE, SEEK_SET) < 0 || 642 read(f, sector, sizeof(sector)) != sizeof(sector)) 643 return (0); 644 /* no direct derefence due to strict alignment */ 645 memcpy(&part, sector, sizeof part); 646 647 if (part.pmSig != PART_ENTRY_MAGIC) 648 return (0); 649 650 /* 651 * If the signature matches, perform a few more sanity checks, 652 * and then loop over the remaining partitions. We can safely 653 * rely on the first entry being of the partition map type, 654 * so it's ok to skip it. 655 */ 656 657 partcnt = part.pmMapBlkCnt; 658 if (partcnt <= 1 || partcnt > 32) 659 return (0); 660 661 for (partno = 2; partno <= partcnt; partno++) { 662 if (lseek(f, (off_t)partno * DEV_BSIZE, SEEK_SET) < 0 || 663 read(f, sector, sizeof(sector)) != sizeof(sector)) 664 return (0); 665 /* no direct derefence due to strict alignment */ 666 memcpy(&part, sector, sizeof part); 667 668 if (part.pmSig != PART_ENTRY_MAGIC) 669 return (0); 670 671 if (strcasecmp(part.pmPartType, PART_TYPE_OPENBSD) == 0) { 672 *start = part.pmPyPartStart; 673 *size = part.pmPartBlkCnt; 674 return (1); 675 } 676 } 677 678 return (0); 679 } 680 #endif 681 682 /* 683 * Fetch requested disklabel into 'lab' using ioctl. 684 */ 685 void 686 readlabel(int f) 687 { 688 if (cflag && ioctl(f, DIOCRLDINFO) < 0) 689 err(4, "ioctl DIOCRLDINFO"); 690 691 if (dflag | aflag) { 692 if (ioctl(f, DIOCGPDINFO, &lab) < 0) 693 err(4, "ioctl DIOCGPDINFO"); 694 } else { 695 if (ioctl(f, DIOCGDINFO, &lab) < 0) 696 err(4, "ioctl DIOCGDINFO"); 697 } 698 699 if (aflag) 700 editor_allocspace(&lab); 701 } 702 703 /* 704 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' 705 * Returns a pointer to the disklabel portion of the bootarea. 706 */ 707 struct disklabel * 708 makebootarea(char *boot, struct disklabel *dp, int f) 709 { 710 struct disklabel *lp; 711 char *p; 712 #if NUMBOOT > 0 713 char *dkbasename; 714 int b; 715 struct stat sb; 716 #endif 717 718 /* XXX */ 719 if (dp->d_secsize == 0) { 720 dp->d_secsize = DEV_BSIZE; 721 dp->d_bbsize = BBSIZE; 722 } 723 lp = (struct disklabel *) 724 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET); 725 memset(lp, 0, sizeof *lp); 726 #if NUMBOOT > 0 727 /* 728 * If we are not installing a boot program but we are installing a 729 * label on disk then we must read the current bootarea so we don't 730 * clobber the existing boot. 731 */ 732 if (!installboot) 733 return (lp); 734 /* 735 * We are installing a boot program. Determine the name(s) and 736 * read them into the appropriate places in the boot area. 737 */ 738 if (!xxboot || !bootxx) { 739 dkbasename = np; 740 if ((p = strrchr(dkname, '/')) == NULL) 741 p = dkname; 742 else 743 p++; 744 while (*p && !isdigit(*p)) 745 *np++ = *p++; 746 *np++ = '\0'; 747 748 if (!xxboot) { 749 (void)snprintf(np, namebuf + sizeof namebuf - np, 750 "%s%sboot", _PATH_BOOTDIR, dkbasename); 751 if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 752 dkbasename++; 753 xxboot = np; 754 (void)snprintf(xxboot, 755 namebuf + sizeof namebuf - np, 756 "%s%sboot", _PATH_BOOTDIR, dkbasename); 757 np += strlen(xxboot) + 1; 758 } 759 } 760 if (verbose) 761 warnx("bootstraps: xxboot = %s, bootxx = %s", xxboot, 762 bootxx ? bootxx : "NONE"); 763 764 /* 765 * For NUMBOOT > 0 architectures (hp300/hppa/hppa64/landisk/vax) 766 * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest 767 * is remembered and written later following the bootarea. 768 */ 769 b = open(xxboot, O_RDONLY); 770 if (b < 0) 771 err(4, "%s", xxboot); 772 if (read(b, boot, (int)dp->d_bbsize) < 0) 773 err(4, "%s", xxboot); 774 (void)fstat(b, &sb); 775 bootsize = (int)sb.st_size - dp->d_bbsize; 776 if (bootsize > 0) { 777 /* XXX assume d_secsize is a power of two */ 778 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1); 779 bootbuf = (char *)malloc((size_t)bootsize); 780 if (bootbuf == NULL) 781 err(4, "%s", xxboot); 782 if (read(b, bootbuf, bootsize) < 0) { 783 free(bootbuf); 784 err(4, "%s", xxboot); 785 } 786 } 787 (void)close(b); 788 #endif 789 /* 790 * Make sure no part of the bootstrap is written in the area 791 * reserved for the label. 792 */ 793 for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 794 if (*p) 795 errx(2, "Bootstrap doesn't leave room for disk label"); 796 return (lp); 797 } 798 799 void 800 makedisktab(FILE *f, struct disklabel *lp) 801 { 802 int i; 803 char *did = "\\\n\t:"; 804 struct partition *pp; 805 806 if (lp->d_packname[0]) 807 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_packname), 808 lp->d_packname); 809 if (lp->d_typename[0]) 810 (void)fprintf(f, "%.*s|", (int)sizeof(lp->d_typename), 811 lp->d_typename); 812 (void)fputs("Automatically generated label:\\\n\t:dt=", f); 813 if ((unsigned) lp->d_type < DKMAXTYPES) 814 (void)fprintf(f, "%s:", dktypenames[lp->d_type]); 815 else 816 (void)fprintf(f, "unknown%d:", lp->d_type); 817 818 (void)fprintf(f, "se#%u:", lp->d_secsize); 819 (void)fprintf(f, "ns#%u:", lp->d_nsectors); 820 (void)fprintf(f, "nt#%u:", lp->d_ntracks); 821 (void)fprintf(f, "nc#%u:", lp->d_ncylinders); 822 (void)fprintf(f, "sc#%u:", lp->d_secpercyl); 823 (void)fprintf(f, "su#%llu:", DL_GETDSIZE(lp)); 824 825 if (lp->d_rpm != 3600) { 826 (void)fprintf(f, "%srm#%hu:", did, lp->d_rpm); 827 did = ""; 828 } 829 if (lp->d_interleave != 1) { 830 (void)fprintf(f, "%sil#%hu:", did, lp->d_interleave); 831 did = ""; 832 } 833 if (lp->d_trackskew != 0) { 834 (void)fprintf(f, "%ssk#%hu:", did, lp->d_trackskew); 835 did = ""; 836 } 837 if (lp->d_cylskew != 0) { 838 (void)fprintf(f, "%scs#%hu:", did, lp->d_cylskew); 839 did = ""; 840 } 841 if (lp->d_headswitch != 0) { 842 (void)fprintf(f, "%shs#%u:", did, lp->d_headswitch); 843 did = ""; 844 } 845 if (lp->d_trkseek != 0) { 846 (void)fprintf(f, "%sts#%u:", did, lp->d_trkseek); 847 did = ""; 848 } 849 for (i = 0; i < NDDATA; i++) 850 if (lp->d_drivedata[i]) 851 (void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]); 852 pp = lp->d_partitions; 853 for (i = 0; i < lp->d_npartitions; i++, pp++) { 854 if (DL_GETPSIZE(pp)) { 855 char c = 'a' + i; 856 857 (void)fprintf(f, "\\\n\t:"); 858 (void)fprintf(f, "p%c#%llu:", c, DL_GETPSIZE(pp)); 859 (void)fprintf(f, "o%c#%llu:", c, DL_GETPOFFSET(pp)); 860 if (pp->p_fstype != FS_UNUSED) { 861 if ((unsigned) pp->p_fstype < FSMAXTYPES) 862 (void)fprintf(f, "t%c=%s:", c, 863 fstypenames[pp->p_fstype]); 864 else 865 (void)fprintf(f, "t%c=unknown%d:", 866 c, pp->p_fstype); 867 } 868 switch (pp->p_fstype) { 869 870 case FS_UNUSED: 871 break; 872 873 case FS_BSDFFS: 874 (void)fprintf(f, "b%c#%u:", c, 875 DISKLABELV1_FFS_BSIZE(pp->p_fragblock)); 876 (void)fprintf(f, "f%c#%u:", c, 877 DISKLABELV1_FFS_FSIZE(pp->p_fragblock)); 878 break; 879 880 default: 881 break; 882 } 883 } 884 } 885 (void)fputc('\n', f); 886 (void)fflush(f); 887 } 888 889 double 890 scale(u_int64_t sz, char unit, struct disklabel *lp) 891 { 892 double fsz; 893 894 fsz = (double)sz * lp->d_secsize; 895 896 switch (unit) { 897 case 'B': 898 return fsz; 899 case 'C': 900 return fsz / lp->d_secsize / lp->d_secpercyl; 901 case 'K': 902 return fsz / 1024; 903 case 'M': 904 return fsz / (1024 * 1024); 905 case 'G': 906 return fsz / (1024 * 1024 * 1024); 907 case 'T': 908 return fsz / (1024ULL * 1024 * 1024 * 1024); 909 default: 910 return -1.0; 911 } 912 } 913 914 /* 915 * Display a particular partition. 916 */ 917 void 918 display_partition(FILE *f, struct disklabel *lp, int i, char unit) 919 { 920 volatile struct partition *pp = &lp->d_partitions[i]; 921 double p_size, p_offset; 922 923 p_size = scale(DL_GETPSIZE(pp), unit, lp); 924 p_offset = scale(DL_GETPOFFSET(pp), unit, lp); 925 if (DL_GETPSIZE(pp)) { 926 u_int32_t frag = DISKLABELV1_FFS_FRAG(pp->p_fragblock); 927 u_int32_t fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 928 929 if (p_size < 0) 930 fprintf(f, " %c: %16llu %16llu ", 'a' + i, 931 DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); 932 else 933 fprintf(f, " %c: %15.*f%c %15.*f%c ", 'a' + i, 934 unit == 'B' ? 0 : 1, p_size, unit, 935 unit == 'B' ? 0 : 1, p_offset, unit); 936 if ((unsigned) pp->p_fstype < FSMAXTYPES) 937 fprintf(f, "%7.7s", fstypenames[pp->p_fstype]); 938 else 939 fprintf(f, "%7d", pp->p_fstype); 940 941 switch (pp->p_fstype) { 942 case FS_BSDFFS: 943 fprintf(f, " %5u %5u %4hu ", 944 fsize, fsize * frag, 945 pp->p_cpg); 946 break; 947 default: 948 fprintf(f, "%19.19s", ""); 949 break; 950 } 951 952 if (mountpoints[i] != NULL) 953 fprintf(f, "# %s", mountpoints[i]); 954 putc('\n', f); 955 } 956 } 957 958 void 959 display(FILE *f, struct disklabel *lp, char unit, int all) 960 { 961 int i, j; 962 double d; 963 964 unit = toupper(unit); 965 fprintf(f, "# %s:\n", specname); 966 967 if ((unsigned) lp->d_type < DKMAXTYPES) 968 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 969 else 970 fprintf(f, "type: %d\n", lp->d_type); 971 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 972 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 973 fprintf(f, "flags:"); 974 if (lp->d_flags & D_BADSECT) 975 fprintf(f, " badsect"); 976 if (lp->d_flags & D_VENDOR) 977 fprintf(f, " vendor"); 978 putc('\n', f); 979 980 fprintf(f, "bytes/sector: %u\n", lp->d_secsize); 981 fprintf(f, "sectors/track: %u\n", lp->d_nsectors); 982 fprintf(f, "tracks/cylinder: %u\n", lp->d_ntracks); 983 fprintf(f, "sectors/cylinder: %u\n", lp->d_secpercyl); 984 fprintf(f, "cylinders: %u\n", lp->d_ncylinders); 985 d = scale(DL_GETDSIZE(lp), unit, lp); 986 if (d < 0) 987 fprintf(f, "total sectors: %llu\n", DL_GETDSIZE(lp)); 988 else 989 fprintf(f, "total bytes: %.*f%c\n", unit == 'B' ? 0 : 1, 990 d, unit); 991 992 fprintf(f, "rpm: %hu\n", lp->d_rpm); 993 fprintf(f, "interleave: %hu\n", lp->d_interleave); 994 fprintf(f, "trackskew: %hu\n", lp->d_trackskew); 995 fprintf(f, "cylinderskew: %hu\n", lp->d_cylskew); 996 fprintf(f, "headswitch: %u\t\t# microseconds\n", 997 lp->d_headswitch); 998 fprintf(f, "track-to-track seek: %u\t# microseconds\n", 999 lp->d_trkseek); 1000 fprintf(f, "drivedata: "); 1001 for (i = NDDATA - 1; i >= 0; i--) 1002 if (lp->d_drivedata[i]) 1003 break; 1004 if (i < 0) 1005 i = 0; 1006 for (j = 0; j <= i; j++) 1007 fprintf(f, "%d ", lp->d_drivedata[j]); 1008 fprintf(f, "\n"); 1009 if (all) { 1010 fprintf(f, "\n%hu partitions:\n", lp->d_npartitions); 1011 fprintf(f, "# %16.16s %16.16s fstype [fsize bsize cpg]\n", 1012 "size", "offset"); 1013 for (i = 0; i < lp->d_npartitions; i++) 1014 display_partition(f, lp, i, unit); 1015 } 1016 fflush(f); 1017 } 1018 1019 int 1020 edit(struct disklabel *lp, int f) 1021 { 1022 int first, ch, fd; 1023 struct disklabel label; 1024 FILE *fp; 1025 1026 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 1027 if (fd != -1) 1028 close(fd); 1029 warn("%s", tmpfil); 1030 return (1); 1031 } 1032 display(fp, lp, 0, 1); 1033 fprintf(fp, "\n# Notes:\n"); 1034 fprintf(fp, 1035 "# Up to 16 partitions are valid, named from 'a' to 'p'. Partition 'a' is\n" 1036 "# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n" 1037 "# disk. Any other partition is free for any use. 'size' and 'offset' are\n" 1038 "# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n" 1039 "# other values. fsize/bsize/cpg should typically be '2048 16384 16' for a\n" 1040 "# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, ...)\n"); 1041 fclose(fp); 1042 for (;;) { 1043 if (editit(tmpfil) == -1) 1044 break; 1045 fp = fopen(tmpfil, "r"); 1046 if (fp == NULL) { 1047 warn("%s", tmpfil); 1048 break; 1049 } 1050 memset(&label, 0, sizeof(label)); 1051 if (getasciilabel(fp, &label)) { 1052 if (cmplabel(lp, &label) == 0) { 1053 puts("No changes."); 1054 fclose(fp); 1055 (void) unlink(tmpfil); 1056 return (0); 1057 } 1058 *lp = label; 1059 if (writelabel(f, bootarea, lp) == 0) { 1060 fclose(fp); 1061 (void) unlink(tmpfil); 1062 return (0); 1063 } 1064 } 1065 fclose(fp); 1066 printf("re-edit the label? [y]: "); 1067 fflush(stdout); 1068 first = ch = getchar(); 1069 while (ch != '\n' && ch != EOF) 1070 ch = getchar(); 1071 if (first == 'n' || first == 'N') 1072 break; 1073 } 1074 (void)unlink(tmpfil); 1075 return (1); 1076 } 1077 1078 /* 1079 * Execute an editor on the specified pathname, which is interpreted 1080 * from the shell. This means flags may be included. 1081 * 1082 * Returns -1 on error, or the exit value on success. 1083 */ 1084 int 1085 editit(const char *pathname) 1086 { 1087 char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p; 1088 sig_t sighup, sigint, sigquit, sigchld; 1089 pid_t pid; 1090 int saved_errno, st, ret = -1; 1091 1092 ed = getenv("VISUAL"); 1093 if (ed == NULL || ed[0] == '\0') 1094 ed = getenv("EDITOR"); 1095 if (ed == NULL || ed[0] == '\0') 1096 ed = _PATH_VI; 1097 if (asprintf(&p, "%s %s", ed, pathname) == -1) 1098 return (-1); 1099 argp[2] = p; 1100 1101 sighup = signal(SIGHUP, SIG_IGN); 1102 sigint = signal(SIGINT, SIG_IGN); 1103 sigquit = signal(SIGQUIT, SIG_IGN); 1104 sigchld = signal(SIGCHLD, SIG_DFL); 1105 if ((pid = fork()) == -1) 1106 goto fail; 1107 if (pid == 0) { 1108 execv(_PATH_BSHELL, argp); 1109 _exit(127); 1110 } 1111 while (waitpid(pid, &st, 0) == -1) 1112 if (errno != EINTR) 1113 goto fail; 1114 if (!WIFEXITED(st)) 1115 errno = EINTR; 1116 else 1117 ret = WEXITSTATUS(st); 1118 1119 fail: 1120 saved_errno = errno; 1121 (void)signal(SIGHUP, sighup); 1122 (void)signal(SIGINT, sigint); 1123 (void)signal(SIGQUIT, sigquit); 1124 (void)signal(SIGCHLD, sigchld); 1125 free(p); 1126 errno = saved_errno; 1127 return (ret); 1128 } 1129 1130 char * 1131 skip(char *cp) 1132 { 1133 1134 cp += strspn(cp, " \t"); 1135 if (*cp == '\0') 1136 return (NULL); 1137 return (cp); 1138 } 1139 1140 char * 1141 word(char *cp) 1142 { 1143 1144 cp += strcspn(cp, " \t"); 1145 if (*cp == '\0') 1146 return (NULL); 1147 *cp++ = '\0'; 1148 cp += strspn(cp, " \t"); 1149 if (*cp == '\0') 1150 return (NULL); 1151 return (cp); 1152 } 1153 1154 /* Base the max value on the sizeof of the value we are reading */ 1155 #define GETNUM(field, nptr, min, errstr) \ 1156 getnum((nptr), (min), \ 1157 sizeof(field) == 8 ? LLONG_MAX : \ 1158 (sizeof(field) == 4 ? UINT_MAX : \ 1159 (sizeof(field) == 2 ? USHRT_MAX : UCHAR_MAX)), (errstr)) 1160 1161 u_int64_t 1162 getnum(char *nptr, u_int64_t min, u_int64_t max, const char **errstr) 1163 { 1164 char *p, c; 1165 u_int64_t ret; 1166 1167 for (p = nptr; *p != '\0' && !isspace(*p); p++) 1168 ; 1169 c = *p; 1170 *p = '\0'; 1171 ret = strtonum(nptr, min, max, errstr); 1172 *p = c; 1173 return (ret); 1174 } 1175 1176 /* 1177 * Read an ascii label in from FILE f, 1178 * in the same format as that put out by display(), 1179 * and fill in lp. 1180 */ 1181 int 1182 getasciilabel(FILE *f, struct disklabel *lp) 1183 { 1184 char **cpp, *cp; 1185 const char *errstr; 1186 struct partition *pp; 1187 char *tp, *s, line[BUFSIZ]; 1188 int lineno = 0, errors = 0; 1189 u_int32_t v, fsize; 1190 u_int64_t lv; 1191 1192 lp->d_version = 1; 1193 lp->d_bbsize = BBSIZE; /* XXX */ 1194 lp->d_sbsize = SBSIZE; /* XXX */ 1195 while (fgets(line, sizeof(line), f)) { 1196 lineno++; 1197 if ((cp = strpbrk(line, "#\r\n"))) 1198 *cp = '\0'; 1199 cp = skip(line); 1200 if (cp == NULL) 1201 continue; 1202 tp = strchr(cp, ':'); 1203 if (tp == NULL) { 1204 warnx("line %d: syntax error", lineno); 1205 errors++; 1206 continue; 1207 } 1208 *tp++ = '\0', tp = skip(tp); 1209 if (!strcmp(cp, "type")) { 1210 if (tp == NULL) 1211 tp = "unknown"; 1212 else if (strcasecmp(tp, "IDE") == 0) 1213 tp = "ESDI"; 1214 cpp = dktypenames; 1215 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 1216 if ((s = *cpp) && !strcasecmp(s, tp)) { 1217 lp->d_type = cpp - dktypenames; 1218 goto next; 1219 } 1220 v = GETNUM(lp->d_type, tp, 0, &errstr); 1221 if (errstr || v >= DKMAXTYPES) 1222 warnx("line %d: warning, unknown disk type: %s", 1223 lineno, tp); 1224 lp->d_type = v; 1225 continue; 1226 } 1227 if (!strcmp(cp, "flags")) { 1228 for (v = 0; (cp = tp) && *cp != '\0';) { 1229 tp = word(cp); 1230 if (!strcmp(cp, "badsect")) 1231 v |= D_BADSECT; 1232 else if (!strcmp(cp, "vendor")) 1233 v |= D_VENDOR; 1234 else { 1235 warnx("line %d: bad flag: %s", 1236 lineno, cp); 1237 errors++; 1238 } 1239 } 1240 lp->d_flags = v; 1241 continue; 1242 } 1243 if (!strcmp(cp, "drivedata")) { 1244 int i; 1245 1246 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 1247 v = GETNUM(lp->d_drivedata[i], cp, 0, &errstr); 1248 if (errstr) 1249 warnx("line %d: bad drivedata %s", 1250 lineno, cp); 1251 lp->d_drivedata[i++] = v; 1252 tp = word(cp); 1253 } 1254 continue; 1255 } 1256 if (sscanf(cp, "%d partitions", &v) == 1) { 1257 if (v == 0 || v > MAXPARTITIONS) { 1258 warnx("line %d: bad # of partitions", lineno); 1259 lp->d_npartitions = MAXPARTITIONS; 1260 errors++; 1261 } else 1262 lp->d_npartitions = v; 1263 continue; 1264 } 1265 if (tp == NULL) 1266 tp = ""; 1267 if (!strcmp(cp, "disk")) { 1268 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 1269 continue; 1270 } 1271 if (!strcmp(cp, "label")) { 1272 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 1273 continue; 1274 } 1275 if (!strcmp(cp, "bytes/sector")) { 1276 v = GETNUM(lp->d_secsize, tp, 1, &errstr); 1277 if (errstr || (v % 512) != 0) { 1278 warnx("line %d: bad %s: %s", lineno, cp, tp); 1279 errors++; 1280 } else 1281 lp->d_secsize = v; 1282 continue; 1283 } 1284 if (!strcmp(cp, "sectors/track")) { 1285 v = GETNUM(lp->d_nsectors, tp, 1, &errstr); 1286 if (errstr) { 1287 warnx("line %d: bad %s: %s", lineno, cp, tp); 1288 errors++; 1289 } else 1290 lp->d_nsectors = v; 1291 continue; 1292 } 1293 if (!strcmp(cp, "sectors/cylinder")) { 1294 v = GETNUM(lp->d_secpercyl, tp, 1, &errstr); 1295 if (errstr) { 1296 warnx("line %d: bad %s: %s", lineno, cp, tp); 1297 errors++; 1298 } else 1299 lp->d_secpercyl = v; 1300 continue; 1301 } 1302 if (!strcmp(cp, "tracks/cylinder")) { 1303 v = GETNUM(lp->d_ntracks, tp, 1, &errstr); 1304 if (errstr) { 1305 warnx("line %d: bad %s: %s", lineno, cp, tp); 1306 errors++; 1307 } else 1308 lp->d_ntracks = v; 1309 continue; 1310 } 1311 if (!strcmp(cp, "cylinders")) { 1312 v = GETNUM(lp->d_ncylinders, tp, 1, &errstr); 1313 if (errstr) { 1314 warnx("line %d: bad %s: %s", lineno, cp, tp); 1315 errors++; 1316 } else 1317 lp->d_ncylinders = v; 1318 continue; 1319 } 1320 if (!strcmp(cp, "total sectors")) { 1321 lv = GETNUM(lv, tp, 1, &errstr); 1322 if (errstr) { 1323 warnx("line %d: bad %s: %s", lineno, cp, tp); 1324 errors++; 1325 } else { 1326 DL_SETDSIZE(lp, lv); 1327 } 1328 continue; 1329 } 1330 if (!strcmp(cp, "rpm")) { 1331 v = GETNUM(lp->d_rpm, tp, 1, &errstr); 1332 if (errstr) { 1333 warnx("line %d: bad %s: %s", lineno, cp, tp); 1334 errors++; 1335 } else 1336 lp->d_rpm = v; 1337 continue; 1338 } 1339 if (!strcmp(cp, "interleave")) { 1340 v = GETNUM(lp->d_interleave, tp, 1, &errstr); 1341 if (errstr) { 1342 warnx("line %d: bad %s: %s", lineno, cp, tp); 1343 errors++; 1344 } else 1345 lp->d_interleave = v; 1346 continue; 1347 } 1348 if (!strcmp(cp, "trackskew")) { 1349 v = GETNUM(lp->d_trackskew, tp, 0, &errstr); 1350 if (errstr) { 1351 warnx("line %d: bad %s: %s", lineno, cp, tp); 1352 errors++; 1353 } else 1354 lp->d_trackskew = v; 1355 continue; 1356 } 1357 if (!strcmp(cp, "cylinderskew")) { 1358 v = GETNUM(lp->d_cylskew, tp, 0, &errstr); 1359 if (errstr) { 1360 warnx("line %d: bad %s: %s", lineno, cp, tp); 1361 errors++; 1362 } else 1363 lp->d_cylskew = v; 1364 continue; 1365 } 1366 if (!strcmp(cp, "headswitch")) { 1367 v = GETNUM(lp->d_headswitch, tp, 0, &errstr); 1368 if (errstr) { 1369 warnx("line %d: bad %s: %s", lineno, cp, tp); 1370 errors++; 1371 } else 1372 lp->d_headswitch = v; 1373 continue; 1374 } 1375 if (!strcmp(cp, "track-to-track seek")) { 1376 v = GETNUM(lp->d_trkseek, tp, 0, &errstr); 1377 if (errstr) { 1378 warnx("line %d: bad %s: %s", lineno, cp, tp); 1379 errors++; 1380 } else 1381 lp->d_trkseek = v; 1382 continue; 1383 } 1384 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 1385 unsigned int part = *cp - 'a'; 1386 1387 if (part >= lp->d_npartitions) { 1388 if (part >= MAXPARTITIONS) { 1389 warnx("line %d: bad partition name: %s", 1390 lineno, cp); 1391 errors++; 1392 continue; 1393 } else { 1394 lp->d_npartitions = part + 1; 1395 } 1396 } 1397 pp = &lp->d_partitions[part]; 1398 #define NXTNUM(n, field, errstr) { \ 1399 if (tp == NULL) { \ 1400 warnx("line %d: too few fields", lineno); \ 1401 errors++; \ 1402 break; \ 1403 } else \ 1404 cp = tp, tp = word(cp), (n) = GETNUM(field, cp, 0, errstr); \ 1405 } 1406 NXTNUM(lv, lv, &errstr); 1407 if (errstr) { 1408 warnx("line %d: bad partition size: %s", 1409 lineno, cp); 1410 errors++; 1411 } else { 1412 DL_SETPSIZE(pp, lv); 1413 } 1414 NXTNUM(lv, lv, &errstr); 1415 if (errstr) { 1416 warnx("line %d: bad partition offset: %s", 1417 lineno, cp); 1418 errors++; 1419 } else { 1420 DL_SETPOFFSET(pp, lv); 1421 } 1422 if (tp == NULL) { 1423 pp->p_fstype = FS_UNUSED; 1424 goto gottype; 1425 } 1426 cp = tp, tp = word(cp); 1427 cpp = fstypenames; 1428 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 1429 if ((s = *cpp) && !strcasecmp(s, cp)) { 1430 pp->p_fstype = cpp - fstypenames; 1431 goto gottype; 1432 } 1433 if (isdigit(*cp)) 1434 v = GETNUM(pp->p_fstype, cp, 0, &errstr); 1435 else 1436 v = FSMAXTYPES; 1437 if (errstr || v >= FSMAXTYPES) { 1438 warnx("line %d: warning, unknown filesystem type: %s", 1439 lineno, cp); 1440 v = FS_UNUSED; 1441 } 1442 pp->p_fstype = v; 1443 gottype: 1444 switch (pp->p_fstype) { 1445 1446 case FS_UNUSED: /* XXX */ 1447 if (tp == NULL) /* ok to skip fsize/bsize */ 1448 break; 1449 NXTNUM(fsize, fsize, &errstr); 1450 if (fsize == 0) 1451 break; 1452 NXTNUM(v, v, &errstr); 1453 pp->p_fragblock = 1454 DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); 1455 break; 1456 1457 case FS_BSDFFS: 1458 NXTNUM(fsize, fsize, &errstr); 1459 if (fsize == 0) 1460 break; 1461 NXTNUM(v, v, &errstr); 1462 pp->p_fragblock = 1463 DISKLABELV1_FFS_FRAGBLOCK(fsize, v / fsize); 1464 NXTNUM(pp->p_cpg, pp->p_cpg, &errstr); 1465 break; 1466 1467 default: 1468 break; 1469 } 1470 continue; 1471 } 1472 warnx("line %d: unknown field: %s", lineno, cp); 1473 errors++; 1474 next: 1475 ; 1476 } 1477 errors += checklabel(lp); 1478 return (errors == 0); 1479 } 1480 1481 /* 1482 * Check disklabel for errors and fill in 1483 * derived fields according to supplied values. 1484 */ 1485 int 1486 checklabel(struct disklabel *lp) 1487 { 1488 struct partition *pp; 1489 int i, errors = 0; 1490 char part; 1491 1492 if (lp->d_secsize == 0) { 1493 warnx("sector size %d", lp->d_secsize); 1494 return (1); 1495 } 1496 if (lp->d_nsectors == 0) { 1497 warnx("sectors/track %d", lp->d_nsectors); 1498 return (1); 1499 } 1500 if (lp->d_ntracks == 0) { 1501 warnx("tracks/cylinder %d", lp->d_ntracks); 1502 return (1); 1503 } 1504 if (lp->d_ncylinders == 0) { 1505 warnx("cylinders/unit %d", lp->d_ncylinders); 1506 errors++; 1507 } 1508 if (lp->d_rpm == 0) 1509 warnx("warning, revolutions/minute %d", lp->d_rpm); 1510 if (lp->d_secpercyl == 0) 1511 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1512 if (DL_GETDSIZE(lp) == 0) 1513 DL_SETDSIZE(lp, (u_int64_t)lp->d_secpercyl * lp->d_ncylinders); 1514 #ifdef i386__notyet 1515 if (dosdp && dosdp->dp_size && 1516 (dosdp->dp_typ == DOSPTYP_OPENBSD)) { 1517 && DL_GETDSIZE(lp) > dosdp->dp_start + dosdp->dp_size) { 1518 warnx("exceeds DOS partition size"); 1519 errors++; 1520 DL_SETDSIZE(lp, dosdp->dp_start + dosdp->dp_size); 1521 } 1522 #endif 1523 if (lp->d_bbsize == 0) { 1524 warnx("boot block size %d", lp->d_bbsize); 1525 errors++; 1526 } else if (lp->d_bbsize % lp->d_secsize) 1527 warnx("warning, boot block size %% sector-size != 0"); 1528 if (lp->d_sbsize == 0) { 1529 warnx("super block size %d", lp->d_sbsize); 1530 errors++; 1531 } else if (lp->d_sbsize % lp->d_secsize) 1532 warnx("warning, super block size %% sector-size != 0"); 1533 if (lp->d_npartitions > MAXPARTITIONS) 1534 warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", 1535 lp->d_npartitions, MAXPARTITIONS); 1536 for (i = 0; i < lp->d_npartitions; i++) { 1537 part = 'a' + i; 1538 pp = &lp->d_partitions[i]; 1539 if (DL_GETPSIZE(pp) == 0 && DL_GETPOFFSET(pp) != 0) 1540 warnx("warning, partition %c: size 0, but offset %lld", 1541 part, DL_GETPOFFSET(pp)); 1542 #ifdef SUN_CYLCHECK 1543 if (lp->d_flags & D_VENDOR) { 1544 if (i != RAW_PART && DL_GETPSIZE(pp) % lp->d_secpercyl) 1545 warnx("warning, partition %c: size %% " 1546 "cylinder-size != 0", part); 1547 if (i != RAW_PART && DL_GETPOFFSET(pp) % lp->d_secpercyl) 1548 warnx("warning, partition %c: offset %% " 1549 "cylinder-size != 0", part); 1550 } 1551 #endif 1552 #ifdef SUN_AAT0 1553 if ((lp->d_flags & D_VENDOR) && 1554 i == 0 && DL_GETPSIZE(pp) != 0 && DL_GETPOFFSET(pp) != 0) { 1555 warnx("this architecture requires partition 'a' to " 1556 "start at sector 0"); 1557 errors++; 1558 } 1559 #endif 1560 if (DL_GETPOFFSET(pp) > DL_GETDSIZE(lp)) { 1561 warnx("partition %c: offset past end of unit", part); 1562 errors++; 1563 } 1564 if (DL_GETPOFFSET(pp) + DL_GETPSIZE(pp) > DL_GETDSIZE(lp)) { 1565 warnx("partition %c: partition extends past end of unit", 1566 part); 1567 errors++; 1568 } 1569 #if 0 1570 if (pp->p_frag == 0 && pp->p_fsize != 0) { 1571 warnx("partition %c: block size < fragment size", part); 1572 errors++; 1573 } 1574 #endif 1575 } 1576 for (; i < MAXPARTITIONS; i++) { 1577 part = 'a' + i; 1578 pp = &lp->d_partitions[i]; 1579 if (DL_GETPSIZE(pp) || DL_GETPOFFSET(pp)) 1580 warnx("warning, unused partition %c: size %lld offset %lld", 1581 'a' + i, DL_GETPSIZE(pp), DL_GETPOFFSET(pp)); 1582 } 1583 return (errors); 1584 } 1585 1586 #if NUMBOOT > 0 1587 /* 1588 * If we are installing a boot program that doesn't fit in d_bbsize 1589 * we need to mark those partitions that the boot overflows into. 1590 * This allows newfs to prevent creation of a filesystem where it might 1591 * clobber bootstrap code. 1592 */ 1593 void 1594 setbootflag(struct disklabel *lp) 1595 { 1596 struct partition *pp; 1597 int i, errors = 0; 1598 daddr64_t bend; 1599 char part; 1600 1601 if (bootbuf == NULL) 1602 return; 1603 1604 bend = bootsize / lp->d_secsize; 1605 for (i = 0; i < lp->d_npartitions; i++) { 1606 if (i == RAW_PART) 1607 /* It will *ALWAYS* overlap 'c'. */ 1608 continue; 1609 pp = &lp->d_partitions[i]; 1610 if (DL_GETPSIZE(pp) == 0) 1611 /* Partition is unused. */ 1612 continue; 1613 if (bend <= DL_GETPOFFSET(pp)) { 1614 /* Boot blocks end before this partition starts. */ 1615 if (pp->p_fstype == FS_BOOT) 1616 pp->p_fstype = FS_UNUSED; 1617 continue; 1618 } 1619 1620 part = 'a' + i; 1621 switch (pp->p_fstype) { 1622 case FS_BOOT: /* Already marked. */ 1623 break; 1624 case FS_UNUSED: /* Mark. */ 1625 pp->p_fstype = FS_BOOT; 1626 warnx("warning, boot overlaps partition %c, %s", 1627 part, "marked as FS_BOOT"); 1628 break; 1629 default: 1630 warnx("boot overlaps used partition %c", part); 1631 errors++; 1632 break; 1633 } 1634 } 1635 if (errors) 1636 errx(4, "cannot install boot program"); 1637 } 1638 #endif 1639 1640 int 1641 cmplabel(struct disklabel *lp1, struct disklabel *lp2) 1642 { 1643 struct disklabel lab1 = *lp1; 1644 struct disklabel lab2 = *lp2; 1645 1646 /* We don't compare these fields */ 1647 lab1.d_magic = lab2.d_magic; 1648 lab1.d_magic2 = lab2.d_magic2; 1649 lab1.d_checksum = lab2.d_checksum; 1650 lab1.d_bbsize = lab2.d_bbsize; 1651 lab1.d_sbsize = lab2.d_sbsize; 1652 1653 return (memcmp(&lab1, &lab2, sizeof(struct disklabel))); 1654 } 1655 1656 void 1657 usage(void) 1658 { 1659 char *boot = ""; 1660 char *blank = " "; 1661 char *Bflag = ""; 1662 1663 #if NUMBOOT == 1 1664 Bflag = "B"; 1665 boot = " [-b boot1]"; 1666 #endif 1667 1668 fprintf(stderr, 1669 "usage: disklabel [-c | -d | -t] [-Av] [-p unit] disk\t\t(read)\n"); 1670 fprintf(stderr, 1671 " disklabel -w [-c | -d] [-Anv] disk disktype [packid]\t(write)\n"); 1672 fprintf(stderr, 1673 " disklabel -e [-c | -d] [-Anv] disk\t\t\t(edit)\n"); 1674 fprintf(stderr, 1675 " disklabel -E [-c | -d] [-Anv] [-f tempfile] disk\t\t(simple editor)\n"); 1676 fprintf(stderr, 1677 " disklabel -R [-nv] disk protofile\t\t\t(restore)\n"); 1678 fprintf(stderr, 1679 " disklabel -N | -W [-nv] disk\t\t\t\t(protect)\n\n"); 1680 #if NUMBOOT > 0 1681 fprintf(stderr, 1682 "%sdisklabel -B [-nv]%s disk [disktype] (boot)\n", 1683 blank, boot); 1684 #endif 1685 fprintf(stderr, 1686 "%sdisklabel -%sw [-nv]%s disk disktype [packid] (write)\n", 1687 blank, Bflag, boot); 1688 fprintf(stderr, 1689 "%sdisklabel -%sR [-nv]%s disk protofile [disktype] (restore)\n\n", 1690 blank, Bflag, boot); 1691 fprintf(stderr, 1692 "`disk' may be of the form: sd0 or /dev/rsd0%c.\n", 'a'+RAW_PART); 1693 fprintf(stderr, 1694 "`disktype' is an entry from %s, see disktab(5) for more info.\n", 1695 DISKTAB); 1696 fprintf(stderr, 1697 "`packid' is an identification string for the device.\n"); 1698 fprintf(stderr, 1699 "`protofile' is the output from the read cmd form; -R is powerful.\n"); 1700 #ifdef SEEALSO 1701 fprintf(stderr, 1702 "For procedures specific to this architecture see: %s\n", SEEALSO); 1703 #endif 1704 exit(1); 1705 } 1706