Move unit-parsing code to src/lib/confmgt

lib/confmgt is at a higher level than lib/conf, since it needs to
call down to logging and similar modules.
This commit is contained in:
Nick Mathewson 2019-06-13 11:59:17 -04:00
parent 246599abb4
commit 458da8a80d
8 changed files with 267 additions and 193 deletions

2
.gitignore vendored
View File

@ -162,6 +162,8 @@ uptime-*.json
/src/lib/libtor-buf-testing.a /src/lib/libtor-buf-testing.a
/src/lib/libtor-compress.a /src/lib/libtor-compress.a
/src/lib/libtor-compress-testing.a /src/lib/libtor-compress-testing.a
/src/lib/libtor-confmgt.a
/src/lib/libtor-confmgt-testing.a
/src/lib/libtor-container.a /src/lib/libtor-container.a
/src/lib/libtor-container-testing.a /src/lib/libtor-container-testing.a
/src/lib/libtor-crypt-ops.a /src/lib/libtor-crypt-ops.a

View File

@ -54,6 +54,7 @@ TOR_UTIL_LIBS = \
src/lib/libtor-math.a \ src/lib/libtor-math.a \
src/lib/libtor-meminfo.a \ src/lib/libtor-meminfo.a \
src/lib/libtor-osinfo.a \ src/lib/libtor-osinfo.a \
src/lib/libtor-confmgt.a \
src/lib/libtor-log.a \ src/lib/libtor-log.a \
src/lib/libtor-lock.a \ src/lib/libtor-lock.a \
src/lib/libtor-fdio.a \ src/lib/libtor-fdio.a \
@ -88,6 +89,7 @@ TOR_UTIL_TESTING_LIBS = \
src/lib/libtor-meminfo-testing.a \ src/lib/libtor-meminfo-testing.a \
src/lib/libtor-osinfo-testing.a \ src/lib/libtor-osinfo-testing.a \
src/lib/libtor-term-testing.a \ src/lib/libtor-term-testing.a \
src/lib/libtor-confmgt-testing.a \
src/lib/libtor-log-testing.a \ src/lib/libtor-log-testing.a \
src/lib/libtor-lock-testing.a \ src/lib/libtor-lock-testing.a \
src/lib/libtor-fdio-testing.a \ src/lib/libtor-fdio-testing.a \

View File

