Commit 42349687 authored by Michał Kępień's avatar Michał Kępień Committed by Evan Hunt
Browse files

add a function for processing a list of configured plugins

Add a new libisccfg function, cfg_pluginlist_foreach(), which allows an
arbitrary callback to be invoked for every "plugin" stanza present in a
configuration object.  Use this function for both loading plugins and
checking their configuration in order to reduce duplication of
configuration processing code present in bin/named/server.c and
lib/bind9/check.c.
parent fd20f10d
......@@ -1535,45 +1535,6 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
name, isc_result_totext(result));
return (result);
}
static isc_result_t
configure_plugin(dns_view_t *view, const cfg_obj_t *plugin,
const cfg_obj_t *config)
{
isc_result_t result = ISC_R_SUCCESS;
const cfg_obj_t *obj;
const char *type, *library;
const char *parameters = NULL;
/* Get the path to the plugin module. */
obj = cfg_tuple_get(plugin, "type");
type = cfg_obj_asstring(obj);
/* Only query plugins are supported currently. */
if (strcasecmp(type, "query") != 0) {
cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
"unsupported plugin type");
return (ISC_R_FAILURE);
}
library = cfg_obj_asstring(cfg_tuple_get(plugin, "library"));
obj = cfg_tuple_get(plugin, "parameters");
if (obj != NULL && cfg_obj_isstring(obj)) {
parameters = cfg_obj_asstring(obj);
}
result = ns_plugin_register(library, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
named_g_mctx, named_g_lctx,
named_g_aclconfctx, view);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"%s: module configuration failed: %s",
library, isc_result_totext(result));
}
return (result);
}
#endif
......@@ -3686,6 +3647,35 @@ create_mapped_acl(void) {
return (result);
}
#ifdef HAVE_DLOPEN
/*%
* A callback for the cfg_pluginlist_foreach() call in configure_view() below.
* If registering any plugin fails, registering subsequent ones is not
* attempted.
*/
static isc_result_t
register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data)
{
dns_view_t *view = callback_data;
isc_result_t result;
result = ns_plugin_register(plugin_path, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
named_g_mctx, named_g_lctx,
named_g_aclconfctx, view);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"%s: plugin configuration failed: %s",
plugin_path, isc_result_totext(result));
}
return (result);
}
#endif
/*
* Configure 'view' according to 'vconfig', taking defaults from 'config'
* where values are missing in 'vconfig'.
......@@ -5314,15 +5304,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
view->plugins_free = ns_plugins_free;
}
for (element = cfg_list_first(plugin_list);
element != NULL;
element = cfg_list_next(element))
{
const cfg_obj_t *plugin = cfg_listelt_value(element);
CHECK(configure_plugin(view, plugin, config));
CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
register_one_plugin, view));
}
#endif
......
......@@ -3348,6 +3348,46 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj,
return (result);
}
#ifdef HAVE_DLOPEN
/*%
* Data structure used for the 'callback_data' argument to check_one_plugin().
*/
struct check_one_plugin_data {
isc_mem_t *mctx;
isc_log_t *lctx;
cfg_aclconfctx_t *actx;
isc_result_t *check_result;
};
/*%
* A callback for the cfg_pluginlist_foreach() call in check_viewconf() below.
* Since the point is to check configuration of all plugins even when
* processing some of them fails, always return ISC_R_SUCCESS and indicate any
* check failures through the 'check_result' variable passed in via the
* 'callback_data' structure.
*/
static isc_result_t
check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data)
{
struct check_one_plugin_data *data = callback_data;
isc_result_t result;
result = ns_plugin_check(plugin_path, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
data->mctx, data->lctx, data->actx);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR,
"%s: plugin check failed: %s",
plugin_path, isc_result_totext(result));
*data->check_result = result;
}
return (ISC_R_SUCCESS);
}
#endif
static isc_result_t
check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
const char *viewname, dns_rdataclass_t vclass,
......@@ -3677,39 +3717,18 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
}
#ifdef HAVE_DLOPEN
for (element = cfg_list_first(plugin_list);
element != NULL;
element = cfg_list_next(element))
{
const cfg_obj_t *plugin = cfg_listelt_value(element);
const char *type, *library;
const char *parameters = NULL;
/* Get the path to the plugin module. */
obj = cfg_tuple_get(plugin, "type");
type = cfg_obj_asstring(obj);
/* Only query plugins are supported currently. */
if (strcasecmp(type, "query") != 0) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"unsupported plugin type");
return (ISC_R_FAILURE);
}
library = cfg_obj_asstring(cfg_tuple_get(plugin, "library"));
obj = cfg_tuple_get(plugin, "parameters");
if (obj != NULL && cfg_obj_isstring(obj)) {
parameters = cfg_obj_asstring(obj);
}
tresult = ns_plugin_check(library, parameters, config,
cfg_obj_file(obj), cfg_obj_line(obj),
mctx, logctx, actx);
struct check_one_plugin_data check_one_plugin_data = {
.mctx = mctx,
.lctx = logctx,
.actx = actx,
.check_result = &tresult,
};
(void)cfg_pluginlist_foreach(config, plugin_list, logctx,
check_one_plugin,
&check_one_plugin_data);
if (tresult != ISC_R_SUCCESS) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"%s: module check failed: %s",
library, isc_result_totext(tresult));
result = tresult;
}
}
......
......@@ -555,6 +555,47 @@ const char *
cfg_map_nextclause(const cfg_type_t *map, const void **clauses,
unsigned int *idx);
typedef isc_result_t
(pluginlist_cb_t)(const cfg_obj_t *config, const cfg_obj_t *obj,
const char *plugin_path, const char *parameters,
void *callback_data);
/*%<
* Function prototype for the callback used with cfg_pluginlist_foreach().
* Called once for each element of the list passed to cfg_pluginlist_foreach().
* If this callback returns anything else than #ISC_R_SUCCESS, no further list
* elements will be processed.
*
* \li 'config' - the 'config' object passed to cfg_pluginlist_foreach()
* \li 'obj' - object representing the specific "plugin" stanza to be processed
* \li 'plugin_path' - path to the shared object with plugin code
* \li 'parameters' - configuration text for the plugin
* \li 'callback_data' - the pointer passed to cfg_pluginlist_foreach()
*/
isc_result_t
cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
isc_log_t *lctx, pluginlist_cb_t callback,
void *callback_data);
/*%<
* For every "plugin" stanza present in 'list' (which in turn is a part of
* 'config'), invoke the given 'callback', passing 'callback_data' to it along
* with a fixed set of arguments (see the definition of the #pluginlist_cb_t
* type). Use logging context 'lctx' for logging error messages. Interrupt
* processing if 'callback' returns something else than #ISC_R_SUCCESS for any
* element of 'list'.
*
* Requires:
*
* \li 'config' is not NULL
* \li 'callback' is not NULL
*
* Returns:
*
* \li #ISC_R_SUCCESS if 'callback' returned #ISC_R_SUCCESS for all elements of
* 'list'
* \li first 'callback' return value which was not #ISC_R_SUCCESS otherwise
*/
ISC_LANG_ENDDECLS
#endif /* ISCCFG_CFG_H */
......@@ -3457,3 +3457,51 @@ cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj,
return (result);
}
isc_result_t
cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list,
isc_log_t *lctx, pluginlist_cb_t *callback,
void *callback_data)
{
isc_result_t result = ISC_R_SUCCESS;
const cfg_listelt_t *element;
REQUIRE(config != NULL);
REQUIRE(callback != NULL);
for (element = cfg_list_first(list);
element != NULL;
element = cfg_list_next(element))
{
const cfg_obj_t *plugin = cfg_listelt_value(element);
const cfg_obj_t *obj;
const char *type, *library;
const char *parameters = NULL;
/* Get the path to the plugin module. */
obj = cfg_tuple_get(plugin, "type");
type = cfg_obj_asstring(obj);
/* Only query plugins are supported currently. */
if (strcasecmp(type, "query") != 0) {
cfg_obj_log(obj, lctx, ISC_LOG_ERROR,
"unsupported plugin type");
return (ISC_R_FAILURE);
}
library = cfg_obj_asstring(cfg_tuple_get(plugin, "library"));
obj = cfg_tuple_get(plugin, "parameters");
if (obj != NULL && cfg_obj_isstring(obj)) {
parameters = cfg_obj_asstring(obj);
}
result = callback(config, obj, library, parameters,
callback_data);
if (result != ISC_R_SUCCESS) {
break;
}
}
return (result);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment