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,
 417                     vtoc.v_part[snum].p_start) != 0) {
 418                         return (ENOMEM);
 419                 }
 420 
 421                 if (nvlist_add_uint64(attrs, DM_SIZE,
 422                     vtoc.v_part[snum].p_size) != 0) {
 423                         return (ENOMEM);
 424                 }
 425 
 426                 if (nvlist_add_uint32(attrs, DM_TAG,
 427                     vtoc.v_part[snum].p_tag) != 0) {
 428                         return (ENOMEM);
 429                 }
 430 
 431                 if (nvlist_add_uint32(attrs, DM_FLAG,
 432                     vtoc.v_part[snum].p_flag) != 0) {
 433                         return (ENOMEM);
 434                 }
 435         } else { /* data_format == FMT_EFI */
 436                 if (nvlist_add_uint64(attrs, DM_START,
 437                     efip->efi_parts[snum].p_start) != 0) {
 438                         efi_free(efip);
 439                         return (ENOMEM);
 440                 }
 441 
 442                 if (nvlist_add_uint64(attrs, DM_SIZE,
 443                     efip->efi_parts[snum].p_size) != 0) {
 444                         efi_free(efip);
 445                         return (ENOMEM);
 446                 }
 447 
 448                 if (efip->efi_parts[snum].p_name[0] != 0) {
 449                         char    label[EFI_PART_NAME_LEN + 1];
 450 
 451                         (void) snprintf(label, sizeof (label), "%.*s",
 452                             EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
 453                         if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
 454                                 efi_free(efip);
 455                                 return (ENOMEM);
 456                         }
 457                 }
 458         }
 459 
 460         if (data_format == FMT_EFI) {
 461                 efi_free(efip);
 462         }
 463 
 464         if (inuse_mnt(dp->name, attrs, &error)) {
 465                 if (error != 0)
 466                         return (error);
 467         }
 468 
 469         if (fstat(fd, &buf) != -1) {
 470                 if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
 471                         return (ENOMEM);
 472                 }
 473         }
 474 
 475         /*
 476          * We need to open the cooked slice (not the raw one) to get the
 477          * correct devid.
 478          */
 479         cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);
 480 
 481         if (cooked_fd >= 0) {
 482                 int             no_mem = 0;
 483                 ddi_devid_t     devid;
 484 
 485                 if (devid_get(cooked_fd, &devid) == 0) {
 486                         char    *minor;
 487 
 488                         if (devid_get_minor_name(cooked_fd, &minor) == 0) {
 489                                 char    *devidstr;
 490 
 491                                 devidstr = devid_str_encode(devid, minor);
 492                                 if (devidstr != NULL) {
 493 
 494                                         if (nvlist_add_string(attrs,
 495                                             DM_DEVICEID, devidstr) != 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         devp = desc->p.disk->aliases->devpaths;
 547         for (cnt = 0; devp != NULL; devp = devp->next)
 548                 cnt++;
 549 
 550         /* allocate the array for the descriptors */
 551         slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
 552         if (slices == NULL) {
 553                 if (data_format == FMT_EFI) {
 554                         efi_free(efip);
 555                 }
 556                 *errp = ENOMEM;
 557                 return (NULL);
 558         }
 559 
 560         /* get the media name from the descriptor */
 561         if (desc->type == DM_MEDIA) {
 562                 media_name = desc->name;
 563         } else {
 564                 /* must be a DM_PARTITION */
 565                 media_name = desc->secondary_name;
 566         }
 567 
 568         pos = 0;
 569         for (devp = desc->p.disk->aliases->devpaths; devp != NULL;
 570             devp = devp->next) {
 571 
 572                 int             slice_num;
 573                 char    devpath[MAXPATHLEN];
 574 
 575                 slice_num = get_slice_num(devp);
 576                 /* can't get slicenum, so no need to keep trying the drive */
 577                 if (slice_num == -1) {
 578                         break;
 579                 }
 580 
 581                 if (data_format == FMT_VTOC) {
 582                         if (slice_num >= vtoc.v_nparts ||
 583                             vtoc.v_part[slice_num].p_size == 0) {
 584                                 continue;
 585                         }
 586                 } else { /* data_format == FMT_EFI */
 587                         if (slice_num >= efip->efi_nparts ||
 588                             efip->efi_parts[slice_num].p_size == 0) {
 589                                 continue;
 590                         }
 591                 }
 592 
 593                 slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
 594                 slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath,
 595                     media_name, errp);
 596                 if (*errp != 0) {
 597                         cache_free_descriptors(slices);
 598                         if (data_format == FMT_EFI) {
 599                                 efi_free(efip);
 600                         }
 601                         return (NULL);
 602                 }
 603                 pos++;
 604         }
 605         slices[pos] = NULL;
 606 
 607         if (data_format == FMT_EFI) {
 608                 efi_free(efip);
 609         }
 610 
 611         *errp = 0;
 612         return (slices);
 613 }
 614 
 615 static int
 616 get_slice_num(slice_t *devp)
 617 {
 618         /* check if we already determined the devpath slice number */
 619         if (devp->slice_num == -1) {
 620                 int             fd;
 621 
 622                 if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
 623                         struct dk_cinfo dkinfo;
 624                         if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
 625                                 devp->slice_num = dkinfo.dki_partition;
 626                         }
 627                         (void) close(fd);
 628                 }
 629         }
 630 
 631         return (devp->slice_num);
 632 }
 633 
 634 static int
 635 make_fixed_descriptors(disk_t *dp)
 636 {
 637         int             error = 0;
 638         alias_t         *ap;
 639         slice_t         *devp;
 640         char            mname[MAXPATHLEN];
 641         int             data_format = FMT_UNKNOWN;
 642         struct extvtoc  vtoc;
 643         struct dk_gpt   *efip;
 644 
 645         /* Just check the first drive name. */
 646         if ((ap = dp->aliases) == NULL) {
 647                 return (0);
 648         }
 649 
 650         mname[0] = 0;
 651         (void) media_read_name(dp, mname, sizeof (mname));
 652 
 653         for (devp = ap->devpaths; devp != NULL; devp = devp->next) {
 654                 int             slice_num;
 655                 char    devpath[MAXPATHLEN];
 656 
 657                 slice_num = get_slice_num(devp);
 658                 /* can't get slicenum, so no need to keep trying the drive */
 659                 if (slice_num == -1) {
 660                         break;
 661                 }
 662 
 663                 if (data_format == FMT_UNKNOWN) {
 664                         int     fd;
 665                         int     status;
 666 
 667                         if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
 668                                 if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 669                                         data_format = FMT_VTOC;
 670                                 } else if (status == VT_ENOTSUP &&
 671                                     efi_alloc_and_read(fd, &efip) >= 0) {
 672                                         data_format = FMT_EFI;
 673                                 }
 674                                 (void) close(fd);
 675                         }
 676                 }
 677 
 678                 /* can't get slice data, so no need to keep trying the drive */
 679                 if (data_format == FMT_UNKNOWN) {
 680                         break;
 681                 }
 682 
 683                 if (data_format == FMT_VTOC) {
 684                         if (slice_num >= vtoc.v_nparts ||
 685                             vtoc.v_part[slice_num].p_size == 0) {
 686                                 continue;
 687                         }
 688                 } else { /* data_format == FMT_EFI */
 689                         if (slice_num >= efip->efi_nparts ||
 690                             efip->efi_parts[slice_num].p_size == 0) {
 691                                 continue;
 692                         }
 693                 }
 694 
 695                 slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
 696                 cache_load_desc(DM_SLICE, dp, devpath, mname, &error);
 697                 if (error != 0) {
 698                         break;
 699                 }
 700         }
 701 
 702         if (data_format == FMT_EFI) {
 703                 efi_free(efip);
 704         }
 705 
 706         return (error);
 707 }
 708 
 709 /*
 710  * Just look for the name on the devpaths we have cached. Return 1 if we
 711  * find the name and the size of that slice is non-zero.
 712  */
 713 static int
 714 match_fixed_name(disk_t *diskp, char *name, int *errp)
 715 {
 716         slice_t         *dp = NULL;
 717         alias_t         *ap;
 718         int             slice_num;
 719         int             fd;
 720         int             status;
 721         int             data_format = FMT_UNKNOWN;
 722         struct extvtoc  vtoc;
 723         struct dk_gpt   *efip;
 724 
 725         ap = diskp->aliases;
 726         while (ap != NULL) {
 727                 slice_t *devp;
 728 
 729                 devp = ap->devpaths;
 730                 while (devp != NULL) {
 731                         char    path[MAXPATHLEN];
 732 
 733                         slice_rdsk2dsk(devp->devpath, path, sizeof (path));
 734                         if (libdiskmgt_str_eq(path, name)) {
 735                                 /* found it */
 736                                 dp = devp;
 737                                 break;
 738                         }
 739 
 740                         devp = devp->next;
 741                 }
 742 
 743                 if (dp != NULL) {
 744                         break;
 745                 }
 746 
 747                 ap = ap->next;
 748         }
 749 
 750         if (dp == NULL) {
 751                 *errp = 0;
 752                 return (0);
 753         }
 754 
 755         /*
 756          * If we found a match on the name we now have to check that this
 757          * slice really exists (non-0 size).
 758          */
 759 
 760         slice_num = get_slice_num(dp);
 761         /* can't get slicenum, so no slice */
 762         if (slice_num == -1) {
 763                 *errp = ENODEV;
 764                 return (1);
 765         }
 766 
 767         if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) {
 768                 *errp = ENODEV;
 769                 return (1);
 770         }
 771 
 772         if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
 773                 data_format = FMT_VTOC;
 774         } else if (status == VT_ENOTSUP) {
 775                 status = efi_alloc_and_read(fd, &efip);
 776                 if (status >= 0) {
 777                         data_format = FMT_EFI;
 778                 } else if (status == VT_ERROR && errno == ENOTTY) {
 779                         *errp = 0;
 780                         return (1);
 781                 }
 782         } else {
 783                 (void) close(fd);
 784                 *errp = ENODEV;
 785                 return (1);
 786         }
 787         (void) close(fd);
 788 
 789         if (data_format == FMT_VTOC) {
 790                 if (slice_num < vtoc.v_nparts &&
 791                     vtoc.v_part[slice_num].p_size > 0) {
 792                         *errp = 0;
 793                         return (1);
 794                 }
 795         } else { /* data_format == FMT_EFI */
 796                 if (slice_num < efip->efi_nparts &&
 797                     efip->efi_parts[slice_num].p_size > 0) {
 798                         efi_free(efip);
 799                         *errp = 0;
 800                         return (1);
 801                 }
 802                 efi_free(efip);
 803         }
 804 
 805         *errp = ENODEV;
 806         return (1);
 807 }