1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /* 35 * Copyright (c) 1987, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed to Berkeley by 39 * Symmetric Computer Systems. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Berkeley and its contributors. 53 * 4. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 * 69 * @(#)disklabel.c 1.2 (Symmetric) 11/28/85 70 * @(#)disklabel.c 8.2 (Berkeley) 1/7/94 71 * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $ 72 */ 73 74 #include <sys/param.h> 75 #include <sys/file.h> 76 #include <sys/stat.h> 77 #include <sys/wait.h> 78 #define DKTYPENAMES 79 #include <sys/disklabel64.h> 80 #include <sys/diskslice.h> 81 #include <sys/diskmbr.h> 82 #include <sys/dtype.h> 83 #include <sys/sysctl.h> 84 #include <disktab.h> 85 #include <fstab.h> 86 87 #include <vfs/ufs/dinode.h> 88 #include <vfs/ufs/fs.h> 89 90 #include <unistd.h> 91 #include <string.h> 92 #include <stdio.h> 93 #include <stdlib.h> 94 #include <signal.h> 95 #include <stdarg.h> 96 #include <stddef.h> 97 #include <ctype.h> 98 #include <err.h> 99 #include <errno.h> 100 #include <uuid.h> 101 #include "pathnames.h" 102 103 extern uint32_t crc32(const void *buf, size_t size); 104 105 /* 106 * Disklabel64: read and write 64 bit disklabels. 107 * The label is usually placed on one of the first sectors of the disk. 108 * Many machines also place a bootstrap in the same area, 109 * in which case the label is embedded in the bootstrap. 110 * The bootstrap source must leave space at the proper offset 111 * for the label on such machines. 112 */ 113 114 #define LABELSIZE ((sizeof(struct disklabel64) + 4095) & ~4095) 115 #define BOOTSIZE 32768 116 117 /* FIX! These are too low, but are traditional */ 118 #define DEFAULT_NEWFS_BLOCK 8192U 119 #define DEFAULT_NEWFS_FRAG 1024U 120 #define DEFAULT_NEWFS_CPG 16U 121 122 #define BIG_NEWFS_BLOCK 16384U 123 #define BIG_NEWFS_FRAG 2048U 124 #define BIG_NEWFS_CPG 64U 125 126 void makelabel(const char *, const char *, struct disklabel64 *); 127 int writelabel(int, struct disklabel64 *); 128 void l_perror(const char *); 129 struct disklabel64 *readlabel(int); 130 struct disklabel64 *makebootarea(int); 131 void display(FILE *, const struct disklabel64 *); 132 int edit(struct disklabel64 *, int); 133 int editit(void); 134 char *skip(char *); 135 char *word(char *); 136 int getasciilabel(FILE *, struct disklabel64 *); 137 int getasciipartspec(char *, struct disklabel64 *, int, int, uint32_t); 138 int getasciipartuuid(char *, struct disklabel64 *, int, int, uint32_t); 139 int checklabel(struct disklabel64 *); 140 void Warning(const char *, ...) __printflike(1, 2); 141 void usage(void); 142 struct disklabel64 *getvirginlabel(void); 143 144 #define DEFEDITOR _PATH_VI 145 #define streq(a,b) (strcmp(a,b) == 0) 146 147 char *dkname; 148 char *specname; 149 char tmpfil[] = PATH_TMPFILE; 150 151 struct disklabel64 lab; 152 153 #define MAX_PART ('z') 154 #define MAX_NUM_PARTS (1 + MAX_PART - 'a') 155 char part_size_type[MAX_NUM_PARTS]; 156 char part_offset_type[MAX_NUM_PARTS]; 157 int part_set[MAX_NUM_PARTS]; 158 159 int installboot; /* non-zero if we should install a boot program */ 160 int boot1size; 161 int boot1lsize; 162 int boot2size; 163 char *boot1buf; 164 char *boot2buf; 165 char *boot1path; 166 char *boot2path; 167 168 enum { 169 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 170 } op = UNSPEC; 171 172 int rflag; 173 int Vflag; 174 int disable_write; /* set to disable writing to disk label */ 175 u_int32_t slice_start_lba; 176 177 #ifdef DEBUG 178 int debug; 179 #define OPTIONS "BNRWb:denrs:Vw" 180 #else 181 #define OPTIONS "BNRWb:enrs:Vw" 182 #endif 183 184 int 185 main(int argc, char *argv[]) 186 { 187 struct disklabel64 *lp; 188 FILE *t; 189 int ch, f = 0, flag, error = 0; 190 char *name = NULL; 191 192 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 193 switch (ch) { 194 case 'B': 195 ++installboot; 196 break; 197 case 'b': 198 boot1path = optarg; 199 break; 200 201 case 's': 202 boot2path = optarg; 203 break; 204 case 'N': 205 if (op != UNSPEC) 206 usage(); 207 op = NOWRITE; 208 break; 209 case 'n': 210 disable_write = 1; 211 break; 212 case 'R': 213 if (op != UNSPEC) 214 usage(); 215 op = RESTORE; 216 break; 217 case 'W': 218 if (op != UNSPEC) 219 usage(); 220 op = WRITEABLE; 221 break; 222 case 'e': 223 if (op != UNSPEC) 224 usage(); 225 op = EDIT; 226 break; 227 case 'V': 228 ++Vflag; 229 break; 230 case 'r': 231 ++rflag; 232 break; 233 case 'w': 234 if (op != UNSPEC) 235 usage(); 236 op = WRITE; 237 break; 238 #ifdef DEBUG 239 case 'd': 240 debug++; 241 break; 242 #endif 243 case '?': 244 default: 245 usage(); 246 } 247 argc -= optind; 248 argv += optind; 249 if (installboot) { 250 rflag++; 251 if (op == UNSPEC) 252 op = WRITEBOOT; 253 } else { 254 if (op == UNSPEC) 255 op = READ; 256 boot1path = NULL; 257 boot2path = NULL; 258 } 259 if (argc < 1) 260 usage(); 261 262 dkname = getdevpath(argv[0], 0); 263 specname = dkname; 264 f = open(specname, op == READ ? O_RDONLY : O_RDWR); 265 if (f < 0) 266 err(4, "%s", specname); 267 268 switch(op) { 269 270 case UNSPEC: 271 break; 272 273 case EDIT: 274 if (argc != 1) 275 usage(); 276 lp = readlabel(f); 277 error = edit(lp, f); 278 break; 279 280 case NOWRITE: 281 flag = 0; 282 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 283 err(4, "ioctl DIOCWLABEL"); 284 break; 285 286 case READ: 287 if (argc != 1) 288 usage(); 289 lp = readlabel(f); 290 display(stdout, lp); 291 error = checklabel(lp); 292 break; 293 294 case RESTORE: 295 if (installboot && argc == 3) { 296 makelabel(argv[2], 0, &lab); 297 argc--; 298 299 /* 300 * We only called makelabel() for its side effect 301 * of setting the bootstrap file names. Discard 302 * all changes to `lab' so that all values in the 303 * final label come from the ASCII label. 304 */ 305 bzero((char *)&lab, sizeof(lab)); 306 } 307 if (argc != 2) 308 usage(); 309 if (!(t = fopen(argv[1], "r"))) 310 err(4, "%s", argv[1]); 311 if (!getasciilabel(t, &lab)) 312 exit(1); 313 lp = makebootarea(f); 314 bcopy(&lab.d_magic, &lp->d_magic, 315 sizeof(lab) - offsetof(struct disklabel64, d_magic)); 316 error = writelabel(f, lp); 317 break; 318 319 case WRITE: 320 if (argc == 3) { 321 name = argv[2]; 322 argc--; 323 } 324 if (argc != 2) 325 usage(); 326 makelabel(argv[1], name, &lab); 327 lp = makebootarea(f); 328 bcopy(&lab.d_magic, &lp->d_magic, 329 sizeof(lab) - offsetof(struct disklabel64, d_magic)); 330 if (checklabel(lp) == 0) 331 error = writelabel(f, lp); 332 break; 333 334 case WRITEABLE: 335 flag = 1; 336 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 337 err(4, "ioctl DIOCWLABEL"); 338 break; 339 340 case WRITEBOOT: 341 { 342 struct disklabel64 tlab; 343 344 lp = readlabel(f); 345 tlab = *lp; 346 if (argc == 2) 347 makelabel(argv[1], 0, &lab); 348 lp = makebootarea(f); 349 bcopy(&tlab.d_magic, &lp->d_magic, 350 sizeof(tlab) - offsetof(struct disklabel64, d_magic)); 351 if (checklabel(lp) == 0) 352 error = writelabel(f, lp); 353 break; 354 } 355 } 356 exit(error); 357 } 358 359 /* 360 * Construct a prototype disklabel from /etc/disktab. As a side 361 * effect, set the names of the primary and secondary boot files 362 * if specified. 363 */ 364 void 365 makelabel(const char *type, const char *name, struct disklabel64 *lp) 366 { 367 struct disklabel64 *dp; 368 369 if (strcmp(type, "auto") == 0) 370 dp = getvirginlabel(); 371 else 372 dp = NULL; 373 if (dp == NULL) 374 errx(1, "%s: unknown disk type", type); 375 *lp = *dp; 376 377 /* 378 * NOTE: boot control files may no longer be specified in disktab. 379 */ 380 if (name) 381 strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 382 } 383 384 int 385 writelabel(int f, struct disklabel64 *lp) 386 { 387 struct disklabel64 *blp; 388 int flag; 389 int r; 390 size_t lpsize; 391 size_t lpcrcsize; 392 393 lpsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]); 394 lpcrcsize = lpsize - offsetof(struct disklabel64, d_magic); 395 396 if (disable_write) { 397 Warning("write to disk label suppressed - label was as follows:"); 398 display(stdout, lp); 399 return (0); 400 } else { 401 lp->d_magic = DISKMAGIC64; 402 lp->d_crc = 0; 403 lp->d_crc = crc32(&lp->d_magic, lpcrcsize); 404 if (rflag) { 405 /* 406 * Make sure the boot area is not too large 407 */ 408 if (boot2buf) { 409 int lpbsize = (int)(lp->d_pbase - lp->d_bbase); 410 if (lp->d_pbase == 0) { 411 errx(1, "no space was set aside in " 412 "the disklabel for boot2!"); 413 } 414 if (boot2size > lpbsize) { 415 errx(1, "label did not reserve enough " 416 "space for boot! %d/%d", 417 boot2size, lpbsize); 418 } 419 } 420 421 /* 422 * First set the kernel disk label, 423 * then write a label to the raw disk. 424 * If the SDINFO ioctl fails because it is 425 * unimplemented, keep going; otherwise, the kernel 426 * consistency checks may prevent us from changing 427 * the current (in-core) label. 428 */ 429 if (ioctl(f, DIOCSDINFO64, lp) < 0 && 430 errno != ENODEV && errno != ENOTTY) { 431 l_perror("ioctl DIOCSDINFO"); 432 return (1); 433 } 434 lseek(f, (off_t)0, SEEK_SET); 435 436 /* 437 * The disklabel embeds areas which we may not 438 * have wanted to change. Merge those areas in 439 * from disk. 440 */ 441 blp = makebootarea(f); 442 if (blp != lp) { 443 bcopy(&lp->d_magic, &blp->d_magic, 444 sizeof(*lp) - 445 offsetof(struct disklabel64, d_magic)); 446 } 447 448 /* 449 * write enable label sector before write 450 * (if necessary), disable after writing. 451 */ 452 flag = 1; 453 if (ioctl(f, DIOCWLABEL, &flag) < 0) 454 warn("ioctl DIOCWLABEL"); 455 456 r = write(f, boot1buf, boot1lsize); 457 if (r != (ssize_t)boot1lsize) { 458 warn("write"); 459 return (1); 460 } 461 /* 462 * Output the remainder of the disklabel 463 */ 464 if (boot2buf) { 465 lseek(f, lp->d_bbase, 0); 466 r = write(f, boot2buf, boot2size); 467 if (r != boot2size) { 468 warn("write"); 469 return(1); 470 } 471 } 472 flag = 0; 473 ioctl(f, DIOCWLABEL, &flag); 474 } else if (ioctl(f, DIOCWDINFO64, lp) < 0) { 475 l_perror("ioctl DIOCWDINFO64"); 476 return (1); 477 } 478 } 479 return (0); 480 } 481 482 void 483 l_perror(const char *s) 484 { 485 switch (errno) { 486 487 case ESRCH: 488 warnx("%s: no disk label on disk;", s); 489 fprintf(stderr, "add \"-r\" to install initial label\n"); 490 break; 491 492 case EINVAL: 493 warnx("%s: label magic number or checksum is wrong!", s); 494 fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 495 break; 496 497 case EBUSY: 498 warnx("%s: open partition would move or shrink", s); 499 break; 500 501 case ENOATTR: 502 warnx("%s: the disk already has a label of a different type,\n" 503 "probably a 32 bit disklabel. It must be cleaned out " 504 "first.\n", s); 505 break; 506 507 default: 508 warn(NULL); 509 break; 510 } 511 } 512 513 /* 514 * Fetch disklabel for disk. 515 * Use ioctl to get label unless -r flag is given. 516 */ 517 struct disklabel64 * 518 readlabel(int f) 519 { 520 struct disklabel64 *lp; 521 u_int32_t savecrc; 522 size_t lpcrcsize; 523 524 if (rflag) { 525 /* 526 * Allocate space for the label. The boot1 code, if any, 527 * is embedded in the label. The label overlaps the boot1 528 * code. 529 */ 530 lp = makebootarea(f); 531 lpcrcsize = offsetof(struct disklabel64, 532 d_partitions[lp->d_npartitions]) - 533 offsetof(struct disklabel64, d_magic); 534 savecrc = lp->d_crc; 535 lp->d_crc = 0; 536 if (lp->d_magic != DISKMAGIC64) 537 errx(1, "bad pack magic number"); 538 if (lp->d_npartitions > MAXPARTITIONS64 || 539 savecrc != crc32(&lp->d_magic, lpcrcsize) 540 ) { 541 errx(1, "corrupted disklabel64"); 542 } 543 lp->d_crc = savecrc; 544 } else { 545 /* 546 * Just use a static structure to hold the label. Note 547 * that DIOCSDINFO64 does not overwrite the boot1 area 548 * even though it is part of the disklabel64 structure. 549 */ 550 lp = &lab; 551 if (Vflag) { 552 if (ioctl(f, DIOCGDVIRGIN64, lp) < 0) { 553 l_perror("ioctl DIOCGDVIRGIN64"); 554 exit(4); 555 } 556 } else { 557 if (ioctl(f, DIOCGDINFO64, lp) < 0) { 558 l_perror("ioctl DIOCGDINFO64"); 559 exit(4); 560 } 561 } 562 } 563 return (lp); 564 } 565 566 /* 567 * Construct a boot area for boot1 and boot2 and return the location of 568 * the label within the area. The caller will overwrite the label so 569 * we don't actually have to read it. 570 */ 571 struct disklabel64 * 572 makebootarea(int f) 573 { 574 struct disklabel64 *lp; 575 struct partinfo info; 576 u_int32_t secsize; 577 struct stat st; 578 int fd; 579 int r; 580 581 if (ioctl(f, DIOCGPART, &info) == 0) 582 secsize = info.media_blksize; 583 else 584 secsize = 512; 585 586 if (boot1buf == NULL) { 587 size_t rsize; 588 589 rsize = (sizeof(struct disklabel64) + secsize - 1) & 590 ~(secsize - 1); 591 boot1size = offsetof(struct disklabel64, d_magic); 592 boot1lsize = rsize; 593 boot1buf = malloc(rsize); 594 bzero(boot1buf, rsize); 595 r = read(f, boot1buf, rsize); 596 if (r != (int)rsize) 597 err(4, "%s", specname); 598 } 599 lp = (void *)boot1buf; 600 601 if (installboot == 0) 602 return(lp); 603 604 if (boot2buf == NULL) { 605 boot2size = 32768; 606 boot2buf = malloc(boot2size); 607 bzero(boot2buf, boot2size); 608 } 609 610 /* 611 * If installing the boot code, read it into the appropriate portions 612 * of the buffer(s) 613 */ 614 if (boot1path == NULL) 615 asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR); 616 if (boot2path == NULL) 617 asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR); 618 619 if ((fd = open(boot1path, O_RDONLY)) < 0) 620 err(4, "%s", boot1path); 621 if (fstat(fd, &st) < 0) 622 err(4, "%s", boot1path); 623 if (st.st_size > boot1size) 624 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 625 if (read(fd, boot1buf, boot1size) != boot1size) 626 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 627 close(fd); 628 629 if ((fd = open(boot2path, O_RDONLY)) < 0) 630 err(4, "%s", boot2path); 631 if (fstat(fd, &st) < 0) 632 err(4, "%s", boot2path); 633 if (st.st_size > boot2size) 634 err(4, "%s must be <= %d bytes!", boot2path, boot2size); 635 if ((r = read(fd, boot2buf, boot2size)) < 1) 636 err(4, "%s is empty!", boot2path); 637 boot2size = (r + secsize - 1) & ~(secsize - 1); 638 close(fd); 639 640 /* 641 * XXX dangerously dedicated support goes here XXX 642 */ 643 return (lp); 644 } 645 646 void 647 display(FILE *f, const struct disklabel64 *lp) 648 { 649 const struct partition64 *pp; 650 char *str; 651 unsigned int part; 652 int didany; 653 uint32_t blksize; 654 655 /* 656 * Use a human readable block size if possible. This is for 657 * display and editing purposes only. 658 */ 659 if (lp->d_align > 1024) 660 blksize = 1024; 661 else 662 blksize = lp->d_align; 663 664 fprintf(f, "# %s:\n", specname); 665 fprintf(f, "#\n"); 666 fprintf(f, "# Informational fields calculated from the above\n"); 667 fprintf(f, "# All byte equivalent offsets must be aligned\n"); 668 fprintf(f, "#\n"); 669 fprintf(f, "# boot space: %10ju bytes\n", 670 (intmax_t)(lp->d_pbase - lp->d_bbase)); 671 fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n", 672 (intmax_t)(lp->d_pstop - lp->d_pbase) / blksize, 673 (double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0, 674 (intmax_t)(lp->d_pstop - lp->d_pbase)); 675 fprintf(f, "#\n"); 676 fprintf(f, "# NOTE: If the partition data base looks odd it may be\n"); 677 fprintf(f, "# physically aligned instead of slice-aligned\n"); 678 fprintf(f, "#\n"); 679 680 uuid_to_string(&lp->d_stor_uuid, &str, NULL); 681 fprintf(f, "diskid: %s\n", str ? str : "<unknown>"); 682 free(str); 683 684 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 685 lp->d_packname); 686 fprintf(f, "boot2 data base: 0x%012jx\n", (intmax_t)lp->d_bbase); 687 fprintf(f, "partitions data base: 0x%012jx\n", (intmax_t)lp->d_pbase); 688 fprintf(f, "partitions data stop: 0x%012jx\n", (intmax_t)lp->d_pstop); 689 fprintf(f, "backup label: 0x%012jx\n", (intmax_t)lp->d_abase); 690 fprintf(f, "total size: 0x%012jx\t# %6.2f MB\n", 691 (intmax_t)lp->d_total_size, 692 (double)lp->d_total_size / 1024.0 / 1024.0); 693 fprintf(f, "alignment: %u\n", lp->d_align); 694 fprintf(f, "display block size: %u\t# for partition display only\n", 695 blksize); 696 697 fprintf(f, "\n"); 698 fprintf(f, "%u partitions:\n", lp->d_npartitions); 699 fprintf(f, "# size offset fstype fsuuid\n"); 700 didany = 0; 701 for (part = 0; part < lp->d_npartitions; part++) { 702 pp = &lp->d_partitions[part]; 703 const u_long onemeg = 1024 * 1024; 704 705 if (pp->p_bsize == 0) 706 continue; 707 didany = 1; 708 fprintf(f, " %c: ", 'a' + part); 709 710 if (pp->p_bsize % lp->d_align) 711 fprintf(f, "%10s ", "ILLEGAL"); 712 else 713 fprintf(f, "%10ju ", (intmax_t)pp->p_bsize / blksize); 714 715 if ((pp->p_boffset - lp->d_pbase) % lp->d_align) 716 fprintf(f, "%10s ", "ILLEGAL"); 717 else 718 fprintf(f, "%10ju ", 719 (intmax_t)(pp->p_boffset - lp->d_pbase) / blksize); 720 721 if (pp->p_fstype < FSMAXTYPES) 722 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 723 else 724 fprintf(f, "%8d", pp->p_fstype); 725 fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg); 726 fprintf(f, "\n"); 727 } 728 for (part = 0; part < lp->d_npartitions; part++) { 729 pp = &lp->d_partitions[part]; 730 731 if (pp->p_bsize == 0) 732 continue; 733 734 if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) { 735 fprintf(f, " %c-stor_uuid: ", 'a' + part); 736 str = NULL; 737 uuid_to_string(&pp->p_stor_uuid, &str, NULL); 738 if (str) { 739 fprintf(f, "%s", str); 740 free(str); 741 } 742 fprintf(f, "\n"); 743 } 744 } 745 if (didany == 0) { 746 fprintf(f, "# EXAMPLE\n"); 747 fprintf(f, "#a: 4g 0 4.2BSD\n"); 748 fprintf(f, "#a: * * 4.2BSD\n"); 749 750 } 751 fflush(f); 752 } 753 754 int 755 edit(struct disklabel64 *lp, int f) 756 { 757 int c, fd; 758 struct disklabel64 label; 759 FILE *fp; 760 761 if ((fd = mkstemp(tmpfil)) == -1 || 762 (fp = fdopen(fd, "w")) == NULL) { 763 warnx("can't create %s", tmpfil); 764 return (1); 765 } 766 display(fp, lp); 767 fclose(fp); 768 for (;;) { 769 if (!editit()) 770 break; 771 fp = fopen(tmpfil, "r"); 772 if (fp == NULL) { 773 warnx("can't reopen %s for reading", tmpfil); 774 break; 775 } 776 bzero((char *)&label, sizeof(label)); 777 if (getasciilabel(fp, &label)) { 778 *lp = label; 779 if (writelabel(f, lp) == 0) { 780 fclose(fp); 781 unlink(tmpfil); 782 return (0); 783 } 784 } 785 fclose(fp); 786 printf("re-edit the label? [y]: "); fflush(stdout); 787 c = getchar(); 788 if (c != EOF && c != (int)'\n') 789 while (getchar() != (int)'\n') 790 ; 791 if (c == (int)'n') 792 break; 793 } 794 unlink(tmpfil); 795 return (1); 796 } 797 798 int 799 editit(void) 800 { 801 int pid, xpid; 802 int status, omask; 803 const char *ed; 804 805 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 806 while ((pid = fork()) < 0) { 807 if (errno == EPROCLIM) { 808 warnx("you have too many processes"); 809 return(0); 810 } 811 if (errno != EAGAIN) { 812 warn("fork"); 813 return(0); 814 } 815 sleep(1); 816 } 817 if (pid == 0) { 818 sigsetmask(omask); 819 setgid(getgid()); 820 setuid(getuid()); 821 if ((ed = getenv("EDITOR")) == NULL) 822 ed = DEFEDITOR; 823 execlp(ed, ed, tmpfil, NULL); 824 err(1, "%s", ed); 825 } 826 while ((xpid = wait(&status)) >= 0) 827 if (xpid == pid) 828 break; 829 sigsetmask(omask); 830 return(!status); 831 } 832 833 char * 834 skip(char *cp) 835 { 836 837 while (*cp != '\0' && isspace(*cp)) 838 cp++; 839 if (*cp == '\0' || *cp == '#') 840 return (NULL); 841 return (cp); 842 } 843 844 char * 845 word(char *cp) 846 { 847 char c; 848 849 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 850 cp++; 851 if ((c = *cp) != '\0') { 852 *cp++ = '\0'; 853 if (c != '#') 854 return (skip(cp)); 855 } 856 return (NULL); 857 } 858 859 /* 860 * Read an ascii label in from fd f, 861 * in the same format as that put out by display(), 862 * and fill in lp. 863 */ 864 int 865 getasciilabel(FILE *f, struct disklabel64 *lp) 866 { 867 char *cp; 868 u_int part; 869 char *tp, line[BUFSIZ]; 870 u_long v; 871 uint32_t blksize = 0; 872 uint64_t vv; 873 int lineno = 0, errors = 0; 874 char empty[] = ""; 875 876 bzero(&part_set, sizeof(part_set)); 877 bzero(&part_size_type, sizeof(part_size_type)); 878 bzero(&part_offset_type, sizeof(part_offset_type)); 879 while (fgets(line, sizeof(line) - 1, f)) { 880 lineno++; 881 if ((cp = strchr(line,'\n')) != NULL) 882 *cp = '\0'; 883 cp = skip(line); 884 if (cp == NULL) 885 continue; 886 tp = strchr(cp, ':'); 887 if (tp == NULL) { 888 fprintf(stderr, "line %d: syntax error\n", lineno); 889 errors++; 890 continue; 891 } 892 *tp++ = '\0', tp = skip(tp); 893 if (sscanf(cp, "%lu partitions", &v) == 1) { 894 if (v == 0 || v > MAXPARTITIONS64) { 895 fprintf(stderr, 896 "line %d: bad # of partitions\n", lineno); 897 lp->d_npartitions = MAXPARTITIONS64; 898 errors++; 899 } else 900 lp->d_npartitions = v; 901 continue; 902 } 903 if (tp == NULL) 904 tp = empty; 905 906 if (streq(cp, "diskid")) { 907 uint32_t status = 0; 908 uuid_from_string(tp, &lp->d_stor_uuid, &status); 909 if (status != uuid_s_ok) { 910 fprintf(stderr, 911 "line %d: %s: illegal UUID\n", 912 lineno, tp); 913 errors++; 914 } 915 continue; 916 } 917 if (streq(cp, "label")) { 918 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 919 continue; 920 } 921 922 if (streq(cp, "alignment")) { 923 v = strtoul(tp, NULL, 0); 924 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 925 fprintf(stderr, 926 "line %d: %s: bad alignment\n", 927 lineno, tp); 928 errors++; 929 } else { 930 lp->d_align = v; 931 } 932 continue; 933 } 934 if (streq(cp, "total size")) { 935 vv = strtoull(tp, NULL, 0); 936 if (vv == 0 || vv == (uint64_t)-1) { 937 fprintf(stderr, "line %d: %s: bad %s\n", 938 lineno, tp, cp); 939 errors++; 940 } else { 941 lp->d_total_size = vv; 942 } 943 continue; 944 } 945 if (streq(cp, "boot2 data base")) { 946 vv = strtoull(tp, NULL, 0); 947 if (vv == 0 || vv == (uint64_t)-1) { 948 fprintf(stderr, "line %d: %s: bad %s\n", 949 lineno, tp, cp); 950 errors++; 951 } else { 952 lp->d_bbase = vv; 953 } 954 continue; 955 } 956 if (streq(cp, "partitions data base")) { 957 vv = strtoull(tp, NULL, 0); 958 if (vv == 0 || vv == (uint64_t)-1) { 959 fprintf(stderr, "line %d: %s: bad %s\n", 960 lineno, tp, cp); 961 errors++; 962 } else { 963 lp->d_pbase = vv; 964 } 965 continue; 966 } 967 if (streq(cp, "partitions data stop")) { 968 vv = strtoull(tp, NULL, 0); 969 if (vv == 0 || vv == (uint64_t)-1) { 970 fprintf(stderr, "line %d: %s: bad %s\n", 971 lineno, tp, cp); 972 errors++; 973 } else { 974 lp->d_pstop = vv; 975 } 976 continue; 977 } 978 if (streq(cp, "backup label")) { 979 vv = strtoull(tp, NULL, 0); 980 if (vv == 0 || vv == (uint64_t)-1) { 981 fprintf(stderr, "line %d: %s: bad %s\n", 982 lineno, tp, cp); 983 errors++; 984 } else { 985 lp->d_abase = vv; 986 } 987 continue; 988 } 989 if (streq(cp, "display block size")) { 990 v = strtoul(tp, NULL, 0); 991 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 992 fprintf(stderr, 993 "line %d: %s: bad alignment\n", 994 lineno, tp); 995 errors++; 996 } else { 997 blksize = v; 998 } 999 continue; 1000 } 1001 1002 /* the ':' was removed above */ 1003 1004 /* 1005 * Handle main partition data, e.g. a:, b:, etc. 1006 */ 1007 if (*cp < 'a' || *cp > MAX_PART) { 1008 fprintf(stderr, 1009 "line %d: %s: Unknown disklabel field\n", lineno, 1010 cp); 1011 errors++; 1012 continue; 1013 } 1014 1015 /* Process a partition specification line. */ 1016 part = *cp - 'a'; 1017 if (part >= lp->d_npartitions) { 1018 fprintf(stderr, 1019 "line %d: partition name out of range a-%c: %s\n", 1020 lineno, 'a' + lp->d_npartitions - 1, cp); 1021 errors++; 1022 continue; 1023 } 1024 1025 if (blksize == 0) { 1026 fprintf(stderr, "block size to use for partition " 1027 "display was not specified!\n"); 1028 errors++; 1029 continue; 1030 } 1031 1032 if (strcmp(cp + 1, "-stor_uuid") == 0) { 1033 if (getasciipartuuid(tp, lp, part, lineno, blksize)) { 1034 errors++; 1035 break; 1036 } 1037 continue; 1038 } else if (cp[1] == 0) { 1039 part_set[part] = 1; 1040 if (getasciipartspec(tp, lp, part, lineno, blksize)) { 1041 errors++; 1042 break; 1043 } 1044 continue; 1045 } 1046 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1047 lineno, cp); 1048 errors++; 1049 continue; 1050 } 1051 errors += checklabel(lp); 1052 return (errors == 0); 1053 } 1054 1055 static 1056 int 1057 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno) 1058 { 1059 char *tmp; 1060 1061 if (*tp == NULL || **tp == 0) { 1062 fprintf(stderr, "line %d: too few numeric fields\n", lineno); 1063 return(-1); 1064 } 1065 *cp = *tp; 1066 *tp = word(*cp); 1067 *vv = strtoull(*cp, &tmp, 0); 1068 if (*vv == ULLONG_MAX) { 1069 fprintf(stderr, "line %d: illegal number\n", lineno); 1070 return(-1); 1071 } 1072 if (tmp) 1073 return(*tmp); 1074 else 1075 return(0); 1076 } 1077 1078 /* 1079 * Read a partition line into partition `part' in the specified disklabel. 1080 * Return 0 on success, 1 on failure. 1081 */ 1082 int 1083 getasciipartspec(char *tp, struct disklabel64 *lp, int part, 1084 int lineno, uint32_t blksize) 1085 { 1086 struct partition64 *pp; 1087 char *cp; 1088 const char **cpp; 1089 int r; 1090 u_long v; 1091 uint64_t vv; 1092 uint64_t mpx; 1093 1094 pp = &lp->d_partitions[part]; 1095 cp = NULL; 1096 1097 /* 1098 * size 1099 */ 1100 r = parse_field_val(&tp, &cp, &vv, lineno); 1101 if (r < 0) 1102 return (1); 1103 1104 mpx = 1; 1105 switch(r) { 1106 case 0: 1107 mpx = blksize; 1108 break; 1109 case '%': 1110 /* mpx = 1; */ 1111 break; 1112 case '*': 1113 mpx = 0; 1114 break; 1115 case 't': 1116 case 'T': 1117 mpx *= 1024ULL; 1118 /* fall through */ 1119 case 'g': 1120 case 'G': 1121 mpx *= 1024ULL; 1122 /* fall through */ 1123 case 'm': 1124 case 'M': 1125 mpx *= 1024ULL; 1126 /* fall through */ 1127 case 'k': 1128 case 'K': 1129 mpx *= 1024ULL; 1130 r = 0; /* eat the suffix */ 1131 break; 1132 default: 1133 Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)", 1134 r); 1135 return(1); 1136 } 1137 1138 part_size_type[part] = r; 1139 if (vv == 0 && r != '*') { 1140 fprintf(stderr, 1141 "line %d: %s: bad partition size (0)\n", lineno, cp); 1142 return (1); 1143 } 1144 pp->p_bsize = vv * mpx; 1145 1146 /* 1147 * offset 1148 */ 1149 r = parse_field_val(&tp, &cp, &vv, lineno); 1150 if (r < 0) 1151 return (1); 1152 part_offset_type[part] = r; 1153 switch(r) { 1154 case '*': 1155 pp->p_boffset = 0; 1156 break; 1157 case 0: 1158 pp->p_boffset = vv * blksize + lp->d_pbase; 1159 break; 1160 default: 1161 fprintf(stderr, 1162 "line %d: %s: bad suffix on partition offset (%c)\n", 1163 lineno, cp, r); 1164 return (1); 1165 } 1166 1167 /* 1168 * fstype 1169 */ 1170 cp = tp; 1171 tp = word(cp); 1172 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 1173 if (*cpp && strcasecmp(*cpp, cp) == 0) 1174 break; 1175 } 1176 if (*cpp != NULL) { 1177 pp->p_fstype = cpp - fstypenames; 1178 } else { 1179 if (isdigit(*cp)) 1180 v = strtoul(cp, NULL, 0); 1181 else 1182 v = FSMAXTYPES; 1183 if (v >= FSMAXTYPES) { 1184 fprintf(stderr, 1185 "line %d: Warning, unknown filesystem type %s\n", 1186 lineno, cp); 1187 v = FS_UNUSED; 1188 } 1189 pp->p_fstype = v; 1190 } 1191 1192 cp = tp; 1193 if (tp) { 1194 fprintf(stderr, "line %d: Warning, extra data on line\n", 1195 lineno); 1196 } 1197 return(0); 1198 } 1199 1200 int 1201 getasciipartuuid(char *tp, struct disklabel64 *lp, int part, 1202 int lineno, uint32_t blksize __unused) 1203 { 1204 struct partition64 *pp; 1205 uint32_t status; 1206 char *cp; 1207 1208 pp = &lp->d_partitions[part]; 1209 1210 cp = tp; 1211 tp = word(cp); 1212 uuid_from_string(cp, &pp->p_stor_uuid, &status); 1213 if (status != uuid_s_ok) { 1214 fprintf(stderr, "line %d: Illegal storage uuid specification\n", 1215 lineno); 1216 return(1); 1217 } 1218 return(0); 1219 } 1220 1221 /* 1222 * Check disklabel for errors and fill in 1223 * derived fields according to supplied values. 1224 */ 1225 int 1226 checklabel(struct disklabel64 *lp) 1227 { 1228 struct partition64 *pp; 1229 int errors = 0; 1230 char part; 1231 u_int64_t total_size; 1232 u_int64_t current_offset; 1233 u_long total_percent; 1234 int seen_default_offset; 1235 int hog_part; 1236 int i, j; 1237 struct partition64 *pp2; 1238 u_int64_t off; 1239 1240 if (lp->d_align < 512 || 1241 (lp->d_align ^ (lp->d_align - 1)) != lp->d_align * 2 - 1) { 1242 Warning("Illegal alignment specified: %u\n", lp->d_align); 1243 return (1); 1244 } 1245 if (lp->d_npartitions > MAXPARTITIONS64) { 1246 Warning("number of partitions (%u) > MAXPARTITIONS (%d)", 1247 lp->d_npartitions, MAXPARTITIONS64); 1248 return (1); 1249 } 1250 off = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]); 1251 off = (off + lp->d_align - 1) & ~(int64_t)(lp->d_align - 1); 1252 1253 if (lp->d_bbase < off || lp->d_bbase % lp->d_align) { 1254 Warning("illegal boot2 data base "); 1255 return (1); 1256 } 1257 1258 /* 1259 * pbase can be unaligned slice-relative but will be 1260 * aligned physically. 1261 */ 1262 if (lp->d_pbase < lp->d_bbase) { 1263 Warning("illegal partition data base"); 1264 return (1); 1265 } 1266 if (lp->d_pstop < lp->d_pbase) { 1267 Warning("illegal partition data stop"); 1268 return (1); 1269 } 1270 if (lp->d_pstop > lp->d_total_size) { 1271 printf("%012jx\n%012jx\n", 1272 (intmax_t)lp->d_pstop, (intmax_t)lp->d_total_size); 1273 Warning("disklabel control info is beyond the total size"); 1274 return (1); 1275 } 1276 if (lp->d_abase && 1277 (lp->d_abase < lp->d_pstop || 1278 lp->d_abase > lp->d_total_size - off)) { 1279 Warning("illegal backup label location"); 1280 return (1); 1281 } 1282 1283 /* first allocate space to the partitions, then offsets */ 1284 total_size = 0; /* in bytes */ 1285 total_percent = 0; /* in percent */ 1286 hog_part = -1; 1287 /* find all fixed partitions */ 1288 for (i = 0; i < (int)lp->d_npartitions; i++) { 1289 pp = &lp->d_partitions[i]; 1290 if (part_set[i]) { 1291 if (part_size_type[i] == '*') { 1292 if (part_offset_type[i] != '*') { 1293 if (total_size < pp->p_boffset) 1294 total_size = pp->p_boffset; 1295 } 1296 if (hog_part != -1) { 1297 Warning("Too many '*' partitions (%c and %c)", 1298 hog_part + 'a',i + 'a'); 1299 } else { 1300 hog_part = i; 1301 } 1302 } else { 1303 off_t size; 1304 1305 size = pp->p_bsize; 1306 if (part_size_type[i] == '%') { 1307 /* 1308 * don't count %'s yet 1309 */ 1310 total_percent += size; 1311 } else { 1312 /* 1313 * Value has already been converted 1314 * to bytes. 1315 */ 1316 if (size % lp->d_align != 0) { 1317 Warning("partition %c's size is not properly aligned", 1318 i + 'a'); 1319 } 1320 total_size += size; 1321 } 1322 } 1323 } 1324 } 1325 /* handle % partitions - note %'s don't need to add up to 100! */ 1326 if (total_percent != 0) { 1327 int64_t free_space; 1328 int64_t space_left; 1329 1330 free_space = (int64_t)(lp->d_pstop - lp->d_pbase - total_size); 1331 free_space &= ~(u_int64_t)(lp->d_align - 1); 1332 1333 space_left = free_space; 1334 if (total_percent > 100) { 1335 fprintf(stderr,"total percentage %lu is greater than 100\n", 1336 total_percent); 1337 errors++; 1338 } 1339 1340 if (free_space > 0) { 1341 for (i = 0; i < (int)lp->d_npartitions; i++) { 1342 pp = &lp->d_partitions[i]; 1343 if (part_set[i] && part_size_type[i] == '%') { 1344 /* careful of overflows! and integer roundoff */ 1345 pp->p_bsize = ((double)pp->p_bsize/100) * free_space; 1346 pp->p_bsize = (pp->p_bsize + lp->d_align - 1) & ~(u_int64_t)(lp->d_align - 1); 1347 if ((int64_t)pp->p_bsize > space_left) 1348 pp->p_bsize = (u_int64_t)space_left; 1349 total_size += pp->p_bsize; 1350 space_left -= pp->p_bsize; 1351 } 1352 } 1353 } else { 1354 fprintf(stderr, "%jd bytes available to give to " 1355 "'*' and '%%' partitions\n", 1356 (intmax_t)free_space); 1357 errors++; 1358 /* fix? set all % partitions to size 0? */ 1359 } 1360 } 1361 /* give anything remaining to the hog partition */ 1362 if (hog_part != -1) { 1363 off = lp->d_pstop - lp->d_pbase - total_size; 1364 off &= ~(u_int64_t)(lp->d_align - 1); 1365 lp->d_partitions[hog_part].p_bsize = off; 1366 total_size = lp->d_pstop - lp->d_pbase; 1367 } 1368 1369 /* Now set the offsets for each partition */ 1370 current_offset = lp->d_pbase; 1371 seen_default_offset = 0; 1372 for (i = 0; i < (int)lp->d_npartitions; i++) { 1373 part = 'a' + i; 1374 pp = &lp->d_partitions[i]; 1375 if (pp->p_bsize == 0) 1376 continue; 1377 if (part_set[i]) { 1378 if (part_offset_type[i] == '*') { 1379 pp->p_boffset = current_offset; 1380 seen_default_offset = 1; 1381 } else { 1382 /* allow them to be out of order for old-style tables */ 1383 if (pp->p_boffset < current_offset && 1384 seen_default_offset && 1385 pp->p_fstype != FS_VINUM) { 1386 fprintf(stderr, 1387 "Offset 0x%012jx for partition %c overlaps previous partition which ends at 0x%012jx\n", 1388 (intmax_t)pp->p_boffset, 1389 i + 'a', 1390 (intmax_t)current_offset); 1391 fprintf(stderr, 1392 "Labels with any *'s for offset must be in ascending order by sector\n"); 1393 errors++; 1394 } else if (pp->p_boffset != current_offset && 1395 seen_default_offset) { 1396 /* 1397 * this may give unneeded warnings if 1398 * partitions are out-of-order 1399 */ 1400 Warning( 1401 "Offset 0x%012jx for partition %c doesn't match expected value 0x%012jx", 1402 pp->p_boffset, i + 'a', 1403 (intmax_t)current_offset); 1404 } 1405 } 1406 current_offset = pp->p_boffset + pp->p_bsize; 1407 } 1408 } 1409 1410 for (i = 0; i < (int)lp->d_npartitions; i++) { 1411 part = 'a' + i; 1412 pp = &lp->d_partitions[i]; 1413 if (pp->p_bsize == 0 && pp->p_boffset != 0) 1414 Warning("partition %c: size 0, but offset 0x%012jx", 1415 part, (intmax_t)pp->p_boffset); 1416 if (pp->p_bsize == 0) { 1417 pp->p_boffset = 0; 1418 continue; 1419 } 1420 if (uuid_is_nil(&pp->p_stor_uuid, NULL)) 1421 uuid_create(&pp->p_stor_uuid, NULL); 1422 1423 if (pp->p_boffset < lp->d_pbase) { 1424 fprintf(stderr, 1425 "partition %c: offset out of bounds (%jd)\n", 1426 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1427 errors++; 1428 } 1429 if (pp->p_boffset > lp->d_pstop) { 1430 fprintf(stderr, 1431 "partition %c: offset out of bounds (%jd)\n", 1432 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1433 errors++; 1434 } 1435 if (pp->p_boffset + pp->p_bsize > lp->d_pstop) { 1436 fprintf(stderr, 1437 "partition %c: size out of bounds (%jd)\n", 1438 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1439 errors++; 1440 } 1441 1442 /* check for overlaps */ 1443 /* this will check for all possible overlaps once and only once */ 1444 for (j = 0; j < i; j++) { 1445 pp2 = &lp->d_partitions[j]; 1446 if (pp->p_fstype != FS_VINUM && 1447 pp2->p_fstype != FS_VINUM && 1448 part_set[i] && part_set[j]) { 1449 if (pp2->p_boffset < pp->p_boffset + pp->p_bsize && 1450 (pp2->p_boffset + pp2->p_bsize > pp->p_boffset || 1451 pp2->p_boffset >= pp->p_boffset)) { 1452 fprintf(stderr,"partitions %c and %c overlap!\n", 1453 j + 'a', i + 'a'); 1454 errors++; 1455 } 1456 } 1457 } 1458 } 1459 for (; i < (int)lp->d_npartitions; i++) { 1460 part = 'a' + i; 1461 pp = &lp->d_partitions[i]; 1462 if (pp->p_bsize || pp->p_boffset) 1463 Warning("unused partition %c: size 0x%012jx " 1464 "offset 0x%012jx", 1465 'a' + i, (intmax_t)pp->p_bsize, 1466 (intmax_t)pp->p_boffset); 1467 } 1468 return (errors); 1469 } 1470 1471 /* 1472 * When operating on a "virgin" disk, try getting an initial label 1473 * from the associated device driver. This might work for all device 1474 * drivers that are able to fetch some initial device parameters 1475 * without even having access to a (BSD) disklabel, like SCSI disks, 1476 * most IDE drives, or vn devices. 1477 * 1478 * The device name must be given in its "canonical" form. 1479 */ 1480 static struct disklabel64 dlab; 1481 1482 struct disklabel64 * 1483 getvirginlabel(void) 1484 { 1485 struct disklabel64 *dl = &dlab; 1486 int f; 1487 1488 if ((f = open(dkname, O_RDONLY)) == -1) { 1489 warn("cannot open %s", dkname); 1490 return (NULL); 1491 } 1492 1493 /* 1494 * Try to use the new get-virgin-label ioctl. If it fails, 1495 * fallback to the old get-disk-info ioctl. 1496 */ 1497 if (ioctl(f, DIOCGDVIRGIN64, dl) < 0) { 1498 l_perror("ioctl DIOCGDVIRGIN64"); 1499 close(f); 1500 return (NULL); 1501 } 1502 close(f); 1503 return (dl); 1504 } 1505 1506 /*VARARGS1*/ 1507 void 1508 Warning(const char *fmt, ...) 1509 { 1510 va_list ap; 1511 1512 fprintf(stderr, "Warning, "); 1513 va_start(ap, fmt); 1514 vfprintf(stderr, fmt, ap); 1515 fprintf(stderr, "\n"); 1516 va_end(ap); 1517 } 1518 1519 void 1520 usage(void) 1521 { 1522 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 1523 "usage: disklabel64 [-r] disk", 1524 "\t\t(to read label)", 1525 " disklabel64 -w [-r] [-n] disk type [packid]", 1526 "\t\t(to write label with existing boot program)", 1527 " disklabel64 -e [-r] [-n] disk", 1528 "\t\t(to edit label)", 1529 " disklabel64 -R [-r] [-n] disk protofile", 1530 "\t\t(to restore label with existing boot program)", 1531 " disklabel64 -B [-n] [-b boot1 -s boot2] disk [type]", 1532 "\t\t(to install boot program with existing label)", 1533 " disklabel64 -w -B [-n] [-b boot1 -s boot2] disk type [packid]", 1534 "\t\t(to write label and boot program)", 1535 " disklabel64 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]", 1536 "\t\t(to restore label and boot program)", 1537 " disklabel64 [-NW] disk", 1538 "\t\t(to write disable/enable label)"); 1539 exit(1); 1540 } 1541