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 **
slice_get_assoc_descriptors(descriptor_t * desc,dm_desc_type_t type,int * errp)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 **
slice_get_assocs(descriptor_t * desc,int * errp)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 *
slice_get_attributes(descriptor_t * dp,int * errp)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 *
slice_get_descriptor_by_name(char * name,int * errp)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 **
slice_get_descriptors(int filter[],int * errp)185 slice_get_descriptors(int filter[], int *errp)
186 {
187 	return (cache_get_descriptors(DM_SLICE, errp));
188 }
189 
190 char *
slice_get_name(descriptor_t * desc)191 slice_get_name(descriptor_t *desc)
192 {
193 	return (desc->name);
194 }
195 
196 nvlist_t *
slice_get_stats(descriptor_t * dp,int stat_type,int * errp)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
slice_make_descriptors()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
slice_rdsk2dsk(char * rdsk,char * dsk,int size)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
add_inuse(char * name,nvlist_t * attrs)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
desc_ok(descriptor_t * dp)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
dsk2rdsk(char * dsk,char * rdsk,int size)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
get_attrs(descriptor_t * dp,int fd,nvlist_t * attrs)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 **
get_fixed_assocs(descriptor_t * desc,int * errp)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
get_slice_num(slice_t * devp)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
make_fixed_descriptors(disk_t * dp)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
match_fixed_name(disk_t * diskp,char * name,int * errp)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 }
808