]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add a function for processing a list of configured plugins
authorMichał Kępień <michal@isc.org>
Mon, 3 Dec 2018 14:30:02 +0000 (15:30 +0100)
committerEvan Hunt <each@isc.org>
Thu, 6 Dec 2018 18:36:50 +0000 (10:36 -0800)
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.

bin/named/server.c
lib/bind9/check.c
lib/isccfg/include/isccfg/cfg.h
lib/isccfg/parser.c

index 19f67aeec553392cf493bf094f964631b60e7af5..b44fd1e2810ec325bcee2f013df23b12b44a3c72 100644 (file)
@@ -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
 
index ada1e257dbdb7ab96653f45ac93bed3b8803c06b..e07c3d0d0c5564ca11fafb6989d901479f79288a 100644 (file)
@@ -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;
                }
        }
index 8f8ca55e439ab20fbe1f0fecbd26ed61c6f8c59a..03d340bd81b7064b40d53e043666b34af83fee61 100644 (file)
@@ -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 */
index eea80b2789a8919d78579c75cf51c19d2f6d4362..07341bf725fee5f4c05994ffe1aa61075be315d6 100644 (file)
@@ -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);
+}