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