btrfs-progs: alias btrfs device delete to btrfs device remove
[platform/upstream/btrfs-progs.git] / cmds-device.c
index 9323986..0e60500 100644 (file)
@@ -28,6 +28,7 @@
 #include "ctree.h"
 #include "ioctl.h"
 #include "utils.h"
+#include "cmds-fi-usage.h"
 
 #include "commands.h"
 
@@ -51,17 +52,16 @@ static int cmd_add_dev(int argc, char **argv)
        DIR     *dirstream = NULL;
        int discard = 1;
        int force = 0;
-       char estr[100];
 
        while (1) {
-               int long_index;
-               static struct option long_options[] = {
+               int c;
+               static const struct option long_options[] = {
                        { "nodiscard", optional_argument, NULL, 'K'},
                        { "force", no_argument, NULL, 'f'},
-                       { 0, 0, 0, 0 }
+                       { NULL, 0, NULL, 0}
                };
-               int c = getopt_long(argc, argv, "Kf", long_options,
-                                       &long_index);
+
+               c = getopt_long(argc, argv, "Kf", long_options, NULL);
                if (c < 0)
                        break;
                switch (c) {
@@ -96,9 +96,8 @@ static int cmd_add_dev(int argc, char **argv)
                int mixed = 0;
                char *path;
 
-               res = test_dev_for_mkfs(argv[i], force, estr);
+               res = test_dev_for_mkfs(argv[i], force);
                if (res) {
-                       fprintf(stderr, "%s", estr);
                        ret++;
                        continue;
                }
@@ -127,6 +126,7 @@ static int cmd_add_dev(int argc, char **argv)
                        goto error_out;
                }
 
+               memset(&ioctl_args, 0, sizeof(ioctl_args));
                strncpy_null(ioctl_args.name, path);
                res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
                e = errno;
@@ -143,20 +143,14 @@ error_out:
        return !!ret;
 }
 
-static const char * const cmd_rm_dev_usage[] = {
-       "btrfs device delete <device> [<device>...] <path>",
-       "Remove a device from a filesystem",
-       NULL
-};
-
-static int cmd_rm_dev(int argc, char **argv)
+static int _cmd_rm_dev(int argc, char **argv, const char * const *usagestr)
 {
        char    *mntpnt;
        int     i, fdmnt, ret=0, e;
        DIR     *dirstream = NULL;
 
        if (check_argc_min(argc, 3))
-               usage(cmd_rm_dev_usage);
+               usage(usagestr);
 
        mntpnt = argv[argc - 1];
 
@@ -176,18 +170,20 @@ static int cmd_rm_dev(int argc, char **argv)
                        ret++;
                        continue;
                }
+               memset(&arg, 0, sizeof(arg));
                strncpy_null(arg.name, argv[i]);
                res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
                e = errno;
-               if (res > 0) {
-                       fprintf(stderr,
-                               "ERROR: error removing the device '%s' - %s\n",
-                               argv[i], btrfs_err_str(res));
-                       ret++;
-               } else if (res < 0) {
+               if (res) {
+                       const char *msg;
+
+                       if (res > 0)
+                               msg = btrfs_err_str(res);
+                       else
+                               msg = strerror(e);
                        fprintf(stderr,
                                "ERROR: error removing the device '%s' - %s\n",
-                               argv[i], strerror(e));
+                               argv[i], msg);
                        ret++;
                }
        }
@@ -196,6 +192,28 @@ static int cmd_rm_dev(int argc, char **argv)
        return !!ret;
 }
 
