1 /* $OpenBSD: disklabel.c,v 1.71 2001/09/03 16:14:27 millert 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 const 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 const char rcsid[] = "$OpenBSD: disklabel.c,v 1.71 2001/09/03 16:14:27 millert 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#%u:", lp->d_secsize); 913 (void)fprintf(f, "ns#%u:", lp->d_nsectors); 914 (void)fprintf(f, "nt#%u:", lp->d_ntracks); 915 (void)fprintf(f, "nc#%u:", lp->d_ncylinders); 916 (void)fprintf(f, "sc#%u:", lp->d_secpercyl); 917 (void)fprintf(f, "su#%u:", lp->d_secperunit); 918 919 if (lp->d_rpm != 3600) { 920 (void)fprintf(f, "%srm#%d:", did, lp->d_rpm); 921 did = ""; 922 } 923 if (lp->d_interleave != 1) { 924 (void)fprintf(f, "%sil#%d:", did, lp->d_interleave); 925 did = ""; 926 } 927 if (lp->d_trackskew != 0) { 928 (void)fprintf(f, "%ssk#%d:", did, lp->d_trackskew); 929 did = ""; 930 } 931 if (lp->d_cylskew != 0) { 932 (void)fprintf(f, "%scs#%d:", did, lp->d_cylskew); 933 did = ""; 934 } 935 if (lp->d_headswitch != 0) { 936 (void)fprintf(f, "%shs#%u:", did, lp->d_headswitch); 937 did = ""; 938 } 939 if (lp->d_trkseek != 0) { 940 (void)fprintf(f, "%sts#%u:", did, lp->d_trkseek); 941 did = ""; 942 } 943 for (i = 0; i < NDDATA; i++) 944 if (lp->d_drivedata[i]) 945 (void)fprintf(f, "d%d#%u", i, lp->d_drivedata[i]); 946 pp = lp->d_partitions; 947 for (i = 0; i < lp->d_npartitions; i++, pp++) { 948 if (pp->p_size) { 949 char c = 'a' + i; 950 951 (void)fprintf(f, "\\\n\t:"); 952 (void)fprintf(f, "p%c#%u:", c, pp->p_size); 953 (void)fprintf(f, "o%c#%u:", c, pp->p_offset); 954 if (pp->p_fstype != FS_UNUSED) { 955 if ((unsigned) pp->p_fstype < FSMAXTYPES) 956 (void)fprintf(f, "t%c=%s:", c, 957 fstypenames[pp->p_fstype]); 958 else 959 (void)fprintf(f, "t%c=unknown%d:", 960 c, pp->p_fstype); 961 } 962 switch (pp->p_fstype) { 963 964 case FS_UNUSED: 965 break; 966 967 case FS_BSDFFS: 968 (void)fprintf(f, "b%c#%u:", c, 969 pp->p_fsize * pp->p_frag); 970 (void)fprintf(f, "f%c#%u:", c, pp->p_fsize); 971 break; 972 973 default: 974 break; 975 } 976 } 977 } 978 (void)fputc('\n', f); 979 (void)fflush(f); 980 } 981 982 int 983 width_partition(lp, unit) 984 struct disklabel *lp; 985 { 986 unit = toupper(unit); 987 switch (unit) { 988 case 'K': 989 return 10; 990 } 991 return 8; 992 } 993 994 /* 995 * Display a particular partion. 996 */ 997 void 998 display_partition(f, lp, mp, i, unit, width) 999 FILE *f; 1000 struct disklabel *lp; 1001 char **mp; 1002 int i; 1003 char unit; 1004 int width; 1005 { 1006 struct partition *pp = &lp->d_partitions[i]; 1007 double p_size, p_offset; 1008 1009 if (width == 0) 1010 width = 8; 1011 unit = toupper(unit); 1012 switch (unit) { 1013 case 'B': 1014 p_size = (double)pp->p_size * lp->d_secsize; 1015 p_offset = (double)pp->p_offset * lp->d_secsize; 1016 break; 1017 1018 case 'C': 1019 p_size = (double)pp->p_size / lp->d_secpercyl; 1020 p_offset = (double)pp->p_offset / lp->d_secpercyl; 1021 break; 1022 1023 case 'K': 1024 p_size = (double)pp->p_size / (1024 / lp->d_secsize); 1025 p_offset = (double)pp->p_offset / (1024 / lp->d_secsize); 1026 break; 1027 1028 case 'M': 1029 p_size = (double)pp->p_size / ((1024*1024) / lp->d_secsize); 1030 p_offset = (double)pp->p_offset / ((1024*1024) / lp->d_secsize); 1031 break; 1032 1033 case 'G': 1034 p_size = (double)pp->p_size / ((1024*1024*1024) / lp->d_secsize); 1035 p_offset = (double)pp->p_offset / ((1024*1024*1024) / lp->d_secsize); 1036 break; 1037 1038 default: 1039 p_size = -1; /* no conversion */ 1040 p_offset = 0; 1041 break; 1042 } 1043 1044 if (pp->p_size) { 1045 if (p_size < 0) 1046 fprintf(f, " %c: %*u %*u ", 'a' + i, 1047 width, pp->p_size, width, pp->p_offset); 1048 else 1049 fprintf(f, " %c: %*.1f%c %*.1f%c ", 'a' + i, 1050 width-1, p_size, unit, width-1, p_offset, unit); 1051 if ((unsigned) pp->p_fstype < FSMAXTYPES) 1052 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 1053 else 1054 fprintf(f, "%8d", pp->p_fstype); 1055 switch (pp->p_fstype) { 1056 1057 case FS_UNUSED: /* XXX */ 1058 fprintf(f, " %5d %5d %5.5s ", 1059 pp->p_fsize, pp->p_fsize * pp->p_frag, ""); 1060 break; 1061 1062 case FS_BSDFFS: 1063 fprintf(f, " %5d %5d %5d ", 1064 pp->p_fsize, pp->p_fsize * pp->p_frag, 1065 pp->p_cpg); 1066 break; 1067 1068 default: 1069 fprintf(f, "%22.22s", ""); 1070 break; 1071 } 1072 if (mp != NULL) { 1073 if (mp[i] != NULL) 1074 fprintf(f, " # %s", mp[i]); 1075 } else if (lp->d_secpercyl) { 1076 fprintf(f, "\t# (Cyl. %4d", 1077 pp->p_offset / lp->d_secpercyl); 1078 if (pp->p_offset % lp->d_secpercyl) 1079 putc('*', f); 1080 else 1081 putc(' ', f); 1082 fprintf(f, "- %u", 1083 (pp->p_offset + 1084 pp->p_size + lp->d_secpercyl - 1) / 1085 lp->d_secpercyl - 1); 1086 if ((pp->p_offset + pp->p_size) % lp->d_secpercyl) 1087 putc('*', f); 1088 putc(')', f); 1089 } 1090 putc('\n', f); 1091 } 1092 } 1093 1094 void 1095 display(f, lp) 1096 FILE *f; 1097 struct disklabel *lp; 1098 { 1099 int i, j; 1100 int width; 1101 1102 fprintf(f, "# %s:\n", specname); 1103 if ((unsigned) lp->d_type < DKMAXTYPES) 1104 fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 1105 else 1106 fprintf(f, "type: %d\n", lp->d_type); 1107 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename); 1108 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname); 1109 fprintf(f, "flags:"); 1110 if (lp->d_flags & D_REMOVABLE) 1111 fprintf(f, " removable"); 1112 if (lp->d_flags & D_ECC) 1113 fprintf(f, " ecc"); 1114 if (lp->d_flags & D_BADSECT) 1115 fprintf(f, " badsect"); 1116 putc('\n', f); 1117 fprintf(f, "bytes/sector: %ld\n", (long)lp->d_secsize); 1118 fprintf(f, "sectors/track: %ld\n", (long)lp->d_nsectors); 1119 fprintf(f, "tracks/cylinder: %ld\n", (long)lp->d_ntracks); 1120 fprintf(f, "sectors/cylinder: %ld\n", (long)lp->d_secpercyl); 1121 fprintf(f, "cylinders: %ld\n", (long)lp->d_ncylinders); 1122 fprintf(f, "total sectors: %ld\n", (long)lp->d_secperunit); 1123 fprintf(f, "rpm: %ld\n", (long)lp->d_rpm); 1124 fprintf(f, "interleave: %ld\n", (long)lp->d_interleave); 1125 fprintf(f, "trackskew: %ld\n", (long)lp->d_trackskew); 1126 fprintf(f, "cylinderskew: %ld\n", (long)lp->d_cylskew); 1127 fprintf(f, "headswitch: %ld\t\t# microseconds\n", 1128 (long)lp->d_headswitch); 1129 fprintf(f, "track-to-track seek: %ld\t# microseconds\n", 1130 (long)lp->d_trkseek); 1131 fprintf(f, "drivedata: "); 1132 for (i = NDDATA - 1; i >= 0; i--) 1133 if (lp->d_drivedata[i]) 1134 break; 1135 if (i < 0) 1136 i = 0; 1137 for (j = 0; j <= i; j++) 1138 fprintf(f, "%d ", lp->d_drivedata[j]); 1139 fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); 1140 width = width_partition(lp, 0); 1141 fprintf(f, 1142 "# %*.*s %*.*s fstype [fsize bsize cpg]\n", 1143 width, width, "size", width, width, "offset"); 1144 for (i = 0; i < lp->d_npartitions; i++) 1145 display_partition(f, lp, NULL, i, 0, width); 1146 fflush(f); 1147 } 1148 1149 int 1150 edit(lp, f) 1151 struct disklabel *lp; 1152 int f; 1153 { 1154 int first, ch, fd; 1155 struct disklabel label; 1156 FILE *fp; 1157 1158 if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) { 1159 if (fd != -1) 1160 close(fd); 1161 warn("%s", tmpfil); 1162 return (1); 1163 } 1164 display(fp, lp); 1165 fprintf(fp, "\n# Notes:\n"); 1166 fprintf(fp, 1167 "# Up to 16 partitions are valid, named from 'a' to 'p'. Partition 'a' is\n" 1168 "# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n" 1169 "# disk. Any other partition is free for any use. 'size' and 'offset' are\n" 1170 "# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n" 1171 "# other values. fsize/bsize/cpg should typically be '1024 8192 16' for a\n" 1172 "# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, amiga, sun3...)\n"); 1173 fclose(fp); 1174 for (;;) { 1175 if (!editit()) 1176 break; 1177 fp = fopen(tmpfil, "r"); 1178 if (fp == NULL) { 1179 warn("%s", tmpfil); 1180 break; 1181 } 1182 memset(&label, 0, sizeof(label)); 1183 if (getasciilabel(fp, &label)) { 1184 if (cmplabel(lp, &label) == 0) { 1185 puts("No changes."); 1186 fclose(fp); 1187 (void) unlink(tmpfil); 1188 return (0); 1189 } 1190 *lp = label; 1191 if (writelabel(f, bootarea, lp) == 0) { 1192 fclose(fp); 1193 (void) unlink(tmpfil); 1194 return (0); 1195 } 1196 } 1197 fclose(fp); 1198 printf("re-edit the label? [y]: "); 1199 fflush(stdout); 1200 first = ch = getchar(); 1201 while (ch != '\n' && ch != EOF) 1202 ch = getchar(); 1203 if (first == 'n' || first == 'N') 1204 break; 1205 } 1206 (void)unlink(tmpfil); 1207 return (1); 1208 } 1209 1210 int 1211 editit() 1212 { 1213 pid_t pid, xpid; 1214 int stat; 1215 extern char *getenv(); 1216 char *argp[] = {"sh", "-c", NULL, NULL}; 1217 char *ed, *p; 1218 1219 if ((ed = getenv("EDITOR")) == NULL) 1220 ed = _PATH_VI; 1221 p = (char *)malloc(strlen(ed) + 1 + strlen(tmpfil) + 1); 1222 if (!p) { 1223 warn("failed to start editor"); 1224 return (0); 1225 } 1226 sprintf(p, "%s %s", ed, tmpfil); 1227 argp[2] = p; 1228 1229 /* Turn off signals. */ 1230 (void)signal(SIGHUP, SIG_IGN); 1231 (void)signal(SIGINT, SIG_IGN); 1232 (void)signal(SIGQUIT, SIG_IGN); 1233 while ((pid = fork()) < 0) { 1234 if (errno != EAGAIN) { 1235 warn("fork"); 1236 free(p); 1237 stat = 1; 1238 goto bail; 1239 } 1240 sleep(1); 1241 } 1242 if (pid == 0) { 1243 execv(_PATH_BSHELL, argp); 1244 _exit(127); 1245 } 1246 free(p); 1247 for (;;) { 1248 xpid = waitpid(pid, (int *)&stat, WUNTRACED); 1249 if (WIFSTOPPED(stat)) 1250 raise(WSTOPSIG(stat)); 1251 else if (WIFEXITED(stat)) 1252 break; 1253 } 1254 bail: 1255 (void)signal(SIGHUP, SIG_DFL); 1256 (void)signal(SIGINT, SIG_DFL); 1257 (void)signal(SIGQUIT, SIG_DFL); 1258 return (!stat); 1259 } 1260 1261 char * 1262 skip(cp) 1263 char *cp; 1264 { 1265 1266 cp += strspn(cp, " \t"); 1267 if (*cp == '\0') 1268 return (NULL); 1269 return (cp); 1270 } 1271 1272 char * 1273 word(cp) 1274 char *cp; 1275 { 1276 1277 cp += strcspn(cp, " \t"); 1278 if (*cp == '\0') 1279 return (NULL); 1280 *cp++ = '\0'; 1281 cp += strspn(cp, " \t"); 1282 if (*cp == '\0') 1283 return (NULL); 1284 return (cp); 1285 } 1286 1287 /* 1288 * Read an ascii label in from fd f, 1289 * in the same format as that put out by display(), 1290 * and fill in lp. 1291 */ 1292 int 1293 getasciilabel(f, lp) 1294 FILE *f; 1295 struct disklabel *lp; 1296 { 1297 char **cpp, *cp; 1298 struct partition *pp; 1299 char *tp, *s, line[BUFSIZ]; 1300 int v, lineno = 0, errors = 0; 1301 1302 lp->d_bbsize = BBSIZE; /* XXX */ 1303 lp->d_sbsize = SBSIZE; /* XXX */ 1304 while (fgets(line, sizeof(line) - 1, f)) { 1305 lineno++; 1306 if ((cp = strpbrk(line, "#\r\n"))) 1307 *cp = '\0'; 1308 cp = skip(line); 1309 if (cp == NULL) 1310 continue; 1311 tp = strchr(cp, ':'); 1312 if (tp == NULL) { 1313 warnx("line %d: syntax error", lineno); 1314 errors++; 1315 continue; 1316 } 1317 *tp++ = '\0', tp = skip(tp); 1318 if (!strcmp(cp, "type")) { 1319 if (tp == NULL) 1320 tp = "unknown"; 1321 else if (strcasecmp(tp, "IDE") == 0) 1322 tp = "ESDI"; 1323 cpp = dktypenames; 1324 for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 1325 if ((s = *cpp) && !strcasecmp(s, tp)) { 1326 lp->d_type = cpp - dktypenames; 1327 goto next; 1328 } 1329 v = atoi(tp); 1330 if ((unsigned)v >= DKMAXTYPES) 1331 warnx("line %d: warning, unknown disk type: %s", 1332 lineno, tp); 1333 lp->d_type = v; 1334 continue; 1335 } 1336 if (!strcmp(cp, "flags")) { 1337 for (v = 0; (cp = tp) && *cp != '\0';) { 1338 tp = word(cp); 1339 if (!strcmp(cp, "removable")) 1340 v |= D_REMOVABLE; 1341 else if (!strcmp(cp, "ecc")) 1342 v |= D_ECC; 1343 else if (!strcmp(cp, "badsect")) 1344 v |= D_BADSECT; 1345 else { 1346 warnx("line %d: bad flag: %s", 1347 lineno, cp); 1348 errors++; 1349 } 1350 } 1351 lp->d_flags = v; 1352 continue; 1353 } 1354 if (!strcmp(cp, "drivedata")) { 1355 int i; 1356 1357 for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 1358 lp->d_drivedata[i++] = atoi(cp); 1359 tp = word(cp); 1360 } 1361 continue; 1362 } 1363 if (sscanf(cp, "%d partitions", &v) == 1) { 1364 if (v == 0 || (unsigned)v > MAXPARTITIONS) { 1365 warnx("line %d: bad # of partitions", lineno); 1366 lp->d_npartitions = MAXPARTITIONS; 1367 errors++; 1368 } else 1369 lp->d_npartitions = v; 1370 continue; 1371 } 1372 if (tp == NULL) 1373 tp = ""; 1374 if (!strcmp(cp, "disk")) { 1375 strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 1376 continue; 1377 } 1378 if (!strcmp(cp, "label")) { 1379 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 1380 continue; 1381 } 1382 if (!strcmp(cp, "bytes/sector")) { 1383 v = atoi(tp); 1384 if (v <= 0 || (v % 512) != 0) { 1385 warnx("line %d: bad %s: %s", lineno, cp, tp); 1386 errors++; 1387 } else 1388 lp->d_secsize = v; 1389 continue; 1390 } 1391 if (!strcmp(cp, "sectors/track")) { 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_nsectors = v; 1398 continue; 1399 } 1400 if (!strcmp(cp, "sectors/cylinder")) { 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_secpercyl = v; 1407 continue; 1408 } 1409 if (!strcmp(cp, "tracks/cylinder")) { 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_ntracks = v; 1416 continue; 1417 } 1418 if (!strcmp(cp, "cylinders")) { 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_ncylinders = v; 1425 continue; 1426 } 1427 if (!strcmp(cp, "total sectors")) { 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_secperunit = v; 1434 continue; 1435 } 1436 if (!strcmp(cp, "rpm")) { 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_rpm = v; 1443 continue; 1444 } 1445 if (!strcmp(cp, "interleave")) { 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_interleave = v; 1452 continue; 1453 } 1454 if (!strcmp(cp, "trackskew")) { 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_trackskew = v; 1461 continue; 1462 } 1463 if (!strcmp(cp, "cylinderskew")) { 1464 v = atoi(tp); 1465 if (v < 0) { 1466 warnx("line %d: bad %s: %s", lineno, cp, tp); 1467 errors++; 1468 } else 1469 lp->d_cylskew = v; 1470 continue; 1471 } 1472 if (!strcmp(cp, "headswitch")) { 1473 v = atoi(tp); 1474 if (v < 0) { 1475 warnx("line %d: bad %s: %s", lineno, cp, tp); 1476 errors++; 1477 } else 1478 lp->d_headswitch = v; 1479 continue; 1480 } 1481 if (!strcmp(cp, "track-to-track seek")) { 1482 v = atoi(tp); 1483 if (v < 0) { 1484 warnx("line %d: bad %s: %s", lineno, cp, tp); 1485 errors++; 1486 } else 1487 lp->d_trkseek = v; 1488 continue; 1489 } 1490 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 1491 unsigned part = *cp - 'a'; 1492 1493 if (part >= lp->d_npartitions) { 1494 if (part >= MAXPARTITIONS) { 1495 warnx("line %d: bad partition name: %s", 1496 lineno, cp); 1497 errors++; 1498 continue; 1499 } else { 1500 lp->d_npartitions = part + 1; 1501 } 1502 } 1503 pp = &lp->d_partitions[part]; 1504 #define NXTNUM(n) { \ 1505 if (tp == NULL) { \ 1506 warnx("line %d: too few fields", lineno); \ 1507 errors++; \ 1508 break; \ 1509 } else \ 1510 cp = tp, tp = word(cp), (n) = atoi(cp); \ 1511 } 1512 NXTNUM(v); 1513 if (v < 0) { 1514 warnx("line %d: bad partition size: %s", 1515 lineno, cp); 1516 errors++; 1517 } else 1518 pp->p_size = v; 1519 NXTNUM(v); 1520 if (v < 0) { 1521 warnx("line %d: bad partition offset: %s", 1522 lineno, cp); 1523 errors++; 1524 } else 1525 pp->p_offset = v; 1526 if (tp == NULL) { 1527 pp->p_fstype = FS_UNUSED; 1528 goto gottype; 1529 } 1530 cp = tp, tp = word(cp); 1531 cpp = fstypenames; 1532 for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 1533 if ((s = *cpp) && !strcasecmp(s, cp)) { 1534 pp->p_fstype = cpp - fstypenames; 1535 goto gottype; 1536 } 1537 if (isdigit(*cp)) 1538 v = atoi(cp); 1539 else 1540 v = FSMAXTYPES; 1541 if ((unsigned)v >= FSMAXTYPES) { 1542 warnx("line %d: warning, unknown filesystem type: %s", 1543 lineno, cp); 1544 v = FS_UNUSED; 1545 } 1546 pp->p_fstype = v; 1547 gottype: 1548 switch (pp->p_fstype) { 1549 1550 case FS_UNUSED: /* XXX */ 1551 if (tp == NULL) /* ok to skip fsize/bsize */ 1552 break; 1553 NXTNUM(pp->p_fsize); 1554 if (pp->p_fsize == 0) 1555 break; 1556 NXTNUM(v); 1557 pp->p_frag = v / pp->p_fsize; 1558 break; 1559 1560 case FS_BSDFFS: 1561 NXTNUM(pp->p_fsize); 1562 if (pp->p_fsize == 0) 1563 break; 1564 NXTNUM(v); 1565 pp->p_frag = v / pp->p_fsize; 1566 NXTNUM(pp->p_cpg); 1567 break; 1568 1569 default: 1570 break; 1571 } 1572 continue; 1573 } 1574 warnx("line %d: unknown field: %s", lineno, cp); 1575 errors++; 1576 next: 1577 ; 1578 } 1579 errors += checklabel(lp); 1580 return (errors == 0); 1581 } 1582 1583 /* 1584 * Check disklabel for errors and fill in 1585 * derived fields according to supplied values. 1586 */ 1587 int 1588 checklabel(lp) 1589 struct disklabel *lp; 1590 { 1591 struct partition *pp; 1592 int i, errors = 0; 1593 char part; 1594 1595 if (lp->d_secsize == 0) { 1596 warnx("sector size %d", lp->d_secsize); 1597 return (1); 1598 } 1599 if (lp->d_nsectors == 0) { 1600 warnx("sectors/track %d", lp->d_nsectors); 1601 return (1); 1602 } 1603 if (lp->d_ntracks == 0) { 1604 warnx("tracks/cylinder %d", lp->d_ntracks); 1605 return (1); 1606 } 1607 if (lp->d_ncylinders == 0) { 1608 warnx("cylinders/unit %d", lp->d_ncylinders); 1609 errors++; 1610 } 1611 if (lp->d_rpm == 0) 1612 warnx("warning, revolutions/minute %d", lp->d_rpm); 1613 if (lp->d_secpercyl == 0) 1614 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 1615 if (lp->d_secperunit == 0) 1616 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 1617 #ifdef i386__notyet 1618 if (dosdp && dosdp->dp_size && 1619 (dosdp->dp_typ == DOSPTYP_OPENBSD || 1620 dosdp->dp_typ == DOSPTYP_FREEBSD || 1621 dosdp->dp_typ == DOSPTYP_NETBSD)) { 1622 && lp->d_secperunit > dosdp->dp_start + dosdp->dp_size) { 1623 warnx("exceeds DOS partition size"); 1624 errors++; 1625 lp->d_secperunit = dosdp->dp_start + dosdp->dp_size; 1626 } 1627 /* XXX should also check geometry against BIOS's idea */ 1628 #endif 1629 if (lp->d_bbsize == 0) { 1630 warnx("boot block size %d", lp->d_bbsize); 1631 errors++; 1632 } else if (lp->d_bbsize % lp->d_secsize) 1633 warnx("warning, boot block size %% sector-size != 0"); 1634 if (lp->d_sbsize == 0) { 1635 warnx("super block size %d", lp->d_sbsize); 1636 errors++; 1637 } else if (lp->d_sbsize % lp->d_secsize) 1638 warnx("warning, super block size %% sector-size != 0"); 1639 if (lp->d_npartitions > MAXPARTITIONS) 1640 warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)", 1641 lp->d_npartitions, MAXPARTITIONS); 1642 for (i = 0; i < lp->d_npartitions; i++) { 1643 part = 'a' + i; 1644 pp = &lp->d_partitions[i]; 1645 if (pp->p_size == 0 && pp->p_offset != 0) 1646 warnx("warning, partition %c: size 0, but offset %d", 1647 part, pp->p_offset); 1648 #ifdef CYLCHECK 1649 if (pp->p_size % lp->d_secpercyl) 1650 warnx("warning, partition %c: size %% cylinder-size != 0", 1651 part); 1652 if (pp->p_offset % lp->d_secpercyl) 1653 warnx("warning, partition %c: offset %% cylinder-size != 0", 1654 part); 1655 #endif 1656 #ifdef AAT0 1657 if (i == 0 && pp->p_size != 0 && pp->p_offset != 0) { 1658 warnx("this architecture requires partition 'a' to " 1659 "start at sector 0"); 1660 errors++; 1661 } 1662 #endif 1663 if (pp->p_offset > lp->d_secperunit) { 1664 warnx("partition %c: offset past end of unit", part); 1665 errors++; 1666 } 1667 if (pp->p_offset + pp->p_size > lp->d_secperunit) { 1668 warnx("partition %c: partition extends past end of unit", 1669 part); 1670 errors++; 1671 } 1672 if (pp->p_frag == 0 && pp->p_fsize != 0) { 1673 warnx("partition %c: block size < fragment size", part); 1674 errors++; 1675 } 1676 } 1677 for (; i < MAXPARTITIONS; i++) { 1678 part = 'a' + i; 1679 pp = &lp->d_partitions[i]; 1680 if (pp->p_size || pp->p_offset) 1681 warnx("warning, unused partition %c: size %d offset %d", 1682 'a' + i, pp->p_size, pp->p_offset); 1683 } 1684 return (errors); 1685 } 1686 1687 #if NUMBOOT > 0 1688 /* 1689 * If we are installing a boot program that doesn't fit in d_bbsize 1690 * we need to mark those partitions that the boot overflows into. 1691 * This allows newfs to prevent creation of a filesystem where it might 1692 * clobber bootstrap code. 1693 */ 1694 void 1695 setbootflag(lp) 1696 struct disklabel *lp; 1697 { 1698 struct partition *pp; 1699 int i, errors = 0; 1700 u_long boffset; 1701 char part; 1702 1703 if (bootbuf == 0) 1704 return; 1705 boffset = bootsize / lp->d_secsize; 1706 for (i = 0; i < lp->d_npartitions; i++) { 1707 part = 'a' + i; 1708 pp = &lp->d_partitions[i]; 1709 if (pp->p_size == 0) 1710 continue; 1711 if (boffset <= pp->p_offset) { 1712 if (pp->p_fstype == FS_BOOT) 1713 pp->p_fstype = FS_UNUSED; 1714 } else if (pp->p_fstype != FS_BOOT) { 1715 if (pp->p_fstype != FS_UNUSED) { 1716 warnx("boot overlaps used partition %c", part); 1717 errors++; 1718 } else { 1719 pp->p_fstype = FS_BOOT; 1720 warnx("warning, boot overlaps partition %c, %s", 1721 part, "marked as FS_BOOT"); 1722 } 1723 } 1724 } 1725 if (errors) 1726 errx(4, "cannot install boot program"); 1727 } 1728 #endif 1729 1730 int 1731 cmplabel(lp1, lp2) 1732 struct disklabel *lp1; 1733 struct disklabel *lp2; 1734 { 1735 struct disklabel lab1 = *lp1; 1736 struct disklabel lab2 = *lp2; 1737 1738 /* We don't compare these fields */ 1739 lab1.d_magic = lab2.d_magic; 1740 lab1.d_magic2 = lab2.d_magic2; 1741 lab1.d_checksum = lab2.d_checksum; 1742 lab1.d_bbsize = lab2.d_bbsize; 1743 lab1.d_sbsize = lab2.d_sbsize; 1744 1745 return (memcmp(&lab1, &lab2, sizeof(struct disklabel))); 1746 } 1747 1748 void 1749 usage() 1750 { 1751 char *boot = ""; 1752 char blank[] = " "; 1753 1754 #if NUMBOOT == 1 1755 boot = " [-B [-b xxboot]]"; 1756 #elif NUMBOOT == 2 1757 boot = " [-B [-b xxboot [-s bootxx]]]"; 1758 #endif 1759 blank[strlen(boot)] = '\0'; 1760 1761 fprintf(stderr, "usage:\n"); 1762 fprintf(stderr, 1763 " disklabel [-nv] [-r|-cd] [-t] disk%s (read)\n", 1764 blank); 1765 fprintf(stderr, 1766 " disklabel [-nv] [-r|-cd] -e disk%s (edit)\n", 1767 blank); 1768 fprintf(stderr, 1769 " disklabel [-nv] [-r|-cd] [-f temp] -E disk%.*s (simple editor)\n", 1770 (int)strlen(blank) - 5, blank); 1771 fprintf(stderr, 1772 " disklabel [-nv] [-r]%s -R disk proto (restore)\n", 1773 boot); 1774 fprintf(stderr, 1775 " disklabel [-nv] [-r]%s -w disk dtab [id] (write)\n", 1776 boot); 1777 fprintf(stderr, 1778 " disklabel [-nv] [-N|-W] disk%s (protect)\n", blank); 1779 fprintf(stderr, 1780 "`disk' may be of the forms: sd0 or /dev/rsd0%c.\n", 'a'+RAW_PART); 1781 fprintf(stderr, 1782 "`dtab' is an entry from %s, see disktab(5) for more info.\n", 1783 DISKTAB); 1784 fprintf(stderr, 1785 "`proto' is the output from the read cmd form; -R is powerful.\n"); 1786 #ifdef SEEALSO 1787 fprintf(stderr, 1788 "For procedures specific to this architecture see: %s\n", SEEALSO); 1789 #endif 1790 exit(1); 1791 } 1792