From 4cae8946d581a6ecf0b26e154bf9c00e390024b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 2 Mar 2014 00:05:16 -0500 Subject: [PATCH] Allow fractional parts in disk sizes It seems natural to be able to say SystemMaxUsage=1.5G. https://bugzilla.redhat.com/show_bug.cgi?id=1047568 (cherry picked from commit 9480794b277b5ce33e467578ed669996df576bb9) --- src/shared/util.c | 24 ++++++++++++++++++++++-- src/test/test-util.c | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/shared/util.c b/src/shared/util.c index 5cb598c..3164515 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -2198,6 +2198,8 @@ int parse_size(const char *t, off_t base, off_t *size) { p = t; do { long long l; + unsigned long long l2; + double frac = 0; char *e; unsigned i; @@ -2213,14 +2215,32 @@ int parse_size(const char *t, off_t base, off_t *size) { if (e == p) return -EINVAL; + if (*e == '.') { + e++; + if (*e >= '0' && *e <= '9') { + char *e2; + + /* strotoull itself would accept space/+/- */ + l2 = strtoull(e, &e2, 10); + + if (errno == ERANGE) + return -errno; + + /* Ignore failure. E.g. 10.M is valid */ + frac = l2; + for (; e < e2; e++) + frac /= 10; + } + } + e += strspn(e, WHITESPACE); for (i = 0; i < n_entries; i++) if (startswith(e, table[i].suffix)) { unsigned long long tmp; - if ((unsigned long long) l > ULLONG_MAX / table[i].factor) + if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) return -ERANGE; - tmp = l * table[i].factor; + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); if (tmp > ULLONG_MAX - r) return -ERANGE; diff --git a/src/test/test-util.c b/src/test/test-util.c index b718206..74f83a2 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -30,6 +30,7 @@ #include "strv.h" #include "def.h" #include "fileio.h" +#include "conf-parser.h" static void test_streq_ptr(void) { assert_se(streq_ptr(NULL, NULL)); @@ -441,17 +442,32 @@ static void test_parse_size(void) { assert_se(parse_size("111", 1024, &bytes) == 0); assert_se(bytes == 111); + assert_se(parse_size("111.4", 1024, &bytes) == 0); + assert_se(bytes == 111); + assert_se(parse_size(" 112 B", 1024, &bytes) == 0); assert_se(bytes == 112); - assert_se(parse_size("3 K", 1024, &bytes) == 0); + assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size("3.5 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024 + 512); + + assert_se(parse_size("3. K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3.0 K", 1024, &bytes) == 0); assert_se(bytes == 3*1024); - assert_se(parse_size(" 4 M 11K", 1024, &bytes) == 0); - assert_se(bytes == 4*1024*1024 + 11 * 1024); + assert_se(parse_size("3. 0 K", 1024, &bytes) == 0); + assert_se(bytes == 3); - assert_se(parse_size("3B3G", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 3); + assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); + assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); + + assert_se(parse_size("3B3.5G", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); assert_se(parse_size("3B3G4T", 1024, &bytes) == 0); assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); @@ -464,6 +480,10 @@ static void test_parse_size(void) { assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); + assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); + assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); @@ -473,6 +493,14 @@ static void test_parse_size(void) { assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); } +static void test_config_parse_iec_off(void) { + off_t offset = 0; + assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); + assert_se(offset == 4 * 1024 * 1024); + + assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); +} + static void test_strextend(void) { _cleanup_free_ char *str = strdup("0123"); strextend(&str, "456", "78", "9", NULL); @@ -589,6 +617,9 @@ static void test_writing_tmpfile(void) { } int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + test_streq_ptr(); test_first_word(); test_close_many(); @@ -618,6 +649,7 @@ int main(int argc, char *argv[]) { test_get_process_comm(); test_protect_errno(); test_parse_size(); + test_config_parse_iec_off(); test_strextend(); test_strrep(); test_split_pair();