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