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 * $DragonFly: src/sbin/disklabel64/disklabel64.c,v 1.8 2008/08/22 14:25:02 swildner Exp $ 35 */ 36 /* 37 * Copyright (c) 1987, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * This code is derived from software contributed to Berkeley by 41 * Symmetric Computer Systems. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)disklabel.c 1.2 (Symmetric) 11/28/85 72 * @(#)disklabel.c 8.2 (Berkeley) 1/7/94 73 * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $ 74 * $DragonFly: src/sbin/disklabel64/disklabel64.c,v 1.8 2008/08/22 14:25:02 swildner Exp $ 75 */ 76 77 #include <sys/param.h> 78 #include <sys/file.h> 79 #include <sys/stat.h> 80 #include <sys/wait.h> 81 #define DKTYPENAMES 82 #include <sys/disklabel64.h> 83 #include <sys/diskslice.h> 84 #include <sys/diskmbr.h> 85 #include <sys/dtype.h> 86 #include <sys/sysctl.h> 87 #include <disktab.h> 88 #include <fstab.h> 89 90 #include <vfs/ufs/dinode.h> 91 #include <vfs/ufs/fs.h> 92 93 #include <unistd.h> 94 #include <string.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <signal.h> 98 #include <stdarg.h> 99 #include <stddef.h> 100 #include <ctype.h> 101 #include <err.h> 102 #include <errno.h> 103 #include <disktab.h> 104 #include <uuid.h> 105 #include "pathnames.h" 106 107 extern uint32_t crc32(const void *buf, size_t size); 108 109 /* 110 * Disklabel64: read and write 64 bit disklabels. 111 * The label is usually placed on one of the first sectors of the disk. 112 * Many machines also place a bootstrap in the same area, 113 * in which case the label is embedded in the bootstrap. 114 * The bootstrap source must leave space at the proper offset 115 * for the label on such machines. 116 */ 117 118 #define LABELSIZE ((sizeof(struct disklabel64) + 4095) & ~4095) 119 #define BOOTSIZE 32768 120 121 /* FIX! These are too low, but are traditional */ 122 #define DEFAULT_NEWFS_BLOCK 8192U 123 #define DEFAULT_NEWFS_FRAG 1024U 124 #define DEFAULT_NEWFS_CPG 16U 125 126 #define BIG_NEWFS_BLOCK 16384U 127 #define BIG_NEWFS_FRAG 2048U 128 #define BIG_NEWFS_CPG 64U 129 130 void makelabel(const char *, const char *, struct disklabel64 *); 131 int writelabel(int, struct disklabel64 *); 132 void l_perror(const char *); 133 struct disklabel64 *readlabel(int); 134 struct disklabel64 *makebootarea(int); 135 void display(FILE *, const struct disklabel64 *); 136 int edit(struct disklabel64 *, int); 137 int editit(void); 138 char *skip(char *); 139 char *word(char *); 140 int getasciilabel(FILE *, struct disklabel64 *); 141 int getasciipartspec(char *, struct disklabel64 *, int, int, uint32_t); 142 int getasciipartuuid(char *, struct disklabel64 *, int, int, uint32_t); 143 int checklabel(struct disklabel64 *); 144 void Warning(const char *, ...) __printflike(1, 2); 145 void usage(void); 146 struct disklabel64 *getvirginlabel(void); 147 148 #define DEFEDITOR _PATH_VI 149 #define streq(a,b) (strcmp(a,b) == 0) 150 151 char *dkname; 152 char *specname; 153 char tmpfil[] = PATH_TMPFILE; 154 155 struct disklabel64 lab; 156 157 #define MAX_PART ('z') 158 #define MAX_NUM_PARTS (1 + MAX_PART - 'a') 159 char part_size_type[MAX_NUM_PARTS]; 160 char part_offset_type[MAX_NUM_PARTS]; 161 int part_set[MAX_NUM_PARTS]; 162 163 int installboot; /* non-zero if we should install a boot program */ 164 int boot1size; 165 int boot1lsize; 166 int boot2size; 167 char *boot1buf; 168 char *boot2buf; 169 char *boot1path; 170 char *boot2path; 171 172 enum { 173 UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT 174 } op = UNSPEC; 175 176 int rflag; 177 int Vflag; 178 int disable_write; /* set to disable writing to disk label */ 179 u_int32_t slice_start_lba; 180 181 #ifdef DEBUG 182 int debug; 183 #define OPTIONS "BNRWb:denrs:Vw" 184 #else 185 #define OPTIONS "BNRWb:enrs:Vw" 186 #endif 187 188 int 189 main(int argc, char *argv[]) 190 { 191 struct disklabel64 *lp; 192 FILE *t; 193 int ch, f = 0, flag, error = 0; 194 char *name = 0; 195 196 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 197 switch (ch) { 198 case 'B': 199 ++installboot; 200 break; 201 case 'b': 202 boot1path = optarg; 203 break; 204 205 case 's': 206 boot2path = optarg; 207 break; 208 case 'N': 209 if (op != UNSPEC) 210 usage(); 211 op = NOWRITE; 212 break; 213 case 'n': 214 disable_write = 1; 215 break; 216 case 'R': 217 if (op != UNSPEC) 218 usage(); 219 op = RESTORE; 220 break; 221 case 'W': 222 if (op != UNSPEC) 223 usage(); 224 op = WRITEABLE; 225 break; 226 case 'e': 227 if (op != UNSPEC) 228 usage(); 229 op = EDIT; 230 break; 231 case 'V': 232 ++Vflag; 233 break; 234 case 'r': 235 ++rflag; 236 break; 237 case 'w': 238 if (op != UNSPEC) 239 usage(); 240 op = WRITE; 241 break; 242 #ifdef DEBUG 243 case 'd': 244 debug++; 245 break; 246 #endif 247 case '?': 248 default: 249 usage(); 250 } 251 argc -= optind; 252 argv += optind; 253 if (installboot) { 254 rflag++; 255 if (op == UNSPEC) 256 op = WRITEBOOT; 257 } else { 258 if (op == UNSPEC) 259 op = READ; 260 boot1path = NULL; 261 boot2path = NULL; 262 } 263 if (argc < 1) 264 usage(); 265 266 dkname = getdevpath(argv[0], 0); 267 specname = dkname; 268 f = open(specname, op == READ ? O_RDONLY : O_RDWR); 269 if (f < 0) 270 err(4, "%s", specname); 271 272 switch(op) { 273 274 case UNSPEC: 275 break; 276 277 case EDIT: 278 if (argc != 1) 279 usage(); 280 lp = readlabel(f); 281 error = edit(lp, f); 282 break; 283 284 case NOWRITE: 285 flag = 0; 286 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 287 err(4, "ioctl DIOCWLABEL"); 288 break; 289 290 case READ: 291 if (argc != 1) 292 usage(); 293 lp = readlabel(f); 294 display(stdout, lp); 295 error = checklabel(lp); 296 break; 297 298 case RESTORE: 299 if (installboot && argc == 3) { 300 makelabel(argv[2], 0, &lab); 301 argc--; 302 303 /* 304 * We only called makelabel() for its side effect 305 * of setting the bootstrap file names. Discard 306 * all changes to `lab' so that all values in the 307 * final label come from the ASCII label. 308 */ 309 bzero((char *)&lab, sizeof(lab)); 310 } 311 if (argc != 2) 312 usage(); 313 if (!(t = fopen(argv[1], "r"))) 314 err(4, "%s", argv[1]); 315 if (!getasciilabel(t, &lab)) 316 exit(1); 317 lp = makebootarea(f); 318 bcopy(&lab.d_magic, &lp->d_magic, 319 sizeof(lab) - offsetof(struct disklabel64, d_magic)); 320 error = writelabel(f, lp); 321 break; 322 323 case WRITE: 324 if (argc == 3) { 325 name = argv[2]; 326 argc--; 327 } 328 if (argc != 2) 329 usage(); 330 makelabel(argv[1], name, &lab); 331 lp = makebootarea(f); 332 bcopy(&lab.d_magic, &lp->d_magic, 333 sizeof(lab) - offsetof(struct disklabel64, d_magic)); 334 if (checklabel(lp) == 0) 335 error = writelabel(f, lp); 336 break; 337 338 case WRITEABLE: 339 flag = 1; 340 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 341 err(4, "ioctl DIOCWLABEL"); 342 break; 343 344 case WRITEBOOT: 345 { 346 struct disklabel64 tlab; 347 348 lp = readlabel(f); 349 tlab = *lp; 350 if (argc == 2) 351 makelabel(argv[1], 0, &lab); 352 lp = makebootarea(f); 353 bcopy(&tlab.d_magic, &lp->d_magic, 354 sizeof(tlab) - offsetof(struct disklabel64, d_magic)); 355 if (checklabel(lp) == 0) 356 error = writelabel(f, lp); 357 break; 358 } 359 } 360 exit(error); 361 } 362 363 /* 364 * Construct a prototype disklabel from /etc/disktab. As a side 365 * effect, set the names of the primary and secondary boot files 366 * if specified. 367 */ 368 void 369 makelabel(const char *type, const char *name, struct disklabel64 *lp) 370 { 371 struct disklabel64 *dp; 372 373 if (strcmp(type, "auto") == 0) 374 dp = getvirginlabel(); 375 else 376 dp = NULL; 377 if (dp == NULL) 378 errx(1, "%s: unknown disk type", type); 379 *lp = *dp; 380 381 /* 382 * NOTE: boot control files may no longer be specified in disktab. 383 */ 384 if (name) 385 strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 386 } 387 388 int 389 writelabel(int f, struct disklabel64 *lp) 390 { 391 struct disklabel64 *blp; 392 int flag; 393 int r; 394 size_t lpsize; 395 size_t lpcrcsize; 396 397 lpsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]); 398 lpcrcsize = lpsize - offsetof(struct disklabel64, d_magic); 399 400 if (disable_write) { 401 Warning("write to disk label suppressed - label was as follows:"); 402 display(stdout, lp); 403 return (0); 404 } else { 405 lp->d_magic = DISKMAGIC64; 406 lp->d_crc = 0; 407 lp->d_crc = crc32(&lp->d_magic, lpcrcsize); 408 if (rflag) { 409 /* 410 * Make sure the boot area is not too large 411 */ 412 if (boot2buf) { 413 int lpbsize = (int)(lp->d_pbase - lp->d_bbase); 414 if (lp->d_pbase == 0) { 415 errx(1, "no space was set aside in " 416 "the disklabel for boot2!"); 417 } 418 if (boot2size > lpbsize) { 419 errx(1, "label did not reserve enough " 420 "space for boot! %d/%d", 421 boot2size, lpbsize); 422 } 423 } 424 425 /* 426 * First set the kernel disk label, 427 * then write a label to the raw disk. 428 * If the SDINFO ioctl fails because it is 429 * unimplemented, keep going; otherwise, the kernel 430 * consistency checks may prevent us from changing 431 * the current (in-core) label. 432 */ 433 if (ioctl(f, DIOCSDINFO64, lp) < 0 && 434 errno != ENODEV && errno != ENOTTY) { 435 l_perror("ioctl DIOCSDINFO"); 436 return (1); 437 } 438 lseek(f, (off_t)0, SEEK_SET); 439 440 /* 441 * The disklabel embeds areas which we may not 442 * have wanted to change. Merge those areas in 443 * from disk. 444 */ 445 blp = makebootarea(f); 446 if (blp != lp) { 447 bcopy(&lp->d_magic, &blp->d_magic, 448 sizeof(*lp) - 449 offsetof(struct disklabel64, d_magic)); 450 } 451 452 /* 453 * write enable label sector before write 454 * (if necessary), disable after writing. 455 */ 456 flag = 1; 457 if (ioctl(f, DIOCWLABEL, &flag) < 0) 458 warn("ioctl DIOCWLABEL"); 459 460 r = write(f, boot1buf, boot1lsize); 461 if (r != (ssize_t)boot1lsize) { 462 warn("write"); 463 return (1); 464 } 465 /* 466 * Output the remainder of the disklabel 467 */ 468 if (boot2buf) { 469 lseek(f, lp->d_bbase, 0); 470 r = write(f, boot2buf, boot2size); 471 if (r != boot2size) { 472 warn("write"); 473 return(1); 474 } 475 } 476 flag = 0; 477 ioctl(f, DIOCWLABEL, &flag); 478 } else if (ioctl(f, DIOCWDINFO64, lp) < 0) { 479 l_perror("ioctl DIOCWDINFO64"); 480 return (1); 481 } 482 } 483 return (0); 484 } 485 486 void 487 l_perror(const char *s) 488 { 489 switch (errno) { 490 491 case ESRCH: 492 warnx("%s: no disk label on disk;", s); 493 fprintf(stderr, "add \"-r\" to install initial label\n"); 494 break; 495 496 case EINVAL: 497 warnx("%s: label magic number or checksum is wrong!", s); 498 fprintf(stderr, "(disklabel or kernel is out of date?)\n"); 499 break; 500 501 case EBUSY: 502 warnx("%s: open partition would move or shrink", s); 503 break; 504 505 case ENOATTR: 506 warnx("%s: the disk already has a label of a different type,\n" 507 "probably a 32 bit disklabel. It must be cleaned out " 508 "first.\n", s); 509 break; 510 511 default: 512 warn(NULL); 513 break; 514 } 515 } 516 517 /* 518 * Fetch disklabel for disk. 519 * Use ioctl to get label unless -r flag is given. 520 */ 521 struct disklabel64 * 522 readlabel(int f) 523 { 524 struct disklabel64 *lp; 525 u_int32_t savecrc; 526 size_t lpcrcsize; 527 528 if (rflag) { 529 /* 530 * Allocate space for the label. The boot1 code, if any, 531 * is embedded in the label. The label overlaps the boot1 532 * code. 533 */ 534 lp = makebootarea(f); 535 lpcrcsize = offsetof(struct disklabel64, 536 d_partitions[lp->d_npartitions]) - 537 offsetof(struct disklabel64, d_magic); 538 savecrc = lp->d_crc; 539 lp->d_crc = 0; 540 if (lp->d_magic != DISKMAGIC64) 541 errx(1, "bad pack magic number"); 542 if (lp->d_npartitions > MAXPARTITIONS64 || 543 savecrc != crc32(&lp->d_magic, lpcrcsize) 544 ) { 545 errx(1, "corrupted disklabel64"); 546 } 547 lp->d_crc = savecrc; 548 } else { 549 /* 550 * Just use a static structure to hold the label. Note 551 * that DIOCSDINFO64 does not overwrite the boot1 area 552 * even though it is part of the disklabel64 structure. 553 */ 554 lp = &lab; 555 if (Vflag) { 556 if (ioctl(f, DIOCGDVIRGIN64, lp) < 0) { 557 l_perror("ioctl DIOCGDVIRGIN64"); 558 exit(4); 559 } 560 } else { 561 if (ioctl(f, DIOCGDINFO64, lp) < 0) { 562 l_perror("ioctl DIOCGDINFO64"); 563 exit(4); 564 } 565 } 566 } 567 return (lp); 568 } 569 570 /* 571 * Construct a boot area for boot1 and boot2 and return the location of 572 * the label within the area. The caller will overwrite the label so 573 * we don't actually have to read it. 574 */ 575 struct disklabel64 * 576 makebootarea(int f) 577 { 578 struct disklabel64 *lp; 579 struct partinfo info; 580 u_int32_t secsize; 581 struct stat st; 582 int fd; 583 int r; 584 585 if (ioctl(f, DIOCGPART, &info) == 0) 586 secsize = info.media_blksize; 587 else 588 secsize = 512; 589 590 if (boot1buf == NULL) { 591 size_t rsize; 592 593 rsize = (sizeof(struct disklabel64) + secsize - 1) & 594 ~(secsize - 1); 595 boot1size = offsetof(struct disklabel64, d_magic); 596 boot1lsize = rsize; 597 boot1buf = malloc(rsize); 598 bzero(boot1buf, rsize); 599 r = read(f, boot1buf, rsize); 600 if (r != (int)rsize) 601 err(4, "%s", specname); 602 } 603 lp = (void *)boot1buf; 604 605 if (installboot == 0) 606 return(lp); 607 608 if (boot2buf == NULL) { 609 boot2size = 32768; 610 boot2buf = malloc(boot2size); 611 bzero(boot2buf, boot2size); 612 } 613 614 /* 615 * If installing the boot code, read it into the appropriate portions 616 * of the buffer(s) 617 */ 618 if (boot1path == NULL) 619 asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR); 620 if (boot2path == NULL) 621 asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR); 622 623 if ((fd = open(boot1path, O_RDONLY)) < 0) 624 err(4, "%s", boot1path); 625 if (fstat(fd, &st) < 0) 626 err(4, "%s", boot1path); 627 if (st.st_size > boot1size) 628 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 629 if (read(fd, boot1buf, boot1size) != boot1size) 630 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 631 close(fd); 632 633 if ((fd = open(boot2path, O_RDONLY)) < 0) 634 err(4, "%s", boot2path); 635 if (fstat(fd, &st) < 0) 636 err(4, "%s", boot2path); 637 if (st.st_size > boot2size) 638 err(4, "%s must be <= %d bytes!", boot2path, boot2size); 639 if ((r = read(fd, boot2buf, boot2size)) < 1) 640 err(4, "%s is empty!", boot2path); 641 boot2size = (r + secsize - 1) & ~(secsize - 1); 642 close(fd); 643 644 /* 645 * XXX dangerously dedicated support goes here XXX 646 */ 647 return (lp); 648 } 649 650 void 651 display(FILE *f, const struct disklabel64 *lp) 652 { 653 const struct partition64 *pp; 654 char *str; 655 unsigned int part; 656 int didany; 657 uint32_t blksize; 658 659 /* 660 * Use a human readable block size if possible. This is for 661 * display and editing purposes only. 662 */ 663 if (lp->d_align > 1024) 664 blksize = 1024; 665 else 666 blksize = lp->d_align; 667 668 fprintf(f, "# %s:\n", specname); 669 fprintf(f, "#\n"); 670 fprintf(f, "# Informational fields calculated from the above\n"); 671 fprintf(f, "# All byte equivalent offsets must be aligned\n"); 672 fprintf(f, "#\n"); 673 fprintf(f, "# boot space: %10ju bytes\n", 674 (intmax_t)(lp->d_pbase - lp->d_bbase)); 675 fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n", 676 (intmax_t)(lp->d_pstop - lp->d_pbase) / blksize, 677 (double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0, 678 (intmax_t)(lp->d_pstop - lp->d_pbase)); 679 fprintf(f, "#\n"); 680 fprintf(f, "# NOTE: If the partition data base looks odd it may be\n"); 681 fprintf(f, "# physically aligned instead of slice-aligned\n"); 682 fprintf(f, "#\n"); 683 684 uuid_to_string(&lp->d_stor_uuid, &str, NULL); 685 fprintf(f, "diskid: %s\n", str ? str : "<unknown>"); 686 free(str); 687 688 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 689 lp->d_packname); 690 fprintf(f, "boot2 data base: 0x%012jx\n", (intmax_t)lp->d_bbase); 691 fprintf(f, "partitions data base: 0x%012jx\n", (intmax_t)lp->d_pbase); 692 fprintf(f, "partitions data stop: 0x%012jx\n", (intmax_t)lp->d_pstop); 693 fprintf(f, "backup label: 0x%012jx\n", (intmax_t)lp->d_abase); 694 fprintf(f, "total size: 0x%012jx\t# %6.2f MB\n", 695 (intmax_t)lp->d_total_size, 696 (double)lp->d_total_size / 1024.0 / 1024.0); 697 fprintf(f, "alignment: %u\n", lp->d_align); 698 fprintf(f, "display block size: %u\t# for partition display only\n", 699 blksize); 700 701 fprintf(f, "\n"); 702 fprintf(f, "%u partitions:\n", lp->d_npartitions); 703 fprintf(f, "# size offset fstype fsuuid\n"); 704 didany = 0; 705 for (part = 0; part < lp->d_npartitions; part++) { 706 pp = &lp->d_partitions[part]; 707 const u_long onemeg = 1024 * 1024; 708 709 if (pp->p_bsize == 0) 710 continue; 711 didany = 1; 712 fprintf(f, " %c: ", 'a' + part); 713 714 if (pp->p_bsize % lp->d_align) 715 fprintf(f, "%10s ", "ILLEGAL"); 716 else 717 fprintf(f, "%10ju ", (intmax_t)pp->p_bsize / blksize); 718 719 if ((pp->p_boffset - lp->d_pbase) % lp->d_align) 720 fprintf(f, "%10s ", "ILLEGAL"); 721 else 722 fprintf(f, "%10ju ", 723 (intmax_t)(pp->p_boffset - lp->d_pbase) / blksize); 724 725 if (pp->p_fstype < FSMAXTYPES) 726 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 727 else 728 fprintf(f, "%8d", pp->p_fstype); 729 fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg); 730 fprintf(f, "\n"); 731 } 732 for (part = 0; part < lp->d_npartitions; part++) { 733 pp = &lp->d_partitions[part]; 734 735 if (pp->p_bsize == 0) 736 continue; 737 738 if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) { 739 fprintf(f, " %c-stor_uuid: ", 'a' + part); 740 str = NULL; 741 uuid_to_string(&pp->p_stor_uuid, &str, NULL); 742 if (str) { 743 fprintf(f, "%s", str); 744 free(str); 745 } 746 fprintf(f, "\n"); 747 } 748 } 749 if (didany == 0) { 750 fprintf(f, "# EXAMPLE\n"); 751 fprintf(f, "#a: 4g 0 4.2BSD\n"); 752 fprintf(f, "#a: * * 4.2BSD\n"); 753 754 } 755 fflush(f); 756 } 757 758 int 759 edit(struct disklabel64 *lp, int f) 760 { 761 int c, fd; 762 struct disklabel64 label; 763 FILE *fp; 764 765 if ((fd = mkstemp(tmpfil)) == -1 || 766 (fp = fdopen(fd, "w")) == NULL) { 767 warnx("can't create %s", tmpfil); 768 return (1); 769 } 770 display(fp, lp); 771 fclose(fp); 772 for (;;) { 773 if (!editit()) 774 break; 775 fp = fopen(tmpfil, "r"); 776 if (fp == NULL) { 777 warnx("can't reopen %s for reading", tmpfil); 778 break; 779 } 780 bzero((char *)&label, sizeof(label)); 781 if (getasciilabel(fp, &label)) { 782 *lp = label; 783 if (writelabel(f, lp) == 0) { 784 fclose(fp); 785 unlink(tmpfil); 786 return (0); 787 } 788 } 789 fclose(fp); 790 printf("re-edit the label? [y]: "); fflush(stdout); 791 c = getchar(); 792 if (c != EOF && c != (int)'\n') 793 while (getchar() != (int)'\n') 794 ; 795 if (c == (int)'n') 796 break; 797 } 798 unlink(tmpfil); 799 return (1); 800 } 801 802 int 803 editit(void) 804 { 805 int pid, xpid; 806 int status, omask; 807 const char *ed; 808 809 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 810 while ((pid = fork()) < 0) { 811 if (errno == EPROCLIM) { 812 warnx("you have too many processes"); 813 return(0); 814 } 815 if (errno != EAGAIN) { 816 warn("fork"); 817 return(0); 818 } 819 sleep(1); 820 } 821 if (pid == 0) { 822 sigsetmask(omask); 823 setgid(getgid()); 824 setuid(getuid()); 825 if ((ed = getenv("EDITOR")) == NULL) 826 ed = DEFEDITOR; 827 execlp(ed, ed, tmpfil, NULL); 828 err(1, "%s", ed); 829 } 830 while ((xpid = wait(&status)) >= 0) 831 if (xpid == pid) 832 break; 833 sigsetmask(omask); 834 return(!status); 835 } 836 837 char * 838 skip(char *cp) 839 { 840 841 while (*cp != '\0' && isspace(*cp)) 842 cp++; 843 if (*cp == '\0' || *cp == '#') 844 return (NULL); 845 return (cp); 846 } 847 848 char * 849 word(char *cp) 850 { 851 char c; 852 853 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 854 cp++; 855 if ((c = *cp) != '\0') { 856 *cp++ = '\0'; 857 if (c != '#') 858 return (skip(cp)); 859 } 860 return (NULL); 861 } 862 863 /* 864 * Read an ascii label in from fd f, 865 * in the same format as that put out by display(), 866 * and fill in lp. 867 */ 868 int 869 getasciilabel(FILE *f, struct disklabel64 *lp) 870 { 871 char *cp; 872 u_int part; 873 char *tp, line[BUFSIZ]; 874 u_long v; 875 uint32_t blksize = 0; 876 uint64_t vv; 877 int lineno = 0, errors = 0; 878 char empty[] = ""; 879 880 bzero(&part_set, sizeof(part_set)); 881 bzero(&part_size_type, sizeof(part_size_type)); 882 bzero(&part_offset_type, sizeof(part_offset_type)); 883 while (fgets(line, sizeof(line) - 1, f)) { 884 lineno++; 885 if ((cp = strchr(line,'\n')) != 0) 886 *cp = '\0'; 887 cp = skip(line); 888 if (cp == NULL) 889 continue; 890 tp = strchr(cp, ':'); 891 if (tp == NULL) { 892 fprintf(stderr, "line %d: syntax error\n", lineno); 893 errors++; 894 continue; 895 } 896 *tp++ = '\0', tp = skip(tp); 897 if (sscanf(cp, "%lu partitions", &v) == 1) { 898 if (v == 0 || v > MAXPARTITIONS64) { 899 fprintf(stderr, 900 "line %d: bad # of partitions\n", lineno); 901 lp->d_npartitions = MAXPARTITIONS64; 902 errors++; 903 } else 904 lp->d_npartitions = v; 905 continue; 906 } 907 if (tp == NULL) 908 tp = empty; 909 910 if (streq(cp, "diskid")) { 911 uint32_t status = 0; 912 uuid_from_string(tp, &lp->d_stor_uuid, &status); 913 if (status != uuid_s_ok) { 914 fprintf(stderr, 915 "line %d: %s: illegal UUID\n", 916 lineno, tp); 917 errors++; 918 } 919 continue; 920 } 921 if (streq(cp, "label")) { 922 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 923 continue; 924 } 925 926 if (streq(cp, "alignment")) { 927 v = strtoul(tp, NULL, 0); 928 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 929 fprintf(stderr, 930 "line %d: %s: bad alignment\n", 931 lineno, tp); 932 errors++; 933 } else { 934 lp->d_align = v; 935 } 936 continue; 937 } 938 if (streq(cp, "total size")) { 939 vv = strtoull(tp, NULL, 0); 940 if (vv == 0 || vv == (uint64_t)-1) { 941 fprintf(stderr, "line %d: %s: bad %s\n", 942 lineno, tp, cp); 943 errors++; 944 } else { 945 lp->d_total_size = vv; 946 } 947 continue; 948 } 949 if (streq(cp, "boot2 data base")) { 950 vv = strtoull(tp, NULL, 0); 951 if (vv == 0 || vv == (uint64_t)-1) { 952 fprintf(stderr, "line %d: %s: bad %s\n", 953 lineno, tp, cp); 954 errors++; 955 } else { 956 lp->d_bbase = vv; 957 } 958 continue; 959 } 960 if (streq(cp, "partitions data base")) { 961 vv = strtoull(tp, NULL, 0); 962 if (vv == 0 || vv == (uint64_t)-1) { 963 fprintf(stderr, "line %d: %s: bad %s\n", 964 lineno, tp, cp); 965 errors++; 966 } else { 967 lp->d_pbase = vv; 968 } 969 continue; 970 } 971 if (streq(cp, "partitions data stop")) { 972 vv = strtoull(tp, NULL, 0); 973 if (vv == 0 || vv == (uint64_t)-1) { 974 fprintf(stderr, "line %d: %s: bad %s\n", 975 lineno, tp, cp); 976 errors++; 977 } else { 978 lp->d_pstop = vv; 979 } 980 continue; 981 } 982 if (streq(cp, "backup label")) { 983 vv = strtoull(tp, NULL, 0); 984 if (vv == 0 || vv == (uint64_t)-1) { 985 fprintf(stderr, "line %d: %s: bad %s\n", 986 lineno, tp, cp); 987 errors++; 988 } else { 989 lp->d_abase = vv; 990 } 991 continue; 992 } 993 if (streq(cp, "display block size")) { 994 v = strtoul(tp, NULL, 0); 995 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 996 fprintf(stderr, 997 "line %d: %s: bad alignment\n", 998 lineno, tp); 999 errors++; 1000 } else { 1001 blksize = v; 1002 } 1003 continue; 1004 } 1005 1006 /* the ':' was removed above */ 1007 1008 /* 1009 * Handle main partition data, e.g. a:, b:, etc. 1010 */ 1011 if (*cp < 'a' || *cp > MAX_PART) { 1012 fprintf(stderr, 1013 "line %d: %s: Unknown disklabel field\n", lineno, 1014 cp); 1015 errors++; 1016 continue; 1017 } 1018 1019 /* Process a partition specification line. */ 1020 part = *cp - 'a'; 1021 if (part >= lp->d_npartitions) { 1022 fprintf(stderr, 1023 "line %d: partition name out of range a-%c: %s\n", 1024 lineno, 'a' + lp->d_npartitions - 1, cp); 1025 errors++; 1026 continue; 1027 } 1028 1029 if (blksize == 0) { 1030 fprintf(stderr, "block size to use for partition " 1031 "display was not specified!\n"); 1032 errors++; 1033 continue; 1034 } 1035 1036 if (strcmp(cp + 1, "-stor_uuid") == 0) { 1037 if (getasciipartuuid(tp, lp, part, lineno, blksize)) { 1038 errors++; 1039 break; 1040 } 1041 continue; 1042 } else if (cp[1] == 0) { 1043 part_set[part] = 1; 1044 if (getasciipartspec(tp, lp, part, lineno, blksize)) { 1045 errors++; 1046 break; 1047 } 1048 continue; 1049 } 1050 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1051 lineno, cp); 1052 errors++; 1053 continue; 1054 } 1055 errors += checklabel(lp); 1056 return (errors == 0); 1057 } 1058 1059 static 1060 int 1061 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno) 1062 { 1063 char *tmp; 1064 1065 if (*tp == NULL || **tp == 0) { 1066 fprintf(stderr, "line %d: too few numeric fields\n", lineno); 1067 return(-1); 1068 } 1069 *cp = *tp; 1070 *tp = word(*cp); 1071 *vv = strtoull(*cp, &tmp, 0); 1072 if (*vv == ULLONG_MAX) { 1073 fprintf(stderr, "line %d: illegal number\n", lineno); 1074 return(-1); 1075 } 1076 if (tmp) 1077 return(*tmp); 1078 else 1079 return(0); 1080 } 1081 1082 /* 1083 * Read a partition line into partition `part' in the specified disklabel. 1084 * Return 0 on success, 1 on failure. 1085 */ 1086 int 1087 getasciipartspec(char *tp, struct disklabel64 *lp, int part, 1088 int lineno, uint32_t blksize) 1089 { 1090 struct partition64 *pp; 1091 char *cp; 1092 const char **cpp; 1093 int r; 1094 u_long v; 1095 uint64_t vv; 1096 uint64_t mpx; 1097 1098 pp = &lp->d_partitions[part]; 1099 cp = NULL; 1100 1101 /* 1102 * size 1103 */ 1104 r = parse_field_val(&tp, &cp, &vv, lineno); 1105 if (r < 0) 1106 return (1); 1107 1108 mpx = 1; 1109 switch(r) { 1110 case 0: 1111 mpx = blksize; 1112 break; 1113 case '%': 1114 /* mpx = 1; */ 1115 break; 1116 case '*': 1117 mpx = 0; 1118 break; 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 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