diff --git a/cmd/zpool/zpool_vdev.c b/cmd/zpool/zpool_vdev.c index ae2e7b59f5..661946cef2 100644 --- a/cmd/zpool/zpool_vdev.c +++ b/cmd/zpool/zpool_vdev.c @@ -192,7 +192,7 @@ check_slice(const char *path, blkid_cache cache, int force, boolean_t isspare) int err; if (stat64(path, &statbuf) != 0) { - vdev_error(gettext("cannot open %s: %s\n"), + vdev_error(gettext("cannot stat %s: %s\n"), path, strerror(errno)); return (-1); } @@ -295,7 +295,15 @@ check_disk(const char *path, blkid_cache cache, int force, uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid)) continue; - sprintf(slice_path, "%s%d", path, i+1); + /* Resolve possible symlink to safely append partition */ + if (realpath(path, slice_path) == NULL) { + (void) fprintf(stderr, + gettext("cannot resolve path '%s'\n"), slice_path); + err = errno; + break; + } + + sprintf(slice_path, "%s%d", slice_path, i+1); err = check_slice(slice_path, cache, force, isspare); if (err) break; @@ -400,7 +408,9 @@ make_leaf_vdev(const char *arg, uint64_t is_log) * Complete device or file path. Exact type is determined by * examining the file descriptor afterwards. Symbolic links * are resolved to their real paths for the is_whole_disk() - * and S_ISBLK/S_ISREG type checks. + * and S_ISBLK/S_ISREG type checks. However, we are careful + * to store the given path as ZPOOL_CONFIG_PATH to ensure we + * can leverage udev's persistent device labels. */ if (realpath(arg, path) == NULL) { (void) fprintf(stderr, @@ -415,6 +425,9 @@ make_leaf_vdev(const char *arg, uint64_t is_log) path, strerror(errno)); return (NULL); } + + /* After is_whole_disk() check restore original passed path */ + strlcpy(path, arg, MAXPATHLEN); } else { /* * This may be a short path for a device, or it could be total @@ -476,6 +489,7 @@ make_leaf_vdev(const char *arg, uint64_t is_log) verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, (uint64_t)wholedisk) == 0); +#if defined(__sun__) || defined(__sun) /* * For a whole disk, defer getting its devid until after labeling it. */ @@ -510,6 +524,7 @@ make_leaf_vdev(const char *arg, uint64_t is_log) (void) close(fd); } +#endif return (vdev); } @@ -954,21 +969,36 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv) return (ret); } - diskname = strrchr(path, '/'); + if (realpath(path, buf) == NULL) { + ret = errno; + (void) fprintf(stderr, + gettext("cannot resolve path '%s'\n"), path); + return (ret); + } + + diskname = strrchr(buf, '/'); assert(diskname != NULL); diskname++; if (zpool_label_disk(g_zfs, zhp, diskname) == -1) return (-1); /* - * Fill in the devid, now that we've labeled the disk. + * Fill in the devid, now that we've labeled the disk. We + * attempt to open the new zfs slice first by appending the + * slice number. If that fails this may be a Linux udev + * path in which case the -part# convention is tried. */ (void) snprintf(buf, sizeof (buf), "%s%s", path, FIRST_SLICE); if ((fd = open(buf, O_RDONLY)) < 0) { - (void) fprintf(stderr, - gettext("cannot open '%s': %s\n"), - buf, strerror(errno)); - return (-1); + + (void) snprintf(buf, sizeof (buf), "%s%s%s", + path, "-part", FIRST_SLICE); + if ((fd = open(buf, O_RDONLY)) < 0) { + (void) fprintf(stderr, + gettext("cannot open '%s': %s\n"), + buf, strerror(errno)); + return (-1); + } } #if defined(__sun__) || defined(__sun) diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 4f669bc17d..0c35b85993 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -2619,12 +2619,11 @@ set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path) char * zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) { - char *path, *devid; + char *path, *devid, *type; uint64_t value; char buf[64]; vdev_stat_t *vs; uint_t vsc; - size_t droot_len = strlen(DISK_ROOT) + 1; if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &value) == 0) { @@ -2634,7 +2633,6 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) (u_longlong_t)value); path = buf; } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { - /* * If the device is dead (faulted, offline, etc) then don't * bother opening it. Otherwise we may be forcing the user to @@ -2673,13 +2671,18 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv) devid_str_free(newdevid); } - if (strncmp(path, DISK_ROOT "/", droot_len) == 0) - path += droot_len; + /* + * For a block device only use the name. + */ + verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0); + if (strcmp(type, VDEV_TYPE_DISK) == 0) { + path = strrchr(path, '/'); + path++; + } #if defined(__sun__) || defined(__sun) /* * The following code strips the slice from the device path. - * This is only meaningful in Solaris. */ if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &value) == 0 && value) {