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 = 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, 988 "line %d: %s: bad alignment\n", 989 lineno, tp); 990 errors++; 991 } else { 992 blksize = v; 993 } 994 continue; 995 } 996 997 /* the ':' was removed above */ 998 999 /* 1000 * Handle main partition data, e.g. a:, b:, etc. 1001 */ 1002 if (*cp < 'a' || *cp > MAX_PART) { 1003 fprintf(stderr, 1004 "line %d: %s: Unknown disklabel field\n", lineno, 1005 cp); 1006 errors++; 1007 continue; 1008 } 1009 1010 /* Process a partition specification line. */ 1011 part = *cp - 'a'; 1012 if (part >= lp->d_npartitions) { 1013 fprintf(stderr, 1014 "line %d: partition name out of range a-%c: %s\n", 1015 lineno, 'a' + lp->d_npartitions - 1, cp); 1016 errors++; 1017 continue; 1018 } 1019 1020 if (blksize == 0) { 1021 fprintf(stderr, "block size to use for partition " 1022 "display was not specified!\n"); 1023 errors++; 1024 continue; 1025 } 1026 1027 if (strcmp(cp + 1, "-stor_uuid") == 0) { 1028 if (getasciipartuuid(tp, lp, part, lineno, blksize)) { 1029 errors++; 1030 break; 1031 } 1032 continue; 1033 } else if (cp[1] == 0) { 1034 part_set[part] = 1; 1035 if (getasciipartspec(tp, lp, part, lineno, blksize)) { 1036 errors++; 1037 break; 1038 } 1039 continue; 1040 } 1041 fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 1042 lineno, cp); 1043 errors++; 1044 continue; 1045 } 1046 errors += checklabel(lp); 1047 return (errors == 0); 1048 } 1049 1050 static 1051 int 1052 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno) 1053 { 1054 char *tmp; 1055 1056 if (*tp == NULL || **tp == 0) { 1057 fprintf(stderr, "line %d: too few numeric fields\n", lineno); 1058 return(-1); 1059 } 1060 *cp = *tp; 1061 *tp = word(*cp); 1062 *vv = strtoull(*cp, &tmp, 0); 1063 if (*vv == ULLONG_MAX) { 1064 fprintf(stderr, "line %d: illegal number\n", lineno); 1065 return(-1); 1066 } 1067 if (tmp) 1068 return(*tmp); 1069 else 1070 return(0); 1071 } 1072 1073 /* 1074 * Read a partition line into partition `part' in the specified disklabel. 1075 * Return 0 on success, 1 on failure. 1076 */ 1077 int 1078 getasciipartspec(char *tp, struct disklabel64 *lp, int part, 1079 int lineno, uint32_t blksize) 1080 { 1081 struct partition64 *pp; 1082 char *cp; 1083 const char **cpp; 1084 int r; 1085 u_long v; 1086 uint64_t vv; 1087 uint64_t mpx; 1088 1089 pp = &lp->d_partitions[part]; 1090 cp = NULL; 1091 1092 /* 1093 * size 1094 */ 1095 r = parse_field_val(&tp, &cp, &vv, lineno); 1096 if (r < 0) 1097 return (1); 1098 1099 mpx = 1; 1100 switch(r) { 1101 case 0: 1102 mpx = blksize; 1103 break; 1104 case '%': 1105 /* mpx = 1; */ 1106 break; 1107 case '*': 1108 mpx = 0; 1109 break; 1110 case 't': 1111 case 'T': 1112 mpx *= 1024ULL; 1113 /* fall through */ 1114 case 'g': 1115 case 'G': 1116 mpx *= 1024ULL; 1117 /* fall through */ 1118 case 'm': 1119 case 'M': 1120 mpx *= 1024ULL; 1121 /* fall through */ 1122 case 'k': 1123 case 'K': 1124 mpx *= 1024ULL; 1125 r = 0; /* eat the suffix */ 1126 break; 1127 default: 1128 Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)", 1129 r); 1130 return(1); 1131 } 1132 1133 part_size_type[part] = r; 1134 if (vv == 0 && r != '*') { 1135 fprintf(stderr, 1136 "line %d: %s: bad partition size (0)\n", lineno, cp); 1137 return (1); 1138 } 1139 pp->p_bsize = vv * mpx; 1140 1141 /* 1142 * offset 1143 */ 1144 r = parse_field_val(&tp, &cp, &vv, lineno); 1145 if (r < 0) 1146 return (1); 1147 part_offset_type[part] = r; 1148 switch(r) { 1149 case '*': 1150 pp->p_boffset = 0; 1151 break; 1152 case 0: 1153 pp->p_boffset = vv * blksize + lp->d_pbase; 1154 break; 1155 default: 1156 fprintf(stderr, 1157 "line %d: %s: bad suffix on partition offset (%c)\n", 1158 lineno, cp, r); 1159 return (1); 1160 } 1161 1162 /* 1163 * fstype 1164 */ 1165 if (tp == NULL) { 1166 fprintf(stderr, 1167 "line %d: no filesystem type was specified\n", lineno); 1168 return(1); 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