Re: [PATCH] btrfs-progs: add options for changing size representations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

> Add '--si', '-h'/'--human-readable' and '--block-size' global options,
> which allow users to customize the way sizes are displayed.

why not use the function getopt_long()  to complete the parsing.
Never Re-inventing the wheel  again.

As discussed  before, better not use 'exit(1)'  in the parsing process,
I think it better to implement the parse_function like this:

int  parse_str(char *str,  u64 *size)

Thanks,
Wang

> 
> Options and their format tries to mimic GNU ls utility.
> 
> Signed-off-by: Audrius Butkevicius <audrius.butkevicius@xxxxxxxxxxxxxxxx>
> ---
> 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 majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux