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