diff --git a/CHANGELOG.md b/CHANGELOG.md index b961882e..410dc887 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,7 @@ * Added Clixon example full system docker container, see [docker/system](docker/system). * Changed clixon base system container to use Alpine [docker/base](docker/base). * clixon-config YAML file has new revision: 2019-02-06. +* Added new log function: `clicon_log_xml()` for logging XML tree * Replaced all calls to (obsolete) `cli_output` with `fprintf` * Added _experimental_ config option `CLICON_CLI_UTF8` default set to 0. * CLIgen UTF8 does not work with scrolling and control editing diff --git a/apps/restconf/clixon_restconf.h b/apps/restconf/clixon_restconf.h index a8625e9f..4c93c104 100644 --- a/apps/restconf/clixon_restconf.h +++ b/apps/restconf/clixon_restconf.h @@ -51,8 +51,6 @@ int notfound(FCGX_Request *r); int conflict(FCGX_Request *r); int internal_server_error(FCGX_Request *r); int notimplemented(FCGX_Request *r); - -int clicon_debug_xml(int dbglevel, char *str, cxobj *cx); int test(FCGX_Request *r, int dbg); cbuf *readdata(FCGX_Request *r); int get_user_cookie(char *cookiestr, char *attribute, char **val); diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index fdf73f37..ec6689c4 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -284,26 +284,6 @@ notimplemented(FCGX_Request *r) return 0; } -/*! Specialization of clicon_debug with xml tree */ -int -clicon_debug_xml(int dbglevel, - char *str, - cxobj *x) -{ - int retval = -1; - cbuf *cb; - - if ((cb = cbuf_new()) == NULL) - goto done; - if (clicon_xml2cbuf(cb, x, 0, 0) < 0) - goto done; - clicon_debug(1, "%s %s", str, cbuf_get(cb)); - retval = 0; - done: - if (cb!=NULL) - cbuf_free(cb); - return retval; -} /*! * @param[in] r Fastcgi request handle diff --git a/apps/restconf/restconf_lib.h b/apps/restconf/restconf_lib.h index 8c478370..57839bc8 100644 --- a/apps/restconf/restconf_lib.h +++ b/apps/restconf/restconf_lib.h @@ -56,7 +56,6 @@ int conflict(FCGX_Request *r); int internal_server_error(FCGX_Request *r); int notimplemented(FCGX_Request *r); -int clicon_debug_xml(int dbglevel, char *str, cxobj *cx); int test(FCGX_Request *r, int dbg); cbuf *readdata(FCGX_Request *r); int get_user_cookie(char *cookiestr, char *attribute, char **val); diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index da732586..5bcafe6b 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -179,5 +179,10 @@ int xml_body_int32(cxobj *xb, int32_t *val); int xml_body_uint32(cxobj *xb, uint32_t *val); int xml_operation(char *opstr, enum operation_type *op); char *xml_operation2str(enum operation_type op); +#if defined(__GNUC__) && __GNUC__ >= 3 +int clicon_log_xml(int level, cxobj *x, char *format, ...) __attribute__ ((format (printf, 3, 4))); +#else +int clicon_log_xml(int level, cxobj *x, char *format, ...); +#endif #endif /* _CLIXON_XML_H */ diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 427e99fc..7f25330a 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -983,6 +983,11 @@ netconf_trymerge(cxobj *x, char *reason = NULL; cxobj *xc; + if (*xret == NULL){ + if ((*xret = xml_dup(x)) == NULL) + goto done; + goto ok; + } if (xml_merge(*xret, x, yspec, &reason) < 0) goto done; if (reason){ @@ -993,6 +998,7 @@ netconf_trymerge(cxobj *x, retval = 1; goto done; } + ok: retval = 0; done: if (reason) diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index f236c5f0..be277b3d 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -798,6 +798,7 @@ xml_cv_set(cxobj *x, * * @retval xmlobj if found. * @retval NULL if no such node found. + * @see xml_find_type wich is a more generic function */ cxobj * xml_find(cxobj *x_up, @@ -987,7 +988,7 @@ xml_rm(cxobj *xc) * # Here xt will be: 2 * @endcode * @see xml_child_rm - * @see xml_child_rootchild_node where xc is explicitly given + * @see xml_rootchild_node where xc is explicitly given */ int xml_rootchild(cxobj *xp, @@ -1024,7 +1025,7 @@ xml_rootchild(cxobj *xp, * @param[in] xc xml child node. Must be a child of xp * @retval 0 OK * @retval -1 Error - * @see xml_child_rootchild where an index is used to find xc + * @see xml_rootchild where an index is used to find xc */ int xml_rootchild_node(cxobj *xp, @@ -2188,6 +2189,61 @@ xml_operation2str(enum operation_type op) } } +/*! Specialization of clicon_debug with xml tree + * @param[in] level log level, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG. + * @param[in] x XML tree that is logged without prettyprint + * @param[in] format Message to print as argv. +*/ +int +clicon_log_xml(int level, + cxobj *x, + char *format, ...) +{ + va_list args; + int len; + char *msg = NULL; + cbuf *cb = NULL; + int retval = -1; + + /* Print xml as cbuf */ + if ((cb = cbuf_new()) == NULL) + goto done; + if (clicon_xml2cbuf(cb, x, 0, 0) < 0) + goto done; + + /* first round: compute length of debug message */ + va_start(args, format); + len = vsnprintf(NULL, 0, format, args); + va_end(args); + + /* allocate a message string exactly fitting the message length */ + if ((msg = malloc(len+1)) == NULL){ + fprintf(stderr, "malloc: %s\n", strerror(errno)); /* dont use clicon_err here due to recursion */ + goto done; + } + + /* second round: compute write message from format and args */ + va_start(args, format); + if (vsnprintf(msg, len+1, format, args) < 0){ + va_end(args); + fprintf(stderr, "vsnprintf: %s\n", strerror(errno)); /* dont use clicon_err here due to recursion */ + goto done; + } + va_end(args); + + /* Actually log it */ + clicon_log(level, "%s: %s", msg, cbuf_get(cb)); + + retval = 0; + done: + if (cb) + cbuf_free(cb); + if (msg) + free(msg); + return retval; +} + + /* * Turn this on to get a xml parse and pretty print test program * Usage: xpath diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index c0babd4f..6a410510 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2329,6 +2329,11 @@ xml_merge(cxobj *x0, yang_stmt *ymod; cbuf *cbr = NULL; /* Reason buffer */ + if (x0 == NULL || x1 == NULL){ + clicon_err(OE_UNIX, EINVAL, "parameters x0 or x1 is NULL"); + goto done; + goto done; + } /* Loop through children of the modification tree */ x1c = NULL; while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) { diff --git a/yang/clixon/clixon-config@2019-02-06.yang b/yang/clixon/clixon-config@2019-02-06.yang index 4cb5bed0..57b457a3 100644 --- a/yang/clixon/clixon-config@2019-02-06.yang +++ b/yang/clixon/clixon-config@2019-02-06.yang @@ -135,7 +135,10 @@ module clixon-config { leaf CLICON_CONFIGFILE{ type string; description - "Location of configuration-file for default values (this file)"; + "Location of configuration-file for default values (this file). + Default is CLIXON_DEFAULT_CONFIG=/usr/local/etc/clicon.xml + set in configure. Note that due to bootstrapping, a default + value here does not work."; } leaf-list CLICON_YANG_DIR { ordered-by user;