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