2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <fcntl.h>
2N/A#include <libdevinfo.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <dirent.h>
2N/A#include <sys/dkio.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/sunddi.h>
2N/A#include <sys/types.h>
2N/A#include <sys/vtoc.h>
2N/A#include <unistd.h>
2N/A#include <devid.h>
2N/A#include <dirent.h>
2N/A#include <sys/dktp/fdisk.h>
2N/A#include <sys/efi_partition.h>
2N/A
2N/A#include "libdiskmgt.h"
2N/A#include "disks_private.h"
2N/A#include "partition.h"
2N/A
2N/Atypedef int (*detectorp)(char *, nvlist_t *, int *);
2N/A
2N/Astatic detectorp detectors[] = {
2N/A inuse_mnt,
2N/A inuse_svm,
2N/A inuse_active_zpool,
2N/A inuse_lu,
2N/A inuse_dump,
2N/A inuse_vxvm,
2N/A inuse_exported_zpool,
2N/A inuse_fs, /* fs should always be last */
2N/A NULL
2N/A};
2N/A
2N/Astatic int add_inuse(char *name, nvlist_t *attrs);
2N/Astatic int desc_ok(descriptor_t *dp);
2N/Astatic void dsk2rdsk(char *dsk, char *rdsk, int size);
2N/Astatic int get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs);
2N/Astatic descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp);
2N/Astatic int get_slice_num(slice_t *devp);
2N/Astatic int match_fixed_name(disk_t *dp, char *name, int *errp);
2N/Astatic int make_fixed_descriptors(disk_t *dp);
2N/A
2N/Adescriptor_t **
2N/Aslice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
2N/A int *errp)
2N/A{
2N/A if (!desc_ok(desc)) {
2N/A *errp = ENODEV;
2N/A return (NULL);
2N/A }
2N/A
2N/A switch (type) {
2N/A case DM_MEDIA:
2N/A return (media_get_assocs(desc, errp));
2N/A case DM_PARTITION:
2N/A return (partition_get_assocs(desc, errp));
2N/A }
2N/A
2N/A *errp = EINVAL;
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * This is called by media/partition to get the slice descriptors for the given
2N/A * media/partition descriptor.
2N/A * For media, just get the slices, but for a partition, it must be a solaris
2N/A * partition and if there are active partitions, it must be the active one.
2N/A */
2N/Adescriptor_t **
2N/Aslice_get_assocs(descriptor_t *desc, int *errp)
2N/A{
2N/A /* Just check the first drive name. */
2N/A if (desc->p.disk->aliases == NULL) {
2N/A *errp = 0;
2N/A return (libdiskmgt_empty_desc_array(errp));
2N/A }
2N/A
2N/A return (get_fixed_assocs(desc, errp));
2N/A}
2N/A
2N/Anvlist_t *
2N/Aslice_get_attributes(descriptor_t *dp, int *errp)
2N/A{
2N/A nvlist_t *attrs = NULL;
2N/A int fd;
2N/A char devpath[MAXPATHLEN];
2N/A
2N/A if (!desc_ok(dp)) {
2N/A *errp = ENODEV;
2N/A return (NULL);
2N/A }
2N/A
2N/A if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
2N/A *errp = ENOMEM;
2N/A return (NULL);
2N/A }
2N/A
2N/A /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
2N/A dsk2rdsk(dp->name, devpath, sizeof (devpath));
2N/A fd = open(devpath, O_RDONLY|O_NDELAY);
2N/A
2N/A if ((*errp = get_attrs(dp, fd, attrs)) != 0) {
2N/A nvlist_free(attrs);
2N/A attrs = NULL;
2N/A }
2N/A
2N/A if (fd >= 0) {
2N/A (void) close(fd);
2N/A }
2N/A
2N/A return (attrs);
2N/A}
2N/A
2N/A/*
2N/A * Look for the slice by the slice devpath.
2N/A */
2N/Adescriptor_t *
2N/Aslice_get_descriptor_by_name(char *name, int *errp)
2N/A{
2N/A descriptor_t *des;
2N/A disk_t *dp;
2N/A int locked;
2N/A
2N/A *errp = ENODEV;
2N/A des = NULL;
2N/A
2N/A cache_rlock(&locked);
2N/A for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) {
2N/A if (match_fixed_name(dp, name, errp)) {
2N/A char mname[MAXPATHLEN];
2N/A
2N/A if (*errp != 0)
2N/A break;
2N/A
2N/A mname[0] = 0;
2N/A (void) media_read_name(dp, mname, sizeof (mname));
2N/A
2N/A des = cache_get_desc(DM_SLICE, dp, name, mname, errp);
2N/A break;
2N/A }
2N/A }
2N/A cache_unlock(&locked);
2N/A
2N/A return (des);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Adescriptor_t **
2N/Aslice_get_descriptors(int filter[], int *errp)
2N/A{
2N/A return (cache_get_descriptors(DM_SLICE, errp));
2N/A}
2N/A
2N/Achar *
2N/Aslice_get_name(descriptor_t *desc)
2N/A{
2N/A return (desc->name);
2N/A}
2N/A
2N/Anvlist_t *
2N/Aslice_get_stats(descriptor_t *dp, int stat_type, int *errp)
2N/A{
2N/A nvlist_t *stats;
2N/A char *str;
2N/A
2N/A if (stat_type != DM_SLICE_STAT_USE) {
2N/A *errp = EINVAL;
2N/A return (NULL);
2N/A }
2N/A
2N/A *errp = 0;
2N/A
2N/A if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) {
2N/A *errp = ENOMEM;
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((*errp = add_inuse(dp->name, stats)) != 0) {
2N/A return (NULL);
2N/A }
2N/A
2N/A /* if no cluster use, check for a use of the local name */
2N/A if (nvlist_lookup_string(stats, DM_USED_BY, &str) != 0) {
2N/A disk_t *diskp;
2N/A
2N/A diskp = dp->p.disk;
2N/A if (diskp->aliases != NULL && diskp->aliases->cluster) {
2N/A slice_t *sp;
2N/A int snum = -1;
2N/A struct dk_minfo minfo;
2N/A struct dk_cinfo dkinfo;
2N/A char devpath[MAXPATHLEN];
2N/A int fd;
2N/A
2N/A /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
2N/A dsk2rdsk(dp->name, devpath, sizeof (devpath));
2N/A fd = open(devpath, O_RDONLY|O_NDELAY);
2N/A
2N/A if (fd >= 0 && media_read_info(fd, &minfo) &&
2N/A ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
2N/A snum = dkinfo.dki_partition;
2N/A }
2N/A
2N/A if (fd >= 0) {
2N/A (void) close(fd);
2N/A }
2N/A
2N/A if (snum >= 0) {
2N/A for (sp = diskp->aliases->orig_paths; sp != NULL;
2N/A sp = sp->next) {
2N/A
2N/A if (sp->slice_num == snum) {
2N/A char localpath[MAXPATHLEN];
2N/A
2N/A slice_rdsk2dsk(sp->devpath, localpath,
2N/A sizeof (localpath));
2N/A
2N/A if ((*errp = add_inuse(localpath, stats)) != 0) {
2N/A return (NULL);
2N/A }
2N/A
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (stats);
2N/A}
2N/A
2N/A/*
2N/A * A slice descriptor points to a disk, the name is the devpath and the
2N/A * secondary name is the media name.
2N/A */
2N/Aint
2N/Aslice_make_descriptors()
2N/A{
2N/A disk_t *dp;
2N/A int error = 0;
2N/A int locked;
2N/A
2N/A cache_rlock(&locked);
2N/A dp = cache_get_disklist();
2N/A while ((error == 0) && (dp != NULL)) {
2N/A error = make_fixed_descriptors(dp);
2N/A dp = dp->next;
2N/A }
2N/A cache_unlock(&locked);
2N/A
2N/A return (error);
2N/A}
2N/A
2N/A/* convert rdsk paths to dsk paths */
2N/Avoid
2N/Aslice_rdsk2dsk(char *rdsk, char *dsk, int size)
2N/A{
2N/A char *strp;
2N/A
2N/A (void) strlcpy(dsk, rdsk, size);
2N/A
2N/A if ((strp = strstr(dsk, "/rdsk/")) == NULL) {
2N/A /* not rdsk, check for floppy */
2N/A strp = strstr(dsk, "/rdiskette");
2N/A }
2N/A
2N/A if (strp != NULL) {
2N/A strp++; /* move ptr to the r in rdsk or rdiskette */
2N/A
2N/A /* move the succeeding chars over by one */
2N/A do {
2N/A *strp = *(strp + 1);
2N/A strp++;
2N/A } while (*strp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Check if/how the slice is used.
2N/A */
2N/Astatic int
2N/Aadd_inuse(char *name, nvlist_t *attrs)
2N/A{
2N/A int i;
2N/A int error;
2N/A
2N/A for (i = 0; detectors[i] != NULL; i ++) {
2N/A if (detectors[i](name, attrs, &error) || error != 0) {
2N/A if (error != 0) {
2N/A return (error);
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* return 1 if the slice descriptor is still valid, 0 if not. */
2N/Astatic int
2N/Adesc_ok(descriptor_t *dp)
2N/A{
2N/A /* First verify the media name for removable media */
2N/A if (dp->p.disk->removable) {
2N/A char mname[MAXPATHLEN];
2N/A
2N/A if (!media_read_name(dp->p.disk, mname, sizeof (mname))) {
2N/A return (0);
2N/A }
2N/A
2N/A if (mname[0] == 0) {
2N/A return (libdiskmgt_str_eq(dp->secondary_name, NULL));
2N/A } else {
2N/A return (libdiskmgt_str_eq(dp->secondary_name, mname));
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * We could verify the slice is still there, but other code down the
2N/A * line already does these checks (e.g. see get_attrs).
2N/A */
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A/* convert dsk paths to rdsk paths */
2N/Astatic void
2N/Adsk2rdsk(char *dsk, char *rdsk, int size)
2N/A{
2N/A char *slashp;
2N/A size_t len;
2N/A
2N/A (void) strlcpy(rdsk, dsk, size);
2N/A
2N/A /* make sure there is enough room to add the r to dsk */
2N/A len = strlen(dsk);
2N/A if (len + 2 > size) {
2N/A return;
2N/A }
2N/A
2N/A if ((slashp = strstr(rdsk, "/dsk/")) == NULL) {
2N/A /* not dsk, check for floppy */
2N/A slashp = strstr(rdsk, "/diskette");
2N/A }
2N/A
2N/A if (slashp != NULL) {
2N/A char *endp;
2N/A
2N/A endp = rdsk + len; /* point to terminating 0 */
2N/A /* move the succeeding chars over by one */
2N/A do {
2N/A *(endp + 1) = *endp;
2N/A endp--;
2N/A } while (endp != slashp);
2N/A
2N/A *(endp + 1) = 'r';
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aget_attrs(descriptor_t *dp, int fd, nvlist_t *attrs)
2N/A{
2N/A struct dk_minfo minfo;
2N/A int status;
2N/A int data_format = FMT_UNKNOWN;
2N/A int snum = -1;
2N/A int error;
2N/A struct extvtoc vtoc;
2N/A struct dk_gpt *efip;
2N/A struct dk_cinfo dkinfo;
2N/A disk_t *diskp;
2N/A char localpath[MAXPATHLEN];
2N/A int cooked_fd;
2N/A struct stat buf;
2N/A int mntpnt = 0;
2N/A
2N/A if (fd < 0) {
2N/A return (ENODEV);
2N/A }
2N/A
2N/A /* First make sure media is inserted and spun up. */
2N/A if (!media_read_info(fd, &minfo)) {
2N/A return (ENODEV);
2N/A }
2N/A
2N/A if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
2N/A data_format = FMT_VTOC;
2N/A } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
2N/A data_format = FMT_EFI;
2N/A if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
2N/A efi_free(efip);
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A if (data_format == FMT_UNKNOWN) {
2N/A return (ENODEV);
2N/A }
2N/A
2N/A if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
2N/A snum = dkinfo.dki_partition;
2N/A }
2N/A
2N/A /* check the slice */
2N/A if (data_format == FMT_VTOC) {
2N/A if (snum < 0 || snum >= vtoc.v_nparts ||
2N/A vtoc.v_part[snum].p_size == 0) {
2N/A return (ENODEV);
2N/A }
2N/A } else { /* data_format == FMT_EFI */
2N/A if (snum < 0 || snum >= efip->efi_nparts ||
2N/A efip->efi_parts[snum].p_size == 0) {
2N/A efi_free(efip);
2N/A return (ENODEV);
2N/A }
2N/A }
2N/A
2N/A /* the slice exists */
2N/A
2N/A if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) {
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (data_format == FMT_VTOC) {
2N/A if (nvlist_add_uint64(attrs, DM_START,
2N/A vtoc.v_part[snum].p_start) != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size)
2N/A != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag)
2N/A != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag)
2N/A != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A } else { /* data_format == FMT_EFI */
2N/A if (nvlist_add_uint64(attrs, DM_START,
2N/A efip->efi_parts[snum].p_start) != 0) {
2N/A efi_free(efip);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint64(attrs, DM_SIZE,
2N/A efip->efi_parts[snum].p_size) != 0) {
2N/A efi_free(efip);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint32(attrs, DM_TAG,
2N/A efip->efi_parts[snum].p_tag) != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (nvlist_add_uint32(attrs, DM_FLAG,
2N/A efip->efi_parts[snum].p_flag) != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (efip->efi_parts[snum].p_name[0] != 0) {
2N/A char label[EFI_PART_NAME_LEN + 1];
2N/A
2N/A (void) snprintf(label, sizeof (label), "%.*s",
2N/A EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
2N/A if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
2N/A efi_free(efip);
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A if (nvlist_add_uint8_array(attrs, DM_EFI_UGUID,
2N/A (uint8_t *)&(efip->efi_parts[snum].p_uguid),
2N/A sizeof (struct uuid))) {
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A
2N/A if (inuse_mnt(dp->name, attrs, &error)) {
2N/A if (error != 0) {
2N/A return (error);
2N/A }
2N/A mntpnt = 1;
2N/A }
2N/A
2N/A /*
2N/A * Some extra attrs for cluster slices.
2N/A *
2N/A * get localname and possible mnt point for localpath
2N/A */
2N/A localpath[0] = 0;
2N/A diskp = dp->p.disk;
2N/A if (diskp->aliases != NULL && diskp->aliases->cluster) {
2N/A slice_t *sp;
2N/A
2N/A for (sp = diskp->aliases->orig_paths; sp != NULL;
2N/A sp = sp->next) {
2N/A if (sp->slice_num == -1) {
2N/A /* determine the slice number for this path */
2N/A int sfd;
2N/A struct dk_cinfo dkinfo;
2N/A
2N/A if ((sfd = open(sp->devpath,
2N/A O_RDONLY|O_NDELAY)) >= 0) {
2N/A if (ioctl(sfd, DKIOCINFO,
2N/A &dkinfo) >= 0) {
2N/A sp->slice_num =
2N/A dkinfo.dki_partition;
2N/A }
2N/A (void) close(sfd);
2N/A }
2N/A }
2N/A
2N/A if (sp->slice_num == snum) {
2N/A slice_rdsk2dsk(sp->devpath, localpath,
2N/A sizeof (localpath));
2N/A
2N/A if (nvlist_add_string(attrs, DM_LOCALNAME,
2N/A localpath) != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A if (mntpnt == 0) {
2N/A if (inuse_mnt(localpath, attrs,
2N/A &error)) {
2N/A if (error != 0) {
2N/A return (error);
2N/A }
2N/A }
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (fstat(fd, &buf) != -1) {
2N/A if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * We need to open the cooked slice (not the raw one) to get the
2N/A * correct devid. Also see if we need to read the localpath for the
2N/A * cluster disk, since the minor name is unavailable for the did pseudo
2N/A * device.
2N/A */
2N/A if (localpath[0] != 0) {
2N/A cooked_fd = open(localpath, O_RDONLY|O_NDELAY);
2N/A } else {
2N/A cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);
2N/A }
2N/A
2N/A if (cooked_fd >= 0) {
2N/A int no_mem = 0;
2N/A ddi_devid_t devid;
2N/A
2N/A if (devid_get(cooked_fd, &devid) == 0) {
2N/A char *minor;
2N/A
2N/A if (devid_get_minor_name(cooked_fd, &minor) == 0) {
2N/A char *devidstr;
2N/A
2N/A if ((devidstr = devid_str_encode(devid, minor))
2N/A != 0) {
2N/A
2N/A if (nvlist_add_string(attrs,
2N/A DM_DEVICEID, devidstr) != 0) {
2N/A no_mem = 1;
2N/A }
2N/A
2N/A devid_str_free(devidstr);
2N/A }
2N/A devid_str_free(minor);
2N/A }
2N/A devid_free(devid);
2N/A }
2N/A (void) close(cooked_fd);
2N/A
2N/A if (no_mem) {
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic descriptor_t **
2N/Aget_fixed_assocs(descriptor_t *desc, int *errp)
2N/A{
2N/A int fd;
2N/A int status;
2N/A int data_format = FMT_UNKNOWN;
2N/A int cnt;
2N/A struct extvtoc vtoc;
2N/A struct dk_gpt *efip;
2N/A int pos;
2N/A char *media_name = NULL;
2N/A slice_t *devp;
2N/A descriptor_t **slices;
2N/A
2N/A if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) {
2N/A *errp = ENODEV;
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
2N/A data_format = FMT_VTOC;
2N/A } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
2N/A data_format = FMT_EFI;
2N/A } else {
2N/A (void) close(fd);
2N/A *errp = 0;
2N/A return (libdiskmgt_empty_desc_array(errp));
2N/A }
2N/A (void) close(fd);
2N/A
2N/A /* count the number of slices */
2N/A for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL;
2N/A devp = devp->next, cnt++);
2N/A
2N/A /* allocate the array for the descriptors */
2N/A slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
2N/A if (slices == NULL) {
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A *errp = ENOMEM;
2N/A return (NULL);
2N/A }
2N/A
2N/A /* get the media name from the descriptor */
2N/A if (desc->type == DM_MEDIA) {
2N/A media_name = desc->name;
2N/A } else {
2N/A /* must be a DM_PARTITION */
2N/A media_name = desc->secondary_name;
2N/A }
2N/A
2N/A pos = 0;
2N/A for (devp = desc->p.disk->aliases->devpaths; devp != NULL;
2N/A devp = devp->next) {
2N/A
2N/A int slice_num;
2N/A char devpath[MAXPATHLEN];
2N/A
2N/A slice_num = get_slice_num(devp);
2N/A /* can't get slicenum, so no need to keep trying the drive */
2N/A if (slice_num == -1) {
2N/A break;
2N/A }
2N/A
2N/A if (data_format == FMT_VTOC) {
2N/A if (slice_num >= vtoc.v_nparts ||
2N/A vtoc.v_part[slice_num].p_size == 0) {
2N/A continue;
2N/A }
2N/A } else { /* data_format == FMT_EFI */
2N/A if (slice_num >= efip->efi_nparts ||
2N/A efip->efi_parts[slice_num].p_size == 0) {
2N/A continue;
2N/A }
2N/A }
2N/A
2N/A slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
2N/A slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath,
2N/A media_name, errp);
2N/A if (*errp != 0) {
2N/A cache_free_descriptors(slices);
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A return (NULL);
2N/A }
2N/A pos++;
2N/A }
2N/A slices[pos] = NULL;
2N/A
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A
2N/A *errp = 0;
2N/A return (slices);
2N/A}
2N/A
2N/Astatic int
2N/Aget_slice_num(slice_t *devp)
2N/A{
2N/A /* check if we already determined the devpath slice number */
2N/A if (devp->slice_num == -1) {
2N/A int fd;
2N/A
2N/A if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) {
2N/A struct dk_cinfo dkinfo;
2N/A if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
2N/A devp->slice_num = dkinfo.dki_partition;
2N/A }
2N/A (void) close(fd);
2N/A }
2N/A }
2N/A
2N/A return (devp->slice_num);
2N/A}
2N/A
2N/Astatic int
2N/Amake_fixed_descriptors(disk_t *dp)
2N/A{
2N/A int error = 0;
2N/A alias_t *ap;
2N/A slice_t *devp;
2N/A char mname[MAXPATHLEN];
2N/A int data_format = FMT_UNKNOWN;
2N/A struct extvtoc vtoc;
2N/A struct dk_gpt *efip;
2N/A
2N/A /* Just check the first drive name. */
2N/A if ((ap = dp->aliases) == NULL) {
2N/A return (0);
2N/A }
2N/A
2N/A mname[0] = 0;
2N/A (void) media_read_name(dp, mname, sizeof (mname));
2N/A
2N/A for (devp = ap->devpaths; devp != NULL; devp = devp->next) {
2N/A int slice_num;
2N/A char devpath[MAXPATHLEN];
2N/A
2N/A slice_num = get_slice_num(devp);
2N/A /* can't get slicenum, so no need to keep trying the drive */
2N/A if (slice_num == -1) {
2N/A break;
2N/A }
2N/A
2N/A if (data_format == FMT_UNKNOWN) {
2N/A int fd;
2N/A int status;
2N/A
2N/A if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) {
2N/A if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
2N/A data_format = FMT_VTOC;
2N/A } else if (status == VT_ENOTSUP &&
2N/A efi_alloc_and_read(fd, &efip) >= 0) {
2N/A data_format = FMT_EFI;
2N/A }
2N/A (void) close(fd);
2N/A }
2N/A }
2N/A
2N/A /* can't get slice data, so no need to keep trying the drive */
2N/A if (data_format == FMT_UNKNOWN) {
2N/A break;
2N/A }
2N/A
2N/A if (data_format == FMT_VTOC) {
2N/A if (slice_num >= vtoc.v_nparts ||
2N/A vtoc.v_part[slice_num].p_size == 0) {
2N/A continue;
2N/A }
2N/A } else { /* data_format == FMT_EFI */
2N/A if (slice_num >= efip->efi_nparts ||
2N/A efip->efi_parts[slice_num].p_size == 0) {
2N/A continue;
2N/A }
2N/A }
2N/A
2N/A slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath));
2N/A cache_load_desc(DM_SLICE, dp, devpath, mname, &error);
2N/A if (error != 0) {
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (data_format == FMT_EFI) {
2N/A efi_free(efip);
2N/A }
2N/A
2N/A return (error);
2N/A}
2N/A
2N/A/*
2N/A * Just look for the name on the devpaths we have cached. Return 1 if we
2N/A * find the name and the size of that slice is non-zero.
2N/A */
2N/Astatic int
2N/Amatch_fixed_name(disk_t *diskp, char *name, int *errp)
2N/A{
2N/A slice_t *dp = NULL;
2N/A alias_t *ap;
2N/A int slice_num;
2N/A int fd;
2N/A int status;
2N/A int data_format = FMT_UNKNOWN;
2N/A struct extvtoc vtoc;
2N/A struct dk_gpt *efip;
2N/A
2N/A ap = diskp->aliases;
2N/A while (ap != NULL) {
2N/A slice_t *devp;
2N/A
2N/A devp = ap->devpaths;
2N/A while (devp != NULL) {
2N/A char path[MAXPATHLEN];
2N/A
2N/A slice_rdsk2dsk(devp->devpath, path, sizeof (path));
2N/A if (libdiskmgt_str_eq(path, name)) {
2N/A /* found it */
2N/A dp = devp;
2N/A break;
2N/A }
2N/A
2N/A devp = devp->next;
2N/A }
2N/A
2N/A if (dp != NULL) {
2N/A break;
2N/A }
2N/A
2N/A ap = ap->next;
2N/A }
2N/A
2N/A if (dp == NULL) {
2N/A *errp = 0;
2N/A return (0);
2N/A }
2N/A
2N/A /*
2N/A * If we found a match on the name we now have to check that this
2N/A * slice really exists (non-0 size).
2N/A */
2N/A
2N/A slice_num = get_slice_num(dp);
2N/A /* can't get slicenum, so no slice */
2N/A if (slice_num == -1) {
2N/A *errp = ENODEV;
2N/A return (1);
2N/A }
2N/A
2N/A if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) {
2N/A *errp = ENODEV;
2N/A return (1);
2N/A }
2N/A
2N/A if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
2N/A data_format = FMT_VTOC;
2N/A } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
2N/A data_format = FMT_EFI;
2N/A } else {
2N/A (void) close(fd);
2N/A *errp = ENODEV;
2N/A return (1);
2N/A }
2N/A (void) close(fd);
2N/A
2N/A if (data_format == FMT_VTOC) {
2N/A if (slice_num < vtoc.v_nparts &&
2N/A vtoc.v_part[slice_num].p_size > 0) {
2N/A *errp = 0;
2N/A return (1);
2N/A }
2N/A } else { /* data_format == FMT_EFI */
2N/A if (slice_num < efip->efi_nparts &&
2N/A efip->efi_parts[slice_num].p_size > 0) {
2N/A efi_free(efip);
2N/A *errp = 0;
2N/A return (1);
2N/A }
2N/A efi_free(efip);
2N/A }
2N/A
2N/A *errp = ENODEV;
2N/A return (1);
2N/A}