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