btrfs-progs: alias btrfs device delete to btrfs device remove
[platform/upstream/btrfs-progs.git] / cmds-replace.c
index 9eb981b..85365e3 100644 (file)
@@ -53,6 +53,8 @@ static const char *replace_dev_result2string(__u64 result)
                return "not started";
        case BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED:
                return "already started";
+       case BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS:
+               return "scrub is in progress";
        default:
                return "<illegal result value>";
        }
@@ -130,19 +132,16 @@ static int cmd_start_replace(int argc, char **argv)
        int i;
        int c;
        int fdmnt = -1;
-       int fdsrcdev = -1;
        int fddstdev = -1;
        char *path;
        char *srcdev;
-       char *dstdev;
+       char *dstdev = NULL;
        int avoid_reading_from_srcdev = 0;
        int force_using_targetdev = 0;
-       struct stat st;
        u64 dstdev_block_count;
        int do_not_background = 0;
        int mixed = 0;
        DIR *dirstream = NULL;
-       char estr[100]; /* check test_dev_for_mkfs() for error string size*/
 
        while ((c = getopt(argc, argv, "Brf")) != -1) {
                switch (c) {
@@ -184,12 +183,17 @@ static int cmd_start_replace(int argc, char **argv)
 
        /* 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) {
                fprintf(stderr,
-                       "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s, %s\n",
-                       path, strerror(errno),
-                       replace_dev_result2string(status_args.result));
+                       "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
+                       path, strerror(errno));
+               if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+                       fprintf(stderr, ", %s\n",
+                               replace_dev_result2string(status_args.result));
+               else
+                       fprintf(stderr, "\n");
                goto leave_with_error;
        }
 
@@ -209,7 +213,13 @@ static int cmd_start_replace(int argc, char **argv)
        }
 
        srcdev = argv[optind];
-       dstdev = argv[optind + 1];
+       dstdev = canonicalize_path(argv[optind + 1]);
+       if (!dstdev) {
+               fprintf(stderr,
+                       "ERROR: Could not canonicalize path '%s': %s\n",
+                       argv[optind + 1], strerror(errno));
+               goto leave_with_error;
+       }
 
        if (is_numerical(srcdev)) {
                struct btrfs_ioctl_fs_info_args fi_args;
@@ -239,36 +249,16 @@ static int cmd_start_replace(int argc, char **argv)
                                srcdev, path);
                        goto leave_with_error;
                }
-       } else {
-               fdsrcdev = open(srcdev, O_RDWR);
-               if (fdsrcdev < 0) {
-                       fprintf(stderr, "Error: Unable to open device '%s'\n",
-                               srcdev);
-                       fprintf(stderr, "\tTry using the devid instead of the path\n");
-                       goto leave_with_error;
-               }
-               ret = fstat(fdsrcdev, &st);
-               if (ret) {
-                       fprintf(stderr, "Error: Unable to stat '%s'\n", srcdev);
-                       goto leave_with_error;
-               }
-               if (!S_ISBLK(st.st_mode)) {
-                       fprintf(stderr, "Error: '%s' is not a block device\n",
-                               srcdev);
-                       goto leave_with_error;
-               }
+       } else if (is_block_device(srcdev)) {
                strncpy((char *)start_args.start.srcdev_name, srcdev,
                        BTRFS_DEVICE_PATH_NAME_MAX);
-               close(fdsrcdev);
-               fdsrcdev = -1;
                start_args.start.srcdevid = 0;
        }
 
-       ret = test_dev_for_mkfs(dstdev, force_using_targetdev, estr);
-       if (ret) {
-               fprintf(stderr, "%s", estr);
+       ret = test_dev_for_mkfs(dstdev, force_using_targetdev);
+       if (ret)
                goto leave_with_error;
-       }
+
        fddstdev = open(dstdev, O_RDWR);
        if (fddstdev < 0) {
                fprintf(stderr, "Unable to open %s\n", dstdev);
@@ -283,6 +273,8 @@ static int cmd_start_replace(int argc, char **argv)
 
        close(fddstdev);
        fddstdev = -1;
+       free(dstdev);
+       dstdev = NULL;
 
        dev_replace_handle_sigint(fdmnt);
        if (!do_not_background) {
@@ -294,13 +286,23 @@ static int cmd_start_replace(int argc, char **argv)
        }
 
        start_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_START;
+       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) {
                        fprintf(stderr,
-                               "ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s, %s\n",
-                               path, strerror(errno),
-                               replace_dev_result2string(start_args.result));
+                               "ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s",
+                               path, strerror(errno));
+                       if (start_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+                               fprintf(stderr, ", %s\n",
+                                       replace_dev_result2string(start_args.result));
+                       else
+                               fprintf(stderr, "\n");
+
+                       if (errno == EOPNOTSUPP)
+                               fprintf(stderr,
+                                       "WARNING: dev_replace does not yet handle RAID5/6\n");
+
                        goto leave_with_error;
                }
 
@@ -317,10 +319,10 @@ static int cmd_start_replace(int argc, char **argv)
        return 0;
 
 leave_with_error:
+       if (dstdev)
+               free(dstdev);
        if (fdmnt != -1)
                close(fdmnt);
-       if (fdsrcdev != -1)
-               close(fdsrcdev);
        if (fddstdev != -1)
                close(fddstdev);
        return 1;
@@ -388,11 +390,16 @@ static int print_replace_status(int fd, const char *path, int once)
 
        for (;;) {
                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, %s\n",
-                               path, strerror(errno),
-                               replace_dev_result2string(args.result));
+                       fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s",
+                               path, strerror(errno));
+                       if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+                               fprintf(stderr, ", %s\n",
+                                       replace_dev_result2string(args.result));
+                       else
+                               fprintf(stderr, "\n");
                        return ret;
                }
 
@@ -536,13 +543,18 @@ static int cmd_cancel_replace(int argc, char **argv)
        }
 
        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, %s\n",
-                       path, strerror(e),
-                       replace_dev_result2string(args.result));
+               fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s",
+                       path, strerror(e));
+               if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
+                       fprintf(stderr, ", %s\n",
+                               replace_dev_result2string(args.result));
+               else
+                       fprintf(stderr, "\n");
                return 1;
        }
        if (args.result == BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED) {
@@ -553,8 +565,11 @@ static int cmd_cancel_replace(int argc, char **argv)
        return 0;
 }
 
+static const char replace_cmd_group_info[] =
+"replace a device in the filesystem";
+
 const struct cmd_group replace_cmd_group = {
-       replace_cmd_group_usage, NULL, {
+       replace_cmd_group_usage, replace_cmd_group_info, {
                { "start", cmd_start_replace, cmd_start_replace_usage, NULL,
                  0 },
                { "status", cmd_status_replace, cmd_status_replace_usage, NULL,