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