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) __dead2; 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 = roundup2(sizeof(struct disklabel64), secsize); 586 boot1size = offsetof(struct disklabel64, d_magic); 587 boot1lsize = rsize; 588 boot1buf = malloc(rsize); 589 bzero(boot1buf, rsize); 590 r = read(f, boot1buf, rsize); 591 if (r != (int)rsize) 592 err(4, "%s", specname); 593 } 594 lp = (void *)boot1buf; 595 596 if (installboot == 0) 597 return(lp); 598 599 if (boot2buf == NULL) { 600 boot2size = 32768; 601 boot2buf = malloc(boot2size); 602 bzero(boot2buf, boot2size); 603 } 604 605 /* 606 * If installing the boot code, read it into the appropriate portions 607 * of the buffer(s) 608 */ 609 if (boot1path == NULL) 610 asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR); 611 if (boot2path == NULL) 612 asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR); 613 614 if ((fd = open(boot1path, O_RDONLY)) < 0) 615 err(4, "%s", boot1path); 616 if (fstat(fd, &st) < 0) 617 err(4, "%s", boot1path); 618 if (st.st_size > boot1size) 619 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 620 if (read(fd, boot1buf, boot1size) != boot1size) 621 err(4, "%s must be exactly %d bytes!", boot1path, boot1size); 622 close(fd); 623 624 if ((fd = open(boot2path, O_RDONLY)) < 0) 625 err(4, "%s", boot2path); 626 if (fstat(fd, &st) < 0) 627 err(4, "%s", boot2path); 628 if (st.st_size > boot2size) 629 err(4, "%s must be <= %d bytes!", boot2path, boot2size); 630 if ((r = read(fd, boot2buf, boot2size)) < 1) 631 err(4, "%s is empty!", boot2path); 632 boot2size = roundup2(r, secsize); 633 close(fd); 634 635 /* 636 * XXX dangerously dedicated support goes here XXX 637 */ 638 return (lp); 639 } 640 641 void 642 display(FILE *f, const struct disklabel64 *lp) 643 { 644 const struct partition64 *pp; 645 char *str; 646 unsigned int part; 647 int didany; 648 uint32_t blksize; 649 650 /* 651 * Use a human readable block size if possible. This is for 652 * display and editing purposes only. 653 */ 654 if (lp->d_align > 1024) 655 blksize = 1024; 656 else 657 blksize = lp->d_align; 658 659 fprintf(f, "# %s:\n", specname); 660 fprintf(f, "#\n"); 661 fprintf(f, "# Informational fields calculated from the above\n"); 662 fprintf(f, "# All byte equivalent offsets must be aligned\n"); 663 fprintf(f, "#\n"); 664 fprintf(f, "# boot space: %10ju bytes\n", 665 (intmax_t)(lp->d_pbase - lp->d_bbase)); 666 fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n", 667 (intmax_t)(lp->d_pstop - lp->d_pbase) / blksize, 668 (double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0, 669 (intmax_t)(lp->d_pstop - lp->d_pbase)); 670 fprintf(f, "#\n"); 671 fprintf(f, "# NOTE: If the partition data base looks odd it may be\n"); 672 fprintf(f, "# physically aligned instead of slice-aligned\n"); 673 fprintf(f, "#\n"); 674 675 uuid_to_string(&lp->d_stor_uuid, &str, NULL); 676 fprintf(f, "diskid: %s\n", str ? str : "<unknown>"); 677 free(str); 678 679 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), 680 lp->d_packname); 681 fprintf(f, "boot2 data base: 0x%012jx\n", (intmax_t)lp->d_bbase); 682 fprintf(f, "partitions data base: 0x%012jx\n", (intmax_t)lp->d_pbase); 683 fprintf(f, "partitions data stop: 0x%012jx\n", (intmax_t)lp->d_pstop); 684 fprintf(f, "backup label: 0x%012jx\n", (intmax_t)lp->d_abase); 685 fprintf(f, "total size: 0x%012jx\t# %6.2f MB\n", 686 (intmax_t)lp->d_total_size, 687 (double)lp->d_total_size / 1024.0 / 1024.0); 688 fprintf(f, "alignment: %u\n", lp->d_align); 689 fprintf(f, "display block size: %u\t# for partition display only\n", 690 blksize); 691 692 fprintf(f, "\n"); 693 fprintf(f, "%u partitions:\n", lp->d_npartitions); 694 fprintf(f, "# size offset fstype fsuuid\n"); 695 didany = 0; 696 for (part = 0; part < lp->d_npartitions; part++) { 697 pp = &lp->d_partitions[part]; 698 const u_long onemeg = 1024 * 1024; 699 700 if (pp->p_bsize == 0) 701 continue; 702 didany = 1; 703 fprintf(f, " %c: ", 'a' + part); 704 705 if (pp->p_bsize % lp->d_align) 706 fprintf(f, "%10s ", "ILLEGAL"); 707 else 708 fprintf(f, "%10ju ", (intmax_t)pp->p_bsize / blksize); 709 710 if ((pp->p_boffset - lp->d_pbase) % lp->d_align) 711 fprintf(f, "%10s ", "ILLEGAL"); 712 else 713 fprintf(f, "%10ju ", 714 (intmax_t)(pp->p_boffset - lp->d_pbase) / blksize); 715 716 if (pp->p_fstype < FSMAXTYPES) 717 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 718 else 719 fprintf(f, "%8d", pp->p_fstype); 720 fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg); 721 fprintf(f, "\n"); 722 } 723 for (part = 0; part < lp->d_npartitions; part++) { 724 pp = &lp->d_partitions[part]; 725 726 if (pp->p_bsize == 0) 727 continue; 728 729 if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) { 730 fprintf(f, " %c-stor_uuid: ", 'a' + part); 731 str = NULL; 732 uuid_to_string(&pp->p_stor_uuid, &str, NULL); 733 if (str) { 734 fprintf(f, "%s", str); 735 free(str); 736 } 737 fprintf(f, "\n"); 738 } 739 } 740 if (didany == 0) { 741 fprintf(f, "# EXAMPLE\n"); 742 fprintf(f, "#a: 4g 0 4.2BSD\n"); 743 fprintf(f, "#a: * * 4.2BSD\n"); 744 745 } 746 fflush(f); 747 } 748 749 int 750 edit(struct disklabel64 *lp, int f) 751 { 752 int c, fd; 753 struct disklabel64 label; 754 FILE *fp; 755 756 if ((fd = mkstemp(tmpfil)) == -1 || 757 (fp = fdopen(fd, "w")) == NULL) { 758 warnx("can't create %s", tmpfil); 759 return (1); 760 } 761 display(fp, lp); 762 fclose(fp); 763 for (;;) { 764 if (!editit()) 765 break; 766 fp = fopen(tmpfil, "r"); 767 if (fp == NULL) { 768 warnx("can't reopen %s for reading", tmpfil); 769 break; 770 } 771 bzero((char *)&label, sizeof(label)); 772 if (getasciilabel(fp, &label)) { 773 *lp = label; 774 if (writelabel(f, lp) == 0) { 775 fclose(fp); 776 unlink(tmpfil); 777 return (0); 778 } 779 } 780 fclose(fp); 781 printf("re-edit the label? [y]: "); fflush(stdout); 782 c = getchar(); 783 if (c != EOF && c != (int)'\n') 784 while (getchar() != (int)'\n') 785 ; 786 if (c == (int)'n') 787 break; 788 } 789 unlink(tmpfil); 790 return (1); 791 } 792 793 int 794 editit(void) 795 { 796 int pid, xpid; 797 int status, omask; 798 const char *ed; 799 800 omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 801 while ((pid = fork()) < 0) { 802 if (errno == EPROCLIM) { 803 warnx("you have too many processes"); 804 return(0); 805 } 806 if (errno != EAGAIN) { 807 warn("fork"); 808 return(0); 809 } 810 sleep(1); 811 } 812 if (pid == 0) { 813 sigsetmask(omask); 814 setgid(getgid()); 815 setuid(getuid()); 816 if ((ed = getenv("EDITOR")) == NULL) 817 ed = DEFEDITOR; 818 execlp(ed, ed, tmpfil, NULL); 819 err(1, "%s", ed); 820 } 821 while ((xpid = wait(&status)) >= 0) 822 if (xpid == pid) 823 break; 824 sigsetmask(omask); 825 return(!status); 826 } 827 828 char * 829 skip(char *cp) 830 { 831 832 while (*cp != '\0' && isspace(*cp)) 833 cp++; 834 if (*cp == '\0' || *cp == '#') 835 return (NULL); 836 return (cp); 837 } 838 839 char * 840 word(char *cp) 841 { 842 char c; 843 844 while (*cp != '\0' && !isspace(*cp) && *cp != '#') 845 cp++; 846 if ((c = *cp) != '\0') { 847 *cp++ = '\0'; 848 if (c != '#') 849 return (skip(cp)); 850 } 851 return (NULL); 852 } 853 854 /* 855 * Read an ascii label in from fd f, 856 * in the same format as that put out by display(), 857 * and fill in lp. 858 */ 859 int 860 getasciilabel(FILE *f, struct disklabel64 *lp) 861 { 862 char *cp; 863 u_int part; 864 char *tp, line[BUFSIZ]; 865 u_long v; 866 uint32_t blksize = 0; 867 uint64_t vv; 868 int lineno = 0, errors = 0; 869 char empty[] = ""; 870 871 bzero(&part_set, sizeof(part_set)); 872 bzero(&part_size_type, sizeof(part_size_type)); 873 bzero(&part_offset_type, sizeof(part_offset_type)); 874 while (fgets(line, sizeof(line) - 1, f)) { 875 lineno++; 876 if ((cp = strchr(line,'\n')) != NULL) 877 *cp = '\0'; 878 cp = skip(line); 879 if (cp == NULL) 880 continue; 881 tp = strchr(cp, ':'); 882 if (tp == NULL) { 883 fprintf(stderr, "line %d: syntax error\n", lineno); 884 errors++; 885 continue; 886 } 887 *tp++ = '\0', tp = skip(tp); 888 if (sscanf(cp, "%lu partitions", &v) == 1) { 889 if (v == 0 || v > MAXPARTITIONS64) { 890 fprintf(stderr, 891 "line %d: bad # of partitions\n", lineno); 892 lp->d_npartitions = MAXPARTITIONS64; 893 errors++; 894 } else 895 lp->d_npartitions = v; 896 continue; 897 } 898 if (tp == NULL) 899 tp = empty; 900 901 if (streq(cp, "diskid")) { 902 uint32_t status = 0; 903 uuid_from_string(tp, &lp->d_stor_uuid, &status); 904 if (status != uuid_s_ok) { 905 fprintf(stderr, 906 "line %d: %s: illegal UUID\n", 907 lineno, tp); 908 errors++; 909 } 910 continue; 911 } 912 if (streq(cp, "label")) { 913 strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 914 continue; 915 } 916 917 if (streq(cp, "alignment")) { 918 v = strtoul(tp, NULL, 0); 919 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 920 fprintf(stderr, 921 "line %d: %s: bad alignment\n", 922 lineno, tp); 923 errors++; 924 } else { 925 lp->d_align = v; 926 } 927 continue; 928 } 929 if (streq(cp, "total size")) { 930 vv = strtoull(tp, NULL, 0); 931 if (vv == 0 || vv == (uint64_t)-1) { 932 fprintf(stderr, "line %d: %s: bad %s\n", 933 lineno, tp, cp); 934 errors++; 935 } else { 936 lp->d_total_size = vv; 937 } 938 continue; 939 } 940 if (streq(cp, "boot2 data base")) { 941 vv = strtoull(tp, NULL, 0); 942 if (vv == 0 || vv == (uint64_t)-1) { 943 fprintf(stderr, "line %d: %s: bad %s\n", 944 lineno, tp, cp); 945 errors++; 946 } else { 947 lp->d_bbase = vv; 948 } 949 continue; 950 } 951 if (streq(cp, "partitions data base")) { 952 vv = strtoull(tp, NULL, 0); 953 if (vv == 0 || vv == (uint64_t)-1) { 954 fprintf(stderr, "line %d: %s: bad %s\n", 955 lineno, tp, cp); 956 errors++; 957 } else { 958 lp->d_pbase = vv; 959 } 960 continue; 961 } 962 if (streq(cp, "partitions data stop")) { 963 vv = strtoull(tp, NULL, 0); 964 if (vv == 0 || vv == (uint64_t)-1) { 965 fprintf(stderr, "line %d: %s: bad %s\n", 966 lineno, tp, cp); 967 errors++; 968 } else { 969 lp->d_pstop = vv; 970 } 971 continue; 972 } 973 if (streq(cp, "backup label")) { 974 vv = strtoull(tp, NULL, 0); 975 if (vv == 0 || vv == (uint64_t)-1) { 976 fprintf(stderr, "line %d: %s: bad %s\n", 977 lineno, tp, cp); 978 errors++; 979 } else { 980 lp->d_abase = vv; 981 } 982 continue; 983 } 984 if (streq(cp, "display block size")) { 985 v = strtoul(tp, NULL, 0); 986 if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) { 987 fprintf(stderr, "line %d: %s: bad %s\n", 988 lineno, tp, cp); 989 errors++; 990 } else { 991 blksize = v; 992 } 993 continue; 994 } 995 996 /* the ':' was removed above */ 997 998 /* 999 * Handle main partition data, e.g. a:, b:, etc. 1000 */ 1001 if (*cp < 'a' || *cp > MAX_PART) { 1002 fprintf(stderr, 1003 "line %d: %s: Unknown disklabel field\n", lineno, 1004 cp); 1005 errors++; 1006 continue; 1007 } 1008 1009 /* Process a partition specification line. */ 1010 part = *cp - 'a'; 1011 if (part >= lp->d_npartitions) { 1012 fprintf(stderr, 1013 "line %d: partition name out of range a-%c: %s\n", 1014 lineno, 'a' + lp->d_npartitions - 1, cp); 1015 errors++; 1016 continue; 1017 } 1018 1019 if (blksize == 0) { 1020 fprintf(stderr, "block size to use for partition " 1021 "display was not specified!\n"); 1022 errors++; 1023 continue; 1024 } 1025 1026 if (strcmp(cp + 1, "-stor_uuid") == 0) { 1027 if (getasciipartuuid(tp, lp, part, lineno, blksize)) { 1028 errors++; 1029 break; 1030 } 1031 continue; 1032 } else if (cp[1] == 0) { 1033 part_set[part] = 1; 1034 if (getasciipartspec(tp, lp, part, lineno, blksize)) { 1035 errors++; 1036 break; 1037 } 1038 continue; 1039 } 1040 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1041 lineno, cp); 1042 errors++; 1043 continue; 1044 } 1045 errors += checklabel(lp); 1046 return (errors == 0); 1047 } 1048 1049 static 1050 int 1051 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno) 1052 { 1053 char *tmp; 1054 1055 if (*tp == NULL || **tp == 0) { 1056 fprintf(stderr, "line %d: too few numeric fields\n", lineno); 1057 return(-1); 1058 } 1059 *cp = *tp; 1060 *tp = word(*cp); 1061 *vv = strtoull(*cp, &tmp, 0); 1062 if (*vv == ULLONG_MAX) { 1063 fprintf(stderr, "line %d: illegal number\n", lineno); 1064 return(-1); 1065 } 1066 if (tmp) 1067 return(*tmp); 1068 else 1069 return(0); 1070 } 1071 1072 /* 1073 * Read a partition line into partition `part' in the specified disklabel. 1074 * Return 0 on success, 1 on failure. 1075 */ 1076 int 1077 getasciipartspec(char *tp, struct disklabel64 *lp, int part, 1078 int lineno, uint32_t blksize) 1079 { 1080 struct partition64 *pp; 1081 char *cp; 1082 const char **cpp; 1083 int r; 1084 u_long v; 1085 uint64_t vv; 1086 uint64_t mpx; 1087 1088 pp = &lp->d_partitions[part]; 1089 cp = NULL; 1090 1091 /* 1092 * size 1093 */ 1094 r = parse_field_val(&tp, &cp, &vv, lineno); 1095 if (r < 0) 1096 return (1); 1097 1098 mpx = 1; 1099 switch(r) { 1100 case 0: 1101 mpx = blksize; 1102 break; 1103 case '%': 1104 /* mpx = 1; */ 1105 break; 1106 case '*': 1107 mpx = 0; 1108 break; 1109 case 't': 1110 case 'T': 1111 mpx *= 1024ULL; 1112 /* fall through */ 1113 case 'g': 1114 case 'G': 1115 mpx *= 1024ULL; 1116 /* fall through */ 1117 case 'm': 1118 case 'M': 1119 mpx *= 1024ULL; 1120 /* fall through */ 1121 case 'k': 1122 case 'K': 1123 mpx *= 1024ULL; 1124 r = 0; /* eat the suffix */ 1125 break; 1126 default: 1127 Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)", 1128 r); 1129 return(1); 1130 } 1131 1132 part_size_type[part] = r; 1133 if (vv == 0 && r != '*') { 1134 fprintf(stderr, 1135 "line %d: %s: bad partition size (0)\n", lineno, cp); 1136 return (1); 1137 } 1138 pp->p_bsize = vv * mpx; 1139 1140 /* 1141 * offset 1142 */ 1143 r = parse_field_val(&tp, &cp, &vv, lineno); 1144 if (r < 0) 1145 return (1); 1146 part_offset_type[part] = r; 1147 switch(r) { 1148 case '*': 1149 pp->p_boffset = 0; 1150 break; 1151 case 0: 1152 pp->p_boffset = vv * blksize + lp->d_pbase; 1153 break; 1154 default: 1155 fprintf(stderr, 1156 "line %d: %s: bad suffix on partition offset (%c)\n", 1157 lineno, cp, r); 1158 return (1); 1159 } 1160 1161 /* 1162 * fstype 1163 */ 1164 if (tp == NULL) { 1165 fprintf(stderr, 1166 "line %d: no filesystem type was specified\n", lineno); 1167 return(1); 1168 } 1169 cp = tp; 1170 tp = word(cp); 1171 for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) { 1172 if (*cpp && strcasecmp(*cpp, cp) == 0) 1173 break; 1174 } 1175 if (*cpp != NULL) { 1176 pp->p_fstype = cpp - fstypenames; 1177 } else { 1178 if (isdigit(*cp)) 1179 v = strtoul(cp, NULL, 0); 1180 else 1181 v = FSMAXTYPES; 1182 if (v >= FSMAXTYPES) { 1183 fprintf(stderr, 1184 "line %d: Warning, unknown filesystem type %s\n", 1185 lineno, cp); 1186 v = FS_UNUSED; 1187 } 1188 pp->p_fstype = v; 1189 } 1190 1191 cp = tp; 1192 if (tp) { 1193 fprintf(stderr, "line %d: Warning, extra data on line\n", 1194 lineno); 1195 } 1196 return(0); 1197 } 1198 1199 int 1200 getasciipartuuid(char *tp, struct disklabel64 *lp, int part, 1201 int lineno, uint32_t blksize __unused) 1202 { 1203 struct partition64 *pp; 1204 uint32_t status; 1205 char *cp; 1206 1207 pp = &lp->d_partitions[part]; 1208 1209 cp = tp; 1210 tp = word(cp); 1211 uuid_from_string(cp, &pp->p_stor_uuid, &status); 1212 if (status != uuid_s_ok) { 1213 fprintf(stderr, "line %d: Illegal storage uuid specification\n", 1214 lineno); 1215 return(1); 1216 } 1217 return(0); 1218 } 1219 1220 /* 1221 * Check disklabel for errors and fill in 1222 * derived fields according to supplied values. 1223 */ 1224 int 1225 checklabel(struct disklabel64 *lp) 1226 { 1227 struct partition64 *pp; 1228 int errors = 0; 1229 char part; 1230 u_int64_t total_size; 1231 u_int64_t current_offset; 1232 u_long total_percent; 1233 int seen_default_offset; 1234 int hog_part; 1235 int i, j; 1236 struct partition64 *pp2; 1237 u_int64_t off; 1238 1239 if (lp->d_align < 512 || 1240 (lp->d_align ^ (lp->d_align - 1)) != lp->d_align * 2 - 1) { 1241 Warning("Illegal alignment specified: %u\n", lp->d_align); 1242 return (1); 1243 } 1244 if (lp->d_npartitions > MAXPARTITIONS64) { 1245 Warning("number of partitions (%u) > MAXPARTITIONS (%d)", 1246 lp->d_npartitions, MAXPARTITIONS64); 1247 return (1); 1248 } 1249 off = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]); 1250 off = (off + lp->d_align - 1) & ~(int64_t)(lp->d_align - 1); 1251 1252 if (lp->d_bbase < off || lp->d_bbase % lp->d_align) { 1253 Warning("illegal boot2 data base "); 1254 return (1); 1255 } 1256 1257 /* 1258 * pbase can be unaligned slice-relative but will be 1259 * aligned physically. 1260 */ 1261 if (lp->d_pbase < lp->d_bbase) { 1262 Warning("illegal partition data base"); 1263 return (1); 1264 } 1265 if (lp->d_pstop < lp->d_pbase) { 1266 Warning("illegal partition data stop"); 1267 return (1); 1268 } 1269 if (lp->d_pstop > lp->d_total_size) { 1270 printf("%012jx\n%012jx\n", 1271 (intmax_t)lp->d_pstop, (intmax_t)lp->d_total_size); 1272 Warning("disklabel control info is beyond the total size"); 1273 return (1); 1274 } 1275 if (lp->d_abase && 1276 (lp->d_abase < lp->d_pstop || 1277 lp->d_abase > lp->d_total_size - off)) { 1278 Warning("illegal backup label location"); 1279 return (1); 1280 } 1281 1282 /* first allocate space to the partitions, then offsets */ 1283 total_size = 0; /* in bytes */ 1284 total_percent = 0; /* in percent */ 1285 hog_part = -1; 1286 /* find all fixed partitions */ 1287 for (i = 0; i < (int)lp->d_npartitions; i++) { 1288 pp = &lp->d_partitions[i]; 1289 if (part_set[i]) { 1290 if (part_size_type[i] == '*') { 1291 if (part_offset_type[i] != '*') { 1292 if (total_size < pp->p_boffset) 1293 total_size = pp->p_boffset; 1294 } 1295 if (hog_part != -1) { 1296 Warning("Too many '*' partitions (%c and %c)", 1297 hog_part + 'a',i + 'a'); 1298 } else { 1299 hog_part = i; 1300 } 1301 } else { 1302 off_t size; 1303 1304 size = pp->p_bsize; 1305 if (part_size_type[i] == '%') { 1306 /* 1307 * don't count %'s yet 1308 */ 1309 total_percent += size; 1310 } else { 1311 /* 1312 * Value has already been converted 1313 * to bytes. 1314 */ 1315 if (size % lp->d_align != 0) { 1316 Warning("partition %c's size is not properly aligned", 1317 i + 'a'); 1318 } 1319 total_size += size; 1320 } 1321 } 1322 } 1323 } 1324 /* handle % partitions - note %'s don't need to add up to 100! */ 1325 if (total_percent != 0) { 1326 int64_t free_space; 1327 int64_t space_left; 1328 1329 free_space = (int64_t)(lp->d_pstop - lp->d_pbase - total_size); 1330 free_space &= ~(u_int64_t)(lp->d_align - 1); 1331 1332 space_left = free_space; 1333 if (total_percent > 100) { 1334 fprintf(stderr,"total percentage %lu is greater than 100\n", 1335 total_percent); 1336 errors++; 1337 } 1338 1339 if (free_space > 0) { 1340 for (i = 0; i < (int)lp->d_npartitions; i++) { 1341 pp = &lp->d_partitions[i]; 1342 if (part_set[i] && part_size_type[i] == '%') { 1343 /* careful of overflows! and integer roundoff */ 1344 pp->p_bsize = ((double)pp->p_bsize/100) * free_space; 1345 pp->p_bsize = (pp->p_bsize + lp->d_align - 1) & ~(u_int64_t)(lp->d_align - 1); 1346 if ((int64_t)pp->p_bsize > space_left) 1347 pp->p_bsize = (u_int64_t)space_left; 1348 total_size += pp->p_bsize; 1349 space_left -= pp->p_bsize; 1350 } 1351 } 1352 } else { 1353 fprintf(stderr, "%jd bytes available to give to " 1354 "'*' and '%%' partitions\n", 1355 (intmax_t)free_space); 1356 errors++; 1357 /* fix? set all % partitions to size 0? */ 1358 } 1359 } 1360 /* give anything remaining to the hog partition */ 1361 if (hog_part != -1) { 1362 off = lp->d_pstop - lp->d_pbase - total_size; 1363 off &= ~(u_int64_t)(lp->d_align - 1); 1364 lp->d_partitions[hog_part].p_bsize = off; 1365 total_size = lp->d_pstop - lp->d_pbase; 1366 } 1367 1368 /* Now set the offsets for each partition */ 1369 current_offset = lp->d_pbase; 1370 seen_default_offset = 0; 1371 for (i = 0; i < (int)lp->d_npartitions; i++) { 1372 part = 'a' + i; 1373 pp = &lp->d_partitions[i]; 1374 if (pp->p_bsize == 0) 1375 continue; 1376 if (part_set[i]) { 1377 if (part_offset_type[i] == '*') { 1378 pp->p_boffset = current_offset; 1379 seen_default_offset = 1; 1380 } else { 1381 /* allow them to be out of order for old-style tables */ 1382 if (pp->p_boffset < current_offset && 1383 seen_default_offset && 1384 pp->p_fstype != FS_VINUM) { 1385 fprintf(stderr, 1386 "Offset 0x%012jx for partition %c overlaps previous partition which ends at 0x%012jx\n", 1387 (intmax_t)pp->p_boffset, 1388 i + 'a', 1389 (intmax_t)current_offset); 1390 fprintf(stderr, 1391 "Labels with any *'s for offset must be in ascending order by sector\n"); 1392 errors++; 1393 } else if (pp->p_boffset != current_offset && 1394 seen_default_offset) { 1395 /* 1396 * this may give unneeded warnings if 1397 * partitions are out-of-order 1398 */ 1399 Warning( 1400 "Offset 0x%012jx for partition %c doesn't match expected value 0x%012jx", 1401 pp->p_boffset, i + 'a', 1402 (intmax_t)current_offset); 1403 } 1404 } 1405 current_offset = pp->p_boffset + pp->p_bsize; 1406 } 1407 } 1408 1409 for (i = 0; i < (int)lp->d_npartitions; i++) { 1410 part = 'a' + i; 1411 pp = &lp->d_partitions[i]; 1412 if (pp->p_bsize == 0 && pp->p_boffset != 0) 1413 Warning("partition %c: size 0, but offset 0x%012jx", 1414 part, (intmax_t)pp->p_boffset); 1415 if (pp->p_bsize == 0) { 1416 pp->p_boffset = 0; 1417 continue; 1418 } 1419 if (uuid_is_nil(&pp->p_stor_uuid, NULL)) 1420 uuid_create(&pp->p_stor_uuid, NULL); 1421 1422 if (pp->p_boffset < lp->d_pbase) { 1423 fprintf(stderr, 1424 "partition %c: offset out of bounds (%jd)\n", 1425 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1426 errors++; 1427 } 1428 if (pp->p_boffset > lp->d_pstop) { 1429 fprintf(stderr, 1430 "partition %c: offset out of bounds (%jd)\n", 1431 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1432 errors++; 1433 } 1434 if (pp->p_boffset + pp->p_bsize > lp->d_pstop) { 1435 fprintf(stderr, 1436 "partition %c: size out of bounds (%jd)\n", 1437 part, (intmax_t)(pp->p_boffset - lp->d_pbase)); 1438 errors++; 1439 } 1440 1441 /* check for overlaps */ 1442 /* this will check for all possible overlaps once and only once */ 1443 for (j = 0; j < i; j++) { 1444 pp2 = &lp->d_partitions[j]; 1445 if (pp->p_fstype != FS_VINUM && 1446 pp2->p_fstype != FS_VINUM && 1447 part_set[i] && part_set[j]) { 1448 if (pp2->p_boffset < pp->p_boffset + pp->p_bsize && 1449 (pp2->p_boffset + pp2->p_bsize > pp->p_boffset || 1450 pp2->p_boffset >= pp->p_boffset)) { 1451 fprintf(stderr,"partitions %c and %c overlap!\n", 1452 j + 'a', i + 'a'); 1453 errors++; 1454 } 1455 } 1456 } 1457 } 1458 for (; i < (int)lp->d_npartitions; i++) { 1459 part = 'a' + i; 1460 pp = &lp->d_partitions[i]; 1461 if (pp->p_bsize || pp->p_boffset) 1462 Warning("unused partition %c: size 0x%012jx " 1463 "offset 0x%012jx", 1464 'a' + i, (intmax_t)pp->p_bsize, 1465 (intmax_t)pp->p_boffset); 1466 } 1467 return (errors); 1468 } 1469 1470 /* 1471 * When operating on a "virgin" disk, try getting an initial label 1472 * from the associated device driver. This might work for all device 1473 * drivers that are able to fetch some initial device parameters 1474 * without even having access to a (BSD) disklabel, like SCSI disks, 1475 * most IDE drives, or vn devices. 1476 * 1477 * The device name must be given in its "canonical" form. 1478 */ 1479 static struct disklabel64 dlab; 1480 1481 struct disklabel64 * 1482 getvirginlabel(void) 1483 { 1484 struct disklabel64 *dl = &dlab; 1485 int f; 1486 1487 if ((f = open(dkname, O_RDONLY)) == -1) { 1488 warn("cannot open %s", dkname); 1489 return (NULL); 1490 } 1491 1492 /* 1493 * Try to use the new get-virgin-label ioctl. If it fails, 1494 * fallback to the old get-disk-info ioctl. 1495 */ 1496 if (ioctl(f, DIOCGDVIRGIN64, dl) < 0) { 1497 l_perror("ioctl DIOCGDVIRGIN64"); 1498 close(f); 1499 return (NULL); 1500 } 1501 close(f); 1502 return (dl); 1503 } 1504 1505 /*VARARGS1*/ 1506 void 1507 Warning(const char *fmt, ...) 1508 { 1509 va_list ap; 1510 1511 fprintf(stderr, "Warning, "); 1512 va_start(ap, fmt); 1513 vfprintf(stderr, fmt, ap); 1514 fprintf(stderr, "\n"); 1515 va_end(ap); 1516 } 1517 1518 void 1519 usage(void) 1520 { 1521 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", 1522 "usage: disklabel64 [-r] disk", 1523 "\t\t(to read label)", 1524 " disklabel64 -w [-r] [-n] disk type [packid]", 1525 "\t\t(to write label with existing boot program)", 1526 " disklabel64 -e [-r] [-n] disk", 1527 "\t\t(to edit label)", 1528 " disklabel64 -R [-r] [-n] disk protofile", 1529 "\t\t(to restore label with existing boot program)", 1530 " disklabel64 -B [-n] [-b boot1 -s boot2] disk [type]", 1531 "\t\t(to install boot program with existing label)", 1532 " disklabel64 -w -B [-n] [-b boot1 -s boot2] disk type [packid]", 1533 "\t\t(to write label and boot program)", 1534 " disklabel64 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]", 1535 "\t\t(to restore label and boot program)", 1536 " disklabel64 [-NW] disk", 1537 "\t\t(to write disable/enable label)"); 1538 exit(1); 1539 } 1540