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