@ -26,12 +26,10 @@
#include "app/config/confparse.h" #include "app/config/confparse.h"
#include "feature/nodelist/routerset.h" #include "feature/nodelist/routerset.h"
#include "lib/confmgt/unitparse.h"
#include "lib/container/bitarray.h" #include "lib/container/bitarray.h"
#include "lib/encoding/confline.h" #include "lib/encoding/confline.h"
static uint64_t config_parse_memunit(const char *s, int *ok);
static int config_parse_msec_interval(const char *s, int *ok);
static int config_parse_interval(const char *s, int *ok);
static void config_reset(const config_format_t *fmt, void *options, static void config_reset(const config_format_t *fmt, void *options,
const config_var_t *var, int use_defaults); const config_var_t *var, int use_defaults);
@ -1014,193 +1012,3 @@ config_dump(const config_format_t *fmt, const void *default_options,
} }
return result; return result;
} }
/** Mapping from a unit name to a multiplier for converting that unit into a
* base unit. Used by config_parse_unit. */
struct unit_table_t {
const char *unit; /**< The name of the unit */
uint64_t multiplier; /**< How many of the base unit appear in this unit */
};
/** Table to map the names of memory units to the number of bytes they
* contain. */
static struct unit_table_t memory_units[] = {
{ "", 1 },
{ "b", 1<< 0 },
{ "byte", 1<< 0 },
{ "bytes", 1<< 0 },
{ "kb", 1<<10 },
{ "kbyte", 1<<10 },
{ "kbytes", 1<<10 },
{ "kilobyte", 1<<10 },
{ "kilobytes", 1<<10 },
{ "kilobits", 1<<7 },
{ "kilobit", 1<<7 },
{ "kbits", 1<<7 },
{ "kbit", 1<<7 },
{ "m", 1<<20 },
{ "mb", 1<<20 },
{ "mbyte", 1<<20 },
{ "mbytes", 1<<20 },
{ "megabyte", 1<<20 },
{ "megabytes", 1<<20 },
{ "megabits", 1<<17 },
{ "megabit", 1<<17 },
{ "mbits", 1<<17 },
{ "mbit", 1<<17 },
{ "gb", 1<<30 },
{ "gbyte", 1<<30 },
{ "gbytes", 1<<30 },
{ "gigabyte", 1<<30 },
{ "gigabytes", 1<<30 },
{ "gigabits", 1<<27 },
{ "gigabit", 1<<27 },
{ "gbits", 1<<27 },
{ "gbit", 1<<27 },
{ "tb", UINT64_C(1)<<40 },
{ "tbyte", UINT64_C(1)<<40 },
{ "tbytes", UINT64_C(1)<<40 },
{ "terabyte", UINT64_C(1)<<40 },
{ "terabytes", UINT64_C(1)<<40 },
{ "terabits", UINT64_C(1)<<37 },
{ "terabit", UINT64_C(1)<<37 },
{ "tbits", UINT64_C(1)<<37 },
{ "tbit", UINT64_C(1)<<37 },
{ NULL, 0 },
};
/** Table to map the names of time units to the number of seconds they
* contain. */
static struct unit_table_t time_units[] = {
{ "", 1 },
{ "second", 1 },
{ "seconds", 1 },
{ "minute", 60 },
{ "minutes", 60 },
{ "hour", 60*60 },
{ "hours", 60*60 },
{ "day", 24*60*60 },
{ "days", 24*60*60 },
{ "week", 7*24*60*60 },
{ "weeks", 7*24*60*60 },
{ "month", 2629728, }, /* about 30.437 days */
{ "months", 2629728, },
{ NULL, 0 },
};
/** Table to map the names of time units to the number of milliseconds
* they contain. */
static struct unit_table_t time_msec_units[] = {
{ "", 1 },
{ "msec", 1 },
{ "millisecond", 1 },
{ "milliseconds", 1 },
{ "second", 1000 },
{ "seconds", 1000 },
{ "minute", 60*1000 },
{ "minutes", 60*1000 },
{ "hour", 60*60*1000 },
{ "hours", 60*60*1000 },
{ "day", 24*60*60*1000 },
{ "days", 24*60*60*1000 },
{ "week", 7*24*60*60*1000 },
{ "weeks", 7*24*60*60*1000 },
{ NULL, 0 },
};
/** Parse a string <b>val</b> containing a number, zero or more
* spaces, and an optional unit string. If the unit appears in the
* table <b>u</b>, then multiply the number by the unit multiplier.
* On success, set *<b>ok</b> to 1 and return this product.
* Otherwise, set *<b>ok</b> to 0.
*/
static uint64_t
config_parse_units(const char *val, struct unit_table_t *u, int *ok)
{
uint64_t v = 0;
double d = 0;
int use_float = 0;
char *cp;
tor_assert(ok);
v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
if (!*ok || (cp && *cp == '.')) {
d = tor_parse_double(val, 0, (double)UINT64_MAX, ok, &cp);
if (!*ok)
goto done;
use_float = 1;
}
if (!cp) {
*ok = 1;
v = use_float ? ((uint64_t)d) : v;
goto done;
}
cp = (char*) eat_whitespace(cp);
for ( ;u->unit;++u) {
if (!strcasecmp(u->unit, cp)) {
if (use_float)
v = (uint64_t)(u->multiplier * d);
else
v *= u->multiplier;
*ok = 1;
goto done;
}
}
log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
*ok = 0;
done:
if (*ok)
return v;
else
return 0;
}
/** Parse a string in the format "number unit", where unit is a unit of
* information (byte, KB, M, etc). On success, set *<b>ok</b> to true
* and return the number of bytes specified. Otherwise, set
* *<b>ok</b> to false and return 0. */
static uint64_t
config_parse_memunit(const char *s, int *ok)
{
uint64_t u = config_parse_units(s, memory_units, ok);
return u;
}
/** Parse a string in the format "number unit", where unit is a unit of
* time in milliseconds. On success, set *<b>ok</b> to true and return
* the number of milliseconds in the provided interval. Otherwise, set
* *<b>ok</b> to 0 and return -1. */
static int
config_parse_msec_interval(const char *s, int *ok)
{
uint64_t r;
r = config_parse_units(s, time_msec_units, ok);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
*ok = 0;
return -1;
}
return (int)r;
}
/** Parse a string in the format "number unit", where unit is a unit of time.
* On success, set *<b>ok</b> to true and return the number of seconds in
* the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
*/
static int
config_parse_interval(const char *s, int *ok)
{
uint64_t r;
r = config_parse_units(s, time_units, ok);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Interval '%s' is too long", s);
*ok = 0;
return -1;
}
return (int)r;
}

