diff --git a/configs/config_test.conf.sample b/configs/config_test.conf.sample index 425b34e03a984cc8294a4adad4aedb0e178bca30..2fff45ecec95c4761d3024c1962f65e582a09c34 100644 --- a/configs/config_test.conf.sample +++ b/configs/config_test.conf.sample @@ -12,8 +12,8 @@ boolopt=true boolflag1=true boolflag2=false boolflag3=true -acldenyopt=0.0.0.0/0 -aclpermitopt=1.2.3.4/32 +deny=0.0.0.0/0 +permit=1.2.3.4/32 codecopt=!all,ulaw,g729 stropt=test customopt=yes diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h index c65e5d07a66ed51e660e42e96741655576867c58..182740e02c143ad1acffb169b168e6eab0fe89c1 100644 --- a/include/asterisk/config_options.h +++ b/include/asterisk/config_options.h @@ -496,7 +496,8 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc * \param opt_type The option type for default option type handling * \param flags \a type specific flags, stored in the option and available to the handler * - * \returns An option on success, NULL on failure + * \retval 0 Success + * \retval -1 Failure */ #define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags, ...) \ __aco_option_register(info, name, matchtype, types, default_val, opt_type, NULL, flags, VA_NARGS(__VA_ARGS__), __VA_ARGS__); @@ -509,10 +510,22 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc * \param handler The handler callback for the option * \param flags \a type specific flags, stored in the option and available to the handler * - * \returns An option on success, NULL on failure + * \retval 0 Success + * \retval -1 Failure + */ +#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags) \ + __aco_option_register(info, name, matchtype, types, default_val, OPT_CUSTOM_T, handler, flags, 0); + +/*! \brief Register a deprecated (and aliased) config option + * \param info A pointer to the aco_info struct + * \param name The name of the deprecated option + * \param types An array of valid option types for matching categories to the correct struct type + * \param aliased_to The name of the option that this deprecated option matches to + * + * \retval 0 Success + * \retval -1 Failure */ -#define aco_option_register_custom(info, name, matchtype, type, default_val, handler, flags) \ - __aco_option_register(info, name, matchtype, type, default_val, OPT_CUSTOM_T, handler, flags, 0); +int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to); /*! \note Everything below this point is to handle converting varargs * containing field names, to varargs containing a count of args, followed diff --git a/main/config_options.c b/main/config_options.c index efba8de3a578370c2e5b896df72aab1c8ca70e61..73fd6bf97bac57acb6ba8b0f4afd61d2c89e3434 100644 --- a/main/config_options.c +++ b/main/config_options.c @@ -57,13 +57,15 @@ struct aco_type_internal { struct aco_option { const char *name; + const char *aliased_to; + const char *default_val; enum aco_matchtype match_type; regex_t *name_regex; - const char *default_val; struct aco_type **obj; enum aco_option_type type; aco_option_handler handler; unsigned int flags; + unsigned char deprecated:1; size_t argc; intptr_t args[0]; }; @@ -136,11 +138,51 @@ static regex_t *build_regex(const char *text) return regex; } +static int link_option_to_types(struct aco_type **types, struct aco_option *opt) +{ + size_t idx = 0; + struct aco_type *type; + + while ((type = types[idx++])) { + if (!ao2_link(type->internal->opts, opt)) { + while (--idx) { + ao2_unlink(types[idx]->internal->opts, opt); + } + return -1; + } + } + return 0; +} + +int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to) +{ + struct aco_option *opt; + + if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) { + return -1; + } + + if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) { + return -1; + } + + opt->name = name; + opt->aliased_to = aliased_to; + opt->deprecated = 1; + opt->match_type = ACO_EXACT; + + if (link_option_to_types(types, opt)) { + ao2_ref(opt, -1); + return -1; + } + + return 0; +} + int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types, const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, size_t argc, ...) { struct aco_option *opt; - struct aco_type *type; va_list ap; int tmp; @@ -183,15 +225,9 @@ int __aco_option_register(struct aco_info *info, const char *name, enum aco_matc return -1; }; - tmp = 0; - while ((type = types[tmp++])) { - if (!ao2_link(type->internal->opts, opt)) { - while (--tmp) { - ao2_unlink(types[tmp]->internal->opts, opt); - } - ao2_ref(opt, -1); - return -1; - } + if (link_option_to_types(types, opt)) { + ao2_ref(opt, -1); + return -1; } return 0; @@ -501,10 +537,18 @@ int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, for (var = ast_variable_browse(cfg, cat); var; var = var->next) { RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup); + if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) { + const char *alias = ast_strdupa(opt->aliased_to); + ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias); + ao2_ref(opt, -1); + opt = aco_option_find(type, alias); + } + if (!opt) { ast_log(LOG_ERROR, "Could not find option suitable for category '%s' named '%s' at line %d of %s\n", cat, var->name, var->lineno, var->file); return -1; } + if (!opt->handler) { /* It should be impossible for an option to not have a handler */ ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name); diff --git a/tests/test_config.c b/tests/test_config.c index 0c28165798a921a3d73d4dbaa36b6442370c7756..8eeb9f8a9bf34c57e53d6db4ef5c121a361e1b8b 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -824,6 +824,8 @@ AST_TEST_DEFINE(config_options_test) aco_option_register(&cfg_info, "codecopt", ACO_EXACT, config_test_conf.types, CODEC_DEFAULT, OPT_CODEC_T, 1, FLDSET(struct test_item, codecprefopt, codeccapopt)); aco_option_register(&cfg_info, "stropt", ACO_EXACT, config_test_conf.types, STR_DEFAULT, OPT_STRINGFIELD_T, 0, STRFLDSET(struct test_item, stropt)); aco_option_register_custom(&cfg_info, "customopt", ACO_EXACT, config_test_conf.types, CUSTOM_DEFAULT, customopt_handler, 0); + aco_option_register_deprecated(&cfg_info, "permit", config_test_conf.types, "aclpermitopt"); + aco_option_register_deprecated(&cfg_info, "deny", config_test_conf.types, "acldenyopt"); if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) { ast_test_status_update(test, "Could not parse config\n");