From e29cd366a24859195f92b874d4bf260a3cc63bc2 Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Tue, 5 Mar 2013 18:02:13 +0100 Subject: [PATCH] config: add support for enhanced config node output There's a possibility to interconnect the dm_config_node with an ID, which in our case is used to reference the configuration definition ID from config_settings.h. So simply interconnecting struct dm_config_node with struct cfg_def_item. This patch also adds support for enhanced config node output besides existing "output line by line". This patch adds a possibility to register a callback that gets called *before* the config node is processed line by line (for example to include any headers on output) and *after* the config node is processed line by line (to include any footers on output). Also, it adds the config node reference itself as the callback arg in addition to have a possibility to extract more information from the config node itself if needed when processing the output callback (e.g. the key name, the id, or whether this is a section or a value etc...). If the config node from lvm.conf/--config tree is recognized and valid, it's always coupled with the config node definition ID from config_settings.h: struct dm_config_node { int id; const char *key; struct dm_config_node *parent, *sib, *child; struct dm_config_value *v; } For example if the dm_config_node *cn holds "devices/dev" configuration, then the cn->id holds "devices_dev_CFG" ID from config_settings.h, -1 if not found in config_settings.h and 0 if matching has not yet been done. To support the enhanced config node output, a new structure has been defined in libdevmapper to register it: struct dm_config_node_out_spec { dm_config_node_out_fn prefix_fn; /* called before processing config node lines */ dm_config_node_out_fn line_fn; /* called for each config node line */ dm_config_node_out_fn suffix_fn; /* called after processing config node lines */ }; Where dm_config_node_out_fn is: typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton); (so in comparison to existing callbacks for config node output, it has an extra dm_config_node *cn arg in addition) This patch also adds these functions to libdevmapper: - dm_config_write_node_out - dm_config_write_one_node_out ...which have exactly the same functionality as their counterparts without the "out" suffix. The "*_out" functions adds the extra hooks for enhanced config output (prefix_fn and suffix_fn mentioned above). One can still use the old interface for config node output, this is just an enhancement for those who'd like to modify the output more extensively. --- lib/config/config.c | 6 +++ libdm/libdevmapper.h | 17 +++++++++ libdm/libdm-config.c | 91 +++++++++++++++++++++++++++++--------------- 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/lib/config/config.c b/lib/config/config.c index a02f47895..5a51a2966 100644 --- a/lib/config/config.c +++ b/lib/config/config.c @@ -472,6 +472,7 @@ static int _config_def_check_node(const char *vp, char *pvp, char *rp, char *prp if (cn->v) { log_warn_suppress(suppress_messages, "Configuration setting \"%s\" unknown.", rp); + cn->id = -1; return 0; } @@ -482,11 +483,14 @@ static int _config_def_check_node(const char *vp, char *pvp, char *rp, char *prp if (!(def = (cfg_def_item_t *) dm_hash_lookup(ht, vp))) { log_warn_suppress(suppress_messages, "Configuration section \"%s\" unknown.", rp); + cn->id = -1; return 0; } } def->flags |= CFG_USED; + cn->id = def->id; + if (!_config_def_check_node_value(rp, cn->v, def, suppress_messages)) return 0; @@ -962,6 +966,8 @@ static struct dm_config_node *_add_def_node(struct dm_config_tree *cft, return NULL; } + cn->id = def->id; + if (!(def->type & CFG_TYPE_ARRAY)) { switch (def->type) { case CFG_TYPE_SECTION: diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 8c349c507..0460afab3 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1496,6 +1496,7 @@ struct dm_config_value { }; struct dm_config_node { + int id; const char *key; struct dm_config_node *parent, *sib, *child; struct dm_config_value *v; @@ -1528,11 +1529,27 @@ struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft void dm_config_destroy(struct dm_config_tree *cft); +/* Simple output line by line. */ typedef int (*dm_putline_fn)(const char *line, void *baton); +/* More advaced output with config node reference. */ +typedef int (*dm_config_node_out_fn)(const struct dm_config_node *cn, const char *line, void *baton); + +/* + * Specification for advanced config node output. + */ +struct dm_config_node_out_spec { + dm_config_node_out_fn prefix_fn; /* called before processing config node lines */ + dm_config_node_out_fn line_fn; /* called for each config node line */ + dm_config_node_out_fn suffix_fn; /* called after processing config node lines */ +}; + /* Write the node and any subsequent siblings it has. */ int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton); +int dm_config_write_node_out(const struct dm_config_node *cn, const struct dm_config_node_out_spec *out_spec, void *baton); + /* Write given node only without subsequent siblings. */ int dm_config_write_one_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton); +int dm_config_write_one_node_out(const struct dm_config_node *cn, const struct dm_config_node_out_spec *out_spec, void *baton); struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path); int dm_config_has_node(const struct dm_config_node *cn, const char *path); diff --git a/libdm/libdm-config.c b/libdm/libdm-config.c index 4705a1cce..368f9e338 100644 --- a/libdm/libdm-config.c +++ b/libdm/libdm-config.c @@ -50,10 +50,11 @@ struct parser { struct dm_pool *mem; }; -struct output_line { +struct config_output { struct dm_pool *mem; dm_putline_fn putline; - void *putline_baton; + const struct dm_config_node_out_spec *spec; + void *baton; }; static void _get_token(struct parser *p, int tok_prev); @@ -189,9 +190,9 @@ struct dm_config_tree *dm_config_from_string(const char *config_settings) return cft; } -static int _line_start(struct output_line *outline) +static int _line_start(struct config_output *out) { - if (!dm_pool_begin_object(outline->mem, 128)) { + if (!dm_pool_begin_object(out->mem, 128)) { log_error("dm_pool_begin_object failed for config line"); return 0; } @@ -200,7 +201,7 @@ static int _line_start(struct output_line *outline) } __attribute__ ((format(printf, 2, 3))) -static int _line_append(struct output_line *outline, const char *fmt, ...) +static int _line_append(struct config_output *out, const char *fmt, ...) { char buf[4096]; va_list ap; @@ -215,7 +216,7 @@ static int _line_append(struct output_line *outline, const char *fmt, ...) return 0; } - if (!dm_pool_grow_object(outline->mem, &buf[0], strlen(buf))) { + if (!dm_pool_grow_object(out->mem, &buf[0], strlen(buf))) { log_error("dm_pool_grow_object failed for config line"); return 0; } @@ -223,28 +224,32 @@ static int _line_append(struct output_line *outline, const char *fmt, ...) return 1; } -#define line_append(args...) do {if (!_line_append(outline, args)) {return_0;}} while (0) +#define line_append(args...) do {if (!_line_append(out, args)) {return_0;}} while (0) -static int _line_end(struct output_line *outline) +static int _line_end(const struct dm_config_node *cn, struct config_output *out) { const char *line; - if (!dm_pool_grow_object(outline->mem, "\0", 1)) { + if (!dm_pool_grow_object(out->mem, "\0", 1)) { log_error("dm_pool_grow_object failed for config line"); return 0; } - line = dm_pool_end_object(outline->mem); + line = dm_pool_end_object(out->mem); - if (!outline->putline) + if (!out->putline && !out->spec) return 0; - outline->putline(line, outline->putline_baton); + if (out->putline) + out->putline(line, out->baton); + + if (out->spec && out->spec->line_fn) + out->spec->line_fn(cn, line, out->baton); return 1; } -static int _write_value(struct output_line *outline, const struct dm_config_value *v) +static int _write_value(struct config_output *out, const struct dm_config_value *v) { char *buf; @@ -279,7 +284,7 @@ static int _write_value(struct output_line *outline, const struct dm_config_valu } static int _write_config(const struct dm_config_node *n, int only_one, - struct output_line *outline, int level) + struct config_output *out, int level) { char space[MAX_INDENT + 1]; int l = (level < MAX_INDENT) ? level : MAX_INDENT; @@ -293,16 +298,19 @@ static int _write_config(const struct dm_config_node *n, int only_one, space[i] = '\0'; do { - if (!_line_start(outline)) + if (out->spec && out->spec->prefix_fn) + out->spec->prefix_fn(n, space, out->baton); + + if (!_line_start(out)) return_0; line_append("%s%s", space, n->key); if (!n->v) { /* it's a sub section */ line_append(" {"); - if (!_line_end(outline)) + if (!_line_end(n, out)) return_0; - _write_config(n->child, 0, outline, level + 1); - if (!_line_start(outline)) + _write_config(n->child, 0, out, level + 1); + if (!_line_start(out)) return_0; line_append("%s}", space); } else { @@ -312,7 +320,7 @@ static int _write_config(const struct dm_config_node *n, int only_one, if (v->next) { line_append("["); while (v && v->type != DM_CFG_EMPTY_ARRAY) { - if (!_write_value(outline, v)) + if (!_write_value(out, v)) return_0; v = v->next; if (v && v->type != DM_CFG_EMPTY_ARRAY) @@ -320,11 +328,15 @@ static int _write_config(const struct dm_config_node *n, int only_one, } line_append("]"); } else - if (!_write_value(outline, v)) + if (!_write_value(out, v)) return_0; } - if (!_line_end(outline)) + if (!_line_end(n, out)) return_0; + + if (out->spec && out->spec->suffix_fn) + out->spec->suffix_fn(n, space, out->baton); + n = n->sib; } while (n && !only_one); /* FIXME: add error checking */ @@ -332,29 +344,46 @@ static int _write_config(const struct dm_config_node *n, int only_one, } static int _write_node(const struct dm_config_node *cn, int only_one, - dm_putline_fn putline, void *baton) + dm_putline_fn putline, + const struct dm_config_node_out_spec *out_spec, + void *baton) { - struct output_line outline; - if (!(outline.mem = dm_pool_create("config_line", 1024))) + struct config_output out; + if (!(out.mem = dm_pool_create("config_output", 1024))) return_0; - outline.putline = putline; - outline.putline_baton = baton; - if (!_write_config(cn, only_one, &outline, 0)) { - dm_pool_destroy(outline.mem); + out.putline = putline; + out.spec = out_spec; + out.baton = baton; + if (!_write_config(cn, only_one, &out, 0)) { + dm_pool_destroy(out.mem); return_0; } - dm_pool_destroy(outline.mem); + dm_pool_destroy(out.mem); return 1; } int dm_config_write_one_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton) { - return _write_node(cn, 1, putline, baton); + return _write_node(cn, 1, putline, NULL, baton); } int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton) { - return _write_node(cn, 0, putline, baton); + return _write_node(cn, 0, putline, NULL, baton); +} + +int dm_config_write_one_node_out(const struct dm_config_node *cn, + const struct dm_config_node_out_spec *out_spec, + void *baton) +{ + return _write_node(cn, 1, NULL, out_spec, baton); +} + +int dm_config_write_node_out(const struct dm_config_node *cn, + const struct dm_config_node_out_spec *out_spec, + void *baton) +{ + return _write_node(cn, 0, NULL, out_spec, baton); } /*