--- embedaddon/bmon/src/conf.c 2012/02/21 22:19:56 1.1.1.1 +++ embedaddon/bmon/src/conf.c 2014/07/30 07:55:27 1.1.1.2 @@ -1,7 +1,8 @@ /* * conf.c Config Crap * - * Copyright (c) 2001-2005 Thomas Graf + * Copyright (c) 2001-2013 Thomas Graf + * Copyright (c) 2013 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -24,32 +25,83 @@ #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include -static int show_only_running = 1; -static int do_signal_output = 0; -static char fg_char = '*'; -static char bg_char = '.'; -static char noise_char = ':'; -static char unk_char = '?'; -static y_unit_t y_unit = Y_DYNAMIC; -static x_unit_t x_unit = X_SEC; -static char * configfile = NULL; -static float read_interval = 1.0f; -static unsigned long sleep_time = 20000; -static int use_si = 0; -static int ngraphs = 1; -static float hb_factor = 0.1; -static float rate_interval = 1.0f; -static float lifetime = 30.0f; -static char * itemtabfile = "/etc/bmon/itemtab"; +cfg_t *cfg; +static cfg_opt_t element_opts[] = { + CFG_STR("description", NULL, CFGF_NONE), + CFG_BOOL("show", cfg_true, CFGF_NONE), + CFG_INT("rxmax", 0, CFGF_NONE), + CFG_INT("txmax", 0, CFGF_NONE), + CFG_INT("max", 0, CFGF_NONE), + CFG_END() +}; + +static cfg_opt_t history_opts[] = { + CFG_FLOAT("interval", 1.0f, CFGF_NONE), + CFG_INT("size", 60, CFGF_NONE), + CFG_STR("type", "64bit", CFGF_NONE), + CFG_END() +}; + +static cfg_opt_t attr_opts[] = { + CFG_STR("description", "", CFGF_NONE), + CFG_STR("unit", "", CFGF_NONE), + CFG_STR("type", "counter", CFGF_NONE), + CFG_BOOL("history", cfg_false, CFGF_NONE), + CFG_END() +}; + +static cfg_opt_t variant_opts[] = { + CFG_FLOAT_LIST("div", "{}", CFGF_NONE), + CFG_STR_LIST("txt", "", CFGF_NONE), + CFG_END() +}; + +static cfg_opt_t unit_opts[] = { + CFG_SEC("variant", variant_opts, CFGF_MULTI | CFGF_TITLE), + CFG_END() +}; + +static cfg_opt_t global_opts[] = { + CFG_FLOAT("read_interval", 1.0f, CFGF_NONE), + CFG_FLOAT("rate_interval", 1.0f, CFGF_NONE), + CFG_FLOAT("lifetime", 30.0f, CFGF_NONE), + CFG_FLOAT("history_variance", 0.1f, CFGF_NONE), + CFG_FLOAT("variance", 0.1f, CFGF_NONE), + CFG_BOOL("show_all", cfg_false, CFGF_NONE), + CFG_INT("unit_exp", -1, CFGF_NONE), + CFG_INT("sleep_time", 20000UL, CFGF_NONE), + CFG_BOOL("use_si", 0, CFGF_NONE), + CFG_BOOL("use_bit", 0, CFGF_NONE), + CFG_STR("uid", NULL, CFGF_NONE), + CFG_STR("gid", NULL, CFGF_NONE), + CFG_STR("policy", "", CFGF_NONE), + CFG_SEC("unit", unit_opts, CFGF_MULTI | CFGF_TITLE), + CFG_SEC("attr", attr_opts, CFGF_MULTI | CFGF_TITLE), + CFG_SEC("history", history_opts, CFGF_MULTI | CFGF_TITLE), + CFG_SEC("element", element_opts, CFGF_MULTI | CFGF_TITLE), + CFG_END() +}; + +float cfg_read_interval; +float cfg_rate_interval; +float cfg_rate_variance; +float cfg_history_variance; +int cfg_show_all; +int cfg_unit_exp = DYNAMIC_EXP; + +static char * configfile = NULL; + #if defined HAVE_CURSES #if defined HAVE_USE_DEFAULT_COLORS -layout_t layout[] = +struct layout cfg_layout[] = { {-1, -1, 0}, /* dummy, not used */ {-1, -1, 0}, /* default */ @@ -59,7 +111,7 @@ layout_t layout[] = {-1, -1, A_REVERSE}, /* selected */ }; #else -layout_t layout[] = +struct layout cfg_layout[] = { {0, 0, 0}, /* dummy, not used */ {COLOR_BLACK, COLOR_WHITE, 0}, /* default */ @@ -71,199 +123,22 @@ layout_t layout[] = #endif #endif -#define SPLIT(str, var) \ - do { \ - char *s; \ - for (s = str; *s; s++) { \ - if (*s == ' ' || *s == '\t') \ - break; \ - } \ - if (!*s) \ - break; \ - *s = '\0'; \ - for (++s;*s == ' ' || *s == '\t'; s++); \ - if (!*s) \ - break; \ - var = s; \ - } while(0); - -static void conf_read(const char *); - -static inline void parse_include(char *buf) -{ - conf_read(buf); -} - -#if defined HAVE_CURSES -static int parse_color(const char *color) -{ - if (!strcmp(color, "default")) - return -1; - else if (!strcasecmp(color, "black")) - return COLOR_BLACK; - else if (!strcasecmp(color, "red")) - return COLOR_RED; - else if (!strcasecmp(color, "green")) - return COLOR_GREEN; - else if (!strcasecmp(color, "yellow")) - return COLOR_YELLOW; - else if (!strcasecmp(color, "blue")) - return COLOR_BLUE; - else if (!strcasecmp(color, "magenta")) - return COLOR_MAGENTA; - else if (!strcasecmp(color, "cyan")) - return COLOR_CYAN; - else if (!strcasecmp(color, "white")) - return COLOR_WHITE; - else - return -1; -} - -static void parse_layout(char *buf) -{ - char *id, *fg = NULL, *bg = NULL, *attr, *s; - layout_t l; - - id = buf; - SPLIT(buf, fg) - SPLIT(fg, bg) - - for (s = bg; *s; s++) { - if (*s == ' ' || *s == '\t') - break; - } - - if (*s) { - *s = '\0'; - s++; - - for (; *s == ' ' || *s == '\t'; s++); - if (*s) - attr = s; - else - attr = NULL; - } - else - attr = NULL; - - if ((l.fg = parse_color(fg)) == -1) - return; - - if ((l.bg = parse_color(bg)) == -1) - return; - - l.attr = 0; - - if (attr) - { - if (!strcasecmp(attr, "reverse")) - l.attr |= A_REVERSE; - else if (!strcasecmp(attr, "bold")) - l.attr |= A_BOLD; - else if (!strcasecmp(attr, "underline")) - l.attr |= A_UNDERLINE; - } - -#define COPY_LAYOUT(id) do { \ - layout[id].fg = l.fg; \ - layout[id].bg = l.bg; \ - layout[id].attr = l.attr; \ - } while (0); - - if (!strcasecmp(id, "default")) - COPY_LAYOUT(LAYOUT_DEFAULT) - else if (!strcasecmp(id, "statusbar")) - COPY_LAYOUT(LAYOUT_STATUSBAR) - else if (!strcasecmp(id, "header")) - COPY_LAYOUT(LAYOUT_HEADER) - else if (!strcasecmp(id, "list")) - COPY_LAYOUT(LAYOUT_LIST) - else if (!strcasecmp(id, "selected")) - COPY_LAYOUT(LAYOUT_SELECTED) - -#undef COPY_LAYOUT -} -#endif - -static void parse_bind(char *buf) -{ - char *ch, *cmd = NULL, *args, *s; - binding_t *b; - int i; - - ch = buf; - SPLIT(buf, cmd); - args = strdup(cmd); - - b = xcalloc(1, sizeof(binding_t)); - b->args[0] = args; - - for (s = args, i = 1; i < 255; i++) { - s = strchr (s, ' '); - if (s) { - *s = '\0'; - s++; - b->args[i] = s; - } else - break; - } - - b->args[i] = NULL; - - b->ch = ch[0]; - b->cmd = strdup(b->args[0]); - - add_binding(b); -} - -void conf_parse_option(const char *id, const char *value) -{ -#define MATCH(STR) if (!strcasecmp(id, STR)) - MATCH("input") - set_input(value); - else MATCH("secondary_input") - set_sec_input(value); - else MATCH("output") - set_output(value); - else MATCH("secondary_output") - set_sec_output(value); - else MATCH("policy") - item_parse_policy(value); - else MATCH("read_interval") - set_read_interval(value); - else MATCH("sleep_time") - set_sleep_time(value); - else MATCH("show_all") - set_show_only_running(0); - else MATCH("use_si") - set_use_si(); - else MATCH("nr_graphs") - set_ngraphs(strtol(value, NULL, 0)); - else MATCH("heartbeat_factor") - set_hb_factor(value); - else MATCH("rate_interval") - set_rate_interval(value); - else MATCH("lifetime") - set_lifetime(value); - else MATCH("itemtab") - set_itemtab(value); -#undef MATCH -} - tv_t * parse_tv(char *data) { char *value; tv_t *tv = xcalloc(1, sizeof(tv_t)); + init_list_head(&tv->tv_list); + value = strchr(data, '='); if (value) { *value = '\0'; ++value; - tv->value = strdup(value); + tv->tv_value = strdup(value); } - tv->type = strdup(data); + tv->tv_type = strdup(data); return tv; } @@ -277,6 +152,8 @@ module_conf_t * parse_module(char *data) m = xcalloc(1, sizeof(module_conf_t)); + init_list_head(&m->m_attrs); + opts = strchr(data, ':'); if (opts) { @@ -293,25 +170,24 @@ module_conf_t * parse_module(char *data) } tv = parse_tv(opts); + list_add_tail(&tv->tv_list, &m->m_attrs); - tv->next = m->attrs; - m->attrs = tv; - opts = next; } while(next); } - m->name = strdup(name); + m->m_name = strdup(name); return m; } -module_conf_t * parse_module_param(const char *data) +int parse_module_param(const char *data, struct list_head *list) { char *buf = strdup(data); char *next; char *current = buf; - module_conf_t *m, *list = NULL; + module_conf_t *m; + int n = 0; do { next = strchr(current, ','); @@ -322,10 +198,9 @@ module_conf_t * parse_module_param(const char *data) } m = parse_module(current); - if (m) { - m->next = list; - list = m; + list_add_tail(&m->m_list, list); + n++; } current = next; @@ -333,330 +208,401 @@ module_conf_t * parse_module_param(const char *data) free(buf); - return list; + return n; } - -static inline void parse_config_line(char *buf) +static void configfile_read_history(void) { - char *tok = NULL; - - SPLIT(buf, tok); - if (!strcasecmp(buf, "include")) - parse_include(tok); -#if defined HAVE_CURSES - else if (!strcasecmp(buf, "layout")) - parse_layout(tok); -#endif - else if (!strcasecmp(buf, "bind")) - parse_bind(tok); - else - conf_parse_option(buf, tok); -} + int i, nhistory; -static void conf_read(const char *path) -{ - FILE *f; - char buf[1024]; + nhistory = cfg_size(cfg, "history"); - if (!(f = fopen(path, "r"))) - return; + for (i = 0; i < nhistory; i++) { + struct history_def *def; + cfg_t *history; + const char *name, *type; + float interval; + int size; - memset(buf, 0, sizeof(buf)); + if (!(history = cfg_getnsec(cfg, "history", i))) + BUG(); - while (fgets(buf, sizeof(buf), f)) { - char *p; + if (!(name = cfg_title(history))) + BUG(); - if ('#' == *buf) - goto skip; + interval = cfg_getfloat(history, "interval"); + size = cfg_getint(history, "size"); + type = cfg_getstr(history, "type"); - if ((p = strchr(buf, '\r'))) - *p = '\0'; + if (interval == 0.0f) + interval = cfg_getfloat(cfg, "read_interval"); - if ((p = strchr(buf, '\n'))) - *p = '\0'; + def = history_def_alloc(name); + def->hd_interval = interval; + def->hd_size = size; - if (*buf) - parse_config_line(buf); - -skip: - memset(buf, 0, sizeof(buf)); + if (!strcasecmp(type, "8bit")) + def->hd_type = HISTORY_TYPE_8; + else if (!strcasecmp(type, "16bit")) + def->hd_type = HISTORY_TYPE_16; + else if (!strcasecmp(type, "32bit")) + def->hd_type = HISTORY_TYPE_32; + else if (!strcasecmp(type, "64bit")) + def->hd_type = HISTORY_TYPE_64; + else + quit("Invalid type \'%s\', must be \"(8|16|32|64)bit\"" + " in history definition #%d\n", type, i+1); } - - fclose(f); } -void read_configfile(void) +static void configfile_read_element_cfg(void) { - if (configfile) - conf_read(configfile); - else { - conf_read("/etc/bmon.conf"); - - if (getenv("HOME")) { - char path[FILENAME_MAX+1]; - snprintf(path, sizeof(path), "%s/.bmonrc", getenv("HOME")); - conf_read(path); - } - } -} + int i, nelement; + nelement = cfg_size(cfg, "element"); -inline void set_configfile(const char *file) -{ - static int set = 0; - if (!set) { - configfile = strdup(file); - set = 1; - } -} + for (i = 0; i < nelement; i++) { + struct element_cfg *ec; + cfg_t *element; + const char *name, *description; + long max; -inline void set_itemtab(const char *file) -{ - static int set = 0; - if (!set) { - itemtabfile = strdup(file); - set = 1; - } -} + if (!(element = cfg_getnsec(cfg, "element", i))) + BUG(); -inline char *get_itemtab(void) -{ - return itemtabfile; -} + if (!(name = cfg_title(element))) + BUG(); -inline void set_read_interval(const char *i) -{ - static int set = 0; - if (!set) { - read_interval = (float) strtod(i, NULL); - set = 1; - } -} + ec = element_cfg_alloc(name); -inline float get_read_interval(void) -{ - return read_interval; -} + if ((description = cfg_getstr(element, "description"))) + ec->ec_description = strdup(description); -inline void get_read_interval_as_ts(timestamp_t *ts) -{ - float_to_ts(ts, read_interval); -} + if ((max = cfg_getint(element, "max"))) + ec->ec_rxmax = ec->ec_txmax = max; + if ((max = cfg_getint(element, "rxmax"))) + ec->ec_rxmax = max; -inline void set_x_unit(const char *x, int force) -{ - static int set = 0; - if (!set || force) { - if (tolower(*x) == 's') - x_unit = X_SEC; - else if (tolower(*x) == 'm') - x_unit = X_MIN; - else if (tolower(*x) == 'h') - x_unit = X_HOUR; - else if (tolower(*x) == 'd') - x_unit = X_DAY; - else if (tolower(*x) == 'r') - x_unit = X_READ; + if ((max = cfg_getint(element, "txmax"))) + ec->ec_txmax = max; + + if (cfg_getbool(element, "show")) + ec->ec_flags |= ELEMENT_CFG_SHOW; else - quit("Unknown X-axis unit '%s'\n", x); - set = 1; + ec->ec_flags |= ELEMENT_CFG_HIDE; } } -inline x_unit_t get_x_unit(void) +static void add_div(struct unit *unit, int type, cfg_t *variant) { - return x_unit; -} + int ndiv, n, ntxt; -inline void set_y_unit(const char *y) -{ - static int set = 0; - if (!set) { - if (tolower(*y) == 'b') - y_unit = Y_BYTE; - else if (tolower(*y) == 'k') - y_unit = Y_KILO; - else if (tolower(*y) == 'm') - y_unit = Y_MEGA; - else if (tolower(*y) == 'g') - y_unit = Y_GIGA; - else if (tolower(*y) == 't') - y_unit = Y_TERA; - else - quit("Unknown Y-axis unit '%s'\n", y); - set = 1; - } -} + if (!(ndiv = cfg_size(variant, "div"))) + return; -inline y_unit_t get_y_unit(void) -{ - return y_unit; -} + ntxt = cfg_size(variant, "txt"); + if (ntxt != ndiv) + quit("Number of elements for div and txt not equal\n"); + if (!list_empty(&unit->u_div[type])) { + struct fraction *f, *n; -inline char get_fg_char(void) -{ - return fg_char; -} + list_for_each_entry_safe(f, n, &unit->u_div[type], f_list) + fraction_free(f); + } -inline void set_fg_char(char c) -{ - static int set = 0; - if (!set) { - fg_char = c; - set = 1; + for (n = 0; n < ndiv; n++) { + char *txt; + float div; + + div = cfg_getnfloat(variant, "div", n); + txt = cfg_getnstr(variant, "txt", n); + + unit_add_div(unit, type, txt, div); } } -inline char get_unk_char(void) +static void configfile_read_units(void) { - return unk_char; -} + int i, nunits; + struct unit *u; -inline void set_unk_char(char c) -{ - static int set = 0; - if (!set) { - unk_char = c; - set = 1; + nunits = cfg_size(cfg, "unit"); + + for (i = 0; i < nunits; i++) { + int nvariants, n; + cfg_t *unit; + const char *name; + + if (!(unit = cfg_getnsec(cfg, "unit", i))) + BUG(); + + if (!(name = cfg_title(unit))) + BUG(); + + if (!(nvariants = cfg_size(unit, "variant"))) + continue; + + if (!(u = unit_add(name))) + continue; + + for (n = 0; n < nvariants; n++) { + cfg_t *variant; + const char *vtitle; + + if (!(variant = cfg_getnsec(unit, "variant", n))) + BUG(); + + if (!(vtitle = cfg_title(variant))) + BUG(); + + if (!strcasecmp(vtitle, "default")) + add_div(u, UNIT_DEFAULT, variant); + else if (!strcasecmp(vtitle, "si")) + add_div(u, UNIT_SI, variant); + else if (!strcasecmp(vtitle, "bit")) + add_div(u, UNIT_BIT, variant); + else + quit("Unknown unit variant \'%s\'\n", vtitle); + } } } -inline char get_bg_char(void) +static void configfile_read_attrs(void) { - return bg_char; -} + int i, nattrs, t; -inline void set_bg_char(char c) -{ - static int set = 0; - if (!set) { - bg_char = c; - set = 1; + nattrs = cfg_size(cfg, "attr"); + + for (i = 0; i < nattrs; i++) { + struct unit *u; + cfg_t *attr; + const char *name, *description, *unit, *type; + int flags = 0; + + if (!(attr = cfg_getnsec(cfg, "attr", i))) + BUG(); + + if (!(name = cfg_title(attr))) + BUG(); + + description = cfg_getstr(attr, "description"); + unit = cfg_getstr(attr, "unit"); + type = cfg_getstr(attr, "type"); + + if (!unit) + quit("Attribute '%s' is missing unit specification\n", + name); + + if (!type) + quit("Attribute '%s' is missing type specification\n", + name); + + if (!(u = unit_lookup(unit))) + quit("Unknown unit \'%s\' attribute '%s'\n", + unit, name); + + if (!strcasecmp(type, "counter")) + t = ATTR_TYPE_COUNTER; + else if (!strcasecmp(type, "rate")) + t = ATTR_TYPE_RATE; + else if (!strcasecmp(type, "percent")) + t = ATTR_TYPE_PERCENT; + else + quit("Unknown type \'%s\' in attribute '%s'\n", + type, name); + + if (cfg_getbool(attr, "history")) + flags |= ATTR_FORCE_HISTORY; + + if (cfg_getbool(attr, "ignore_overflows")) + flags |= ATTR_IGNORE_OVERFLOWS; + + attr_def_add(name, description, u, t, flags); } } -inline char get_noise_char(void) +static void conf_read(const char *path, int must) { - return noise_char; -} + int err; -inline void set_noise_char(char c) -{ - static int set = 0; - if (!set) { - noise_char = c; - set = 1; + DBG("Reading configfile %s...", path); + + if (access(path, R_OK) != 0) { + if (must) + quit("Error: Unable to read configfile \"%s\": %s\n", + path, strerror(errno)); + else + return; } -} -inline void set_sleep_time(const char *s) -{ - static int set = 0; - if (!set) { - double d = strtod(s, NULL); - sleep_time = (unsigned long) (d * 1000000.0f); - set = 1; + err = cfg_parse(cfg, path); + if (err == CFG_FILE_ERROR) { + quit("Error while reading configfile \"%s\": %s\n", + path, strerror(errno)); + } else if (err == CFG_PARSE_ERROR) { + quit("Error while reading configfile \"%s\": parse error\n", + path); } -} -inline unsigned long get_sleep_time(void) -{ - return sleep_time; + configfile_read_units(); + configfile_read_history(); + configfile_read_attrs(); + configfile_read_element_cfg(); } -inline void set_signal_output(int i) -{ - static int set = 0; - if (!set) { - do_signal_output = i; - set = 1; - } -} +static const char default_config[] = \ +"unit byte {" \ +" variant default {" \ +" div = { 1, 1024, 1048576, 1073741824, 1099511627776}" \ +" txt = { \"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\" }" \ +" }" \ +" variant si {" \ +" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ +" txt = { \"B\", \"KB\", \"MB\", \"GB\", \"TB\" }" \ +" }" \ +" variant bit {" \ +" div = { 0.125, 125, 125000, 125000000, 125000000000 }" \ +" txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ +" }" \ +" }" \ +"unit bit {" \ +" variant default {" \ +" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ +" txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ +" }" \ +" variant si {" \ +" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ +" txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ +" }" \ +" variant bit {" \ +" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ +" txt = { \"b\", \"Kb\", \"Mb\", \"Gb\", \"Tb\" }" \ +" }" \ +"}" \ +"unit number {" \ +" variant default {" \ +" div = { 1, 1000, 1000000, 1000000000, 1000000000000 }" \ +" txt = { \"\", \"K\", \"M\", \"G\", \"T\" }" \ +" }" \ +"}" \ +"unit percent {" \ +" variant default {" \ +" div = { 1. }" \ +" txt = { \"%\" }" \ +" }" \ +"}" \ +"history second {" \ +" interval = 1.0" \ +" size = 60" \ +"}" \ +"history minute {" \ +" interval = 60.0" \ +" size = 60" \ +"}" \ +"history hour {" \ +" interval = 3600.0" \ +" size = 60" \ +"}" \ +"history day {" \ +" interval = 86400.0" \ +" size = 60" \ +"}"; -inline int get_signal_output(void) +static void conf_read_default(void) { - return do_signal_output; -} + int err; -inline void set_show_only_running(int i) -{ - static int set = 0; - if (!set) { - show_only_running = i; - set = 1; - } -} + DBG("Reading default config"); -inline int get_show_only_running(void) -{ - return show_only_running; -} + err = cfg_parse_buf(cfg, default_config); + if (err) + quit("Error while parsing default config\n"); -inline void set_use_si(void) -{ - use_si = 1; + configfile_read_units(); + configfile_read_history(); + configfile_read_attrs(); + configfile_read_element_cfg(); } -inline int get_use_si(void) +void configfile_read(void) { - return use_si; -} - -inline void set_ngraphs(int n) -{ - static int set = 0; - if (!set) { - ngraphs = n; - set = 1; + if (configfile) + conf_read(configfile, 1); + else { + conf_read(SYSCONFDIR "/bmon.conf", 0); + + if (getenv("HOME")) { + char path[FILENAME_MAX+1]; + snprintf(path, sizeof(path), "%s/.bmonrc", + getenv("HOME")); + conf_read(path, 0); + } } } -inline int get_ngraphs(void) +void conf_init_pre(void) { - return ngraphs; + conf_read_default(); } -inline float get_hb_factor(void) +void conf_init_post(void) { - return hb_factor; + cfg_read_interval = cfg_getfloat(cfg, "read_interval"); + cfg_rate_interval = cfg_getfloat(cfg, "rate_interval"); + cfg_rate_variance = cfg_getfloat(cfg, "variance") * cfg_rate_interval; + cfg_history_variance = cfg_getfloat(cfg, "history_variance"); + cfg_show_all = cfg_getbool(cfg, "show_all"); + cfg_unit_exp = cfg_getint(cfg, "unit_exp"); + + element_parse_policy(cfg_getstr(cfg, "policy")); } -inline void set_hb_factor(const char *s) +void set_configfile(const char *file) { static int set = 0; if (!set) { - hb_factor = strtod(s, NULL); + configfile = strdup(file); set = 1; } } -inline void set_rate_interval(const char *i) +void set_unit_exp(const char *name) { - static int set = 0; - if (!set) { - rate_interval = (float) strtod(i, NULL); - set = 1; - } + if (tolower(*name) == 'b') + cfg_setint(cfg, "unit_exp", 0); + else if (tolower(*name) == 'k') + cfg_setint(cfg, "unit_exp", 1); + else if (tolower(*name) == 'm') + cfg_setint(cfg, "unit_exp", 2); + else if (tolower(*name) == 'g') + cfg_setint(cfg, "unit_exp", 3); + else if (tolower(*name) == 't') + cfg_setint(cfg, "unit_exp", 4); + else if (tolower(*name) == 'd') + cfg_setint(cfg, "unit_exp", DYNAMIC_EXP); + else + quit("Unknown unit exponent '%s'\n", name); } -inline float get_rate_interval(void) +unsigned int get_lifecycles(void) { - return rate_interval; + return (unsigned int) + (cfg_getfloat(cfg, "lifetime") / cfg_getfloat(cfg, "read_interval")); } -inline void set_lifetime(const char *i) +static void __exit conf_shutdown(void) { - static int set = 0; - if (!set) { - lifetime = (float) strtod(i, NULL); - set = 1; - } + cfg_free(cfg); } -inline float get_lifetime(void) +static void __init __conf_init(void) { - return lifetime / read_interval; + DBG("init"); + + cfg = cfg_init(global_opts, CFGF_NOCASE); + + /* FIXME: Add validation functions */ + //cfg_set_validate_func(cfg, "bookmark", &cb_validate_bookmark); }