diff --git a/cmd/zpool/zpool_vdev.c b/cmd/zpool/zpool_vdev.c index d4838ad2d..0c4c97075 100644 --- a/cmd/zpool/zpool_vdev.c +++ b/cmd/zpool/zpool_vdev.c @@ -384,23 +384,9 @@ static int is_shorthand_path(const char *arg, char *path, struct stat64 *statbuf, boolean_t *wholedisk) { - char dirs[5][9] = {"by-id", "by-label", "by-path", "by-uuid", "zpool"}; - int i, err; - - /* /dev/ */ - (void) snprintf(path, MAXPATHLEN, "%s/%s", DISK_ROOT, arg); - *wholedisk = is_whole_disk(path); - err = stat64(path, statbuf); - if (*wholedisk || err == 0) - return (0); - - /* /dev/disk// */ - for (i = 0; i < 5; i++) { - (void) snprintf(path, MAXPATHLEN, "%s/%s/%s", - UDISK_ROOT, dirs[i], arg); + if (zfs_resolve_shortname(arg, path, MAXPATHLEN) == 0) { *wholedisk = is_whole_disk(path); - err = stat64(path, statbuf); - if (*wholedisk || err == 0) + if (*wholedisk || (stat64(path, statbuf) == 0)) return (0); } @@ -1009,13 +995,7 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv) * for *-part# to be created. Otherwise just use the normal * syntax for devices in /dev. */ - if (strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) - (void) snprintf(buf, sizeof (buf), - "%s%s%s", path, "-part", FIRST_SLICE); - else - (void) snprintf(buf, sizeof (buf), - "%s%s%s", path, isdigit(path[strlen(path)-1]) ? - "p" : "", FIRST_SLICE); + zfs_append_partition(path, buf, sizeof (buf)); if ((ret = zpool_label_disk_wait(buf, 1000)) != 0) { (void) fprintf(stderr, diff --git a/include/libzfs.h b/include/libzfs.h index dcbd283ac..6752579e8 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -630,6 +630,8 @@ extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t); extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *, zfs_type_t); extern int zfs_spa_version(zfs_handle_t *, int *); +extern void zfs_append_partition(const char *path, char *buf, size_t buflen); +extern int zfs_resolve_shortname(const char *name, char *path, size_t pathlen); /* * Mount support functions. diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index d72b7c0fc..01995f802 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -801,6 +801,46 @@ zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype) return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM)); } +/* + * Given a shorthand device name, check if a file by that name exists in a list + * of directories under /dev. If one is found, store its full path in the + * buffer pointed to by the path argument and return 0, else return -1. The + * path buffer must be allocated by the caller. + */ +int +zfs_resolve_shortname(const char *name, char *path, size_t pathlen) +{ + int i, err; + char dirs[5][9] = {"by-id", "by-label", "by-path", "by-uuid", "zpool"}; + + (void) snprintf(path, pathlen, "%s/%s", DISK_ROOT, name); + err = access(path, F_OK); + for (i = 0; i < 5 && err < 0; i++) { + (void) snprintf(path, pathlen, "%s/%s/%s", + UDISK_ROOT, dirs[i], name); + err = access(path, F_OK); + } + return err; +} + +/* + * Append partition suffix to a device path. This should be used to generate + * the name of a whole disk as it is stored in the vdev label. The + * user-visible names of whole disks do not contain the partition information. + * Modifies buf which must be allocated by the caller. + */ +void +zfs_append_partition(const char *path, char *buf, size_t buflen) +{ + if (strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) + (void) snprintf(buf, buflen, "%s%s%s", path, "-part", + FIRST_SLICE); + else + (void) snprintf(buf, buflen, "%s%s%s", path, + isdigit(path[strlen(path)-1]) ? "p" : "", + FIRST_SLICE); +} + /* * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from * an ioctl().