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