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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2017 Nexenta Systems, Inc.
  29  */
  30 
  31 #include <fcntl.h>
  32 #include <libdevinfo.h>
  33 #include <stdio.h>
  34 #include <stdlib.h>
  35 #include <string.h>
  36 #include <dirent.h>
  37 #include <sys/dkio.h>
  38 #include <sys/stat.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/types.h>
  41 #include <sys/vtoc.h>
  42 #include <unistd.h>
  43 #include <devid.h>
  44 #include <dirent.h>
  45 #include <sys/dktp/fdisk.h>
  46 #include <sys/efi_partition.h>
  47 
  48 #include "libdiskmgt.h"
  49 #include "disks_private.h"
  50 #include "partition.h"
  51 #ifndef VT_ENOTSUP
  52 #define VT_ENOTSUP      (-5)
  53 #endif
  54 
  55 #define FMT_UNKNOWN     0
  56 #define FMT_VTOC        1
  57 #define FMT_EFI         2
  58 
  59 typedef int (*detectorp)(char *, nvlist_t *, int *);
  60 
  61 static detectorp detectors[] = {
  62         inuse_mnt,
  63         inuse_active_zpool,
  64         inuse_lu,
  65         inuse_dump,
  66         inuse_vxvm,
  67         inuse_exported_zpool,
  68         inuse_fs,  /* fs should always be last */
  69         NULL
  70 };
  71 
  72 static int      add_inuse(char *name, nvlist_t *attrs);
  73 static int      desc_ok(descriptor_t *dp);
  74 static void     dsk2rdsk(char *dsk, char *rdsk, int size);
  75 static int      get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs);
  76 static descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp);
  77 static int      get_slice_num(slice_t *devp);
  78 static int      match_fixed_name(disk_t *dp, char *name, int *errp);
  79 static int      make_fixed_descriptors(disk_t *dp);
  80 
  81 descriptor_t **
  82 slice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
  83     int *errp)
  84 {
  85         if (!desc_ok(desc)) {
  86             *errp = ENODEV;
  87             return (NULL);
  88         }
  89 
  90         switch (type) {
  91         case DM_MEDIA:
  92             return (media_get_assocs(desc, errp));
  93         case DM_PARTITION:
  94             return (partition_get_assocs(desc, errp));
  95         }
  96 
  97         *errp = EINVAL;
  98         return (NULL);
  99 }
 100 
 101 /*
 102  * This is called by media/partition to get the slice descriptors for the given
 103  * media/partition descriptor.
 104  * For media, just get the slices, but for a partition, it must be a solaris
 105  * partition and if there are active partitions, it must be the active one.
 106  */
 107 descriptor_t **
 108 slice_get_assocs(descriptor_t *desc, int *errp)
 109 {
 110         /* Just check the first drive name. */
 111         if (desc->p.disk->aliases == NULL) {
 112             *errp = 0;
 113             return (libdiskmgt_empty_desc_array(errp));
 114         }
 115 
 116         return (get_fixed_assocs(desc, errp));
 117 }
 118 
 119 nvlist_t *
 120 slice_get_attributes(descriptor_t *dp, int *errp)
 121 {
 122         nvlist_t        *attrs = NULL;
 123         int             fd;
 124         char            devpath[MAXPATHLEN];
 125 
 126         if (!desc_ok(dp)) {
 127             *errp = ENODEV;
 128             return (NULL);
 129         }
 130 
 131         if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
 132             *errp = ENOMEM;
 133             return (NULL);
 134         }
 135 
 136         /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
 137         dsk2rdsk(dp->name, devpath, sizeof (devpath));
 138         fd = open(devpath, O_RDONLY|O_NDELAY);
 139 
 140         if ((*errp = get_attrs(dp, fd, attrs)) != 0) {
 141             nvlist_free(attrs);
 142             attrs = NULL;
 143         }
 144 
 145         if (fd >= 0) {
 146             (void) close(fd);
 147         }
 148 
 149         return (attrs);
 150 }
 151 
 152 /*
 153  * Look for the slice by the slice devpath.
 154  */
 155 descriptor_t *
 156 slice_get_descriptor_by_name(char *name, int *errp)
 157 {
 158         int             found = 0;
 159         disk_t          *dp;
 160 
 161         for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) {
 162                 found = match_fixed_name(dp, name, errp);
 163 
 164                 if (found) {
 165                         char    mname[MAXPATHLEN];
 166 
 167                         if (*errp != 0) {
 168                             return (NULL);
 169                         }
 170 
 171                         mname[0] = 0;
 172                         (void) media_read_name(dp, mname, sizeof (mname));
 173 
 174                         return (cache_get_desc(DM_SLICE, dp, name, mname,
 175                             errp));
 176                 }
 177         }
 178 
 179         *errp = ENODEV;
 180         return (NULL);
 181 }
 182 
 183 /* ARGSUSED */
 184 descriptor_t **
 185 slice_get_descriptors(int filter[], int *errp)
 186 {
 187         return (cache_get_descriptors(DM_SLICE, errp));
 188 }
 189 
 190 char *
 191 slice_get_name(descriptor_t *desc)
 192 {
 193         return (desc->name);
 194 }
 195 
 196 nvlist_t *
 197 slice_get_stats(descriptor_t *dp, int stat_type, int *errp)
 198 {
 199         nvlist_t        *stats;
 200 
 201         if (stat_type != DM_SLICE_STAT_USE) {
 202             *errp = EINVAL;
 203             return (NULL);
 204         }
 205 
 206         *errp = 0;
 207 
 208         if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) {
 209             *errp = ENOMEM;
 210             return (NULL);
 211         }
 212 
 213         if ((*errp = add_inuse(dp->name, stats)) != 0) {
 214                 nvlist_free(stats);
 215                 return (NULL);
 216         }
 217 
 218         return (stats);
 219 }
 220 
 221 /*
 222  * A slice descriptor points to a disk, the name is the devpath and the
 223  * secondary name is the media name.
 224  */
 225 int
 226 slice_make_descriptors()
 227 {
 228         disk_t          *dp;
 229 
 230         dp = cache_get_disklist();
 231         while (dp != NULL) {
 232             int error;
 233 
 234             error = make_fixed_descriptors(dp);
 235             if (error != 0) {
 236                 return (error);
 237             }
 238 
 239             dp = dp->next;
 240         }
 241 
 242         return (0);
 243 }
 244 
 245 /* convert rdsk paths to dsk paths */
 246 void
 247 slice_rdsk2dsk(char *rdsk, char *dsk, int size)
 248 {
 249         char    *strp;
 250 
 251         (void) strlcpy(dsk, rdsk, size);
 252 
 253         if ((strp = strstr(dsk, "/rdsk/")) == NULL) {
 254             /* not rdsk, check for floppy */
 255             strp = strstr(dsk, "/rdiskette");
 256         }
 257 
 258         if (strp != NULL) {
 259             strp++;     /* move ptr to the r in rdsk or rdiskette */
 260 
 261             /* move the succeeding chars over by one */
 262             do {
 263                 *strp = *(strp + 1);
 264                 strp++;
 265             } while (*strp);
 266         }
 267 }
 268 
 269 /*
 270  * Check if/how the slice is used.
 271  */
 272 static int
 273 add_inuse(char *name, nvlist_t *attrs)
 274 {
 275         int     i;
 276         int     error;
 277 
 278         for (i = 0; detectors[i] != NULL; i ++) {
 279             if (detectors[i](name, attrs, &error) || error != 0) {
 280                 if (error != 0) {
 281                     return (error);
 282                 }
 283                 break;
 284             }
 285         }
 286 
 287         return (0);
 288 }
 289 
 290 /* return 1 if the slice descriptor is still valid, 0 if not. */
 291 static int
 292 desc_ok(descriptor_t *dp)
 293 {
 294         /* First verify the media name for removable media */
 295         if (dp->p.disk->removable) {
 296             char        mname[MAXPATHLEN];
 297 
 298             if (!media_read_name(dp->p.disk, mname, sizeof (mname))) {
 299                 return (0);
 300             }
 301 
 302             if (mname[0] == 0) {
 303                 return (libdiskmgt_str_eq(dp->secondary_name, NULL));
 304             } else {
 305                 return (libdiskmgt_str_eq(dp->secondary_name, mname));
 306             }
 307         }
 308 
 309         /*
 310          * We could verify the slice is still there, but other code down the
 311          * line already does these checks (e.g. see get_attrs).
 312          */
 313 
 314         return (1);
 315 }
 316 
 317 /* convert dsk paths to rdsk paths */
 318 static void
 319 dsk2rdsk(char *dsk, char *rdsk, int size)
 320 {
 321         char    *slashp;
 322         size_t  len;
 323 
 324         (void) strlcpy(rdsk, dsk, size);
 325 
 326         /* make sure there is enough room to add the r to dsk */
 327         len = strlen(dsk);
 328         if (len + 2 > size) {
 329             return;
 330         }
 331 
 332         if ((slashp = strstr(rdsk, "/dsk/")) == NULL) {
 333             /* not dsk, check for floppy */
 334             slashp = strstr(rdsk, "/diskette");
 335         }
 336 
 337         if (slashp != NULL) {
 338             char        *endp;
 339 
 340             endp = rdsk + len;  /* point to terminating 0 */
 341             /* move the succeeding chars over by one */
 342             do {
 343                 *(endp + 1) = *endp;
 344                 endp--;
 345             } while (endp != slashp);
 346 
 347             *(endp + 1) = 'r';
 348         }
 349 }
 350 
 351 static int
 352 get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs)
 353 {
 354         struct dk_minfo minfo;
 355         int             status;
 356         int             data_format = FMT_UNKNOWN;
 357         int             snum = -1;
 358         int             error;
 359         struct extvtoc  vtoc;
 360         struct dk_gpt   *efip;
 361         struct dk_cinfo dkinfo;
 362         int             cooked_fd;
 363         struct stat     buf;
 364 
 365         if (fd < 0) {
 366             return (ENODEV);
 367         }
 368 
 369         /* First make sure media is inserted and spun up. */
 370         if (!media_read_info(fd, &minfo)) {
 371             return (ENODEV);
 372         }
 373 
 374         if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 375             data_format = FMT_VTOC;
 376         } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
 377             data_format = FMT_EFI;
 378             if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
 379                 efi_free(efip);
 380                 return (ENOMEM);
 381             }
 382         }
 383 
 384         if (data_format == FMT_UNKNOWN) {
 385             return (ENODEV);
 386         }
 387 
 388         if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
 389             snum = dkinfo.dki_partition;
 390         }
 391 
 392         /* check the slice */
 393         if (data_format == FMT_VTOC) {
 394             if (snum < 0 || snum >= vtoc.v_nparts ||
 395                 vtoc.v_part[snum].p_size == 0) {
 396                 return (ENODEV);
 397             }
 398         } else { /* data_format == FMT_EFI */
 399             if (snum < 0 || snum >= efip->efi_nparts ||
 400                 efip->efi_parts[snum].p_size == 0) {
 401                 efi_free(efip);
 402                 return (ENODEV);
 403             }
 404         }
 405 
 406         /* the slice exists */
 407 
 408         if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) {
 409             if (data_format == FMT_EFI) {
 410                 efi_free(efip);
 411             }
 412             return (ENOMEM);
 413         }
 414 
 415         if (data_format == FMT_VTOC) {
 416             if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start)
 417                 != 0) {
 418                 return (ENOMEM);
 419             }
 420 
 421             if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size)
 422                 != 0) {
 423                 return (ENOMEM);
 424             }
 425 
 426             if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag)
 427                 != 0) {
 428                 return (ENOMEM);
 429             }
 430 
 431             if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag)
 432                 != 0) {
 433                 return (ENOMEM);
 434             }
 435 
 436         } else { /* data_format == FMT_EFI */
 437             if (nvlist_add_uint64(attrs, DM_START,
 438                 efip->efi_parts[snum].p_start) != 0) {
 439                 efi_free(efip);
 440                 return (ENOMEM);
 441             }
 442 
 443             if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size)
 444                 != 0) {
 445                 efi_free(efip);
 446                 return (ENOMEM);
 447             }
 448 
 449             if (efip->efi_parts[snum].p_name[0] != 0) {
 450                 char    label[EFI_PART_NAME_LEN + 1];
 451 
 452                 (void) snprintf(label, sizeof (label), "%.*s",
 453                     EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
 454                 if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
 455                     efi_free(efip);
 456                     return (ENOMEM);
 457                 }
 458             }
 459         }
 460 
 461         if (data_format == FMT_EFI) {
 462             efi_free(efip);
 463         }
 464 
 465         if (inuse_mnt(dp->name, attrs, &error)) {
 466             if (error != 0)
 467                 return (error);
 468         }
 469 
 470         if (fstat(fd, &buf) != -1) {
 471             if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
 472                 return (ENOMEM);
 473             }
 474         }
 475 
 476         /*
 477          * We need to open the cooked slice (not the raw one) to get the
 478          * correct devid.
 479          */
 480         cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);
 481 
 482         if (cooked_fd >= 0) {
 483             int         no_mem = 0;
 484             ddi_devid_t devid;
 485 
 486             if (devid_get(cooked_fd, &devid) == 0) {
 487                 char    *minor;
 488 
 489                 if (devid_get_minor_name(cooked_fd, &minor) == 0) {
 490                     char        *devidstr;
 491 
 492                     if ((devidstr = devid_str_encode(devid, minor)) != 0) {
 493 
 494                         if (nvlist_add_string(attrs, DM_DEVICEID, devidstr)
 495                             != 0) {
 496                             no_mem = 1;
 497                         }
 498 
 499                         devid_str_free(devidstr);
 500                     }
 501                     devid_str_free(minor);
 502                 }
 503                 devid_free(devid);
 504             }
 505             (void) close(cooked_fd);
 506 
 507             if (no_mem) {
 508                 return (ENOMEM);
 509             }
 510         }
 511 
 512         return (0);
 513 }
 514 
 515 static descriptor_t **
 516 get_fixed_assocs(descriptor_t *desc, int *errp)
 517 {
 518         int             fd;
 519         int             status;
 520         int             data_format = FMT_UNKNOWN;
 521         int             cnt;
 522         struct extvtoc  vtoc;
 523         struct dk_gpt   *efip;
 524         int             pos;
 525         char            *media_name = NULL;
 526         slice_t         *devp;
 527         descriptor_t    **slices;
 528 
 529         if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) {
 530             *errp = ENODEV;
 531             return (NULL);
 532         }
 533 
 534         if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 535             data_format = FMT_VTOC;
 536         } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
 537             data_format = FMT_EFI;
 538         } else {
 539             (void) close(fd);
 540             *errp = 0;
 541             return (libdiskmgt_empty_desc_array(errp));
 542         }
 543         (void) close(fd);
 544 
 545         /* count the number of slices */
 546         for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL;
 547             devp = devp->next, cnt++);
 548 
 549         /* allocate the array for the descriptors */
 550         slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
 551         if (slices == NULL) {
 552             if (data_format == FMT_EFI) {
 553                 efi_free(efip);
 554             }
 555             *errp = ENOMEM;
 556             return (NULL);
 557         }
 558 
 559         /* get the media name from the descriptor */
 560         if (desc->type == DM_MEDIA) {
 561             media_name = desc->name;
 562         } else {
 563             /* must be a DM_PARTITION */
 564             media_name = desc->secondary_name;
 565         }
 566 
 567         pos = 0;
 568         for (devp = desc->p.disk->aliases->devpaths; devp != NULL;
 569             devp = devp->next) {
 570 
 571             int         slice_num;
 572             char        devpath[MAXPATHLEN];
 573 
 574             slice_num = get_slice_num(devp);
 575             /* can't get slicenum, so no need to keep trying the drive */
 576             if (slice_num == -1) {
 577                 break;
 578             }
 579 
 580             if (data_format == FMT_VTOC) {
 581                 if (slice_num >= vtoc.v_nparts ||
 582                     vtoc.v_part[slice_num].p_size == 0) {
 583                     continue;
 584                 }
 585             } else { /* data_format == FMT_EFI */
 586                 if (slice_num >= efip->efi_nparts ||
 587                     efip->efi_parts[slice_num].p_size == 0) {
 588                     continue;
 589                 }
 590             }
 591 
 592             slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
 593             slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath,
 594                 media_name, errp);
 595             if (*errp != 0) {
 596                 cache_free_descriptors(slices);
 597                 if (data_format == FMT_EFI) {
 598                     efi_free(efip);
 599                 }
 600                 return (NULL);
 601             }
 602             pos++;
 603         }
 604         slices[pos] = NULL;
 605 
 606         if (data_format == FMT_EFI) {
 607             efi_free(efip);
 608         }
 609 
 610         *errp = 0;
 611         return (slices);
 612 }
 613 
 614 static int
 615 get_slice_num(slice_t *devp)
 616 {
 617         /* check if we already determined the devpath slice number */
 618         if (devp->slice_num == -1) {
 619             int         fd;
 620 
 621             if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
 622                 struct dk_cinfo dkinfo;
 623                 if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
 624                     devp->slice_num = dkinfo.dki_partition;
 625                 }
 626                 (void) close(fd);
 627             }
 628         }
 629 
 630         return (devp->slice_num);
 631 }
 632 
 633 static int
 634 make_fixed_descriptors(disk_t *dp)
 635 {
 636         int             error = 0;
 637         alias_t         *ap;
 638         slice_t         *devp;
 639         char            mname[MAXPATHLEN];
 640         int             data_format = FMT_UNKNOWN;
 641         struct extvtoc  vtoc;
 642         struct dk_gpt   *efip;
 643 
 644         /* Just check the first drive name. */
 645         if ((ap = dp->aliases) == NULL) {
 646             return (0);
 647         }
 648 
 649         mname[0] = 0;
 650         (void) media_read_name(dp, mname, sizeof (mname));
 651 
 652         for (devp = ap->devpaths; devp != NULL; devp = devp->next) {
 653             int         slice_num;
 654             char        devpath[MAXPATHLEN];
 655 
 656             slice_num = get_slice_num(devp);
 657             /* can't get slicenum, so no need to keep trying the drive */
 658             if (slice_num == -1) {
 659                 break;
 660             }
 661 
 662             if (data_format == FMT_UNKNOWN) {
 663                 int     fd;
 664                 int     status;
 665 
 666                 if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
 667                     if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 668                         data_format = FMT_VTOC;
 669                     } else if (status == VT_ENOTSUP &&
 670                         efi_alloc_and_read(fd, &efip) >= 0) {
 671                         data_format = FMT_EFI;
 672                     }
 673                     (void) close(fd);
 674                 }
 675             }
 676 
 677             /* can't get slice data, so no need to keep trying the drive */
 678             if (data_format == FMT_UNKNOWN) {
 679                 break;
 680             }
 681 
 682             if (data_format == FMT_VTOC) {
 683                 if (slice_num >= vtoc.v_nparts ||
 684                     vtoc.v_part[slice_num].p_size == 0) {
 685                     continue;
 686                 }
 687             } else { /* data_format == FMT_EFI */
 688                 if (slice_num >= efip->efi_nparts ||
 689                     efip->efi_parts[slice_num].p_size == 0) {
 690                     continue;
 691                 }
 692             }
 693 
 694             slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
 695             cache_load_desc(DM_SLICE, dp, devpath, mname, &error);
 696             if (error != 0) {
 697                 break;
 698             }
 699         }
 700 
 701         if (data_format == FMT_EFI) {
 702             efi_free(efip);
 703         }
 704 
 705         return (error);
 706 }
 707 
 708 /*
 709  * Just look for the name on the devpaths we have cached. Return 1 if we
 710  * find the name and the size of that slice is non-zero.
 711  */
 712 static int
 713 match_fixed_name(disk_t *diskp, char *name, int *errp)
 714 {
 715         slice_t         *dp = NULL;
 716         alias_t         *ap;
 717         int             slice_num;
 718         int             fd;
 719         int             status;
 720         int             data_format = FMT_UNKNOWN;
 721         struct extvtoc  vtoc;
 722         struct dk_gpt   *efip;
 723 
 724         ap = diskp->aliases;
 725         while (ap != NULL) {
 726             slice_t     *devp;
 727 
 728             devp = ap->devpaths;
 729             while (devp != NULL) {
 730                 char    path[MAXPATHLEN];
 731 
 732                 slice_rdsk2dsk(devp->devpath, path, sizeof (path));
 733                 if (libdiskmgt_str_eq(path, name)) {
 734                     /* found it */
 735                     dp = devp;
 736                     break;
 737                 }
 738 
 739                 devp = devp->next;
 740             }
 741 
 742             if (dp != NULL) {
 743                 break;
 744             }
 745 
 746             ap = ap->next;
 747         }
 748 
 749         if (dp == NULL) {
 750             *errp = 0;
 751             return (0);
 752         }
 753 
 754         /*
 755          * If we found a match on the name we now have to check that this
 756          * slice really exists (non-0 size).
 757          */
 758 
 759         slice_num = get_slice_num(dp);
 760         /* can't get slicenum, so no slice */
 761         if (slice_num == -1) {
 762             *errp = ENODEV;
 763             return (1);
 764         }
 765 
 766         if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) {
 767             *errp = ENODEV;
 768             return (1);
 769         }
 770 
 771         if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 772             data_format = FMT_VTOC;
 773         } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
 774             data_format = FMT_EFI;
 775         } else {
 776             (void) close(fd);
 777             *errp = ENODEV;
 778             return (1);
 779         }
 780         (void) close(fd);
 781 
 782         if (data_format == FMT_VTOC) {
 783             if (slice_num < vtoc.v_nparts &&
 784                 vtoc.v_part[slice_num].p_size > 0) {
 785                 *errp = 0;
 786                 return (1);
 787             }
 788         } else { /* data_format == FMT_EFI */
 789             if (slice_num < efip->efi_nparts &&
 790                 efip->efi_parts[slice_num].p_size > 0) {
 791                 efi_free(efip);
 792                 *errp = 0;
 793                 return (1);
 794             }
 795             efi_free(efip);
 796         }
 797 
 798         *errp = ENODEV;
 799         return (1);
 800 }