+static const char * const cmd_rm_dev_usage[] = {
+       "btrfs device remove <device> [<device>...] <path>",
+       "Remove a device from a filesystem",
+       NULL
+};
+
+static int cmd_rm_dev(int argc, char **argv)
+{
+       return _cmd_rm_dev(argc, argv, cmd_rm_dev_usage);
+}
+
+static const char * const cmd_del_dev_usage[] = {
+       "btrfs device delete <device> [<device>...] <path>",
+       "Remove a device from a filesystem",
+       NULL
+};
+
+static int cmd_del_dev(int argc, char **argv)
+{
+       return _cmd_rm_dev(argc, argv, cmd_del_dev_usage);
+}
+
 static const char * const cmd_scan_dev_usage[] = {
        "btrfs device scan [(-d|--all-devices)|<device> [<device>...]]",
        "Scan devices for a btrfs filesystem",
@@ -212,13 +230,13 @@ static int cmd_scan_dev(int argc, char **argv)
 
        optind = 1;
        while (1) {
-               int long_index;
-               static struct option long_options[] = {
+               int c;
+               static const struct option long_options[] = {
                        { "all-devices", no_argument, NULL, 'd'},
-                       { 0, 0, 0, 0 },
+                       { NULL, 0, NULL, 0}
                };
-               int c = getopt_long(argc, argv, "d", long_options,
-                                   &long_index);
+
+               c = getopt_long(argc, argv, "d", long_options, NULL);
                if (c < 0)
                        break;
                switch (c) {
@@ -312,7 +330,8 @@ static int cmd_ready_dev(int argc, char **argv)
                goto out;
        }
 
-       strncpy(args.name, path, BTRFS_PATH_NAME_MAX);
+       memset(&args, 0, sizeof(args));
+       strncpy_null(args.name, path);
        ret = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
        if (ret < 0) {
                fprintf(stderr, "ERROR: unable to determine if the device '%s'"
@@ -408,31 +427,37 @@ static int cmd_dev_stats(int argc, char **argv)
                                path, strerror(errno));
                        err = 1;
                } else {
+                       char *canonical_path;
+
+                       canonical_path = canonicalize_path((char *)path);
+
                        if (args.nr_items >= BTRFS_DEV_STAT_WRITE_ERRS + 1)
                                printf("[%s].write_io_errs   %llu\n",
-                                      path,
+                                      canonical_path,
                                       (unsigned long long) args.values[
                                        BTRFS_DEV_STAT_WRITE_ERRS]);
                        if (args.nr_items >= BTRFS_DEV_STAT_READ_ERRS + 1)
                                printf("[%s].read_io_errs    %llu\n",
-                                      path,
+                                      canonical_path,
                                       (unsigned long long) args.values[
                                        BTRFS_DEV_STAT_READ_ERRS]);
                        if (args.nr_items >= BTRFS_DEV_STAT_FLUSH_ERRS + 1)
                                printf("[%s].flush_io_errs   %llu\n",
-                                      path,
+                                      canonical_path,
                                       (unsigned long long) args.values[
                                        BTRFS_DEV_STAT_FLUSH_ERRS]);
                        if (args.nr_items >= BTRFS_DEV_STAT_CORRUPTION_ERRS + 1)
                                printf("[%s].corruption_errs %llu\n",
-                                      path,
+                                      canonical_path,
                                       (unsigned long long) args.values[
                                        BTRFS_DEV_STAT_CORRUPTION_ERRS]);
                        if (args.nr_items >= BTRFS_DEV_STAT_GENERATION_ERRS + 1)
                                printf("[%s].generation_errs %llu\n",
-                                      path,
+                                      canonical_path,
                                       (unsigned long long) args.values[
                                        BTRFS_DEV_STAT_GENERATION_ERRS]);
+
+                       free(canonical_path);
                }
        }
 
@@ -443,13 +468,151 @@ out:
        return err;
 }
 
+const char * const cmd_device_usage_usage[] = {
+       "btrfs device usage [options] <path> [<path>..]",
+       "Show detailed information about internal allocations in devices.",
+       "-b|--raw           raw numbers in bytes",
+       "-h|--human-readable",
+       "                   human friendly numbers, base 1024 (default)",
+       "-H                 human friendly numbers, base 1000",
+       "--iec              use 1024 as a base (KiB, MiB, GiB, TiB)",
+       "--si               use 1000 as a base (kB, MB, GB, TB)",
+       "-k|--kbytes        show sizes in KiB, or kB with --si",
+       "-m|--mbytes        show sizes in MiB, or MB with --si",
+       "-g|--gbytes        show sizes in GiB, or GB with --si",
+       "-t|--tbytes        show sizes in TiB, or TB with --si",
+       NULL
+};
+
+static int _cmd_device_usage(int fd, char *path, unsigned unit_mode)
+{
+       int i;
+       int ret = 0;
+       struct chunk_info *chunkinfo = NULL;
+       struct device_info *devinfo = NULL;
+       int chunkcount = 0;
+       int devcount = 0;
+
+       ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo,
+                       &devcount);
+       if (ret)
+               goto out;
+
+       for (i = 0; i < devcount; i++) {
+               printf("%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
+               print_device_sizes(fd, &devinfo[i], unit_mode);
+               print_device_chunks(fd, &devinfo[i], chunkinfo, chunkcount,
+                               unit_mode);
+               printf("\n");
+       }
+
+out:
+       free(devinfo);
+       free(chunkinfo);
+
+       return ret;
+}
+
+int cmd_device_usage(int argc, char **argv)
+{
+       unsigned unit_mode = UNITS_DEFAULT;
+       int ret = 0;
+       int     i, more_than_one = 0;
+
+       optind = 1;
+       while (1) {
+               int c;
+               static const struct option long_options[] = {
+                       { "raw", no_argument, NULL, 'b'},
+                       { "kbytes", no_argument, NULL, 'k'},
+                       { "mbytes", no_argument, NULL, 'm'},
+                       { "gbytes", no_argument, NULL, 'g'},
+                       { "tbytes", no_argument, NULL, 't'},
+                       { "si", no_argument, NULL, GETOPT_VAL_SI},
+                       { "iec", no_argument, NULL, GETOPT_VAL_IEC},
+                       { "human-readable", no_argument, NULL,
+                               GETOPT_VAL_HUMAN_READABLE},
+                       { NULL, 0, NULL, 0 }
+               };
+
+               c = getopt_long(argc, argv, "bhHkmgt", long_options, NULL);
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'b':
+                       unit_mode = UNITS_RAW;
+                       break;
+               case 'k':
+                       units_set_base(&unit_mode, UNITS_KBYTES);
+                       break;
+               case 'm':
+                       units_set_base(&unit_mode, UNITS_MBYTES);
+                       break;
+               case 'g':
+                       units_set_base(&unit_mode, UNITS_GBYTES);
+                       break;
+               case 't':
+                       units_set_base(&unit_mode, UNITS_TBYTES);
+                       break;
+               case GETOPT_VAL_HUMAN_READABLE:
+               case 'h':
+                       unit_mode = UNITS_HUMAN_BINARY;
+                       break;
+               case 'H':
+                       unit_mode = UNITS_HUMAN_DECIMAL;
+                       break;
+               case GETOPT_VAL_SI:
+                       units_set_mode(&unit_mode, UNITS_DECIMAL);
+                       break;
+               case GETOPT_VAL_IEC:
+                       units_set_mode(&unit_mode, UNITS_BINARY);
+                       break;
+               default:
+                       usage(cmd_device_usage_usage);
+               }
+       }
+
+       if (check_argc_min(argc - optind, 1))
+               usage(cmd_device_usage_usage);
+
+       for (i = optind; i < argc ; i++) {
+               int fd;
+               DIR     *dirstream = NULL;
+               if (more_than_one)
+                       printf("\n");
+
+               fd = open_file_or_dir(argv[i], &dirstream);
+               if (fd < 0) {
+                       fprintf(stderr, "ERROR: can't access '%s'\n",
+                               argv[1]);
+                       ret = 1;
+                       goto out;
+               }
+
+               ret = _cmd_device_usage(fd, argv[i], unit_mode);
+               close_file_or_dir(fd, dirstream);
+
+               if (ret)
+                       goto out;
+               more_than_one = 1;
+       }
+out:
+       return !!ret;
+}
+
+static const char device_cmd_group_info[] =
+"manage and query devices in the filesystem";
+
 const struct cmd_group device_cmd_group = {
-       device_cmd_group_usage, NULL, {
+       device_cmd_group_usage, device_cmd_group_info, {
                { "add", cmd_add_dev, cmd_add_dev_usage, NULL, 0 },
-               { "delete", cmd_rm_dev, cmd_rm_dev_usage, NULL, 0 },
+               { "delete", cmd_del_dev, cmd_del_dev_usage, NULL, CMD_ALIAS },
+               { "remove", cmd_rm_dev, cmd_rm_dev_usage, NULL, 0 },
                { "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 },
                { "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 },
                { "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 },
+               { "usage", cmd_device_usage,
+                       cmd_device_usage_usage, NULL, 0 },
                NULL_CMD_STRUCT
        }
 };