xref: /illumos-gate/usr/src/lib/libdiskmgt/common/slice.c (revision 8c69cc8fbe729fa7b091e901c4b50508ccc6bb33)
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 }
801