diff --git a/include/maxscale/config.h b/include/maxscale/config.h index 855019036..928cbe619 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -33,6 +33,7 @@ #include #include #include +#include MXS_BEGIN_DECLS @@ -211,6 +212,64 @@ bool config_is_ssl_parameter(const char *key); */ SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *error_count); +/** + * @brief Check if a configuration parameter is valid + * + * If a module has declared parameters and parameters were given to the module, + * the given parameters are compared to the expected ones. This function also + * does preliminary type checking for various basic values as well as enumerations. + * + * @param module Module name + * @param key Parameter key + * @param value Parameter value + * + * @return True if the configuration parameter is valid + */ +bool config_param_is_valid(const char *module, const char *key, const char *value); + +/** + * @brief Get a boolean value + * + * @param params List of configuration parameters + * @param key Parameter name + * + * @return The value as a boolean + */ +bool config_get_bool(const CONFIG_PARAMETER *params, const char *key); + +/** + * @brief Get an integer value + * + * This is used for both MXS_MODULE_PARAM_INT and MXS_MODULE_PARAM_COUNT. + * + * @param params List of configuration parameters + * @param key Parameter name + * + * @return The integer value of the parameter + */ +int config_get_integer(const CONFIG_PARAMETER *params, const char *key); + +/** + * @brief Get a string value + * + * @param params List of configuration parameters + * @param key Parameter name + * + * @return The raw string value */ +const char* config_get_string(const CONFIG_PARAMETER *params, const char *key); + +/** + * @brief Get a enumeration value + * + * @param params List of configuration parameters + * @param key Parameter name + * + * @return The raw string value + * + * TODO: Allow multiple enumeration values + */ +const char* config_get_enum(const CONFIG_PARAMETER *params, const char *key); + char* config_clean_string_list(const char* str); CONFIG_PARAMETER* config_clone_param(const CONFIG_PARAMETER* param); void config_enable_feedback_task(void); diff --git a/include/maxscale/modinfo.h b/include/maxscale/modinfo.h index b21135a8c..62ced988a 100644 --- a/include/maxscale/modinfo.h +++ b/include/maxscale/modinfo.h @@ -76,6 +76,24 @@ typedef struct int patch; } MXS_MODULE_VERSION; +enum mxs_module_param_type +{ + MXS_MODULE_PARAM_COUNT, /**< Non-negative number */ + MXS_MODULE_PARAM_INT, /**< Integer number */ + MXS_MODULE_PARAM_BOOL, /**< Boolean value */ + MXS_MODULE_PARAM_STRING, /**< String value */ + MXS_MODULE_PARAM_ENUM /**< Enumeration of string values */ +}; + +/** Module parameter declaration */ +typedef struct mxs_module_param +{ + const char *name; /**< Name of the parameter */ + enum mxs_module_param_type type; /**< Type of the parameter */ + const char *default_value; + const char **accepted_values; /**< Only for enum values */ +} MXS_MODULE_PARAM; + /** * The module information structure */ @@ -87,8 +105,15 @@ typedef struct const char *description; /**< Module description */ const char *version; /**< Module version */ void *module_object; /**< Module type specific API implementation */ + MXS_MODULE_PARAM parameters[]; /**< Declared parameters */ } MXS_MODULE; +/** + * This should be the last value given to @c parameters. If the module has no + * parameters, it should be the only value. + */ +#define MXS_END_MODULE_PARAMS .name = NULL + /** * Name of the module entry point * diff --git a/server/core/config.c b/server/core/config.c index 9db93bbcc..69dab32b3 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -83,7 +83,7 @@ static bool process_config_context(CONFIG_CONTEXT *); static bool process_config_update(CONFIG_CONTEXT *); static char *config_get_value(CONFIG_PARAMETER *, const char *); static char *config_get_password(CONFIG_PARAMETER *); -static const char *config_get_value_string(CONFIG_PARAMETER *, const char *); +static const char* config_get_value_string(const CONFIG_PARAMETER *params, const char *name); static int handle_global_item(const char *, const char *); static int handle_feedback_item(const char *, const char *); static void global_defaults(); @@ -916,8 +916,7 @@ config_get_password(CONFIG_PARAMETER *params) * @param name The parameter to return * @return the parameter value or null string if not found */ -static const char * -config_get_value_string(CONFIG_PARAMETER *params, const char *name) +static const char* config_get_value_string(const CONFIG_PARAMETER *params, const char *name) { while (params) { @@ -1055,6 +1054,34 @@ return_succp: return succp; } +bool config_get_bool(const CONFIG_PARAMETER *params, const char *key) +{ + const char *value = config_get_value_string(params, key); + ss_dassert(*value); + return config_truth_value(value); +} + +int config_get_integer(const CONFIG_PARAMETER *params, const char *key) +{ + const char *value = config_get_value_string(params, key); + ss_dassert(*value); + return strtol(value, NULL, 10); +} + +const char* config_get_string(const CONFIG_PARAMETER *params, const char *key) +{ + const char *value = config_get_value_string(params, key); + ss_dassert(*value); + return value; +} + +const char* config_get_enum(const CONFIG_PARAMETER *params, const char *key) +{ + const char *value = config_get_value_string(params, key); + ss_dassert(*value); + return value; +} + CONFIG_PARAMETER* config_clone_param(const CONFIG_PARAMETER* param) { CONFIG_PARAMETER* p2; @@ -3268,3 +3295,73 @@ bool config_is_ssl_parameter(const char *key) return false; } + +bool config_param_is_valid(const char *module, const char *key, const char *value) +{ + bool valid = false; + const MXS_MODULE *mod = get_module(module); + + if (mod) + { + for (int i = 0; mod->parameters[i].name && !valid; i++) + { + if (strcmp(mod->parameters[i].name, key) == 0) + { + char *endptr; + + switch (mod->parameters[i].type) + { + case MXS_MODULE_PARAM_COUNT: + if ((strtol(value, &endptr, 10)) >= 0 && endptr != value && *endptr == '\0') + { + valid = true; + } + break; + + case MXS_MODULE_PARAM_INT: + strtol(value, &endptr, 10); + if (endptr != value && *endptr == '\0') + { + valid = true; + } + break; + + case MXS_MODULE_PARAM_BOOL: + if (config_truth_value(value) != -1) + { + valid = true; + } + break; + + case MXS_MODULE_PARAM_STRING: + if (*value) + { + valid = true; + } + break; + + case MXS_MODULE_PARAM_ENUM: + if (mod->parameters[i].accepted_values) + { + for (int j = 0; mod->parameters[i].accepted_values[j]; j++) + { + if (strcmp(mod->parameters[i].accepted_values[j], value) == 0) + { + valid = true; + break; + } + } + } + break; + + default: + MXS_ERROR("Unexpected module parameter type: %d", mod->parameters[i].type); + ss_dassert(false); + break; + } + } + } + } + + return valid; +}