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