From e4912f548c609360cdd1b58ef40f428ebe520701 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Wed, 17 Jul 2013 13:25:03 +0200 Subject: [PATCH] thin_metadata_size.c: support -V option; support -n option argument for unit specifier; add input parameter set to long output --- thin-provisioning/thin_metadata_size.c | 130 ++++++++++++++++++------- 1 file changed, 96 insertions(+), 34 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index 51e9454..68eb3e3 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -1,12 +1,26 @@ /* * Copyright (C) 2013 Red Hat, GmbH * - * This file is released under the GPL - * * Calculates device-mapper thin privisioning * metadata device size based on pool, block size and * maximum expected thin provisioned devices and snapshots. * + * This file is part of the thin-provisioning-tools source. + * + * thin-provisioning-tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * thin-provisioning-tools is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with thin-provisioning-tools. If not, see + * . + * */ #include @@ -15,6 +29,7 @@ #include #include #include +#include "version.h" /*----------------------------------------------------------------*/ @@ -32,14 +47,15 @@ struct global { struct options { unsigned long long n[OPT_END]; + char *s[OPT_END]; char unit; } options; }; #define bytes_per_sector g->unit.factors[1] -static struct global *init(void) +static struct global *init_prg(void) { - unsigned u; + unsigned u = 0; static struct global r; static char *unit_strings[] = { "bytes", "sectors", "kilobytes", "kibibytes", "megabytes", "mebibytes", @@ -48,9 +64,7 @@ static struct global *init(void) "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; memset(&r, 0, sizeof(r)); - r.unit.chars = "bskKmMgGtTpPeEzZyY"; - u = 0; r.unit.factors[u++] = 1; r.unit.factors[u++] = 512; r.unit.factors[u++] = 1024; @@ -68,6 +82,16 @@ static struct global *init(void) return &r; } +static void exit_prg(struct global *g) +{ + unsigned u; + + for (u = OPT_END; u--; ) { + if (g->options.s[u]) + free(g->options.s[u]); + } +} + static unsigned get_index(struct global *g, char unit_char) { char *o = strchr(g->unit.chars, unit_char); @@ -114,64 +138,94 @@ static void printf_aligned(struct global *g, char *a, char *b, char *c, int unit if (units) strcat(buf, "["), strcat(buf, g->unit.chars), strcat(buf, "]"); - printf("\t%-4s%-45s%s\n", a, buf, c); + printf("\t%-4s%-44s%s\n", a, buf, c); } static void help(struct global *g) { - printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [opts]\n", prg); + printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [options]\n", prg); printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 1); printf_aligned(g, "-u", "--unit ", "Output unit specifier.", 1); - printf_aligned(g, "-n", "--numeric-only", "Output numeric value only.", 0); + printf_aligned(g, "-n", "--numeric-only[=unit]", "Output numeric value only (optionally with unit identifier).", 0); printf_aligned(g, "-h", "--help", "This help.", 0); + printf_aligned(g, "-V", "--version", "Print thin provisioning tools version.", 0); exit(0); } static void check_unit(struct global *g, char *arg) { if (*(arg + 1)) - abort_prg("only one unit specifier allowed!"); + abort_prg("only one unit specifier character allowed!"); else if (!strchr(g->unit.chars, *arg)) - abort_prg("output unit specifier invalid!"); + abort_prg("output unit specifier character invalid!"); g->options.unit = *arg; } -static struct global *parse_command_line(struct global *g, int argc, char **argv) +static void check_numeric_option(struct global *g, char *arg) +{ + if (g->options.n[NUMERIC]) + abort_prg("-n already given!"); + + g->options.n[NUMERIC] = 1; + + if (arg) { + if (!*arg || strncmp("unit", arg, strlen(arg))) + abort_prg("-n invalid option argument"); + + g->options.n[NUMERIC]++; + } +} + +static void check_size(struct global *g, enum numeric_options o, enum return_units unit, char *arg) +{ + if (g->options.n[o]) + abort_prg("option already given!"); + + g->options.s[o] = strdup(arg); + if (!g->options.s[o]) + abort_prg("failed to allocate string!"); + + g->options.n[o] = to_bytes(g, arg, unit); +} + +static void parse_command_line(struct global *g, int argc, char **argv) { int c; static struct option long_options[] = { - {"block-size", required_argument, 0, 'b' }, - {"pool-size", required_argument, 0, 's' }, - {"max-thins", required_argument, 0, 'm' }, - {"unit", required_argument, 0, 'u' }, - {"numeric-only",required_argument, 0, 'n' }, - {"help", no_argument, 0, 'h' }, - {NULL, 0, 0, 0 } + {"block-size", required_argument, NULL, 'b' }, + {"pool-size", required_argument, NULL, 's' }, + {"max-thins", required_argument, NULL, 'm' }, + {"unit", required_argument, NULL, 'u' }, + {"numeric-only",optional_argument, NULL, 'n' }, + {"help", no_argument, NULL, 'h' }, + {"version", no_argument, NULL, 'V' }, + {NULL, 0, NULL, 0 } }; - while ((c = getopt_long(argc, argv, "b:s:m:u:nh", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:s:m:u:n::hV", long_options, NULL)) != -1) { if (c == 'b') - g->options.n[BLOCKSIZE] = to_bytes(g, optarg, RETURN_SECTORS); + check_size(g, BLOCKSIZE, RETURN_SECTORS, optarg); else if (c == 's') - g->options.n[POOLSIZE] = to_bytes(g, optarg, RETURN_SECTORS); + check_size(g, POOLSIZE, RETURN_SECTORS, optarg); else if (c == 'm') - g->options.n[MAXTHINS] = to_bytes(g, optarg, RETURN_BYTES); + check_size(g, MAXTHINS, RETURN_BYTES, optarg); else if (c == 'u') check_unit(g, optarg); else if (c == 'n') - g->options.n[NUMERIC] = 1; + check_numeric_option(g, optarg); else if (c == 'h') help(g); - else + else if (c == 'V') { + printf("%s\n", THIN_PROVISIONING_TOOLS_VERSION); + exit(0); + } else abort_prg("Invalid option!"); } check_opts(&g->options); - - return g; } static const unsigned mappings_per_block(void) @@ -185,12 +239,14 @@ static const unsigned mappings_per_block(void) return (btree_size.node - btree_size.node_header) / btree_size.entry; } -static void printf_precision(double r, int full, char *unit_str) +static void printf_precision(struct global *g, double r, unsigned idx) { + int full = !g->options.n[NUMERIC]; double rtrunc = truncl(r); if (full) - printf("%s - estimated metadata area size is ", prg); + printf("%s - estimated metadata area size [blocksize=%s,poolsize=%s,maxthins=%s] is ", + prg, g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); if (r == rtrunc) printf("%llu", (unsigned long long) r); @@ -198,12 +254,14 @@ static void printf_precision(double r, int full, char *unit_str) printf(r - truncl(r) < 1E-2 ? "%0.2e" : "%0.2f", r); if (full) - printf(" %s", unit_str); + printf(" %s", g->unit.strings[idx]); + else if (g->options.n[NUMERIC] > 1) + printf("%c", g->unit.chars[idx]); putchar('\n'); } -static void estimated_result(struct global *g) +static void print_estimated_result(struct global *g) { unsigned idx = get_index(g, g->options.unit); double r; @@ -212,12 +270,16 @@ static void estimated_result(struct global *g) r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector; /* in bytes! */ r /= g->unit.factors[idx]; /* in requested unit */ - printf_precision(r, !g->options.n[NUMERIC], g->unit.strings[idx]); + printf_precision(g, r, idx); } int main(int argc, char **argv) { - prg = basename(*argv); - estimated_result(parse_command_line(init(), argc, argv)); + struct global *g = init_prg(); + + prg = basename(argv[0]); + parse_command_line(g, argc, argv); + print_estimated_result(g); + exit_prg(g); return 0; }