New feature: [Customized NETCONF error message](https://github.com/clicon/clixon/issues/454)

* Added new callback `.ca_errmsg`
* Changed signature of `clicon_netconf_error()` and `netconf_err2cb()`
This commit is contained in:
Olof hagsand 2023-10-26 14:35:39 +02:00
parent e7313fc9a2
commit 5bdad1870e
25 changed files with 258 additions and 122 deletions

View file

@ -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){

View file

@ -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: <rpc-error>
* @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:
* <msg>: "<arg>": <netconf-error> or <msg>: <netconf-error>
* @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: <rpc-error>
@ -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));

View file

@ -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: <clixon-config>...</clixon-config>
* 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;

View file

@ -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: <rpc-error>
* @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: <rpc-error>
* @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.
*/

View file

@ -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){

View file

@ -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;

View file

@ -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;