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