/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libdiskmgt.h" #include "disks_private.h" #include "partition.h" #ifndef VT_ENOTSUP #define VT_ENOTSUP (-5) #endif #define FMT_UNKNOWN 0 #define FMT_VTOC 1 #define FMT_EFI 2 typedef int (*detectorp)(char *, nvlist_t *, int *); static detectorp detectors[] = { inuse_mnt, inuse_svm, inuse_active_zpool, inuse_lu, inuse_dump, inuse_vxvm, inuse_exported_zpool, inuse_fs, /* fs should always be last */ NULL }; static int add_inuse(char *name, nvlist_t *attrs); static int desc_ok(descriptor_t *dp); static void dsk2rdsk(char *dsk, char *rdsk, int size); static int get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs); static descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp); static descriptor_t **get_removable_assocs(descriptor_t *desc, char *volm_path, int *errp); static int get_slice_num(slice_t *devp); static int match_fixed_name(disk_t *dp, char *name, int *errp); static int match_removable_name(disk_t *dp, char *name, int *errp); static int make_fixed_descriptors(disk_t *dp); static int make_removable_descriptors(disk_t *dp); static int make_volm_dir_descriptors(disk_t *dp, int fd, char *volm_path); static int num_removable_slices(int fd, struct stat *bufp, char *volm_path); descriptor_t ** slice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, int *errp) { if (!desc_ok(desc)) { *errp = ENODEV; return (NULL); } switch (type) { case DM_MEDIA: return (media_get_assocs(desc, errp)); case DM_PARTITION: return (partition_get_assocs(desc, errp)); } *errp = EINVAL; return (NULL); } /* * This is called by media/partition to get the slice descriptors for the given * media/partition descriptor. * For media, just get the slices, but for a partition, it must be a solaris * partition and if there are active partitions, it must be the active one. */ descriptor_t ** slice_get_assocs(descriptor_t *desc, int *errp) { int under_volm = 0; char volm_path[MAXPATHLEN]; /* Just check the first drive name. */ if (desc->p.disk->aliases == NULL) { *errp = 0; return (libdiskmgt_empty_desc_array(errp)); } if (desc->p.disk->removable) { if ((under_volm = media_get_volm_path(desc->p.disk, volm_path, sizeof (volm_path)))) { if (volm_path[0] == 0) { /* no media */ *errp = 0; return (libdiskmgt_empty_desc_array(errp)); } } } if (desc->p.disk->removable) { if (under_volm) { return (get_removable_assocs(desc, volm_path, errp)); } else { return (get_fixed_assocs(desc, errp)); } } else { return (get_fixed_assocs(desc, errp)); } } nvlist_t * slice_get_attributes(descriptor_t *dp, int *errp) { nvlist_t *attrs = NULL; int fd; char devpath[MAXPATHLEN]; if (!desc_ok(dp)) { *errp = ENODEV; return (NULL); } if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) { *errp = ENOMEM; return (NULL); } /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */ dsk2rdsk(dp->name, devpath, sizeof (devpath)); fd = open(devpath, O_RDONLY|O_NDELAY); if ((*errp = get_attrs(dp, fd, attrs)) != 0) { nvlist_free(attrs); attrs = NULL; } if (fd >= 0) { (void) close(fd); } return (attrs); } /* * Look for the slice by the slice devpath. */ descriptor_t * slice_get_descriptor_by_name(char *name, int *errp) { int found = 0; disk_t *dp; for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) { if (dp->removable) { found = match_removable_name(dp, name, errp); } else { found = match_fixed_name(dp, name, errp); } if (found) { char mname[MAXPATHLEN]; if (*errp != 0) { return (NULL); } mname[0] = 0; (void) media_read_name(dp, mname, sizeof (mname)); return (cache_get_desc(DM_SLICE, dp, name, mname, errp)); } } *errp = ENODEV; return (NULL); } /* ARGSUSED */ descriptor_t ** slice_get_descriptors(int filter[], int *errp) { return (cache_get_descriptors(DM_SLICE, errp)); } char * slice_get_name(descriptor_t *desc) { return (desc->name); } nvlist_t * slice_get_stats(descriptor_t *dp, int stat_type, int *errp) { nvlist_t *stats; char *str; if (stat_type != DM_SLICE_STAT_USE) { *errp = EINVAL; return (NULL); } *errp = 0; if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) { *errp = ENOMEM; return (NULL); } if ((*errp = add_inuse(dp->name, stats)) != 0) { return (NULL); } /* if no cluster use, check for a use of the local name */ if (nvlist_lookup_string(stats, DM_USED_BY, &str) != 0) { disk_t *diskp; diskp = dp->p.disk; if (diskp->aliases != NULL && diskp->aliases->cluster) { slice_t *sp; int snum = -1; struct dk_minfo minfo; struct dk_cinfo dkinfo; char devpath[MAXPATHLEN]; int fd; /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */ dsk2rdsk(dp->name, devpath, sizeof (devpath)); fd = open(devpath, O_RDONLY|O_NDELAY); if (fd >= 0 && media_read_info(fd, &minfo) && ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { snum = dkinfo.dki_partition; } if (fd >= 0) { (void) close(fd); } if (snum >= 0) { for (sp = diskp->aliases->orig_paths; sp != NULL; sp = sp->next) { if (sp->slice_num == snum) { char localpath[MAXPATHLEN]; slice_rdsk2dsk(sp->devpath, localpath, sizeof (localpath)); if ((*errp = add_inuse(localpath, stats)) != 0) { return (NULL); } break; } } } } } return (stats); } /* * A slice descriptor points to a disk, the name is the devpath and the * secondary name is the media name. */ int slice_make_descriptors() { disk_t *dp; dp = cache_get_disklist(); while (dp != NULL) { int error; if (dp->removable) { error = make_removable_descriptors(dp); } else { error = make_fixed_descriptors(dp); } if (error != 0) { return (error); } dp = dp->next; } return (0); } /* convert rdsk paths to dsk paths */ void slice_rdsk2dsk(char *rdsk, char *dsk, int size) { char *strp; (void) strlcpy(dsk, rdsk, size); if ((strp = strstr(dsk, "/rdsk/")) == NULL) { /* not rdsk, check for floppy */ strp = strstr(dsk, "/rdiskette"); } if (strp != NULL) { strp++; /* move ptr to the r in rdsk or rdiskette */ /* move the succeeding chars over by one */ do { *strp = *(strp + 1); strp++; } while (*strp); } } /* * Check if/how the slice is used. */ static int add_inuse(char *name, nvlist_t *attrs) { int i; int error; for (i = 0; detectors[i] != NULL; i ++) { if (detectors[i](name, attrs, &error) || error != 0) { if (error != 0) { return (error); } break; } } return (0); } /* return 1 if the slice descriptor is still valid, 0 if not. */ static int desc_ok(descriptor_t *dp) { /* First verify the media name for removable media */ if (dp->p.disk->removable) { char mname[MAXPATHLEN]; if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { return (0); } if (mname[0] == 0) { return (libdiskmgt_str_eq(dp->secondary_name, NULL)); } else { return (libdiskmgt_str_eq(dp->secondary_name, mname)); } } /* * We could verify the slice is still there, but other code down the * line already does these checks (e.g. see get_attrs). */ return (1); } /* convert dsk paths to rdsk paths */ static void dsk2rdsk(char *dsk, char *rdsk, int size) { char *slashp; size_t len; (void) strlcpy(rdsk, dsk, size); /* make sure there is enough room to add the r to dsk */ len = strlen(dsk); if (len + 2 > size) { return; } if ((slashp = strstr(rdsk, "/dsk/")) == NULL) { /* not dsk, check for floppy */ slashp = strstr(rdsk, "/diskette"); } if (slashp != NULL) { char *endp; endp = rdsk + len; /* point to terminating 0 */ /* move the succeeding chars over by one */ do { *(endp + 1) = *endp; endp--; } while (endp != slashp); *(endp + 1) = 'r'; } } static int get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs) { struct dk_minfo minfo; int status; int data_format = FMT_UNKNOWN; int snum = -1; int error; struct vtoc vtoc; struct dk_gpt *efip; struct dk_cinfo dkinfo; disk_t *diskp; char localpath[MAXPATHLEN]; int cooked_fd; struct stat buf; int mntpnt = 0; if (fd < 0) { return (ENODEV); } /* First make sure media is inserted and spun up. */ if (!media_read_info(fd, &minfo)) { return (ENODEV); } if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; if (nvlist_add_boolean(attrs, DM_EFI) != 0) { efi_free(efip); return (ENOMEM); } } if (data_format == FMT_UNKNOWN) { return (ENODEV); } if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { snum = dkinfo.dki_partition; } /* check the slice */ if (data_format == FMT_VTOC) { if (snum < 0 || snum >= vtoc.v_nparts || vtoc.v_part[snum].p_size == 0) { return (ENODEV); } } else { /* data_format == FMT_EFI */ if (snum < 0 || snum >= efip->efi_nparts || efip->efi_parts[snum].p_size == 0) { efi_free(efip); return (ENODEV); } } /* the slice exists */ if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) { if (data_format == FMT_EFI) { efi_free(efip); } return (ENOMEM); } if (data_format == FMT_VTOC) { if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start) != 0) { return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag) != 0) { return (ENOMEM); } if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag) != 0) { return (ENOMEM); } } else { /* data_format == FMT_EFI */ if (nvlist_add_uint64(attrs, DM_START, efip->efi_parts[snum].p_start) != 0) { efi_free(efip); return (ENOMEM); } if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size) != 0) { efi_free(efip); return (ENOMEM); } if (efip->efi_parts[snum].p_name[0] != 0) { char label[EFI_PART_NAME_LEN + 1]; (void) snprintf(label, sizeof (label), "%.*s", EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name); if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) { efi_free(efip); return (ENOMEM); } } } if (data_format == FMT_EFI) { efi_free(efip); } if (inuse_mnt(dp->name, attrs, &error)) { if (error != 0) { return (error); } mntpnt = 1; } /* * Some extra attrs for cluster slices. * * get localname and possible mnt point for localpath */ localpath[0] = 0; diskp = dp->p.disk; if (diskp->aliases != NULL && diskp->aliases->cluster) { slice_t *sp; for (sp = diskp->aliases->orig_paths; sp != NULL; sp = sp->next) { if (sp->slice_num == -1) { /* determine the slice number for this path */ int sfd; struct dk_cinfo dkinfo; if ((sfd = open(sp->devpath, O_RDONLY|O_NDELAY)) >= 0) { if (ioctl(sfd, DKIOCINFO, &dkinfo) >= 0) { sp->slice_num = dkinfo.dki_partition; } (void) close(sfd); } } if (sp->slice_num == snum) { slice_rdsk2dsk(sp->devpath, localpath, sizeof (localpath)); if (nvlist_add_string(attrs, DM_LOCALNAME, localpath) != 0) { return (ENOMEM); } if (mntpnt == 0) { if (inuse_mnt(localpath, attrs, &error)) { if (error != 0) { return (error); } } } break; } } } if (fstat(fd, &buf) != -1) { if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) { return (ENOMEM); } } /* * We need to open the cooked slice (not the raw one) to get the * correct devid. Also see if we need to read the localpath for the * cluster disk, since the minor name is unavailable for the did pseudo * device. */ if (localpath[0] != 0) { cooked_fd = open(localpath, O_RDONLY|O_NDELAY); } else { cooked_fd = open(dp->name, O_RDONLY|O_NDELAY); } if (cooked_fd >= 0) { int no_mem = 0; ddi_devid_t devid; if (devid_get(cooked_fd, &devid) == 0) { char *minor; if (devid_get_minor_name(cooked_fd, &minor) == 0) { char *devidstr; if ((devidstr = devid_str_encode(devid, minor)) != 0) { if (nvlist_add_string(attrs, DM_DEVICEID, devidstr) != 0) { no_mem = 1; } devid_str_free(devidstr); } devid_str_free(minor); } devid_free(devid); } (void) close(cooked_fd); if (no_mem) { return (ENOMEM); } } return (0); } static descriptor_t ** get_fixed_assocs(descriptor_t *desc, int *errp) { int fd; int status; int data_format = FMT_UNKNOWN; int cnt; struct vtoc vtoc; struct dk_gpt *efip; int pos; char *media_name = NULL; slice_t *devp; descriptor_t **slices; if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) { *errp = ENODEV; return (NULL); } if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } else { (void) close(fd); *errp = 0; return (libdiskmgt_empty_desc_array(errp)); } (void) close(fd); /* count the number of slices */ for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL; devp = devp->next, cnt++); /* allocate the array for the descriptors */ slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); if (slices == NULL) { if (data_format == FMT_EFI) { efi_free(efip); } *errp = ENOMEM; return (NULL); } /* get the media name from the descriptor */ if (desc->type == DM_MEDIA) { media_name = desc->name; } else { /* must be a DM_PARTITION */ media_name = desc->secondary_name; } pos = 0; for (devp = desc->p.disk->aliases->devpaths; devp != NULL; devp = devp->next) { int slice_num; char devpath[MAXPATHLEN]; slice_num = get_slice_num(devp); /* can't get slicenum, so no need to keep trying the drive */ if (slice_num == -1) { break; } if (data_format == FMT_VTOC) { if (slice_num >= vtoc.v_nparts || vtoc.v_part[slice_num].p_size == 0) { continue; } } else { /* data_format == FMT_EFI */ if (slice_num >= efip->efi_nparts || efip->efi_parts[slice_num].p_size == 0) { continue; } } slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath, media_name, errp); if (*errp != 0) { cache_free_descriptors(slices); if (data_format == FMT_EFI) { efi_free(efip); } return (NULL); } pos++; } slices[pos] = NULL; if (data_format == FMT_EFI) { efi_free(efip); } *errp = 0; return (slices); } /* * Called for loaded removable media under volume management control. */ static descriptor_t ** get_removable_assocs(descriptor_t *desc, char *volm_path, int *errp) { int pos; int fd; int cnt; struct stat buf; descriptor_t **slices; char *media_name = NULL; char devpath[MAXPATHLEN]; /* get the media name from the descriptor */ if (desc->type == DM_MEDIA) { media_name = desc->name; } else { /* must be a DM_PARTITION */ media_name = desc->secondary_name; } /* * For removable media under volm control the volm_path will * either be a device (if the media is made up of a single slice) or * a directory (if the media has multiple slices) with the slices * as devices contained in the directory. */ if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) < 0 || fstat(fd, &buf) != 0) { *errp = ENODEV; return (NULL); } cnt = num_removable_slices(fd, &buf, volm_path); /* allocate the array for the descriptors */ slices = calloc(cnt + 1, sizeof (descriptor_t *)); if (slices == NULL) { *errp = ENOMEM; return (NULL); } slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); pos = 0; *errp = 0; if (S_ISCHR(buf.st_mode)) { struct dk_minfo minfo; /* Make sure media has readable label */ if (media_read_info(fd, &minfo)) { int status; int data_format = FMT_UNKNOWN; struct vtoc vtoc; struct dk_gpt *efip; if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } if (data_format != FMT_UNKNOWN) { /* has a readable label */ slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk, devpath, media_name, errp); } } (void) close(fd); } else if (S_ISDIR(buf.st_mode)) { DIR *dirp; struct dirent *dentp; /* rewind, num_removable_slices already traversed */ (void) lseek(fd, 0, SEEK_SET); if ((dirp = fdopendir(fd)) == NULL) { *errp = errno; (void) close(fd); return (NULL); } while ((dentp = readdir(dirp)) != NULL) { int dfd; int is_dev = 0; char slice_path[MAXPATHLEN]; if (libdiskmgt_str_eq(".", dentp->d_name) || libdiskmgt_str_eq("..", dentp->d_name)) { continue; } (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", devpath, dentp->d_name); if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { struct stat buf; if (fstat(dfd, &buf) == 0 && S_ISCHR(buf.st_mode)) { is_dev = 1; } (void) close(dfd); } if (!is_dev) { continue; } slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk, slice_path, media_name, errp); if (*errp != 0) { break; } } (void) closedir(dirp); } else { (void) close(fd); } slices[pos] = NULL; if (*errp != 0) { cache_free_descriptors(slices); return (NULL); } return (slices); } static int get_slice_num(slice_t *devp) { /* check if we already determined the devpath slice number */ if (devp->slice_num == -1) { int fd; if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) { struct dk_cinfo dkinfo; if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { devp->slice_num = dkinfo.dki_partition; } (void) close(fd); } } return (devp->slice_num); } static int make_fixed_descriptors(disk_t *dp) { int error = 0; alias_t *ap; slice_t *devp; char mname[MAXPATHLEN]; int data_format = FMT_UNKNOWN; struct vtoc vtoc; struct dk_gpt *efip; /* Just check the first drive name. */ if ((ap = dp->aliases) == NULL) { return (0); } mname[0] = 0; (void) media_read_name(dp, mname, sizeof (mname)); for (devp = ap->devpaths; devp != NULL; devp = devp->next) { int slice_num; char devpath[MAXPATHLEN]; slice_num = get_slice_num(devp); /* can't get slicenum, so no need to keep trying the drive */ if (slice_num == -1) { break; } if (data_format == FMT_UNKNOWN) { int fd; int status; if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } (void) close(fd); } } /* can't get slice data, so no need to keep trying the drive */ if (data_format == FMT_UNKNOWN) { break; } if (data_format == FMT_VTOC) { if (slice_num >= vtoc.v_nparts || vtoc.v_part[slice_num].p_size == 0) { continue; } } else { /* data_format == FMT_EFI */ if (slice_num >= efip->efi_nparts || efip->efi_parts[slice_num].p_size == 0) { continue; } } slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); cache_load_desc(DM_SLICE, dp, devpath, mname, &error); if (error != 0) { break; } } if (data_format == FMT_EFI) { efi_free(efip); } return (error); } /* * For removable media under volm control we have to do some special handling. * We don't use the vtoc and /dev/dsk devpaths, since the slices are named * under the /vol fs. */ static int make_removable_descriptors(disk_t *dp) { char volm_path[MAXPATHLEN]; int error; int fd; /* * If this removable drive is not under volm control, just use * normal handling. */ if (!media_get_volm_path(dp, volm_path, sizeof (volm_path))) { return (make_fixed_descriptors(dp)); } if (volm_path[0] == 0) { /* no media */ return (0); } /* * For removable media under volm control the rmmedia_devapth will * either be a device (if the media is made up of a single slice) or * a directory (if the media has multiple slices) with the slices * as devices contained in the directory. */ error = 0; if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0) { struct stat buf; if (fstat(fd, &buf) == 0) { if (S_ISCHR(buf.st_mode)) { int status; int data_format = FMT_UNKNOWN; struct dk_minfo minfo; int error; struct vtoc vtoc; struct dk_gpt *efip; char devpath[MAXPATHLEN]; /* Make sure media has readable label */ if (!media_read_info(fd, &minfo)) { /* no media */ return (0); } if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } if (data_format == FMT_UNKNOWN) { /* no readable label */ return (0); } slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); /* The media name is the volm_path in this case. */ cache_load_desc(DM_SLICE, dp, devpath, volm_path, &error); } else if (S_ISDIR(buf.st_mode)) { /* each device file in the dir represents a slice */ error = make_volm_dir_descriptors(dp, fd, volm_path); } } (void) close(fd); } return (error); } /* * This handles removable media with slices under volume management control. * In this case we have a dir which is the media name and each slice on the * media is a device file in this dir. */ static int make_volm_dir_descriptors(disk_t *dp, int dirfd, char *volm_path) { int error; DIR *dirp; struct dirent *dentp; char devpath[MAXPATHLEN]; dirfd = dup(dirfd); if (dirfd < 0) return (0); if ((dirp = fdopendir(dirfd)) == NULL) { (void) close(dirfd); return (0); } slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); error = 0; while ((dentp = readdir(dirp)) != NULL) { int fd; char slice_path[MAXPATHLEN]; if (libdiskmgt_str_eq(".", dentp->d_name) || libdiskmgt_str_eq("..", dentp->d_name)) { continue; } (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", devpath, dentp->d_name); if ((fd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { struct stat buf; /* The media name is the volm_path in this case. */ if (fstat(fd, &buf) == 0 && S_ISCHR(buf.st_mode)) { cache_load_desc(DM_SLICE, dp, slice_path, volm_path, &error); if (error != 0) { (void) close(fd); break; } } (void) close(fd); } } (void) closedir(dirp); return (error); } /* * Just look for the name on the devpaths we have cached. Return 1 if we * find the name and the size of that slice is non-zero. */ static int match_fixed_name(disk_t *diskp, char *name, int *errp) { slice_t *dp = NULL; alias_t *ap; int slice_num; int fd; int status; int data_format = FMT_UNKNOWN; struct vtoc vtoc; struct dk_gpt *efip; ap = diskp->aliases; while (ap != NULL) { slice_t *devp; devp = ap->devpaths; while (devp != NULL) { char path[MAXPATHLEN]; slice_rdsk2dsk(devp->devpath, path, sizeof (path)); if (libdiskmgt_str_eq(path, name)) { /* found it */ dp = devp; break; } devp = devp->next; } if (dp != NULL) { break; } ap = ap->next; } if (dp == NULL) { *errp = 0; return (0); } /* * If we found a match on the name we now have to check that this * slice really exists (non-0 size). */ slice_num = get_slice_num(dp); /* can't get slicenum, so no slice */ if (slice_num == -1) { *errp = ENODEV; return (1); } if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) { *errp = ENODEV; return (1); } if ((status = read_vtoc(fd, &vtoc)) >= 0) { data_format = FMT_VTOC; } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { data_format = FMT_EFI; } else { (void) close(fd); *errp = ENODEV; return (1); } (void) close(fd); if (data_format == FMT_VTOC) { if (slice_num < vtoc.v_nparts && vtoc.v_part[slice_num].p_size > 0) { *errp = 0; return (1); } } else { /* data_format == FMT_EFI */ if (slice_num < efip->efi_nparts && efip->efi_parts[slice_num].p_size > 0) { efi_free(efip); *errp = 0; return (1); } efi_free(efip); } *errp = ENODEV; return (1); } static int match_removable_name(disk_t *diskp, char *name, int *errp) { char volm_path[MAXPATHLEN]; int found; int fd; struct stat buf; /* * If this removable drive is not under volm control, just use * normal handling. */ if (!media_get_volm_path(diskp, volm_path, sizeof (volm_path))) { return (match_fixed_name(diskp, name, errp)); } if (volm_path[0] == 0) { /* no media */ *errp = 0; return (0); } /* * For removable media under volm control the rmmedia_devapth will * either be a device (if the media is made up of a single slice) or * a directory (if the media has multiple slices) with the slices * as devices contained in the directory. */ *errp = 0; if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) == -1 || fstat(fd, &buf) != 0) { return (0); } found = 0; if (S_ISCHR(buf.st_mode)) { char devpath[MAXPATHLEN]; slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); if (libdiskmgt_str_eq(name, devpath)) { found = 1; } (void) close(fd); return (found); } else if (S_ISDIR(buf.st_mode)) { /* each device file in the dir represents a slice */ DIR *dirp; struct dirent *dentp; char devpath[MAXPATHLEN]; if ((dirp = fdopendir(fd)) == NULL) { (void) close(fd); return (0); } slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); while ((dentp = readdir(dirp)) != NULL) { char slice_path[MAXPATHLEN]; if (libdiskmgt_str_eq(".", dentp->d_name) || libdiskmgt_str_eq("..", dentp->d_name)) { continue; } (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", devpath, dentp->d_name); if (libdiskmgt_str_eq(name, slice_path)) { /* found name, check device */ int dfd; int is_dev = 0; dfd = open(slice_path, O_RDONLY|O_NDELAY); if (dfd >= 0) { struct stat buf; if (fstat(dfd, &buf) == 0 && S_ISCHR(buf.st_mode)) { is_dev = 1; } (void) close(dfd); } /* we found the name */ found = 1; if (!is_dev) { *errp = ENODEV; } break; } } (void) closedir(dirp); } else { (void) close(fd); } return (found); } static int num_removable_slices(int fd, struct stat *bufp, char *volm_path) { int cnt = 0; if (S_ISCHR(bufp->st_mode)) return (1); if (S_ISDIR(bufp->st_mode)) { /* each device file in the dir represents a slice */ DIR *dirp; struct dirent *dentp; char devpath[MAXPATHLEN]; fd = dup(fd); if (fd < 0) return (0); if ((dirp = fdopendir(fd)) == NULL) { (void) close(fd); return (0); } slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); while ((dentp = readdir(dirp)) != NULL) { int dfd; char slice_path[MAXPATHLEN]; if (libdiskmgt_str_eq(".", dentp->d_name) || libdiskmgt_str_eq("..", dentp->d_name)) { continue; } (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", devpath, dentp->d_name); if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { struct stat buf; if (fstat(dfd, &buf) == 0 && S_ISCHR(buf.st_mode)) { cnt++; } (void) close(dfd); } } (void) closedir(dirp); } return (cnt); }