summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds-device.c5
-rw-r--r--cmds-replace.c6
-rw-r--r--cmds-scrub.c10
-rw-r--r--utils.c75
-rw-r--r--utils.h2
5 files changed, 70 insertions, 28 deletions
diff --git a/cmds-device.c b/cmds-device.c
index 58df6da6..41e79d37 100644
--- a/cmds-device.c
+++ b/cmds-device.c
@@ -321,13 +321,14 @@ static int cmd_dev_stats(int argc, char **argv)
path = argv[optind];
- fdmnt = open_file_or_dir(path);
+ fdmnt = open_path_or_dev_mnt(path);
+
if (fdmnt < 0) {
fprintf(stderr, "ERROR: can't access '%s'\n", path);
return 12;
}
- ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(path, &fi_args, &di_args);
if (ret) {
fprintf(stderr, "ERROR: getting dev info for devstats failed: "
"%s\n", strerror(-ret));
diff --git a/cmds-replace.c b/cmds-replace.c
index 10030f64..6397bb5d 100644
--- a/cmds-replace.c
+++ b/cmds-replace.c
@@ -168,7 +168,9 @@ static int cmd_start_replace(int argc, char **argv)
if (check_argc_exact(argc - optind, 3))
usage(cmd_start_replace_usage);
path = argv[optind + 2];
- fdmnt = open_file_or_dir(path);
+
+ fdmnt = open_path_or_dev_mnt(path);
+
if (fdmnt < 0) {
fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
path, strerror(errno));
@@ -215,7 +217,7 @@ static int cmd_start_replace(int argc, char **argv)
}
start_args.start.srcdevid = (__u64)atoi(srcdev);
- ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(path, &fi_args, &di_args);
if (ret) {
fprintf(stderr, "ERROR: getting dev info for devstats failed: "
"%s\n", strerror(-ret));
diff --git a/cmds-scrub.c b/cmds-scrub.c
index 1792f5fb..f06eb20d 100644
--- a/cmds-scrub.c
+++ b/cmds-scrub.c
@@ -1101,13 +1101,14 @@ static int scrub_start(int argc, char **argv, int resume)
path = argv[optind];
- fdmnt = open_file_or_dir(path);
+ fdmnt = open_path_or_dev_mnt(path);
+
if (fdmnt < 0) {
ERR(!do_quiet, "ERROR: can't access '%s'\n", path);
return 12;
}
- ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(path, &fi_args, &di_args);
if (ret) {
ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
@@ -1558,13 +1559,14 @@ static int cmd_scrub_status(int argc, char **argv)
path = argv[optind];
- fdmnt = open_file_or_dir(path);
+ fdmnt = open_path_or_dev_mnt(path);
+
if (fdmnt < 0) {
fprintf(stderr, "ERROR: can't access to '%s'\n", path);
return 12;
}
- ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(path, &fi_args, &di_args);
if (ret) {
fprintf(stderr, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
diff --git a/utils.c b/utils.c
index 9c48de46..cfb6116d 100644
--- a/utils.c
+++ b/utils.c
@@ -719,7 +719,7 @@ int open_path_or_dev_mnt(const char *path)
errno = EINVAL;
return -1;
}
- fdmnt = open(mp, O_RDWR);
+ fdmnt = open_file_or_dir(mp);
} else {
fdmnt = open_file_or_dir(path);
}
@@ -1547,9 +1547,20 @@ int get_device_info(int fd, u64 devid,
return ret ? -errno : 0;
}
-int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+/*
+ * For a given path, fill in the ioctl fs_ and info_ args.
+ * If the path is a btrfs mountpoint, fill info for all devices.
+ * If the path is a btrfs device, fill in only that device.
+ *
+ * The path provided must be either on a mounted btrfs fs,
+ * or be a mounted btrfs device.
+ *
+ * Returns 0 on success, or a negative errno.
+ */
+int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
struct btrfs_ioctl_dev_info_args **di_ret)
{
+ int fd = -1;
int ret = 0;
int ndevs = 0;
int i = 1;
@@ -1559,33 +1570,56 @@ int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
memset(fi_args, 0, sizeof(*fi_args));
- ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
- if (ret && (errno == EINVAL || errno == ENOTTY)) {
- /* path is not a mounted btrfs. Try if it's a device */
+ if (is_block_device(path)) {
+ /* Ensure it's mounted, then set path to the mountpoint */
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ fprintf(stderr, "Couldn't open %s: %s\n",
+ path, strerror(errno));
+ goto out;
+ }
ret = check_mounted_where(fd, path, mp, sizeof(mp),
&fs_devices_mnt);
- if (!ret)
- return -EINVAL;
+ if (!ret) {
+ ret = -EINVAL;
+ goto out;
+ }
if (ret < 0)
- return ret;
+ goto out;
+ path = mp;
+ /* Only fill in this one device */
fi_args->num_devices = 1;
fi_args->max_id = fs_devices_mnt->latest_devid;
i = fs_devices_mnt->latest_devid;
memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
close(fd);
- fd = open_file_or_dir(mp);
- if (fd < 0)
- return -errno;
- } else if (ret) {
- return -errno;
+ }
+
+ /* at this point path must not be for a block device */
+ fd = open_file_or_dir(path);
+ if (fd < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ /* fill in fi_args if not just a single device */
+ if (fi_args->num_devices != 1) {
+ ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
+ if (ret < 0) {
+ ret = -errno;
+ goto out;
+ }
}
if (!fi_args->num_devices)
- return 0;
+ goto out;
di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
- if (!di_args)
- return -errno;
+ if (!di_args) {
+ ret = -errno;
+ goto out;
+ }
for (; i <= fi_args->max_id; ++i) {
BUG_ON(ndevs >= fi_args->num_devices);
@@ -1593,13 +1627,16 @@ int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
if (ret == -ENODEV)
continue;
if (ret)
- return ret;
+ goto out;
ndevs++;
}
BUG_ON(ndevs == 0);
-
- return 0;
+ ret = 0;
+out:
+ if (fd != -1)
+ close(fd);
+ return ret;
}
#define isoctal(c) (((c) & ~7) == '0')
diff --git a/utils.h b/utils.h
index 8e0252b6..885b9c54 100644
--- a/utils.h
+++ b/utils.h
@@ -50,7 +50,7 @@ u64 parse_size(char *s);
int open_file_or_dir(const char *fname);
int get_device_info(int fd, u64 devid,
struct btrfs_ioctl_dev_info_args *di_args);
-int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
struct btrfs_ioctl_dev_info_args **di_ret);
int get_label(const char *btrfs_dev);
int set_label(const char *btrfs_dev, const char *label);