Message ID | 20210831090459.2306727-6-vishal.l.verma@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Policy based reconfiguration for daxctl | expand |
> Subject: [ndctl PATCH 5/7] util/parse-configs: add a key/value search helper > > Add a new config query type called CONFIG_SEARCH_SECTION, which searches > all loaded config files based on a query criteria of: specified section name, > specified key/value pair within that section, and can return other key/values from > the section that matched the search criteria. > > This allows for multiple named subsections, where a subsection name is of the > type: '[section subsection]'. > > Cc: QI Fuli <qi.fuli@fujitsu.com> > Cc: Dan Williams <dan.j.williams@intel.com> > Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> > --- > util/parse-configs.h | 15 +++++++++++++ util/parse-configs.c | 51 > ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 66 insertions(+) > > diff --git a/util/parse-configs.h b/util/parse-configs.h index 491aebb..6dcc01c > 100644 > --- a/util/parse-configs.h > +++ b/util/parse-configs.h > @@ -9,6 +9,7 @@ > > enum parse_conf_type { > CONFIG_STRING, > + CONFIG_SEARCH_SECTION, > CONFIG_END, > MONITOR_CALLBACK, > }; > @@ -20,6 +21,10 @@ typedef int parse_conf_cb(const struct config *, const char > *config_file); > > struct config { > enum parse_conf_type type; > + const char *section; > + const char *search_key; > + const char *search_val; > + const char *get_key; > const char *key; > void *value; > void *defval; > @@ -31,6 +36,16 @@ struct config { > #define CONF_END() { .type = CONFIG_END } #define CONF_STR(k,v,d) \ > { .type = CONFIG_STRING, .key = (k), .value = check_vtype(v, const char > **), .defval = (d) } > +#define CONF_SEARCH(s, sk, sv, gk, v, d) \ > +{ \ > + .type = CONFIG_SEARCH_SECTION, \ > + .section = (s), \ > + .search_key = (sk), \ > + .search_val = (sv), \ > + .get_key = (gk), \ > + .value = check_vtype(v, const char **), \ > + .defval = (d) \ > +} > #define CONF_MONITOR(k,f) \ > { .type = MONITOR_CALLBACK, .key = (k), .callback = (f)} > > diff --git a/util/parse-configs.c b/util/parse-configs.c index 72c4913..8eabe3d > 100644 > --- a/util/parse-configs.c > +++ b/util/parse-configs.c > @@ -38,6 +38,54 @@ static void set_str_val(const char **value, const char *val) > *value = strbuf_detach(&buf, NULL); > } > > +static const char *search_section_kv(dictionary *d, const struct config > +*c) { > + int i; > + > + for (i = 0; i < iniparser_getnsec(d); i++) { > + const char *cur_sec_full = iniparser_getsecname(d, i); > + char *cur_sec = strdup(cur_sec_full); > + const char *search_val, *ret_val; > + const char *delim = " \t\n\r"; > + char *save, *cur, *query; > + > + if (!cur_sec) > + return NULL; > + if (!c->section || !c->search_key || !c->search_val > || !c->get_key) { > + fprintf(stderr, "warning: malformed config query, > skipping\n"); > + return NULL; > + } > + > + cur = strtok_r(cur_sec, delim, &save); > + if ((cur == NULL) || (strcmp(cur, c->section) != 0)) > + goto out_sec; > + > + if (asprintf(&query, "%s:%s", cur_sec_full, c->search_key) < 0) > + goto out_sec; > + search_val = iniparser_getstring(d, query, NULL); > + if (!search_val) > + goto out_query; > + if (strcmp(search_val, c->search_val) != 0) > + goto out_query; > + > + /* we're now in a matching section */ > + free(query); > + if (asprintf(&query, "%s:%s", cur_sec_full, c->get_key) < 0) > + goto out_sec; > + ret_val = iniparser_getstring(d, query, NULL); > + free(query); > + free(cur_sec); > + return ret_val; > + > +out_query: > + free(query); > +out_sec: > + free(cur_sec); > + } > + > + return NULL; > +} > + > static int parse_config_file(const char *config_file, > const struct config *configs) > { > @@ -54,6 +102,9 @@ static int parse_config_file(const char *config_file, > iniparser_getstring(dic, > configs->key, configs->defval)); > break; > + case CONFIG_SEARCH_SECTION: > + set_str_val((const char **)configs->value, > + search_section_kv(dic, configs)); > case MONITOR_CALLBACK: > case CONFIG_END: > break; > -- > 2.31.1 Thank you very much. This looks good to me. QI
On Tue, Aug 31, 2021 at 2:05 AM Vishal Verma <vishal.l.verma@intel.com> wrote: > > Add a new config query type called CONFIG_SEARCH_SECTION, which searches > all loaded config files based on a query criteria of: specified section > name, specified key/value pair within that section, and can return other > key/values from the section that matched the search criteria. > > This allows for multiple named subsections, where a subsection name is > of the type: '[section subsection]'. Presumably in the future this could be used to search by subsection as well, but for now daxctl does not need that and the subsection is essentially a comment? Perhaps that should be called out in a sample / comment only daxctl.conf file that gets installed by default. Where it clarifies that everything after the first whitespace in a section name is treated as a subsection. This looks good to me.
On Thu, 2021-09-16 at 16:54 -0700, Dan Williams wrote: > On Tue, Aug 31, 2021 at 2:05 AM Vishal Verma <vishal.l.verma@intel.com> wrote: > > > > Add a new config query type called CONFIG_SEARCH_SECTION, which searches > > all loaded config files based on a query criteria of: specified section > > name, specified key/value pair within that section, and can return other > > key/values from the section that matched the search criteria. > > > > This allows for multiple named subsections, where a subsection name is > > of the type: '[section subsection]'. > > Presumably in the future this could be used to search by subsection as > well, but for now daxctl does not need that and the subsection is > essentially a comment? Correct. > > Perhaps that should be called out in a sample / comment only > daxctl.conf file that gets installed by default. Where it clarifies > that everything after the first whitespace in a section name is > treated as a subsection. Hm the man page does say: Note that the 'subsection name' can be arbitrary, and is only used to identify a specific config section. It does not have to match the 'device name' (e.g. 'dax0.0' etc). I didn't include a sample/comment-only config file - I figured the man page snippets should be sufficient for anyone who wants to write one - but I can add something if it's useful. > > This looks good to me.
diff --git a/util/parse-configs.h b/util/parse-configs.h index 491aebb..6dcc01c 100644 --- a/util/parse-configs.h +++ b/util/parse-configs.h @@ -9,6 +9,7 @@ enum parse_conf_type { CONFIG_STRING, + CONFIG_SEARCH_SECTION, CONFIG_END, MONITOR_CALLBACK, }; @@ -20,6 +21,10 @@ typedef int parse_conf_cb(const struct config *, const char *config_file); struct config { enum parse_conf_type type; + const char *section; + const char *search_key; + const char *search_val; + const char *get_key; const char *key; void *value; void *defval; @@ -31,6 +36,16 @@ struct config { #define CONF_END() { .type = CONFIG_END } #define CONF_STR(k,v,d) \ { .type = CONFIG_STRING, .key = (k), .value = check_vtype(v, const char **), .defval = (d) } +#define CONF_SEARCH(s, sk, sv, gk, v, d) \ +{ \ + .type = CONFIG_SEARCH_SECTION, \ + .section = (s), \ + .search_key = (sk), \ + .search_val = (sv), \ + .get_key = (gk), \ + .value = check_vtype(v, const char **), \ + .defval = (d) \ +} #define CONF_MONITOR(k,f) \ { .type = MONITOR_CALLBACK, .key = (k), .callback = (f)} diff --git a/util/parse-configs.c b/util/parse-configs.c index 72c4913..8eabe3d 100644 --- a/util/parse-configs.c +++ b/util/parse-configs.c @@ -38,6 +38,54 @@ static void set_str_val(const char **value, const char *val) *value = strbuf_detach(&buf, NULL); } +static const char *search_section_kv(dictionary *d, const struct config *c) +{ + int i; + + for (i = 0; i < iniparser_getnsec(d); i++) { + const char *cur_sec_full = iniparser_getsecname(d, i); + char *cur_sec = strdup(cur_sec_full); + const char *search_val, *ret_val; + const char *delim = " \t\n\r"; + char *save, *cur, *query; + + if (!cur_sec) + return NULL; + if (!c->section || !c->search_key || !c->search_val || !c->get_key) { + fprintf(stderr, "warning: malformed config query, skipping\n"); + return NULL; + } + + cur = strtok_r(cur_sec, delim, &save); + if ((cur == NULL) || (strcmp(cur, c->section) != 0)) + goto out_sec; + + if (asprintf(&query, "%s:%s", cur_sec_full, c->search_key) < 0) + goto out_sec; + search_val = iniparser_getstring(d, query, NULL); + if (!search_val) + goto out_query; + if (strcmp(search_val, c->search_val) != 0) + goto out_query; + + /* we're now in a matching section */ + free(query); + if (asprintf(&query, "%s:%s", cur_sec_full, c->get_key) < 0) + goto out_sec; + ret_val = iniparser_getstring(d, query, NULL); + free(query); + free(cur_sec); + return ret_val; + +out_query: + free(query); +out_sec: + free(cur_sec); + } + + return NULL; +} + static int parse_config_file(const char *config_file, const struct config *configs) { @@ -54,6 +102,9 @@ static int parse_config_file(const char *config_file, iniparser_getstring(dic, configs->key, configs->defval)); break; + case CONFIG_SEARCH_SECTION: + set_str_val((const char **)configs->value, + search_section_kv(dic, configs)); case MONITOR_CALLBACK: case CONFIG_END: break;
Add a new config query type called CONFIG_SEARCH_SECTION, which searches all loaded config files based on a query criteria of: specified section name, specified key/value pair within that section, and can return other key/values from the section that matched the search criteria. This allows for multiple named subsections, where a subsection name is of the type: '[section subsection]'. Cc: QI Fuli <qi.fuli@fujitsu.com> Cc: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> --- util/parse-configs.h | 15 +++++++++++++ util/parse-configs.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+)