1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * 27 * Portions of this source code were provided by International 28 * Computers Limited (ICL) under a development agreement with AT&T. 29 */ 30 31 /* 32 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 33 * Use is subject to license terms. 34 */ 35 36 /* 37 * Copyright (c) 2018, Joyent, Inc. 38 */ 39 /* 40 * Sun Microsystems version of fmthard: 41 * 42 * Supports the following arguments: 43 * 44 * -i Writes VTOC to stdout, rather than disk 45 * -q Quick check: exit code 0 if VTOC ok 46 * -d <data> Incremental changes to the VTOC 47 * -n <vname> Change volume name to <vname> 48 * -s <file> Read VTOC information from <file>, or stdin ("-") 49 * -u <state> Reboot after writing VTOC, according to <state>: 50 * boot: AD_BOOT (standard reboot) 51 * firm: AD_IBOOT (interactive reboot) 52 * 53 * Note that fmthard cannot write a VTOC on an unlabeled disk. 54 * You must use format or SunInstall for this purpose. 55 * (NOTE: the above restriction only applies on Sparc systems). 56 * 57 * The primary motivation for fmthard is to duplicate the 58 * partitioning from disk to disk: 59 * 60 * prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2 61 */ 62 63 #include <stdio.h> 64 #include <fcntl.h> 65 #include <errno.h> 66 #include <string.h> 67 #include <stdlib.h> 68 #include <unistd.h> 69 #include <sys/types.h> 70 #include <sys/param.h> 71 #include <sys/int_limits.h> 72 #include <sys/stat.h> 73 #include <sys/uadmin.h> 74 #include <sys/open.h> 75 #include <sys/vtoc.h> 76 #include <sys/dkio.h> 77 #include <sys/isa_defs.h> 78 #include <sys/efi_partition.h> 79 80 #if defined(_SUNOS_VTOC_16) 81 #include <sys/dklabel.h> 82 #endif 83 84 #include <sys/sysmacros.h> 85 86 #ifndef SECSIZE 87 #define SECSIZE DEV_BSIZE 88 #endif /* SECSIZE */ 89 90 /* 91 * Internal functions. 92 */ 93 extern int main(int, char **); 94 static void display(struct dk_geom *, struct extvtoc *, char *); 95 static void display64(struct dk_gpt *, char *); 96 static void insert(char *, struct extvtoc *); 97 static void insert64(char *, struct dk_gpt *); 98 static void load(FILE *, struct dk_geom *, struct extvtoc *); 99 static void load64(FILE *, int fd, struct dk_gpt **); 100 static void usage(void); 101 static void validate(struct dk_geom *, struct extvtoc *); 102 static void validate64(struct dk_gpt *); 103 static int vread(int, struct extvtoc *, char *); 104 static void vread64(int, struct dk_gpt **, char *); 105 static void vwrite(int, struct extvtoc *, char *); 106 static void vwrite64(int, struct dk_gpt *, char *); 107 108 /* 109 * Static variables. 110 */ 111 static char *delta; /* Incremental update */ 112 static short eflag; /* force write of an EFI label */ 113 static short iflag; /* Prints VTOC w/o updating */ 114 static short qflag; /* Check for a formatted disk */ 115 static short uflag; /* Exit to firmware after writing */ 116 /* new vtoc and reboot. Used during */ 117 /* installation of core floppies */ 118 static diskaddr_t lastlba = 0; /* last LBA on 64-bit VTOC */ 119 120 #if defined(sparc) 121 static char *uboot = "boot"; 122 123 #elif defined(i386) 124 /* use installboot(1M) to install boot blocks */ 125 static char *uboot = ""; 126 #else 127 #error No platform defined. 128 #endif /* various platform-specific definitions */ 129 130 static char *ufirm = "firm"; 131 static int sectsiz; 132 #if defined(_SUNOS_VTOC_16) 133 static struct extvtoc disk_vtoc; 134 #endif /* defined(_SUNOS_VTOC_16) */ 135 136 int 137 main(int argc, char **argv) 138 { 139 int fd; 140 int c; 141 char *dfile; 142 char *vname; 143 struct stat statbuf; 144 #if defined(_SUNOS_VTOC_8) 145 struct extvtoc disk_vtoc; 146 #endif /* defined(_SUNOS_VTOC_8) */ 147 struct dk_gpt *disk_efi; 148 struct dk_geom disk_geom; 149 struct dk_minfo minfo; 150 int n; 151 152 153 disk_efi = NULL; 154 dfile = NULL; 155 vname = NULL; 156 #if defined(sparc) 157 while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF) 158 159 #elif defined(i386) 160 while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF) 161 162 #else 163 #error No platform defined. 164 #endif 165 switch (c) { 166 #if defined(i386) 167 case 'p': 168 case 'b': 169 (void) fprintf(stderr, 170 "fmthard: -p and -b no longer supported." 171 " Use installboot(1M) to install boot blocks\n"); 172 break; 173 #endif /* defined(i386) */ 174 175 case 'd': 176 delta = optarg; 177 break; 178 case 'e': 179 ++eflag; 180 break; 181 case 'i': 182 ++iflag; 183 break; 184 case 'n': 185 vname = optarg; 186 break; 187 case 'q': 188 ++qflag; 189 break; 190 case 's': 191 dfile = optarg; 192 break; 193 case 'u': 194 if (strcmp(uboot, optarg) == 0) 195 ++uflag; 196 else if (strcmp(ufirm, optarg) == 0) 197 uflag = 2; 198 199 break; 200 default: 201 usage(); 202 } 203 204 205 if (argc - optind != 1) 206 usage(); 207 208 if (stat(argv[optind], (struct stat *)&statbuf) == -1) { 209 (void) fprintf(stderr, 210 "fmthard: Cannot stat device %s\n", 211 argv[optind]); 212 exit(1); 213 } 214 215 if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 216 (void) fprintf(stderr, 217 "fmthard: %s must be a raw device.\n", 218 argv[optind]); 219 exit(1); 220 } 221 222 if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) { 223 (void) fprintf(stderr, "fmthard: Cannot open device %s - %s\n", 224 argv[optind], strerror(errno)); 225 exit(1); 226 } 227 228 if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == 0) { 229 sectsiz = minfo.dki_lbsize; 230 } 231 232 if (sectsiz == 0) { 233 sectsiz = SECSIZE; 234 } 235 236 /* 237 * Get the geometry information for this disk from the driver 238 */ 239 if (!eflag && ioctl(fd, DKIOCGGEOM, &disk_geom)) { 240 #ifdef DEBUG 241 perror("DKIOCGGEOM failed"); 242 #endif /* DEBUG */ 243 if (errno == ENOTSUP) { 244 /* disk has EFI labels */ 245 eflag++; 246 } else { 247 (void) fprintf(stderr, 248 "%s: Cannot get disk geometry\n", argv[optind]); 249 (void) close(fd); 250 exit(1); 251 } 252 } 253 254 /* 255 * Read the vtoc on the disk 256 */ 257 if (!eflag) { 258 if (vread(fd, &disk_vtoc, argv[optind]) == 1) 259 eflag++; 260 } 261 if (eflag && ((dfile == NULL) || qflag)) { 262 vread64(fd, &disk_efi, argv[optind]); 263 } 264 265 /* 266 * Quick check for valid disk: 0 if ok, 1 if not 267 */ 268 if (qflag) { 269 (void) close(fd); 270 if (!eflag) { 271 exit(disk_vtoc.v_sanity == VTOC_SANE ? 0 : 1); 272 } else { 273 exit(disk_efi->efi_version <= EFI_VERSION102 ? 0 : 1); 274 } 275 } 276 277 /* 278 * Incremental changes to the VTOC 279 */ 280 if (delta) { 281 if (!eflag) { 282 insert(delta, &disk_vtoc); 283 validate(&disk_geom, &disk_vtoc); 284 vwrite(fd, &disk_vtoc, argv[optind]); 285 } else { 286 insert64(delta, disk_efi); 287 validate64(disk_efi); 288 vwrite64(fd, disk_efi, argv[optind]); 289 } 290 (void) close(fd); 291 exit(0); 292 } 293 294 if (!dfile && !vname) 295 usage(); 296 297 /* 298 * Read new VTOC from stdin or data file 299 */ 300 if (dfile) { 301 if (strcmp(dfile, "-") == 0) { 302 if (!eflag) 303 load(stdin, &disk_geom, &disk_vtoc); 304 else 305 load64(stdin, fd, &disk_efi); 306 } else { 307 FILE *fp; 308 if ((fp = fopen(dfile, "r")) == NULL) { 309 (void) fprintf(stderr, "Cannot open file %s\n", 310 dfile); 311 (void) close(fd); 312 exit(1); 313 } 314 if (!eflag) 315 load(fp, &disk_geom, &disk_vtoc); 316 else 317 load64(fp, fd, &disk_efi); 318 (void) fclose(fp); 319 } 320 } 321 322 /* 323 * Print the modified VTOC, rather than updating the disk 324 */ 325 if (iflag) { 326 if (!eflag) 327 display(&disk_geom, &disk_vtoc, argv[optind]); 328 else 329 display64(disk_efi, argv[optind]); 330 (void) close(fd); 331 exit(0); 332 } 333 334 if (vname) { 335 n = MIN(strlen(vname) + 1, LEN_DKL_VVOL); 336 if (!eflag) { 337 (void) memcpy(disk_vtoc.v_volume, vname, n); 338 } else { 339 for (c = 0; c < disk_efi->efi_nparts; c++) { 340 if (disk_efi->efi_parts[c].p_tag == 341 V_RESERVED) { 342 (void) memcpy(&disk_efi->efi_parts[c].p_name, 343 vname, n); 344 } 345 } 346 } 347 348 } 349 /* 350 * Write the new VTOC on the disk 351 */ 352 if (!eflag) { 353 validate(&disk_geom, &disk_vtoc); 354 vwrite(fd, &disk_vtoc, argv[optind]); 355 } else { 356 validate64(disk_efi); 357 vwrite64(fd, disk_efi, argv[optind]); 358 } 359 360 /* 361 * Shut system down after writing a new vtoc to disk 362 * This is used during installation of core floppies. 363 */ 364 if (uflag == 1) 365 (void) uadmin(A_REBOOT, AD_BOOT, 0); 366 else if (uflag == 2) 367 (void) uadmin(A_REBOOT, AD_IBOOT, 0); 368 369 (void) printf("fmthard: New volume table of contents now in place.\n"); 370 371 return (0); 372 } 373 374 375 376 /* 377 * display () 378 * 379 * display contents of VTOC without writing it to disk 380 */ 381 static void 382 display(struct dk_geom *geom, struct extvtoc *vtoc, char *device) 383 { 384 int i; 385 int c; 386 387 /* 388 * Print out the VTOC 389 */ 390 (void) printf("* %s default partition map\n", device); 391 if (*vtoc->v_volume) { 392 (void) printf("* Volume Name: "); 393 for (i = 0; i < LEN_DKL_VVOL; i++) { 394 if ((c = vtoc->v_volume[i]) == 0) 395 break; 396 (void) printf("%c", c); 397 } 398 (void) printf("\n"); 399 } 400 (void) printf("*\n"); 401 (void) printf("* Dimensions:\n"); 402 (void) printf("* %d bytes/sector\n", sectsiz); 403 (void) printf("* %d sectors/track\n", geom->dkg_nsect); 404 (void) printf("* %d tracks/cylinder\n", geom->dkg_nhead); 405 (void) printf("* %d cylinders\n", geom->dkg_pcyl); 406 (void) printf("* %d accessible cylinders\n", geom->dkg_ncyl); 407 (void) printf("*\n"); 408 (void) printf("* Flags:\n"); 409 (void) printf("* 1: unmountable\n"); 410 (void) printf("* 10: read-only\n"); 411 (void) printf("*\n"); 412 (void) printf( 413 "\n* Partition Tag Flag First Sector Sector Count\n"); 414 for (i = 0; i < V_NUMPAR; i++) { 415 if (vtoc->v_part[i].p_size > 0) 416 (void) printf( 417 " %d %d 0%x %llu %llu\n", 418 i, vtoc->v_part[i].p_tag, 419 vtoc->v_part[i].p_flag, 420 vtoc->v_part[i].p_start, 421 vtoc->v_part[i].p_size); 422 } 423 exit(0); 424 } 425 426 /* 427 * display64 () 428 * 429 * display64 contents of EFI partition without writing it to disk 430 */ 431 static void 432 display64(struct dk_gpt *efi, char *device) 433 { 434 int i; 435 436 /* 437 * Print out the VTOC 438 */ 439 (void) printf("* %s default partition map\n", device); 440 (void) printf("*\n"); 441 (void) printf("* Dimensions:\n"); 442 (void) printf("* %d bytes/sector\n", efi->efi_lbasize); 443 (void) printf("* N/A sectors/track\n"); 444 (void) printf("* N/A tracks/cylinder\n"); 445 (void) printf("* N/A cylinders\n"); 446 (void) printf("* N/A accessible cylinders\n"); 447 (void) printf("*\n"); 448 (void) printf("* Flags:\n"); 449 (void) printf("* 1: unmountable\n"); 450 (void) printf("* 10: read-only\n"); 451 (void) printf("*\n"); 452 (void) printf( 453 "\n* Partition Tag Flag First Sector Sector Count\n"); 454 for (i = 0; i < efi->efi_nparts; i++) { 455 if (efi->efi_parts[i].p_size > 0) 456 (void) printf( 457 " %d %d 0%x %8lld %8lld\n", 458 i, efi->efi_parts[i].p_tag, 459 efi->efi_parts[i].p_flag, 460 efi->efi_parts[i].p_start, 461 efi->efi_parts[i].p_size); 462 } 463 exit(0); 464 } 465 466 467 /* 468 * insert() 469 * 470 * Insert a change into the VTOC. 471 */ 472 static void 473 insert(char *data, struct extvtoc *vtoc) 474 { 475 int part; 476 int tag; 477 uint_t flag; 478 diskaddr_t start; 479 uint64_t size; 480 481 if (sscanf(data, "%d:%d:%x:%llu:%llu", 482 &part, &tag, &flag, &start, &size) != 5) { 483 (void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data); 484 exit(1); 485 } 486 if (part >= V_NUMPAR) { 487 (void) fprintf(stderr, 488 "Error in data \"%s\": No such partition %x\n", 489 data, part); 490 exit(1); 491 } 492 vtoc->v_part[part].p_tag = (ushort_t)tag; 493 vtoc->v_part[part].p_flag = (ushort_t)flag; 494 vtoc->v_part[part].p_start = start; 495 vtoc->v_part[part].p_size = size; 496 } 497 498 /* 499 * insert64() 500 * 501 * Insert a change into the VTOC. 502 */ 503 static void 504 insert64(char *data, struct dk_gpt *efi) 505 { 506 int part; 507 int tag; 508 uint_t flag; 509 diskaddr_t start; 510 diskaddr_t size; 511 512 if (sscanf(data, "%d:%d:%x:%lld:%lld", 513 &part, &tag, &flag, &start, &size) != 5) { 514 (void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data); 515 exit(1); 516 } 517 if (part >= efi->efi_nparts) { 518 (void) fprintf(stderr, 519 "Error in data \"%s\": No such partition %x\n", 520 data, part); 521 exit(1); 522 } 523 efi->efi_parts[part].p_tag = (ushort_t)tag; 524 efi->efi_parts[part].p_flag = (ushort_t)flag; 525 efi->efi_parts[part].p_start = start; 526 efi->efi_parts[part].p_size = size; 527 } 528 529 /* 530 * load() 531 * 532 * Load VTOC information from a datafile. 533 */ 534 static void 535 load(FILE *fp, struct dk_geom *geom, struct extvtoc *vtoc) 536 { 537 int part; 538 int tag; 539 uint_t flag; 540 diskaddr_t start; 541 uint64_t size; 542 char line[256]; 543 int i; 544 uint64_t nblks; 545 uint64_t fullsz; 546 547 for (i = 0; i < V_NUMPAR; ++i) { 548 vtoc->v_part[i].p_tag = 0; 549 vtoc->v_part[i].p_flag = V_UNMNT; 550 vtoc->v_part[i].p_start = 0; 551 vtoc->v_part[i].p_size = 0; 552 } 553 /* 554 * initialize partition 2, by convention it corresponds to whole 555 * disk. It will be overwritten, if specified in the input datafile 556 */ 557 fullsz = (uint64_t)geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead; 558 vtoc->v_part[2].p_tag = V_BACKUP; 559 vtoc->v_part[2].p_flag = V_UNMNT; 560 vtoc->v_part[2].p_start = 0; 561 vtoc->v_part[2].p_size = fullsz; 562 563 nblks = geom->dkg_nsect * geom->dkg_nhead; 564 565 while (fgets(line, sizeof (line) - 1, fp)) { 566 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*') 567 continue; 568 line[strlen(line) - 1] = '\0'; 569 if (sscanf(line, "%d %d %x %llu %llu", 570 &part, &tag, &flag, &start, &size) != 5) { 571 (void) fprintf(stderr, "Syntax error: \"%s\"\n", 572 line); 573 exit(1); 574 } 575 if (part >= V_NUMPAR) { 576 (void) fprintf(stderr, 577 "No such partition %x: \"%s\"\n", 578 part, line); 579 exit(1); 580 } 581 if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) { 582 (void) fprintf(stderr, 583 "Partition %d not aligned on cylinder boundary: \"%s\"\n", 584 part, line); 585 exit(1); 586 } 587 vtoc->v_part[part].p_tag = (ushort_t)tag; 588 vtoc->v_part[part].p_flag = (ushort_t)flag; 589 vtoc->v_part[part].p_start = start; 590 vtoc->v_part[part].p_size = size; 591 } 592 for (part = 0; part < V_NUMPAR; part++) { 593 vtoc->timestamp[part] = (time_t)0; 594 } 595 } 596 597 /* 598 * load64() 599 * 600 * Load VTOC information from a datafile. 601 */ 602 static void 603 load64(FILE *fp, int fd, struct dk_gpt **efi) 604 { 605 int part; 606 int tag; 607 uint_t flag; 608 diskaddr_t start; 609 diskaddr_t size; 610 int nlines = 0; 611 char line[256]; 612 int i; 613 uint_t max_part = 0; 614 char **mem = NULL; 615 616 while (fgets(line, sizeof (line) - 1, fp)) { 617 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*') 618 continue; 619 line[strlen(line) - 1] = '\0'; 620 if (sscanf(line, "%d %d %x %lld %lld", 621 &part, &tag, &flag, &start, &size) != 5) { 622 (void) fprintf(stderr, "Syntax error: \"%s\"\n", 623 line); 624 exit(1); 625 } 626 mem = realloc(mem, sizeof (*mem) * (nlines + 1)); 627 if (mem == NULL) { 628 (void) fprintf(stderr, "realloc failed\n"); 629 exit(1); 630 } 631 mem[nlines] = strdup(line); 632 if (mem[nlines] == NULL) { 633 (void) fprintf(stderr, "strdup failed\n"); 634 exit(1); 635 } 636 nlines++; 637 if (part > max_part) 638 max_part = part; 639 } 640 max_part++; 641 642 if ((i = efi_alloc_and_init(fd, max_part, efi)) < 0) { 643 (void) fprintf(stderr, 644 "efi_alloc_and_init failed: %d\n", i); 645 exit(1); 646 } 647 for (i = 0; i < (*efi)->efi_nparts; ++i) { 648 (*efi)->efi_parts[i].p_tag = V_UNASSIGNED; 649 (*efi)->efi_parts[i].p_flag = V_UNMNT; 650 (*efi)->efi_parts[i].p_start = 0; 651 (*efi)->efi_parts[i].p_size = 0; 652 } 653 lastlba = (*efi)->efi_last_u_lba; 654 655 for (i = 0; i < nlines; i++) { 656 if (sscanf(mem[i], "%d %d %x %lld %lld", 657 &part, &tag, &flag, &start, &size) != 5) { 658 (void) fprintf(stderr, "Syntax error: \"%s\"\n", 659 line); 660 exit(1); 661 } 662 free(mem[i]); 663 if (part >= (*efi)->efi_nparts) { 664 (void) fprintf(stderr, 665 "No such partition %x: \"%s\"\n", 666 part, line); 667 exit(1); 668 } 669 (*efi)->efi_parts[part].p_tag = (ushort_t)tag; 670 (*efi)->efi_parts[part].p_flag = (ushort_t)flag; 671 (*efi)->efi_parts[part].p_start = start; 672 (*efi)->efi_parts[part].p_size = size; 673 } 674 (*efi)->efi_nparts = max_part; 675 free(mem); 676 } 677 678 679 static void 680 usage() 681 { 682 #if defined(sparc) 683 (void) fprintf(stderr, 684 "Usage: fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \ 685 raw-device\n"); 686 687 #elif defined(i386) 688 (void) fprintf(stderr, 689 "Usage: fmthard [ -i ] [ -S ] [-I geom_file] \ 690 -n volumename | -s datafile [ -d arguments] raw-device\n"); 691 692 #else 693 #error No platform defined. 694 #endif 695 exit(2); 696 } 697 698 /* 699 * validate() 700 * 701 * Validate the new VTOC. 702 */ 703 static void 704 validate(struct dk_geom *geom, struct extvtoc *vtoc) 705 { 706 int i; 707 int j; 708 uint64_t fullsz; 709 diskaddr_t endsect; 710 diskaddr_t istart; 711 diskaddr_t jstart; 712 uint64_t isize; 713 uint64_t jsize; 714 uint64_t nblks; 715 716 nblks = geom->dkg_nsect * geom->dkg_nhead; 717 718 fullsz = (uint64_t)geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead; 719 720 #if defined(_SUNOS_VTOC_16) 721 /* make the vtoc look sane - ha ha */ 722 vtoc->v_version = V_VERSION; 723 vtoc->v_sanity = VTOC_SANE; 724 vtoc->v_nparts = V_NUMPAR; 725 if (vtoc->v_sectorsz == 0) 726 vtoc->v_sectorsz = sectsiz; 727 #endif /* defined(_SUNOS_VTOC_16) */ 728 729 for (i = 0; i < V_NUMPAR; i++) { 730 if (vtoc->v_part[i].p_tag == V_BACKUP) { 731 if (vtoc->v_part[i].p_size != fullsz) { 732 (void) fprintf(stderr, "\ 733 fmthard: Partition %d specifies the full disk and is not equal\n\ 734 full size of disk. The full disk capacity is %llu sectors.\n", i, fullsz); 735 #if defined(sparc) 736 exit(1); 737 #endif 738 } 739 } 740 if (vtoc->v_part[i].p_size == 0) 741 continue; /* Undefined partition */ 742 if ((vtoc->v_part[i].p_start % nblks) || 743 (vtoc->v_part[i].p_size % nblks)) { 744 (void) fprintf(stderr, "\ 745 fmthard: Partition %d not aligned on cylinder boundary \n", i); 746 exit(1); 747 } 748 if (vtoc->v_part[i].p_start > fullsz || 749 vtoc->v_part[i].p_start + 750 vtoc->v_part[i].p_size > fullsz) { 751 (void) fprintf(stderr, "\ 752 fmthard: Partition %d specified as %llu sectors starting at %llu\n\ 753 \tdoes not fit. The full disk contains %llu sectors.\n", 754 i, vtoc->v_part[i].p_size, 755 vtoc->v_part[i].p_start, fullsz); 756 #if defined(sparc) 757 exit(1); 758 #endif 759 } 760 761 if (vtoc->v_part[i].p_tag != V_BACKUP && 762 vtoc->v_part[i].p_size != fullsz) { 763 for (j = 0; j < V_NUMPAR; j++) { 764 if (vtoc->v_part[j].p_tag == V_BACKUP) 765 continue; 766 if (vtoc->v_part[j].p_size == fullsz) 767 continue; 768 isize = vtoc->v_part[i].p_size; 769 jsize = vtoc->v_part[j].p_size; 770 istart = vtoc->v_part[i].p_start; 771 jstart = vtoc->v_part[j].p_start; 772 if ((i != j) && 773 (isize != 0) && (jsize != 0)) { 774 endsect = jstart + jsize -1; 775 if ((jstart <= istart) && 776 (istart <= endsect)) { 777 (void) fprintf(stderr, "\ 778 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\ 779 \tonly on partition on the full disk partition).\n", 780 i, j); 781 #if defined(sparc) 782 exit(1); 783 #endif 784 } 785 } 786 } 787 } 788 } 789 } 790 791 /* 792 * validate64() 793 * 794 * Validate the new VTOC. 795 */ 796 static void 797 validate64(struct dk_gpt *efi) 798 { 799 int i; 800 int j; 801 int resv_part = 0; 802 diskaddr_t endsect; 803 diskaddr_t fullsz; 804 diskaddr_t istart; 805 diskaddr_t jstart; 806 diskaddr_t isize; 807 diskaddr_t jsize; 808 809 fullsz = lastlba + 1; 810 811 for (i = 0; i < efi->efi_nparts; i++) { 812 if (efi->efi_parts[i].p_size == 0) 813 continue; /* Undefined partition */ 814 if (efi->efi_parts[i].p_tag == V_RESERVED) 815 resv_part++; 816 if (efi->efi_parts[i].p_start > fullsz || 817 efi->efi_parts[i].p_start + 818 efi->efi_parts[i].p_size > fullsz) { 819 (void) fprintf(stderr, "\ 820 fmthard: Partition %d specified as %lld sectors starting at %lld\n\ 821 \tdoes not fit. The full disk contains %lld sectors.\n", 822 i, efi->efi_parts[i].p_size, 823 efi->efi_parts[i].p_start, fullsz); 824 exit(1); 825 } 826 827 if (efi->efi_parts[i].p_tag != V_BACKUP && 828 efi->efi_parts[i].p_size != fullsz) { 829 for (j = 0; j < efi->efi_nparts; j++) { 830 if (efi->efi_parts[j].p_size == fullsz) 831 continue; 832 isize = efi->efi_parts[i].p_size; 833 jsize = efi->efi_parts[j].p_size; 834 istart = efi->efi_parts[i].p_start; 835 jstart = efi->efi_parts[j].p_start; 836 if ((i != j) && 837 (isize != 0) && (jsize != 0)) { 838 endsect = jstart + jsize - 1; 839 if ((jstart <= istart) && 840 (istart <= endsect)) { 841 (void) fprintf(stderr, "\ 842 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\ 843 \tonly on partition on the full disk partition).\n", 844 i, j); 845 #if defined(sparc) 846 exit(1); 847 #endif 848 } 849 } 850 } 851 } 852 } 853 if (resv_part != 1) { 854 (void) fprintf(stderr, 855 "expected one reserved partition, but found %d\n", 856 resv_part); 857 exit(1); 858 } 859 } 860 861 862 /* 863 * Read the VTOC 864 */ 865 int 866 vread(int fd, struct extvtoc *vtoc, char *devname) 867 { 868 int i; 869 870 if ((i = read_extvtoc(fd, vtoc)) < 0) { 871 if (i == VT_ENOTSUP) { 872 return (1); 873 } 874 if (i == VT_EINVAL) { 875 (void) fprintf(stderr, "%s: Invalid VTOC\n", 876 devname); 877 } else { 878 (void) fprintf(stderr, "%s: Cannot read VTOC\n", 879 devname); 880 } 881 exit(1); 882 } 883 return (0); 884 } 885 886 void 887 vread64(int fd, struct dk_gpt **efi_hdr, char *devname) 888 { 889 int i; 890 891 if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) { 892 if (i == VT_EINVAL) 893 (void) fprintf(stderr, 894 "%s: this disk must be labeled first\n", 895 devname); 896 else 897 (void) fprintf(stderr, 898 "%s: read_efi failed %d\n", 899 devname, i); 900 exit(1); 901 } 902 lastlba = (*efi_hdr)->efi_last_u_lba; 903 } 904 905 /* 906 * Write the VTOC 907 */ 908 void 909 vwrite(int fd, struct extvtoc *vtoc, char *devname) 910 { 911 int i; 912 913 if ((i = write_extvtoc(fd, vtoc)) != 0) { 914 if (i == VT_EINVAL) { 915 (void) fprintf(stderr, 916 "%s: invalid entry exists in vtoc\n", 917 devname); 918 } else { 919 (void) fprintf(stderr, "%s: Cannot write VTOC\n", 920 devname); 921 } 922 exit(1); 923 } 924 } 925 926 /* 927 * Write the VTOC 928 */ 929 void 930 vwrite64(int fd, struct dk_gpt *efi, char *devname) 931 { 932 int i; 933 934 if ((i = efi_write(fd, efi)) != 0) { 935 if (i == VT_EINVAL) { 936 (void) fprintf(stderr, 937 "%s: invalid entry exists in vtoc\n", 938 devname); 939 } else { 940 (void) fprintf(stderr, "%s: Cannot write EFI\n", 941 devname); 942 } 943 exit(1); 944 } 945 } 946