diff mbox series

[ndctl,5/7] util/parse-configs: add a key/value search helper

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

Commit Message

Verma, Vishal L Aug. 31, 2021, 9:04 a.m. UTC
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(+)

Comments

qi.fuli@fujitsu.com Sept. 2, 2021, 1:12 p.m. UTC | #1
> 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
Dan Williams Sept. 16, 2021, 11:54 p.m. UTC | #2
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.
Verma, Vishal L Nov. 17, 2021, 11:21 p.m. UTC | #3
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 mbox series

Patch

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;