xref: /illumos-gate/usr/src/lib/libdiskmgt/common/slice.c (revision 3e1bd7a2aaeb6188caef90679b98088cfef1edc6)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <fcntl.h>
30 #include <libdevinfo.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <dirent.h>
35 #include <sys/dkio.h>
36 #include <sys/stat.h>
37 #include <sys/sunddi.h>
38 #include <sys/types.h>
39 #include <sys/vtoc.h>
40 #include <unistd.h>
41 #include <devid.h>
42 #include <dirent.h>
43 #include <sys/dktp/fdisk.h>
44 #include <sys/efi_partition.h>
45 
46 #include "libdiskmgt.h"
47 #include "disks_private.h"
48 #include "partition.h"
49 #ifndef VT_ENOTSUP
50 #define	VT_ENOTSUP	(-5)
51 #endif
52 
53 #define	FMT_UNKNOWN	0
54 #define	FMT_VTOC	1
55 #define	FMT_EFI		2
56 
57 static struct inuse_detectors {
58 	int	(*detectorp)(char *slice, nvlist_t *attrs, int *errp);
59 	char	*used_by;
60 } detectors[] = {
61 	{inuse_mnt, DM_USE_MOUNT},
62 	{inuse_svm, DM_USE_SVM},
63 	{inuse_zpool, DM_USE_ZPOOL},
64 	{inuse_lu, DM_USE_LU},
65 	{inuse_dump, DM_USE_DUMP},
66 	{inuse_vxvm, DM_USE_VXVM},
67 	{inuse_fs, DM_USE_FS},  /* fs should always be last */
68 	{NULL, NULL}
69 };
70 
71 static int	add_inuse(char *name, nvlist_t *attrs);
72 static int	desc_ok(descriptor_t *dp);
73 static void	dsk2rdsk(char *dsk, char *rdsk, int size);
74 static int	get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs);
75 static descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp);
76 static descriptor_t **get_removable_assocs(descriptor_t *desc, char *volm_path,
77 		    int *errp);
78 static int	get_slice_num(slice_t *devp);
79 static int	match_fixed_name(disk_t *dp, char *name, int *errp);
80 static int	match_removable_name(disk_t *dp, char *name, int *errp);
81 static int	make_fixed_descriptors(disk_t *dp);
82 static int	make_removable_descriptors(disk_t *dp);
83 static int	make_volm_dir_descriptors(disk_t *dp, int fd,
84 		    char *volm_path);
85 static int	num_removable_slices(int fd, struct stat *bufp,
86 		    char *volm_path);
87 
88 descriptor_t **
89 slice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
90     int *errp)
91 {
92 	if (!desc_ok(desc)) {
93 	    *errp = ENODEV;
94 	    return (NULL);
95 	}
96 
97 	switch (type) {
98 	case DM_MEDIA:
99 	    return (media_get_assocs(desc, errp));
100 	case DM_PARTITION:
101 	    return (partition_get_assocs(desc, errp));
102 	}
103 
104 	*errp = EINVAL;
105 	return (NULL);
106 }
107 
108 /*
109  * This is called by media/partition to get the slice descriptors for the given
110  * media/partition descriptor.
111  * For media, just get the slices, but for a partition, it must be a solaris
112  * partition and if there are active partitions, it must be the active one.
113  */
114 descriptor_t **
115 slice_get_assocs(descriptor_t *desc, int *errp)
116 {
117 	int		under_volm = 0;
118 	char		volm_path[MAXPATHLEN];
119 
120 	/* Just check the first drive name. */
121 	if (desc->p.disk->aliases == NULL) {
122 	    *errp = 0;
123 	    return (libdiskmgt_empty_desc_array(errp));
124 	}
125 
126 	if (desc->p.disk->removable) {
127 	    if ((under_volm = media_get_volm_path(desc->p.disk, volm_path,
128 		sizeof (volm_path)))) {
129 		if (volm_path[0] == 0) {
130 		    /* no media */
131 		    *errp = 0;
132 		    return (libdiskmgt_empty_desc_array(errp));
133 		}
134 	    }
135 	}
136 
137 	if (desc->p.disk->removable) {
138 	    if (under_volm) {
139 		return (get_removable_assocs(desc, volm_path, errp));
140 	    } else {
141 		return (get_fixed_assocs(desc, errp));
142 	    }
143 	} else {
144 	    return (get_fixed_assocs(desc, errp));
145 	}
146 }
147 
148 nvlist_t *
149 slice_get_attributes(descriptor_t *dp, int *errp)
150 {
151 	nvlist_t	*attrs = NULL;
152 	int		fd;
153 	char		devpath[MAXPATHLEN];
154 
155 	if (!desc_ok(dp)) {
156 	    *errp = ENODEV;
157 	    return (NULL);
158 	}
159 
160 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
161 	    *errp = ENOMEM;
162 	    return (NULL);
163 	}
164 
165 	/* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
166 	dsk2rdsk(dp->name, devpath, sizeof (devpath));
167 	fd = open(devpath, O_RDONLY|O_NDELAY);
168 
169 	if ((*errp = get_attrs(dp, fd, attrs)) != 0) {
170 	    nvlist_free(attrs);
171 	    attrs = NULL;
172 	}
173 
174 	if (fd >= 0) {
175 	    (void) close(fd);
176 	}
177 
178 	return (attrs);
179 }
180 
181 /*
182  * Look for the slice by the slice devpath.
183  */
184 descriptor_t *
185 slice_get_descriptor_by_name(char *name, int *errp)
186 {
187 	int		found = 0;
188 	disk_t		*dp;
189 
190 	for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) {
191 	    if (dp->removable) {
192 		found = match_removable_name(dp, name, errp);
193 	    } else {
194 		found = match_fixed_name(dp, name, errp);
195 	    }
196 
197 	    if (found) {
198 		char	mname[MAXPATHLEN];
199 
200 		if (*errp != 0) {
201 		    return (NULL);
202 		}
203 
204 		mname[0] = 0;
205 		(void) media_read_name(dp, mname, sizeof (mname));
206 
207 		return (cache_get_desc(DM_SLICE, dp, name, mname, errp));
208 	    }
209 	}
210 
211 	*errp = ENODEV;
212 	return (NULL);
213 }
214 
215 /* ARGSUSED */
216 descriptor_t **
217 slice_get_descriptors(int filter[], int *errp)
218 {
219 	return (cache_get_descriptors(DM_SLICE, errp));
220 }
221 
222 char *
223 slice_get_name(descriptor_t *desc)
224 {
225 	return (desc->name);
226 }
227 
228 nvlist_t *
229 slice_get_stats(descriptor_t *dp, int stat_type, int *errp)
230 {
231 	nvlist_t	*stats;
232 	char		*str;
233 
234 	if (stat_type != DM_SLICE_STAT_USE) {
235 	    *errp = EINVAL;
236 	    return (NULL);
237 	}
238 
239 	*errp = 0;
240 
241 	if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) {
242 	    *errp = ENOMEM;
243 	    return (NULL);
244 	}
245 
246 	if ((*errp = add_inuse(dp->name, stats)) != 0) {
247 	    return (NULL);
248 	}
249 
250 	/* if no cluster use, check for a use of the local name */
251 	if (nvlist_lookup_string(stats, DM_USED_BY, &str) != 0) {
252 	    disk_t	*diskp;
253 
254 	    diskp = dp->p.disk;
255 	    if (diskp->aliases != NULL && diskp->aliases->cluster) {
256 		slice_t		*sp;
257 		int		snum = -1;
258 		struct dk_minfo	minfo;
259 		struct dk_cinfo	dkinfo;
260 		char		devpath[MAXPATHLEN];
261 		int		fd;
262 
263 		/* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
264 		dsk2rdsk(dp->name, devpath, sizeof (devpath));
265 		fd = open(devpath, O_RDONLY|O_NDELAY);
266 
267 		if (fd >= 0 && media_read_info(fd, &minfo) &&
268 		    ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
269 		    snum = dkinfo.dki_partition;
270 		}
271 
272 		if (fd >= 0) {
273 		    (void) close(fd);
274 		}
275 
276 		if (snum >= 0) {
277 		    for (sp = diskp->aliases->orig_paths; sp != NULL;
278 			sp = sp->next) {
279 
280 			if (sp->slice_num == snum) {
281 			    char	localpath[MAXPATHLEN];
282 
283 			    slice_rdsk2dsk(sp->devpath, localpath,
284 				sizeof (localpath));
285 
286 			    if ((*errp = add_inuse(localpath, stats)) != 0) {
287 				return (NULL);
288 			    }
289 
290 			    break;
291 			}
292 		    }
293 		}
294 	    }
295 	}
296 
297 	return (stats);
298 }
299 
300 /*
301  * A slice descriptor points to a disk, the name is the devpath and the
302  * secondary name is the media name.
303  */
304 int
305 slice_make_descriptors()
306 {
307 	disk_t		*dp;
308 
309 	dp = cache_get_disklist();
310 	while (dp != NULL) {
311 	    int	error;
312 
313 	    if (dp->removable) {
314 		error = make_removable_descriptors(dp);
315 	    } else {
316 		error = make_fixed_descriptors(dp);
317 	    }
318 	    if (error != 0) {
319 		return (error);
320 	    }
321 
322 	    dp = dp->next;
323 	}
324 
325 	return (0);
326 }
327 
328 /* convert rdsk paths to dsk paths */
329 void
330 slice_rdsk2dsk(char *rdsk, char *dsk, int size)
331 {
332 	char	*strp;
333 
334 	(void) strlcpy(dsk, rdsk, size);
335 
336 	if ((strp = strstr(dsk, "/rdsk/")) == NULL) {
337 	    /* not rdsk, check for floppy */
338 	    strp = strstr(dsk, "/rdiskette");
339 	}
340 
341 	if (strp != NULL) {
342 	    strp++;	/* move ptr to the r in rdsk or rdiskette */
343 
344 	    /* move the succeeding chars over by one */
345 	    do {
346 		*strp = *(strp + 1);
347 		strp++;
348 	    } while (*strp);
349 	}
350 }
351 
352 /*
353  * Check if/how the slice is used.
354  */
355 static int
356 add_inuse(char *name, nvlist_t *attrs)
357 {
358 	int	i;
359 	int	error;
360 
361 	for (i = 0; detectors[i].detectorp != NULL; i ++) {
362 	    if ((detectors[i].detectorp)(name, attrs, &error) || error != 0) {
363 		if (error != 0) {
364 		    return (error);
365 		}
366 		break;
367 	    }
368 	}
369 
370 	return (0);
371 }
372 
373 /* return 1 if the slice descriptor is still valid, 0 if not. */
374 static int
375 desc_ok(descriptor_t *dp)
376 {
377 	/* First verify the media name for removable media */
378 	if (dp->p.disk->removable) {
379 	    char	mname[MAXPATHLEN];
380 
381 	    if (!media_read_name(dp->p.disk, mname, sizeof (mname))) {
382 		return (0);
383 	    }
384 
385 	    if (mname[0] == 0) {
386 		return (libdiskmgt_str_eq(dp->secondary_name, NULL));
387 	    } else {
388 		return (libdiskmgt_str_eq(dp->secondary_name, mname));
389 	    }
390 	}
391 
392 	/*
393 	 * We could verify the slice is still there, but other code down the
394 	 * line already does these checks (e.g. see get_attrs).
395 	 */
396 
397 	return (1);
398 }
399 
400 /* convert dsk paths to rdsk paths */
401 static void
402 dsk2rdsk(char *dsk, char *rdsk, int size)
403 {
404 	char	*slashp;
405 	size_t	len;
406 
407 	(void) strlcpy(rdsk, dsk, size);
408 
409 	/* make sure there is enough room to add the r to dsk */
410 	len = strlen(dsk);
411 	if (len + 2 > size) {
412 	    return;
413 	}
414 
415 	if ((slashp = strstr(rdsk, "/dsk/")) == NULL) {
416 	    /* not dsk, check for floppy */
417 	    slashp = strstr(rdsk, "/diskette");
418 	}
419 
420 	if (slashp != NULL) {
421 	    char	*endp;
422 
423 	    endp = rdsk + len;	/* point to terminating 0 */
424 	    /* move the succeeding chars over by one */
425 	    do {
426 		*(endp + 1) = *endp;
427 		endp--;
428 	    } while (endp != slashp);
429 
430 	    *(endp + 1) = 'r';
431 	}
432 }
433 
434 static int
435 get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs)
436 {
437 	struct dk_minfo	minfo;
438 	int		status;
439 	int		data_format = FMT_UNKNOWN;
440 	int		snum = -1;
441 	int		error;
442 	struct vtoc	vtoc;
443 	struct dk_gpt	*efip;
444 	struct dk_cinfo	dkinfo;
445 	disk_t		*diskp;
446 	char		localpath[MAXPATHLEN];
447 	int		cooked_fd;
448 	struct stat	buf;
449 	int		mntpnt = 0;
450 
451 	if (fd < 0) {
452 	    return (ENODEV);
453 	}
454 
455 	/* First make sure media is inserted and spun up. */
456 	if (!media_read_info(fd, &minfo)) {
457 	    return (ENODEV);
458 	}
459 
460 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
461 	    data_format = FMT_VTOC;
462 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
463 	    data_format = FMT_EFI;
464 	    if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
465 		efi_free(efip);
466 		return (ENOMEM);
467 	    }
468 	}
469 
470 	if (data_format == FMT_UNKNOWN) {
471 	    return (ENODEV);
472 	}
473 
474 	if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
475 	    snum = dkinfo.dki_partition;
476 	}
477 
478 	/* check the slice */
479 	if (data_format == FMT_VTOC) {
480 	    if (snum < 0 || snum >= vtoc.v_nparts ||
481 		vtoc.v_part[snum].p_size == 0) {
482 		return (ENODEV);
483 	    }
484 	} else { /* data_format == FMT_EFI */
485 	    if (snum < 0 || snum >= efip->efi_nparts ||
486 		efip->efi_parts[snum].p_size == 0) {
487 		efi_free(efip);
488 		return (ENODEV);
489 	    }
490 	}
491 
492 	/* the slice exists */
493 
494 	if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) {
495 	    if (data_format == FMT_EFI) {
496 		efi_free(efip);
497 	    }
498 	    return (ENOMEM);
499 	}
500 
501 	if (data_format == FMT_VTOC) {
502 	    if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start)
503 		!= 0) {
504 		return (ENOMEM);
505 	    }
506 
507 	    if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size)
508 		!= 0) {
509 		return (ENOMEM);
510 	    }
511 
512 	    if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag)
513 		!= 0) {
514 		return (ENOMEM);
515 	    }
516 
517 	    if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag)
518 		!= 0) {
519 		return (ENOMEM);
520 	    }
521 
522 	} else { /* data_format == FMT_EFI */
523 	    if (nvlist_add_uint64(attrs, DM_START,
524 		efip->efi_parts[snum].p_start) != 0) {
525 		efi_free(efip);
526 		return (ENOMEM);
527 	    }
528 
529 	    if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size)
530 		!= 0) {
531 		efi_free(efip);
532 		return (ENOMEM);
533 	    }
534 
535 	    if (efip->efi_parts[snum].p_name[0] != 0) {
536 		char	label[EFI_PART_NAME_LEN + 1];
537 
538 		(void) snprintf(label, sizeof (label), "%.*s",
539 		    EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
540 		if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
541 		    efi_free(efip);
542 		    return (ENOMEM);
543 		}
544 	    }
545 	}
546 
547 	if (data_format == FMT_EFI) {
548 	    efi_free(efip);
549 	}
550 
551 	if (inuse_mnt(dp->name, attrs, &error)) {
552 	    if (error != 0) {
553 		return (error);
554 	    }
555 	    mntpnt = 1;
556 	}
557 
558 	/*
559 	 * Some extra attrs for cluster slices.
560 	 *
561 	 * get localname and possible mnt point for localpath
562 	 */
563 	localpath[0] = 0;
564 	diskp = dp->p.disk;
565 	if (diskp->aliases != NULL && diskp->aliases->cluster) {
566 	    slice_t *sp;
567 
568 	    for (sp = diskp->aliases->orig_paths; sp != NULL; sp = sp->next) {
569 		if (sp->slice_num == -1) {
570 		    /* determine the slice number for this path */
571 		    int			sfd;
572 		    struct dk_cinfo	dkinfo;
573 
574 		    if ((sfd = open(sp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
575 			if (ioctl(sfd, DKIOCINFO, &dkinfo) >= 0) {
576 			    sp->slice_num = dkinfo.dki_partition;
577 			}
578 			(void) close(sfd);
579 		    }
580 		}
581 
582 		if (sp->slice_num == snum) {
583 		    slice_rdsk2dsk(sp->devpath, localpath, sizeof (localpath));
584 
585 		    if (nvlist_add_string(attrs, DM_LOCALNAME, localpath)
586 			!= 0) {
587 			return (ENOMEM);
588 		    }
589 
590 		    if (mntpnt == 0) {
591 			if (inuse_mnt(localpath, attrs, &error)) {
592 			    if (error != 0) {
593 				return (error);
594 			    }
595 			}
596 		    }
597 
598 		    break;
599 		}
600 	    }
601 	}
602 
603 	if (fstat(fd, &buf) != -1) {
604 	    if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
605 		return (ENOMEM);
606 	    }
607 	}
608 
609 	/*
610 	 * We need to open the cooked slice (not the raw one) to get the
611 	 * correct devid.  Also see if we need to read the localpath for the
612 	 * cluster disk, since the minor name is unavailable for the did pseudo
613 	 * device.
614 	 */
615 	if (localpath[0] != 0) {
616 	    cooked_fd = open(localpath, O_RDONLY|O_NDELAY);
617 	} else {
618 	    cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);
619 	}
620 
621 	if (cooked_fd >= 0) {
622 	    int		no_mem = 0;
623 	    ddi_devid_t	devid;
624 
625 	    if (devid_get(cooked_fd, &devid) == 0) {
626 		char	*minor;
627 
628 		if (devid_get_minor_name(cooked_fd, &minor) == 0) {
629 		    char	*devidstr;
630 
631 		    if ((devidstr = devid_str_encode(devid, minor)) != 0) {
632 
633 			if (nvlist_add_string(attrs, DM_DEVICEID, devidstr)
634 			    != 0) {
635 			    no_mem = 1;
636 			}
637 
638 			devid_str_free(devidstr);
639 		    }
640 		    devid_str_free(minor);
641 		}
642 		devid_free(devid);
643 	    }
644 	    (void) close(cooked_fd);
645 
646 	    if (no_mem) {
647 		return (ENOMEM);
648 	    }
649 	}
650 
651 	return (0);
652 }
653 
654 static descriptor_t **
655 get_fixed_assocs(descriptor_t *desc, int *errp)
656 {
657 	int		fd;
658 	int		status;
659 	int		data_format = FMT_UNKNOWN;
660 	int		cnt;
661 	struct vtoc	vtoc;
662 	struct dk_gpt	*efip;
663 	int		pos;
664 	char		*media_name = NULL;
665 	slice_t		*devp;
666 	descriptor_t	**slices;
667 
668 	if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) {
669 	    *errp = ENODEV;
670 	    return (NULL);
671 	}
672 
673 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
674 	    data_format = FMT_VTOC;
675 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
676 	    data_format = FMT_EFI;
677 	} else {
678 	    (void) close(fd);
679 	    *errp = 0;
680 	    return (libdiskmgt_empty_desc_array(errp));
681 	}
682 	(void) close(fd);
683 
684 	/* count the number of slices */
685 	for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL;
686 	    devp = devp->next, cnt++);
687 
688 	/* allocate the array for the descriptors */
689 	slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
690 	if (slices == NULL) {
691 	    if (data_format == FMT_EFI) {
692 		efi_free(efip);
693 	    }
694 	    *errp = ENOMEM;
695 	    return (NULL);
696 	}
697 
698 	/* get the media name from the descriptor */
699 	if (desc->type == DM_MEDIA) {
700 	    media_name = desc->name;
701 	} else {
702 	    /* must be a DM_PARTITION */
703 	    media_name = desc->secondary_name;
704 	}
705 
706 	pos = 0;
707 	for (devp = desc->p.disk->aliases->devpaths; devp != NULL;
708 	    devp = devp->next) {
709 
710 	    int		slice_num;
711 	    char	devpath[MAXPATHLEN];
712 
713 	    slice_num = get_slice_num(devp);
714 	    /* can't get slicenum, so no need to keep trying the drive */
715 	    if (slice_num == -1) {
716 		break;
717 	    }
718 
719 	    if (data_format == FMT_VTOC) {
720 		if (slice_num >= vtoc.v_nparts ||
721 		    vtoc.v_part[slice_num].p_size == 0) {
722 		    continue;
723 		}
724 	    } else { /* data_format == FMT_EFI */
725 		if (slice_num >= efip->efi_nparts ||
726 		    efip->efi_parts[slice_num].p_size == 0) {
727 		    continue;
728 		}
729 	    }
730 
731 	    slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
732 	    slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath,
733 		media_name, errp);
734 	    if (*errp != 0) {
735 		cache_free_descriptors(slices);
736 		if (data_format == FMT_EFI) {
737 		    efi_free(efip);
738 		}
739 		return (NULL);
740 	    }
741 	    pos++;
742 	}
743 	slices[pos] = NULL;
744 
745 	if (data_format == FMT_EFI) {
746 	    efi_free(efip);
747 	}
748 
749 	*errp = 0;
750 	return (slices);
751 }
752 
753 /*
754  * Called for loaded removable media under volume management control.
755  */
756 static descriptor_t **
757 get_removable_assocs(descriptor_t *desc, char *volm_path, int *errp)
758 {
759 	int		pos;
760 	int		fd;
761 	int		cnt;
762 	struct stat	buf;
763 	descriptor_t	**slices;
764 	char		*media_name = NULL;
765 	char		devpath[MAXPATHLEN];
766 
767 	/* get the media name from the descriptor */
768 	if (desc->type == DM_MEDIA) {
769 	    media_name = desc->name;
770 	} else {
771 	    /* must be a DM_PARTITION */
772 	    media_name = desc->secondary_name;
773 	}
774 
775 	/*
776 	 * For removable media under volm control the volm_path will
777 	 * either be a device (if the media is made up of a single slice) or
778 	 * a directory (if the media has multiple slices) with the slices
779 	 * as devices contained in the directory.
780 	 */
781 
782 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) < 0 ||
783 	    fstat(fd, &buf) != 0) {
784 	    *errp = ENODEV;
785 	    return (NULL);
786 	}
787 
788 	cnt = num_removable_slices(fd, &buf, volm_path);
789 
790 	/* allocate the array for the descriptors */
791 	slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
792 	if (slices == NULL) {
793 	    *errp = ENOMEM;
794 	    return (NULL);
795 	}
796 
797 	slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
798 
799 	pos = 0;
800 	*errp = 0;
801 	if (buf.st_mode & S_IFCHR) {
802 	    struct dk_minfo	minfo;
803 
804 	    /* Make sure media has readable label */
805 	    if (media_read_info(fd, &minfo)) {
806 		int		status;
807 		int		data_format = FMT_UNKNOWN;
808 		struct vtoc	vtoc;
809 		struct dk_gpt	*efip;
810 
811 		if ((status = read_vtoc(fd, &vtoc)) >= 0) {
812 		    data_format = FMT_VTOC;
813 		} else if (status == VT_ENOTSUP &&
814 		    efi_alloc_and_read(fd, &efip) >= 0) {
815 		    data_format = FMT_EFI;
816 		}
817 
818 		if (data_format != FMT_UNKNOWN) {
819 		    /* has a readable label */
820 		    slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk,
821 			devpath, media_name, errp);
822 		}
823 	    }
824 
825 	} else if (buf.st_mode & S_IFDIR) {
826 	    DIR			*dirp;
827 #ifdef _LP64
828 	    struct dirent 	*result;
829 #endif
830 
831 	    /* rewind, num_removable_slices already traversed */
832 	    (void) lseek(fd, 0, SEEK_SET);
833 
834 	    if ((dirp = fdopendir(fd)) != NULL) {
835 		struct dirent	*dentp;
836 
837 		dentp = (struct dirent *)malloc(sizeof (struct dirent) +
838 		    PATH_MAX + 1);
839 		if (dentp != NULL) {
840 #ifdef _LP64
841 		    while (readdir_r(dirp, dentp, &result) != NULL) {
842 #else
843 		    while (readdir_r(dirp, dentp) != NULL) {
844 #endif
845 			int	dfd;
846 			int	is_dev = 0;
847 			char	slice_path[MAXPATHLEN];
848 
849 			if (libdiskmgt_str_eq(".", dentp->d_name) ||
850 			    libdiskmgt_str_eq("..", dentp->d_name)) {
851 			    continue;
852 			}
853 
854 			(void) snprintf(slice_path, sizeof (slice_path),
855 			    "%s/%s", devpath, dentp->d_name);
856 
857 			if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
858 			    struct stat	buf;
859 
860 			    if (fstat(dfd, &buf) == 0 &&
861 				buf.st_mode & S_IFCHR) {
862 				is_dev = 1;
863 			    }
864 			    (void) close(dfd);
865 			}
866 
867 			if (!is_dev) {
868 			    continue;
869 			}
870 
871 			slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk,
872 			    slice_path, media_name, errp);
873 			if (*errp != 0) {
874 			    break;
875 			}
876 
877 		    }
878 		    free(dentp);
879 		}
880 		/* don't call closedir since it closes the fd */
881 	    }
882 	}
883 
884 	(void) close(fd);
885 
886 	slices[pos] = NULL;
887 
888 	if (*errp != 0) {
889 	    cache_free_descriptors(slices);
890 	    return (NULL);
891 	}
892 
893 	return (slices);
894 }
895 
896 static int
897 get_slice_num(slice_t *devp)
898 {
899 	/* check if we already determined the devpath slice number */
900 	if (devp->slice_num == -1) {
901 	    int		fd;
902 
903 	    if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
904 		struct dk_cinfo	dkinfo;
905 		if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
906 		    devp->slice_num = dkinfo.dki_partition;
907 		}
908 		(void) close(fd);
909 	    }
910 	}
911 
912 	return (devp->slice_num);
913 }
914 
915 static int
916 make_fixed_descriptors(disk_t *dp)
917 {
918 	int		error = 0;
919 	alias_t		*ap;
920 	slice_t		*devp;
921 	char		mname[MAXPATHLEN];
922 	int		data_format = FMT_UNKNOWN;
923 	struct vtoc	vtoc;
924 	struct dk_gpt	*efip;
925 
926 	/* Just check the first drive name. */
927 	if ((ap = dp->aliases) == NULL) {
928 	    return (0);
929 	}
930 
931 	mname[0] = 0;
932 	(void) media_read_name(dp, mname, sizeof (mname));
933 
934 	for (devp = ap->devpaths; devp != NULL; devp = devp->next) {
935 	    int		slice_num;
936 	    char	devpath[MAXPATHLEN];
937 
938 	    slice_num = get_slice_num(devp);
939 	    /* can't get slicenum, so no need to keep trying the drive */
940 	    if (slice_num == -1) {
941 		break;
942 	    }
943 
944 	    if (data_format == FMT_UNKNOWN) {
945 		int	fd;
946 		int	status;
947 
948 		if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
949 		    if ((status = read_vtoc(fd, &vtoc)) >= 0) {
950 			data_format = FMT_VTOC;
951 		    } else if (status == VT_ENOTSUP &&
952 			efi_alloc_and_read(fd, &efip) >= 0) {
953 			data_format = FMT_EFI;
954 		    }
955 		    (void) close(fd);
956 		}
957 	    }
958 
959 	    /* can't get slice data, so no need to keep trying the drive */
960 	    if (data_format == FMT_UNKNOWN) {
961 		break;
962 	    }
963 
964 	    if (data_format == FMT_VTOC) {
965 		if (slice_num >= vtoc.v_nparts ||
966 		    vtoc.v_part[slice_num].p_size == 0) {
967 		    continue;
968 		}
969 	    } else { /* data_format == FMT_EFI */
970 		if (slice_num >= efip->efi_nparts ||
971 		    efip->efi_parts[slice_num].p_size == 0) {
972 		    continue;
973 		}
974 	    }
975 
976 	    slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
977 	    cache_load_desc(DM_SLICE, dp, devpath, mname, &error);
978 	    if (error != 0) {
979 		break;
980 	    }
981 	}
982 
983 	if (data_format == FMT_EFI) {
984 	    efi_free(efip);
985 	}
986 
987 	return (error);
988 }
989 
990 /*
991  * For removable media under volm control we have to do some special handling.
992  * We don't use the vtoc and /dev/dsk devpaths, since the slices are named
993  * under the /vol fs.
994  */
995 static int
996 make_removable_descriptors(disk_t *dp)
997 {
998 	char		volm_path[MAXPATHLEN];
999 	int		error;
1000 	int		fd;
1001 
1002 	/*
1003 	 * If this removable drive is not under volm control, just use
1004 	 * normal handling.
1005 	 */
1006 	if (!media_get_volm_path(dp, volm_path, sizeof (volm_path))) {
1007 	    return (make_fixed_descriptors(dp));
1008 	}
1009 
1010 	if (volm_path[0] == 0) {
1011 	    /* no media */
1012 	    return (0);
1013 	}
1014 
1015 	/*
1016 	 * For removable media under volm control the rmmedia_devapth will
1017 	 * either be a device (if the media is made up of a single slice) or
1018 	 * a directory (if the media has multiple slices) with the slices
1019 	 * as devices contained in the directory.
1020 	 */
1021 	error = 0;
1022 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0) {
1023 	    struct stat	buf;
1024 
1025 	    if (fstat(fd, &buf) == 0) {
1026 		if (buf.st_mode & S_IFCHR) {
1027 		    int			status;
1028 		    int			data_format = FMT_UNKNOWN;
1029 		    struct dk_minfo	minfo;
1030 		    int			error;
1031 		    struct vtoc		vtoc;
1032 		    struct dk_gpt	*efip;
1033 		    char		devpath[MAXPATHLEN];
1034 
1035 		    /* Make sure media has readable label */
1036 		    if (!media_read_info(fd, &minfo)) {
1037 			/* no media */
1038 			return (0);
1039 		    }
1040 
1041 		    if ((status = read_vtoc(fd, &vtoc)) >= 0) {
1042 			data_format = FMT_VTOC;
1043 		    } else if (status == VT_ENOTSUP &&
1044 			efi_alloc_and_read(fd, &efip) >= 0) {
1045 			data_format = FMT_EFI;
1046 		    }
1047 
1048 		    if (data_format == FMT_UNKNOWN) {
1049 			/* no readable label */
1050 			return (0);
1051 		    }
1052 
1053 		    slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
1054 		    /* The media name is the volm_path in this case. */
1055 		    cache_load_desc(DM_SLICE, dp, devpath, volm_path, &error);
1056 
1057 		} else if (buf.st_mode & S_IFDIR) {
1058 		    /* each device file in the dir represents a slice */
1059 		    error = make_volm_dir_descriptors(dp, fd, volm_path);
1060 		}
1061 	    }
1062 	    (void) close(fd);
1063 	}
1064 
1065 	return (error);
1066 }
1067 
1068 /*
1069  * This handles removable media with slices under volume management control.
1070  * In this case we have a dir which is the media name and each slice on the
1071  * media is a device file in this dir.
1072  */
1073 static int
1074 make_volm_dir_descriptors(disk_t *dp, int dirfd, char *volm_path)
1075 {
1076 	int		error;
1077 	DIR		*dirp;
1078 	struct dirent	*dentp;
1079 #ifdef _LP64
1080 	struct dirent	*result;
1081 #endif
1082 	char		devpath[MAXPATHLEN];
1083 
1084 	if ((dirp = fdopendir(dirfd)) == NULL) {
1085 	    return (0);
1086 	}
1087 
1088 	slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
1089 
1090 	error = 0;
1091 	dentp = (struct dirent *)malloc(sizeof (struct dirent) +
1092 	    PATH_MAX + 1);
1093 	if (dentp != NULL) {
1094 #ifdef _LP64
1095 	    while (readdir_r(dirp, dentp, &result) != NULL) {
1096 #else
1097 	    while (readdir_r(dirp, dentp) != NULL) {
1098 #endif
1099 		int	fd;
1100 		char	slice_path[MAXPATHLEN];
1101 
1102 		if (libdiskmgt_str_eq(".", dentp->d_name) ||
1103 		    libdiskmgt_str_eq("..", dentp->d_name)) {
1104 		    continue;
1105 		}
1106 
1107 		(void) snprintf(slice_path, sizeof (slice_path), "%s/%s",
1108 		    devpath, dentp->d_name);
1109 
1110 		if ((fd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
1111 		    struct stat	buf;
1112 
1113 		    if (fstat(fd, &buf) == 0 && buf.st_mode & S_IFCHR) {
1114 			/* The media name is the volm_path in this case. */
1115 			cache_load_desc(DM_SLICE, dp, slice_path, volm_path,
1116 			    &error);
1117 			if (error != 0) {
1118 			    (void) close(fd);
1119 			    break;
1120 			}
1121 		    }
1122 
1123 		    (void) close(fd);
1124 		}
1125 	    }
1126 	    free(dentp);
1127 	}
1128 	/* don't call closedir since it closes the fd */
1129 
1130 	return (error);
1131 }
1132 
1133 /*
1134  * Just look for the name on the devpaths we have cached. Return 1 if we
1135  * find the name and the size of that slice is non-zero.
1136  */
1137 static int
1138 match_fixed_name(disk_t *diskp, char *name, int *errp)
1139 {
1140 	slice_t		*dp = NULL;
1141 	alias_t		*ap;
1142 	int		slice_num;
1143 	int		fd;
1144 	int		status;
1145 	int		data_format = FMT_UNKNOWN;
1146 	struct vtoc	vtoc;
1147 	struct dk_gpt	*efip;
1148 
1149 	ap = diskp->aliases;
1150 	while (ap != NULL) {
1151 	    slice_t	*devp;
1152 
1153 	    devp = ap->devpaths;
1154 	    while (devp != NULL) {
1155 		char	path[MAXPATHLEN];
1156 
1157 		slice_rdsk2dsk(devp->devpath, path, sizeof (path));
1158 		if (libdiskmgt_str_eq(path, name)) {
1159 		    /* found it */
1160 		    dp = devp;
1161 		    break;
1162 		}
1163 
1164 		devp = devp->next;
1165 	    }
1166 
1167 	    if (dp != NULL) {
1168 		break;
1169 	    }
1170 
1171 	    ap = ap->next;
1172 	}
1173 
1174 	if (dp == NULL) {
1175 	    *errp = 0;
1176 	    return (0);
1177 	}
1178 
1179 	/*
1180 	 * If we found a match on the name we now have to check that this
1181 	 * slice really exists (non-0 size).
1182 	 */
1183 
1184 	slice_num = get_slice_num(dp);
1185 	/* can't get slicenum, so no slice */
1186 	if (slice_num == -1) {
1187 	    *errp = ENODEV;
1188 	    return (1);
1189 	}
1190 
1191 	if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) {
1192 	    *errp = ENODEV;
1193 	    return (1);
1194 	}
1195 
1196 	if ((status = read_vtoc(fd, &vtoc)) >= 0) {
1197 	    data_format = FMT_VTOC;
1198 	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
1199 	    data_format = FMT_EFI;
1200 	} else {
1201 	    (void) close(fd);
1202 	    *errp = ENODEV;
1203 	    return (1);
1204 	}
1205 	(void) close(fd);
1206 
1207 	if (data_format == FMT_VTOC) {
1208 	    if (slice_num < vtoc.v_nparts &&
1209 		vtoc.v_part[slice_num].p_size > 0) {
1210 		*errp = 0;
1211 		return (1);
1212 	    }
1213 	} else { /* data_format == FMT_EFI */
1214 	    if (slice_num < efip->efi_nparts &&
1215 		efip->efi_parts[slice_num].p_size > 0) {
1216 		efi_free(efip);
1217 		*errp = 0;
1218 		return (1);
1219 	    }
1220 	    efi_free(efip);
1221 	}
1222 
1223 	*errp = ENODEV;
1224 	return (1);
1225 }
1226 
1227 static int
1228 match_removable_name(disk_t *diskp, char *name, int *errp)
1229 {
1230 	char		volm_path[MAXPATHLEN];
1231 	int		found;
1232 	int		fd;
1233 	struct stat	buf;
1234 
1235 	/*
1236 	 * If this removable drive is not under volm control, just use
1237 	 * normal handling.
1238 	 */
1239 	if (!media_get_volm_path(diskp, volm_path, sizeof (volm_path))) {
1240 	    return (match_fixed_name(diskp, name, errp));
1241 	}
1242 
1243 	if (volm_path[0] == 0) {
1244 	    /* no media */
1245 	    *errp = 0;
1246 	    return (0);
1247 	}
1248 
1249 	/*
1250 	 * For removable media under volm control the rmmedia_devapth will
1251 	 * either be a device (if the media is made up of a single slice) or
1252 	 * a directory (if the media has multiple slices) with the slices
1253 	 * as devices contained in the directory.
1254 	 */
1255 
1256 	*errp = 0;
1257 
1258 	found = 0;
1259 	if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0 &&
1260 	    fstat(fd, &buf) == 0) {
1261 
1262 	    if (buf.st_mode & S_IFCHR) {
1263 		char	devpath[MAXPATHLEN];
1264 
1265 		slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
1266 		if (libdiskmgt_str_eq(name, devpath)) {
1267 		    found = 1;
1268 		}
1269 
1270 	    } else if (buf.st_mode & S_IFDIR) {
1271 		/* each device file in the dir represents a slice */
1272 		DIR		*dirp;
1273 
1274 		if ((dirp = fdopendir(fd)) != NULL) {
1275 		    struct dirent	*dentp;
1276 #ifdef _LP64
1277 		    struct dirent	*result;
1278 #endif
1279 		    char		devpath[MAXPATHLEN];
1280 
1281 		    slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
1282 
1283 		    dentp = (struct dirent *)malloc(sizeof (struct dirent) +
1284 			PATH_MAX + 1);
1285 		    if (dentp != NULL) {
1286 #ifdef _LP64
1287 			while (readdir_r(dirp, dentp, &result) != NULL) {
1288 #else
1289 			while (readdir_r(dirp, dentp) != NULL) {
1290 #endif
1291 			    char	slice_path[MAXPATHLEN];
1292 
1293 			    if (libdiskmgt_str_eq(".", dentp->d_name) ||
1294 				libdiskmgt_str_eq("..", dentp->d_name)) {
1295 				continue;
1296 			    }
1297 
1298 			    (void) snprintf(slice_path, sizeof (slice_path),
1299 				"%s/%s", devpath, dentp->d_name);
1300 
1301 			    if (libdiskmgt_str_eq(name, slice_path)) {
1302 				/* found name, check device */
1303 				int	dfd;
1304 				int	is_dev = 0;
1305 
1306 				if ((dfd = open(slice_path, O_RDONLY|O_NDELAY))
1307 				    >= 0) {
1308 				    struct stat	buf;
1309 
1310 				    if (fstat(dfd, &buf) == 0 &&
1311 					buf.st_mode & S_IFCHR) {
1312 					is_dev = 1;
1313 				    }
1314 				    (void) close(dfd);
1315 				}
1316 
1317 				/* we found the name */
1318 				found = 1;
1319 
1320 				if (!is_dev) {
1321 				    *errp = ENODEV;
1322 				}
1323 
1324 				break;
1325 			    }
1326 			}
1327 			free(dentp);
1328 		    }
1329 		    /* don't call closedir since it closes the fd */
1330 		}
1331 	    } /* end of dir handling */
1332 
1333 	    (void) close(fd);
1334 	}
1335 
1336 	return (found);
1337 }
1338 
1339 static int
1340 num_removable_slices(int fd, struct stat *bufp, char *volm_path)
1341 {
1342 	int cnt = 0;
1343 
1344 	if (bufp->st_mode & S_IFCHR) {
1345 	    cnt = 1;
1346 
1347 	} else if (bufp->st_mode & S_IFDIR) {
1348 	    /* each device file in the dir represents a slice */
1349 	    DIR		*dirp;
1350 
1351 	    if ((dirp = fdopendir(fd)) != NULL) {
1352 		struct dirent	*dentp;
1353 #ifdef _LP64
1354 		struct dirent	*result;
1355 #endif
1356 		char		devpath[MAXPATHLEN];
1357 
1358 		slice_rdsk2dsk(volm_path, devpath, sizeof (devpath));
1359 
1360 		dentp = (struct dirent *)malloc(sizeof (struct dirent) +
1361 		    PATH_MAX + 1);
1362 		if (dentp != NULL) {
1363 #ifdef _LP64
1364 		    while (readdir_r(dirp, dentp, &result) != NULL) {
1365 #else
1366 		    while (readdir_r(dirp, dentp) != NULL) {
1367 #endif
1368 			int	dfd;
1369 			char	slice_path[MAXPATHLEN];
1370 
1371 			if (libdiskmgt_str_eq(".", dentp->d_name) ||
1372 			    libdiskmgt_str_eq("..", dentp->d_name)) {
1373 			    continue;
1374 			}
1375 
1376 			(void) snprintf(slice_path, sizeof (slice_path),
1377 			    "%s/%s", devpath, dentp->d_name);
1378 
1379 			if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) {
1380 			    struct stat	buf;
1381 
1382 			    if (fstat(dfd, &buf) == 0 &&
1383 				buf.st_mode & S_IFCHR) {
1384 				cnt++;
1385 			    }
1386 			    (void) close(dfd);
1387 			}
1388 		    }
1389 		    free(dentp);
1390 		}
1391 		/* don't call closedir since it closes the fd */
1392 	    }
1393 	} /* end of dir handling */
1394 
1395 	return (cnt);
1396 }
1397