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 installgrub(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 installgrub(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 }