diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c index e6218d65f..df393caa2 100644 --- a/lib/format_text/import_vsn1.c +++ b/lib/format_text/import_vsn1.c @@ -547,6 +547,96 @@ int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, return 1; } +/* Ensure config_value has matching type before copy */ +static int _copy_config_value(const struct dm_config_node *cn, + const struct config_value *cv) +{ + const char *err = "list"; + + if (cn->v) { + switch (cv->type) { + case CONFIG_VALUE_STRING: + if (cn->v->type != DM_CFG_STRING) { + err = "string"; + break; + } + *(const char**)(cv->result) = cn->v->v.str; + return 1; + case CONFIG_VALUE_UINT64: + if (cn->v->type != DM_CFG_INT) { + err = "number"; + break; + } + *(uint64_t*)(cv->result) = (uint64_t)cn->v->v.i; + return 1; + case CONFIG_VALUE_UINT32: + if (cn->v->type != DM_CFG_INT) { + err = "number"; + break; + } + *(uint32_t*)(cv->result) = (uint32_t)cn->v->v.i; + return 1; + case CONFIG_VALUE_LIST: + *(struct dm_config_value**)(cv->result) = cn->v; + return 1; + } + } + + if (cv->mandatory) { + /* For mandatory value mismatching type fails parsing. */ + log_error("Value for %s is not a %s.", cv->name, err); + return 0; + } + + /* For non-mandatory value warn user and continue with parsing. */ + log_warn("WARNING: Ignoring non %s value for %s.", err, cv->name); + + return -1; +} + +static int _compare_config_values_s(const void *a, const void *b) +{ + return strcmp(((const struct config_value*)a)->name, + ((const struct config_value*)b)->name); +} + +/* + * Read set of values out of config tree nodes + * + * config_values are expected to be in Alphabetic order for use with bsearch!! + */ +int text_import_values(const struct dm_config_node *cn, + struct config_value *values, size_t values_count) +{ + struct config_value *found; + struct config_value findme; + unsigned i; + int ret = 1; + + while (cn) { + findme.name = cn->key; + + if ((found = bsearch(&findme, values, values_count, + sizeof(*found), + _compare_config_values_s))) { + if (!_copy_config_value(cn, found)) + return_0; + + --(found->mandatory); + } + + cn = cn->sib; + } + + for (i = 0 ; i < values_count; ++i) + if (values[i].mandatory > 0) { + log_error("Required option %s is missing!", values[i].name); + ret = 0; + } + + return ret; +} + static int _read_segments(struct cmd_context *cmd, struct format_type *fmt, struct format_instance *fid, diff --git a/lib/format_text/text_import.h b/lib/format_text/text_import.h index 643751b65..7697c6260 100644 --- a/lib/format_text/text_import.h +++ b/lib/format_text/text_import.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. - * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * Copyright (C) 2004-2024 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * @@ -25,4 +25,29 @@ struct dm_config_node; int text_import_areas(struct lv_segment *seg, const struct dm_config_node *sn, const struct dm_config_value *cv, uint64_t status); +typedef enum { + CONFIG_VALUE_STRING, /* const char * */ + CONFIG_VALUE_UINT64, /* uint64_t * */ + CONFIG_VALUE_UINT32, /* uint32_t * */ + CONFIG_VALUE_LIST, /* struct dm_config_value * */ +} config_value_t; + +struct config_value { + const char *name; /* config value name/path to look for */ + void *result; /* where to store resulting value of expected type */ + config_value_t type; /* expected value type */ + int mandatory; /* fail import if this value is missing in config node */ +}; + +/* + * Parses config values out of config node out of sorted array like this + * + * struct config_value values[] = { + * { "value1", &uint_value1, CONFIG_VALUE_UINT32, 1 }, + * { "value2", &list_value2, CONFIG_VALUE_LIST, }, + * }; + */ +int text_import_values(const struct dm_config_node *cn, + struct config_value *values, size_t values_count); + #endif