diff --git a/CHANGELOG.md b/CHANGELOG.md index d52aa9a6..b18ad0cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,10 @@ Expected: December 2023 ### C/CLI-API changes on existing features Developers may need to change their code +* Changed signature of `clicon_netconf_error()` and `netconf_err2cb()` + * You need to add the clixon handle as first parameter: + * `clicon_netconf_error(...)` --> `clicon_netconf_error(h, ...)` + * `netconf_err2cb(...)` --> `netconf_err2cb(h, ...)` * Changed function name for `clicon_debug` functions. You need to rename as follows: * clicon_debug() -> clixon_debug() * clicon_debug_init() -> clixon_debug_init() @@ -57,6 +61,9 @@ Developers may need to change their code ### Minor features +* New feature: [Customized NETCONF error message](https://github.com/clicon/clixon/issues/454) + * Added new callback `.ca_errmsg` + * See https://clixon-docs.readthedocs.io/en/latest/errors.html#customized-errors for more info * New `clixon-lib@2023-11-01.yang` revision * Added ignore-compare extension diff --git a/apps/backend/backend_startup.c b/apps/backend/backend_startup.c index 0056ea53..4687efc0 100644 --- a/apps/backend/backend_startup.c +++ b/apps/backend/backend_startup.c @@ -243,7 +243,7 @@ load_extraxml(clicon_handle h, if ((ret = xml_bind_yang(h, xt, YB_MODULE, yspec, &xerr)) < 0) goto done; if (ret == 0){ - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; retval = 0; goto done; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 81535b1b..f6902a2a 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -467,7 +467,7 @@ cli_dbxml(clicon_handle h, goto done; } cprintf(cb, "api-path syntax error \"%s\": ", api_path_fmt); - if (netconf_err2cb(xerr, cb) < 0) + if (netconf_err2cb(h, xerr, cb) < 0) goto done; clicon_err(OE_CFG, EINVAL, "%s", cbuf_get(cb)); goto done; @@ -946,13 +946,13 @@ compare_db_names(clicon_handle h, if (clicon_rpc_get_config(h, NULL, db1, "/", NULL, NULL, &xc1) < 0) goto done; if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } if (clicon_rpc_get_config(h, NULL, db2, "/", NULL, NULL, &xc2) < 0) goto done; if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } /* Note that XML and TEXT uses a (new) structured in-mem algorithm while @@ -1120,7 +1120,7 @@ load_config_file(clicon_handle h, if ((ret = clixon_xml_parse_file(fp, YB_NONE, yspec, &xt, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "Loading", filename); + clixon_netconf_error(h, xerr, "Loading", filename); goto done; } break; @@ -1128,7 +1128,7 @@ load_config_file(clicon_handle h, if ((ret = clixon_json_parse_file(fp, 1, YB_NONE, yspec, &xt, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "Loading", filename); + clixon_netconf_error(h, xerr, "Loading", filename); goto done; } break; @@ -1139,7 +1139,7 @@ load_config_file(clicon_handle h, if ((ret = clixon_text_syntax_parse_file(fp, YB_MODULE_NEXT, yspec, &xt, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "Loading", filename); + clixon_netconf_error(h, xerr, "Loading", filename); goto done; } break; @@ -1277,7 +1277,7 @@ save_config_file(clicon_handle h, goto done; } if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } /* get-config returns a tree. Save as tree so it can be used @@ -1661,7 +1661,7 @@ cli_copy_config(clicon_handle h, if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, NULL, &x1) < 0) goto done; if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } @@ -1874,7 +1874,7 @@ cli_process_control(clicon_handle h, if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, NULL) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 1, NULL, cligen_output, 0, 1) < 0) diff --git a/apps/cli/cli_pipe.c b/apps/cli/cli_pipe.c index 07cfed19..b945f86f 100644 --- a/apps/cli/cli_pipe.c +++ b/apps/cli/cli_pipe.c @@ -308,7 +308,7 @@ pipe_showas_fn(clicon_handle h, if ((ret = xml_bind_yang(h, xt, YB_MODULE, yspec, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "Parse top file", NULL); + clixon_netconf_error(h, xerr, "Parse top file", NULL); goto done; } break; diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 5ab50a05..ae42967c 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -321,7 +321,7 @@ expand_dbvar(void *h, goto done; if (ret == 0){ // XXX cf cli_dbxml - clixon_netconf_error(xerr, "Expand datastore symbol", NULL); + clixon_netconf_error(h, xerr, "Expand datastore symbol", NULL); goto done; } } @@ -384,7 +384,7 @@ expand_dbvar(void *h, if (clicon_rpc_get_config(h, NULL, dbstr, cbuf_get(cbxpath), nsc, NULL, &xt) < 0) goto done; if ((xe = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xe, "Get configuration", NULL); + clixon_netconf_error(h, xe, "Get configuration", NULL); goto ok; } if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, cbuf_get(cbxpath)) < 0) @@ -543,7 +543,7 @@ cli_show_common(clicon_handle h, goto done; } if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } /* Special tagged modes: strip wd:default=true attribute and (optionally) nodes associated with it */ @@ -1314,7 +1314,7 @@ cli_pagination(clicon_handle h, goto done; } if ((xerr = xpath_first(xret, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0) @@ -1764,7 +1764,7 @@ cli_show_statistics(clicon_handle h, if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, NULL) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } fprintf(stdout, "Backend:\n"); diff --git a/apps/restconf/restconf_err.c b/apps/restconf/restconf_err.c index 67242c3d..df2efb4f 100644 --- a/apps/restconf/restconf_err.c +++ b/apps/restconf/restconf_err.c @@ -234,7 +234,7 @@ api_return_err(clicon_handle h, goto done; } cprintf(cberr, "Internal error, system returned invalid error message: "); - if (netconf_err2cb(xerr, cberr) < 0) + if (netconf_err2cb(h, xerr, cberr) < 0) goto done; if (netconf_operation_failed_xml(&xerr2, "application", cbuf_get(cberr)) < 0) diff --git a/apps/restconf/restconf_main_fcgi.c b/apps/restconf/restconf_main_fcgi.c index e4e0b93b..d90bf1eb 100644 --- a/apps/restconf/restconf_main_fcgi.c +++ b/apps/restconf/restconf_main_fcgi.c @@ -187,7 +187,7 @@ restconf_main_config(clicon_handle h, if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, NULL, &xconfig) < 0) goto done; if ((xerr = xpath_first(xconfig, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get backend restconf config", NULL); + clixon_netconf_error(h, xerr, "Get backend restconf config", NULL); goto done; } /* Extract restconf configuration */ diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index 87c1b4b5..a1b07557 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -679,7 +679,7 @@ restconf_clixon_backend(clicon_handle h, if (clicon_rpc_get_config(h, pw->pw_name, "running", "/restconf", nsc, NULL, &xconfig) < 0) goto done; if ((xerr = xpath_first(xconfig, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get backend restconf config", NULL); + clixon_netconf_error(h, xerr, "Get backend restconf config", NULL); goto done; } /* Extract restconf configuration */ @@ -1017,7 +1017,7 @@ restconf_clixon_init(clicon_handle h, if ((ret = clixon_xml_parse_string(inline_config, YB_MODULE, yspec, &xrestconf, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "Inline restconf config", NULL); + clixon_netconf_error(h, xerr, "Inline restconf config", NULL); goto done; } /* Replace parent w first child */ diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index 1191d94a..f8df0243 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -1214,7 +1214,7 @@ snmp_table_getnext(clicon_handle h, if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, NULL, &xt) < 0) goto done; if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "clicon_rpc_get", NULL); + clixon_netconf_error(h, xerr, "clicon_rpc_get", NULL); goto done; } if ((xtable = xpath_first(xt, nsc, "%s", xpath)) != NULL) { diff --git a/apps/snmp/snmp_register.c b/apps/snmp/snmp_register.c index 6d9041b2..edd41689 100644 --- a/apps/snmp/snmp_register.c +++ b/apps/snmp/snmp_register.c @@ -491,7 +491,7 @@ mibyang_table_poll(clicon_handle h, if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, NULL, &xt) < 0) goto done; if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - clixon_netconf_error(xerr, "clicon_rpc_get", NULL); + clixon_netconf_error(h, xerr, "clicon_rpc_get", NULL); goto done; } if ((xtable = xpath_first(xt, nsc, "%s", xpath)) != NULL) { diff --git a/example/main/example_cli.c b/example/main/example_cli.c index 78d1174e..ea083adc 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -129,7 +129,7 @@ example_client_rpc(clicon_handle h, if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Get configuration", NULL); + clixon_netconf_error(h, xerr, "Get configuration", NULL); goto done; } /* Print result */ @@ -232,16 +232,51 @@ example_cli_yang_mount(clicon_handle h, return retval; } +/*! Callback to customize Netconf error message + * + * @param[in] h Clixon handle + * @param[in] xerr Netconf error message on the level: + * @param[out] cberr Translation from netconf err to cbuf. + * @retval 0 OK, with cberr set + * @retval -1 Error + * @see netconf_err2cb this errmsg is the same as the default + */ +int +example_cli_errmsg(clicon_handle h, + cxobj *xerr, + cbuf *cberr) +{ + int retval = -1; + cxobj *x; + + if ((x=xpath_first(xerr, NULL, "//error-type"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-tag"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-message"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL && + xml_child_nr(x) > 0){ + if (clixon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, NULL, -1, 0) < 0) + goto done; + } + if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL) + cprintf(cberr, ": %s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-path"))!=NULL) + cprintf(cberr, ": %s ", xml_body(x)); + retval = 0; + done: + return retval; +} + #ifndef CLIXON_STATIC_PLUGINS static clixon_plugin_api api = { "example", /* name */ clixon_plugin_init, /* init */ NULL, /* start */ NULL, /* exit */ - .ca_prompt=NULL, /* cli_prompthook_t */ - .ca_suspend=NULL, /* cligen_susp_cb_t */ - .ca_interrupt=NULL, /* cligen_interrupt_cb_t */ - .ca_yang_mount=example_cli_yang_mount /* RFC 8528 schema mount */ + .ca_yang_mount=example_cli_yang_mount, /* RFC 8528 schema mount */ + .ca_errmsg=example_cli_errmsg, /* customize errmsg */ }; /*! CLI plugin initialization diff --git a/lib/clixon/clixon_client.h b/lib/clixon/clixon_client.h index f31260b0..1f847581 100644 --- a/lib/clixon/clixon_client.h +++ b/lib/clixon/clixon_client.h @@ -73,7 +73,7 @@ extern "C" { clixon_handle clixon_client_init(const char *config_file); int clixon_client_terminate(clixon_handle h); -int clixon_client_lock(int sock, const char *descr, const int lock, const char *db); +int clixon_client_lock(clixon_handle h, int sock, const char *descr, const int lock, const char *db); int clixon_client_hello(int sock, const char *descr, int version); clixon_client_handle clixon_client_connect(clixon_handle h, clixon_client_type socktype, const char *dest); int clixon_client_disconnect(clixon_client_handle ch); diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h index 41e0a84c..0b44b0bc 100644 --- a/lib/clixon/clixon_netconf_lib.h +++ b/lib/clixon/clixon_netconf_lib.h @@ -153,7 +153,7 @@ typedef enum withdefaults_type withdefaults_type; * @param[in] format Format string * @param[in] arg String argument to format (optional) */ -#define clixon_netconf_error(x, f, a) clixon_netconf_error_fn(__FUNCTION__, __LINE__, (x), (f), (a)) +#define clixon_netconf_error(h, x, f, a) clixon_netconf_error_fn((h), __FUNCTION__, __LINE__, (x), (f), (a)) /* * Prototypes @@ -199,13 +199,13 @@ int netconf_trymerge(cxobj *x, yang_stmt *yspec, cxobj **xret); int netconf_module_features(clicon_handle h); int netconf_module_load(clicon_handle h); char *netconf_db_find(cxobj *xn, char *name); -int netconf_err2cb(cxobj *xerr, cbuf *cberr); +int netconf_err2cb(clicon_handle h, cxobj *xerr, cbuf *cberr); const netconf_content netconf_content_str2int(char *str); const char *netconf_content_int2str(netconf_content nr); int netconf_capabilites(clicon_handle h, cbuf *cb); int netconf_hello_server(clicon_handle h, cbuf *cb, uint32_t session_id); int netconf_hello_req(clicon_handle h, cbuf *cb); -int clixon_netconf_error_fn(const char *fn, const int line, cxobj *xerr, const char *fmt, const char *arg); +int clixon_netconf_error_fn(clicon_handle h, const char *fn, const int line, cxobj *xerr, const char *fmt, const char *arg); int clixon_netconf_internal_error(cxobj *xerr, char *msg, char *arg); int netconf_parse_uint32(char *name, char *valstr, char *defaultstr, uint32_t defaultval, cbuf *cbret, uint32_t *value); int netconf_parse_uint32_xml(char *name, char *valstr, char *defaultstr, uint32_t defaultval, cxobj **xerr, uint32_t *value); diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index 58c16f92..d9211a61 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -53,7 +53,7 @@ /*! Registered RPC callback function * - * @param[in] h Clicon handle + * @param[in] h Clixon handle * @param[in] xn Request: * @param[out] cbret Return xml tree, eg ..., + * @param[out] cberr Translation from netconf err to cbuf. + * @retval 0 OK, with cberr set + * @retval -1 Error + */ +typedef int (netconf_errmsg_t)(clicon_handle, cxobj *xerr, cbuf *cberr); + /*! Startup status for use in startup-callback * * Note that for STARTUP_ERR and STARTUP_INVALID, running runs in failsafe mode @@ -344,6 +354,7 @@ struct clixon_plugin_api{ plgextension_t *ca_extension; /* Yang extension/unknown handler */ yang_mount_t *ca_yang_mount; /* RFC 8528 schema mount */ yang_patch_t *ca_yang_patch; /* Patch yang after parse */ + netconf_errmsg_t *ca_errmsg; /* Customize error message callback */ union { struct { /* cli-specific */ cli_prompthook_t *ci_prompt; /* Prompt hook */ @@ -476,6 +487,9 @@ int clixon_plugin_yang_mount_all(clicon_handle h, cxobj *xt, int *config, valida int clixon_plugin_yang_patch_one(clixon_plugin_t *cp, clicon_handle h, yang_stmt *ymod); int clixon_plugin_yang_patch_all(clicon_handle h, yang_stmt *ymod); +int clixon_plugin_netconf_errmsg_one(clixon_plugin_t *cp, clicon_handle h, cxobj *xerr, cbuf *cberr); +int clixon_plugin_netconf_errmsg_all(clicon_handle h, cxobj *xerr, cbuf *cberr); + /* 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_call(clicon_handle h, cxobj *xe, void *arg, int *nrp, cbuf *cbret); diff --git a/lib/src/clixon_client.c b/lib/src/clixon_client.c index 2a59cbc9..f9c4dbc8 100644 --- a/lib/src/clixon_client.c +++ b/lib/src/clixon_client.c @@ -84,6 +84,7 @@ */ struct clixon_client_handle{ uint32_t cch_magic; /* magic number */ + clicon_handle cch_h; /* Clixon handle */ clixon_client_type cch_type; /* Clixon socket type */ int cch_socket; /* Input/output socket */ char *cch_descr; /* Description of socket / peer for logging XXX NYI */ @@ -93,7 +94,7 @@ struct clixon_client_handle{ /*! Check struct magic number for sanity checks * - * @param[in] h Clicon client handle + * @param[in] h Clixon client handle * @retval 0 Sanity check OK * @retval -1 Sanity check failed */ @@ -146,6 +147,7 @@ clixon_client_terminate(clicon_handle h) /*! Send a lock request (internal) * + * @param[in] h Clixon handle * @param[in] sock Open socket * @param[in] descr Description of peer for logging * @param[in] lock 0: unlock, 1: lock @@ -154,10 +156,11 @@ clixon_client_terminate(clicon_handle h) * @retval -1 Error */ int -clixon_client_lock(int sock, - const char *descr, - const int lock, - const char *db) +clixon_client_lock(clixon_handle h, + int sock, + const char *descr, + const int lock, + const char *db) { int retval = -1; cxobj *xret = NULL; @@ -195,7 +198,7 @@ clixon_client_lock(int sock, goto done; if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL){ xd = xml_parent(xd); /* point to rpc-reply */ - clixon_netconf_error(xd, "Get config", NULL); + clixon_netconf_error(h, xd, "Get config", NULL); goto done; /* Not fatal */ } retval = 0; @@ -364,6 +367,7 @@ clixon_client_connect(clicon_handle h, memset(cch, 0, sz); cch->cch_magic = CLIXON_CLIENT_MAGIC; cch->cch_type = socktype; + cch->cch_h = h; switch (socktype){ case CLIXON_CLIENT_IPC: if (clicon_rpc_connect(h, &cch->cch_socket) < 0) @@ -469,6 +473,7 @@ clixon_xml_bottom(cxobj *xtop, /*! Internal function to construct a get-config and query a value from the backend * + * @param[in] h Clixon handle * @param[in] sock Socket * @param[in] descr Description of peer for logging * @param[in] namespace Default namespace used for non-prefixed entries in xpath. (Alt use nsc) @@ -479,7 +484,8 @@ clixon_xml_bottom(cxobj *xtop, * @note configurable netconf framing type, now hardwired to 0 */ static int -clixon_client_get_xdata(int sock, +clixon_client_get_xdata(clicon_handle h, + int sock, const char *descr, const char *namespace, const char *xpath, @@ -535,7 +541,7 @@ clixon_client_get_xdata(int sock, goto done; if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL){ xd = xml_parent(xd); /* point to rpc-reply */ - clixon_netconf_error(xd, "Get config", NULL); + clixon_netconf_error(h, xd, "Get config", NULL); goto done; /* Not fatal */ } else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL){ @@ -561,6 +567,7 @@ clixon_client_get_xdata(int sock, /*! Generic get value of body * + * @param[in] h Clixon handle * @param[in] sock Open socket * @param[in] descr Description of peer for logging * @param[in] namespace Default namespace used for non-prefixed entries in xpath. @@ -570,7 +577,8 @@ clixon_client_get_xdata(int sock, * @retval -1 Error */ static int -clixon_client_get_body_val(int sock, +clixon_client_get_body_val(clicon_handle h, + int sock, const char *descr, const char *namespace, const char *xpath, @@ -585,7 +593,7 @@ clixon_client_get_body_val(int sock, clicon_err(OE_XML, EINVAL, "Expected val"); goto done; } - if (clixon_client_get_xdata(sock, descr, namespace, xpath, &xdata) < 0) + if (clixon_client_get_xdata(h, sock, descr, namespace, xpath, &xdata) < 0) goto done; if (xdata == NULL){ clicon_err(OE_XML, EINVAL, "No xml obj found"); @@ -632,7 +640,7 @@ clixon_client_get_bool(clixon_client_handle ch, uint8_t val0=0; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; if ((ret = parse_bool(val, &val0, &reason)) < 0){ @@ -673,7 +681,7 @@ clixon_client_get_str(clixon_client_handle ch, char *val = NULL; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; strncpy(rval, val, n-1); @@ -705,7 +713,7 @@ clixon_client_get_uint8(clixon_client_handle ch, int ret; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint8(val, rval, &reason)) < 0){ @@ -745,7 +753,7 @@ clixon_client_get_uint16(clixon_client_handle ch, int ret; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint16(val, rval, &reason)) < 0){ @@ -785,7 +793,7 @@ clixon_client_get_uint32(clixon_client_handle ch, int ret; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; if (val == NULL){ @@ -830,7 +838,7 @@ clixon_client_get_uint64(clixon_client_handle ch, int ret; clixon_debug(CLIXON_DBG_DEFAULT, "%s", __FUNCTION__); - if (clixon_client_get_body_val(cch->cch_socket, cch->cch_descr, + if (clixon_client_get_body_val(cch->cch_h, cch->cch_socket, cch->cch_descr, namespace, xpath, &val) < 0) goto done; if ((ret = parse_uint64(val, rval, &reason)) < 0){ diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 9f0e0f44..fc77e8c8 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1747,46 +1747,51 @@ netconf_db_find(cxobj *xn, return db; } -/*! Generate netconf error msg to cbuf to use in string printout or logs +/*! Generate netconf error msg to cbuf using callback to use in string printout or logs * + * If no callback is registered, a default error message is genereated * @param[in] xerr Netconf error message on the level: - * @param[in,out] cberr Translation from netconf err to cbuf. - * @retval 0 OK, with cberr set - * @retval -1 Error + * @param[out] cberr Translation from netconf err to cbuf. + * @retval 0 OK, with cberr set + * @retval -1 Error * @code * cbuf *cb = NULL; * if ((cb = cbuf_new()) ==NULL){ * err; - * if (netconf_err2cb(xerr, cb) < 0) + * if (netconf_err2cb(h, xerr, cb) < 0) * err; * printf("%s", cbuf_get(cb)); * cbuf_free(cb); * @endcode * @see clixon_netconf_error_fn - * XXX does not support prefixes properly */ int -netconf_err2cb(cxobj *xerr, - cbuf *cberr) +netconf_err2cb(clicon_handle h, + cxobj *xerr, + cbuf *cberr) { int retval = -1; cxobj *x; - if ((x=xpath_first(xerr, NULL, "//error-type"))!=NULL) - cprintf(cberr, "%s ", xml_body(x)); - if ((x=xpath_first(xerr, NULL, "//error-tag"))!=NULL) - cprintf(cberr, "%s ", xml_body(x)); - if ((x=xpath_first(xerr, NULL, "//error-message"))!=NULL) - cprintf(cberr, "%s ", xml_body(x)); - if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL && - xml_child_nr(x) > 0){ - if (clixon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, NULL, -1, 0) < 0) - goto done; + if (clixon_plugin_netconf_errmsg_all(h, xerr, cberr) < 0) + goto done; + if (cbuf_len(cberr) == 0){ + if ((x=xpath_first(xerr, NULL, "//error-type"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-tag"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-message"))!=NULL) + cprintf(cberr, "%s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-info")) != NULL && + xml_child_nr(x) > 0){ + if (clixon_xml2cbuf(cberr, xml_child_i(x, 0), 0, 0, NULL, -1, 0) < 0) + goto done; + } + if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL) + cprintf(cberr, ": %s ", xml_body(x)); + if ((x=xpath_first(xerr, NULL, "//error-path"))!=NULL) + cprintf(cberr, ": %s ", xml_body(x)); } - if ((x=xpath_first(xerr, NULL, "//error-app-tag"))!=NULL) - cprintf(cberr, ": %s ", xml_body(x)); - if ((x=xpath_first(xerr, NULL, "//error-path"))!=NULL) - cprintf(cberr, ": %s ", xml_body(x)); retval = 0; done: return retval; @@ -1953,6 +1958,7 @@ netconf_hello_server(clicon_handle h, * * Get a text error message from netconf error message and generate error on the form: * : "": or : + * @param[in] h Clixon handle * @param[in] fn Inline function name (when called from clicon_err() macro) * @param[in] line Inline file line number (when called from clicon_err() macro) * @param[in] xerr Netconf error xml tree on the form: @@ -1961,13 +1967,15 @@ netconf_hello_server(clicon_handle h, * @retval 0 OK * @retval -1 Error * @see netconf_err2cb + * ßee clixon_netconf_error macro */ int -clixon_netconf_error_fn(const char *fn, - const int line, - cxobj *xerr, - const char *msg, - const char *arg) +clixon_netconf_error_fn(clicon_handle h, + const char *fn, + const int line, + cxobj *xerr, + const char *msg, + const char *arg) { int retval = -1; cbuf *cb = NULL; @@ -1983,7 +1991,7 @@ clixon_netconf_error_fn(const char *fn, cprintf(cb, ": "); } - if (netconf_err2cb(xerr, cb) < 0) + if (netconf_err2cb(h, xerr, cb) < 0) goto done; #if 0 /* More verbose output for debugging */ clicon_log(LOG_ERR, "%s: %d: %s", fn, line, cbuf_get(cb)); diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index a8344e7f..950bebfc 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -242,16 +242,18 @@ clicon_option_dump1(clicon_handle h, /*! Open and parse single config file * - * @param[in] filename + * @param[in] h Clixon handle + * @param[in] filename * @param[in] yspec * @param[out] xconfig Pointer to xml config tree. Should be freed by caller * @retval 0 OK * @retval -1 Error */ static int -parse_configfile_one(const char *filename, - yang_stmt *yspec, - cxobj **xconfig) +parse_configfile_one(clicon_handle h, + const char *filename, + yang_stmt *yspec, + cxobj **xconfig) { int retval = -1; FILE *fp = NULL; @@ -273,10 +275,10 @@ parse_configfile_one(const char *filename, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; /* Here one could make it more relaxing to not quit on unrecognized option? */ - clixon_netconf_error(xerr, NULL, NULL); + clixon_netconf_error(h, xerr, NULL, NULL); goto done; } /* Ensure a single root */ @@ -424,7 +426,7 @@ parse_configfile(clicon_handle h, clixon_debug(CLIXON_DBG_DETAIL, "%s: Reading config file %s", __FUNCTION__, filename); /* Parse main config file */ - if (parse_configfile_one(filename, yspec, &xt) < 0) + if (parse_configfile_one(h, filename, yspec, &xt) < 0) goto done; /* xt is a single-rooted: ... * If no override (eg from command-line) @@ -444,7 +446,7 @@ parse_configfile(clicon_handle h, /* Loop through files */ for (i = 0; i < ndp; i++){ snprintf(filename1, sizeof(filename1), "%s/%s", extraconfdir, dp[i].d_name); - if (parse_configfile_one(filename1, yspec, &xe) < 0) + if (parse_configfile_one(h, filename1, yspec, &xe) < 0) goto done; /* Merge objects from extrafile into main, xml_merge cannot be used due to special cases */ if (merge_control_xml(h, xt, xe) < 0) @@ -474,7 +476,7 @@ parse_configfile(clicon_handle h, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret)); goto done; diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index e51b8a27..2124822b 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -1163,6 +1163,68 @@ clixon_plugin_yang_patch_all(clicon_handle h, return retval; } +/*! Callback plugin to customize Netconf error message + * + * @param[in] cp Plugin handle + * @param[in] h Clixon handle + * @param[in] xerr Netconf error message on the level: + * @param[out] cberr Translation from netconf err to cbuf. + * @retval 0 OK + * @retval -1 Error + */ +int +clixon_plugin_netconf_errmsg_one(clixon_plugin_t *cp, + clicon_handle h, + cxobj *xerr, + cbuf *cberr) +{ + int retval = -1; + netconf_errmsg_t *fn; + void *wh = NULL; + + if ((fn = cp->cp_api.ca_errmsg) != NULL){ + wh = NULL; + if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0) + goto done; + if (fn(h, xerr, cberr) < 0) { + if (clicon_errno < 0) + clicon_log(LOG_WARNING, "%s: Internal error: Yang patch callback in plugin: %s returned -1 but did not make a clicon_err call", + __FUNCTION__, cp->cp_name); + goto done; + } + if (plugin_context_check(h, &wh, cp->cp_name, __FUNCTION__) < 0) + goto done; + } + retval = 0; + done: + return retval; +} + +/*! Call plugin customize Netconf error message + * + * @param[in] h Clixon handle + * @param[in] xerr Netconf error message on the level: + * @param[out] cberr Translation from netconf err to cbuf. + * @retval 0 OK + * @retval -1 Error + */ +int +clixon_plugin_netconf_errmsg_all(clicon_handle h, + cxobj *xerr, + cbuf *cberr) +{ + int retval = -1; + clixon_plugin_t *cp = NULL; + + while ((cp = clixon_plugin_each(h, cp)) != NULL) { + if (clixon_plugin_netconf_errmsg_one(cp, h, xerr, cberr) < 0) + goto done; + } + retval = 0; + done: + return retval; +} + /*-------------------------------------------------------------------- * RPC callbacks for both client/frontend and backend plugins. */ diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 39423535..54b310c7 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -670,7 +670,7 @@ clicon_rpc_edit_config(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Editing configuration", NULL); + clixon_netconf_error(h, xerr, "Editing configuration", NULL); goto done; } retval = 0; @@ -732,7 +732,7 @@ clicon_rpc_copy_config(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Copying configuration", NULL); + clixon_netconf_error(h, xerr, "Copying configuration", NULL); goto done; } retval = 0; @@ -790,7 +790,7 @@ clicon_rpc_delete_config(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Deleting configuration", NULL); + clixon_netconf_error(h, xerr, "Deleting configuration", NULL); goto done; } retval = 0; @@ -844,7 +844,7 @@ clicon_rpc_lock(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Locking configuration", NULL); + clixon_netconf_error(h, xerr, "Locking configuration", NULL); goto done; } retval = 0; @@ -898,7 +898,7 @@ clicon_rpc_unlock(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Configuration unlock", NULL); + clixon_netconf_error(h, xerr, "Configuration unlock", NULL); goto done; } retval = 0; @@ -936,7 +936,7 @@ clicon_rpc_unlock(clicon_handle h, * if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0) * err; * if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - * clixon_netconf_error(xerr, "clicon_rpc_get", NULL); + * clixon_netconf_error(h, xerr, "clicon_rpc_get", NULL); * err; * } * if (xt) @@ -984,7 +984,7 @@ clicon_rpc_get(clicon_handle h, * if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0) * err; * if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ - * clixon_netconf_error(xerr, "clicon_rpc_get", NULL); + * clixon_netconf_error(h, xerr, "clicon_rpc_get", NULL); * err; * } * if (xt) @@ -1329,7 +1329,7 @@ clicon_rpc_close_session(clicon_handle h) clicon_client_socket_set(h, -1); } if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Close session", NULL); + clixon_netconf_error(h, xerr, "Close session", NULL); goto done; } retval = 0; @@ -1383,7 +1383,7 @@ clicon_rpc_kill_session(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Kill session", NULL); + clixon_netconf_error(h, xerr, "Kill session", NULL); goto done; } retval = 0; @@ -1439,7 +1439,7 @@ clicon_rpc_validate(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL); + clixon_netconf_error(h, xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL); retval = 0; goto done; } @@ -1546,7 +1546,7 @@ clicon_rpc_commit(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL); + clixon_netconf_error(h, xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL); retval = 0; goto done; } @@ -1605,7 +1605,7 @@ clicon_rpc_discard_changes(clicon_handle h) if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Discard changes", NULL); + clixon_netconf_error(h, xerr, "Discard changes", NULL); goto done; } retval = 0; @@ -1670,7 +1670,7 @@ clicon_rpc_create_subscription(clicon_handle h, if (clicon_rpc_msg_persistent(h, msg, &xret, s0) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Create subscription", NULL); + clixon_netconf_error(h, xerr, "Create subscription", NULL); goto done; } retval = 0; @@ -1725,7 +1725,7 @@ clicon_rpc_debug(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Debug", NULL); + clixon_netconf_error(h, xerr, "Debug", NULL); goto done; } if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){ @@ -1791,7 +1791,7 @@ clicon_rpc_restconf_debug(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Debug", NULL); + clixon_netconf_error(h, xerr, "Debug", NULL); goto done; } if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){ @@ -1880,7 +1880,7 @@ clicon_hello_req(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Hello", NULL); + clixon_netconf_error(h, xerr, "Hello", NULL); goto done; } if ((x = xpath_first(xret, NULL, "hello/session-id")) == NULL){ @@ -1944,7 +1944,7 @@ clicon_rpc_restart_plugin(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret) < 0) goto done; if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ - clixon_netconf_error(xerr, "Debug", NULL); + clixon_netconf_error(h, xerr, "Debug", NULL); goto done; } if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){ diff --git a/lib/src/clixon_xml_bind.c b/lib/src/clixon_xml_bind.c index 38029056..eacfc560 100644 --- a/lib/src/clixon_xml_bind.c +++ b/lib/src/clixon_xml_bind.c @@ -894,7 +894,7 @@ xml_bind_yang_rpc_reply(clicon_handle h, goto done; } cprintf(cberr, "Internal error in backend reply: "); - if (netconf_err2cb(xerr1, cberr) < 0) + if (netconf_err2cb(h, xerr1, cberr) < 0) goto done; if (xerr && netconf_operation_failed_xml(xerr, "application", cbuf_get(cberr)) < 0) goto done; diff --git a/lib/src/clixon_xml_changelog.c b/lib/src/clixon_xml_changelog.c index f009e42e..e0da821f 100644 --- a/lib/src/clixon_xml_changelog.c +++ b/lib/src/clixon_xml_changelog.c @@ -468,7 +468,7 @@ clixon_xml_changelog_init(clicon_handle h) clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xret, cbret) < 0) + if (netconf_err2cb(h, xret, cbret) < 0) goto done; clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret)); goto done; diff --git a/util/clixon_util_path.c b/util/clixon_util_path.c index 0f0c4dff..012c1a75 100644 --- a/util/clixon_util_path.c +++ b/util/clixon_util_path.c @@ -231,7 +231,7 @@ main(int argc, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cb) < 0) + if (netconf_err2cb(h, xerr, cb) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cb)); goto done; @@ -253,7 +253,7 @@ main(int argc, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cb) < 0) + if (netconf_err2cb(h, xerr, cb) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cb)); goto done; diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c index 00f2eb83..938a2ba9 100644 --- a/util/clixon_util_xml.c +++ b/util/clixon_util_xml.c @@ -94,7 +94,7 @@ validate_tree(clicon_handle h, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret)); goto done; @@ -278,7 +278,7 @@ main(int argc, goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "Parse top file", NULL); + clixon_netconf_error(h, xerr, "Parse top file", NULL); goto done; } if (validate_tree(h, xtop, yspec) < 0) @@ -304,7 +304,7 @@ main(int argc, if ((ret = clixon_json_parse_file(fp, 1, top_input_filename?YB_PARENT:YB_MODULE, yspec, &xt, &xerr)) < 0) goto done; if (ret == 0){ - clixon_netconf_error(xerr, "util_xml", NULL); + clixon_netconf_error(h, xerr, "util_xml", NULL); goto done; } } @@ -320,7 +320,7 @@ main(int argc, goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "util_xml", NULL); + clixon_netconf_error(h, xerr, "util_xml", NULL); goto done; } } diff --git a/util/clixon_util_xml_mod.c b/util/clixon_util_xml_mod.c index d4f35a48..6d9e092d 100644 --- a/util/clixon_util_xml_mod.c +++ b/util/clixon_util_xml_mod.c @@ -194,7 +194,7 @@ main(int argc, char **argv) goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "Parsing base xml", NULL); + clixon_netconf_error(h, xerr, "Parsing base xml", NULL); goto done; } /* Get base subtree by xpath */ @@ -216,7 +216,7 @@ main(int argc, char **argv) goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "Parsing secondary xml", NULL); + clixon_netconf_error(h, xerr, "Parsing secondary xml", NULL); goto done; } break; @@ -227,7 +227,7 @@ main(int argc, char **argv) goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "Parsing secondary xml", NULL); + clixon_netconf_error(h, xerr, "Parsing secondary xml", NULL); goto done; } if (xpath == NULL) @@ -250,7 +250,7 @@ main(int argc, char **argv) goto done; } if (ret == 0){ - clixon_netconf_error(xerr, "Parsing secondary xml", NULL); + clixon_netconf_error(h, xerr, "Parsing secondary xml", NULL); goto done; } /* Get secondary subtree by xpath */ diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c index 7af0f809..8b267841 100644 --- a/util/clixon_util_xpath.c +++ b/util/clixon_util_xpath.c @@ -326,7 +326,7 @@ main(int argc, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret)); goto done; @@ -349,7 +349,7 @@ main(int argc, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (netconf_err2cb(xerr, cbret) < 0) + if (netconf_err2cb(h, xerr, cbret) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret)); goto done;