diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/conf-parser.c | 44 | ||||
-rw-r--r-- | src/shared/conf-parser.h | 5 | ||||
-rw-r--r-- | src/shared/util.c | 53 | ||||
-rw-r--r-- | src/shared/util.h | 3 |
4 files changed, 86 insertions, 19 deletions
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index dde62b5755..cfa669b113 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -447,8 +447,7 @@ DEFINE_PARSER(double, double, safe_atod) DEFINE_PARSER(nsec, nsec_t, parse_nsec) DEFINE_PARSER(sec, usec_t, parse_sec) - -int config_parse_bytes_size(const char* unit, +int config_parse_iec_size(const char* unit, const char *filename, unsigned line, const char *section, @@ -468,10 +467,9 @@ int config_parse_bytes_size(const char* unit, assert(rvalue); assert(data); - r = parse_bytes(rvalue, &o); + r = parse_size(rvalue, 1024, &o); if (r < 0 || (off_t) (size_t) o != o) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse byte value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); return 0; } @@ -479,8 +477,37 @@ int config_parse_bytes_size(const char* unit, return 0; } +int config_parse_si_size(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + size_t *sz = data; + off_t o; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_size(rvalue, 1000, &o); + if (r < 0 || (off_t) (size_t) o != o) { + log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + return 0; + } + + *sz = (size_t) o; + return 0; +} -int config_parse_bytes_off(const char* unit, +int config_parse_iec_off(const char* unit, const char *filename, unsigned line, const char *section, @@ -501,10 +528,9 @@ int config_parse_bytes_off(const char* unit, assert_cc(sizeof(off_t) == sizeof(uint64_t)); - r = parse_bytes(rvalue, bytes); + r = parse_size(rvalue, 1024, bytes); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse bytes value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index ebbcaa54fe..4ccdaddd29 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -97,8 +97,9 @@ int config_parse_unsigned(const char *unit, const char *filename, unsigned line, int config_parse_long(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_uint64(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_double(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bytes_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bytes_off(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_iec_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_si_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_iec_off(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bool(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_show_status(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_string(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/shared/util.c b/src/shared/util.c index b33f1203e6..5cb598c4c5 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -2135,11 +2135,28 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return n; } -int parse_bytes(const char *t, off_t *bytes) { - static const struct { +int parse_size(const char *t, off_t base, off_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffxies, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardrware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { const char *suffix; unsigned long long factor; - } table[] = { + }; + + static const struct table iec[] = { { "B", 1 }, { "K", 1024ULL }, { "M", 1024ULL*1024ULL }, @@ -2150,11 +2167,33 @@ int parse_bytes(const char *t, off_t *bytes) { { "", 1 }, }; + static const struct table si[] = { + { "B", 1 }, + { "K", 1000ULL }, + { "M", 1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "", 1 }, + }; + + const struct table *table; const char *p; unsigned long long r = 0; + unsigned n_entries; assert(t); - assert(bytes); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } p = t; do { @@ -2176,7 +2215,7 @@ int parse_bytes(const char *t, off_t *bytes) { e += strspn(e, WHITESPACE); - for (i = 0; i < ELEMENTSOF(table); i++) + 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) @@ -2193,12 +2232,12 @@ int parse_bytes(const char *t, off_t *bytes) { break; } - if (i >= ELEMENTSOF(table)) + if (i >= n_entries) return -EINVAL; } while (*p); - *bytes = r; + *size = r; return 0; } diff --git a/src/shared/util.h b/src/shared/util.h index d1230d2b64..9913fcefae 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -144,8 +144,9 @@ int close_nointr(int fd); void close_nointr_nofail(int fd); void close_many(const int fds[], unsigned n_fd); +int parse_size(const char *t, off_t base, off_t *size); + int parse_boolean(const char *v) _pure_; -int parse_bytes(const char *t, off_t *bytes); int parse_pid(const char *s, pid_t* ret_pid); int parse_uid(const char *s, uid_t* ret_uid); #define parse_gid(s, ret_uid) parse_uid(s, ret_uid) |