btrfs-progs: convert: Fix offset-by-one error in read_data_extent()
[platform/upstream/btrfs-progs.git] / cmds-replace.c
index c777f1c..032a44f 100644 (file)
@@ -37,7 +37,8 @@
 #include "disk-io.h"
 
 #include "commands.h"
-
+#include "help.h"
+#include "mkfs/common.h"
 
 static int print_replace_status(int fd, const char *path, int once);
 static char *time2string(char *buf, size_t s, __u64 t);
@@ -65,17 +66,6 @@ static const char * const replace_cmd_group_usage[] = {
        NULL
 };
 
-static int is_numerical(const char *str)
-{
-       if (!(*str >= '0' && *str <= '9'))
-               return 0;
-       while (*str >= '0' && *str <= '9')
-               str++;
-       if (*str != '\0')
-               return 0;
-       return 1;
-}
-
 static int dev_replace_cancel_fd = -1;
 static void dev_replace_sigint_handler(int signal)
 {
@@ -140,7 +130,6 @@ static int cmd_replace_start(int argc, char **argv)
        int force_using_targetdev = 0;
        u64 dstdev_block_count;
        int do_not_background = 0;
-       int mixed = 0;
        DIR *dirstream = NULL;
        u64 srcdev_size;
        u64 dstdev_size;
@@ -170,27 +159,18 @@ static int cmd_replace_start(int argc, char **argv)
                usage(cmd_replace_start_usage);
        path = argv[optind + 2];
 
-       fdmnt = open_path_or_dev_mnt(path, &dirstream);
-
-       if (fdmnt < 0) {
-               if (errno == EINVAL)
-                       fprintf(stderr,
-                               "ERROR: '%s' is not a mounted btrfs device\n",
-                               path);
-               else
-                       fprintf(stderr, "ERROR: can't access '%s': %s\n",
-                               path, strerror(errno));
+       fdmnt = open_path_or_dev_mnt(path, &dirstream, 1);
+       if (fdmnt < 0)
                goto leave_with_error;
-       }
 
        /* check for possible errors before backgrounding */
        status_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS;
        status_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
        ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &status_args);
-       if (ret) {
+       if (ret < 0) {
                fprintf(stderr,
-                       "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
-                       path, strerror(errno));
+                       "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %m",
+                       path);
                if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
                        fprintf(stderr, ", %s\n",
                                replace_dev_result2string(status_args.result));
@@ -200,30 +180,26 @@ static int cmd_replace_start(int argc, char **argv)
        }
 
        if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
-               fprintf(stderr,
-                       "ERROR: ioctl(DEV_REPLACE_STATUS) on \"%s\" returns error: %s\n",
+               error("ioctl(DEV_REPLACE_STATUS) on '%s' returns error: %s",
                        path, replace_dev_result2string(status_args.result));
                goto leave_with_error;
        }
 
        if (status_args.status.replace_state ==
            BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
-               fprintf(stderr,
-                       "ERROR: btrfs replace on \"%s\" already started!\n",
-                       path);
+               error("device replace on '%s' already started", path);
                goto leave_with_error;
        }
 
        srcdev = argv[optind];
        dstdev = canonicalize_path(argv[optind + 1]);
        if (!dstdev) {
-               fprintf(stderr,
-                       "ERROR: Could not canonicalize path '%s': %s\n",
-                       argv[optind + 1], strerror(errno));
+               error("cannot canonicalize path '%s': %m",
+                       argv[optind + 1]);
                goto leave_with_error;
        }
 
