From 477059f33dfab060d5c38ee8af2cd7aae859cba0 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 24 Mar 2021 12:23:00 +0100 Subject: [PATCH] Fixed again: [backend start resconf failed due to path string truncated #192](https://github.com/clicon/clixon/issues/192) --- CHANGELOG.md | 2 + README.md | 2 +- apps/backend/backend_main.c | 1 + apps/backend/backend_plugin_restconf.c | 12 ++- apps/cli/cli_main.c | 1 + apps/netconf/netconf_main.c | 1 + apps/restconf/restconf_lib.c | 1 + lib/clixon/clixon_err.h | 9 ++ lib/src/clixon_err.c | 115 ++++++++++++++++++++++--- lib/src/clixon_hash.c | 5 +- lib/src/clixon_netns.c | 4 + lib/src/clixon_sig.c | 5 +- lib/src/clixon_uid.c | 5 +- 13 files changed, 144 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 183fddfd..ddb1c506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,8 @@ Developers may need to change their code ### Minor features +* Application specialized error handling for specific error categories + * See: https://clixon-docs.readthedocs.io/en/latest/misc.html#specialized-error-handling * Added several fields to process-control status operation: active, description, command, status, starttime, pid * Changed signal handling * Moved clixon-proc sigchild handling from handler to clixon_events diff --git a/README.md b/README.md index 33da87b3..e182ee71 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,6 @@ See [CHANGELOG.md](CHANGELOG.md) release history. Clixon interaction is best done posting issues, pull requests, or joining the [slack channel](https://clixondev.slack.com). -[Slack invite](https://join.slack.com/t/clixondev/shared_invite/zt-l36yx3fp-Lmi3qJGQyu5PEC~Zxi2Z5Q) (updated 5/2 2021) +[Slack invite](https://join.slack.com/t/clixondev/shared_invite/zt-o8lv7ysk-vcLb7yY9S7XMEklqqVBziQ) (updated 24/3 2021) Clixon is sponsored by [Rubicon Communications LLC(Netgate)](https://www.netgate.com/) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 96a12b46..79744fa2 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -142,6 +142,7 @@ backend_terminate(clicon_handle h) backend_handle_exit(h); /* Also deletes streams. Cannot use h after this. */ clixon_event_exit(); clicon_debug(1, "%s done", __FUNCTION__); + clixon_err_exit(); clicon_log_exit(); return 0; } diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c index 97227ba7..f4f3a07e 100644 --- a/apps/backend/backend_plugin_restconf.c +++ b/apps/backend/backend_plugin_restconf.c @@ -112,6 +112,7 @@ restconf_pseudo_process_control(clicon_handle h) int i; int nr; cbuf *cb = NULL; + cbuf *cbdbg = NULL; nr = 4; if (clicon_debug_get() != 0) @@ -134,9 +135,12 @@ restconf_pseudo_process_control(clicon_handle h) */ if (clicon_debug_get() != 0){ argv[i++] = "-D"; - cbuf_reset(cb); - cprintf(cb, "%d", clicon_debug_get()); - argv[i++] = cbuf_get(cb); + if ((cbdbg = cbuf_new()) == NULL){ /* Cant use cb since it would overwrite it */ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cbdbg, "%d", clicon_debug_get()); + argv[i++] = cbuf_get(cbdbg); } argv[i++] = NULL; assert(i==nr); @@ -152,6 +156,8 @@ restconf_pseudo_process_control(clicon_handle h) done: if (cb) cbuf_free(cb); + if (cbdbg) + cbuf_free(cbdbg); return retval; } diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index f347cca1..594f51f0 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -181,6 +181,7 @@ cli_terminate(clicon_handle h) cli_plugin_finish(h); cli_history_save(h); cli_handle_exit(h); + clixon_err_exit(); clicon_log_exit(); return 0; } diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index fca359df..94259b9f 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -598,6 +598,7 @@ netconf_terminate(clicon_handle h) xpath_optimize_exit(); clixon_event_exit(); clicon_handle_exit(h); + clixon_err_exit(); clicon_log_exit(); return 0; } diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index c1d2e835..8881d5f7 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -255,6 +255,7 @@ restconf_terminate(clicon_handle h) xml_free(x); xpath_optimize_exit(); restconf_handle_exit(h); + clixon_err_exit(); clicon_log_exit(); clicon_debug(1, "%s done", __FUNCTION__); return 0; diff --git a/lib/clixon/clixon_err.h b/lib/clixon/clixon_err.h index 3f45fae4..49c00f46 100644 --- a/lib/clixon/clixon_err.h +++ b/lib/clixon/clixon_err.h @@ -70,12 +70,19 @@ enum clicon_err{ OE_SYSLOG, /* syslog error */ OE_ROUTING, /* routing daemon error (eg quagga) */ OE_XML, /* xml parsing etc */ + OE_SSL, /* Openssl errors, see eg ssl_get_error */ OE_PLUGIN, /* plugin loading, etc */ OE_YANG , /* Yang error */ OE_FATAL, /* Fatal error */ OE_UNDEF, }; +/* Clixon error category log callback + * @param[in] handle Application-specific handle + * @param[out] cb Read log/error string into this buffer + */ +typedef int (clixon_cat_log_cb)(void *handle, cbuf *cb); + /* * Variables * XXX: should not be global @@ -101,5 +108,7 @@ int clicon_err_fn(const char *fn, const int line, int category, int err, const char *clicon_strerror(int err); void *clicon_err_save(void); int clicon_err_restore(void *handle); +int clixon_err_cat_reg(enum clicon_err category, void *handle, clixon_cat_log_cb logfn); +int clixon_err_exit(void); #endif /* _CLIXON_ERR_H_ */ diff --git a/lib/src/clixon_err.c b/lib/src/clixon_err.c index a82f43fa..1b5fb732 100644 --- a/lib/src/clixon_err.c +++ b/lib/src/clixon_err.c @@ -57,6 +57,10 @@ #include #include +/* cligen */ +#include + +/* clixon */ #include "clixon_log.h" #include "clixon_queue.h" #include "clixon_err.h" @@ -75,11 +79,26 @@ struct err_state{ char es_reason[ERR_STRLEN]; }; +/* Clixon error category callbacks provides a way to specialize + * error handling to something that clixon is not aware of + * An example is Openssl BIO I/O abstraction objects, see man BIO_new() + */ +struct clixon_err_cats { + qelem_t cec_qelem; /* List header */ + enum clicon_err cec_category; + void *cec_handle; + clixon_cat_log_cb *cec_logfn; +}; +typedef struct clixon_err_cats clixon_err_cats; + +/* Internal global list of category callbacks */ +static clixon_err_cats *_err_cat_list = NULL; + /* * Variables */ -int clicon_errno = 0; /* See enum clicon_err XXX: hide this and change to err_category */ -int clicon_suberrno = 0; /* Corresponds to errno.h XXX: change to errno */ +int clicon_errno = 0; /* See enum clicon_err XXX: hide this and change to err_category */ +int clicon_suberrno = 0; /* Corresponds to errno.h XXX: change to errno */ char clicon_err_reason[ERR_STRLEN] = {0, }; /* @@ -97,6 +116,7 @@ static struct errvec EV[] = { {"Syslog error", OE_SYSLOG}, {"Routing demon error", OE_ROUTING}, {"XML error", OE_XML}, + {"OpenSSL error", OE_SSL}, {"Plugins", OE_PLUGIN}, {"Yang error", OE_YANG}, {"FATAL", OE_FATAL}, @@ -129,6 +149,21 @@ clicon_err_reset(void) return 0; } +static struct clixon_err_cats * +find_category(int category) +{ + clixon_err_cats *cec = NULL; + + if ((cec = _err_cat_list) != NULL){ + do { + if (cec->cec_category == category) + break; + cec = NEXTQ(clixon_err_cats *, cec); + } while (cec && cec != _err_cat_list); + } + return cec; +} + /*! Report an error. * * Library routines should call this function when an error occurs. @@ -142,20 +177,22 @@ clicon_err_reset(void) * @param[in] line Inline file line number (when called from clicon_err() macro) * @param[in] category Clixon error category, See enum clicon_err * @param[in] suberr Error number, typically errno - * @param[in] reason Error string, format with argv + * @param[in] format Error string, format with argv * @see clicon_err_reset Reset the global error variables. */ -int clicon_err_fn(const char *fn, - const int line, - int category, - int suberr, - const char *format, ...) +int +clicon_err_fn(const char *fn, + const int line, + int category, + int suberr, + const char *format, ...) { va_list args; int len; char *msg = NULL; int retval = -1; - + struct clixon_err_cats *cec; + /* Set the global variables */ clicon_errno = category; clicon_suberrno = suberr; @@ -181,8 +218,27 @@ int clicon_err_fn(const char *fn, va_end(args); strncpy(clicon_err_reason, msg, ERR_STRLEN-1); - /* Actually log it */ - if (suberr){ + /* Check category callbacks */ + if ((cec = find_category(category)) != NULL && + cec->cec_logfn){ + cbuf *cb = NULL; + if ((cb = cbuf_new()) == NULL){ + fprintf(stderr, "cbuf_new: %s\n", strerror(errno)); /* dont use clicon_err here due to recursion */ + goto done; + } + if (cec->cec_logfn(cec->cec_handle, cb) < 0) + goto done; + /* Here we could take care of specific errno, like application-defined errors */ + clicon_log(LOG_ERR, "%s: %d: %s: %s: %s", + fn, + line, + clicon_strerror(category), + cbuf_get(cb), + msg); + if (cb) + cbuf_free(cb); + } + else if (suberr){ /* Actually log it */ /* Here we could take care of specific errno, like application-defined errors */ clicon_log(LOG_ERR, "%s: %d: %s: %s: %s", fn, @@ -197,7 +253,6 @@ int clicon_err_fn(const char *fn, line, clicon_strerror(category), msg); - retval = 0; done: if (msg) @@ -243,3 +298,39 @@ clicon_err_restore(void* handle) } return 0; } + +/*! Register error categories for application-based error handling + * + * @param[in] category Applies for this category (first arg to clicon_err()) + * @param[in] logfn Call att error for generating application-defined errstring + */ +int +clixon_err_cat_reg(enum clicon_err category, + void *handle, + clixon_cat_log_cb logfn) +{ + clixon_err_cats *cec; + + if ((cec = malloc(sizeof *cec)) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + return -1; + } + memset(cec, 0, sizeof *cec); + cec->cec_category = category; + cec->cec_handle = handle; + cec->cec_logfn = logfn; + INSQ(cec, _err_cat_list); + return 0; +} + +int +clixon_err_exit(void) +{ + clixon_err_cats *cec = NULL; + + while ((cec = _err_cat_list) != NULL){ + DELQ(cec, _err_cat_list, clixon_err_cats *); + free(cec); + } + return 0; +} diff --git a/lib/src/clixon_hash.c b/lib/src/clixon_hash.c index d08df841..f07cdd9d 100644 --- a/lib/src/clixon_hash.c +++ b/lib/src/clixon_hash.c @@ -90,7 +90,10 @@ #include #include -/* clicon */ +/* cligen */ +#include + +/* clixon */ #include "clixon_queue.h" #include "clixon_err.h" #include "clixon_hash.h" diff --git a/lib/src/clixon_netns.c b/lib/src/clixon_netns.c index 66dc2ac9..d3ec8740 100644 --- a/lib/src/clixon_netns.c +++ b/lib/src/clixon_netns.c @@ -37,6 +37,10 @@ #include #include +/* cligen */ +#include + +/* clixon */ #include "clixon_err.h" #include "clixon_log.h" #include "clixon_netns.h" diff --git a/lib/src/clixon_sig.c b/lib/src/clixon_sig.c index 16fbe661..16cb3176 100644 --- a/lib/src/clixon_sig.c +++ b/lib/src/clixon_sig.c @@ -48,7 +48,10 @@ #include #include -/* clicon */ +/* cligen */ +#include + +/* clixon */ #include "clixon_err.h" #include "clixon_log.h" #include "clixon_sig.h" diff --git a/lib/src/clixon_uid.c b/lib/src/clixon_uid.c index 3788bbf7..f9f4a2aa 100644 --- a/lib/src/clixon_uid.c +++ b/lib/src/clixon_uid.c @@ -55,7 +55,10 @@ #include #include -/* clicon */ +/* cligen */ +#include + +/* clixon */ #include "clixon_err.h" #include "clixon_log.h" #include "clixon_uid.h"