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