diff --git a/Makefile.in b/Makefile.in index 69416a14..c7833265 100644 --- a/Makefile.in +++ b/Makefile.in @@ -138,9 +138,9 @@ configure: configure.ac cd $(srcdir) && autoconf clean: - rm -f *.gcov for i in $(SUBDIRS) doc example util docker; \ do (cd $$i && $(MAKE) $(MFLAGS) $@); done; + rm -f *.gcov test/*.gcov # Uninstall and clean all the targets used for testing, but without cloning or # checking-out from git. Provides a reliabily clean slate for testing changes diff --git a/apps/backend/Makefile.in b/apps/backend/Makefile.in index be2a7d15..66c70d10 100644 --- a/apps/backend/Makefile.in +++ b/apps/backend/Makefile.in @@ -46,7 +46,9 @@ endif SH_SUFFIX = @SH_SUFFIX@ INSTALLFLAGS = @INSTALLFLAGS@ LDFLAGS = @LDFLAGS@ - +ifeq ($(LINKAGE),static) +LDFLAGS += -rdynamic -L. +endif prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ @@ -63,7 +65,7 @@ CLIXON_MINOR = @CLIXON_VERSION_MINOR@ # Use this clixon lib for linking ifeq ($(LINKAGE),static) - CLIXON_LIB = libclixon$(SH_SUFFIX) + CLIXON_LIB = libclixon.a else CLIXON_LIB = libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR) endif @@ -113,6 +115,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f *.core $(APPL) $(APPOBJ) $(LIBOBJ) $(MYLIB) $(MYLIBSO) $(MYLIBLINK) test test.c + rm -f *.gcda *.gcno *.gcov # coverage distclean: clean rm -f Makefile *~ .depend @@ -130,8 +133,8 @@ install-lib: $(MYLIB) install -m 0644 $(INSTALLFLAGS) $(MYLIB) $(DESTDIR)$(libdir) install -d -m 0755 $(DESTDIR)$(libdir)/clixon/plugins/backend ifeq ($(LINKAGE),dynamic) - ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclixon_config.so.2 - ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon_config.so + ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclixon_backend.so.2 + ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon_backend.so endif uninstall: @@ -147,7 +150,7 @@ install-include: clixon_backend.h clixon_backend_handle.h clixon_backend_transac .SUFFIXES: .c .o .c.o: - $(CC) $(INCLUDES) -D__PROGRAM__=\"$(APPL)\" $(CPPFLAGS) $(CFLAGS) -c $< + $(CC) $(INCLUDES) $(CPPFLAGS) -D__PROGRAM__=\"$(APPL)\" $(CFLAGS) -c $< # Just link test programs test.c : @@ -157,7 +160,11 @@ test: test.c $(LIBOBJ) $(MYLIB) $(CC) $(INCLUDES) $(LDFLAGS) $< $(LIBOBJ) -L. $(MYLIB) $(LIBS) -o $@ $(APPL) : $(APPOBJ) $(MYLIB) $(LIBDEPS) +ifeq ($(LINKAGE),dynamic) $(CC) $(LDFLAGS) $(APPOBJ) -L. $(MYLIB) $(LIBS) -o $@ +else + $(CC) $(LDFLAGS) $(APPOBJ) -L. $(LIBOBJ) $(LIBS) -o $@ +endif $(MYLIBDYNAMIC): $(LIBOBJ) $(LIBDEPS) ifeq ($(HOST_VENDOR),apple) diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 0335a009..7d0a1c91 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -1547,7 +1547,7 @@ from_client_restart_plugin(clicon_handle h, cxobj **vec = NULL; size_t veclen; int i; - clixon_plugin *cp; + clixon_plugin_t *cp; int ret; if (xpath_vec(xe, NULL, "plugin", &vec, &veclen) < 0) diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 61e58a08..8d06de86 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -878,7 +878,7 @@ from_client_validate(clicon_handle h, */ int from_client_restart_one(clicon_handle h, - clixon_plugin *cp, + clixon_plugin_t *cp, cbuf *cbret) { int retval = -1; @@ -895,7 +895,7 @@ from_client_restart_one(clicon_handle h, if (xmldb_db_reset(h, db) < 0) goto done; /* Application may define extra xml in its reset function*/ - if ((resetfn = cp->cp_api.ca_reset) != NULL){ + if ((resetfn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ if ((retval = resetfn(h, db)) < 0) { clicon_debug(1, "plugin_start() failed"); goto done; diff --git a/apps/backend/backend_commit.h b/apps/backend/backend_commit.h index 6c53505e..0c98da80 100644 --- a/apps/backend/backend_commit.h +++ b/apps/backend/backend_commit.h @@ -50,6 +50,6 @@ int from_client_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void int from_client_discard_changes(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); int from_client_cancel_commit(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); int from_client_validate(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg, void *regarg); -int from_client_restart_one(clicon_handle h, clixon_plugin *cp, cbuf *cbret); +int from_client_restart_one(clicon_handle h, clixon_plugin_t *cp, cbuf *cbret); #endif /* _BACKEND_COMMIT_H_ */ diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 2510db17..f0309132 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -125,11 +125,8 @@ backend_terminate(clicon_handle h) if ((x = clicon_conf_xml(h)) != NULL) xml_free(x); stream_publish_exit(); - clixon_plugin_exit_all(h); - /* Delete all backend plugin RPC callbacks */ - rpc_callback_delete_all(h); - /* Delete all backend plugin upgrade callbacks */ - upgrade_callback_delete_all(h); + /* Delete all plugins, RPC callbacks, and upgrade callbacks */ + clixon_plugin_module_exit(h); /* Delete all process-control entries */ clixon_process_delete_all(h); @@ -517,7 +514,6 @@ main(int argc, /* Initiate CLICON handle */ if ((h = backend_handle_init()) == NULL) return -1; - foreground = 0; once = 0; zap = 0; @@ -582,12 +578,10 @@ main(int argc, clicon_option_str_set(h, "CLICON_WWWUSER", WWWUSER); clicon_option_str_set(h, "CLICON_WWWDIR", WWWDIR); - /* External NACM file? */ - nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); - if (nacm_mode && strcmp(nacm_mode, "external") == 0) - if (nacm_load_external(h) < 0) - goto done; - + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; + /* Now run through the operational args */ opterr = 1; optind = 1; @@ -780,6 +774,14 @@ main(int argc, if (netconf_module_features(h) < 0) goto done; + /* External NACM file? + * Note, loads yang -> extensions -> plugins + */ + nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); + if (nacm_mode && strcmp(nacm_mode, "external") == 0) + if (nacm_load_external(h) < 0) + goto done; + /* Create top-level yang spec and store as option */ if ((yspec = yspec_new()) == NULL) goto done; diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 2f75fcdd..83824eae 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -74,18 +74,18 @@ * @retval -1 Error */ int -clixon_plugin_reset_one(clixon_plugin *cp, +clixon_plugin_reset_one(clixon_plugin_t *cp, clicon_handle h, char *db) { int retval = -1; plgreset_t *fn; /* callback */ - if ((fn = cp->cp_api.ca_reset) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ if (fn(h, db) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -106,7 +106,7 @@ clixon_plugin_reset_all(clicon_handle h, char *db) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { @@ -125,18 +125,18 @@ clixon_plugin_reset_all(clicon_handle h, * @retval -1 Error */ static int -clixon_plugin_pre_daemon_one(clixon_plugin *cp, +clixon_plugin_pre_daemon_one(clixon_plugin_t *cp, clicon_handle h) { int retval = -1; plgdaemon_t *fn; /* Daemonize plugin callback function */ - if ((fn = cp->cp_api.ca_pre_daemon) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_pre_daemon) != NULL){ if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Pre-daemon callback in plugin:\ %s returned -1 but did not make a clicon_err call", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -158,7 +158,7 @@ int clixon_plugin_pre_daemon_all(clicon_handle h) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { @@ -177,17 +177,17 @@ clixon_plugin_pre_daemon_all(clicon_handle h) * @retval -1 Error */ static int -clixon_plugin_daemon_one(clixon_plugin *cp, +clixon_plugin_daemon_one(clixon_plugin_t *cp, clicon_handle h) { int retval = -1; plgdaemon_t *fn; /* Daemonize plugin callback function */ - if ((fn = cp->cp_api.ca_daemon) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){ if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -211,7 +211,7 @@ int clixon_plugin_daemon_all(clicon_handle h) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { @@ -244,7 +244,7 @@ clixon_plugin_daemon_all(clicon_handle h) * @retval 1 OK if callback found (and called) xret is set */ static int -clixon_plugin_statedata_one(clixon_plugin *cp, +clixon_plugin_statedata_one(clixon_plugin_t *cp, clicon_handle h, cvec *nsc, char *xpath, @@ -254,13 +254,13 @@ clixon_plugin_statedata_one(clixon_plugin *cp, plgstatedata_t *fn; /* Plugin statedata fn */ cxobj *x = NULL; - if ((fn = cp->cp_api.ca_statedata) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){ if ((x = xml_new(XML_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; if (fn(h, nsc, xpath, x) < 0){ if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto fail; /* Dont quit here on user callbacks */ } @@ -298,7 +298,7 @@ clixon_plugin_statedata_all(clicon_handle h, int retval = -1; int ret; cxobj *x = NULL; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; cbuf *cberr = NULL; cxobj *xerr = NULL; @@ -313,7 +313,7 @@ clixon_plugin_statedata_all(clicon_handle h, } /* error reason should be in clicon_err_reason */ cprintf(cberr, "Internal error, state callback in plugin %s returned invalid XML: %s", - cp->cp_name, clicon_err_reason); + clixon_plugin_name_get(cp), clicon_err_reason); if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0) goto done; xml_free(*xret); @@ -338,7 +338,7 @@ clixon_plugin_statedata_all(clicon_handle h, if (ret == 0){ if (clixon_netconf_internal_error(xerr, ". Internal error, state callback returned invalid XML from plugin: ", - cp->cp_name) < 0) + clixon_plugin_name_get(cp)) < 0) goto done; xml_free(*xret); *xret = xerr; @@ -432,18 +432,18 @@ transaction_free(transaction_data_t *td) * @retval -1 Error */ int -plugin_transaction_begin_one(clixon_plugin *cp, +plugin_transaction_begin_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_begin) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -465,7 +465,7 @@ plugin_transaction_begin_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_begin_one(cp, h, td) < 0) @@ -484,18 +484,18 @@ plugin_transaction_begin_all(clicon_handle h, * @retval -1 Error */ int -plugin_transaction_validate_one(clixon_plugin *cp, +plugin_transaction_validate_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_validate) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -515,7 +515,7 @@ plugin_transaction_validate_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_validate_one(cp, h, td) < 0) @@ -535,18 +535,18 @@ plugin_transaction_validate_all(clicon_handle h, * @retval -1 Error */ int -plugin_transaction_complete_one(clixon_plugin *cp, +plugin_transaction_complete_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_complete) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -568,7 +568,7 @@ plugin_transaction_complete_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_complete_one(cp, h, td) < 0) @@ -594,15 +594,15 @@ plugin_transaction_revert_all(clicon_handle h, int nr) { int retval = 0; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; trans_cb_t *fn; while ((cp = clixon_plugin_each_revert(h, cp, nr)) != NULL) { - if ((fn = cp->cp_api.ca_trans_revert) == NULL) + if ((fn = clixon_plugin_api_get(cp)->ca_trans_revert) == NULL) continue; if ((retval = fn(h, (transaction_data)td)) < 0){ clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_revert callback failed", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); break; } } @@ -618,18 +618,18 @@ plugin_transaction_revert_all(clicon_handle h, * @retval -1 Error */ int -plugin_transaction_commit_one(clixon_plugin *cp, +plugin_transaction_commit_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_commit) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -652,7 +652,7 @@ plugin_transaction_commit_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; int i=0; while ((cp = clixon_plugin_each(h, cp)) != NULL) { @@ -677,18 +677,18 @@ plugin_transaction_commit_all(clicon_handle h, * @retval -1 Error */ int -plugin_transaction_commit_done_one(clixon_plugin *cp, +plugin_transaction_commit_done_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_commit_done) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -709,7 +709,7 @@ plugin_transaction_commit_done_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_commit_done_one(cp, h, td) < 0) @@ -728,18 +728,18 @@ plugin_transaction_commit_done_all(clicon_handle h, * @retval -1 Error */ int -plugin_transaction_end_one(clixon_plugin *cp, +plugin_transaction_end_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_end) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -759,7 +759,7 @@ plugin_transaction_end_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_end_one(cp, h, td) < 0) @@ -771,18 +771,18 @@ plugin_transaction_end_all(clicon_handle h, } int -plugin_transaction_abort_one(clixon_plugin *cp, +plugin_transaction_abort_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td) { int retval = -1; trans_cb_t *fn; - if ((fn = cp->cp_api.ca_trans_abort) != NULL){ + if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){ if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", - __FUNCTION__, cp->cp_name); + __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } } @@ -802,7 +802,7 @@ plugin_transaction_abort_all(clicon_handle h, transaction_data_t *td) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_abort_one(cp, h, td) < 0) diff --git a/apps/backend/backend_plugin.h b/apps/backend/backend_plugin.h index f0f800c5..f5edb4f3 100644 --- a/apps/backend/backend_plugin.h +++ b/apps/backend/backend_plugin.h @@ -69,7 +69,7 @@ typedef struct { /* * Prototypes */ -int clixon_plugin_reset_one(clixon_plugin *cp, clicon_handle h, char *db); +int clixon_plugin_reset_one(clixon_plugin_t *cp, clicon_handle h, char *db); int clixon_plugin_reset_all(clicon_handle h, char *db); int clixon_plugin_pre_daemon_all(clicon_handle h); @@ -80,25 +80,25 @@ int clixon_plugin_statedata_all(clicon_handle h, yang_stmt *yspec, cvec *nsc, ch transaction_data_t * transaction_new(void); int transaction_free(transaction_data_t *); -int plugin_transaction_begin_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_begin_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_begin_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_validate_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_validate_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_validate_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_complete_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_complete_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_complete_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_commit_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_commit_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_commit_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_commit_done_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_commit_done_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_commit_done_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_end_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_end_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_end_all(clicon_handle h, transaction_data_t *td); -int plugin_transaction_abort_one(clixon_plugin *cp, clicon_handle h, transaction_data_t *td); +int plugin_transaction_abort_one(clixon_plugin_t *cp, clicon_handle h, transaction_data_t *td); int plugin_transaction_abort_all(clicon_handle h, transaction_data_t *td); #endif /* _BACKEND_PLUGIN_H_ */ diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c index ceba7f04..d796b8c6 100644 --- a/apps/backend/backend_plugin_restconf.c +++ b/apps/backend/backend_plugin_restconf.c @@ -300,13 +300,13 @@ backend_plugin_restconf_register(clicon_handle h, yang_stmt *yspec) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; if (clixon_pseudo_plugin(h, "restconf pseudo plugin", &cp) < 0) goto done; - cp->cp_api.ca_trans_validate = restconf_pseudo_process_validate; - cp->cp_api.ca_trans_commit = restconf_pseudo_process_commit; + clixon_plugin_api_get(cp)->ca_trans_validate = restconf_pseudo_process_validate; + clixon_plugin_api_get(cp)->ca_trans_commit = restconf_pseudo_process_commit; /* Register generic process-control of restconf daemon, ie start/stop restconf */ if (restconf_pseudo_process_control(h) < 0) diff --git a/apps/backend/clixon_backend_transaction.c b/apps/backend/clixon_backend_transaction.c index f917c64e..1e427f3e 100644 --- a/apps/backend/clixon_backend_transaction.c +++ b/apps/backend/clixon_backend_transaction.c @@ -214,7 +214,7 @@ transaction_print(FILE *f, xn = td->td_avec[i]; xml_print(f, xn); } - fprintf(stderr, "Changed\n=========\n"); + fprintf(f, "Changed\n=========\n"); for (i=0; itd_clen; i++){ xn = td->td_scvec[i]; xml_print(f, xn); diff --git a/apps/cli/Makefile.in b/apps/cli/Makefile.in index 242f0bf2..91bcd795 100644 --- a/apps/cli/Makefile.in +++ b/apps/cli/Makefile.in @@ -41,7 +41,7 @@ CFLAGS = @CFLAGS@ LINKAGE = @LINKAGE@ CPPFLAGS = @CPPFLAGS@ ifeq ($(LINKAGE),dynamic) - CPPFLAGS += -fPIC +CPPFLAGS += -fPIC endif SH_SUFFIX = @SH_SUFFIX@ INSTALLFLAGS = @INSTALLFLAGS@ @@ -66,10 +66,10 @@ CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@ CLIXON_MINOR = @CLIXON_VERSION_MINOR@ # Use this clixon lib for linking -ifeq ($(LINKAGE),dynamic) - CLIXON_LIB = libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR) -else +ifeq ($(LINKAGE),static) CLIXON_LIB = libclixon.a +else + CLIXON_LIB = libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR) endif # For dependency. A little strange that we rely on it being built in the src dir @@ -78,7 +78,6 @@ LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB) LIBS = -L$(top_srcdir)/lib/src $(top_srcdir)/lib/src/$(CLIXON_LIB) @LIBS@ - INCLUDES = -I. -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@ # Name of application @@ -118,6 +117,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f $(LIBOBJ) $(APPOBJ) *.core $(APPL) $(MYLIB) $(MYLIBSO) $(MYLIBLINK) test test.c + rm -f *.gcda *.gcno *.gcov # coverage distclean: clean rm -f Makefile *~ .depend diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 594f51f0..a78a128b 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -178,7 +178,11 @@ cli_terminate(clicon_handle h) xml_free(x); clicon_data_cvec_del(h, "cli-edit-cvv");; xpath_optimize_exit(); - cli_plugin_finish(h); + /* Delete all plugins, and RPC callbacks */ + clixon_plugin_module_exit(h); + /* Delete CLI syntax et al */ + cli_plugin_finish(h); + cli_history_save(h); cli_handle_exit(h); clixon_err_exit(); @@ -615,6 +619,10 @@ main(int argc, */ cv_exclude_keys(clicon_cli_varonly(h)); + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; + /* Load cli plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_cli_dir(h)) != NULL && clixon_plugins_load(h, CLIXON_PLUGIN_INIT, dir, NULL) < 0) @@ -625,7 +633,6 @@ main(int argc, */ if (netconf_module_features(h) < 0) goto done; - /* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */ xml_nsctx_namespace_netconf_default(h); diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index d283dcb0..255866d2 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -271,7 +271,7 @@ cli_load_syntax_file(clicon_handle h, char **vec = NULL; int i, nvec; char *plgnam; - clixon_plugin *cp; + clixon_plugin_t *cp; if ((pt = pt_new()) == NULL){ clicon_err(OE_UNIX, errno, "pt_new"); @@ -313,7 +313,7 @@ cli_load_syntax_file(clicon_handle h, if (plgnam != NULL) { /* Find plugin for callback resolving */ if ((cp = clixon_plugin_find(h, plgnam)) != NULL) - handle = cp->cp_handle; + handle = clixon_plugin_handle_get(cp); if (handle == NULL){ clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s", plgnam, filename, plgnam, @@ -393,7 +393,7 @@ cli_syntax_load(clicon_handle h) cli_syntaxmode_t *m; cligen_susp_cb_t *fns = NULL; cligen_interrupt_cb_t *fni = NULL; - clixon_plugin *cp; + clixon_plugin_t *cp; parse_tree *ptall = NULL; /* Universal CLIgen parse tree all modes */ /* Syntax already loaded. XXX should we re-load?? */ @@ -457,10 +457,10 @@ cli_syntax_load(clicon_handle h) /* Set susp and interrupt callbacks into CLIgen */ cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { - if (fns==NULL && (fns = cp->cp_api.ca_suspend) != NULL) + if (fns==NULL && (fns = clixon_plugin_api_get(cp)->ca_suspend) != NULL) if (cli_susp_hook(h, fns) < 0) goto done; - if (fni==NULL && (fni = cp->cp_api.ca_interrupt) != NULL) + if (fni==NULL && (fni = clixon_plugin_api_get(cp)->ca_interrupt) != NULL) if (cli_interrupt_hook(h, fni) < 0) goto done; } @@ -469,7 +469,6 @@ cli_syntax_load(clicon_handle h) retval = 0; done: if (retval != 0) { - clixon_plugin_exit_all(h); cli_syntax_unload(h); cli_syntax_set(h, NULL); } @@ -485,8 +484,6 @@ done: int cli_plugin_finish(clicon_handle h) { - /* Remove all CLI plugins */ - clixon_plugin_exit_all(h); /* Remove all cligen syntax modes */ cli_syntax_unload(h); cli_syntax_set(h, NULL); @@ -744,7 +741,7 @@ clicon_cliread(clicon_handle h, cli_syntaxmode_t *mode; cli_syntax_t *stx; cli_prompthook_t *fn; - clixon_plugin *cp; + clixon_plugin_t *cp; char *promptstr; stx = cli_syntax(h); @@ -752,7 +749,7 @@ clicon_cliread(clicon_handle h, /* Get prompt from plugin callback? */ cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { - if ((fn = cp->cp_api.ca_prompt) == NULL) + if ((fn = clixon_plugin_api_get(cp)->ca_prompt) == NULL) continue; pfmt = fn(h, mode->csm_name); break; diff --git a/apps/netconf/Makefile.in b/apps/netconf/Makefile.in index d0ec8f0e..e2d4214a 100644 --- a/apps/netconf/Makefile.in +++ b/apps/netconf/Makefile.in @@ -111,6 +111,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f $(APPL) $(APPOBJ) $(LIBOBJ) *.core $(MYLIB) $(MYLIBSO) $(MYLIBLINK) + rm -f *.gcda *.gcno *.gcov # coverage distclean: clean rm -f Makefile *~ .depend diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 70896242..7aa8c9da 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -584,8 +584,9 @@ netconf_terminate(clicon_handle h) cvec *nsctx; cxobj *x; - clixon_plugin_exit_all(h); - rpc_callback_delete_all(h); + /* Delete all plugins, and RPC callbacks */ + clixon_plugin_module_exit(h); + clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) ys_free(yspec); @@ -796,6 +797,10 @@ main(int argc, if (netconf_module_features(h) < 0) goto done; + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; + /* Create top-level yang spec and store as option */ if ((yspec = yspec_new()) == NULL) goto done; diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index 2613e287..b67e67c8 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -78,10 +78,9 @@ LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB) LIBS = -L$(top_srcdir)/lib/src $(top_srcdir)/lib/src/$(CLIXON_LIB) @LIBS@ +CPPFLAGS = @CPPFLAGS@ ifeq ($(LINKAGE),dynamic) - CPPFLAGS = @CPPFLAGS@ -fPIC -else - CPPFLAGS = @CPPFLAGS@ +CPPFLAGS += -fPIC endif INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@ @@ -139,6 +138,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f $(LIBOBJ) *.core $(APPL) $(APPOBJ) *.o $(MYLIB) $(MYLIBSO) $(MYLIBLINK) # extra .o to clean residue if with_restconf changes + rm -f *.gcda *.gcno *.gcov # coverage distclean: clean rm -f Makefile *~ .depend @@ -201,4 +201,3 @@ depend: $(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(APPFCGI) $(APPSRC) > .depend #include .depend - diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index c6f4bf55..f3e4a31a 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -247,8 +247,9 @@ restconf_terminate(clicon_handle h) clicon_debug(1, "%s", __FUNCTION__); if ((fs = clicon_socket_get(h)) != -1) close(fs); - clixon_plugin_exit_all(h); - rpc_callback_delete_all(h); + /* Delete all plugins, and RPC callbacks */ + clixon_plugin_module_exit(h); + clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) ys_free(yspec); diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c index 2d5a29d4..a632fe42 100644 --- a/apps/restconf/restconf_main_fcgi.c +++ b/apps/restconf/restconf_main_fcgi.c @@ -211,7 +211,7 @@ main(int argc, char *stream_path; int finish = 0; char *str; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; uint32_t id = 0; cvec *nsctx_global = NULL; /* Global namespace context */ size_t cligen_buflen; @@ -362,6 +362,10 @@ main(int argc, /* Treat unknown XML as anydata */ if (clicon_option_bool(h, "CLICON_YANG_UNKNOWN_ANYDATA") == 1) xml_bind_yang_unknown_anydata(1); + + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; /* Load restconf plugins before yangs are loaded (eg extension callbacks) */ if ((dir = clicon_restconf_dir(h)) != NULL) @@ -372,7 +376,7 @@ main(int argc, */ if (clixon_pseudo_plugin(h, "pseudo restconf", &cp) < 0) goto done; - cp->cp_api.ca_extension = restconf_main_extension_cb; + clixon_plugin_api_get(cp)->ca_extension = restconf_main_extension_cb; /* Load Yang modules * 1. Load a yang module as a specific absolute filename */ @@ -427,6 +431,9 @@ main(int argc, if (dbg) clicon_option_dump(h, dbg); + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; /* Call start function in all plugins before we go interactive */ if (clixon_plugin_start_all(h) < 0) goto done; diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index a8382d78..f4544b14 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -1544,7 +1544,7 @@ restconf_clixon_init(clicon_handle h, size_t cligen_buflen; size_t cligen_bufthreshold; yang_stmt *yspec = NULL; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; char *str; cvec *nsctx_global = NULL; /* Global namespace context */ cxobj *xrestconf; @@ -1581,7 +1581,7 @@ restconf_clixon_init(clicon_handle h, */ if (clixon_pseudo_plugin(h, "pseudo restconf", &cp) < 0) goto done; - cp->cp_api.ca_extension = restconf_main_extension_cb; + clixon_plugin_api_get(cp)->ca_extension = restconf_main_extension_cb; /* Load Yang modules * 1. Load a yang module as a specific absolute filename */ @@ -1614,7 +1614,6 @@ restconf_clixon_init(clicon_handle h, /* Add netconf yang spec, used as internal protocol */ if (netconf_module_load(h) < 0) goto done; - /* Add system modules */ if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0) @@ -1847,6 +1846,9 @@ main(int argc, if (dbg) clicon_option_dump(h, dbg); + /* Initialize plugin module by creating a handle holding plugin and callback lists */ + if (clixon_plugin_module_init(h) < 0) + goto done; /* Call start function in all plugins before we go interactive */ if (clixon_plugin_start_all(h) < 0) goto done; diff --git a/example/main/Makefile.in b/example/main/Makefile.in index ad8aa6a9..356426c8 100644 --- a/example/main/Makefile.in +++ b/example/main/Makefile.in @@ -32,6 +32,14 @@ # # ***** END LICENSE BLOCK ***** # +# Note, for linkage=static, libclixon is linked twice: +# First static when building: +# libclixon_backend, libclixon_cli, libclixon_restconf and libclixon_netconf +# Second in this Makefile dynamic using -lclixon +# This means global variables used in plugin code is in separate domains and will not work +# Dont know enough about dynamic/static linkage to fix it. +# One way is to not use global variables in libraries, but there are still some, eg in error +# and log modules VPATH = @srcdir@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -56,12 +64,12 @@ INSTALLFLAGS = @INSTALLFLAGS@ with_restconf = @with_restconf@ INCLUDES = -I$(includedir) @INCLUDES@ +LINKAGE = @LINKAGE@ LDFLAGS = @LDFLAGS@ CPPFLAGS = @CPPFLAGS@ ifeq ($(LINKAGE),dynamic) CPPFLAGS += -fPIC endif -LINKAGE = @LINKAGE@ BE_PLUGIN = $(APPNAME)_backend.so BE2_PLUGIN = $(APPNAME)_backend_nacm.so @@ -93,7 +101,7 @@ BE_SRC = $(APPNAME)_backend.c BE_OBJ = $(BE_SRC:%.c=%.o) $(BE_PLUGIN): $(BE_OBJ) ifeq ($(LINKAGE),static) - $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -lclixon_backend + $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -L ../../apps/backend/ -lclixon_backend else $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -lclixon_backend endif @@ -103,7 +111,7 @@ BE2_SRC = $(APPNAME)_backend_nacm.c BE2_OBJ = $(BE2_SRC:%.c=%.o) $(BE2_PLUGIN): $(BE2_OBJ) ifeq ($(LINKAGE),static) - $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -lclixon_backend + $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -L ../../apps/backend/ -lclixon_backend else $(CC) -Wall -shared $(LDFLAGS) -o $@ -lc $< -lclixon -lclixon_backend endif @@ -147,6 +155,7 @@ OBJS += $(RESTCONF_OBJ) clean: rm -f $(PLUGINS) $(OBJS) + rm -f *.gcda *.gcno *.gcov # coverage distclean: clean rm -f Makefile *~ .depend diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index 6cda4bfa..2d15531a 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -312,14 +312,9 @@ struct clixon_plugin_api{ typedef struct clixon_plugin_api clixon_plugin_api; -/* Internal plugin structure with dlopen() handle and plugin_api - */ -struct clixon_plugin{ - char cp_name[MAXPATHLEN]; /* Plugin filename. Note api ca_name is given by plugin itself */ - plghndl_t cp_handle; /* Handle to plugin using dlopen(3) */ - clixon_plugin_api cp_api; -}; -typedef struct clixon_plugin clixon_plugin; +/* This is the external handle type exposed in the API. + * The internal struct is defined in clixon_plugin.c */ +typedef struct clixon_plugin clixon_plugin_t; /* * Prototypes @@ -333,42 +328,43 @@ typedef struct clixon_plugin clixon_plugin; */ clixon_plugin_api *clixon_plugin_init(clicon_handle h); -clixon_plugin *clixon_plugin_each(clicon_handle h, clixon_plugin *cpprev); -clixon_plugin *clixon_plugin_each_revert(clicon_handle h, clixon_plugin *cpprev, int nr); +clixon_plugin_api *clixon_plugin_api_get(clixon_plugin_t *cp); +char *clixon_plugin_name_get(clixon_plugin_t *cp); +plghndl_t clixon_plugin_handle_get(clixon_plugin_t *cp); -clixon_plugin *clixon_plugin_find(clicon_handle h, const char *name); +clixon_plugin_t *clixon_plugin_each(clicon_handle h, clixon_plugin_t *cpprev); + +clixon_plugin_t *clixon_plugin_each_revert(clicon_handle h, clixon_plugin_t *cpprev, int nr); + +clixon_plugin_t *clixon_plugin_find(clicon_handle h, const char *name); int clixon_plugins_load(clicon_handle h, const char *function, const char *dir, const char *regexp); -int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin **cpp); +int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin_t **cpp); -int clixon_plugin_start_one(clixon_plugin *cp, clicon_handle h); +int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h); int clixon_plugin_start_all(clicon_handle h); -int clixon_plugin_exit_one(clixon_plugin *cp, clicon_handle h); -int clixon_plugin_exit_all(clicon_handle h); - int clixon_plugin_auth_all(clicon_handle h, void *req, clixon_auth_type_t auth_type, char **authp); -int clixon_plugin_extension_one(clixon_plugin *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys); +int clixon_plugin_extension_one(clixon_plugin_t *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys); int clixon_plugin_extension_all(clicon_handle h, yang_stmt *yext, yang_stmt *ys); -int clixon_plugin_datastore_upgrade_one(clixon_plugin *cp, clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd); +int clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd); int clixon_plugin_datastore_upgrade_all(clicon_handle h, const char *db, cxobj *xt, modstate_diff_t *msd); /* rpc callback API */ int rpc_callback_register(clicon_handle h, clicon_rpc_cb cb, void *arg, const char *ns, const char *name); -int rpc_callback_delete_all(clicon_handle h); int rpc_callback_call(clicon_handle h, cxobj *xe, cbuf *cbret, void *arg); /* upgrade callback API */ int upgrade_callback_reg_fn(clicon_handle h, clicon_upgrade_cb cb, const char *strfn, const char *ns, void *arg); -int upgrade_callback_delete_all(clicon_handle h); int upgrade_callback_call(clicon_handle h, cxobj *xt, char *ns, uint16_t op, uint32_t from, uint32_t to, cbuf *cbret); const int clixon_auth_type_str2int(char *auth_type); const char *clixon_auth_type_int2str(clixon_auth_type_t auth_type); - +int clixon_plugin_module_init(clicon_handle h); +int clixon_plugin_module_exit(clicon_handle h); #endif /* _CLIXON_PLUGIN_H_ */ diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 2311473f..c964a4b6 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -155,7 +155,9 @@ typedef enum yang_class yang_class; struct xml; -typedef struct yang_stmt yang_stmt; /* Defined in clixon_yang_internal */ +/* This is the external handle type exposed in the API. + * The internal struct is defined in clixon_yang_internal.h */ +typedef struct yang_stmt yang_stmt; /*! Yang apply function worker * @param[in] yn yang node diff --git a/lib/src/Makefile.in b/lib/src/Makefile.in index fc097594..324b666e 100644 --- a/lib/src/Makefile.in +++ b/lib/src/Makefile.in @@ -128,6 +128,7 @@ clean: rm -f lex.clixon_xpath_parse.c rm -f lex.clixon_api_path_parse.c rm -f lex.clixon_instance_id_parse.c + rm -f *.gcda *.gcno *.gcov # coverage ############################################################################# # Implicit rules for lex and yacc. diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 41a475db..57c4d937 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -67,12 +66,128 @@ #include "clixon_yang_module.h" #include "clixon_plugin.h" -/* List of plugins XXX - * 1. Place in clixon handle not global variables - * 2. Use qelem circular lists +/* + * Private types */ -static clixon_plugin *_clixon_plugins = NULL; /* List of plugins (of client) */ -static int _clixon_nplugins = 0; /* Number of plugins */ + +/* Internal plugin structure with dlopen() handle and plugin_api + * This is an internal type, not exposed in the API + * The external type is "clixon_plugin_t" defined in clixon_plugin.h + */ +struct clixon_plugin{ + qelem_t cp_q; /* queue header */ + char cp_name[MAXPATHLEN]; /* Plugin filename. Note api ca_name is given by plugin itself */ + plghndl_t cp_handle; /* Handle to plugin using dlopen(3) */ + clixon_plugin_api cp_api; +}; + +/* + * RPC callbacks for both client/frontend and backend plugins. + * RPC callbacks are explicitly registered in the plugin_init() function + * with a tag and a function + * When the the tag is encountered, the callback is called. + * Primarily backend, but also netconf and restconf frontend plugins. + * CLI frontend so far have direct callbacks, ie functions in the cligen + * specification are directly dlsym:ed to the CLI plugin. + * It would be possible to use this rpc registering API for CLI plugins as well. + * + * When namespace and name match, the callback is made + */ +typedef struct { + qelem_t rc_qelem; /* List header */ + clicon_rpc_cb rc_callback; /* RPC Callback */ + void *rc_arg; /* Application specific argument to cb */ + char *rc_namespace;/* Namespace to combine with name tag */ + char *rc_name; /* Xml/json tag/name */ +} rpc_callback_t; + +/* + * Upgrade callbacks for backend upgrade of datastore + * Register upgrade callbacks in plugin_init() with a module and a "from" and "to" + * revision. + */ +typedef struct { + qelem_t uc_qelem; /* List header */ + clicon_upgrade_cb uc_callback; /* RPC Callback */ + const char *uc_fnstr; /* Stringified fn name for debug */ + void *uc_arg; /* Application specific argument to cb */ + char *uc_namespace; /* Module namespace */ +} upgrade_callback_t; + +/* Internal struct for accessing plugin list and rpc list. This handle is accessed + * via clixon-handle "cdata" structure (see clixon_data.h) using the key "clixon-plugin-handle"." + * It is just a way to avoid using global variables + */ +struct plugin_module_struct { + clixon_plugin_t *ms_plugin_list; + rpc_callback_t *ms_rpc_callbacks; + upgrade_callback_t *ms_upgrade_callbacks; +}; +typedef struct plugin_module_struct plugin_module_struct; + + +/*! Get plugin handle containing plugin and callback lists + * @param[in] h Clicon handle + */ +static plugin_module_struct * +plugin_module_struct_get(clicon_handle h) +{ + clicon_hash_t *cdat = clicon_data(h); + size_t len; + void *p; + + if ((p = clicon_hash_value(cdat, "plugin-module-struct", &len)) != NULL) + return *(plugin_module_struct **)p; + return NULL; +} + +/*! Set plugin handle containing plugin and callback lists + * @param[in] h Clicon handle + * @param[in] pl Clixon plugin handle + */ +static int +plugin_module_struct_set(clicon_handle h, + plugin_module_struct *ms) +{ + clicon_hash_t *cdat = clicon_data(h); + + /* It is the pointer to ys that should be copied by hash, + so we send a ptr to the ptr to indicate what to copy. + */ + if (clicon_hash_add(cdat, "plugin-module-struct", &ms, sizeof(ms)) == NULL) + return -1; + return 0; +} + + +/* Access functions */ + +/*! Get plugin api + * @param[in] cp Clixon plugin handle + */ +clixon_plugin_api * +clixon_plugin_api_get(clixon_plugin_t *cp) +{ + return &cp->cp_api; +} + +/*! Get plugin name + * @param[in] cp Clixon plugin handle + */ +char * +clixon_plugin_name_get(clixon_plugin_t *cp) +{ + return cp->cp_name; +} + +/*! Get plugin handle + * @param[in] cp Clixon plugin handle + */ +plghndl_t +clixon_plugin_handle_get(clixon_plugin_t *cp) +{ + return cp->cp_handle; +} /*! Iterator over clixon plugins * @@ -87,27 +202,24 @@ static int _clixon_nplugins = 0; /* Number of plugins */ * ... * } * @endcode - * @note Not optimized, alwasy iterates from the start of the list + * @note Not optimized, always iterates from the start of the list */ -clixon_plugin * -clixon_plugin_each(clicon_handle h, - clixon_plugin *cpprev) +clixon_plugin_t * +clixon_plugin_each(clicon_handle h, + clixon_plugin_t *cpprev) { - int i; - clixon_plugin *cp; - clixon_plugin *cpnext = NULL; + clixon_plugin_t *cpnext = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); - if (cpprev == NULL) - cpnext = _clixon_plugins; + /* ms == NULL means plugins are not yet initialized */ + if (ms == NULL || ms->ms_plugin_list == NULL) + cpnext = NULL; + else if (cpprev == NULL) + cpnext = ms->ms_plugin_list; else{ - for (i = 0; i < _clixon_nplugins; i++) { - cp = &_clixon_plugins[i]; - if (cp == cpprev) - break; - cp = NULL; - } - if (cp && i < _clixon_nplugins-1) - cpnext = &_clixon_plugins[i+1]; + cpnext = NEXTQ(clixon_plugin_t *, cpprev); + if (cpnext == ms->ms_plugin_list) + cpnext = NULL; } return cpnext; } @@ -118,38 +230,47 @@ clixon_plugin_each(clicon_handle h, * same object recursively * * @param[in] h Clicon handle - * @param[in] plugin previous plugin, or NULL on init + * @param[in] plugin previous plugin, or NULL on init + * @param[in] nr Start from this nr <= lngth of list * @code - * clicon_plugin *cp = NULL; + * clicon_plugin_t *cp = NULL; * while ((cp = clixon_plugin_each_revert(h, cp, nr)) != NULL) { * ... * } * @endcode - * @note Not optimized, alwasy iterates from the start of the list + * @note Not optimized, always iterates from the start of the list */ -clixon_plugin * -clixon_plugin_each_revert(clicon_handle h, - clixon_plugin *cpprev, - int nr) +clixon_plugin_t * +clixon_plugin_each_revert(clicon_handle h, + clixon_plugin_t *cpprev, + int nr) { int i; - clixon_plugin *cp = NULL; - clixon_plugin *cpnext = NULL; + clixon_plugin_t *cpnext = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); - if (cpprev == NULL){ - if (nr>0) - cpnext = &_clixon_plugins[nr-1]; + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + return NULL; + } + if (ms->ms_plugin_list == NULL) + cpnext = NULL; + else if (cpprev == NULL){ + cpnext = ms->ms_plugin_list; + for (i = nr-1; i > 0; i--) { + cpnext = NEXTQ(clixon_plugin_t *, cpnext); + if (cpnext == ms->ms_plugin_list){ + cpnext = NULL; + break; + } + } } else{ - for (i = nr-1; i >= 0; i--) { - cp = &_clixon_plugins[i]; - if (cp == cpprev) - break; - cp = NULL; - } - if (cp && i > 0) - cpnext = &_clixon_plugins[i-1]; - } + if (cpprev == ms->ms_plugin_list) + cpnext = NULL; + else + cpnext = PREVQ(clixon_plugin_t *, cpprev); + } return cpnext; } @@ -159,21 +280,27 @@ clixon_plugin_each_revert(clicon_handle h, * @retval p Plugin if found * @retval NULL Not found * @code - * clixon_plugin *cp; + * clixon_plugin_t *cp; * cp = clixon_plugin_find(h, "plugin-name"); * @endcode */ -clixon_plugin * +clixon_plugin_t * clixon_plugin_find(clicon_handle h, const char *name) { - int i; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); - for (i = 0; i < _clixon_nplugins; i++) { - cp = &_clixon_plugins[i]; - if (strcmp(cp->cp_name, name) == 0) - return cp; + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + return NULL; + } + if ((cp = ms->ms_plugin_list) != NULL){ + do { + if (strcmp(cp->cp_name, name) == 0) + return cp; + cp = NEXTQ(clixon_plugin_t *, cp); + } while (cp && cp != ms->ms_plugin_list); } return NULL; } @@ -194,14 +321,14 @@ plugin_load_one(clicon_handle h, char *file, /* note modified */ const char *function, int dlflags, - clixon_plugin **cpp) + clixon_plugin_t **cpp) { int retval = -1; char *error; void *handle = NULL; plginit2_t *initfn; clixon_plugin_api *api = NULL; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; char *name; char *p; @@ -234,7 +361,7 @@ plugin_load_one(clicon_handle h, } } /* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */ - if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){ + if ((cp = (clixon_plugin_t *)malloc(sizeof(struct clixon_plugin))) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); goto done; } @@ -249,13 +376,13 @@ plugin_load_one(clicon_handle h, snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s", (int)strlen(name), name); cp->cp_api = *api; - clicon_debug(1, "%s", __FUNCTION__); if (cp){ *cpp = cp; cp = NULL; } retval = 1; done: + clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); if (retval != 1 && handle) dlclose(handle); if (cp) @@ -282,10 +409,15 @@ clixon_plugins_load(clicon_handle h, struct dirent *dp = NULL; int i; char filename[MAXPATHLEN]; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; int ret; + plugin_module_struct *ms = plugin_module_struct_get(h); clicon_debug(1, "%s", __FUNCTION__); + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } /* Get plugin objects names from plugin directory */ if((ndp = clicon_file_dirent(dir, &dp, regexp?regexp:"(.so)$", S_IFREG)) < 0) goto done; @@ -298,13 +430,7 @@ clixon_plugins_load(clicon_handle h, goto done; if (ret == 0) continue; - _clixon_nplugins++; - if ((_clixon_plugins = realloc(_clixon_plugins, _clixon_nplugins*sizeof(clixon_plugin))) == NULL) { - clicon_err(OE_UNIX, errno, "realloc"); - goto done; - } - _clixon_plugins[_clixon_nplugins-1] = *cp; - free(cp); + ADDQ(cp, ms->ms_plugin_list); } retval = 0; done: @@ -320,39 +446,37 @@ done: * @retval 0 OK, with cpp set * @retval -1 Error * @code - * clixon_plugin *cp = NULL; + * clixon_plugin_t *cp = NULL; * if (clixon_pseudo_plugin(h, "pseudo plugin", &cp) < 0) * err; * cp->cp_api.ca_extension = my_ext_cb; * @endcode */ int -clixon_pseudo_plugin(clicon_handle h, - const char *name, - clixon_plugin **cpp) +clixon_pseudo_plugin(clicon_handle h, + const char *name, + clixon_plugin_t **cpp) { - int retval = -1; - clixon_plugin *cp = NULL; + int retval = -1; + clixon_plugin_t *cp = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); clicon_debug(1, "%s %s", __FUNCTION__, name); - + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } /* Create a pseudo plugins */ /* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */ - if ((cp = (clixon_plugin *)malloc(sizeof(struct clixon_plugin))) == NULL){ + if ((cp = (clixon_plugin_t *)malloc(sizeof(struct clixon_plugin))) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); goto done; } memset(cp, 0, sizeof(struct clixon_plugin)); snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s", (int)strlen(name), name); - - _clixon_nplugins++; - if ((_clixon_plugins = realloc(_clixon_plugins, _clixon_nplugins*sizeof(clixon_plugin))) == NULL) { - clicon_err(OE_UNIX, errno, "realloc"); - goto done; - } - _clixon_plugins[_clixon_nplugins-1] = *cp; - *cpp = &_clixon_plugins[_clixon_nplugins-1]; - + ADDQ(cp, ms->ms_plugin_list); + *cpp = cp; + cp = NULL; retval = 0; done: if (cp) @@ -367,7 +491,7 @@ done: * @retval -1 Error */ int -clixon_plugin_start_one(clixon_plugin *cp, +clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h) { int retval = -1; @@ -395,7 +519,7 @@ int clixon_plugin_start_all(clicon_handle h) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_start_one(cp, h) < 0) @@ -413,8 +537,8 @@ clixon_plugin_start_all(clicon_handle h) * @retval 0 OK * @retval -1 Error */ -int -clixon_plugin_exit_one(clixon_plugin *cp, +static int +clixon_plugin_exit_one(clixon_plugin_t *cp, clicon_handle h) { int retval = -1; @@ -443,21 +567,21 @@ clixon_plugin_exit_one(clixon_plugin *cp, * @retval 0 OK * @retval -1 Error */ -int +static int clixon_plugin_exit_all(clicon_handle h) { int retval = -1; - clixon_plugin *cp = NULL; - - while ((cp = clixon_plugin_each(h, cp)) != NULL) { - if (clixon_plugin_exit_one(cp, h) < 0) - goto done; + clixon_plugin_t *cp = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); + + if (ms != NULL){ + while ((cp = ms->ms_plugin_list) != NULL){ + DELQ(cp, ms->ms_plugin_list, clixon_plugin_t *); + if (clixon_plugin_exit_one(cp, h) < 0) + goto done; + free(cp); + } } - if (_clixon_plugins){ - free(_clixon_plugins); - _clixon_plugins = NULL; - } - _clixon_nplugins = 0; retval = 0; done: return retval; @@ -477,7 +601,7 @@ clixon_plugin_exit_all(clicon_handle h) * Or no callback was found. */ static int -clixon_plugin_auth_one(clixon_plugin *cp, +clixon_plugin_auth_one(clixon_plugin_t *cp, clicon_handle h, void *req, clixon_auth_type_t auth_type, @@ -523,7 +647,7 @@ clixon_plugin_auth_all(clicon_handle h, char **authp) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; int ret = 0; clicon_debug(1, "%s", __FUNCTION__); @@ -556,7 +680,7 @@ clixon_plugin_auth_all(clicon_handle h, * @retval -1 Error */ int -clixon_plugin_extension_one(clixon_plugin *cp, +clixon_plugin_extension_one(clixon_plugin_t *cp, clicon_handle h, yang_stmt *yext, yang_stmt *ys) @@ -595,7 +719,7 @@ clixon_plugin_extension_all(clicon_handle h, yang_stmt *ys) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_extension_one(cp, h, yext, ys) < 0) @@ -618,7 +742,7 @@ clixon_plugin_extension_all(clicon_handle h, * Upgrade datastore on load before or as an alternative to module-specific upgrading mechanism */ int -clixon_plugin_datastore_upgrade_one(clixon_plugin *cp, +clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, clicon_handle h, const char *db, cxobj *xt, @@ -658,7 +782,7 @@ clixon_plugin_datastore_upgrade_all(clicon_handle h, modstate_diff_t *msd) { int retval = -1; - clixon_plugin *cp = NULL; + clixon_plugin_t *cp = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_datastore_upgrade_one(cp, h, db, xt, msd) < 0) @@ -671,41 +795,21 @@ clixon_plugin_datastore_upgrade_all(clicon_handle h, /*-------------------------------------------------------------------- * RPC callbacks for both client/frontend and backend plugins. - * RPC callbacks are explicitly registered in the plugin_init() function - * with a tag and a function - * When the the tag is encountered, the callback is called. - * Primarily backend, but also netconf and restconf frontend plugins. - * CLI frontend so far have direct callbacks, ie functions in the cligen - * specification are directly dlsym:ed to the CLI plugin. - * It would be possible to use this rpc registering API for CLI plugins as well. - * - * When namespace and name match, the callback is made */ -typedef struct { - qelem_t rc_qelem; /* List header */ - clicon_rpc_cb rc_callback; /* RPC Callback */ - void *rc_arg; /* Application specific argument to cb */ - char *rc_namespace;/* Namespace to combine with name tag */ - char *rc_name; /* Xml/json tag/name */ -} rpc_callback_t; - -/* List of rpc callback entries XXX hang on handle */ -static rpc_callback_t *rpc_cb_list = NULL; #if 0 /* Debugging */ static int -rpc_callback_dump(clicon_handle h, - FILE *f) +rpc_callback_dump(clicon_handle h) { rpc_callback_t *rc; + plugin_module_struct *ms = plugin_module_struct_get(h); - if ((rc = rpc_cb_list) != NULL) + clicon_debug(1, "%s--------------", __FUNCTION__); + if ((rc = ms->ms_rpc_callbacks) != NULL) do { - fprintf(f, "%s %s\n", __FUNCTION__, rc->rc_name); - + clicon_debug(1, "%s %s", __FUNCTION__, rc->rc_name); rc = NEXTQ(rpc_callback_t *, rc); - } while (rc != rpc_cb_list); - fprintf(f, "%s--------------\n", __FUNCTION__); + } while (rc != ms->ms_rpc_callbacks); return 0; } #endif @@ -729,7 +833,13 @@ rpc_callback_register(clicon_handle h, const char *name) { rpc_callback_t *rc = NULL; + plugin_module_struct *ms = plugin_module_struct_get(h); + clicon_debug(1, "%s %s", __FUNCTION__, name); + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } if (name == NULL || ns == NULL){ clicon_err(OE_DB, EINVAL, "name or namespace NULL"); goto done; @@ -743,7 +853,7 @@ rpc_callback_register(clicon_handle h, rc->rc_arg = arg; rc->rc_namespace = strdup(ns); rc->rc_name = strdup(name); - ADDQ(rc, rpc_cb_list); + ADDQ(rc, ms->ms_rpc_callbacks); return 0; done: if (rc){ @@ -758,19 +868,21 @@ rpc_callback_register(clicon_handle h, /*! Delete all RPC callbacks */ -int +static int rpc_callback_delete_all(clicon_handle h) { rpc_callback_t *rc; + plugin_module_struct *ms = plugin_module_struct_get(h); - while((rc = rpc_cb_list) != NULL) { - DELQ(rc, rpc_cb_list, rpc_callback_t *); - if (rc->rc_namespace) - free(rc->rc_namespace); - if (rc->rc_name) - free(rc->rc_name); - free(rc); - } + if (ms != NULL) + while((rc = ms->ms_rpc_callbacks) != NULL) { + DELQ(rc, ms->ms_rpc_callbacks, rpc_callback_t *); + if (rc->rc_namespace) + free(rc->rc_namespace); + if (rc->rc_name) + free(rc->rc_name); + free(rc); + } return 0; } @@ -800,25 +912,28 @@ rpc_callback_call(clicon_handle h, char *prefix; char *ns; int nr = 0; /* How many callbacks */ + plugin_module_struct *ms = plugin_module_struct_get(h); - if (rpc_cb_list == NULL) - return 0; + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } name = xml_name(xe); prefix = xml_prefix(xe); xml2ns(xe, prefix, &ns); - rc = rpc_cb_list; - do { - if (strcmp(rc->rc_name, name) == 0 && - ns && rc->rc_namespace && - strcmp(rc->rc_namespace, ns) == 0){ - if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){ - clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name); - goto done; + if ((rc = ms->ms_rpc_callbacks) != NULL) + do { + if (strcmp(rc->rc_name, name) == 0 && + ns && rc->rc_namespace && + strcmp(rc->rc_namespace, ns) == 0){ + if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){ + clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name); + goto done; + } + nr++; } - nr++; - } - rc = NEXTQ(rpc_callback_t *, rc); - } while (rc != rpc_cb_list); + rc = NEXTQ(rpc_callback_t *, rc); + } while (rc != ms->ms_rpc_callbacks); retval = nr; /* 0: none found, >0 nr of handlers called */ done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); @@ -827,19 +942,7 @@ rpc_callback_call(clicon_handle h, /*-------------------------------------------------------------------- * Upgrade callbacks for backend upgrade of datastore - * Register upgrade callbacks in plugin_init() with a module and a "from" and "to" - * revision. */ -typedef struct { - qelem_t uc_qelem; /* List header */ - clicon_upgrade_cb uc_callback; /* RPC Callback */ - const char *uc_fnstr; /* Stringified fn name for debug */ - void *uc_arg; /* Application specific argument to cb */ - char *uc_namespace; /* Module namespace */ -} upgrade_callback_t; - -/* List of rpc callback entries XXX hang on handle */ -static upgrade_callback_t *upgrade_cb_list = NULL; /*! Register an upgrade callback by appending the new callback to the list * @@ -860,7 +963,12 @@ upgrade_callback_reg_fn(clicon_handle h, void *arg) { upgrade_callback_t *uc; + plugin_module_struct *ms = plugin_module_struct_get(h); + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } if ((uc = malloc(sizeof(upgrade_callback_t))) == NULL) { clicon_err(OE_DB, errno, "malloc"); goto done; @@ -871,7 +979,7 @@ upgrade_callback_reg_fn(clicon_handle h, uc->uc_arg = arg; if (ns) uc->uc_namespace = strdup(ns); - ADDQ(uc, upgrade_cb_list); + ADDQ(uc, ms->ms_upgrade_callbacks); return 0; done: if (uc){ @@ -884,17 +992,19 @@ upgrade_callback_reg_fn(clicon_handle h, /*! Delete all Upgrade callbacks */ -int +static int upgrade_callback_delete_all(clicon_handle h) { upgrade_callback_t *uc; + plugin_module_struct *ms = plugin_module_struct_get(h); - while((uc = upgrade_cb_list) != NULL) { - DELQ(uc, upgrade_cb_list, upgrade_callback_t *); - if (uc->uc_namespace) - free(uc->uc_namespace); - free(uc); - } + if (ms != NULL) + while((uc = ms->ms_upgrade_callbacks) != NULL) { + DELQ(uc, ms->ms_upgrade_callbacks, upgrade_callback_t *); + if (uc->uc_namespace) + free(uc->uc_namespace); + free(uc); + } return 0; } @@ -925,36 +1035,39 @@ upgrade_callback_call(clicon_handle h, upgrade_callback_t *uc; int nr = 0; /* How many callbacks */ int ret; + plugin_module_struct *ms = plugin_module_struct_get(h); - if (upgrade_cb_list == NULL) - return 1; - uc = upgrade_cb_list; - do { - /* For matching an upgrade callback: - * - No module name registered (matches all modules) OR - * - Names match - * AND - * - No registered from revision (matches all revisions) OR - * - Registered from revision >= from AND - * - Registered to revision <= to (which includes case both 0) - */ - if (uc->uc_namespace == NULL || strcmp(uc->uc_namespace, ns)==0){ - if ((ret = uc->uc_callback(h, xt, ns, op, from, to, uc->uc_arg, cbret)) < 0){ - clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace); - goto done; - } - if (ret == 0){ - if (cbuf_len(cbret)==0){ - clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set", - uc->uc_fnstr, ns); + if (ms == NULL){ + clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); + goto done; + } + if ((uc = ms->ms_upgrade_callbacks) != NULL) + do { + /* For matching an upgrade callback: + * - No module name registered (matches all modules) OR + * - Names match + * AND + * - No registered from revision (matches all revisions) OR + * - Registered from revision >= from AND + * - Registered to revision <= to (which includes case both 0) + */ + if (uc->uc_namespace == NULL || strcmp(uc->uc_namespace, ns)==0){ + if ((ret = uc->uc_callback(h, xt, ns, op, from, to, uc->uc_arg, cbret)) < 0){ + clicon_debug(1, "%s Error in: %s", __FUNCTION__, uc->uc_namespace); goto done; } - goto fail; + if (ret == 0){ + if (cbuf_len(cbret)==0){ + clicon_err(OE_CFG, 0, "Validation fail %s(%s): cbret not set", + uc->uc_fnstr, ns); + goto done; + } + goto fail; + } + nr++; } - nr++; - } - uc = NEXTQ(upgrade_callback_t *, uc); - } while (uc != upgrade_cb_list); + uc = NEXTQ(upgrade_callback_t *, uc); + } while (uc != ms->ms_upgrade_callbacks); retval = 1; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); @@ -990,3 +1103,49 @@ clixon_auth_type_int2str(clixon_auth_type_t auth_type) { return clicon_int2str(clixon_auth_type, auth_type); } + +/*! Initialize plugin module by creating a handle holding plugin and callback lists + * This should be called once at start by every application + * @param[in] h Clixon handle + * @see clixon_plugin_module_exit + */ +int +clixon_plugin_module_init(clicon_handle h) +{ + int retval = -1; + struct plugin_module_struct *ph; + + if ((ph = malloc(sizeof(*ph))) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + memset(ph, 0, sizeof(*ph)); + if (plugin_module_struct_set(h, ph) < 0) + goto done; + retval = 0; + done: + return retval; +} + +/*! Delete plugin module + * This should be called once at exit by every application + * @param[in] h Clixon handle + */ +int +clixon_plugin_module_exit(clicon_handle h) +{ + struct plugin_module_struct *ph; + + /* Delete all plugins */ + clixon_plugin_exit_all(h); + /* Delete all RPC callbacks */ + rpc_callback_delete_all(h); + /* Delete all backend plugin upgrade callbacks (only backend) */ + upgrade_callback_delete_all(h); + /* Delete plugin_module itself */ + if ((ph = plugin_module_struct_get(h)) != NULL){ + free(ph); + plugin_module_struct_set(h, NULL); + } + return 0; +} diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 6c5469a3..f866418d 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -2130,7 +2130,10 @@ ys_populate_unknown(clicon_handle h, return -1; } #endif - /* Make extension callbacks that may alter yang structure */ + /* Make extension callbacks that may alter yang structure + * Note: this may be a "layering" violation: assuming plugins are loaded + * at yang parse time + */ if (clixon_plugin_extension_all(h, yext, ys) < 0) goto done; diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index 25c110fe..a2da9248 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -60,6 +60,8 @@ struct yang_type_cache{ typedef struct yang_type_cache yang_type_cache; /*! yang statement + * This is an internal type, not exposed in the API + * The external type is "yang_stmt" defined in clixon_yang.h */ struct yang_stmt{ int ys_len; /* Number of children */ diff --git a/test/config.sh.in b/test/config.sh.in index d9753130..0dd198c8 100755 --- a/test/config.sh.in +++ b/test/config.sh.in @@ -77,3 +77,6 @@ CLIXON_EXAMPLE_REV="2020-12-01" # Problem with long keys are they take time to generate, eg on ARM CERTKEYLEN=2048 +# Linking: static or dynamic +LINKAGE=@LINKAGE@ +SH_SUFFIX=@SH_SUFFIX@ diff --git a/test/test_install.sh b/test/test_install.sh index 6f1ea39e..efb04cb3 100755 --- a/test/test_install.sh +++ b/test/test_install.sh @@ -7,6 +7,14 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi # Eg on FreeBSD use gmake : ${make:=make} + +# Check for soft links for .so files in case of dynamic linkage, but .a files f static linking +if [ ${LINKAGE} = static ]; then + LIBOPT=-f +else + LIBOPT=-h +fi + new "Set up installdir $dir" new "Make DESTDIR install ($dir)" @@ -26,18 +34,18 @@ new "Check installed files clixon-config" if [ ! -f $dir/usr/local/share/clixon/clixon-config* ]; then err $dir/usr/local/share/clixon/clixon-config* fi -new "Check installed files libclixon.so" +new "Check installed files libclixon${SH_SUFFIX}" # Check both /usr/local/lib and /usr/lib # This is a problem on some platforms that dont have /usr/local/ in LD_LIBRARY_PATH -if [ ! -h $dir/usr/local/lib/libclixon.so ]; then - if [ ! -h $dir/usr/lib/libclixon.so ]; then - err $dir/usr/local/lib/libclixon.so +if [ ! ${LIBOPT} $dir/usr/local/lib/libclixon${SH_SUFFIX} ]; then + if [ ! ${LIBOPT} $dir/usr/lib/libclixon${SH_SUFFIX} ]; then + err $dir/usr/local/lib/libclixon${SH_SUFFIX} fi fi -new "Check installed files libclixon_backend.so" -if [ ! -h $dir/usr/local/lib/libclixon_backend.so ]; then - if [ ! -h $dir/usr/lib/libclixon_backend.so ]; then - err $dir/usr/local/lib/libclixon_backend.so +new "Check installed files libclixon_backend${SH_SUFFIX}" +if [ ! ${LIBOPT} $dir/usr/local/lib/libclixon_backend${SH_SUFFIX} ]; then + if [ ! ${LIBOPT} $dir/usr/lib/libclixon_backend${SH_SUFFIX} ]; then + err $dir/usr/local/lib/libclixon_backend${SH_SUFFIX} fi fi diff --git a/util/Makefile.in b/util/Makefile.in index 0af63b05..6b51773a 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -105,6 +105,7 @@ $(top_srcdir)/lib/src/$(CLIXON_LIB): clean: rm -f $(APPS) clixon_util_stream *.core + rm -f *.gcda *.gcno *.gcov # coverage # APPS clixon_util_xml: clixon_util_xml.c $(LIBDEPS)