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