diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM index 6a983a783..c81d354a1 100644 --- a/WHATS_NEW_DM +++ b/WHATS_NEW_DM @@ -1,5 +1,6 @@ Version 1.02.88 - ================================= + Add dm_units_to_factor for size unit parsing. Increase bitset size for minors for thin dmeventd plugin. Version 1.02.85 - 10th April 2014 diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index d62fb8a17..b2f829334 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -282,8 +282,8 @@ static int _check_config(struct cmd_context *cmd) int process_profilable_config(struct cmd_context *cmd) { if (!(cmd->default_settings.unit_factor = - units_to_bytes(find_config_tree_str(cmd, global_units_CFG, NULL), - &cmd->default_settings.unit_type))) { + dm_units_to_factor(find_config_tree_str(cmd, global_units_CFG, NULL), + &cmd->default_settings.unit_type, 1, NULL))) { log_error("Invalid units specification"); return 0; } diff --git a/lib/display/display.c b/lib/display/display.c index b7fbf1a82..c93b2b350 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -20,8 +20,6 @@ #include "toolcontext.h" #include "segtype.h" #include "defaults.h" -#include /* fabs() */ -#include /* DBL_EPSILON */ #include #define SIZE_BUF 128 @@ -44,103 +42,6 @@ static const struct { static const int _num_policies = DM_ARRAY_SIZE(_policies); -/* Test if the doubles are close enough to be considered equal */ -static int _close_enough(double d1, double d2) -{ - return fabs(d1 - d2) < DBL_EPSILON; -} - -uint64_t units_to_bytes(const char *units, char *unit_type) -{ - char *ptr = NULL; - uint64_t v; - double custom_value = 0; - uint64_t multiplier; - - if (isdigit(*units)) { - custom_value = strtod(units, &ptr); - if (ptr == units) - return 0; - v = (uint64_t) strtoull(units, NULL, 10); - if (_close_enough((double) v, custom_value)) - custom_value = 0; /* Use integer arithmetic */ - units = ptr; - } else - v = 1; - - /* Only one units char permitted. */ - if (units[0] && units[1]) - return 0; - - if (v == 1) - *unit_type = *units; - else - *unit_type = 'U'; - - switch (*units) { - case 'h': - case 'H': - multiplier = v = UINT64_C(1); - *unit_type = *units; - break; - case 'b': - case 'B': - multiplier = UINT64_C(1); - break; -#define KILO UINT64_C(1024) - case 's': - case 'S': - multiplier = (KILO/2); - break; - case 'k': - multiplier = KILO; - break; - case 'm': - multiplier = KILO * KILO; - break; - case 'g': - multiplier = KILO * KILO * KILO; - break; - case 't': - multiplier = KILO * KILO * KILO * KILO; - break; - case 'p': - multiplier = KILO * KILO * KILO * KILO * KILO; - break; - case 'e': - multiplier = KILO * KILO * KILO * KILO * KILO * KILO; - break; -#undef KILO -#define KILO UINT64_C(1000) - case 'K': - multiplier = KILO; - break; - case 'M': - multiplier = KILO * KILO; - break; - case 'G': - multiplier = KILO * KILO * KILO; - break; - case 'T': - multiplier = KILO * KILO * KILO * KILO; - break; - case 'P': - multiplier = KILO * KILO * KILO * KILO * KILO; - break; - case 'E': - multiplier = KILO * KILO * KILO * KILO * KILO * KILO; - break; -#undef KILO - default: - return 0; - } - - if (_close_enough(custom_value, 0.)) - return v * multiplier; /* Use integer arithmetic */ - else - return (uint64_t) (custom_value * multiplier); -} - char alloc_policy_char(alloc_policy_t alloc) { int i; diff --git a/lib/display/display.h b/lib/display/display.h index 41fba03a3..d5c0efa2e 100644 --- a/lib/display/display.h +++ b/lib/display/display.h @@ -22,8 +22,6 @@ #include -uint64_t units_to_bytes(const char *units, char *unit_type); - /* Specify size in KB */ const char *display_size(const struct cmd_context *cmd, uint64_t size); const char *display_size_long(const struct cmd_context *cmd, uint64_t size); diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 5f7b14cf1..8ffa14545 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1454,6 +1454,50 @@ void dm_unescape_colons_and_at_signs(char *src, */ int dm_strncpy(char *dest, const char *src, size_t n); +/* + * Recognize unit specifier in the 'units' arg and return a factor + * representing that unit. If the 'units' contains a prefix with digits, + * the 'units' is considered to be a custom unit. + * + * Also, set 'unit_type' output arg to the character that represents + * the unit specified. The 'unit_type' character equals to the unit + * character itself recognized in the 'units' arg for canonical units. + * Otherwise, the 'unit_type' character is set to 'U' for custom unit. + * + * An example for k/K canonical units and 8k/8K custom units: + * + * units unit_type return value (factor) + * k k 1024 + * K K 1000 + * 8k U 1024*8 + * 8K U 1000*8 + * etc... + * + * Recognized units: + * + * h/H - human readable (returns 1 for both) + * b/B - byte (returns 1 for both) + * s/S - sector (returns 512 for both) + * k/K - kilo (returns 1024/1000 respectively) + * m/M - mega (returns 1024^2/1000^2 respectively) + * g/G - giga (returns 1024^3/1000^3 respectively) + * t/T - tera (returns 1024^4/1000^4 respectively) + * p/P - peta (returns 1024^5/1000^5 respectively) + * e/E - exa (returns 1024^6/1000^6 respectively) + * + * Only one units character is allowed in the 'units' arg + * if strict mode is enabled by 'strict' arg. + * + * The 'endptr' output arg, if not NULL, saves the pointer + * in the 'units' string which follows the unit specifier + * recognized (IOW the position where the parsing of the + * unit specifier stopped). + * + * Returns the unit factor or 0 if no unit is recognized. + */ +uint64_t dm_units_to_factor(const char *units, char *unit_type, + int strict, char **endptr); + /************************** * file/stream manipulation **************************/ diff --git a/libdm/libdm-string.c b/libdm/libdm-string.c index 64a9792e5..7336e6bf7 100644 --- a/libdm/libdm-string.c +++ b/libdm/libdm-string.c @@ -16,6 +16,8 @@ #include #include +#include /* fabs() */ +#include /* DBL_EPSILON */ /* * consume characters while they match the predicate function. @@ -434,3 +436,107 @@ int dm_strncpy(char *dest, const char *src, size_t n) return 0; } + +/* Test if the doubles are close enough to be considered equal */ +static int _close_enough(double d1, double d2) +{ + return fabs(d1 - d2) < DBL_EPSILON; +} + +uint64_t dm_units_to_factor(const char *units, char *unit_type, + int strict, char **endptr) +{ + char *ptr = NULL; + uint64_t v; + double custom_value = 0; + uint64_t multiplier; + + if (endptr) + *endptr = (char *) units; + + if (isdigit(*units)) { + custom_value = strtod(units, &ptr); + if (ptr == units) + return 0; + v = (uint64_t) strtoull(units, NULL, 10); + if (_close_enough((double) v, custom_value)) + custom_value = 0; /* Use integer arithmetic */ + units = ptr; + } else + v = 1; + + /* Only one units char permitted in strict mode. */ + if (strict && units[0] && units[1]) + return 0; + + if (v == 1) + *unit_type = *units; + else + *unit_type = 'U'; + + switch (*units) { + case 'h': + case 'H': + multiplier = v = UINT64_C(1); + *unit_type = *units; + break; + case 'b': + case 'B': + multiplier = UINT64_C(1); + break; +#define KILO UINT64_C(1024) + case 's': + case 'S': + multiplier = (KILO/2); + break; + case 'k': + multiplier = KILO; + break; + case 'm': + multiplier = KILO * KILO; + break; + case 'g': + multiplier = KILO * KILO * KILO; + break; + case 't': + multiplier = KILO * KILO * KILO * KILO; + break; + case 'p': + multiplier = KILO * KILO * KILO * KILO * KILO; + break; + case 'e': + multiplier = KILO * KILO * KILO * KILO * KILO * KILO; + break; +#undef KILO +#define KILO UINT64_C(1000) + case 'K': + multiplier = KILO; + break; + case 'M': + multiplier = KILO * KILO; + break; + case 'G': + multiplier = KILO * KILO * KILO; + break; + case 'T': + multiplier = KILO * KILO * KILO * KILO; + break; + case 'P': + multiplier = KILO * KILO * KILO * KILO * KILO; + break; + case 'E': + multiplier = KILO * KILO * KILO * KILO * KILO * KILO; + break; +#undef KILO + default: + return 0; + } + + if (endptr) + *endptr = (char *) units + 1; + + if (_close_enough(custom_value, 0.)) + return v * multiplier; /* Use integer arithmetic */ + else + return (uint64_t) (custom_value * multiplier); +} diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 758c429d1..7e4d9a6a3 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -923,8 +923,8 @@ static int _get_settings(struct cmd_context *cmd) if (arg_count(cmd, units_ARG)) if (!(cmd->current_settings.unit_factor = - units_to_bytes(arg_str_value(cmd, units_ARG, ""), - &cmd->current_settings.unit_type))) { + dm_units_to_factor(arg_str_value(cmd, units_ARG, ""), + &cmd->current_settings.unit_type, 1, NULL))) { log_error("Invalid units specification"); return EINVALID_CMD_LINE; }