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 
  22 /*
  23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright 2014 Toomas Soome <tsoome@me.com>
  26  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  27  */
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <errno.h>
  32 #include <strings.h>
  33 #include <unistd.h>
  34 #include <smbios.h>
  35 #include <uuid/uuid.h>
  36 #include <libintl.h>
  37 #include <sys/types.h>
  38 #include <sys/dkio.h>
  39 #include <sys/vtoc.h>
  40 #include <sys/mhd.h>
  41 #include <sys/param.h>
  42 #include <sys/dktp/fdisk.h>
  43 #include <sys/efi_partition.h>
  44 #include <sys/byteorder.h>
  45 #include <sys/ddi.h>
  46 
  47 /*
  48  * The original conversion array used simple array index, but since
  49  * we do need to take account of VTOC tag numbers from other systems,
  50  * we need to provide tag values too, or the array will grow too large.
  51  *
  52  * Still we will fabricate the missing p_tag values.
  53  */
  54 static struct uuid_to_ptag {
  55         struct uuid     uuid;
  56         ushort_t        p_tag;
  57 } conversion_array[] = {
  58         { EFI_UNUSED, V_UNASSIGNED },
  59         { EFI_BOOT, V_BOOT },
  60         { EFI_ROOT, V_ROOT },
  61         { EFI_SWAP, V_SWAP },
  62         { EFI_USR, V_USR },
  63         { EFI_BACKUP, V_BACKUP },
  64         { EFI_VAR, V_VAR },
  65         { EFI_HOME, V_HOME },
  66         { EFI_ALTSCTR, V_ALTSCTR },
  67         { EFI_RESERVED, V_RESERVED },
  68         { EFI_SYSTEM, V_SYSTEM },               /* V_SYSTEM is 0xc */
  69         { EFI_LEGACY_MBR, 0x10 },
  70         { EFI_SYMC_PUB, 0x11 },
  71         { EFI_SYMC_CDS, 0x12 },
  72         { EFI_MSFT_RESV, 0x13 },
  73         { EFI_DELL_BASIC, 0x14 },
  74         { EFI_DELL_RAID, 0x15 },
  75         { EFI_DELL_SWAP, 0x16 },
  76         { EFI_DELL_LVM, 0x17 },
  77         { EFI_DELL_RESV, 0x19 },
  78         { EFI_AAPL_HFS, 0x1a },
  79         { EFI_AAPL_UFS, 0x1b },
  80         { EFI_AAPL_ZFS, 0x1c },
  81         { EFI_AAPL_APFS, 0x1d },
  82         { EFI_BIOS_BOOT, V_BIOS_BOOT },         /* V_BIOS_BOOT is 0x18 */
  83         { EFI_FREEBSD_BOOT,  V_FREEBSD_BOOT },
  84         { EFI_FREEBSD_SWAP, V_FREEBSD_SWAP },
  85         { EFI_FREEBSD_UFS, V_FREEBSD_UFS },
  86         { EFI_FREEBSD_VINUM, V_FREEBSD_VINUM },
  87         { EFI_FREEBSD_ZFS, V_FREEBSD_ZFS },
  88         { EFI_FREEBSD_NANDFS, V_FREEBSD_NANDFS }
  89 };
  90 
  91 /*
  92  * Default vtoc information for non-SVr4 partitions
  93  */
  94 struct dk_map2  default_vtoc_map[NDKMAP] = {
  95         {       V_ROOT,         0       },              /* a - 0 */
  96         {       V_SWAP,         V_UNMNT },              /* b - 1 */
  97         {       V_BACKUP,       V_UNMNT },              /* c - 2 */
  98         {       V_UNASSIGNED,   0       },              /* d - 3 */
  99         {       V_UNASSIGNED,   0       },              /* e - 4 */
 100         {       V_UNASSIGNED,   0       },              /* f - 5 */
 101         {       V_USR,          0       },              /* g - 6 */
 102         {       V_UNASSIGNED,   0       },              /* h - 7 */
 103 
 104 #if defined(_SUNOS_VTOC_16)
 105 
 106 #if defined(i386) || defined(__amd64)
 107         {       V_BOOT,         V_UNMNT },              /* i - 8 */
 108         {       V_ALTSCTR,      0       },              /* j - 9 */
 109 
 110 #else
 111 #error No VTOC format defined.
 112 #endif                  /* defined(i386) */
 113 
 114         {       V_UNASSIGNED,   0       },              /* k - 10 */
 115         {       V_UNASSIGNED,   0       },              /* l - 11 */
 116         {       V_UNASSIGNED,   0       },              /* m - 12 */
 117         {       V_UNASSIGNED,   0       },              /* n - 13 */
 118         {       V_UNASSIGNED,   0       },              /* o - 14 */
 119         {       V_UNASSIGNED,   0       },              /* p - 15 */
 120 #endif                  /* defined(_SUNOS_VTOC_16) */
 121 };
 122 
 123 #ifdef DEBUG
 124 int efi_debug = 1;
 125 #else
 126 int efi_debug = 0;
 127 #endif
 128 
 129 #define EFI_FIXES_DB "/usr/share/hwdata/efi.fixes"
 130 
 131 extern unsigned int     efi_crc32(const unsigned char *, unsigned int);
 132 static int              efi_read(int, struct dk_gpt *);
 133 
 134 static int
 135 read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
 136 {
 137         struct dk_minfo         disk_info;
 138 
 139         if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
 140                 return (errno);
 141         *capacity = disk_info.dki_capacity;
 142         *lbsize = disk_info.dki_lbsize;
 143         return (0);
 144 }
 145 
 146 /*
 147  * the number of blocks the EFI label takes up (round up to nearest
 148  * block)
 149  */
 150 #define NBLOCKS(p, l)   (1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
 151                                 ((l) - 1)) / (l)))
 152 /* number of partitions -- limited by what we can malloc */
 153 #define MAX_PARTS       ((4294967295UL - sizeof (struct dk_gpt)) / \
 154                             sizeof (struct dk_part))
 155 
 156 int
 157 efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
 158 {
 159         diskaddr_t      capacity;
 160         uint_t          lbsize;
 161         uint_t          nblocks;
 162         size_t          length;
 163         struct dk_gpt   *vptr;
 164         struct uuid     uuid;
 165 
 166         if (read_disk_info(fd, &capacity, &lbsize) != 0) {
 167                 if (efi_debug)
 168                         (void) fprintf(stderr,
 169                             "couldn't read disk information\n");
 170                 return (-1);
 171         }
 172 
 173         nblocks = NBLOCKS(nparts, lbsize);
 174         if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
 175                 /* 16K plus one block for the GPT */
 176                 nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
 177         }
 178 
 179         if (nparts > MAX_PARTS) {
 180                 if (efi_debug) {
 181                         (void) fprintf(stderr,
 182                         "the maximum number of partitions supported is %lu\n",
 183                             MAX_PARTS);
 184                 }
 185                 return (-1);
 186         }
 187 
 188         length = sizeof (struct dk_gpt) +
 189             sizeof (struct dk_part) * (nparts - 1);
 190 
 191         if ((*vtoc = calloc(length, 1)) == NULL)
 192                 return (-1);
 193 
 194         vptr = *vtoc;
 195 
 196         vptr->efi_version = EFI_VERSION_CURRENT;
 197         vptr->efi_lbasize = lbsize;
 198         vptr->efi_nparts = nparts;
 199         /*
 200          * add one block here for the PMBR; on disks with a 512 byte
 201          * block size and 128 or fewer partitions, efi_first_u_lba
 202          * should work out to "34"
 203          */
 204         vptr->efi_first_u_lba = nblocks + 1;
 205         vptr->efi_last_lba = capacity - 1;
 206         vptr->efi_altern_lba = capacity -1;
 207         vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
 208 
 209         (void) uuid_generate((uchar_t *)&uuid);
 210         UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
 211         return (0);
 212 }
 213 
 214 /*
 215  * Read EFI - return partition number upon success.
 216  */
 217 int
 218 efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
 219 {
 220         int                     rval;
 221         uint32_t                nparts;
 222         int                     length;
 223         struct mboot            *mbr;
 224         struct ipart            *ipart;
 225         diskaddr_t              capacity;
 226         uint_t                  lbsize;
 227         int                     i;
 228 
 229         if (read_disk_info(fd, &capacity, &lbsize) != 0)
 230                 return (VT_ERROR);
 231 
 232         if ((mbr = calloc(lbsize, 1)) == NULL)
 233                 return (VT_ERROR);
 234 
 235         if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) {
 236                 free(mbr);
 237                 return (VT_ERROR);
 238         }
 239 
 240         if (mbr->signature != MBB_MAGIC) {
 241                 free(mbr);
 242                 return (VT_EINVAL);
 243         }
 244         ipart = (struct ipart *)(uintptr_t)mbr->parts;
 245 
 246         /* Check if we have partition with ID EFI_PMBR */
 247         for (i = 0; i < FD_NUMPART; i++) {
 248                 if (ipart[i].systid == EFI_PMBR)
 249                         break;
 250         }
 251         free(mbr);
 252         if (i == FD_NUMPART)
 253                 return (VT_EINVAL);
 254 
 255         /* figure out the number of entries that would fit into 16K */
 256         nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
 257         length = (int) sizeof (struct dk_gpt) +
 258             (int) sizeof (struct dk_part) * (nparts - 1);
 259         if ((*vtoc = calloc(length, 1)) == NULL)
 260                 return (VT_ERROR);
 261 
 262         (*vtoc)->efi_nparts = nparts;
 263         rval = efi_read(fd, *vtoc);
 264 
 265         if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
 266                 void *tmp;
 267                 length = (int) sizeof (struct dk_gpt) +
 268                     (int) sizeof (struct dk_part) *
 269                     ((*vtoc)->efi_nparts - 1);
 270                 nparts = (*vtoc)->efi_nparts;
 271                 if ((tmp = realloc(*vtoc, length)) == NULL) {
 272                         free (*vtoc);
 273                         *vtoc = NULL;
 274                         return (VT_ERROR);
 275                 } else {
 276                         *vtoc = tmp;
 277                         rval = efi_read(fd, *vtoc);
 278                 }
 279         }
 280 
 281         if (rval < 0) {
 282                 if (efi_debug) {
 283                         (void) fprintf(stderr,
 284                             "read of EFI table failed, rval=%d\n", rval);
 285                 }
 286                 free (*vtoc);
 287                 *vtoc = NULL;
 288         }
 289 
 290         return (rval);
 291 }
 292 
 293 static int
 294 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
 295 {
 296         void *data = dk_ioc->dki_data;
 297         int error;
 298 
 299         dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
 300         error = ioctl(fd, cmd, (void *)dk_ioc);
 301         dk_ioc->dki_data = data;
 302 
 303         return (error);
 304 }
 305 
 306 static int
 307 check_label(int fd, dk_efi_t *dk_ioc)
 308 {
 309         efi_gpt_t               *efi;
 310         uint_t                  crc;
 311 
 312         if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
 313                 switch (errno) {
 314                 case EIO:
 315                         return (VT_EIO);
 316                 default:
 317                         return (VT_ERROR);
 318                 }
 319         }
 320         efi = dk_ioc->dki_data;
 321         if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
 322                 if (efi_debug)
 323                         (void) fprintf(stderr,
 324                             "Bad EFI signature: 0x%llx != 0x%llx\n",
 325                             (long long)efi->efi_gpt_Signature,
 326                             (long long)LE_64(EFI_SIGNATURE));
 327                 return (VT_EINVAL);
 328         }
 329 
 330         /*
 331          * check CRC of the header; the size of the header should
 332          * never be larger than one block
 333          */
 334         crc = efi->efi_gpt_HeaderCRC32;
 335         efi->efi_gpt_HeaderCRC32 = 0;
 336 
 337         if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
 338             crc != LE_32(efi_crc32((unsigned char *)efi,
 339             LE_32(efi->efi_gpt_HeaderSize)))) {
 340                 if (efi_debug)
 341                         (void) fprintf(stderr,
 342                             "Bad EFI CRC: 0x%x != 0x%x\n",
 343                             crc,
 344                             LE_32(efi_crc32((unsigned char *)efi,
 345                             sizeof (struct efi_gpt))));
 346                 return (VT_EINVAL);
 347         }
 348 
 349         return (0);
 350 }
 351 
 352 static int
 353 efi_read(int fd, struct dk_gpt *vtoc)
 354 {
 355         int                     i, j;
 356         int                     label_len;
 357         int                     rval = 0;
 358         int                     vdc_flag = 0;
 359         struct dk_minfo         disk_info;
 360         dk_efi_t                dk_ioc;
 361         efi_gpt_t               *efi;
 362         efi_gpe_t               *efi_parts;
 363         struct dk_cinfo         dki_info;
 364         uint32_t                user_length;
 365         boolean_t               legacy_label = B_FALSE;
 366 
 367         /*
 368          * get the partition number for this file descriptor.
 369          */
 370         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 371                 if (efi_debug) {
 372                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 373                 }
 374                 switch (errno) {
 375                 case EIO:
 376                         return (VT_EIO);
 377                 case EINVAL:
 378                         return (VT_EINVAL);
 379                 default:
 380                         return (VT_ERROR);
 381                 }
 382         }
 383 
 384         if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
 385             (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
 386                 /*
 387                  * The controller and drive name "vdc" (virtual disk client)
 388                  * indicates a LDoms virtual disk.
 389                  */
 390                 vdc_flag++;
 391         }
 392 
 393         /* get the LBA size */
 394         if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) {
 395                 if (efi_debug) {
 396                         (void) fprintf(stderr,
 397                             "assuming LBA 512 bytes %d\n",
 398                             errno);
 399                 }
 400                 disk_info.dki_lbsize = DEV_BSIZE;
 401         }
 402         if (disk_info.dki_lbsize == 0) {
 403                 if (efi_debug) {
 404                         (void) fprintf(stderr,
 405                             "efi_read: assuming LBA 512 bytes\n");
 406                 }
 407                 disk_info.dki_lbsize = DEV_BSIZE;
 408         }
 409         /*
 410          * Read the EFI GPT to figure out how many partitions we need
 411          * to deal with.
 412          */
 413         dk_ioc.dki_lba = 1;
 414         if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
 415                 label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
 416         } else {
 417                 label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
 418                     disk_info.dki_lbsize;
 419                 if (label_len % disk_info.dki_lbsize) {
 420                         /* pad to physical sector size */
 421                         label_len += disk_info.dki_lbsize;
 422                         label_len &= ~(disk_info.dki_lbsize - 1);
 423                 }
 424         }
 425 
 426         if ((dk_ioc.dki_data = calloc(label_len, 1)) == NULL)
 427                 return (VT_ERROR);
 428 
 429         dk_ioc.dki_length = disk_info.dki_lbsize;
 430         user_length = vtoc->efi_nparts;
 431         efi = dk_ioc.dki_data;
 432         if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
 433                 /*
 434                  * No valid label here; try the alternate. Note that here
 435                  * we just read GPT header and save it into dk_ioc.data,
 436                  * Later, we will read GUID partition entry array if we
 437                  * can get valid GPT header.
 438                  */
 439 
 440                 /*
 441                  * This is a workaround for legacy systems. In the past, the
 442                  * last sector of SCSI disk was invisible on x86 platform. At
 443                  * that time, backup label was saved on the next to the last
 444                  * sector. It is possible for users to move a disk from previous
 445                  * solaris system to present system. Here, we attempt to search
 446                  * legacy backup EFI label first.
 447                  */
 448                 dk_ioc.dki_lba = disk_info.dki_capacity - 2;
 449                 dk_ioc.dki_length = disk_info.dki_lbsize;
 450                 rval = check_label(fd, &dk_ioc);
 451                 if (rval == VT_EINVAL) {
 452                         /*
 453                          * we didn't find legacy backup EFI label, try to
 454                          * search backup EFI label in the last block.
 455                          */
 456                         dk_ioc.dki_lba = disk_info.dki_capacity - 1;
 457                         dk_ioc.dki_length = disk_info.dki_lbsize;
 458                         rval = check_label(fd, &dk_ioc);
 459                         if (rval == 0) {
 460                                 legacy_label = B_TRUE;
 461                                 if (efi_debug)
 462                                         (void) fprintf(stderr,
 463                                             "efi_read: primary label corrupt; "
 464                                             "using EFI backup label located on"
 465                                             " the last block\n");
 466                         }
 467                 } else {
 468                         if ((efi_debug) && (rval == 0))
 469                                 (void) fprintf(stderr, "efi_read: primary label"
 470                                     " corrupt; using legacy EFI backup label "
 471                                     " located on the next to last block\n");
 472                 }
 473 
 474                 if (rval == 0) {
 475                         dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 476                         vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
 477                         vtoc->efi_nparts =
 478                             LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 479                         /*
 480                          * Partition tables are between backup GPT header
 481                          * table and ParitionEntryLBA (the starting LBA of
 482                          * the GUID partition entries array). Now that we
 483                          * already got valid GPT header and saved it in
 484                          * dk_ioc.dki_data, we try to get GUID partition
 485                          * entry array here.
 486                          */
 487                         /* LINTED */
 488                         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 489                             + disk_info.dki_lbsize);
 490                         if (legacy_label)
 491                                 dk_ioc.dki_length = disk_info.dki_capacity - 1 -
 492                                     dk_ioc.dki_lba;
 493                         else
 494                                 dk_ioc.dki_length = disk_info.dki_capacity - 2 -
 495                                     dk_ioc.dki_lba;
 496                         dk_ioc.dki_length *= disk_info.dki_lbsize;
 497                         if (dk_ioc.dki_length >
 498                             ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
 499                                 rval = VT_EINVAL;
 500                         } else {
 501                                 /*
 502                                  * read GUID partition entry array
 503                                  */
 504                                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 505                         }
 506                 }
 507 
 508         } else if (rval == 0) {
 509 
 510                 dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
 511                 /* LINTED */
 512                 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
 513                     + disk_info.dki_lbsize);
 514                 dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
 515                 rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
 516 
 517         } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
 518                 /*
 519                  * When the device is a LDoms virtual disk, the DKIOCGETEFI
 520                  * ioctl can fail with EINVAL if the virtual disk backend
 521                  * is a ZFS volume serviced by a domain running an old version
 522                  * of Solaris. This is because the DKIOCGETEFI ioctl was
 523                  * initially incorrectly implemented for a ZFS volume and it
 524                  * expected the GPT and GPE to be retrieved with a single ioctl.
 525                  * So we try to read the GPT and the GPE using that old style
 526                  * ioctl.
 527                  */
 528                 dk_ioc.dki_lba = 1;
 529                 dk_ioc.dki_length = label_len;
 530                 rval = check_label(fd, &dk_ioc);
 531         }
 532 
 533         if (rval < 0) {
 534                 free(efi);
 535                 return (rval);
 536         }
 537 
 538         /* LINTED -- always longlong aligned */
 539         efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
 540 
 541         /*
 542          * Assemble this into a "dk_gpt" struct for easier
 543          * digestibility by applications.
 544          */
 545         vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
 546         vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
 547         vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
 548         vtoc->efi_lbasize = disk_info.dki_lbsize;
 549         vtoc->efi_last_lba = disk_info.dki_capacity - 1;
 550         vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
 551         vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
 552         vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
 553         UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
 554 
 555         /*
 556          * If the array the user passed in is too small, set the length
 557          * to what it needs to be and return
 558          */
 559         if (user_length < vtoc->efi_nparts) {
 560                 return (VT_EINVAL);
 561         }
 562 
 563         for (i = 0; i < vtoc->efi_nparts; i++) {
 564 
 565                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
 566                     efi_parts[i].efi_gpe_PartitionTypeGUID);
 567 
 568                 for (j = 0;
 569                     j < sizeof (conversion_array)
 570                     / sizeof (struct uuid_to_ptag); j++) {
 571 
 572                         if (bcmp(&vtoc->efi_parts[i].p_guid,
 573                             &conversion_array[j].uuid,
 574                             sizeof (struct uuid)) == 0) {
 575                                 vtoc->efi_parts[i].p_tag =
 576                                     conversion_array[j].p_tag;
 577                                 break;
 578                         }
 579                 }
 580                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
 581                         continue;
 582                 vtoc->efi_parts[i].p_flag =
 583                     LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
 584                 vtoc->efi_parts[i].p_start =
 585                     LE_64(efi_parts[i].efi_gpe_StartingLBA);
 586                 vtoc->efi_parts[i].p_size =
 587                     LE_64(efi_parts[i].efi_gpe_EndingLBA) -
 588                     vtoc->efi_parts[i].p_start + 1;
 589                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
 590                         vtoc->efi_parts[i].p_name[j] =
 591                             (uchar_t)LE_16(
 592                             efi_parts[i].efi_gpe_PartitionName[j]);
 593                 }
 594 
 595                 UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
 596                     efi_parts[i].efi_gpe_UniquePartitionGUID);
 597         }
 598         free(efi);
 599 
 600         return (dki_info.dki_partition);
 601 }
 602 
 603 static void
 604 hardware_workarounds(int *slot, int *active)
 605 {
 606         smbios_struct_t s_sys, s_mb;
 607         smbios_info_t sys, mb;
 608         smbios_hdl_t *shp;
 609         char buf[0x400];
 610         FILE *fp;
 611         int err;
 612 
 613         if ((fp = fopen(EFI_FIXES_DB, "rF")) == NULL)
 614                 return;
 615 
 616         if ((shp = smbios_open(NULL, SMB_VERSION, 0, &err)) == NULL) {
 617                 if (efi_debug)
 618                         (void) fprintf(stderr,
 619                             "libefi failed to load SMBIOS: %s\n",
 620                             smbios_errmsg(err));
 621                 (void) fclose(fp);
 622                 return;
 623         }
 624 
 625         if (smbios_lookup_type(shp, SMB_TYPE_SYSTEM, &s_sys) == SMB_ERR ||
 626             smbios_info_common(shp, s_sys.smbstr_id, &sys) == SMB_ERR)
 627                 (void) memset(&sys, '\0', sizeof (sys));
 628         if (smbios_lookup_type(shp, SMB_TYPE_BASEBOARD, &s_mb) == SMB_ERR ||
 629             smbios_info_common(shp, s_mb.smbstr_id, &mb) == SMB_ERR)
 630                 (void) memset(&mb, '\0', sizeof (mb));
 631 
 632         while (fgets(buf, sizeof (buf), fp) != NULL) {
 633                 char *tok, *val, *end;
 634 
 635                 tok = buf + strspn(buf, " \t");
 636                 if (*tok == '#')
 637                         continue;
 638                 while (*tok != '\0') {
 639                         tok += strspn(tok, " \t");
 640                         if ((val = strchr(tok, '=')) == NULL)
 641                                 break;
 642                         *val++ = '\0';
 643                         if (*val == '"')
 644                                 end = strchr(++val, '"');
 645                         else
 646                                 end = strpbrk(val, " \t\n");
 647                         if (end == NULL)
 648                                 break;
 649                         *end++ = '\0';
 650 
 651                         if (strcmp(tok, "sys.manufacturer") == 0 &&
 652                             (sys.smbi_manufacturer == NULL ||
 653                             strcasecmp(val, sys.smbi_manufacturer)))
 654                                 break;
 655                         if (strcmp(tok, "sys.product") == 0 &&
 656                             (sys.smbi_product == NULL ||
 657                             strcasecmp(val, sys.smbi_product)))
 658                                 break;
 659                         if (strcmp(tok, "sys.version") == 0 &&
 660                             (sys.smbi_version == NULL ||
 661                             strcasecmp(val, sys.smbi_version)))
 662                                 break;
 663                         if (strcmp(tok, "mb.manufacturer") == 0 &&
 664                             (mb.smbi_manufacturer == NULL ||
 665                             strcasecmp(val, mb.smbi_manufacturer)))
 666                                 break;
 667                         if (strcmp(tok, "mb.product") == 0 &&
 668                             (mb.smbi_product == NULL ||
 669                             strcasecmp(val, mb.smbi_product)))
 670                                 break;
 671                         if (strcmp(tok, "mb.version") == 0 &&
 672                             (mb.smbi_version == NULL ||
 673                             strcasecmp(val, mb.smbi_version)))
 674                                 break;
 675 
 676                         if (strcmp(tok, "pmbr_slot") == 0) {
 677                                 *slot = atoi(val);
 678                                 if (*slot < 0 || *slot > 3)
 679                                         *slot = 0;
 680                                 if (efi_debug)
 681                                         (void) fprintf(stderr,
 682                                             "Using slot %d\n", *slot);
 683                         }
 684 
 685                         if (strcmp(tok, "pmbr_active") == 0) {
 686                                 *active = atoi(val);
 687                                 if (*active < 0 || *active > 1)
 688                                         *active = 0;
 689                                 if (efi_debug)
 690                                         (void) fprintf(stderr,
 691                                             "Using active %d\n", *active);
 692                         }
 693 
 694                         tok = end;
 695                 }
 696         }
 697         (void) fclose(fp);
 698         smbios_close(shp);
 699 }
 700 
 701 /* writes a "protective" MBR */
 702 static int
 703 write_pmbr(int fd, struct dk_gpt *vtoc)
 704 {
 705         dk_efi_t        dk_ioc;
 706         struct mboot    mb;
 707         uchar_t         *cp;
 708         diskaddr_t      size_in_lba;
 709         uchar_t         *buf;
 710         int             len, slot, active;
 711 
 712         slot = active = 0;
 713 
 714         hardware_workarounds(&slot, &active);
 715 
 716         len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
 717         buf = calloc(len, 1);
 718 
 719         /*
 720          * Preserve any boot code and disk signature if the first block is
 721          * already an MBR.
 722          */
 723         dk_ioc.dki_lba = 0;
 724         dk_ioc.dki_length = len;
 725         /* LINTED -- always longlong aligned */
 726         dk_ioc.dki_data = (efi_gpt_t *)buf;
 727         if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
 728                 (void) memcpy(&mb, buf, sizeof (mb));
 729                 bzero(&mb, sizeof (mb));
 730                 mb.signature = LE_16(MBB_MAGIC);
 731         } else {
 732                 (void) memcpy(&mb, buf, sizeof (mb));
 733                 if (mb.signature != LE_16(MBB_MAGIC)) {
 734                         bzero(&mb, sizeof (mb));
 735                         mb.signature = LE_16(MBB_MAGIC);
 736                 }
 737         }
 738 
 739         bzero(&mb.parts, sizeof (mb.parts));
 740         cp = (uchar_t *)&mb.parts[slot * sizeof (struct ipart)];
 741         /* bootable or not */
 742         *cp++ = active ? ACTIVE : NOTACTIVE;
 743         /* beginning CHS; 0xffffff if not representable */
 744         *cp++ = 0xff;
 745         *cp++ = 0xff;
 746         *cp++ = 0xff;
 747         /* OS type */
 748         *cp++ = EFI_PMBR;
 749         /* ending CHS; 0xffffff if not representable */
 750         *cp++ = 0xff;
 751         *cp++ = 0xff;
 752         *cp++ = 0xff;
 753         /* starting LBA: 1 (little endian format) by EFI definition */
 754         *cp++ = 0x01;
 755         *cp++ = 0x00;
 756         *cp++ = 0x00;
 757         *cp++ = 0x00;
 758         /* ending LBA: last block on the disk (little endian format) */
 759         size_in_lba = vtoc->efi_last_lba;
 760         if (size_in_lba < 0xffffffff) {
 761                 *cp++ = (size_in_lba & 0x000000ff);
 762                 *cp++ = (size_in_lba & 0x0000ff00) >> 8;
 763                 *cp++ = (size_in_lba & 0x00ff0000) >> 16;
 764                 *cp++ = (size_in_lba & 0xff000000) >> 24;
 765         } else {
 766                 *cp++ = 0xff;
 767                 *cp++ = 0xff;
 768                 *cp++ = 0xff;
 769                 *cp++ = 0xff;
 770         }
 771 
 772         (void) memcpy(buf, &mb, sizeof (mb));
 773         /* LINTED -- always longlong aligned */
 774         dk_ioc.dki_data = (efi_gpt_t *)buf;
 775         dk_ioc.dki_lba = 0;
 776         dk_ioc.dki_length = len;
 777         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
 778                 free(buf);
 779                 switch (errno) {
 780                 case EIO:
 781                         return (VT_EIO);
 782                 case EINVAL:
 783                         return (VT_EINVAL);
 784                 default:
 785                         return (VT_ERROR);
 786                 }
 787         }
 788         free(buf);
 789         return (0);
 790 }
 791 
 792 /* make sure the user specified something reasonable */
 793 static int
 794 check_input(struct dk_gpt *vtoc)
 795 {
 796         int                     resv_part = -1;
 797         int                     i, j;
 798         diskaddr_t              istart, jstart, isize, jsize, endsect;
 799 
 800         /*
 801          * Sanity-check the input (make sure no partitions overlap)
 802          */
 803         for (i = 0; i < vtoc->efi_nparts; i++) {
 804                 /* It can't be unassigned and have an actual size */
 805                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
 806                     (vtoc->efi_parts[i].p_size != 0)) {
 807                         if (efi_debug) {
 808                                 (void) fprintf(stderr,
 809 "partition %d is \"unassigned\" but has a size of %llu",
 810                                     i,
 811                                     vtoc->efi_parts[i].p_size);
 812                         }
 813                         return (VT_EINVAL);
 814                 }
 815                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
 816                         if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
 817                                 continue;
 818                         /* we have encountered an unknown uuid */
 819                         vtoc->efi_parts[i].p_tag = 0xff;
 820                 }
 821                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
 822                         if (resv_part != -1) {
 823                                 if (efi_debug) {
 824                                         (void) fprintf(stderr,
 825 "found duplicate reserved partition at %d\n",
 826                                             i);
 827                                 }
 828                                 return (VT_EINVAL);
 829                         }
 830                         resv_part = i;
 831                 }
 832                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
 833                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
 834                         if (efi_debug) {
 835                                 (void) fprintf(stderr,
 836                                     "Partition %d starts at %llu.  ",
 837                                     i,
 838                                     vtoc->efi_parts[i].p_start);
 839                                 (void) fprintf(stderr,
 840                                     "It must be between %llu and %llu.\n",
 841                                     vtoc->efi_first_u_lba,
 842                                     vtoc->efi_last_u_lba);
 843                         }
 844                         return (VT_EINVAL);
 845                 }
 846                 if ((vtoc->efi_parts[i].p_start +
 847                     vtoc->efi_parts[i].p_size <
 848                     vtoc->efi_first_u_lba) ||
 849                     (vtoc->efi_parts[i].p_start +
 850                     vtoc->efi_parts[i].p_size >
 851                     vtoc->efi_last_u_lba + 1)) {
 852                         if (efi_debug) {
 853                                 (void) fprintf(stderr,
 854                                     "Partition %d ends at %llu.  ",
 855                                     i,
 856                                     vtoc->efi_parts[i].p_start +
 857                                     vtoc->efi_parts[i].p_size);
 858                                 (void) fprintf(stderr,
 859                                     "It must be between %llu and %llu.\n",
 860                                     vtoc->efi_first_u_lba,
 861                                     vtoc->efi_last_u_lba);
 862                         }
 863                         return (VT_EINVAL);
 864                 }
 865 
 866                 for (j = 0; j < vtoc->efi_nparts; j++) {
 867                         isize = vtoc->efi_parts[i].p_size;
 868                         jsize = vtoc->efi_parts[j].p_size;
 869                         istart = vtoc->efi_parts[i].p_start;
 870                         jstart = vtoc->efi_parts[j].p_start;
 871                         if ((i != j) && (isize != 0) && (jsize != 0)) {
 872                                 endsect = jstart + jsize -1;
 873                                 if ((jstart <= istart) &&
 874                                     (istart <= endsect)) {
 875                                         if (efi_debug) {
 876                                                 (void) fprintf(stderr,
 877 "Partition %d overlaps partition %d.",
 878                                                     i, j);
 879                                         }
 880                                         return (VT_EINVAL);
 881                                 }
 882                         }
 883                 }
 884         }
 885         /* just a warning for now */
 886         if ((resv_part == -1) && efi_debug) {
 887                 (void) fprintf(stderr,
 888                     "no reserved partition found\n");
 889         }
 890         return (0);
 891 }
 892 
 893 /*
 894  * add all the unallocated space to the current label
 895  */
 896 int
 897 efi_use_whole_disk(int fd)
 898 {
 899         struct dk_gpt           *efi_label;
 900         int                     rval;
 901         int                     i;
 902         uint_t                  phy_last_slice = 0;
 903         diskaddr_t              pl_start = 0;
 904         diskaddr_t              pl_size;
 905 
 906         rval = efi_alloc_and_read(fd, &efi_label);
 907         if (rval < 0) {
 908                 return (rval);
 909         }
 910 
 911         /* find the last physically non-zero partition */
 912         for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
 913                 if (pl_start < efi_label->efi_parts[i].p_start) {
 914                         pl_start = efi_label->efi_parts[i].p_start;
 915                         phy_last_slice = i;
 916                 }
 917         }
 918         pl_size = efi_label->efi_parts[phy_last_slice].p_size;
 919 
 920         /*
 921          * If alter_lba is 1, we are using the backup label.
 922          * Since we can locate the backup label by disk capacity,
 923          * there must be no unallocated space.
 924          */
 925         if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
 926             >= efi_label->efi_last_lba)) {
 927                 if (efi_debug) {
 928                         (void) fprintf(stderr,
 929                             "efi_use_whole_disk: requested space not found\n");
 930                 }
 931                 efi_free(efi_label);
 932                 return (VT_ENOSPC);
 933         }
 934 
 935         /*
 936          * If there is space between the last physically non-zero partition
 937          * and the reserved partition, just add the unallocated space to this
 938          * area. Otherwise, the unallocated space is added to the last
 939          * physically non-zero partition.
 940          */
 941         if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
 942             EFI_MIN_RESV_SIZE) {
 943                 efi_label->efi_parts[phy_last_slice].p_size +=
 944                     efi_label->efi_last_lba - efi_label->efi_altern_lba;
 945         }
 946 
 947         /*
 948          * Move the reserved partition. There is currently no data in
 949          * here except fabricated devids (which get generated via
 950          * efi_write()). So there is no need to copy data.
 951          */
 952         efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
 953             efi_label->efi_last_lba - efi_label->efi_altern_lba;
 954         efi_label->efi_last_u_lba += efi_label->efi_last_lba
 955             - efi_label->efi_altern_lba;
 956 
 957         rval = efi_write(fd, efi_label);
 958         if (rval < 0) {
 959                 if (efi_debug) {
 960                         (void) fprintf(stderr,
 961                             "efi_use_whole_disk:fail to write label, rval=%d\n",
 962                             rval);
 963                 }
 964                 efi_free(efi_label);
 965                 return (rval);
 966         }
 967 
 968         efi_free(efi_label);
 969         return (0);
 970 }
 971 
 972 
 973 /*
 974  * write EFI label and backup label
 975  */
 976 int
 977 efi_write(int fd, struct dk_gpt *vtoc)
 978 {
 979         dk_efi_t                dk_ioc;
 980         efi_gpt_t               *efi;
 981         efi_gpe_t               *efi_parts;
 982         int                     i, j;
 983         struct dk_cinfo         dki_info;
 984         int                     nblocks;
 985         diskaddr_t              lba_backup_gpt_hdr;
 986 
 987         if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
 988                 if (efi_debug)
 989                         (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
 990                 switch (errno) {
 991                 case EIO:
 992                         return (VT_EIO);
 993                 case EINVAL:
 994                         return (VT_EINVAL);
 995                 default:
 996                         return (VT_ERROR);
 997                 }
 998         }
 999 
1000         if (check_input(vtoc))
1001                 return (VT_EINVAL);
1002 
1003         dk_ioc.dki_lba = 1;
1004         if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
1005                 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
1006         } else {
1007                 dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
1008                     vtoc->efi_lbasize) *
1009                     vtoc->efi_lbasize;
1010         }
1011 
1012         /*
1013          * the number of blocks occupied by GUID partition entry array
1014          */
1015         nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
1016 
1017         /*
1018          * Backup GPT header is located on the block after GUID
1019          * partition entry array. Here, we calculate the address
1020          * for backup GPT header.
1021          */
1022         lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
1023         if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL)
1024                 return (VT_ERROR);
1025 
1026         efi = dk_ioc.dki_data;
1027 
1028         /* stuff user's input into EFI struct */
1029         efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
1030         efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
1031         efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
1032         efi->efi_gpt_Reserved1 = 0;
1033         efi->efi_gpt_MyLBA = LE_64(1ULL);
1034         efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
1035         efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
1036         efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
1037         efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
1038         efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
1039         efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
1040         UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
1041 
1042         /* LINTED -- always longlong aligned */
1043         efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
1044 
1045         for (i = 0; i < vtoc->efi_nparts; i++) {
1046                 for (j = 0;
1047                     j < sizeof (conversion_array) /
1048                     sizeof (struct uuid_to_ptag); j++) {
1049 
1050                         if (vtoc->efi_parts[i].p_tag ==
1051                             conversion_array[j].p_tag) {
1052                                 UUID_LE_CONVERT(
1053                                     efi_parts[i].efi_gpe_PartitionTypeGUID,
1054                                     conversion_array[j].uuid);
1055                                 break;
1056                         }
1057                 }
1058 
1059                 if (j == sizeof (conversion_array) /
1060                     sizeof (struct uuid_to_ptag)) {
1061                         /*
1062                          * If we didn't have a matching uuid match, bail here.
1063                          * Don't write a label with unknown uuid.
1064                          */
1065                         if (efi_debug) {
1066                                 (void) fprintf(stderr,
1067                                     "Unknown uuid for p_tag %d\n",
1068                                     vtoc->efi_parts[i].p_tag);
1069                         }
1070                         return (VT_EINVAL);
1071                 }
1072 
1073                 efi_parts[i].efi_gpe_StartingLBA =
1074                     LE_64(vtoc->efi_parts[i].p_start);
1075                 efi_parts[i].efi_gpe_EndingLBA =
1076                     LE_64(vtoc->efi_parts[i].p_start +
1077                     vtoc->efi_parts[i].p_size - 1);
1078                 efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
1079                     LE_16(vtoc->efi_parts[i].p_flag);
1080                 for (j = 0; j < EFI_PART_NAME_LEN; j++) {
1081                         efi_parts[i].efi_gpe_PartitionName[j] =
1082                             LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
1083                 }
1084                 if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
1085                     uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
1086                         (void) uuid_generate((uchar_t *)
1087                             &vtoc->efi_parts[i].p_uguid);
1088                 }
1089                 bcopy(&vtoc->efi_parts[i].p_uguid,
1090                     &efi_parts[i].efi_gpe_UniquePartitionGUID,
1091                     sizeof (uuid_t));
1092         }
1093         efi->efi_gpt_PartitionEntryArrayCRC32 =
1094             LE_32(efi_crc32((unsigned char *)efi_parts,
1095             vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
1096         efi->efi_gpt_HeaderCRC32 =
1097             LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
1098 
1099         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1100                 free(dk_ioc.dki_data);
1101                 switch (errno) {
1102                 case EIO:
1103                         return (VT_EIO);
1104                 case EINVAL:
1105                         return (VT_EINVAL);
1106                 default:
1107                         return (VT_ERROR);
1108                 }
1109         }
1110 
1111         /* write backup partition array */
1112         dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
1113         dk_ioc.dki_length -= vtoc->efi_lbasize;
1114         /* LINTED */
1115         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
1116             vtoc->efi_lbasize);
1117 
1118         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1119                 /*
1120                  * we wrote the primary label okay, so don't fail
1121                  */
1122                 if (efi_debug) {
1123                         (void) fprintf(stderr,
1124                             "write of backup partitions to block %llu "
1125                             "failed, errno %d\n",
1126                             vtoc->efi_last_u_lba + 1,
1127                             errno);
1128                 }
1129         }
1130         /*
1131          * now swap MyLBA and AlternateLBA fields and write backup
1132          * partition table header
1133          */
1134         dk_ioc.dki_lba = lba_backup_gpt_hdr;
1135         dk_ioc.dki_length = vtoc->efi_lbasize;
1136         /* LINTED */
1137         dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
1138             vtoc->efi_lbasize);
1139         efi->efi_gpt_AlternateLBA = LE_64(1ULL);
1140         efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
1141         efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
1142         efi->efi_gpt_HeaderCRC32 = 0;
1143         efi->efi_gpt_HeaderCRC32 =
1144             LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
1145             sizeof (struct efi_gpt)));
1146 
1147         if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
1148                 if (efi_debug) {
1149                         (void) fprintf(stderr,
1150                             "write of backup header to block %llu failed, "
1151                             "errno %d\n",
1152                             lba_backup_gpt_hdr,
1153                             errno);
1154                 }
1155         }
1156         /* write the PMBR */
1157         (void) write_pmbr(fd, vtoc);
1158         free(dk_ioc.dki_data);
1159         return (0);
1160 }
1161 
1162 void
1163 efi_free(struct dk_gpt *ptr)
1164 {
1165         free(ptr);
1166 }
1167 
1168 /*
1169  * Input: File descriptor
1170  * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
1171  * Otherwise 0.
1172  */
1173 int
1174 efi_type(int fd)
1175 {
1176         struct vtoc vtoc;
1177         struct extvtoc extvtoc;
1178 
1179         if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
1180                 if (errno == ENOTSUP)
1181                         return (1);
1182                 else if (errno == ENOTTY) {
1183                         if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
1184                                 if (errno == ENOTSUP)
1185                                         return (1);
1186                 }
1187         }
1188         return (0);
1189 }
1190 
1191 void
1192 efi_err_check(struct dk_gpt *vtoc)
1193 {
1194         int                     resv_part = -1;
1195         int                     i, j;
1196         diskaddr_t              istart, jstart, isize, jsize, endsect;
1197         int                     overlap = 0;
1198 
1199         /*
1200          * make sure no partitions overlap
1201          */
1202         for (i = 0; i < vtoc->efi_nparts; i++) {
1203                 /* It can't be unassigned and have an actual size */
1204                 if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
1205                     (vtoc->efi_parts[i].p_size != 0)) {
1206                         (void) fprintf(stderr,
1207                             "partition %d is \"unassigned\" but has a size "
1208                             "of %llu\n", i, vtoc->efi_parts[i].p_size);
1209                 }
1210                 if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
1211                         continue;
1212                 }
1213                 if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
1214                         if (resv_part != -1) {
1215                                 (void) fprintf(stderr,
1216                                     "found duplicate reserved partition at "
1217                                     "%d\n", i);
1218                         }
1219                         resv_part = i;
1220                         if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
1221                                 (void) fprintf(stderr,
1222                                     "Warning: reserved partition size must "
1223                                     "be %d sectors\n", EFI_MIN_RESV_SIZE);
1224                 }
1225                 if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
1226                     (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
1227                         (void) fprintf(stderr,
1228                             "Partition %d starts at %llu\n",
1229                             i,
1230                             vtoc->efi_parts[i].p_start);
1231                         (void) fprintf(stderr,
1232                             "It must be between %llu and %llu.\n",
1233                             vtoc->efi_first_u_lba,
1234                             vtoc->efi_last_u_lba);
1235                 }
1236                 if ((vtoc->efi_parts[i].p_start +
1237                     vtoc->efi_parts[i].p_size <
1238                     vtoc->efi_first_u_lba) ||
1239                     (vtoc->efi_parts[i].p_start +
1240                     vtoc->efi_parts[i].p_size >
1241                     vtoc->efi_last_u_lba + 1)) {
1242                         (void) fprintf(stderr,
1243                             "Partition %d ends at %llu\n",
1244                             i,
1245                             vtoc->efi_parts[i].p_start +
1246                             vtoc->efi_parts[i].p_size);
1247                         (void) fprintf(stderr,
1248                             "It must be between %llu and %llu.\n",
1249                             vtoc->efi_first_u_lba,
1250                             vtoc->efi_last_u_lba);
1251                 }
1252 
1253                 for (j = 0; j < vtoc->efi_nparts; j++) {
1254                         isize = vtoc->efi_parts[i].p_size;
1255                         jsize = vtoc->efi_parts[j].p_size;
1256                         istart = vtoc->efi_parts[i].p_start;
1257                         jstart = vtoc->efi_parts[j].p_start;
1258                         if ((i != j) && (isize != 0) && (jsize != 0)) {
1259                                 endsect = jstart + jsize -1;
1260                                 if ((jstart <= istart) &&
1261                                     (istart <= endsect)) {
1262                                         if (!overlap) {
1263                                         (void) fprintf(stderr,
1264                                             "label error: EFI Labels do not "
1265                                             "support overlapping partitions\n");
1266                                         }
1267                                         (void) fprintf(stderr,
1268                                             "Partition %d overlaps partition "
1269                                             "%d.\n", i, j);
1270                                         overlap = 1;
1271                                 }
1272                         }
1273                 }
1274         }
1275         /* make sure there is a reserved partition */
1276         if (resv_part == -1) {
1277                 (void) fprintf(stderr,
1278                     "no reserved partition found\n");
1279         }
1280 }
1281 
1282 /*
1283  * We need to get information necessary to construct a *new* efi
1284  * label type
1285  */
1286 int
1287 efi_auto_sense(int fd, struct dk_gpt **vtoc)
1288 {
1289 
1290         int     i;
1291 
1292         /*
1293          * Now build the default partition table
1294          */
1295         if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
1296                 if (efi_debug) {
1297                         (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
1298                 }
1299                 return (-1);
1300         }
1301 
1302         for (i = 0; i < min((*vtoc)->efi_nparts, V_NUMPAR); i++) {
1303                 (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
1304                 (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
1305                 (*vtoc)->efi_parts[i].p_start = 0;
1306                 (*vtoc)->efi_parts[i].p_size = 0;
1307         }
1308         /*
1309          * Make constants first
1310          * and variable partitions later
1311          */
1312 
1313         /* root partition - s0 128 MB */
1314         (*vtoc)->efi_parts[0].p_start = 34;
1315         (*vtoc)->efi_parts[0].p_size = 262144;
1316 
1317         /* partition - s1  128 MB */
1318         (*vtoc)->efi_parts[1].p_start = 262178;
1319         (*vtoc)->efi_parts[1].p_size = 262144;
1320 
1321         /* partition -s2 is NOT the Backup disk */
1322         (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
1323 
1324         /* partition -s6 /usr partition - HOG */
1325         (*vtoc)->efi_parts[6].p_start = 524322;
1326         (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
1327             - (1024 * 16);
1328 
1329         /* efi reserved partition - s9 16K */
1330         (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
1331         (*vtoc)->efi_parts[8].p_size = (1024 * 16);
1332         (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
1333         return (0);
1334 }