View File

@ -6,6 +6,7 @@ include src/lib/cc/include.am
include src/lib/ctime/include.am include src/lib/ctime/include.am
include src/lib/compress/include.am include src/lib/compress/include.am
include src/lib/conf/include.am include src/lib/conf/include.am
include src/lib/confmgt/include.am
include src/lib/container/include.am include src/lib/container/include.am
include src/lib/crypt_ops/include.am include src/lib/crypt_ops/include.am
include src/lib/defs/include.am include src/lib/defs/include.am

View File

@ -0,0 +1,7 @@
orconfig.h
lib/cc/*.h
lib/conf/*.h
lib/confmgt/*.h
lib/log/*.h
lib/malloc/*.h
lib/string/*.h

View File

@ -0,0 +1,18 @@
noinst_LIBRARIES += src/lib/libtor-confmgt.a
if UNITTESTS_ENABLED
noinst_LIBRARIES += src/lib/libtor-confmgt-testing.a
endif
# ADD_C_FILE: INSERT SOURCES HERE.
src_lib_libtor_confmgt_a_SOURCES = \
src/lib/confmgt/unitparse.c
src_lib_libtor_confmgt_testing_a_SOURCES = \
$(src_lib_libtor_confmgt_a_SOURCES)
src_lib_libtor_confmgt_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS)
src_lib_libtor_confmgt_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
src/lib/confmgt/unitparse.h

202
src/lib/confmgt/unitparse.c Normal file
View File

@ -0,0 +1,202 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file unitparse.c
* @brief Functions for parsing values with units from a configuration file.
**/
#include "orconfig.h"
#include "lib/confmgt/unitparse.h"
#include "lib/log/log.h"
#include "lib/log/util_bug.h"
#include "lib/string/parse_int.h"
#include "lib/string/util_string.h"
#include <string.h>
/** Table to map the names of memory units to the number of bytes they
* contain. */
const struct unit_table_t memory_units[] = {
{ "", 1 },
{ "b", 1<< 0 },
{ "byte", 1<< 0 },
{ "bytes", 1<< 0 },
{ "kb", 1<<10 },
{ "kbyte", 1<<10 },
{ "kbytes", 1<<10 },
{ "kilobyte", 1<<10 },
{ "kilobytes", 1<<10 },
{ "kilobits", 1<<7 },
{ "kilobit", 1<<7 },
{ "kbits", 1<<7 },
{ "kbit", 1<<7 },
{ "m", 1<<20 },
{ "mb", 1<<20 },
{ "mbyte", 1<<20 },
{ "mbytes", 1<<20 },
{ "megabyte", 1<<20 },
{ "megabytes", 1<<20 },
{ "megabits", 1<<17 },
{ "megabit", 1<<17 },
{ "mbits", 1<<17 },
{ "mbit", 1<<17 },
{ "gb", 1<<30 },
{ "gbyte", 1<<30 },
{ "gbytes", 1<<30 },
{ "gigabyte", 1<<30 },
{ "gigabytes", 1<<30 },
{ "gigabits", 1<<27 },
{ "gigabit", 1<<27 },
{ "gbits", 1<<27 },
{ "gbit", 1<<27 },
{ "tb", UINT64_C(1)<<40 },
{ "tbyte", UINT64_C(1)<<40 },
{ "tbytes", UINT64_C(1)<<40 },
{ "terabyte", UINT64_C(1)<<40 },
{ "terabytes", UINT64_C(1)<<40 },
{ "terabits", UINT64_C(1)<<37 },
{ "terabit", UINT64_C(1)<<37 },
{ "tbits", UINT64_C(1)<<37 },
{ "tbit", UINT64_C(1)<<37 },
{ NULL, 0 },
};
/** Table to map the names of time units to the number of seconds they
* contain. */
const struct unit_table_t time_units[] = {
{ "", 1 },
{ "second", 1 },
{ "seconds", 1 },
{ "minute", 60 },
{ "minutes", 60 },
{ "hour", 60*60 },
{ "hours", 60*60 },
{ "day", 24*60*60 },
{ "days", 24*60*60 },
{ "week", 7*24*60*60 },
{ "weeks", 7*24*60*60 },
{ "month", 2629728, }, /* about 30.437 days */
{ "months", 2629728, },
{ NULL, 0 },
};
/** Table to map the names of time units to the number of milliseconds
* they contain. */
const struct unit_table_t time_msec_units[] = {
{ "", 1 },
{ "msec", 1 },
{ "millisecond", 1 },
{ "milliseconds", 1 },
{ "second", 1000 },
{ "seconds", 1000 },
{ "minute", 60*1000 },
{ "minutes", 60*1000 },
{ "hour", 60*60*1000 },
{ "hours", 60*60*1000 },
{ "day", 24*60*60*1000 },
{ "days", 24*60*60*1000 },
{ "week", 7*24*60*60*1000 },
{ "weeks", 7*24*60*60*1000 },
{ NULL, 0 },
};
/** Parse a string <b>val</b> containing a number, zero or more
* spaces, and an optional unit string. If the unit appears in the
* table <b>u</b>, then multiply the number by the unit multiplier.
* On success, set *<b>ok</b> to 1 and return this product.
* Otherwise, set *<b>ok</b> to 0.
*/
uint64_t
config_parse_units(const char *val, const unit_table_t *u, int *ok)
{
uint64_t v = 0;
double d = 0;
int use_float = 0;
char *cp;
tor_assert(ok);
v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp);
if (!*ok || (cp && *cp == '.')) {
d = tor_parse_double(val, 0, (double)UINT64_MAX, ok, &cp);
if (!*ok)
goto done;
use_float = 1;
}
if (!cp) {
*ok = 1;
v = use_float ? ((uint64_t)d) : v;
goto done;
}
cp = (char*) eat_whitespace(cp);
for ( ;u->unit;++u) {
if (!strcasecmp(u->unit, cp)) {
if (use_float)
v = (uint64_t)(u->multiplier * d);
else
v *= u->multiplier;
*ok = 1;
goto done;
}
}
log_warn(LD_CONFIG, "Unknown unit '%s'.", cp);
*ok = 0;
done:
if (*ok)
return v;
else
return 0;
}
/** Parse a string in the format "number unit", where unit is a unit of
* information (byte, KB, M, etc). On success, set *<b>ok</b> to true
* and return the number of bytes specified. Otherwise, set
* *<b>ok</b> to false and return 0. */
uint64_t
config_parse_memunit(const char *s, int *ok)
{
uint64_t u = config_parse_units(s, memory_units, ok);
return u;
}
/** Parse a string in the format "number unit", where unit is a unit of
* time in milliseconds. On success, set *<b>ok</b> to true and return
* the number of milliseconds in the provided interval. Otherwise, set
* *<b>ok</b> to 0 and return -1. */
int
config_parse_msec_interval(const char *s, int *ok)
{
uint64_t r;
r = config_parse_units(s, time_msec_units, ok);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Msec interval '%s' is too long", s);
*ok = 0;
return -1;
}
return (int)r;
}
/** Parse a string in the format "number unit", where unit is a unit of time.
* On success, set *<b>ok</b> to true and return the number of seconds in
* the provided interval. Otherwise, set *<b>ok</b> to 0 and return -1.
*/
int
config_parse_interval(const char *s, int *ok)
{
uint64_t r;
r = config_parse_units(s, time_units, ok);
if (r > INT_MAX) {
log_warn(LD_CONFIG, "Interval '%s' is too long", s);
*ok = 0;
return -1;
}
return (int)r;
}

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* @file unitparse.h
* @brief Header for lib/confmgt/unitparse.c
**/
#ifndef TOR_LIB_CONFMGT_UNITPARSE_H
#define TOR_LIB_CONFMGT_UNITPARSE_H
#include <lib/cc/torint.h>
/** Mapping from a unit name to a multiplier for converting that unit into a
* base unit. Used by config_parse_unit. */
typedef struct unit_table_t {
const char *unit; /**< The name of the unit */
uint64_t multiplier; /**< How many of the base unit appear in this unit */
} unit_table_t;
extern const unit_table_t memory_units[];
extern const unit_table_t time_units[];
extern const struct unit_table_t time_msec_units[];
uint64_t config_parse_units(const char *val, const unit_table_t *u, int *ok);
uint64_t config_parse_memunit(const char *s, int *ok);
int config_parse_msec_interval(const char *s, int *ok);
int config_parse_interval(const char *s, int *ok);
#endif /* !defined(TOR_LIB_CONFMGT_UNITPARSE_H) */