Add '--si', '-h'/'--human-readable' and '--block-size' global options, which allow users to customize the way sizes are displayed.
Options and their format tries to mimic GNU ls utility. Signed-off-by: Audrius Butkevicius <audrius.butkevic...@elastichosts.com> --- btrfs.c | 3 ++ utils.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- utils.h | 6 +++ 3 files changed, 138 insertions(+), 17 deletions(-) diff --git a/btrfs.c b/btrfs.c index 691adef..6a8fc30 100644 --- a/btrfs.c +++ b/btrfs.c @@ -22,6 +22,8 @@ #include "crc32c.h" #include "commands.h" #include "version.h" +#include "ctree.h" +#include "utils.h" static const char * const btrfs_cmd_group_usage[] = { "btrfs [--help] [--version] <group> [<group>...] <command> [<args>]", @@ -291,6 +293,7 @@ int main(int argc, char **argv) crc32c_optimization_init(); + handle_size_unit_args(&argc, &argv); fixup_argv0(argv, cmd->token); exit(cmd->fn(argc, argv)); } diff --git a/utils.c b/utils.c index d660507..58c1919 100644 --- a/utils.c +++ b/utils.c @@ -16,6 +16,7 @@ * Boston, MA 021110-1307, USA. */ +#define _GNU_SOURCE #define _XOPEN_SOURCE 700 #define __USE_XOPEN2K8 #define __XOPEN2K8 /* due to an error in dirent.h, to get dirfd() */ @@ -1095,33 +1096,144 @@ out: return ret; } -static char *size_strs[] = { "", "KB", "MB", "GB", "TB", - "PB", "EB", "ZB", "YB"}; +static int sizes_format = SIZES_FORMAT_BYTES; +static u64 sizes_divisor = 1; + +void remove_arg(int i, int *argc, char ***argv) +{ + while (i++ < *argc) + (*argv)[i - 1] = (*argv)[i]; + (*argc)--; +} + +void handle_size_unit_args(int *argc, char ***argv) +{ + int k; + int base = 1024; + char *suffix; + char *block_size; + u64 value; + + for (k = *argc - 1; k >= 0; k--) { + if (!strcmp((*argv)[k], "-h") || + !strcmp((*argv)[k], "--human-readable")) { + sizes_format = SIZES_FORMAT_HUMAN; + remove_arg(k, argc, argv); + } else if (!strcmp((*argv)[k], "--si")) { + sizes_format = SIZES_FORMAT_SI; + remove_arg(k, argc, argv); + } else if (!strncmp((*argv)[k], "--block-size", 12)) { + if (strlen((*argv)[k]) < 14 || (*argv)[k][12] != '=') { + fprintf(stderr, + "--block-size requires an argument\n"); + exit(1); + } + + sizes_format = SIZES_FORMAT_BLOCK; + block_size = strchr((*argv)[k], '='); + + errno = 0; + value = strtoull(++block_size, &suffix, 10); + if (errno == ERANGE && value == ULLONG_MAX) { + fprintf(stderr, + "--block-size argument '%s' too large\n", + block_size); + exit(1); + } + if (suffix == block_size) + value = 1; + + if (strlen(suffix) == 1 && value > 0) { + base = 1024; + } else if (strlen(suffix) == 2 && suffix[1] == 'B' + && value > 0) { + base = 1000; + /* Allow non-zero values without a suffix */ + } else if (strlen(suffix) != 0 || value == 0) { + fprintf(stderr, + "invalid --block-size argument '%s'\n", + block_size); + exit(1); + } + + if (strlen(suffix) > 0) { + switch(suffix[0]) { + case 'E': + sizes_divisor *= base; + case 'P': + sizes_divisor *= base; + case 'T': + sizes_divisor *= base; + case 'G': + sizes_divisor *= base; + case 'M': + sizes_divisor *= base; + case 'K': + sizes_divisor *= base; + break; + default: + fprintf(stderr, + "invalid --block-size \ +argument '%s'\n", + block_size); + exit(1); + } + } + + if (ULLONG_MAX / sizes_divisor < value) { + fprintf(stderr, + "--block-size argument '%s' too large\n", + block_size); + exit(1); + } + + if (suffix != block_size) + sizes_divisor *= value; + + remove_arg(k, argc, argv); + } + } +} + +static char *size_strs[] = { "", "K", "M", "G", "T", "P", "E"}; char *pretty_sizes(u64 size) { int num_divs = 0; - int pretty_len = 16; + int sizes_base = 1024; float fraction; char *pretty; - - if( size < 1024 ){ - fraction = size; - num_divs = 0; + char *sizes_suffix = "iB"; + u64 last_size; + + if (sizes_format == SIZES_FORMAT_BYTES) { + asprintf(&pretty, "%llu", (unsigned long long)size); + } else if (sizes_format == SIZES_FORMAT_BLOCK) { + fraction = (float)size / sizes_divisor; + asprintf(&pretty, "%.2f", fraction); } else { - u64 last_size = size; - num_divs = 0; - while(size >= 1024){ + if (sizes_format == SIZES_FORMAT_SI) { + sizes_base = 1000; + sizes_suffix = "B"; + } + + if (size < sizes_base) { + fraction = size; + } else { last_size = size; - size /= 1024; - num_divs ++; + while (size >= sizes_base) { + last_size = size; + size /= 1024; + num_divs++; + } + + if (num_divs > ARRAY_SIZE(size_strs)) + return NULL; + fraction = (float)last_size / sizes_base; } - if (num_divs >= ARRAY_SIZE(size_strs)) - return NULL; - fraction = (float)last_size / 1024; + asprintf(&pretty, "%.2f%s%s", fraction, size_strs[num_divs], + sizes_suffix); } - pretty = malloc(pretty_len); - snprintf(pretty, pretty_len, "%.2f%s", fraction, size_strs[num_divs]); return pretty; } diff --git a/utils.h b/utils.h index 60a0fea..56d7950 100644 --- a/utils.h +++ b/utils.h @@ -23,6 +23,11 @@ #define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024) +#define SIZES_FORMAT_BYTES 0 +#define SIZES_FORMAT_HUMAN 1 +#define SIZES_FORMAT_SI 2 +#define SIZES_FORMAT_BLOCK 3 + int make_btrfs(int fd, const char *device, const char *label, u64 blocks[6], u64 num_bytes, u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize); @@ -44,6 +49,7 @@ int check_mounted_where(int fd, const char *file, char *where, int size, int btrfs_device_already_in_root(struct btrfs_root *root, int fd, int super_offset); char *pretty_sizes(u64 size); +void handle_size_unit_args(int *argc, char ***argv); int check_label(char *input); int get_mountpt(char *dev, char *mntpt, size_t size); int btrfs_scan_block_devices(int run_ioctl); -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html