mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
libdm: Add dm_size_to_string to libdevmapper.
Moved out from lib/display and a little documentation added. It's tuned to LVM's requirements historically and its behaviour might not always be what you would expect.
This commit is contained in:
parent
fa11ddd7df
commit
af1c7bf0c7
@ -24,10 +24,6 @@
|
|||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define SIZE_BUF 128
|
|
||||||
|
|
||||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
alloc_policy_t alloc;
|
alloc_policy_t alloc;
|
||||||
const char str[14]; /* must be changed when size extends 13 chars */
|
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;
|
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 */
|
/* Size supplied in sectors */
|
||||||
static const char *_display_size(const struct cmd_context *cmd,
|
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;
|
return dm_size_to_string(cmd->mem, size, cmd->current_settings.unit_type,
|
||||||
unsigned s;
|
cmd->si_unit_consistency,
|
||||||
int suffix, precision;
|
cmd->current_settings.unit_factor,
|
||||||
uint64_t byte = UINT64_C(0);
|
cmd->current_settings.suffix,
|
||||||
uint64_t units = UINT64_C(1024);
|
suffix_type);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *display_size_long(const struct cmd_context *cmd, uint64_t size)
|
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)
|
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)
|
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)
|
void pvdisplay_colons(const struct physical_volume *pv)
|
||||||
|
1
libdm/.exported_symbols.DM_1_02_104
Normal file
1
libdm/.exported_symbols.DM_1_02_104
Normal file
@ -0,0 +1 @@
|
|||||||
|
dm_size_to_string
|
@ -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,
|
uint64_t dm_units_to_factor(const char *units, char *unit_type,
|
||||||
int strict, const char **endptr);
|
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
|
* file/stream manipulation
|
||||||
**************************/
|
**************************/
|
||||||
|
@ -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.
|
* 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;
|
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,
|
uint64_t dm_units_to_factor(const char *units, char *unit_type,
|
||||||
int strict, const char **endptr)
|
int strict, const char **endptr)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user