10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1352Seschrock  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <fcntl.h>
300Sstevel@tonic-gate #include <libdevinfo.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <dirent.h>
350Sstevel@tonic-gate #include <sys/dkio.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/sunddi.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/vtoc.h>
400Sstevel@tonic-gate #include <unistd.h>
410Sstevel@tonic-gate #include <devid.h>
420Sstevel@tonic-gate #include <dirent.h>
430Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
440Sstevel@tonic-gate #include <sys/efi_partition.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include "libdiskmgt.h"
470Sstevel@tonic-gate #include "disks_private.h"
480Sstevel@tonic-gate #include "partition.h"
490Sstevel@tonic-gate #ifndef VT_ENOTSUP
500Sstevel@tonic-gate #define	VT_ENOTSUP	(-5)
510Sstevel@tonic-gate #endif
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	FMT_UNKNOWN	0
540Sstevel@tonic-gate #define	FMT_VTOC	1
550Sstevel@tonic-gate #define	FMT_EFI		2
560Sstevel@tonic-gate 
57*1352Seschrock typedef int (*detectorp)(char *, nvlist_t *, int *);
58*1352Seschrock 
59*1352Seschrock static detectorp detectors[] = {
60*1352Seschrock 	inuse_mnt,
61*1352Seschrock 	inuse_svm,
62*1352Seschrock 	inuse_active_zpool,
63*1352Seschrock 	inuse_lu,
64*1352Seschrock 	inuse_dump,
65*1352Seschrock 	inuse_vxvm,
66*1352Seschrock 	inuse_exported_zpool,
67*1352Seschrock 	inuse_fs,  /* fs should always be last */
68*1352Seschrock 	NULL
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static int	add_inuse(char *name, nvlist_t *attrs);
720Sstevel@tonic-gate static int	desc_ok(descriptor_t *dp);
730Sstevel@tonic-gate static void	dsk2rdsk(char *dsk, char *rdsk, int size);
740Sstevel@tonic-gate static int	get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs);
750Sstevel@tonic-gate static descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp);
760Sstevel@tonic-gate static descriptor_t **get_removable_assocs(descriptor_t *desc, char *volm_path,
770Sstevel@tonic-gate 		    int *errp);
780Sstevel@tonic-gate static int	get_slice_num(slice_t *devp);
790Sstevel@tonic-gate static int	match_fixed_name(disk_t *dp, char *name, int *errp);
800Sstevel@tonic-gate static int	match_removable_name(disk_t *dp, char *name, int *errp);
810Sstevel@tonic-gate static int	make_fixed_descriptors(disk_t *dp);
820Sstevel@tonic-gate static int	make_removable_descriptors(disk_t *dp);
830Sstevel@tonic-gate static int	make_volm_dir_descriptors(disk_t *dp, int fd,
840Sstevel@tonic-gate 		    char *volm_path);
850Sstevel@tonic-gate static int	num_removable_slices(int fd, struct stat *bufp,
860Sstevel@tonic-gate 		    char *volm_path);
870Sstevel@tonic-gate 
880Sstevel@tonic-gate descriptor_t **
890Sstevel@tonic-gate slice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
900Sstevel@tonic-gate     int *errp)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	if (!desc_ok(desc)) {
930Sstevel@tonic-gate 	    *errp = ENODEV;
940Sstevel@tonic-gate 	    return (NULL);
950Sstevel@tonic-gate 	}
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	switch (type) {
980Sstevel@tonic-gate 	case DM_MEDIA:
990Sstevel@tonic-gate 	    return (media_get_assocs(desc, errp));
1000Sstevel@tonic-gate 	case DM_PARTITION:
1010Sstevel@tonic-gate 	    return (partition_get_assocs(desc, errp));
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	*errp = EINVAL;
1050Sstevel@tonic-gate 	return (NULL);
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * This is called by media/partition to get the slice descriptors for the given
1100Sstevel@tonic-gate  * media/partition descriptor.
1110Sstevel@tonic-gate  * For media, just get the slices, but for a partition, it must be a solaris
1120Sstevel@tonic-gate  * partition and if there are active partitions, it must be the active one.
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate descriptor_t **
1150Sstevel@tonic-gate slice_get_assocs(descriptor_t *desc, int *errp)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	int		under_volm = 0;
1180Sstevel@tonic-gate 	char		volm_path[MAXPATHLEN];
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Just check the first drive name. */
1210Sstevel@tonic-gate 	if (desc->p.disk->aliases == NULL) {
1220Sstevel@tonic-gate 	    *errp = 0;
1230Sstevel@tonic-gate 	    return (libdiskmgt_empty_desc_array(errp));
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (desc->p.disk->removable) {
1270Sstevel@tonic-gate 	    if ((under_volm = media_get_volm_path(desc->p.disk, volm_path,
1280Sstevel@tonic-gate 		sizeof (volm_path)))) {
1290Sstevel@tonic-gate 		if (volm_path[0] == 0) {
1300Sstevel@tonic-gate 		    /* no media */
1310Sstevel@tonic-gate 		    *errp = 0;
1320Sstevel@tonic-gate 		    return (libdiskmgt_empty_desc_array(errp));
1330Sstevel@tonic-gate 		}
1340Sstevel@tonic-gate 	    }
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	if (desc->p.disk->removable) {
1380Sstevel@tonic-gate 	    if (under_volm) {
1390Sstevel@tonic-gate 		return (get_removable_assocs(desc, volm_path, errp));
1400Sstevel@tonic-gate 	    } else {
1410Sstevel@tonic-gate 		return (get_fixed_assocs(desc, errp));
1420Sstevel@tonic-gate 	    }
1430Sstevel@tonic-gate 	} else {
1440Sstevel@tonic-gate 	    return (get_fixed_assocs(desc, errp));
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate nvlist_t *
1490Sstevel@tonic-gate slice_get_attributes(descriptor_t *dp, int *errp)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
1520Sstevel@tonic-gate 	int		fd;
1530Sstevel@tonic-gate 	char		devpath[MAXPATHLEN];
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	if (!desc_ok(dp)) {
1560Sstevel@tonic-gate 	    *errp = ENODEV;
1570Sstevel@tonic-gate 	    return (NULL);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
1610Sstevel@tonic-gate 	    *errp = ENOMEM;
1620Sstevel@tonic-gate 	    return (NULL);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	/* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
1660Sstevel@tonic-gate 	dsk2rdsk(dp->name, devpath, sizeof (devpath));
1670Sstevel@tonic-gate 	fd = open(devpath, O_RDONLY|O_NDELAY);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if ((*errp = get_attrs(dp, fd, attrs)) != 0) {
1700Sstevel@tonic-gate 	    nvlist_free(attrs);
1710Sstevel@tonic-gate 	    attrs = NULL;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if (fd >= 0) {
1750Sstevel@tonic-gate 	    (void) close(fd);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	return (attrs);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * Look for the slice by the slice devpath.
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate descriptor_t *
1850Sstevel@tonic-gate slice_get_descriptor_by_name(char *name, int *errp)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	int		found = 0;
1880Sstevel@tonic-gate 	disk_t		*dp;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) {
1910Sstevel@tonic-gate 	    if (dp->removable) {
1920Sstevel@tonic-gate 		found = match_removable_name(dp, name, errp);
1930Sstevel@tonic-gate 	    } else {
1940Sstevel@tonic-gate 		found = match_fixed_name(dp, name, errp);
1950Sstevel@tonic-gate 	    }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	    if (found) {
1980Sstevel@tonic-gate 		char	mname[MAXPATHLEN];
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 		if (*errp != 0) {
2010Sstevel@tonic-gate 		    return (NULL);
2020Sstevel@tonic-gate 		}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 		mname[0] = 0;
2050Sstevel@tonic-gate 		(void) media_read_name(dp, mname, sizeof (mname));
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 		return (cache_get_desc(DM_SLICE, dp, name, mname, errp));
2080Sstevel@tonic-gate 	    }
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	*errp = ENODEV;
2120Sstevel@tonic-gate 	return (NULL);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /* ARGSUSED */
2160Sstevel@tonic-gate descriptor_t **
2170Sstevel@tonic-gate slice_get_descriptors(int filter[], int *errp)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	return (cache_get_descriptors(DM_SLICE, errp));
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate char *
2230Sstevel@tonic-gate slice_get_name(descriptor_t *desc)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	return (desc->name);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate nvlist_t *
2290Sstevel@tonic-gate slice_get_stats(descriptor_t *dp, int stat_type, int *errp)
2300Sstevel@tonic-gate {
2310Sstevel@tonic-gate 	nvlist_t	*stats;
2320Sstevel@tonic-gate 	char		*str;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if (stat_type != DM_SLICE_STAT_USE) {
2350Sstevel@tonic-gate 	    *errp = EINVAL;
2360Sstevel@tonic-gate 	    return (NULL);
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	*errp = 0;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) {
2420Sstevel@tonic-gate 	    *errp = ENOMEM;
2430Sstevel@tonic-gate 	    return (NULL);
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if ((*errp = add_inuse(dp->name, stats)) != 0) {
2470Sstevel@tonic-gate 	    return (NULL);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	/* if no cluster use, check for a use of the local name */
2510Sstevel@tonic-gate 	if (nvlist_lookup_string(stats, DM_USED_BY, &str) != 0) {
2520Sstevel@tonic-gate 	    disk_t	*diskp;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	    diskp = dp->p.disk;
2550Sstevel@tonic-gate 	    if (diskp->aliases != NULL && diskp->aliases->cluster) {
2560Sstevel@tonic-gate 		slice_t		*sp;
2570Sstevel@tonic-gate 		int		snum = -1;
2580Sstevel@tonic-gate 		struct dk_minfo	minfo;
2590Sstevel@tonic-gate 		struct dk_cinfo	dkinfo;
2600Sstevel@tonic-gate 		char		devpath[MAXPATHLEN];
2610Sstevel@tonic-gate 		int		fd;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
2640Sstevel@tonic-gate 		dsk2rdsk(dp->name, devpath, sizeof (devpath));
2650Sstevel@tonic-gate 		fd = open(devpath, O_RDONLY|O_NDELAY);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 		if (fd >= 0 && media_read_info(fd, &minfo) &&
2680Sstevel@tonic-gate 		    ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
2690Sstevel@tonic-gate 		    snum = dkinfo.dki_partition;
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		if (fd >= 0) {
2730Sstevel@tonic-gate 		    (void) close(fd);
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 		if (snum >= 0) {
2770Sstevel@tonic-gate 		    for (sp = diskp->aliases->orig_paths; sp != NULL;
2780Sstevel@tonic-gate 			sp = sp->next) {
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 			if (sp->slice_num == snum) {
2810Sstevel@tonic-gate 			    char	localpath[MAXPATHLEN];
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 			    slice_rdsk2dsk(sp->devpath, localpath,
2840Sstevel@tonic-gate 				sizeof (localpath));
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 			    if ((*errp = add_inuse(localpath, stats)) != 0) {
2870Sstevel@tonic-gate 				return (NULL);
2880Sstevel@tonic-gate 			    }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 			    break;
2910Sstevel@tonic-gate 			}
2920Sstevel@tonic-gate 		    }
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 	    }
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	return (stats);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate /*
3010Sstevel@tonic-gate  * A slice descriptor points to a disk, the name is the devpath and the
3020Sstevel@tonic-gate  * secondary name is the media name.
3030Sstevel@tonic-gate  */
3040Sstevel@tonic-gate int
3050Sstevel@tonic-gate slice_make_descriptors()
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	disk_t		*dp;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	dp = cache_get_disklist();
3100Sstevel@tonic-gate 	while (dp != NULL) {
3110Sstevel@tonic-gate 	    int	error;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	    if (dp->removable) {
3140Sstevel@tonic-gate 		error = make_removable_descriptors(dp);
3150Sstevel@tonic-gate 	    } else {
3160Sstevel@tonic-gate 		error = make_fixed_descriptors(dp);
3170Sstevel@tonic-gate 	    }
3180Sstevel@tonic-gate 	    if (error != 0) {
3190Sstevel@tonic-gate 		return (error);
3200Sstevel@tonic-gate 	    }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	    dp = dp->next;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	return (0);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate /* convert rdsk paths to dsk paths */
3290Sstevel@tonic-gate void
3300Sstevel@tonic-gate slice_rdsk2dsk(char *rdsk, char *dsk, int size)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate 	char	*strp;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	(void) strlcpy(dsk, rdsk, size);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	if ((strp = strstr(dsk, "/rdsk/")) == NULL) {
3370Sstevel@tonic-gate 	    /* not rdsk, check for floppy */
3380Sstevel@tonic-gate 	    strp = strstr(dsk, "/rdiskette");
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (strp != NULL) {
3420Sstevel@tonic-gate 	    strp++;	/* move ptr to the r in rdsk or rdiskette */
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	    /* move the succeeding chars over by one */
3450Sstevel@tonic-gate 	    do {
3460Sstevel@tonic-gate 		*strp = *(strp + 1);
3470Sstevel@tonic-gate 		strp++;
3480Sstevel@tonic-gate 	    } while (*strp);
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate /*
3530Sstevel@tonic-gate  * Check if/how the slice is used.
3540Sstevel@tonic-gate  */
3550Sstevel@tonic-gate static int
3560Sstevel@tonic-gate add_inuse(char *name, nvlist_t *attrs)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	int	i;
3590Sstevel@tonic-gate 	int	error;
3600Sstevel@tonic-gate 
361*1352Seschrock 	for (i = 0; detectors[i] != NULL; i ++) {
362*1352Seschrock 	    if (detectors[i](name, attrs, &error) || error != 0) {
3630Sstevel@tonic-gate 		if (error != 0) {
3640Sstevel@tonic-gate 		    return (error);
3650Sstevel@tonic-gate 		}
3660Sstevel@tonic-gate 		break;
3670Sstevel@tonic-gate 	    }
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	return (0);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /* return 1 if the slice descriptor is still valid, 0 if not. */
3740Sstevel@tonic-gate static int
3750Sstevel@tonic-gate desc_ok(descriptor_t *dp)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	/* First verify the media name for removable media */
3780Sstevel@tonic-gate 	if (dp->p.disk->removable) {
3790Sstevel@tonic-gate 	    char	mname[MAXPATHLEN];
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	    if (!media_read_name(dp->p.disk, mname, sizeof (mname))) {
3820Sstevel@tonic-gate 		return (0);
3830Sstevel@tonic-gate 	    }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	    if (mname[0] == 0) {
3860Sstevel@tonic-gate 		return (libdiskmgt_str_eq(dp->secondary_name, NULL));
3870Sstevel@tonic-gate 	    } else {
3880Sstevel@tonic-gate 		return (libdiskmgt_str_eq(dp->secondary_name, mname));
3890Sstevel@tonic-gate 	    }
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/*
3930Sstevel@tonic-gate 	 * We could verify the slice is still there, but other code down the
3940Sstevel@tonic-gate 	 * line already does these checks (e.g. see get_attrs).
3950Sstevel@tonic-gate 	 */
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	return (1);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate /* convert dsk paths to rdsk paths */
4010Sstevel@tonic-gate static void
4020Sstevel@tonic-gate dsk2rdsk(char *dsk, char *rdsk, int size)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	char	*slashp;
4050Sstevel@tonic-gate 	size_t	len;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	(void) strlcpy(rdsk, dsk, size);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/* make sure there is enough room to add the r to dsk */
4100Sstevel@tonic-gate 	len = strlen(dsk);
4110Sstevel@tonic-gate 	if (len + 2 > size) {
4120Sstevel@tonic-gate 	    return;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if ((slashp = strstr(rdsk, "/dsk/")) == NULL) {
4160Sstevel@tonic-gate 	    /* not dsk, check for floppy */
4170Sstevel@tonic-gate 	    slashp = strstr(rdsk, "/diskette");
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (slashp != NULL) {
4210Sstevel@tonic-gate 	    char	*endp;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	    endp = rdsk + len;	/* point to terminating 0 */
4240Sstevel@tonic-gate 	    /* move the succeeding chars over by one */
4250Sstevel@tonic-gate 	    do {
4260Sstevel@tonic-gate 		*(endp + 1) = *endp;
4270Sstevel@tonic-gate 		endp--;
4280Sstevel@tonic-gate 	    } while (endp != slashp);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	    *(endp + 1) = 'r';
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate static int
4350Sstevel@tonic-gate get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	struct dk_minfo	minfo;
4380Sstevel@tonic-gate 	int		status;
4390Sstevel@tonic-gate 	int		data_format = FMT_UNKNOWN;
4400Sstevel@tonic-gate 	int		snum = -1;
4410Sstevel@tonic-gate 	int		error;
4420Sstevel@tonic-gate 	struct vtoc	vtoc;
4430Sstevel@tonic-gate 	struct dk_gpt	*efip;
4440Sstevel@tonic-gate 	struct dk_cinfo	dkinfo;
4450Sstevel@tonic-gate 	disk_t		*diskp;
4460Sstevel@tonic-gate 	char		localpath[MAXPATHLEN];
4470Sstevel@tonic-gate 	int		cooked_fd;
4480Sstevel@tonic-gate 	struct stat	buf;
4490Sstevel@tonic-gate 	int		mntpnt = 0;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (fd < 0) {
4520Sstevel@tonic-gate 	    return (ENODEV);
4530Sstevel@tonic-gate 	}
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/* First make sure media is inserted and spun up. */
4560Sstevel@tonic-gate 	if (!media_read_info(fd, &minfo)) {
4570Sstevel@tonic-gate 	    return (ENODEV);
4580Sstevel@tonic-gate 	}
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
4610Sstevel@tonic-gate 	    data_format = FMT_VTOC;
4620Sstevel@tonic-gate 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
4630Sstevel@tonic-gate 	    data_format = FMT_EFI;
4640Sstevel@tonic-gate 	    if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
4650Sstevel@tonic-gate 		efi_free(efip);
4660Sstevel@tonic-gate 		return (ENOMEM);
4670Sstevel@tonic-gate 	    }
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (data_format == FMT_UNKNOWN) {
4710Sstevel@tonic-gate 	    return (ENODEV);
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
4750Sstevel@tonic-gate 	    snum = dkinfo.dki_partition;
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	/* check the slice */
4790Sstevel@tonic-gate 	if (data_format == FMT_VTOC) {
4800Sstevel@tonic-gate 	    if (snum < 0 || snum >= vtoc.v_nparts ||
4810Sstevel@tonic-gate 		vtoc.v_part[snum].p_size == 0) {
4820Sstevel@tonic-gate 		return (ENODEV);
4830Sstevel@tonic-gate 	    }
4840Sstevel@tonic-gate 	} else { /* data_format == FMT_EFI */
4850Sstevel@tonic-gate 	    if (snum < 0 || snum >= efip->efi_nparts ||
4860Sstevel@tonic-gate 		efip->efi_parts[snum].p_size == 0) {
4870Sstevel@tonic-gate 		efi_free(efip);
4880Sstevel@tonic-gate 		return (ENODEV);
4890Sstevel@tonic-gate 	    }
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/* the slice exists */
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) {
4950Sstevel@tonic-gate 	    if (data_format == FMT_EFI) {
4960Sstevel@tonic-gate 		efi_free(efip);
4970Sstevel@tonic-gate 	    }
4980Sstevel@tonic-gate 	    return (ENOMEM);
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	if (data_format == FMT_VTOC) {
5020Sstevel@tonic-gate 	    if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start)
5030Sstevel@tonic-gate 		!= 0) {
5040Sstevel@tonic-gate 		return (ENOMEM);
5050Sstevel@tonic-gate 	    }
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	    if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size)
5080Sstevel@tonic-gate 		!= 0) {
5090Sstevel@tonic-gate 		return (ENOMEM);
5100Sstevel@tonic-gate 	    }
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag)
5130Sstevel@tonic-gate 		!= 0) {
5140Sstevel@tonic-gate 		return (ENOMEM);
5150Sstevel@tonic-gate 	    }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	    if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag)
5180Sstevel@tonic-gate 		!= 0) {
5190Sstevel@tonic-gate 		return (ENOMEM);
5200Sstevel@tonic-gate 	    }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	} else { /* data_format == FMT_EFI */
5230Sstevel@tonic-gate 	    if (nvlist_add_uint64(attrs, DM_START,
5240Sstevel@tonic-gate 		efip->efi_parts[snum].p_start) != 0) {
5250Sstevel@tonic-gate 		efi_free(efip);
5260Sstevel@tonic-gate 		return (ENOMEM);
5270Sstevel@tonic-gate 	    }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	    if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size)
5300Sstevel@tonic-gate 		!= 0) {
5310Sstevel@tonic-gate 		efi_free(efip);
5320Sstevel@tonic-gate 		return (ENOMEM);
5330Sstevel@tonic-gate 	    }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	    if (efip->efi_parts[snum].p_name[0] != 0) {
5360Sstevel@tonic-gate 		char	label[EFI_PART_NAME_LEN + 1];
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 		(void) snprintf(label, sizeof (label), "%.*s",
5390Sstevel@tonic-gate 		    EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
5400Sstevel@tonic-gate 		if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
5410Sstevel@tonic-gate 		    efi_free(efip);
5420Sstevel@tonic-gate 		    return (ENOMEM);
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 	    }
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (data_format == FMT_EFI) {
5480Sstevel@tonic-gate 	    efi_free(efip);
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (inuse_mnt(dp->name, attrs, &error)) {
5520Sstevel@tonic-gate 	    if (error != 0) {
5530Sstevel@tonic-gate 		return (error);
5540Sstevel@tonic-gate 	    }
5550Sstevel@tonic-gate 	    mntpnt = 1;
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	/*
5590Sstevel@tonic-gate 	 * Some extra attrs for cluster slices.
5600Sstevel@tonic-gate 	 *
5610Sstevel@tonic-gate 	 * get localname and possible mnt point for localpath
5620Sstevel@tonic-gate 	 */
5630Sstevel@tonic-gate 	localpath[0] = 0;
5640Sstevel@tonic-gate 	diskp = dp->p.disk;
5650Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->cluster) {
5660Sstevel@tonic-gate 	    slice_t *sp;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	    for (sp = diskp->aliases->orig_paths; sp != NULL; sp = sp->next) {
5690Sstevel@tonic-gate 		if (sp->slice_num == -1) {
5700Sstevel@tonic-gate 		    /* determine the slice number for this path */
5710Sstevel@tonic-gate 		    int			sfd;
5720Sstevel@tonic-gate 		    struct dk_cinfo	dkinfo;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 		    if ((sfd = open(sp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
5750Sstevel@tonic-gate 			if (ioctl(sfd, DKIOCINFO, &dkinfo) >= 0) {
5760Sstevel@tonic-gate 			    sp->slice_num = dkinfo.dki_partition;
5770Sstevel@tonic-gate 			}
5780Sstevel@tonic-gate 			(void) close(sfd);
5790Sstevel@tonic-gate 		    }
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		if (sp->slice_num == snum) {
5830Sstevel@tonic-gate 		    slice_rdsk2dsk(sp->devpath, localpath, sizeof (localpath));
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		    if (nvlist_add_string(attrs, DM_LOCALNAME, localpath)
5860Sstevel@tonic-gate 			!= 0) {
5870Sstevel@tonic-gate 			return (ENOMEM);
5880Sstevel@tonic-gate 		    }
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		    if (mntpnt == 0) {
5910Sstevel@tonic-gate 			if (inuse_mnt(localpath, attrs, &error)) {
5920Sstevel@tonic-gate 			    if (error != 0) {
5930Sstevel@tonic-gate 				return (error);
5940Sstevel@tonic-gate 			    }
5950Sstevel@tonic-gate 			}
5960Sstevel@tonic-gate 		    }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		    break;
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 	    }
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (fstat(fd, &buf) != -1) {
6040Sstevel@tonic-gate 	    if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
6050Sstevel@tonic-gate 		return (ENOMEM);
6060Sstevel@tonic-gate 	    }
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * We need to open the cooked slice (not the raw one) to get the
6110Sstevel@tonic-gate 	 * correct devid.  Also see if we need to read the localpath for the
6120Sstevel@tonic-gate 	 * cluster disk, since the minor name is unavailable for the did pseudo
6130Sstevel@tonic-gate 	 * device.
6140Sstevel@tonic-gate 	 */
6150Sstevel@tonic-gate 	if (localpath[0] != 0) {
6160Sstevel@tonic-gate 	    cooked_fd = open(localpath, O_RDONLY|O_NDELAY);
6170Sstevel@tonic-gate 	} else {
6180Sstevel@tonic-gate 	    cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (cooked_fd >= 0) {
6220Sstevel@tonic-gate 	    int		no_mem = 0;
6230Sstevel@tonic-gate 	    ddi_devid_t	devid;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	    if (devid_get(cooked_fd, &devid) == 0) {
6260Sstevel@tonic-gate 		char	*minor;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		if (devid_get_minor_name(cooked_fd, &minor) == 0) {
6290Sstevel@tonic-gate 		    char	*devidstr;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 		    if ((devidstr = devid_str_encode(devid, minor)) != 0) {
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 			if (nvlist_add_string(attrs, DM_DEVICEID, devidstr)
6340Sstevel@tonic-gate 			    != 0) {
6350Sstevel@tonic-gate 			    no_mem = 1;
6360Sstevel@tonic-gate 			}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 			devid_str_free(devidstr);
6390Sstevel@tonic-gate 		    }
6400Sstevel@tonic-gate 		    devid_str_free(minor);
6410Sstevel@tonic-gate 		}
6420Sstevel@tonic-gate 		devid_free(devid);
6430Sstevel@tonic-gate 	    }
6440Sstevel@tonic-gate 	    (void) close(cooked_fd);
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	    if (no_mem) {
6470Sstevel@tonic-gate 		return (ENOMEM);
6480Sstevel@tonic-gate 	    }
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	return (0);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate static descriptor_t **
6550Sstevel@tonic-gate get_fixed_assocs(descriptor_t *desc, int *errp)
6560Sstevel@tonic-gate {
6570Sstevel@tonic-gate 	int		fd;
6580Sstevel@tonic-gate 	int		status;
6590Sstevel@tonic-gate 	int		data_format = FMT_UNKNOWN;
6600Sstevel@tonic-gate 	int		cnt;
6610Sstevel@tonic-gate 	struct vtoc	vtoc;
6620Sstevel@tonic-gate 	struct dk_gpt	*efip;
6630Sstevel@tonic-gate 	int		pos;
6640Sstevel@tonic-gate 	char		*media_name = NULL;
6650Sstevel@tonic-gate 	slice_t		*devp;
6660Sstevel@tonic-gate 	descriptor_t	**slices;
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) {
6690Sstevel@tonic-gate 	    *errp = ENODEV;
6700Sstevel@tonic-gate 	    return (NULL);
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
6740Sstevel@tonic-gate 	    data_format = FMT_VTOC;
6750Sstevel@tonic-gate 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
6760Sstevel@tonic-gate 	    data_format = FMT_EFI;
6770Sstevel@tonic-gate 	} else {
6780Sstevel@tonic-gate 	    (void) close(fd);
6790Sstevel@tonic-gate 	    *errp = 0;
6800Sstevel@tonic-gate 	    return (libdiskmgt_empty_desc_array(errp));
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 	(void) close(fd);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	/* count the number of slices */
6850Sstevel@tonic-gate 	for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL;
6860Sstevel@tonic-gate 	    devp = devp->next, cnt++);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	/* allocate the array for the descriptors */
6890Sstevel@tonic-gate 	slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
6900Sstevel@tonic-gate 	if (slices == NULL) {
6910Sstevel@tonic-gate 	    if (data_format == FMT_EFI) {
6920Sstevel@tonic-gate 		efi_free(efip);
6930Sstevel@tonic-gate 	    }
6940Sstevel@tonic-gate 	    *errp = ENOMEM;
6950Sstevel@tonic-gate 	    return (NULL);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/* get the media name from the descriptor */
6990Sstevel@tonic-gate 	if (desc->type == DM_MEDIA) {
7000Sstevel@tonic-gate 	    media_name = desc->name;
7010Sstevel@tonic-gate 	} else {
7020Sstevel@tonic-gate 	    /* must be a DM_PARTITION */
7030Sstevel@tonic-gate 	    media_name = desc->secondary_name;
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	pos = 0;
7070Sstevel@tonic-gate 	for (devp = desc->p.disk->aliases->devpaths; devp != NULL;
7080Sstevel@tonic-gate 	    devp = devp->next) {
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	    int		slice_num;
7110Sstevel@tonic-gate 	    char	devpath[MAXPATHLEN];
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	    slice_num = get_slice_num(devp);
7140Sstevel@tonic-gate 	    /* can't get slicenum, so no need to keep trying the drive */
7150Sstevel@tonic-gate 	    if (slice_num == -1) {
7160Sstevel@tonic-gate 		break;
7170Sstevel@tonic-gate 	    }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	    if (data_format == FMT_VTOC) {
7200Sstevel@tonic-gate 		if (slice_num >= vtoc.v_nparts ||
7210Sstevel@tonic-gate 		    vtoc.v_part[slice_num].p_size == 0) {
7220Sstevel@tonic-gate 		    continue;
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 	    } else { /* data_format == FMT_EFI */
7250Sstevel@tonic-gate 		if (slice_num >= efip->efi_nparts ||
7260Sstevel@tonic-gate 		    efip->efi_parts[slice_num].p_size == 0) {
7270Sstevel@tonic-gate 		    continue;
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 	    }
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	    slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
7320Sstevel@tonic-gate 	    slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath,
7330Sstevel@tonic-gate 		media_name, errp);
7340Sstevel@tonic-gate 	    if (*errp != 0) {
7350Sstevel@tonic-gate 		cache_free_descriptors(slices);
7360Sstevel@tonic-gate 		if (data_format == FMT_EFI) {
7370Sstevel@tonic-gate 		    efi_free(efip);
7380Sstevel@tonic-gate 		}
7390Sstevel@tonic-gate 		return (NULL);
7400Sstevel@tonic-gate 	    }
7410Sstevel@tonic-gate 	    pos++;
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 	slices[pos] = NULL;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (data_format == FMT_EFI) {
7460Sstevel@tonic-gate 	    efi_free(efip);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	*errp = 0;
7500Sstevel@tonic-gate 	return (slices);
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate /*
7540Sstevel@tonic-gate  * Called for loaded removable media under volume management control.
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate static descriptor_t **
7570Sstevel@tonic-gate get_removable_assocs(descriptor_t *desc, char *volm_path, int *errp)
7580Sstevel@tonic-gate {
7590Sstevel@tonic-gate 	int		pos;
7600Sstevel@tonic-gate 	int		fd;
7610Sstevel@tonic-gate 	int		cnt;
7620Sstevel@tonic-gate 	struct stat	buf;
7630Sstevel@tonic-gate 	descriptor_t	**slices;
7640Sstevel@tonic-gate 	char		*media_name = NULL;
7650Sstevel@tonic-gate 	char		devpath[MAXPATHLEN];
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/* get the media name from the descriptor */
7680Sstevel@tonic-gate 	if (desc->type == DM_MEDIA) {
769871Scasper 		media_name = desc->name;
7700Sstevel@tonic-gate 	} else {
771871Scasper 		/* must be a DM_PARTITION */
772871Scasper 		media_name = desc->secondary_name;
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/*
7760Sstevel@tonic-gate 	 * For removable media under volm control the volm_path will
7770Sstevel@tonic-gate 	 * either be a device (if the media is made up of a single slice) or
7780Sstevel@tonic-gate 	 * a directory (if the media has multiple slices) with the slices
7790Sstevel@tonic-gate 	 * as devices contained in the directory.
7800Sstevel@tonic-gate 	 */
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) < 0 ||
7830Sstevel@tonic-gate 	    fstat(fd, &buf) != 0) {
784871Scasper 		*errp = ENODEV;
785871Scasper 		return (NULL);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	cnt = num_removable_slices(fd, &buf, volm_path);
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/* allocate the array for the descriptors */
791871Scasper 	slices = calloc(cnt + 1, sizeof (descriptor_t *));
7920Sstevel@tonic-gate 	if (slices == NULL) {
793871Scasper 		*errp = ENOMEM;
794871Scasper 		return (NULL);
7950Sstevel@tonic-gate 	}
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	pos = 0;
8000Sstevel@tonic-gate 	*errp = 0;
801871Scasper 	if (S_ISCHR(buf.st_mode)) {
802871Scasper 		struct dk_minfo	minfo;
803871Scasper 
804871Scasper 		/* Make sure media has readable label */
805871Scasper 		if (media_read_info(fd, &minfo)) {
806871Scasper 			int		status;
807871Scasper 			int		data_format = FMT_UNKNOWN;
808871Scasper 			struct vtoc	vtoc;
809871Scasper 			struct dk_gpt	*efip;
810871Scasper 
811871Scasper 			if ((status = read_vtoc(fd, &vtoc)) >= 0) {
812871Scasper 				data_format = FMT_VTOC;
813871Scasper 			} else if (status == VT_ENOTSUP &&
814871Scasper 			    efi_alloc_and_read(fd, &efip) >= 0) {
815871Scasper 				data_format = FMT_EFI;
816871Scasper 			}
8170Sstevel@tonic-gate 
818871Scasper 			if (data_format != FMT_UNKNOWN) {
819871Scasper 			    /* has a readable label */
820871Scasper 				slices[pos++] =
821871Scasper 				    cache_get_desc(DM_SLICE, desc->p.disk,
822871Scasper 				    devpath, media_name, errp);
823871Scasper 			}
824871Scasper 		}
825871Scasper 		(void) close(fd);
826871Scasper 	} else if (S_ISDIR(buf.st_mode)) {
827871Scasper 		DIR		*dirp;
828871Scasper 		struct dirent	*dentp;
8290Sstevel@tonic-gate 
830871Scasper 		/* rewind, num_removable_slices already traversed */
831871Scasper 		(void) lseek(fd, 0, SEEK_SET);
832871Scasper 
833871Scasper 		if ((dirp = fdopendir(fd)) == NULL) {
834871Scasper 			*errp = errno;
835871Scasper 			(void) close(fd);
836871Scasper 			return (NULL);
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 
839871Scasper 		while ((dentp = readdir(dirp)) != NULL) {
8400Sstevel@tonic-gate 			int	dfd;
8410Sstevel@tonic-gate 			int	is_dev = 0;
8420Sstevel@tonic-gate 			char	slice_path[MAXPATHLEN];
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 			if (libdiskmgt_str_eq(".", dentp->d_name) ||
8450Sstevel@tonic-gate 			    libdiskmgt_str_eq("..", dentp->d_name)) {
846871Scasper 				continue;
8470Sstevel@tonic-gate 			}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 			(void) snprintf(slice_path, sizeof (slice_path),
8500Sstevel@tonic-gate 			    "%s/%s", devpath, dentp->d_name);
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 			if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
853871Scasper 				struct stat	buf;
8540Sstevel@tonic-gate 
855871Scasper 				if (fstat(dfd, &buf) == 0 &&
856871Scasper 				    S_ISCHR(buf.st_mode)) {
857871Scasper 					is_dev = 1;
858871Scasper 				}
859871Scasper 				(void) close(dfd);
8600Sstevel@tonic-gate 			}
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 			if (!is_dev) {
863871Scasper 				continue;
8640Sstevel@tonic-gate 			}
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 			slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk,
8670Sstevel@tonic-gate 			    slice_path, media_name, errp);
8680Sstevel@tonic-gate 			if (*errp != 0) {
869871Scasper 				break;
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 		}
872871Scasper 		(void) closedir(dirp);
873871Scasper 	} else {
874871Scasper 		(void) close(fd);
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	slices[pos] = NULL;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (*errp != 0) {
880871Scasper 		cache_free_descriptors(slices);
881871Scasper 		return (NULL);
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	return (slices);
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate static int
8880Sstevel@tonic-gate get_slice_num(slice_t *devp)
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	/* check if we already determined the devpath slice number */
8910Sstevel@tonic-gate 	if (devp->slice_num == -1) {
8920Sstevel@tonic-gate 	    int		fd;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	    if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
8950Sstevel@tonic-gate 		struct dk_cinfo	dkinfo;
8960Sstevel@tonic-gate 		if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
8970Sstevel@tonic-gate 		    devp->slice_num = dkinfo.dki_partition;
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 		(void) close(fd);
9000Sstevel@tonic-gate 	    }
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	return (devp->slice_num);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate static int
9070Sstevel@tonic-gate make_fixed_descriptors(disk_t *dp)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate 	int		error = 0;
9100Sstevel@tonic-gate 	alias_t		*ap;
9110Sstevel@tonic-gate 	slice_t		*devp;
9120Sstevel@tonic-gate 	char		mname[MAXPATHLEN];
9130Sstevel@tonic-gate 	int		data_format = FMT_UNKNOWN;
9140Sstevel@tonic-gate 	struct vtoc	vtoc;
9150Sstevel@tonic-gate 	struct dk_gpt	*efip;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	/* Just check the first drive name. */
9180Sstevel@tonic-gate 	if ((ap = dp->aliases) == NULL) {
9190Sstevel@tonic-gate 	    return (0);
9200Sstevel@tonic-gate 	}
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	mname[0] = 0;
9230Sstevel@tonic-gate 	(void) media_read_name(dp, mname, sizeof (mname));
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	for (devp = ap->devpaths; devp != NULL; devp = devp->next) {
9260Sstevel@tonic-gate 	    int		slice_num;
9270Sstevel@tonic-gate 	    char	devpath[MAXPATHLEN];
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	    slice_num = get_slice_num(devp);
9300Sstevel@tonic-gate 	    /* can't get slicenum, so no need to keep trying the drive */
9310Sstevel@tonic-gate 	    if (slice_num == -1) {
9320Sstevel@tonic-gate 		break;
9330Sstevel@tonic-gate 	    }
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	    if (data_format == FMT_UNKNOWN) {
9360Sstevel@tonic-gate 		int	fd;
9370Sstevel@tonic-gate 		int	status;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
9400Sstevel@tonic-gate 		    if ((status = read_vtoc(fd, &vtoc)) >= 0) {
9410Sstevel@tonic-gate 			data_format = FMT_VTOC;
9420Sstevel@tonic-gate 		    } else if (status == VT_ENOTSUP &&
9430Sstevel@tonic-gate 			efi_alloc_and_read(fd, &efip) >= 0) {
9440Sstevel@tonic-gate 			data_format = FMT_EFI;
9450Sstevel@tonic-gate 		    }
9460Sstevel@tonic-gate 		    (void) close(fd);
9470Sstevel@tonic-gate 		}
9480Sstevel@tonic-gate 	    }
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	    /* can't get slice data, so no need to keep trying the drive */
9510Sstevel@tonic-gate 	    if (data_format == FMT_UNKNOWN) {
9520Sstevel@tonic-gate 		break;
9530Sstevel@tonic-gate 	    }
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	    if (data_format == FMT_VTOC) {
9560Sstevel@tonic-gate 		if (slice_num >= vtoc.v_nparts ||
9570Sstevel@tonic-gate 		    vtoc.v_part[slice_num].p_size == 0) {
9580Sstevel@tonic-gate 		    continue;
9590Sstevel@tonic-gate 		}
9600Sstevel@tonic-gate 	    } else { /* data_format == FMT_EFI */
9610Sstevel@tonic-gate 		if (slice_num >= efip->efi_nparts ||
9620Sstevel@tonic-gate 		    efip->efi_parts[slice_num].p_size == 0) {
9630Sstevel@tonic-gate 		    continue;
9640Sstevel@tonic-gate 		}
9650Sstevel@tonic-gate 	    }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	    slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
9680Sstevel@tonic-gate 	    cache_load_desc(DM_SLICE, dp, devpath, mname, &error);
9690Sstevel@tonic-gate 	    if (error != 0) {
9700Sstevel@tonic-gate 		break;
9710Sstevel@tonic-gate 	    }
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (data_format == FMT_EFI) {
9750Sstevel@tonic-gate 	    efi_free(efip);
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	return (error);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate /*
9820Sstevel@tonic-gate  * For removable media under volm control we have to do some special handling.
9830Sstevel@tonic-gate  * We don't use the vtoc and /dev/dsk devpaths, since the slices are named
9840Sstevel@tonic-gate  * under the /vol fs.
9850Sstevel@tonic-gate  */
9860Sstevel@tonic-gate static int
9870Sstevel@tonic-gate make_removable_descriptors(disk_t *dp)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	char		volm_path[MAXPATHLEN];
9900Sstevel@tonic-gate 	int		error;
9910Sstevel@tonic-gate 	int		fd;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	/*
9940Sstevel@tonic-gate 	 * If this removable drive is not under volm control, just use
9950Sstevel@tonic-gate 	 * normal handling.
9960Sstevel@tonic-gate 	 */
9970Sstevel@tonic-gate 	if (!media_get_volm_path(dp, volm_path, sizeof (volm_path))) {
9980Sstevel@tonic-gate 	    return (make_fixed_descriptors(dp));
9990Sstevel@tonic-gate 	}
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	if (volm_path[0] == 0) {
10020Sstevel@tonic-gate 	    /* no media */
10030Sstevel@tonic-gate 	    return (0);
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	/*
10070Sstevel@tonic-gate 	 * For removable media under volm control the rmmedia_devapth will
10080Sstevel@tonic-gate 	 * either be a device (if the media is made up of a single slice) or
10090Sstevel@tonic-gate 	 * a directory (if the media has multiple slices) with the slices
10100Sstevel@tonic-gate 	 * as devices contained in the directory.
10110Sstevel@tonic-gate 	 */
10120Sstevel@tonic-gate 	error = 0;
10130Sstevel@tonic-gate 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0) {
10140Sstevel@tonic-gate 	    struct stat	buf;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 	    if (fstat(fd, &buf) == 0) {
1017871Scasper 		if (S_ISCHR(buf.st_mode)) {
10180Sstevel@tonic-gate 		    int			status;
10190Sstevel@tonic-gate 		    int			data_format = FMT_UNKNOWN;
10200Sstevel@tonic-gate 		    struct dk_minfo	minfo;
10210Sstevel@tonic-gate 		    int			error;
10220Sstevel@tonic-gate 		    struct vtoc		vtoc;
10230Sstevel@tonic-gate 		    struct dk_gpt	*efip;
10240Sstevel@tonic-gate 		    char		devpath[MAXPATHLEN];
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 		    /* Make sure media has readable label */
10270Sstevel@tonic-gate 		    if (!media_read_info(fd, &minfo)) {
10280Sstevel@tonic-gate 			/* no media */
10290Sstevel@tonic-gate 			return (0);
10300Sstevel@tonic-gate 		    }
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		    if ((status = read_vtoc(fd, &vtoc)) >= 0) {
10330Sstevel@tonic-gate 			data_format = FMT_VTOC;
10340Sstevel@tonic-gate 		    } else if (status == VT_ENOTSUP &&
10350Sstevel@tonic-gate 			efi_alloc_and_read(fd, &efip) >= 0) {
10360Sstevel@tonic-gate 			data_format = FMT_EFI;
10370Sstevel@tonic-gate 		    }
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 		    if (data_format == FMT_UNKNOWN) {
10400Sstevel@tonic-gate 			/* no readable label */
10410Sstevel@tonic-gate 			return (0);
10420Sstevel@tonic-gate 		    }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 		    slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
10450Sstevel@tonic-gate 		    /* The media name is the volm_path in this case. */
10460Sstevel@tonic-gate 		    cache_load_desc(DM_SLICE, dp, devpath, volm_path, &error);
10470Sstevel@tonic-gate 
1048871Scasper 		} else if (S_ISDIR(buf.st_mode)) {
10490Sstevel@tonic-gate 		    /* each device file in the dir represents a slice */
10500Sstevel@tonic-gate 		    error = make_volm_dir_descriptors(dp, fd, volm_path);
10510Sstevel@tonic-gate 		}
10520Sstevel@tonic-gate 	    }
10530Sstevel@tonic-gate 	    (void) close(fd);
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	return (error);
10570Sstevel@tonic-gate }
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate /*
10600Sstevel@tonic-gate  * This handles removable media with slices under volume management control.
10610Sstevel@tonic-gate  * In this case we have a dir which is the media name and each slice on the
10620Sstevel@tonic-gate  * media is a device file in this dir.
10630Sstevel@tonic-gate  */
10640Sstevel@tonic-gate static int
10650Sstevel@tonic-gate make_volm_dir_descriptors(disk_t *dp, int dirfd, char *volm_path)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	int		error;
10680Sstevel@tonic-gate 	DIR		*dirp;
10690Sstevel@tonic-gate 	struct dirent	*dentp;
10700Sstevel@tonic-gate 	char		devpath[MAXPATHLEN];
10710Sstevel@tonic-gate 
1072871Scasper 	dirfd = dup(dirfd);
1073871Scasper 	if (dirfd < 0)
1074871Scasper 		return (0);
10750Sstevel@tonic-gate 	if ((dirp = fdopendir(dirfd)) == NULL) {
1076871Scasper 		(void) close(dirfd);
1077871Scasper 		return (0);
10780Sstevel@tonic-gate 	}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	error = 0;
1083871Scasper 	while ((dentp = readdir(dirp)) != NULL) {
10840Sstevel@tonic-gate 		int	fd;
10850Sstevel@tonic-gate 		char	slice_path[MAXPATHLEN];
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 		if (libdiskmgt_str_eq(".", dentp->d_name) ||
10880Sstevel@tonic-gate 		    libdiskmgt_str_eq("..", dentp->d_name)) {
1089871Scasper 			continue;
10900Sstevel@tonic-gate 		}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		(void) snprintf(slice_path, sizeof (slice_path), "%s/%s",
10930Sstevel@tonic-gate 		    devpath, dentp->d_name);
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 		if ((fd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
1096871Scasper 			struct stat	buf;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 			/* The media name is the volm_path in this case. */
1099871Scasper 			if (fstat(fd, &buf) == 0 && S_ISCHR(buf.st_mode)) {
1100871Scasper 				cache_load_desc(DM_SLICE, dp, slice_path,
1101871Scasper 				    volm_path, &error);
1102871Scasper 				if (error != 0) {
1103871Scasper 					(void) close(fd);
1104871Scasper 					break;
1105871Scasper 				}
11060Sstevel@tonic-gate 			}
11070Sstevel@tonic-gate 
1108871Scasper 			(void) close(fd);
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 	}
1111871Scasper 	(void) closedir(dirp);
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	return (error);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate /*
11170Sstevel@tonic-gate  * Just look for the name on the devpaths we have cached. Return 1 if we
11180Sstevel@tonic-gate  * find the name and the size of that slice is non-zero.
11190Sstevel@tonic-gate  */
11200Sstevel@tonic-gate static int
11210Sstevel@tonic-gate match_fixed_name(disk_t *diskp, char *name, int *errp)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	slice_t		*dp = NULL;
11240Sstevel@tonic-gate 	alias_t		*ap;
11250Sstevel@tonic-gate 	int		slice_num;
11260Sstevel@tonic-gate 	int		fd;
11270Sstevel@tonic-gate 	int		status;
11280Sstevel@tonic-gate 	int		data_format = FMT_UNKNOWN;
11290Sstevel@tonic-gate 	struct vtoc	vtoc;
11300Sstevel@tonic-gate 	struct dk_gpt	*efip;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ap = diskp->aliases;
11330Sstevel@tonic-gate 	while (ap != NULL) {
11340Sstevel@tonic-gate 	    slice_t	*devp;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	    devp = ap->devpaths;
11370Sstevel@tonic-gate 	    while (devp != NULL) {
11380Sstevel@tonic-gate 		char	path[MAXPATHLEN];
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		slice_rdsk2dsk(devp->devpath, path, sizeof (path));
11410Sstevel@tonic-gate 		if (libdiskmgt_str_eq(path, name)) {
11420Sstevel@tonic-gate 		    /* found it */
11430Sstevel@tonic-gate 		    dp = devp;
11440Sstevel@tonic-gate 		    break;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 		devp = devp->next;
11480Sstevel@tonic-gate 	    }
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	    if (dp != NULL) {
11510Sstevel@tonic-gate 		break;
11520Sstevel@tonic-gate 	    }
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	    ap = ap->next;
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	if (dp == NULL) {
11580Sstevel@tonic-gate 	    *errp = 0;
11590Sstevel@tonic-gate 	    return (0);
11600Sstevel@tonic-gate 	}
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 	/*
11630Sstevel@tonic-gate 	 * If we found a match on the name we now have to check that this
11640Sstevel@tonic-gate 	 * slice really exists (non-0 size).
11650Sstevel@tonic-gate 	 */
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	slice_num = get_slice_num(dp);
11680Sstevel@tonic-gate 	/* can't get slicenum, so no slice */
11690Sstevel@tonic-gate 	if (slice_num == -1) {
11700Sstevel@tonic-gate 	    *errp = ENODEV;
11710Sstevel@tonic-gate 	    return (1);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) {
11750Sstevel@tonic-gate 	    *errp = ENODEV;
11760Sstevel@tonic-gate 	    return (1);
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
11800Sstevel@tonic-gate 	    data_format = FMT_VTOC;
11810Sstevel@tonic-gate 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
11820Sstevel@tonic-gate 	    data_format = FMT_EFI;
11830Sstevel@tonic-gate 	} else {
11840Sstevel@tonic-gate 	    (void) close(fd);
11850Sstevel@tonic-gate 	    *errp = ENODEV;
11860Sstevel@tonic-gate 	    return (1);
11870Sstevel@tonic-gate 	}
11880Sstevel@tonic-gate 	(void) close(fd);
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	if (data_format == FMT_VTOC) {
11910Sstevel@tonic-gate 	    if (slice_num < vtoc.v_nparts &&
11920Sstevel@tonic-gate 		vtoc.v_part[slice_num].p_size > 0) {
11930Sstevel@tonic-gate 		*errp = 0;
11940Sstevel@tonic-gate 		return (1);
11950Sstevel@tonic-gate 	    }
11960Sstevel@tonic-gate 	} else { /* data_format == FMT_EFI */
11970Sstevel@tonic-gate 	    if (slice_num < efip->efi_nparts &&
11980Sstevel@tonic-gate 		efip->efi_parts[slice_num].p_size > 0) {
11990Sstevel@tonic-gate 		efi_free(efip);
12000Sstevel@tonic-gate 		*errp = 0;
12010Sstevel@tonic-gate 		return (1);
12020Sstevel@tonic-gate 	    }
12030Sstevel@tonic-gate 	    efi_free(efip);
12040Sstevel@tonic-gate 	}
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	*errp = ENODEV;
12070Sstevel@tonic-gate 	return (1);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate static int
12110Sstevel@tonic-gate match_removable_name(disk_t *diskp, char *name, int *errp)
12120Sstevel@tonic-gate {
12130Sstevel@tonic-gate 	char		volm_path[MAXPATHLEN];
12140Sstevel@tonic-gate 	int		found;
12150Sstevel@tonic-gate 	int		fd;
12160Sstevel@tonic-gate 	struct stat	buf;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * If this removable drive is not under volm control, just use
12200Sstevel@tonic-gate 	 * normal handling.
12210Sstevel@tonic-gate 	 */
12220Sstevel@tonic-gate 	if (!media_get_volm_path(diskp, volm_path, sizeof (volm_path))) {
12230Sstevel@tonic-gate 	    return (match_fixed_name(diskp, name, errp));
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	if (volm_path[0] == 0) {
12270Sstevel@tonic-gate 	    /* no media */
12280Sstevel@tonic-gate 	    *errp = 0;
12290Sstevel@tonic-gate 	    return (0);
12300Sstevel@tonic-gate 	}
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	/*
12330Sstevel@tonic-gate 	 * For removable media under volm control the rmmedia_devapth will
12340Sstevel@tonic-gate 	 * either be a device (if the media is made up of a single slice) or
12350Sstevel@tonic-gate 	 * a directory (if the media has multiple slices) with the slices
12360Sstevel@tonic-gate 	 * as devices contained in the directory.
12370Sstevel@tonic-gate 	 */
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	*errp = 0;
12400Sstevel@tonic-gate 
1241871Scasper 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) == -1 ||
1242871Scasper 	    fstat(fd, &buf) != 0) {
1243871Scasper 		return (0);
1244871Scasper 	}
1245871Scasper 
12460Sstevel@tonic-gate 	found = 0;
12470Sstevel@tonic-gate 
1248871Scasper 	if (S_ISCHR(buf.st_mode)) {
12490Sstevel@tonic-gate 		char	devpath[MAXPATHLEN];
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 		slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
12520Sstevel@tonic-gate 		if (libdiskmgt_str_eq(name, devpath)) {
1253871Scasper 			found = 1;
12540Sstevel@tonic-gate 		}
1255871Scasper 		(void) close(fd);
1256871Scasper 		return (found);
1257871Scasper 	} else if (S_ISDIR(buf.st_mode)) {
12580Sstevel@tonic-gate 		/* each device file in the dir represents a slice */
12590Sstevel@tonic-gate 		DIR		*dirp;
1260871Scasper 		struct dirent	*dentp;
1261871Scasper 		char		devpath[MAXPATHLEN];
12620Sstevel@tonic-gate 
1263871Scasper 		if ((dirp = fdopendir(fd)) == NULL) {
1264871Scasper 			(void) close(fd);
1265871Scasper 			return (0);
1266871Scasper 		}
12670Sstevel@tonic-gate 
1268871Scasper 		slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
12690Sstevel@tonic-gate 
1270871Scasper 		while ((dentp = readdir(dirp)) != NULL) {
1271871Scasper 			char	slice_path[MAXPATHLEN];
12720Sstevel@tonic-gate 
1273871Scasper 			if (libdiskmgt_str_eq(".", dentp->d_name) ||
1274871Scasper 			    libdiskmgt_str_eq("..", dentp->d_name)) {
12750Sstevel@tonic-gate 				continue;
1276871Scasper 			}
12770Sstevel@tonic-gate 
1278871Scasper 			(void) snprintf(slice_path, sizeof (slice_path),
1279871Scasper 			    "%s/%s", devpath, dentp->d_name);
12800Sstevel@tonic-gate 
1281871Scasper 			if (libdiskmgt_str_eq(name, slice_path)) {
12820Sstevel@tonic-gate 				/* found name, check device */
12830Sstevel@tonic-gate 				int	dfd;
12840Sstevel@tonic-gate 				int	is_dev = 0;
12850Sstevel@tonic-gate 
1286871Scasper 				dfd = open(slice_path, O_RDONLY|O_NDELAY);
1287871Scasper 				if (dfd >= 0) {
1288871Scasper 					struct stat	buf;
12890Sstevel@tonic-gate 
1290871Scasper 					if (fstat(dfd, &buf) == 0 &&
1291871Scasper 					    S_ISCHR(buf.st_mode)) {
1292871Scasper 						is_dev = 1;
1293871Scasper 					}
1294871Scasper 					(void) close(dfd);
12950Sstevel@tonic-gate 				}
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 				/* we found the name */
12980Sstevel@tonic-gate 				found = 1;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 				if (!is_dev) {
1301871Scasper 					*errp = ENODEV;
13020Sstevel@tonic-gate 				}
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 				break;
13050Sstevel@tonic-gate 			}
13060Sstevel@tonic-gate 		}
1307871Scasper 		(void) closedir(dirp);
1308871Scasper 	} else {
1309871Scasper 		(void) close(fd);
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	return (found);
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate static int
13160Sstevel@tonic-gate num_removable_slices(int fd, struct stat *bufp, char *volm_path)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate 	int cnt = 0;
13190Sstevel@tonic-gate 
1320871Scasper 	if (S_ISCHR(bufp->st_mode))
1321871Scasper 		return (1);
13220Sstevel@tonic-gate 
1323871Scasper 	if (S_ISDIR(bufp->st_mode)) {
1324871Scasper 		/* each device file in the dir represents a slice */
1325871Scasper 		DIR		*dirp;
1326871Scasper 		struct dirent	*dentp;
1327871Scasper 		char		devpath[MAXPATHLEN];
13280Sstevel@tonic-gate 
1329871Scasper 		fd = dup(fd);
1330871Scasper 
1331871Scasper 		if (fd < 0)
1332871Scasper 			return (0);
1333871Scasper 
1334871Scasper 		if ((dirp = fdopendir(fd)) == NULL) {
1335871Scasper 			(void) close(fd);
1336871Scasper 			return (0);
1337871Scasper 		}
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 		slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
13400Sstevel@tonic-gate 
1341871Scasper 		while ((dentp = readdir(dirp)) != NULL) {
13420Sstevel@tonic-gate 			int	dfd;
13430Sstevel@tonic-gate 			char	slice_path[MAXPATHLEN];
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 			if (libdiskmgt_str_eq(".", dentp->d_name) ||
13460Sstevel@tonic-gate 			    libdiskmgt_str_eq("..", dentp->d_name)) {
1347871Scasper 				continue;
13480Sstevel@tonic-gate 			}
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 			(void) snprintf(slice_path, sizeof (slice_path),
13510Sstevel@tonic-gate 			    "%s/%s", devpath, dentp->d_name);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 			if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
1354871Scasper 				struct stat	buf;
13550Sstevel@tonic-gate 
1356871Scasper 				if (fstat(dfd, &buf) == 0 &&
1357871Scasper 				    S_ISCHR(buf.st_mode)) {
1358871Scasper 					cnt++;
1359871Scasper 				}
1360871Scasper 				(void) close(dfd);
13610Sstevel@tonic-gate 			}
13620Sstevel@tonic-gate 		}
1363871Scasper 		(void) closedir(dirp);
1364871Scasper 	}
13650Sstevel@tonic-gate 	return (cnt);
13660Sstevel@tonic-gate }
1367