diff --git a/configure.in b/configure.in index c2cd69ad4..e273e1ddc 100644 --- a/configure.in +++ b/configure.in @@ -1726,7 +1726,7 @@ if test "$BUILD_CMIRRORD" = yes; then fi if test "$BUILD_LVMLOCKD" = yes; then - AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout) + AC_CHECK_FUNCS(clock_gettime strtoull,,hard_bailout) fi if test "$BUILD_LVMPOLLD" = yes; then diff --git a/lib/display/display.c b/lib/display/display.c index 62ad1feba..308ce3191 100644 --- a/lib/display/display.c +++ b/lib/display/display.c @@ -24,10 +24,6 @@ #include -#define SIZE_BUF 128 - -typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t; - static const struct { alloc_policy_t alloc; const char str[14]; /* must be changed when size extends 13 chars */ @@ -146,164 +142,30 @@ const char *display_lvname(const struct logical_volume *lv) return name; } -#define BASE_UNKNOWN 0 -#define BASE_SHARED 1 -#define BASE_1024 8 -#define BASE_1000 15 -#define BASE_SPECIAL 21 -#define NUM_UNIT_PREFIXES 6 -#define NUM_SPECIAL 3 - /* Size supplied in sectors */ static const char *_display_size(const struct cmd_context *cmd, - uint64_t size, size_len_t sl) + uint64_t size, dm_size_suffix_t suffix_type) { - unsigned base = BASE_UNKNOWN; - unsigned s; - int suffix, precision; - uint64_t byte = UINT64_C(0); - uint64_t units = UINT64_C(1024); - char *size_buf = NULL; - const char * const size_str[][3] = { - /* BASE_UNKNOWN */ - {" ", " ", " "}, /* [0] */ - - /* BASE_SHARED - Used if cmd->si_unit_consistency = 0 */ - {" Exabyte", " EB", "E"}, /* [1] */ - {" Petabyte", " PB", "P"}, /* [2] */ - {" Terabyte", " TB", "T"}, /* [3] */ - {" Gigabyte", " GB", "G"}, /* [4] */ - {" Megabyte", " MB", "M"}, /* [5] */ - {" Kilobyte", " KB", "K"}, /* [6] */ - {" Byte ", " B", "B"}, /* [7] */ - - /* BASE_1024 - Used if cmd->si_unit_consistency = 1 */ - {" Exbibyte", " EiB", "e"}, /* [8] */ - {" Pebibyte", " PiB", "p"}, /* [9] */ - {" Tebibyte", " TiB", "t"}, /* [10] */ - {" Gibibyte", " GiB", "g"}, /* [11] */ - {" Mebibyte", " MiB", "m"}, /* [12] */ - {" Kibibyte", " KiB", "k"}, /* [13] */ - {" Byte ", " B", "b"}, /* [14] */ - - /* BASE_1000 - Used if cmd->si_unit_consistency = 1 */ - {" Exabyte", " EB", "E"}, /* [15] */ - {" Petabyte", " PB", "P"}, /* [16] */ - {" Terabyte", " TB", "T"}, /* [17] */ - {" Gigabyte", " GB", "G"}, /* [18] */ - {" Megabyte", " MB", "M"}, /* [19] */ - {" Kilobyte", " kB", "K"}, /* [20] */ - - /* BASE_SPECIAL */ - {" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */ - {" Units ", " Un", "U"}, /* [22] */ - {" Sectors ", " Se", "S"}, /* [23] */ - }; - - if (!(size_buf = dm_pool_alloc(cmd->mem, SIZE_BUF))) { - log_error("no memory for size display buffer"); - return ""; - } - - suffix = cmd->current_settings.suffix; - - if (!cmd->si_unit_consistency) { - /* Case-independent match */ - for (s = 0; s < NUM_UNIT_PREFIXES; s++) - if (toupper((int) cmd->current_settings.unit_type) == - *size_str[BASE_SHARED + s][2]) { - base = BASE_SHARED; - break; - } - } else { - /* Case-dependent match for powers of 1000 */ - for (s = 0; s < NUM_UNIT_PREFIXES; s++) - if (cmd->current_settings.unit_type == - *size_str[BASE_1000 + s][2]) { - base = BASE_1000; - break; - } - - /* Case-dependent match for powers of 1024 */ - if (base == BASE_UNKNOWN) - for (s = 0; s < NUM_UNIT_PREFIXES; s++) - if (cmd->current_settings.unit_type == - *size_str[BASE_1024 + s][2]) { - base = BASE_1024; - break; - } - } - - if (base == BASE_UNKNOWN) - /* Check for special units - s, b or u */ - for (s = 0; s < NUM_SPECIAL; s++) - if (toupper((int) cmd->current_settings.unit_type) == - *size_str[BASE_SPECIAL + s][2]) { - base = BASE_SPECIAL; - break; - } - - if (size == UINT64_C(0)) { - if (base == BASE_UNKNOWN) - s = 0; - sprintf(size_buf, "0%s", suffix ? size_str[base + s][sl] : ""); - return size_buf; - } - - size *= UINT64_C(512); - - if (base != BASE_UNKNOWN) - byte = cmd->current_settings.unit_factor; - else { - /* Human-readable style */ - if (cmd->current_settings.unit_type == 'H') { - units = UINT64_C(1000); - base = BASE_1000; - } else { - units = UINT64_C(1024); - base = BASE_1024; - } - - if (!cmd->si_unit_consistency) - base = BASE_SHARED; - - byte = units * units * units * units * units * units; - - for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++) - byte /= units; - - suffix = 1; - } - - /* FIXME Make precision configurable */ - switch (toupper(*size_str[base + s][SIZE_UNIT])) { - case 'B': - case 'S': - precision = 0; - break; - default: - precision = 2; - } - - snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, - (double) size / byte, suffix ? size_str[base + s][sl] : ""); - - return size_buf; + return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type, + cmd->si_unit_consistency, + cmd->current_settings.unit_factor, + cmd->current_settings.suffix, + suffix_type); } const char *display_size_long(const struct cmd_context *cmd, uint64_t size) { - return _display_size(cmd, size, SIZE_LONG); + return _display_size(cmd, size, DM_SIZE_LONG); } const char *display_size_units(const struct cmd_context *cmd, uint64_t size) { - return _display_size(cmd, size, SIZE_UNIT); + return _display_size(cmd, size, DM_SIZE_UNIT); } const char *display_size(const struct cmd_context *cmd, uint64_t size) { - return _display_size(cmd, size, SIZE_SHORT); + return _display_size(cmd, size, DM_SIZE_SHORT); } void pvdisplay_colons(const struct physical_volume *pv) diff --git a/libdm/.exported_symbols.DM_1_02_104 b/libdm/.exported_symbols.DM_1_02_104 new file mode 100644 index 000000000..7bd144dde --- /dev/null +++ b/libdm/.exported_symbols.DM_1_02_104 @@ -0,0 +1 @@ +dm_size_to_string diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 6523c7033..3a900be48 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1532,6 +1532,32 @@ int dm_strncpy(char *dest, const char *src, size_t n); uint64_t dm_units_to_factor(const char *units, char *unit_type, int strict, const char **endptr); +/* + * Type of unit specifier used by dm_size_to_string(). + */ +typedef enum { + DM_SIZE_LONG = 0, /* Megabyte */ + DM_SIZE_SHORT = 1, /* MB or MiB */ + DM_SIZE_UNIT = 2 /* M or m */ +} dm_size_suffix_t; + +/* + * Convert a size (in 512-byte sectors) into a printable string using units of unit_type. + * An upper-case unit_type indicates output units based on powers of 1000 are + * required; a lower-case unit_type indicates powers of 1024. + * For correct operation, unit_factor must be one of: + * 0 - the correct value will be calculated internally; + * or the output from dm_units_to_factor() corresponding to unit_type; + * or 'u' or 'U', an arbitrary number of bytes to use as the power base. + * Set include_suffix to 1 to include a suffix of suffix_type. + * Set use_si_units to 0 for suffixes that don't distinguish between 1000 and 1024. + * Set use_si_units to 1 for a suffix that does distinguish. + */ +const char *dm_size_to_string(struct dm_pool *mem, uint64_t size, + char unit_type, int use_si_units, + uint64_t unit_factor, int include_suffix, + dm_size_suffix_t suffix_type); + /************************** * file/stream manipulation **************************/ diff --git a/libdm/libdm-string.c b/libdm/libdm-string.c index bc41b7042..587abfe34 100644 --- a/libdm/libdm-string.c +++ b/libdm/libdm-string.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 Red Hat, Inc. All rights reserved. + * Copyright (C) 2006-2015 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * @@ -443,6 +443,161 @@ static int _close_enough(double d1, double d2) return fabs(d1 - d2) < DBL_EPSILON; } +#define BASE_UNKNOWN 0 +#define BASE_SHARED 1 +#define BASE_1024 8 +#define BASE_1000 15 +#define BASE_SPECIAL 21 +#define NUM_UNIT_PREFIXES 6 +#define NUM_SPECIAL 3 + +#define SIZE_BUF 128 + +const char *dm_size_to_string(struct dm_pool *mem, uint64_t size, + char unit_type, int use_si_units, + uint64_t unit_factor, int include_suffix, + dm_size_suffix_t suffix_type) +{ + unsigned base = BASE_UNKNOWN; + unsigned s; + int precision; + uint64_t byte = UINT64_C(0); + uint64_t units = UINT64_C(1024); + char *size_buf = NULL; + char new_unit_type = '\0', unit_type_buf[2]; + const char * const size_str[][3] = { + /* BASE_UNKNOWN */ + {" ", " ", " "}, /* [0] */ + + /* BASE_SHARED - Used if use_si_units = 0 */ + {" Exabyte", " EB", "E"}, /* [1] */ + {" Petabyte", " PB", "P"}, /* [2] */ + {" Terabyte", " TB", "T"}, /* [3] */ + {" Gigabyte", " GB", "G"}, /* [4] */ + {" Megabyte", " MB", "M"}, /* [5] */ + {" Kilobyte", " KB", "K"}, /* [6] */ + {" Byte ", " B", "B"}, /* [7] */ + + /* BASE_1024 - Used if use_si_units = 1 */ + {" Exbibyte", " EiB", "e"}, /* [8] */ + {" Pebibyte", " PiB", "p"}, /* [9] */ + {" Tebibyte", " TiB", "t"}, /* [10] */ + {" Gibibyte", " GiB", "g"}, /* [11] */ + {" Mebibyte", " MiB", "m"}, /* [12] */ + {" Kibibyte", " KiB", "k"}, /* [13] */ + {" Byte ", " B", "b"}, /* [14] */ + + /* BASE_1000 - Used if use_si_units = 1 */ + {" Exabyte", " EB", "E"}, /* [15] */ + {" Petabyte", " PB", "P"}, /* [16] */ + {" Terabyte", " TB", "T"}, /* [17] */ + {" Gigabyte", " GB", "G"}, /* [18] */ + {" Megabyte", " MB", "M"}, /* [19] */ + {" Kilobyte", " kB", "K"}, /* [20] */ + + /* BASE_SPECIAL */ + {" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */ + {" Units ", " Un", "U"}, /* [22] */ + {" Sectors ", " Se", "S"}, /* [23] */ + }; + + if (!(size_buf = dm_pool_alloc(mem, SIZE_BUF))) { + log_error("no memory for size display buffer"); + return ""; + } + + if (!use_si_units) { + /* Case-independent match */ + for (s = 0; s < NUM_UNIT_PREFIXES; s++) + if (toupper((int) unit_type) == + *size_str[BASE_SHARED + s][2]) { + base = BASE_SHARED; + break; + } + } else { + /* Case-dependent match for powers of 1000 */ + for (s = 0; s < NUM_UNIT_PREFIXES; s++) + if (unit_type == *size_str[BASE_1000 + s][2]) { + base = BASE_1000; + break; + } + + /* Case-dependent match for powers of 1024 */ + if (base == BASE_UNKNOWN) + for (s = 0; s < NUM_UNIT_PREFIXES; s++) + if (unit_type == *size_str[BASE_1024 + s][2]) { + base = BASE_1024; + break; + } + } + + if (base == BASE_UNKNOWN) + /* Check for special units - s, b or u */ + for (s = 0; s < NUM_SPECIAL; s++) + if (toupper((int) unit_type) == + *size_str[BASE_SPECIAL + s][2]) { + base = BASE_SPECIAL; + break; + } + + if (size == UINT64_C(0)) { + if (base == BASE_UNKNOWN) + s = 0; + sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : ""); + return size_buf; + } + + size *= UINT64_C(512); + + if (base != BASE_UNKNOWN) { + if (!unit_factor) { + unit_type_buf[0] = unit_type; + unit_type_buf[1] = '\0'; + if (!(unit_factor = dm_units_to_factor(&unit_type_buf[0], &new_unit_type, 1, NULL)) || + unit_type != new_unit_type) { + /* The two functions should match (and unrecognised units get treated like 'h'). */ + log_error(INTERNAL_ERROR "Inconsistent units: %c and %c.", unit_type, new_unit_type); + return ""; + } + } + byte = unit_factor; + } else { + /* Human-readable style */ + if (unit_type == 'H') { + units = UINT64_C(1000); + base = BASE_1000; + } else { + units = UINT64_C(1024); + base = BASE_1024; + } + + if (!use_si_units) + base = BASE_SHARED; + + byte = units * units * units * units * units * units; + + for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++) + byte /= units; + + include_suffix = 1; + } + + /* FIXME Make precision configurable */ + switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) { + case 'B': + case 'S': + precision = 0; + break; + default: + precision = 2; + } + + snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, + (double) size / byte, include_suffix ? size_str[base + s][suffix_type] : ""); + + return size_buf; +} + uint64_t dm_units_to_factor(const char *units, char *unit_type, int strict, const char **endptr) {