-       if (is_numerical(srcdev)) {
+       if (string_is_numerical(srcdev)) {
                struct btrfs_ioctl_fs_info_args fi_args;
                struct btrfs_ioctl_dev_info_args *di_args = NULL;
 
@@ -231,13 +207,12 @@ static int cmd_replace_start(int argc, char **argv)
 
                ret = get_fs_info(path, &fi_args, &di_args);
                if (ret) {
-                       fprintf(stderr, "ERROR: getting dev info for devstats failed: "
-                                       "%s\n", strerror(-ret));
+                       error("failed to get device info: %s", strerror(-ret));
                        free(di_args);
                        goto leave_with_error;
                }
                if (!fi_args.num_devices) {
-                       fprintf(stderr, "ERROR: no devices found\n");
+                       error("no devices found");
                        free(di_args);
                        goto leave_with_error;
                }
@@ -245,20 +220,20 @@ static int cmd_replace_start(int argc, char **argv)
                for (i = 0; i < fi_args.num_devices; i++)
                        if (start_args.start.srcdevid == di_args[i].devid)
                                break;
+               srcdev_size = di_args[i].total_bytes;
                free(di_args);
                if (i == fi_args.num_devices) {
-                       fprintf(stderr, "Error: '%s' is not a valid devid for filesystem '%s'\n",
+                       error("'%s' is not a valid devid for filesystem '%s'",
                                srcdev, path);
                        goto leave_with_error;
                }
-               srcdev_size = di_args[i].total_bytes;
        } else if (is_block_device(srcdev) > 0) {
                strncpy((char *)start_args.start.srcdev_name, srcdev,
                        BTRFS_DEVICE_PATH_NAME_MAX);
                start_args.start.srcdevid = 0;
                srcdev_size = get_partition_size(srcdev);
        } else {
-               fprintf(stderr, "ERROR: source device must be a block device or a devid\n");
+               error("source device must be a block device or a devid");
                goto leave_with_error;
        }
 
@@ -268,20 +243,20 @@ static int cmd_replace_start(int argc, char **argv)
 
        dstdev_size = get_partition_size(dstdev);
        if (srcdev_size > dstdev_size) {
-               fprintf(stderr, "ERROR: target device smaller than source device (required %llu bytes)\n",
+               error("target device smaller than source device (required %llu bytes)",
                        srcdev_size);
                goto leave_with_error;
        }
 
        fddstdev = open(dstdev, O_RDWR);
        if (fddstdev < 0) {
-               fprintf(stderr, "Unable to open %s\n", dstdev);
+               error("unable to open %s: %m", dstdev);
                goto leave_with_error;
        }
        strncpy((char *)start_args.start.tgtdev_name, dstdev,
                BTRFS_DEVICE_PATH_NAME_MAX);
-       ret = btrfs_prepare_device(fddstdev, dstdev, 1, &dstdev_block_count, 0,
-                                &mixed, 0);
+       ret = btrfs_prepare_device(fddstdev, dstdev, &dstdev_block_count, 0,
+                       PREP_DEVICE_ZERO_END | PREP_DEVICE_VERBOSE);
        if (ret)
                goto leave_with_error;
 
@@ -293,8 +268,7 @@ static int cmd_replace_start(int argc, char **argv)
        dev_replace_handle_sigint(fdmnt);
        if (!do_not_background) {
                if (daemon(0, 0) < 0) {
-                       fprintf(stderr, "ERROR, backgrounding failed: %s\n",
-                               strerror(errno));
+                       error("backgrounding failed: %m");
                        goto leave_with_error;
                }
        }
@@ -303,10 +277,10 @@ static int cmd_replace_start(int argc, char **argv)
        start_args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
        ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &start_args);
        if (do_not_background) {
-               if (ret) {
+               if (ret < 0) {
                        fprintf(stderr,
-                               "ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s",
-                               path, strerror(errno));
+                               "ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %m",
+                               path);
                        if (start_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
                                fprintf(stderr, ", %s\n",
                                        replace_dev_result2string(start_args.result));
@@ -314,16 +288,14 @@ static int cmd_replace_start(int argc, char **argv)
                                fprintf(stderr, "\n");
 
                        if (errno == EOPNOTSUPP)
-                               fprintf(stderr,
-                                       "WARNING: dev_replace does not yet handle RAID5/6\n");
+                               warning("device replace of RAID5/6 not supported with this kernel");
 
                        goto leave_with_error;
                }
 
                if (start_args.result !=
                    BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
-                       fprintf(stderr,
-                               "ERROR: ioctl(DEV_REPLACE_START) on \"%s\" returns error: %s\n",
+                       error("ioctl(DEV_REPLACE_START) on '%s' returns error: %s",
                                path,
                                replace_dev_result2string(start_args.result));
                        goto leave_with_error;
@@ -355,7 +327,6 @@ static const char *const cmd_replace_status_usage[] = {
 static int cmd_replace_status(int argc, char **argv)
 {
        int fd;
-       int e;
        int c;
        char *path;
        int once = 0;
@@ -377,13 +348,9 @@ static int cmd_replace_status(int argc, char **argv)
                usage(cmd_replace_status_usage);
 
        path = argv[optind];
-       fd = open_file_or_dir(path, &dirstream);
-       e = errno;
-       if (fd < 0) {
-               fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
-                       path, strerror(e));
+       fd = btrfs_open_dir(path, &dirstream, 1);
+       if (fd < 0)
                return 1;
-       }
 
        ret = print_replace_status(fd, path, once);
        close_file_or_dir(fd, dirstream);
@@ -406,9 +373,9 @@ static int print_replace_status(int fd, const char *path, int once)
                args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS;
                args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
                ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
-               if (ret) {
-                       fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
-                               path, strerror(errno));
+               if (ret < 0) {
+                       fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %m",
+                               path);
                        if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
                                fprintf(stderr, ", %s\n",
                                        replace_dev_result2string(args.result));
@@ -418,7 +385,7 @@ static int print_replace_status(int fd, const char *path, int once)
                }
 
                if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
-                       fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) on \"%s\" returns error: %s\n",
+                       error("ioctl(DEV_REPLACE_STATUS) on '%s' returns error: %s",
                                path,
                                replace_dev_result2string(args.result));
                        return -1;
@@ -470,8 +437,7 @@ static int print_replace_status(int fd, const char *path, int once)
                        printf("Never started");
                        break;
                default:
-                       fprintf(stderr,
-       "ERROR: ioctl(DEV_REPLACE_STATUS) on \"%s\" got unknown status: %llu\n",
+                       error("unknown status from ioctl DEV_REPLACE_STATUS on '%s': %llu",
                                        path, status->replace_state);
                        return -EINVAL;
                }
@@ -532,7 +498,6 @@ static int cmd_replace_cancel(int argc, char **argv)
        int ret;
        int c;
        int fd;
-       int e;
        char *path;
        DIR *dirstream = NULL;
 
@@ -548,21 +513,17 @@ static int cmd_replace_cancel(int argc, char **argv)
                usage(cmd_replace_cancel_usage);
 
        path = argv[optind];
-       fd = open_file_or_dir(path, &dirstream);
-       if (fd < 0) {
-               fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
-                       path, strerror(errno));
+       fd = btrfs_open_dir(path, &dirstream, 1);
+       if (fd < 0)
                return 1;
-       }
 
        args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL;
        args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
        ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
-       e = errno;
        close_file_or_dir(fd, dirstream);
-       if (ret) {
-               fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s",
-                       path, strerror(e));
+       if (ret < 0) {
+               fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %m",
+                       path);
                if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
                        fprintf(stderr, ", %s\n",
                                replace_dev_result2string(args.result));