* Added new functions: xml_tree_equal and xpath2xml
* RFC 8528 yang schema mount-points: * Made expand_dbvar and cli_dbxml mountpoint-aware (RFC 8528) * autocli supportgenerate * Made api_path2xml and xml2api_path mount-point-aware * Temporar fix in clixon_custom.h: XPATH_CANONICAL_SKIP_CHECK * `xml2xpath()`: Added `apostrophe` as 4th parameter, default 0 * removed extra assert.h includes
This commit is contained in:
parent
1e136bc9df
commit
da2edceb7e
37 changed files with 658 additions and 145 deletions
|
|
@ -1160,7 +1160,7 @@ text_modify_top(clicon_handle h,
|
|||
* @param[out] cbret Initialized cligen buffer. On exit contains XML if retval == 0
|
||||
* @retval 1 OK
|
||||
* @retval 0 Failed, cbret contains error xml message
|
||||
* @retval -1 Error
|
||||
* @retval -1 Error
|
||||
* The xml may contain the "operation" attribute which defines the operation.
|
||||
* @code
|
||||
* cxobj *xt;
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ clixon_event_unreg_fd(int s,
|
|||
}
|
||||
|
||||
/*! Call a callback function at an absolute time
|
||||
*
|
||||
* @param[in] t Absolute (not relative!) timestamp when callback is called
|
||||
* @param[in] fn Function to call at time t
|
||||
* @param[in] arg Argument to function fn
|
||||
|
|
@ -241,11 +242,9 @@ clixon_event_unreg_fd(int s,
|
|||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Note that the timestamp is an absolute timestamp, not relative.
|
||||
* Note also that the callback is not periodic, you need to make a new
|
||||
* registration for each period, see example above.
|
||||
* Note also that the first argument to fn is a dummy, just to get the same
|
||||
* signature as for file-descriptor callbacks.
|
||||
* @note The timestamp is an absolute timestamp, not relative.
|
||||
* @note The callback is not periodic, you need to make a new registration for each period, see example.
|
||||
* @note The first argument to fn is a dummy, just to get the same signature as for file-descriptor callbacks.
|
||||
* @see clixon_event_reg_fd
|
||||
* @see clixon_event_unreg_timeout
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1045,7 +1045,7 @@ netconf_missing_choice_xml(cxobj **xret,
|
|||
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
/* error-path: Path to the element with the missing choice. */
|
||||
if (xml2xpath(x, NULL, 0, &path) < 0)
|
||||
if (xml2xpath(x, NULL, 0, 0, &path) < 0)
|
||||
goto done;
|
||||
if (xml_chardata_encode(&encpath, "%s", path) < 0)
|
||||
goto done;
|
||||
|
|
@ -1407,7 +1407,7 @@ netconf_data_not_unique_xml(cxobj **xret,
|
|||
if (cvec_len(cvk)){
|
||||
if ((xinfo = xml_new("error-info", xerr, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (xml2xpath(x, NULL, 0, &path) < 0)
|
||||
if (xml2xpath(x, NULL, 0, 0, &path) < 0)
|
||||
goto done;
|
||||
if (xml_chardata_encode(&encpath, "%s", path) < 0)
|
||||
goto done;
|
||||
|
|
@ -1465,7 +1465,7 @@ netconf_minmax_elements_xml(cxobj **xret,
|
|||
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (xml_parent(xp)){ /* Dont include root, eg <config> */
|
||||
if (xml2xpath(xp, NULL, 0, &path) < 0)
|
||||
if (xml2xpath(xp, NULL, 0, 0, &path) < 0)
|
||||
goto done;
|
||||
if (xml_chardata_encode(&encpath, "%s", path) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
|
@ -97,9 +96,12 @@
|
|||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_xml_vec.h"
|
||||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_yang_schema_mount.h"
|
||||
#include "clixon_path.h"
|
||||
#include "clixon_api_path_parse.h"
|
||||
#include "clixon_instance_id_parse.h"
|
||||
|
|
@ -664,6 +666,8 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
cvec *nsc = NULL;
|
||||
char *val1;
|
||||
char *decval;
|
||||
int ret;
|
||||
int root;
|
||||
|
||||
cprintf(xpath, "/");
|
||||
/* Initialize namespace context */
|
||||
|
|
@ -673,6 +677,7 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
root = 1; /* root or mountpoint */
|
||||
for (i=offset; i<cvec_len(api_path); i++){
|
||||
cv = cvec_i(api_path, i);
|
||||
nodeid = cv_name_get(cv);
|
||||
|
|
@ -698,16 +703,16 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
}
|
||||
namespace = yang_find_mynamespace(ymod); /* change namespace */
|
||||
}
|
||||
if (i == offset && ymod) /* root */
|
||||
if (root && ymod) /* root */
|
||||
y = yang_find_datanode(ymod, name);
|
||||
else
|
||||
y = yang_find_datanode(y, name);
|
||||
root = 0;
|
||||
if (y == NULL){
|
||||
if (xerr && netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get XML/xpath prefix given namespace.
|
||||
* note different from api-path prefix
|
||||
*/
|
||||
|
|
@ -790,6 +795,23 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
cprintf(xpath, "%s:", xprefix);
|
||||
cprintf(xpath, "%s", name);
|
||||
}
|
||||
|
||||
/* If x/y is mountpoint, pass moint yspec to children */
|
||||
if ((ret = yang_schema_mount_point(y)) < 0)
|
||||
goto done;
|
||||
if (ret == 1){
|
||||
yang_stmt *y1 = NULL;
|
||||
if (xml_nsctx_yangspec(yspec, &nsc) < 0)
|
||||
goto done;
|
||||
if (yang_mount_get(y, cbuf_get(xpath), &y1) < 0)
|
||||
goto done;
|
||||
if (y1 == NULL || yang_keyword_get(y1) != Y_SPEC){
|
||||
clicon_err(OE_YANG, 0, "No such mountpoint %s", cbuf_get(xpath));
|
||||
goto done;
|
||||
}
|
||||
yspec = y1;
|
||||
root = 1;
|
||||
}
|
||||
if (prefix){
|
||||
free(prefix);
|
||||
prefix = NULL;
|
||||
|
|
@ -826,7 +848,7 @@ api_path2xpath_cvv(cvec *api_path,
|
|||
* @param[in] api_path URI-encoded path expression" (RFC8040 3.5.3)
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] xpath xpath (use free() to deallocate)
|
||||
* @param[out] nsc Namespace context of xpath (free w xml_nsctx_free)
|
||||
* @param[out] nsc Namespace context of xpath (free w cvec_free)
|
||||
* @param[out] xerr Netconf error message
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid api_path or associated XML, netconf called
|
||||
|
|
@ -897,9 +919,10 @@ api_path2xpath(char *api_path,
|
|||
}
|
||||
|
||||
/*! Create xml tree from api-path as vector
|
||||
*
|
||||
* @param[in] vec APIpath as char* vector
|
||||
* @param[in] nvec Length of vec
|
||||
* @param[in] x0 Xpath tree so far
|
||||
* @param[in] x0 XML tree so far
|
||||
* @param[in] y0 Yang spec for x0
|
||||
* @param[in] nodeclass Set to schema nodes, data nodes, etc
|
||||
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
|
||||
|
|
@ -945,6 +968,9 @@ api_path2xml_vec(char **vec,
|
|||
char *namespace = NULL;
|
||||
cbuf *cberr = NULL;
|
||||
char *val = NULL;
|
||||
int ret;
|
||||
char *xpath = NULL;
|
||||
cvec *nsc = NULL;
|
||||
|
||||
if ((nodeid = vec[0]) == NULL || strlen(nodeid)==0){
|
||||
if (xbotp)
|
||||
|
|
@ -1112,6 +1138,27 @@ api_path2xml_vec(char **vec,
|
|||
if (xmlns_set(x, NULL, namespace) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* If x/y is mountpoint, pass moint yspec to children */
|
||||
if ((ret = yang_schema_mount_point(y)) < 0)
|
||||
goto done;
|
||||
if (ret == 1){
|
||||
yang_stmt *y1 = NULL;
|
||||
if (xml_nsctx_yangspec(ys_spec(y), &nsc) < 0)
|
||||
goto done;
|
||||
if (xml2xpath(x, nsc, 0, 1, &xpath) < 0) // XXX should be canonical
|
||||
goto done;
|
||||
if (xpath == NULL){
|
||||
clicon_err(OE_YANG, 0, "No xpath from xml");
|
||||
goto done;
|
||||
}
|
||||
if (yang_mount_get(y, xpath, &y1) < 0)
|
||||
goto done;
|
||||
if (y1 == NULL){
|
||||
clicon_err(OE_YANG, 0, "No such mountpoint %s", xpath);
|
||||
goto done;
|
||||
}
|
||||
y = y1;
|
||||
}
|
||||
if ((retval = api_path2xml_vec(vec+1, nvec-1,
|
||||
x, y,
|
||||
nodeclass, strict,
|
||||
|
|
@ -1121,6 +1168,10 @@ api_path2xml_vec(char **vec,
|
|||
retval = 1; /* OK */
|
||||
done:
|
||||
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (nsc)
|
||||
cvec_free(nsc);
|
||||
if (cberr)
|
||||
cbuf_free(cberr);
|
||||
if (prefix)
|
||||
|
|
@ -1218,7 +1269,6 @@ api_path2xml(char *api_path,
|
|||
if (xmlns_assign(xroot) < 0)
|
||||
goto done;
|
||||
}
|
||||
// ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (cberr)
|
||||
|
|
@ -1241,7 +1291,6 @@ api_path2xml(char *api_path,
|
|||
*/
|
||||
int
|
||||
xml2api_path_1(cxobj *x,
|
||||
|
||||
cbuf *cb)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@
|
|||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ set_signal_flags(int signo,
|
|||
*oldhandler = sold.sa_handler;
|
||||
return 0;
|
||||
#elif defined(HAVE_SIGVEC)
|
||||
assert(0);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@
|
|||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
|
|||
|
|
@ -314,8 +314,8 @@ xml_diff1(cxobj *x0,
|
|||
cxobj *x1c = NULL; /* x1 child */
|
||||
yang_stmt *yc0;
|
||||
yang_stmt *yc1;
|
||||
char *b0;
|
||||
char *b1;
|
||||
char *b2;
|
||||
int eq;
|
||||
|
||||
/* Traverse x0 and x1 in lock-step */
|
||||
|
|
@ -366,12 +366,12 @@ xml_diff1(cxobj *x0,
|
|||
else
|
||||
if (yc0 && yang_keyword_get(yc0) == Y_LEAF){
|
||||
/* if x0c and x1c are leafs w bodies, then they may be changed */
|
||||
b1 = xml_body(x0c);
|
||||
b2 = xml_body(x1c);
|
||||
if (b1 == NULL && b2 == NULL)
|
||||
b0 = xml_body(x0c);
|
||||
b1 = xml_body(x1c);
|
||||
if (b0 == NULL && b1 == NULL)
|
||||
;
|
||||
else if (b1 == NULL || b2 == NULL
|
||||
|| strcmp(b1, b2) != 0
|
||||
else if (b0 == NULL || b1 == NULL
|
||||
|| strcmp(b0, b1) != 0
|
||||
){
|
||||
if (cxvec_append(x0c, changed_x0, changedlen) < 0)
|
||||
goto done;
|
||||
|
|
@ -396,7 +396,7 @@ xml_diff1(cxobj *x0,
|
|||
}
|
||||
|
||||
/*! Compute differences between two xml trees
|
||||
* @param[in] yspec Yang specification
|
||||
*
|
||||
* @param[in] x0 First XML tree
|
||||
* @param[in] x1 Second XML tree
|
||||
* @param[out] first Pointervector to XML nodes existing in only first tree
|
||||
|
|
@ -406,11 +406,13 @@ xml_diff1(cxobj *x0,
|
|||
* @param[out] changed_x0 Pointervector to XML nodes changed orig value
|
||||
* @param[out] changed_x1 Pointervector to XML nodes changed wanted value
|
||||
* @param[out] changedlen Length of changed vector
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* All xml vectors should be freed after use.
|
||||
* @see xml_tree_equal same algorithm but do not bother with what has changed
|
||||
*/
|
||||
int
|
||||
xml_diff(yang_stmt *yspec,
|
||||
cxobj *x0,
|
||||
xml_diff(cxobj *x0,
|
||||
cxobj *x1,
|
||||
cxobj ***first,
|
||||
int *firstlen,
|
||||
|
|
@ -448,6 +450,85 @@ xml_diff(yang_stmt *yspec,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Compute if two XML trees are equal or not
|
||||
*
|
||||
* @param[in] x0 First XML tree
|
||||
* @param[in] x1 Second XML tree
|
||||
* @retval 1 Not equal
|
||||
* @retval 0 Equal
|
||||
* @see xml_diff
|
||||
*/
|
||||
int
|
||||
xml_tree_equal(cxobj *x0,
|
||||
cxobj *x1)
|
||||
{
|
||||
int retval = 1; /* Not equal */
|
||||
int eq;
|
||||
yang_stmt *yc0;
|
||||
yang_stmt *yc1;
|
||||
char *b0;
|
||||
char *b1;
|
||||
cxobj *x0c = NULL; /* x0 child */
|
||||
cxobj *x1c = NULL; /* x1 child */
|
||||
|
||||
/* Traverse x0 and x1 in lock-step */
|
||||
x0c = x1c = NULL;
|
||||
x0c = xml_child_each(x0, x0c, CX_ELMNT);
|
||||
x1c = xml_child_each(x1, x1c, CX_ELMNT);
|
||||
for (;;){
|
||||
if (x0c == NULL && x1c == NULL)
|
||||
goto ok;
|
||||
else if (x0c == NULL){
|
||||
goto done;
|
||||
}
|
||||
else if (x1c == NULL){
|
||||
goto done;
|
||||
}
|
||||
/* Both x0c and x1c exists, check if they are yang-equal. */
|
||||
eq = xml_cmp(x0c, x1c, 0, 0, NULL);
|
||||
if (eq < 0){
|
||||
goto done;
|
||||
}
|
||||
else if (eq > 0){
|
||||
goto done;
|
||||
}
|
||||
else{ /* equal */
|
||||
/* xml-spec NULL could happen with anydata children for example,
|
||||
* if so, continute compare children but without yang
|
||||
*/
|
||||
yc0 = xml_spec(x0c);
|
||||
yc1 = xml_spec(x1c);
|
||||
if (yc0 && yc1 && yc0 != yc1){ /* choice */
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (yc0 && yang_keyword_get(yc0) == Y_LEAF){
|
||||
/* if x0c and x1c are leafs w bodies, then they may be changed */
|
||||
b0 = xml_body(x0c);
|
||||
b1 = xml_body(x1c);
|
||||
if (b0 == NULL && b1 == NULL)
|
||||
;
|
||||
else if (b0 == NULL || b1 == NULL
|
||||
|| strcmp(b0, b1) != 0
|
||||
){
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eq = xml_tree_equal(x0c, x1c);
|
||||
if (eq)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
x0c = xml_child_each(x0, x0c, CX_ELMNT);
|
||||
x1c = xml_child_each(x1, x1c, CX_ELMNT);
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Prune everything that does not pass test or have at least a child* does not
|
||||
*
|
||||
* @param[in] xt XML tree with some node marked
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ xml_nsctx_namespace_netconf_default(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Create and initialize XML namespace context
|
||||
*
|
||||
* @param[in] prefix Namespace prefix, or NULL for default
|
||||
* @param[in] ns Set this namespace. If NULL create empty nsctx
|
||||
* @retval nsc Return namespace context in form of a cvec
|
||||
|
|
@ -126,6 +127,7 @@ xml_nsctx_init(char *prefix,
|
|||
}
|
||||
|
||||
/*! Free XML namespace context
|
||||
*
|
||||
* @param[in] prefix Namespace prefix, or NULL for default
|
||||
* @param[in] namespace Cached namespace to set (assume non-null?)
|
||||
* @retval nsc Return namespace context in form of a cvec
|
||||
|
|
@ -142,6 +144,7 @@ xml_nsctx_free(cvec *nsc)
|
|||
}
|
||||
|
||||
/*! Get namespace given prefix (or NULL for default) from namespace context
|
||||
*
|
||||
* @param[in] cvv Namespace context
|
||||
* @param[in] prefix Namespace prefix, or NULL for default
|
||||
* @retval ns Cached namespace
|
||||
|
|
@ -159,11 +162,12 @@ xml_nsctx_get(cvec *cvv,
|
|||
}
|
||||
|
||||
/*! Reverse get prefix given namespace
|
||||
*
|
||||
* @param[in] cvv Namespace context
|
||||
* @param[in] ns Namespace
|
||||
* @param[out] prefix Prefix (direct pointer)
|
||||
* @retval 0 No prefix found
|
||||
* @retval 1 Prefix found
|
||||
* @retval 0 No prefix found
|
||||
* @note NULL is a valid prefix (default)
|
||||
*/
|
||||
int
|
||||
|
|
@ -188,6 +192,7 @@ xml_nsctx_get_prefix(cvec *cvv,
|
|||
}
|
||||
|
||||
/*! Set or replace namespace in namespace context
|
||||
*
|
||||
* @param[in] cvv Namespace context
|
||||
* @param[in] prefix Namespace prefix, or NULL for default
|
||||
* @param[in] ns Cached namespace to set (assume non-null?)
|
||||
|
|
@ -261,11 +266,12 @@ xml_nsctx_node1(cxobj *xn,
|
|||
}
|
||||
|
||||
/*! Create and initialize XML namespace from XML node context
|
||||
*
|
||||
* Fully explore all prefix:namespace pairs from context of one node
|
||||
* @param[in] xn XML node
|
||||
* @param[out] ncp XML namespace context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* cxobj *x; // must initialize
|
||||
* cvec *nsc = NULL;
|
||||
|
|
@ -297,12 +303,13 @@ xml_nsctx_node(cxobj *xn,
|
|||
}
|
||||
|
||||
/*! Create and initialize XML namespace context from Yang node (non-spec)
|
||||
*
|
||||
* Primary use is Yang path statements, eg leafrefs and others
|
||||
* Fully explore all prefix:namespace pairs from context of one node
|
||||
* @param[in] yn Yang statement in module tree (or module itself)
|
||||
* @param[out] ncp XML namespace context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* yang_stmt *y; // must initialize
|
||||
* cvec *nsc = NULL;
|
||||
|
|
@ -394,7 +401,7 @@ xml_nsctx_yang(yang_stmt *yn,
|
|||
* Also add netconf base namespace: nc , urn:ietf:params:xml:ns:netconf:base:1.0
|
||||
* Fully explore all prefix:namespace pairs of all yang modules
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] ncp XML namespace context
|
||||
* @param[out] ncp XML namespace context (create if does not exist)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
|
|
@ -416,7 +423,9 @@ xml_nsctx_yangspec(yang_stmt *yspec,
|
|||
yang_stmt *yprefix;
|
||||
yang_stmt *ynamespace;
|
||||
|
||||
if ((nc = cvec_new(0)) == NULL){
|
||||
if (ncp && *ncp)
|
||||
nc = *ncp;
|
||||
else if ((nc = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_XML, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -443,6 +452,7 @@ xml_nsctx_yangspec(yang_stmt *yspec,
|
|||
}
|
||||
|
||||
/*! Print a namespace context to a cbuf using xmlns notation
|
||||
*
|
||||
* @param[in] *cb CLIgen buf written to
|
||||
* @param[in] *nsc Namespace context
|
||||
* @retval 0 OK
|
||||
|
|
@ -531,6 +541,7 @@ xml2ns(cxobj *x,
|
|||
}
|
||||
|
||||
/*! Recursively check prefix / namespaces (and populate ns cache)
|
||||
*
|
||||
* @retval 1 OK
|
||||
* @retval 0 (Some) prefix not found
|
||||
* @retval -1 Error
|
||||
|
|
@ -563,6 +574,7 @@ xml2ns_recurse(cxobj *xt)
|
|||
}
|
||||
|
||||
/*! Add a namespace attribute to an XML node, either default or specific prefix
|
||||
*
|
||||
* @param[in] x XML tree
|
||||
* @param[in] prefix prefix/ns localname. If NULL then set default xmlns
|
||||
* @param[in] ns URI namespace (or NULL). Will be copied
|
||||
|
|
@ -636,12 +648,13 @@ xmlns_set_all(cxobj *x,
|
|||
}
|
||||
|
||||
/*! Get prefix of given namespace recursively
|
||||
*
|
||||
* @param[in] xn XML node
|
||||
* @param[in] namespace Namespace
|
||||
* @param[out] prefixp Pointer to prefix if found
|
||||
* @retval -1 Error
|
||||
* @retval 0 No namespace found
|
||||
* @retval 1 Namespace found, prefix returned in prefixp
|
||||
* @retval 0 No namespace found
|
||||
* @retval -1 Error
|
||||
* @note a namespace can have two or more prefixes, this just returns the first
|
||||
* @see xml2prefixexists to check a specific pair
|
||||
*/
|
||||
|
|
@ -700,8 +713,8 @@ xml2prefix(cxobj *xn,
|
|||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/*! Add prefix:namespace pair to xml node, set cache, etc
|
||||
*
|
||||
* @param[in] x XML node whose namespace should change
|
||||
* @param[in] xp XML node where namespace attribute should be declared (can be same)
|
||||
* @param[in] prefix1 Use this prefix
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
|
|||
|
|
@ -90,12 +90,21 @@
|
|||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_netconf_lib.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_yang_schema_mount.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_parse.h"
|
||||
#include "clixon_xpath_eval.h"
|
||||
|
||||
/* Use apostrophe(') in xpath literals, eg a/[x='foo'], not double-quotes(")
|
||||
* If not set, use ": a/[x="foo"]
|
||||
* Advantage with ' is it works well in clispecs, " must be escaped
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-Literal
|
||||
*/
|
||||
#define XPATH_USE_APOSTROPHE
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
|
|
@ -174,7 +183,10 @@ xpath_tree_int2str(int nodetype)
|
|||
return (char*)clicon_int2str(xpath_tree_map, nodetype);
|
||||
}
|
||||
|
||||
/*! Print XPATH parse tree */
|
||||
/*! Print XPATH parse tree
|
||||
*
|
||||
* @note uses "" instead of '' in printing literals, rule [29] in https://www.w3.org/TR/xpath-10
|
||||
*/
|
||||
static int
|
||||
xpath_tree_print0(cbuf *cb,
|
||||
xpath_tree *xs,
|
||||
|
|
@ -243,6 +255,8 @@ xpath_tree_print(FILE *f,
|
|||
/*! Create an xpath string from an xpath tree, ie "unparsing"
|
||||
* @param[in] xs XPATH tree
|
||||
* @param[out] xpath XPath string as CLIgen buf
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xpath_tree_print
|
||||
*/
|
||||
int
|
||||
|
|
@ -279,7 +293,11 @@ xpath_tree2cbuf(xpath_tree *xs,
|
|||
cprintf(xcb, "%s", xs->xs_strnr?xs->xs_strnr:"0");
|
||||
break;
|
||||
case XP_PRIME_STR:
|
||||
#ifdef XPATH_USE_APOSTROPHE
|
||||
cprintf(xcb, "'%s'", xs->xs_s0?xs->xs_s0:"");
|
||||
#else
|
||||
cprintf(xcb, "\"%s\"", xs->xs_s0?xs->xs_s0:"");
|
||||
#endif
|
||||
break;
|
||||
case XP_PRIME_FN:
|
||||
if (xs->xs_s0)
|
||||
|
|
@ -951,28 +969,31 @@ xpath_vec_bool(cxobj *xcur,
|
|||
* @retval 1 OK with nsc1 containing the transformed nsc
|
||||
* @retval 0 XPath failure with reason set to why
|
||||
* @retval -1 Fatal Error
|
||||
* XXX Detects mountpoint but is not mountpoint aware, just copies prefixes
|
||||
*/
|
||||
static int
|
||||
traverse_canonical(xpath_tree *xs,
|
||||
yang_stmt *yspec,
|
||||
cvec *nsc0,
|
||||
cvec *nsc1,
|
||||
cbuf **reason)
|
||||
xpath_traverse_canonical(xpath_tree *xs,
|
||||
yang_stmt *yspec,
|
||||
cvec *nsc0,
|
||||
cvec *nsc1,
|
||||
cbuf **reason)
|
||||
{
|
||||
int retval = -1;
|
||||
char *prefix0;
|
||||
char *prefix1;
|
||||
char *prefix1 = NULL;
|
||||
char *namespace;
|
||||
yang_stmt *ymod;
|
||||
cbuf *cb = NULL;
|
||||
int ret;
|
||||
|
||||
// char *name;
|
||||
|
||||
switch (xs->xs_type){
|
||||
case XP_NODE: /* s0 is namespace prefix, s1 is name */
|
||||
/* Nodetest = * needs no prefix */
|
||||
if (xs->xs_s1 && strcmp(xs->xs_s1, "*") == 0)
|
||||
break;
|
||||
prefix0 = xs->xs_s0;
|
||||
// name = xs->xs_s1;
|
||||
if ((namespace = xml_nsctx_get(nsc0, prefix0)) == NULL){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
|
|
@ -981,19 +1002,23 @@ traverse_canonical(xpath_tree *xs,
|
|||
cprintf(cb, "No namespace found for prefix: %s", prefix0);
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
goto fail;
|
||||
}
|
||||
if ((ymod = yang_find_module_by_namespace(yspec, namespace)) == NULL){
|
||||
#ifndef XPATH_CANONICAL_SKIP_CHECK
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "No modules found for namespace: %s", namespace);
|
||||
cprintf(cb, "No yang found for namespace: %s", namespace);
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
if ((prefix1 = yang_find_myprefix(ymod)) == NULL){
|
||||
if (ymod == NULL)
|
||||
prefix1 = prefix0;
|
||||
else if ((prefix1 = yang_find_myprefix(ymod)) == NULL){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
|
|
@ -1001,7 +1026,7 @@ traverse_canonical(xpath_tree *xs,
|
|||
cprintf(cb, "No prefix found in module: %s", yang_argument_get(ymod));
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
goto fail;
|
||||
}
|
||||
if (xml_nsctx_get(nsc1, prefix1) == NULL)
|
||||
if (xml_nsctx_add(nsc1, prefix1, namespace) < 0)
|
||||
|
|
@ -1019,21 +1044,21 @@ traverse_canonical(xpath_tree *xs,
|
|||
break;
|
||||
}
|
||||
if (xs->xs_c0){
|
||||
if ((ret = traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1, reason)) < 0)
|
||||
if ((ret = xpath_traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1, reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
goto fail;
|
||||
}
|
||||
if (xs->xs_c1){
|
||||
if ((ret = traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1, reason)) < 0)
|
||||
if ((ret = xpath_traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1, reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
goto fail;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
failed:
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1092,10 +1117,10 @@ xpath2canonical(const char *xpath0,
|
|||
/* Traverse tree to find prefixes, transform them to canonical form and
|
||||
* create a canonical network namespace
|
||||
*/
|
||||
if ((ret = traverse_canonical(xpt, yspec, nsc0, nsc1, cbreason)) < 0)
|
||||
if ((ret = xpath_traverse_canonical(xpt, yspec, nsc0, nsc1, cbreason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
goto fail;
|
||||
/* Print tree with new prefixes */
|
||||
if ((xcb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
|
|
@ -1122,7 +1147,7 @@ xpath2canonical(const char *xpath0,
|
|||
if (xpt)
|
||||
xpath_tree_free(xpt);
|
||||
return retval;
|
||||
failed:
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1166,10 +1191,11 @@ xpath_count(cxobj *xcur,
|
|||
}
|
||||
|
||||
/*! Given an XML node, build an xpath recursively to root, internal function
|
||||
*
|
||||
* @param[in] x XML object
|
||||
* @param[in] nsc Namespace context
|
||||
* @param[in] spec If set, recursively continue only to root without spec
|
||||
* @param[out] cb XPath string as cbuf.
|
||||
* @param[in] apostrophe If set, use apostrophe in xpath literals, eg a/[x='foo'], not double-quotes(") * @param[out] cb XPath string as cbuf.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. eg XML malformed
|
||||
*/
|
||||
|
|
@ -1177,6 +1203,7 @@ static int
|
|||
xml2xpath1(cxobj *x,
|
||||
cvec *nsc,
|
||||
int spec,
|
||||
int apostrophe,
|
||||
cbuf *cb)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -1196,7 +1223,7 @@ xml2xpath1(cxobj *x,
|
|||
goto ok;
|
||||
if (spec && xml_spec(x) == NULL)
|
||||
goto ok;
|
||||
if (xml2xpath1(xp, nsc, spec, cb) < 0)
|
||||
if (xml2xpath1(xp, nsc, spec, apostrophe, cb) < 0)
|
||||
goto done;
|
||||
if (nsc){
|
||||
if (xml2ns(x, xml_prefix(x), &namespace) < 0)
|
||||
|
|
@ -1219,10 +1246,18 @@ xml2xpath1(cxobj *x,
|
|||
keyword = yang_keyword_get(y);
|
||||
switch (keyword){
|
||||
case Y_LEAF_LIST:
|
||||
if ((b = xml_body(x)) != NULL)
|
||||
cprintf(cb, "[.=\"%s\"]", b);
|
||||
else
|
||||
cprintf(cb, "[.=\"\"]");
|
||||
if (apostrophe){
|
||||
if ((b = xml_body(x)) != NULL)
|
||||
cprintf(cb, "[.='%s']", b);
|
||||
else
|
||||
cprintf(cb, "[.='']");
|
||||
}
|
||||
else{
|
||||
if ((b = xml_body(x)) != NULL)
|
||||
cprintf(cb, "[.=\"%s\"]", b);
|
||||
else
|
||||
cprintf(cb, "[.=\"\"]");
|
||||
}
|
||||
break;
|
||||
case Y_LIST:
|
||||
cvk = yang_cvec_get(y);
|
||||
|
|
@ -1234,10 +1269,17 @@ xml2xpath1(cxobj *x,
|
|||
if ((xb = xml_find(x, keyname)) == NULL)
|
||||
goto done;
|
||||
b = xml_body(xb);
|
||||
#if 1
|
||||
if (b==NULL || strlen(b)==0)
|
||||
continue;
|
||||
#endif
|
||||
cprintf(cb, "[");
|
||||
if (prefix)
|
||||
cprintf(cb, "%s:", prefix);
|
||||
cprintf(cb, "%s=\"%s\"]", keyname, b?b:"");
|
||||
if (apostrophe)
|
||||
cprintf(cb, "%s='%s']", keyname, b?b:"");
|
||||
else
|
||||
cprintf(cb, "%s=\"%s\"]", keyname, b?b:"");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1260,6 +1302,7 @@ xml2xpath1(cxobj *x,
|
|||
* @param[in] x XML object
|
||||
* @param[in] nsc Namespace context
|
||||
* @param[in] spec If set, recursively continue only to root without spec (added in 6.1 for yang mount)
|
||||
* @param[in] apostrophe If set, use apostrophe in xpath literals, eg a/[x='foo'], not double-quotes(")
|
||||
* @param[out] xpath Malloced xpath string. Need to free() after use
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. (eg XML malformed)
|
||||
|
|
@ -1267,16 +1310,18 @@ xml2xpath1(cxobj *x,
|
|||
* char *xpath = NULL;
|
||||
* cxobj *x;
|
||||
* ... x is inside an xml tree ...
|
||||
* if (xml2xpath(x, nsc, 0, &xpath) < 0)
|
||||
* if (xml2xpath(x, nsc, 0, 0, &xpath) < 0)
|
||||
* err;
|
||||
* free(xpath);
|
||||
* @endcode
|
||||
* @note x needs to be bound to YANG, see eg xml_bind_yang()
|
||||
* @note namespaces of xpath is not well-defined, follows xml, should be canonical?
|
||||
*/
|
||||
int
|
||||
xml2xpath(cxobj *x,
|
||||
cvec *nsc,
|
||||
int spec,
|
||||
int apostrophe,
|
||||
char **xpathp)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -1287,7 +1332,7 @@ xml2xpath(cxobj *x,
|
|||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (xml2xpath1(x, nsc, spec, cb) < 0)
|
||||
if (xml2xpath1(x, nsc, spec, apostrophe, cb) < 0)
|
||||
goto done;
|
||||
/* XXX: see xpath in test statement,.. */
|
||||
xpath = cbuf_get(cb);
|
||||
|
|
@ -1304,3 +1349,167 @@ xml2xpath(cxobj *x,
|
|||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create xml tree from xpath as xpath-tree
|
||||
*
|
||||
* @param[in] xs Parsed xpath - xpath_tree
|
||||
* @param[in] nsc Namespace context for xpath
|
||||
* @param[in] x0 XML tree so far
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath) (optional)
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid xpath
|
||||
* @retval -1 Fatal error, clicon_err called
|
||||
* @see xpath_traverse_canonical
|
||||
*/
|
||||
static int
|
||||
xpath2xml_traverse(xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
cxobj *x0,
|
||||
yang_stmt *y0,
|
||||
cxobj **xbotp,
|
||||
yang_stmt **ybotp,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char *name;
|
||||
char *prefix;
|
||||
char *namespace;
|
||||
char *ns = NULL;
|
||||
cbuf *cberr = NULL;
|
||||
cxobj *xc;
|
||||
yang_stmt *ymod;
|
||||
yang_stmt *yc;
|
||||
|
||||
*xbotp = x0;
|
||||
*ybotp = y0;
|
||||
switch (xs->xs_type){
|
||||
case XP_NODE: /* s0 is namespace prefix, s1 is name */
|
||||
prefix = xs->xs_s0;
|
||||
name = xs->xs_s1;
|
||||
if ((namespace = xml_nsctx_get(nsc, prefix)) == NULL){
|
||||
if ((cberr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cberr, "No namespace found for prefix: %s", prefix);
|
||||
if (xerr &&
|
||||
netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (yang_keyword_get(y0) == Y_SPEC){ /* top-node */
|
||||
if ((ymod = yang_find_module_by_namespace(y0, namespace)) == NULL){
|
||||
cprintf(cberr, "No such yang module namespace");
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", namespace, cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
y0 = ymod;
|
||||
}
|
||||
if ((yc = yang_find_datanode(y0, name)) == NULL){
|
||||
if (xerr &&
|
||||
netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if ((xc = xml_new(name, x0, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (xml2ns(x0, prefix, &ns) < 0)
|
||||
goto done;
|
||||
if (ns == NULL)
|
||||
if (xmlns_set(xc, NULL, namespace) < 0)
|
||||
goto done;
|
||||
*xbotp = xc;
|
||||
*ybotp = yc;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (xs->xs_c0){
|
||||
if ((ret = xpath2xml_traverse(xs->xs_c0, nsc, x0, y0, xbotp, ybotp, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (xs->xs_c1){
|
||||
x0 = *xbotp;
|
||||
y0 = *ybotp;
|
||||
if ((ret = xpath2xml_traverse(xs->xs_c1, nsc, x0, y0, xbotp, ybotp, xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
goto fail;
|
||||
}
|
||||
if (xs->xs_type == XP_STEP){
|
||||
*xbotp = x0;
|
||||
*ybotp = y0;
|
||||
}
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(CLIXON_DBG_DETAIL, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Create xml tree from restricted xpath
|
||||
*
|
||||
* Create an XML tree from "scratch" using xpath.
|
||||
* @param[in] xpath (Absolute) XPath
|
||||
* @param[in] nsc Namespace context for xpath
|
||||
* @param[in,out] xtop Incoming XML tree
|
||||
* @param[in] yspec Yang spec for xtop
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath) (optional)
|
||||
* @param[out] ybotp Yang spec matching xpathp
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid xpath
|
||||
* @retval -1 Fatal error, clicon_err called
|
||||
* @see api_path2xml
|
||||
* @see xml2xpath
|
||||
* @note xpath is restricted to absolute paths, and simple expressions, eg as "node-identifier"
|
||||
*/
|
||||
int
|
||||
xpath2xml(char *xpath,
|
||||
cvec *nsc,
|
||||
cxobj *xtop,
|
||||
yang_stmt *ytop,
|
||||
cxobj **xbotp,
|
||||
yang_stmt **ybotp,
|
||||
cxobj **xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cberr = NULL;
|
||||
xpath_tree *xpt = NULL;
|
||||
|
||||
clicon_debug(CLIXON_DBG_DETAIL, "%s xpath:%s", __FUNCTION__, xpath);
|
||||
if ((cberr = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (*xpath != '/'){
|
||||
cprintf(cberr, "Invalid absolute xpath: %s (must start with '/')", xpath);
|
||||
if (xerr && netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
/* Parse input xpath into an xpath-tree */
|
||||
if (xpath_parse(xpath, &xpt) < 0)
|
||||
goto done;
|
||||
if ((retval = xpath2xml_traverse(xpt, nsc, xtop, ytop, xbotp, ybotp, xerr)) < 1)
|
||||
goto done;
|
||||
done:
|
||||
if (xpt)
|
||||
xpath_tree_free(xpt);
|
||||
if (cberr)
|
||||
cbuf_free(cberr);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@
|
|||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* NaN */
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* NaN */
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* NaN */
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ struct yang_stmt{
|
|||
fraction-digits for fraction-digits
|
||||
revision (uint32)
|
||||
unknown-stmt (optional argument)
|
||||
spec: mount-point xpath
|
||||
*/
|
||||
cvec *ys_cvec; /* List of stmt-specific variables
|
||||
Y_RANGE: range_min, range_max
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@
|
|||
* 4. yang_schema_mount_statedata(): from get_common/get_statedata to retrieve system state
|
||||
* 5. yang_schema_yanglib_parse_mount(): from xml_bind_yang to parse and mount
|
||||
* 6. yang_schema_get_child(): from xmldb_put/text_modify when adding new XML nodes
|
||||
*
|
||||
* Note: the xpath used as key in yang unknown cvec is "canonical" in the sense:
|
||||
* - it uses prefixes of the yang spec of relevance
|
||||
* - it uses '' not "" in prefixes (eg a[x='foo']. The reason is '' is easier printed in clispecs
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
@ -133,8 +137,8 @@ yang_schema_mount_point(yang_stmt *y)
|
|||
|
||||
/*! Get yangspec mount-point
|
||||
*
|
||||
* @param[in] yu Yang unknown node to save the yspecs
|
||||
* @param[in] xpath Key for yspec on yu
|
||||
* @param[in] yu Yang unknown node to save the yspecs
|
||||
* @param[in] xpath Key for yspec on yu
|
||||
* @param[out] yspec YANG stmt spec
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -157,9 +161,9 @@ yang_mount_get(yang_stmt *yu,
|
|||
|
||||
/*! Set yangspec mount-point on yang unknwon node
|
||||
*
|
||||
* Stored in a separate structure (not in XML config tree)
|
||||
* Mount-points are stored in unknown yang cvec
|
||||
* @param[in] yu Yang unknown node to save the yspecs
|
||||
* @param[in] xpath Key for yspec on yu
|
||||
* @param[in] xpath Key for yspec on yu, in canonical form
|
||||
* @param[in] yspec Yangspec for this mount-point (consumed)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -173,6 +177,7 @@ yang_mount_set(yang_stmt *yu,
|
|||
yang_stmt *yspec0;
|
||||
cvec *cvv;
|
||||
cg_var *cv;
|
||||
cg_var *cv2;
|
||||
|
||||
if ((cvv = yang_cvec_get(yu)) != NULL &&
|
||||
(cv = cvec_find(cvv, xpath)) != NULL &&
|
||||
|
|
@ -184,6 +189,16 @@ yang_mount_set(yang_stmt *yu,
|
|||
}
|
||||
else if ((cv = yang_cvec_add(yu, CGV_VOID, xpath)) == NULL)
|
||||
goto done;
|
||||
if ((cv2 = cv_new(CGV_STRING)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "cv_new");
|
||||
goto done;
|
||||
}
|
||||
if (cv_string_set(cv2, xpath) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
/* tag yspec with key/xpath */
|
||||
yang_cv_set(yspec, cv2);
|
||||
cv_void_set(cv, yspec);
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -224,7 +239,7 @@ xml_yang_mount_get(clicon_handle h,
|
|||
// XXX hardcoded prefix: yangmnt
|
||||
if ((yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL)
|
||||
goto ok;
|
||||
if (xml2xpath(xt, NULL, 1, &xpath) < 0)
|
||||
if (xml2xpath(xt, NULL, 1, 0, &xpath) < 0)
|
||||
goto done;
|
||||
if (yang_mount_get(yu, xpath, yspec) < 0)
|
||||
goto done;
|
||||
|
|
@ -261,7 +276,7 @@ xml_yang_mount_set(cxobj *x,
|
|||
(yu = yang_find(y, Y_UNKNOWN, "yangmnt:mount-point")) == NULL){
|
||||
goto done;
|
||||
}
|
||||
if (xml2xpath(x, NULL, 1, &xpath) < 0)
|
||||
if (xml2xpath(x, NULL, 1, 0, &xpath) < 0)
|
||||
goto done;
|
||||
if (yang_mount_set(yu, xpath, yspec) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <regex.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <regex.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/param.h>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue