Reverted some of the nsc xpath API changes. In the revert, xpath_first() and xpath_vec() retain their old syntax with nsc==NULL.

The reason is to be conservative with the API. However, less used functions, such as xpath_vec_bool(), xpath_vec_ctx() and xpath_vec_flag()  are changed with a new `nsc`parameter, which should be set to NULL in most cases.
This commit is contained in:
Olof hagsand 2019-07-09 12:19:03 +02:00
parent 89f751357d
commit 40d5b99d3b
32 changed files with 391 additions and 266 deletions

View file

@ -69,17 +69,18 @@
### API changes on existing features (you may need to change your code) ### API changes on existing features (you may need to change your code)
* The Clixon API has been extended with namespaces, or namespace contexts in the following cases [Netconf get/get-config :xpath capability does not support namespaces](https://github.com/clicon/clixon/issues/75) * The Clixon API has been extended with namespaces, or namespace contexts in the following cases (see [README.md#xml-and-xpath] for explanation):
* CLIspec functions have added namespace parameter: * CLIspec functions have added optional namespace parameter:
* `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>` * `cli_show_config <db> <format> <xpath>` --> `cli_show_config <db> <format> <xpath> <namespace>`
* `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...` * `cli_copy_config <db> <xpath> ...` --> `cli_copy_config <db> <xpath> <namespace> ...`
* Xpath API * Change the following Xpath API functions (xpath_first and xpath_vec remain as-is):
* `xpath_first(x, format, ...)` --> `xpath_first(x, nsc, format, ...)` * `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, nsc, format, flags, vec, veclen, ...)`
* `xpath_vec(x, format, vec, veclen, ...)` --> `xpath_vec(x, nsc, format, vec, veclen, ...)`
* `xpath_vec_flag(x, format, flags, vec, veclen, ...)` --> `xpath_vec_flag(x, format, flags, vec, veclen, ...)`
* `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)` * `xpath_vec_bool(x, format, ...)` --> `xpath_vec_bool(x, nsc, format, ...)`
* `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)` * `xpath_vec_ctx(x, xpath, xp)` --> `xpath_vec_ctx(x, nsc, xpath, xp)`
* xmldb_get0 has an added `nsc` parameter: * New Xpath API functions with namespace contexts:
* `xpath_first_nsc(x, nsc, format, ...)`
* `xpath_vec_nsc(x, nsc, format, vec, veclen, ...)`
* Change xmldb_get0 with added `nsc` parameter:
* `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)` * `xmldb_get0(h, db, xpath, copy, xret, msd)` --> `xmldb_get0(h, db, nsc, xpath, copy, xret, msd)`
* The plugin statedata callback (ca_statedata) has been extended with an nsc parameter: * The plugin statedata callback (ca_statedata) has been extended with an nsc parameter:
* `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);` * `int example_statedata(clicon_handle h, cvec *nsc, char *xpath, cxobj *xstate);`
@ -104,7 +105,6 @@
``` ```
curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"} curl -X PUT http://localhost/restconf/data/mod:a -d {"a":"x"}
``` ```
* Undefine `RESTCONF_NS_DATA_CHECK` in include/clixon_custom.h to disable strict check.
* Many validation functions have changed error parameter from cbuf to xml tree. * Many validation functions have changed error parameter from cbuf to xml tree.
* XML trees are more flexible for utility tools * XML trees are more flexible for utility tools
* If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only` * If you use these(mostly internal), you need to change the error function: `generic_validate, from_validate_common, xml_yang_validate_all_top, xml_yang_validate_all, xml_yang_validate_add, xml_yang_validate_rpc, xml_yang_validate_list_key_only`

View file

@ -131,14 +131,14 @@ The standards covered include:
- [Namespaces in XML 1.0](https://www.w3.org/TR/2009/REC-xml-names-20091208) - [Namespaces in XML 1.0](https://www.w3.org/TR/2009/REC-xml-names-20091208)
- [XPATH 1.0](https://www.w3.org/TR/xpath-10) - [XPATH 1.0](https://www.w3.org/TR/xpath-10)
Not supported: Not supported in the XML:
- !DOCTYPE (ie DTD) - !DOCTYPE (ie DTD)
The following xpath axes are supported: The following XPATH axes are supported:
- CHILD, DESCENDANT, DESCENDANT_OR_SELF, SELF, and PARENT - child, descendant, descendant_or_self, self, and parent
The following xpath axes are _not_ supported: The following xpath axes are _not_ supported:
- PRECEEDING, PRECEEDING_SIBLING, NAMESPACE, FOLLOWING_SIBLING, FOLLOWING, ANCESTOR,ANCESTOR_OR_SELF, ATTRIBUTE - preceeding, preceeding_sibling, namespace, following_sibling, following, ancestor,ancestor_or_self, and attribute
Note that base netconf namespace syntax is not enforced but recommended, which means that the following two expressions are treated equivalently: Note that base netconf namespace syntax is not enforced but recommended, which means that the following two expressions are treated equivalently:
``` ```
@ -157,7 +157,10 @@ XPATHs may contain prefixes. Example: `/if:a/if:b`. The prefixes have
associated namespaces. For example, `if` may be bound to associated namespaces. For example, `if` may be bound to
`urn:ietf:params:xml:ns:yang:ietf-interfaces`. The prefix to namespace binding is called a _namespace context_ (nsc). `urn:ietf:params:xml:ns:yang:ietf-interfaces`. The prefix to namespace binding is called a _namespace context_ (nsc).
In yang, the xpath and xml prefixes may not be well-known. For example, the import statement specifies a prefix to an imported module that is local in scope. Other modules may use another prefix. The module name and namespace however are unique.
In the Clixon API, there are two variants on namespace contexts: _implicit_ (given by the XML); or _explicit_ given by an external mapping. In the Clixon API, there are two variants on namespace contexts: _implicit_ (given by the XML); or _explicit_ given by an external mapping.
#### 1. Implicit namespace mapping #### 1. Implicit namespace mapping
Implicit mapping is typical for basic known XML, where the context is Implicit mapping is typical for basic known XML, where the context is
@ -169,7 +172,8 @@ Example:
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if> XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
XPATH: /if:a/ip:b XPATH: /if:a/ip:b
``` ```
When you call an xpath API function, call it with nsc set to NULL. This is the default. When you call an xpath API function, call it with nsc set to NULL, or use an API function without an nsc parameter.
This is the default and normal case.
#### 2. Explicit namespace mapping #### 2. Explicit namespace mapping
@ -184,7 +188,7 @@ call. Example:
XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if> XML: <if:a xmlns:if="urn:example:if" xmlns:ip="urn:example:ip"><ip:b/></if>
NETCONF:<get-config><filter select="/x:a/y:b" xmlns:x="urn:example:if" xmlns:y="urn:example:ip/> NETCONF:<get-config><filter select="/x:a/y:b" xmlns:x="urn:example:if" xmlns:y="urn:example:ip/>
``` ```
Here, x,y are prefixes used for two namespaces that are given by if,ip Here, x,y are prefixes used for two namespaces that are given by `if,ip`
in the xml. In this case, the namespaces (eg `urn:example:if`) must be in the xml. In this case, the namespaces (eg `urn:example:if`) must be
compared instead. compared instead.

View file

@ -266,7 +266,7 @@ client_statedata(clicon_handle h,
* Actually this is a safety catch, should realy be done in plugins * Actually this is a safety catch, should realy be done in plugins
* and modules_state functions. * and modules_state functions.
*/ */
if (xpath_vec(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* If vectors are specified then mark the nodes found and /* If vectors are specified then mark the nodes found and
* then filter out everything else, * then filter out everything else,
@ -363,7 +363,7 @@ from_client_get_config(clicon_handle h,
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
goto done; goto done;
if (ret == 0){ /* Do NACM validation */ if (ret == 0){ /* Do NACM validation */
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* NACM datanode/module read validation */ /* NACM datanode/module read validation */
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0) if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
@ -455,14 +455,14 @@ from_client_edit_config(clicon_handle h,
goto done; goto done;
goto ok; goto ok;
} }
if ((x = xpath_first(xn, NULL, "default-operation")) != NULL){ if ((x = xpath_first(xn, "default-operation")) != NULL){
if (xml_operation(xml_body(x), &operation) < 0){ if (xml_operation(xml_body(x), &operation) < 0){
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0) if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
goto done; goto done;
goto ok; goto ok;
} }
} }
if ((xc = xpath_first(xn, NULL, "config")) == NULL){ if ((xc = xpath_first(xn, "config")) == NULL){
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0) if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
goto done; goto done;
goto ok; goto ok;
@ -858,7 +858,7 @@ from_client_get(clicon_handle h,
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
goto done; goto done;
if (ret == 0){ /* Do NACM validation */ if (ret == 0){ /* Do NACM validation */
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* NACM datanode/module read validation */ /* NACM datanode/module read validation */
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0) if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
@ -1016,9 +1016,9 @@ from_client_create_subscription(clicon_handle h,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL) if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL)
goto done; goto done;
if ((x = xpath_first(xe, nsc, "//stream")) != NULL) if ((x = xpath_first_nsc(xe, nsc, "//stream")) != NULL)
stream = xml_find_value(x, "body"); stream = xml_find_value(x, "body");
if ((x = xpath_first(xe, nsc, "//stopTime")) != NULL){ if ((x = xpath_first_nsc(xe, nsc, "//stopTime")) != NULL){
if ((stoptime = xml_find_value(x, "body")) != NULL && if ((stoptime = xml_find_value(x, "body")) != NULL &&
str2time(stoptime, &stop) < 0){ str2time(stoptime, &stop) < 0){
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0) if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
@ -1026,7 +1026,7 @@ from_client_create_subscription(clicon_handle h,
goto ok; goto ok;
} }
} }
if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){ if ((x = xpath_first_nsc(xe, nsc, "//startTime")) != NULL){
if ((starttime = xml_find_value(x, "body")) != NULL && if ((starttime = xml_find_value(x, "body")) != NULL &&
str2time(starttime, &start) < 0){ str2time(starttime, &start) < 0){
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0) if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
@ -1034,7 +1034,7 @@ from_client_create_subscription(clicon_handle h,
goto ok; goto ok;
} }
} }
if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){ if ((xfilter = xpath_first_nsc(xe, nsc, "//filter")) != NULL){
if ((ftype = xml_find_value(xfilter, "type")) != NULL){ if ((ftype = xml_find_value(xfilter, "type")) != NULL){
/* Only accept xpath as filter type */ /* Only accept xpath as filter type */
if (strcmp(ftype, "xpath") != 0){ if (strcmp(ftype, "xpath") != 0){
@ -1175,7 +1175,7 @@ from_client_msg(clicon_handle h,
goto reply; goto reply;
} }
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){ if ((x = xpath_first_nsc(xt, NULL, "/rpc")) == NULL){
if (netconf_malformed_message(cbret, "rpc keyword expected")< 0) if (netconf_malformed_message(cbret, "rpc keyword expected")< 0)
goto done; goto done;
goto reply; goto reply;

View file

@ -682,13 +682,13 @@ compare_dbs(clicon_handle h,
astext = 0; astext = 0;
if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0) if (clicon_rpc_get_config(h, "running", "/", NULL, &xc1) < 0)
goto done; goto done;
if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0) if (clicon_rpc_get_config(h, "candidate", "/", NULL, &xc2) < 0)
goto done; goto done;
if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
@ -853,7 +853,7 @@ save_config_file(clicon_handle h,
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */ clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
goto done; goto done;
} }
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
@ -961,7 +961,7 @@ cli_notification_cb(int s,
} }
if (clicon_msg_decode(reply, NULL, &xt) < 0) /* XXX pass yang_spec */ if (clicon_msg_decode(reply, NULL, &xt) < 0) /* XXX pass yang_spec */
goto done; goto done;
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){ if ((xe = xpath_first(xt, "//event")) != NULL){
x = NULL; x = NULL;
while ((x = xml_child_each(xe, x, -1)) != NULL) { while ((x = xml_child_each(xe, x, -1)) != NULL) {
switch (format){ switch (format){
@ -1191,7 +1191,7 @@ cli_copy_config(clicon_handle h,
/* Get from object configuration and store in x1 */ /* Get from object configuration and store in x1 */
if (clicon_rpc_get_config(h, db, cbuf_get(cb), namespace, &x1) < 0) if (clicon_rpc_get_config(h, db, cbuf_get(cb), namespace, &x1) < 0)
goto done; goto done;
if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
@ -1211,7 +1211,7 @@ cli_copy_config(clicon_handle h,
cprintf(cb, "/%s", keyname); cprintf(cb, "/%s", keyname);
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL) if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
goto done; goto done;
if ((x = xpath_first(x2, nsc, "%s", cbuf_get(cb))) == NULL){ if ((x = xpath_first_nsc(x2, nsc, "%s", cbuf_get(cb))) == NULL){
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname); clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
goto done; goto done;
} }

View file

@ -157,7 +157,7 @@ expand_dbvar(void *h,
/* Get configuration */ /* Get configuration */
if (clicon_rpc_get_config(h, dbstr, xpath, namespace, &xt) < 0) /* XXX */ if (clicon_rpc_get_config(h, dbstr, xpath, namespace, &xt) < 0) /* XXX */
goto done; goto done;
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto ok; goto ok;
} }
@ -198,12 +198,12 @@ expand_dbvar(void *h,
fprintf(stderr, "%s\n", reason); fprintf(stderr, "%s\n", reason);
goto done; goto done;
} }
if ((xcur = xpath_first(xt, nsc, "%s", xpath)) == NULL){ if ((xcur = xpath_first_nsc(xt, nsc, "%s", xpath)) == NULL){
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath); clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
goto done; goto done;
} }
} }
if (xpath_vec(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0) if (xpath_vec_nsc(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
goto done; goto done;
bodystr0 = NULL; /* Assume sorted XML where duplicates are adjacent */ bodystr0 = NULL; /* Assume sorted XML where duplicates are adjacent */
for (i = 0; i < xlen; i++) { for (i = 0; i < xlen; i++) {
@ -463,7 +463,7 @@ cli_show_config1(clicon_handle h,
if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, &xt) < 0) if (clicon_rpc_get(h, cbuf_get(cbxpath), namespace, &xt) < 0)
goto done; goto done;
} }
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
@ -608,13 +608,13 @@ show_conf_xpath(clicon_handle h,
if (clicon_rpc_get_config(h, str, xpath, namespace, &xt) < 0) if (clicon_rpc_get_config(h, str, xpath, namespace, &xt) < 0)
goto done; goto done;
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL) if ((nsc = xml_nsctx_init(NULL, namespace)) == NULL)
goto done; goto done;
if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0) if (xpath_vec_nsc(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
goto done; goto done;
for (i=0; i<xlen; i++) for (i=0; i<xlen; i++)
xml_print(stdout, xv[i]); xml_print(stdout, xv[i]);
@ -715,11 +715,11 @@ cli_show_auto1(clicon_handle h,
goto done; goto done;
} }
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }
if ((xp = xpath_first(xt, nsc, "%s", xpath)) != NULL) if ((xp = xpath_first_nsc(xt, nsc, "%s", xpath)) != NULL)
/* Print configuration according to format */ /* Print configuration according to format */
switch (format){ switch (format){
case FORMAT_XML: case FORMAT_XML:

View file

@ -100,7 +100,7 @@ netconf_hello_dispatch(cxobj *xn)
cxobj *xp; cxobj *xp;
int retval = -1; int retval = -1;
if ((xp = xpath_first(xn, NULL, "//hello")) != NULL) if ((xp = xpath_first(xn, "//hello")) != NULL)
retval = netconf_hello(xp); retval = netconf_hello(xp);
return retval; return retval;
} }

View file

@ -164,14 +164,14 @@ netconf_get_target(cxobj *xn,
cxobj *x; cxobj *x;
char *target = NULL; char *target = NULL;
if ((x = xpath_first(xn, NULL, "%s", path)) != NULL){ if ((x = xpath_first(xn, "%s", path)) != NULL){
if (xpath_first(x, NULL, "candidate") != NULL) if (xpath_first(x, "candidate") != NULL)
target = "candidate"; target = "candidate";
else else
if (xpath_first(x, NULL, "running") != NULL) if (xpath_first(x, "running") != NULL)
target = "running"; target = "running";
else else
if (xpath_first(x, NULL, "startup") != NULL) if (xpath_first(x, "startup") != NULL)
target = "startup"; target = "startup";
} }
return target; return target;

View file

@ -121,7 +121,7 @@ netconf_input_packet(clicon_handle h,
goto done; goto done;
} }
free(str0); free(str0);
if ((xrpc=xpath_first(xreq, NULL, "//rpc")) != NULL){ if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
isrpc++; isrpc++;
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0) if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
goto done; goto done;
@ -134,7 +134,7 @@ netconf_input_packet(clicon_handle h,
} }
} }
else else
if (xpath_first(xreq, NULL, "//hello") != NULL) if (xpath_first(xreq, "//hello") != NULL)
; ;
else{ else{
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped"); clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");

View file

@ -140,7 +140,7 @@ netconf_get_config(clicon_handle h,
cxobj *xconf; cxobj *xconf;
/* ie <filter>...</filter> */ /* ie <filter>...</filter> */
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL) if ((xfilter = xpath_first(xn, "filter")) != NULL)
ftype = xml_find_value(xfilter, "type"); ftype = xml_find_value(xfilter, "type");
if (ftype == NULL || strcmp(ftype, "xpath")==0){ if (ftype == NULL || strcmp(ftype, "xpath")==0){
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
@ -154,8 +154,8 @@ netconf_get_config(clicon_handle h,
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done; goto done;
if (xfilter && if (xfilter &&
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL && (xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){ (xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
/* xml_filter removes parts of xml tree not matching */ /* xml_filter removes parts of xml tree not matching */
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) || if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
xml_filter(xfilterconf, xconf) < 0){ xml_filter(xfilterconf, xconf) < 0){
@ -208,7 +208,7 @@ get_edit_opts(cxobj *xn,
cxobj *x; cxobj *x;
char *optstr; char *optstr;
if ((x = xpath_first(xn, NULL, "test-option")) != NULL){ if ((x = xpath_first(xn, "test-option")) != NULL){
if ((optstr = xml_body(x)) != NULL){ if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "test-then-set") == 0) if (strcmp(optstr, "test-then-set") == 0)
*testopt = TEST_THEN_SET; *testopt = TEST_THEN_SET;
@ -220,7 +220,7 @@ get_edit_opts(cxobj *xn,
goto parerr; goto parerr;
} }
} }
if ((x = xpath_first(xn, NULL, "error-option")) != NULL){ if ((x = xpath_first(xn, "error-option")) != NULL){
if ((optstr = xml_body(x)) != NULL){ if ((optstr = xml_body(x)) != NULL){
if (strcmp(optstr, "stop-on-error") == 0) if (strcmp(optstr, "stop-on-error") == 0)
*erropt = STOP_ON_ERROR; *erropt = STOP_ON_ERROR;
@ -352,7 +352,7 @@ netconf_get(clicon_handle h,
cxobj *xconf; cxobj *xconf;
/* ie <filter>...</filter> */ /* ie <filter>...</filter> */
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL) if ((xfilter = xpath_first(xn, "filter")) != NULL)
ftype = xml_find_value(xfilter, "type"); ftype = xml_find_value(xfilter, "type");
if (ftype == NULL || strcmp(ftype, "xpath")==0){ if (ftype == NULL || strcmp(ftype, "xpath")==0){
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
@ -366,8 +366,8 @@ netconf_get(clicon_handle h,
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
goto done; goto done;
if (xfilter && if (xfilter &&
(xfilterconf = xpath_first(xfilter, NULL, "//configuration"))!= NULL && (xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
(xconf = xpath_first(*xret, NULL, "/rpc-reply/data")) != NULL){ (xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
/* xml_filter removes parts of xml tree not matching */ /* xml_filter removes parts of xml tree not matching */
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) || if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
xml_filter(xfilterconf, xconf) < 0){ xml_filter(xfilterconf, xconf) < 0){
@ -448,7 +448,7 @@ netconf_notification_cb(int s,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL) if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL)
goto done; goto done;
if ((xn = xpath_first(xt, nsc, "notification")) == NULL) if ((xn = xpath_first_nsc(xt, nsc, "notification")) == NULL)
goto ok; goto ok;
/* create netconf message */ /* create netconf message */
if ((cb = cbuf_new()) == NULL){ if ((cb = cbuf_new()) == NULL){
@ -500,7 +500,7 @@ netconf_create_subscription(clicon_handle h,
int s; int s;
char *ftype; char *ftype;
if ((xfilter = xpath_first(xn, NULL, "//filter")) != NULL){ if ((xfilter = xpath_first(xn, "//filter")) != NULL){
if ((ftype = xml_find_value(xfilter, "type")) != NULL){ if ((ftype = xml_find_value(xfilter, "type")) != NULL){
if (strcmp(ftype, "xpath") != 0){ if (strcmp(ftype, "xpath") != 0){
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>" xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
@ -516,7 +516,7 @@ netconf_create_subscription(clicon_handle h,
} }
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0) if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0)
goto done; goto done;
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL) if (xpath_first(*xret, "rpc-reply/rpc-error") != NULL)
goto ok; goto ok;
if (event_reg_fd(s, if (event_reg_fd(s,
netconf_notification_cb, netconf_notification_cb,
@ -622,7 +622,7 @@ netconf_application_rpc(clicon_handle h,
*/ */
if (0) if (0)
if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){ if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){
xoutput=xpath_first(*xret, NULL, "/"); xoutput=xpath_first(*xret, "/");
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */ xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;

View file

@ -415,7 +415,7 @@ api_return_err(clicon_handle h,
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if ((cb = cbuf_new()) == NULL) if ((cb = cbuf_new()) == NULL)
goto done; goto done;
if ((xtag = xpath_first(xerr, NULL, "//error-tag")) == NULL){ if ((xtag = xpath_first(xerr, "//error-tag")) == NULL){
notfound(r); notfound(r);
goto ok; goto ok;
} }

View file

@ -396,7 +396,7 @@ api_restconf(clicon_handle h,
else{ else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0) if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;

View file

@ -212,7 +212,7 @@ api_data_get2(clicon_handle h,
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
goto done; goto done;
clicon_err_reset(); clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -229,7 +229,7 @@ api_data_get2(clicon_handle h,
if (clicon_rpc_get(h, xpath, namespace, &xret) < 0){ if (clicon_rpc_get(h, xpath, namespace, &xret) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -251,7 +251,7 @@ api_data_get2(clicon_handle h,
} }
#endif #endif
/* Check if error return */ /* Check if error return */
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -276,10 +276,10 @@ api_data_get2(clicon_handle h,
} }
} }
else{ else{
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){ if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0) if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -465,10 +465,8 @@ api_data_post(clicon_handle h,
cxobj *xtop = NULL; /* top of api-path */ cxobj *xtop = NULL; /* top of api-path */
cxobj *xbot = NULL; /* bottom of api-path */ cxobj *xbot = NULL; /* bottom of api-path */
yang_stmt *ybot = NULL; /* yang of xbot */ yang_stmt *ybot = NULL; /* yang of xbot */
#ifdef RESTCONF_NS_DATA_CHECK
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */ yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */ yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
#endif
yang_stmt *yspec; yang_stmt *yspec;
cxobj *xa; cxobj *xa;
cxobj *xret = NULL; cxobj *xret = NULL;
@ -496,15 +494,13 @@ api_data_post(clicon_handle h,
if (api_path){ if (api_path){
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0) if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done; goto done;
#ifdef RESTCONF_NS_DATA_CHECK
if (ybot) if (ybot)
ymodapi=ys_module(ybot); ymodapi=ys_module(ybot);
#endif
if (ret == 0){ /* validation failed */ if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
clicon_err_reset(); clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -518,7 +514,7 @@ api_data_post(clicon_handle h,
if (xml_parse_string(data, NULL, &xdata0) < 0){ if (xml_parse_string(data, NULL, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -531,7 +527,7 @@ api_data_post(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){ if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -540,7 +536,7 @@ api_data_post(clicon_handle h,
goto ok; goto ok;
} }
if (ret == 0){ if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -555,7 +551,7 @@ api_data_post(clicon_handle h,
if (xml_child_nr(xdata0) != 1){ if (xml_child_nr(xdata0) != 1){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -564,7 +560,6 @@ api_data_post(clicon_handle h,
goto ok; goto ok;
} }
xdata = xml_child_i(xdata0,0); xdata = xml_child_i(xdata0,0);
#ifdef RESTCONF_NS_DATA_CHECK
/* If the api-path (above) defines a module, then xdata must have a prefix /* If the api-path (above) defines a module, then xdata must have a prefix
* and it match the module defined in api-path. * and it match the module defined in api-path.
* In a POST, maybe there are cornercases where xdata (which is a child) and * In a POST, maybe there are cornercases where xdata (which is a child) and
@ -577,7 +572,7 @@ api_data_post(clicon_handle h,
if (ymoddata != ymodapi){ if (ymoddata != ymodapi){
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0) if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -594,7 +589,6 @@ api_data_post(clicon_handle h,
goto ok; goto ok;
} }
} }
#endif /* RESTCONF_NS_DATA_CHECK */
/* Add operation (create/replace) as attribute */ /* Add operation (create/replace) as attribute */
if ((xa = xml_new("operation", xdata, NULL)) == NULL) if ((xa = xml_new("operation", xdata, NULL)) == NULL)
@ -620,7 +614,7 @@ api_data_post(clicon_handle h,
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -634,14 +628,14 @@ api_data_post(clicon_handle h,
cprintf(cbx, "<commit/></rpc>"); cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx); cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", username?username:""); cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
cprintf(cbx, "<discard-changes/></rpc>"); cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done; goto done;
/* log errors from discard, but ignore */ /* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) /* Use original xe */ if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) /* Use original xe */
goto done; goto done;
@ -664,7 +658,7 @@ api_data_post(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
/* If copy-config failed, log and ignore (already committed) */ /* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
} }
@ -809,10 +803,8 @@ api_data_put(clicon_handle h,
cxobj *xtop = NULL; /* top of api-path */ cxobj *xtop = NULL; /* top of api-path */
cxobj *xbot = NULL; /* bottom of api-path */ cxobj *xbot = NULL; /* bottom of api-path */
yang_stmt *ybot = NULL; /* yang of xbot */ yang_stmt *ybot = NULL; /* yang of xbot */
#ifdef RESTCONF_NS_DATA_CHECK
yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */ yang_stmt *ymodapi = NULL; /* yang module of api-path (if any) */
yang_stmt *ymoddata = NULL; /* yang module of data (-d) */ yang_stmt *ymoddata = NULL; /* yang module of data (-d) */
#endif
cxobj *xparent; cxobj *xparent;
yang_stmt *yp; /* yang parent */ yang_stmt *yp; /* yang parent */
yang_stmt *yspec; yang_stmt *yspec;
@ -845,15 +837,13 @@ api_data_put(clicon_handle h,
if (api_path){ if (api_path){
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0) if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot)) < 0)
goto done; goto done;
#ifdef RESTCONF_NS_DATA_CHECK
if (ybot) if (ybot)
ymodapi=ys_module(ybot); ymodapi=ys_module(ybot);
#endif
if (ret == 0){ /* validation failed */ if (ret == 0){ /* validation failed */
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
clicon_err_reset(); clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -868,7 +858,7 @@ api_data_put(clicon_handle h,
if (xml_parse_string(data, yspec, &xdata0) < 0){ if (xml_parse_string(data, yspec, &xdata0) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -881,7 +871,7 @@ api_data_put(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){ if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -890,7 +880,7 @@ api_data_put(clicon_handle h,
goto ok; goto ok;
} }
if (ret == 0){ if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -905,7 +895,7 @@ api_data_put(clicon_handle h,
if (xml_child_nr(xdata0) != 1){ if (xml_child_nr(xdata0) != 1){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -914,7 +904,6 @@ api_data_put(clicon_handle h,
goto ok; goto ok;
} }
xdata = xml_child_i(xdata0,0); xdata = xml_child_i(xdata0,0);
#ifdef RESTCONF_NS_DATA_CHECK
/* If the api-path (above) defines a module, then xdata must have a prefix /* If the api-path (above) defines a module, then xdata must have a prefix
* and it match the module defined in api-path * and it match the module defined in api-path
* This does not apply if api-path is / (no module) * This does not apply if api-path is / (no module)
@ -925,7 +914,7 @@ api_data_put(clicon_handle h,
if (ymoddata != ymodapi){ if (ymoddata != ymodapi){
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0) if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -934,7 +923,6 @@ api_data_put(clicon_handle h,
goto ok; goto ok;
} }
} }
#endif /* RESTCONF_NS_DATA_CHECK */
/* Add operation (create/replace) as attribute */ /* Add operation (create/replace) as attribute */
if ((xa = xml_new("operation", xdata, NULL)) == NULL) if ((xa = xml_new("operation", xdata, NULL)) == NULL)
@ -965,7 +953,7 @@ api_data_put(clicon_handle h,
if (strcmp(dname, xml_name(xbot))){ if (strcmp(dname, xml_name(xbot))){
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0) if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -990,7 +978,7 @@ api_data_put(clicon_handle h,
if (match_list_keys(ybot, xdata, xbot) < 0){ if (match_list_keys(ybot, xdata, xbot) < 0){
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1014,7 +1002,7 @@ api_data_put(clicon_handle h,
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){ if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1053,7 +1041,7 @@ api_data_put(clicon_handle h,
clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path);
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -1066,14 +1054,14 @@ api_data_put(clicon_handle h,
cprintf(cbx, "<commit/></rpc>"); cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx); cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", username?username:""); cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
cprintf(cbx, "<discard-changes/></rpc>"); cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done; goto done;
/* log errors from discard, but ignore */ /* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
@ -1096,7 +1084,7 @@ api_data_put(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
/* If copy-config failed, log and ignore (already committed) */ /* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
} }
@ -1204,7 +1192,7 @@ api_data_delete(clicon_handle h,
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
clicon_err_reset(); clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1231,7 +1219,7 @@ api_data_delete(clicon_handle h,
cprintf(cbx, "</edit-config></rpc>"); cprintf(cbx, "</edit-config></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -1245,14 +1233,14 @@ api_data_delete(clicon_handle h,
cprintf(cbx, "<commit/></rpc>"); cprintf(cbx, "<commit/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
cbuf_reset(cbx); cbuf_reset(cbx);
cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER); cprintf(cbx, "<rpc username=\"%s\">", NACM_RECOVERY_USER);
cprintf(cbx, "<discard-changes/></rpc>"); cprintf(cbx, "<discard-changes/></rpc>");
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
goto done; goto done;
/* log errors from discard, but ignore */ /* log errors from discard, but ignore */
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) if ((xpath_first(xretdis, "//rpc-error")) != NULL)
clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__);
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
@ -1275,7 +1263,7 @@ api_data_delete(clicon_handle h,
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
goto done; goto done;
/* If copy-config failed, log and ignore (already committed) */ /* If copy-config failed, log and ignore (already committed) */
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
} }
@ -1442,7 +1430,7 @@ api_operations_post_input(clicon_handle h,
if (xml_parse_string(data, yspec, &xdata) < 0){ if (xml_parse_string(data, yspec, &xdata) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1455,7 +1443,7 @@ api_operations_post_input(clicon_handle h,
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){ if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1464,7 +1452,7 @@ api_operations_post_input(clicon_handle h,
goto fail; goto fail;
} }
if (ret == 0){ if (ret == 0){
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1497,7 +1485,7 @@ api_operations_post_input(clicon_handle h,
else else
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0) if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1571,7 +1559,7 @@ api_operations_post_output(clicon_handle h,
xml_child_nr_type(xret, CX_ELMNT) != 1){ xml_child_nr_type(xret, CX_ELMNT) != 1){
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0) if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1608,7 +1596,7 @@ api_operations_post_output(clicon_handle h,
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0) (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
goto done; goto done;
if (ret == 0){ /* validation failed */ if (ret == 0){ /* validation failed */
if ((xe = xpath_first(xerr, NULL, "rpc-reply/rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1741,7 +1729,7 @@ api_operations_post(clicon_handle h,
if (oppath == NULL || strcmp(oppath,"/")==0){ if (oppath == NULL || strcmp(oppath,"/")==0){
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0) if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1760,7 +1748,7 @@ api_operations_post(clicon_handle h,
if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){ if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0) if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1771,7 +1759,7 @@ api_operations_post(clicon_handle h,
if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){ if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){
if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0) if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0)
goto done; goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1800,7 +1788,7 @@ api_operations_post(clicon_handle h,
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
goto done; goto done;
clicon_err_reset(); clicon_err_reset();
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto done; goto done;
} }
@ -1840,7 +1828,7 @@ api_operations_post(clicon_handle h,
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0) if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){ if ((xe = xpath_first(xret, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
goto ok; goto ok;
} }
@ -1872,7 +1860,7 @@ api_operations_post(clicon_handle h,
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0) if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
goto done; goto done;
/* Local error: return it and quit */ /* Local error: return it and quit */
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -1881,7 +1869,7 @@ api_operations_post(clicon_handle h,
else { /* Send to backend */ else { /* Send to backend */
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
goto done; goto done;
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;

View file

@ -187,11 +187,11 @@ restconf_stream_cb(int s,
clicon_err(OE_PLUGIN, errno, "cbuf_new"); clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done; goto done;
} }
if ((xn = xpath_first(xtop, NULL, "notification")) == NULL) if ((xn = xpath_first(xtop, "notification")) == NULL)
goto ok; goto ok;
#ifdef notused #ifdef notused
xt = xpath_first(xn, NULL, "eventTime"); xt = xpath_first(xn, "eventTime");
if ((xe = xpath_first(xn, NULL, "event")) == NULL) /* event can depend on yang? */ if ((xe = xpath_first(xn, "event")) == NULL) /* event can depend on yang? */
goto ok; goto ok;
if (xt) if (xt)
@ -268,7 +268,7 @@ restconf_stream(clicon_handle h,
cprintf(cb, "</create-subscription></rpc>]]>]]>"); cprintf(cb, "</create-subscription></rpc>]]>]]>");
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0) if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
goto done; goto done;
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xe, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;
@ -416,7 +416,7 @@ api_stream(clicon_handle h,
else{ else{
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0) if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0) if (api_return_err(h, r, xerr, pretty, use_xml, 0) < 0)
goto done; goto done;
goto ok; goto ok;

View file

@ -480,7 +480,7 @@ You use XPATHs on the XML trees in the transaction commit callback.
Suppose you want to print all added interfaces: Suppose you want to print all added interfaces:
``` ```
cxobj *target = transaction_target(td); # wanted XML tree cxobj *target = transaction_target(td); # wanted XML tree
vec = xpath_vec_flag(target, "//interface", &len, XML_FLAG_ADD); /* Get added i/fs */ vec = xpath_vec_flag(target, NULL, "//interface", &len, XML_FLAG_ADD); /* Get added i/fs */
for (i=0; i<len; i++) /* Loop over added i/fs */ for (i=0; i<len; i++) /* Loop over added i/fs */
clicon_xml2file(stdout, vec[i], 0, 1); /* Print the added interface */ clicon_xml2file(stdout, vec[i], 0, 1); /* Print the added interface */
``` ```

View file

@ -128,7 +128,7 @@ main_commit(clicon_handle h,
goto done; goto done;
/* Get all added i/fs */ /* Get all added i/fs */
if (xpath_vec_flag(target, NULL, "//interface", XML_FLAG_ADD, &vec, &len) < 0) if (xpath_vec_flag(target, nsc, "//interface", XML_FLAG_ADD, &vec, &len) < 0)
return -1; return -1;
if (debug) if (debug)
for (i=0; i<len; i++) /* Loop over added i/fs */ for (i=0; i<len; i++) /* Loop over added i/fs */
@ -319,7 +319,7 @@ example_statedata(clicon_handle h,
*/ */
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
goto done; goto done;
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
goto done; goto done;
if (xlen){ if (xlen){
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">"); cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
@ -415,7 +415,7 @@ upgrade_2016(clicon_handle h,
if ((name = xml_find_body(xi, "name")) == NULL) if ((name = xml_find_body(xi, "name")) == NULL)
continue; /* shouldnt happen */ continue; /* shouldnt happen */
/* Get corresponding /interfaces/interface entry */ /* Get corresponding /interfaces/interface entry */
xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name); xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name);
/* - Move /if:interfaces-state/if:interface/if:admin-status to /* - Move /if:interfaces-state/if:interface/if:admin-status to
* /if:interfaces/if:interface/ */ * /if:interfaces/if:interface/ */
if ((x = xml_find(xi, "admin-status")) != NULL && xif){ if ((x = xml_find(xi, "admin-status")) != NULL && xif){
@ -518,7 +518,7 @@ upgrade_2018(clicon_handle h,
/* Change type /interfaces/interface/statistics/in-octets to /* Change type /interfaces/interface/statistics/in-octets to
* decimal64 with fraction-digits 3 and divide values with 1000 * decimal64 with fraction-digits 3 and divide values with 1000
*/ */
if ((x = xpath_first(xi, NULL, "statistics/in-octets")) != NULL){ if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){
if ((xb = xml_body_get(x)) != NULL){ if ((xb = xml_body_get(x)) != NULL){
uint64_t u64; uint64_t u64;
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();

View file

@ -87,7 +87,7 @@ nacm_validate(clicon_handle h,
if (_transaction_log){ if (_transaction_log){
transaction_log(h, td, LOG_NOTICE, __FUNCTION__); transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
if (_transaction_error_toggle==0 && if (_transaction_error_toggle==0 &&
xpath_first(transaction_target(td), NULL, "%s", _transaction_xpath)){ xpath_first(transaction_target(td), "%s", _transaction_xpath)){
_transaction_error_toggle=1; /* toggle if triggered */ _transaction_error_toggle=1; /* toggle if triggered */
clicon_err(OE_XML, 0, "User error"); clicon_err(OE_XML, 0, "User error");
return -1; /* induce fail */ return -1; /* induce fail */
@ -116,7 +116,7 @@ nacm_commit(clicon_handle h,
if (_transaction_log){ if (_transaction_log){
transaction_log(h, td, LOG_NOTICE, __FUNCTION__); transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
if (_transaction_error_toggle==1 && if (_transaction_error_toggle==1 &&
xpath_first(target, NULL, "%s", _transaction_xpath)){ xpath_first(target, "%s", _transaction_xpath)){
_transaction_error_toggle=0; /* toggle if triggered */ _transaction_error_toggle=0; /* toggle if triggered */
clicon_err(OE_XML, 0, "User error"); clicon_err(OE_XML, 0, "User error");
return -1; /* induce fail */ return -1; /* induce fail */

View file

@ -105,7 +105,7 @@ example_client_rpc(clicon_handle h,
/* Send to backend */ /* Send to backend */
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0) if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Get configuration", xerr); clicon_rpc_generate_error("Get configuration", xerr);
goto done; goto done;
} }

View file

@ -48,9 +48,3 @@
*/ */
#define USE_NETCONF_NS_AS_DEFAULT #define USE_NETCONF_NS_AS_DEFAULT
/* Make namespace check on RESTCONF PUT and POST -d data
* Should be defined according to standard
* Undefine it if you want allow no namespace (pick first name it finds in list
* of loaded modules).
*/
#define RESTCONF_NS_DATA_CHECK

View file

@ -116,20 +116,39 @@ char* xpath_tree_int2str(int nodetype);
int xpath_tree_print(cbuf *cb, xpath_tree *xs); int xpath_tree_print(cbuf *cb, xpath_tree *xs);
int xpath_tree_free(xpath_tree *xs); int xpath_tree_free(xpath_tree *xs);
int xpath_parse(cvec *nsc, char *xpath, xpath_tree **xptree); int xpath_parse(cvec *nsc, char *xpath, xpath_tree **xptree);
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...) __attribute__ ((format (printf, 3, 4)));
#else
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *format, ...);
int xpath_vec(cxobj *xcur, cvec *nsc, char *format, cxobj ***vec, size_t *veclen, ...);
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *format, uint16_t flags,
cxobj ***vec, size_t *veclen, ...);
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *format, ...);
#endif
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp); int xpath_vec_ctx(cxobj *xcur, cvec *nsc, char *xpath, xp_ctx **xrp);
#if defined(__GNUC__) && __GNUC__ >= 3
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 7)));
#else
int xpath_vec_bool(cxobj *xcur, cvec *nsc, char *xpformat, ...);
int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags,
cxobj ***vec, size_t *veclen, ...);
#endif
/* Functions with explicit namespace context (nsc) set. If you do not need
* explicit namespace contexts (most do not) consider using the API functions
* below without nsc set.
* If you do not know what a namespace context is, see README.md#xml-and-xpath
*/
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6)));
#else
cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...);
int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...);
#endif
/* Functions with nsc == NULL (implicit xpath context). */
#if defined(__GNUC__) && __GNUC__ >= 3
cxobj *xpath_first(cxobj *xcur, char *xpformat, ...) __attribute__ ((format (printf, 2, 3)));
int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
#else
cxobj *xpath_first(cxobj *xcur, char *xpformat, ...);
int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...);
#endif
#endif /* _CLIXON_XPATH_H */ #endif /* _CLIXON_XPATH_H */

View file

@ -258,7 +258,7 @@ text_read_modstate(clicon_handle h,
if ((name = xml_find_body(xm, "name")) == NULL) if ((name = xml_find_body(xm, "name")) == NULL)
continue; continue;
/* 3a) There is no such module in the system */ /* 3a) There is no such module in the system */
if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){ if ((xs = xpath_first(xmcache, "module[name=\"%s\"]", name)) == NULL){
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name); // fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
if ((xm2 = xml_dup(xm)) == NULL) if ((xm2 = xml_dup(xm)) == NULL)
goto done; goto done;
@ -420,7 +420,7 @@ xmldb_get_nocache(clicon_handle h,
goto done; goto done;
/* Here xt looks like: <config>...</config> */ /* Here xt looks like: <config>...</config> */
/* Given the xpath, return a vector of matches in xvec */ /* Given the xpath, return a vector of matches in xvec */
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* If vectors are specified then mark the nodes found with all ancestors /* If vectors are specified then mark the nodes found with all ancestors
@ -526,7 +526,7 @@ xmldb_get_cache(clicon_handle h,
*/ */
/* Here xt looks like: <config>...</config> */ /* Here xt looks like: <config>...</config> */
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* Make new tree by copying top-of-tree from x0t to x1t */ /* Make new tree by copying top-of-tree from x0t to x1t */
@ -615,7 +615,7 @@ xmldb_get_zerocopy(clicon_handle h,
else else
x0t = de->de_xml; x0t = de->de_xml;
/* Here xt looks like: <config>...</config> */ /* Here xt looks like: <config>...</config> */
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
/* Iterate through the match vector /* Iterate through the match vector
* For every node found in x0, mark the tree up to t1 * For every node found in x0, mark the tree up to t1

View file

@ -662,7 +662,7 @@ xmldb_put(clicon_handle h,
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL) if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL)
goto done; goto done;
if (xnacm0 != NULL && if (xnacm0 != NULL &&
(xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){ (xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) != NULL){
/* Pre-NACM access step, if permit, then dont do any nacm checks in /* Pre-NACM access step, if permit, then dont do any nacm checks in
* text_modify_* below */ * text_modify_* below */
if ((permit = nacm_access(mode, xnacm, username)) < 0) if ((permit = nacm_access(mode, xnacm, username)) < 0)

View file

@ -214,7 +214,7 @@ nacm_rpc(char *rpc,
goto step10; goto step10;
/* User's group */ /* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done; goto done;
/* 5. If no groups are found, continue with step 10. */ /* 5. If no groups are found, continue with step 10. */
if (glen == 0) if (glen == 0)
@ -223,14 +223,14 @@ nacm_rpc(char *rpc,
configuration. If a rule-list's "group" leaf-list does not configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list match any of the user's groups, proceed to the next rule-list
entry. */ entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0) if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done; goto done;
for (i=0; i<rlistlen; i++){ for (i=0; i<rlistlen; i++){
rlist = rlistvec[i]; rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */ /* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){ for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name"); gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL) if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */ break; /* found */
} }
if (j==glen) /* not found */ if (j==glen) /* not found */
@ -239,7 +239,7 @@ nacm_rpc(char *rpc,
until a rule that matches the requested access operation is until a rule that matches the requested access operation is
found. found.
*/ */
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0) if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done; goto done;
for (j=0; j<rlen; j++){ for (j=0; j<rlen; j++){
xrule = rvec[j]; xrule = rvec[j];
@ -390,7 +390,7 @@ nacm_rule_datanode(cxobj *xt,
} }
/* Here module is matched, now check for path if any NYI */ /* Here module is matched, now check for path if any NYI */
if (path){ if (path){
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL) if ((xpath = xpath_first_nsc(xt, nsc, "%s", path)) == NULL)
goto nomatch; goto nomatch;
/* The requested node xr is the node specified by the path or is a /* The requested node xr is the node specified by the path or is a
* descendant node of the path: * descendant node of the path:
@ -447,7 +447,7 @@ nacm_data_read_xr(cxobj *xt,
/* Loop through user's group to find match in this rule-list */ /* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){ for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name"); gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL) if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */ break; /* found */
} }
if (j==glen) /* not found */ if (j==glen) /* not found */
@ -456,7 +456,7 @@ nacm_data_read_xr(cxobj *xt,
until a rule that matches the requested access operation is until a rule that matches the requested access operation is
found. (see 6 sub rules in nacm_rule_datanode found. (see 6 sub rules in nacm_rule_datanode
*/ */
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0) if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done; goto done;
for (j=0; j<rlen; j++){ /* Loop through rules */ for (j=0; j<rlen; j++){ /* Loop through rules */
xrule = rvec[j]; xrule = rvec[j];
@ -588,7 +588,7 @@ nacm_datanode_read(cxobj *xt,
if (username == NULL) if (username == NULL)
goto step9; goto step9;
/* User's group */ /* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done; goto done;
/* 4. If no groups are found (glen=0), continue and check read-default /* 4. If no groups are found (glen=0), continue and check read-default
in step 11. */ in step 11. */
@ -596,7 +596,7 @@ nacm_datanode_read(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list match any of the user's groups, proceed to the next rule-list
entry. */ entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0) if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done; goto done;
/* read-default has default permit so should never be NULL */ /* read-default has default permit so should never be NULL */
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){ if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
@ -713,7 +713,7 @@ nacm_datanode_write(cxobj *xt,
if (username == NULL) if (username == NULL)
goto step9; goto step9;
/* User's group */ /* User's group */
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
goto done; goto done;
/* 4. If no groups are found, continue with step 9. */ /* 4. If no groups are found, continue with step 9. */
if (glen == 0) if (glen == 0)
@ -722,19 +722,19 @@ nacm_datanode_write(cxobj *xt,
configuration. If a rule-list's "group" leaf-list does not configuration. If a rule-list's "group" leaf-list does not
match any of the user's groups, proceed to the next rule-list match any of the user's groups, proceed to the next rule-list
entry. */ entry. */
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0) if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
goto done; goto done;
for (i=0; i<rlistlen; i++){ for (i=0; i<rlistlen; i++){
rlist = rlistvec[i]; rlist = rlistvec[i];
/* Loop through user's group to find match in this rule-list */ /* Loop through user's group to find match in this rule-list */
for (j=0; j<glen; j++){ for (j=0; j<glen; j++){
gname = xml_find_body(gvec[j], "name"); gname = xml_find_body(gvec[j], "name");
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL) if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
break; /* found */ break; /* found */
} }
if (j==glen) /* not found */ if (j==glen) /* not found */
continue; continue;
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0) if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
goto done; goto done;
/* 6. For each rule-list entry found, process all rules, in order, /* 6. For each rule-list entry found, process all rules, in order,
until a rule that matches the requested access operation is until a rule that matches the requested access operation is
@ -862,7 +862,7 @@ nacm_access(char *mode,
* RFC8341 3.4 */ * RFC8341 3.4 */
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol /* 1. If the "enable-nacm" leaf is set to "false", then the protocol
operation is permitted. */ operation is permitted. */
if ((x = xpath_first(xnacm, nsc, "enable-nacm")) == NULL) if ((x = xpath_first_nsc(xnacm, nsc, "enable-nacm")) == NULL)
goto permit; goto permit;
enabled = xml_body(x); enabled = xml_body(x);
if (strcmp(enabled, "true") != 0) if (strcmp(enabled, "true") != 0)
@ -937,7 +937,7 @@ nacm_access_pre(clicon_handle h,
if (xnacm0 == NULL) if (xnacm0 == NULL)
goto permit; goto permit;
/* If config does not exist then the operation is permitted(?) */ /* If config does not exist then the operation is permitted(?) */
if ((xnacm = xpath_first(xnacm0, nsc, "nacm")) == NULL) if ((xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) == NULL)
goto permit; goto permit;
if (xml_rootchild_node(xnacm0, xnacm) < 0) if (xml_rootchild_node(xnacm0, xnacm) < 0)
goto done; goto done;

View file

@ -1303,13 +1303,13 @@ netconf_err2cb(cxobj *xerr,
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
if ((x=xpath_first(xerr, NULL, "error-type"))!=NULL) if ((x=xpath_first(xerr, "error-type"))!=NULL)
cprintf(cb, "%s ", xml_body(x)); cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-tag"))!=NULL) if ((x=xpath_first(xerr, "error-tag"))!=NULL)
cprintf(cb, "%s ", xml_body(x)); cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-message"))!=NULL) if ((x=xpath_first(xerr, "error-message"))!=NULL)
cprintf(cb, "%s ", xml_body(x)); cprintf(cb, "%s ", xml_body(x));
if ((x=xpath_first(xerr, NULL, "error-info"))!=NULL) if ((x=xpath_first(xerr, "error-info"))!=NULL)
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0); clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
*cberr = cb; *cberr = cb;
retval = 0; retval = 0;

View file

@ -201,8 +201,8 @@ parse_configfile(clicon_handle h,
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */ /* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL) if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL)
goto done; goto done;
if ((xc = xpath_first(xt, nsc, "clixon-config")) == NULL){ if ((xc = xpath_first_nsc(xt, nsc, "clixon-config")) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\" (See Changelog in Clixon 3.10)>", filename, CLIXON_CONF_NS); clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: <clixon-config xmlns=\"%s\">", filename, CLIXON_CONF_NS);
goto done; goto done;
} }
@ -362,7 +362,6 @@ clicon_options_main(clicon_handle h,
goto done; goto done;
if (xml_spec(xconfig) == NULL){ if (xml_spec(xconfig) == NULL){
clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"%s\"> or clixon-config.yang not found?", configfile, CLIXON_CONF_NS); clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: <clixon-config xmlns=\"%s\"> or clixon-config.yang not found?", configfile, CLIXON_CONF_NS);
goto done; goto done;
} }
/* Set clixon_conf pointer to handle */ /* Set clixon_conf pointer to handle */

View file

@ -262,7 +262,7 @@ clicon_rpc_generate_error(char *prefix,
* cxobj *xt = NULL; * cxobj *xt = NULL;
* if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0) * if (clicon_rpc_get_config(h, "running", "/hello/world", "urn:example:hello", &xt) < 0)
* err; * err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error("", xerr); * clicon_rpc_generate_error("", xerr);
* err; * err;
* } * }
@ -306,9 +306,9 @@ clicon_rpc_get_config(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
/* Send xml error back: first check error, then ok */ /* Send xml error back: first check error, then ok */
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL) if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */ xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL) else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
if ((xd = xml_new("data", NULL, NULL)) == NULL) if ((xd = xml_new("data", NULL, NULL)) == NULL)
goto done; goto done;
if (xt){ if (xt){
@ -369,7 +369,7 @@ clicon_rpc_edit_config(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Editing configuration", xerr); clicon_rpc_generate_error("Editing configuration", xerr);
goto done; goto done;
} }
@ -415,7 +415,7 @@ clicon_rpc_copy_config(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Copying configuration", xerr); clicon_rpc_generate_error("Copying configuration", xerr);
goto done; goto done;
} }
@ -454,7 +454,7 @@ clicon_rpc_delete_config(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Deleting configuration", xerr); clicon_rpc_generate_error("Deleting configuration", xerr);
goto done; goto done;
} }
@ -489,7 +489,7 @@ clicon_rpc_lock(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Locking configuration", xerr); clicon_rpc_generate_error("Locking configuration", xerr);
goto done; goto done;
} }
@ -523,7 +523,7 @@ clicon_rpc_unlock(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Configuration unlock", xerr); clicon_rpc_generate_error("Configuration unlock", xerr);
goto done; goto done;
} }
@ -550,7 +550,7 @@ clicon_rpc_unlock(clicon_handle h,
* cxobj *xt = NULL; * cxobj *xt = NULL;
* if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", &xt) < 0) * if (clicon_rpc_get(h, "/hello/world", "urn:example:hello", &xt) < 0)
* err; * err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr); * clicon_rpc_generate_error(xerr);
* err; * err;
* } * }
@ -593,9 +593,9 @@ clicon_rpc_get(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
/* Send xml error back: first check error, then ok */ /* Send xml error back: first check error, then ok */
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL) if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
xd = xml_parent(xd); /* point to rpc-reply */ xd = xml_parent(xd); /* point to rpc-reply */
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL) else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
if ((xd = xml_new("data", NULL, NULL)) == NULL) if ((xd = xml_new("data", NULL, NULL)) == NULL)
goto done; goto done;
if (xt){ if (xt){
@ -634,7 +634,7 @@ clicon_rpc_close_session(clicon_handle h)
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Close session", xerr); clicon_rpc_generate_error("Close session", xerr);
goto done; goto done;
} }
@ -669,7 +669,7 @@ clicon_rpc_kill_session(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Kill session", xerr); clicon_rpc_generate_error("Kill session", xerr);
goto done; goto done;
} }
@ -703,7 +703,7 @@ clicon_rpc_validate(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr); clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
goto done; goto done;
} }
@ -735,7 +735,7 @@ clicon_rpc_commit(clicon_handle h)
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr); clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
goto done; goto done;
} }
@ -767,7 +767,7 @@ clicon_rpc_discard_changes(clicon_handle h)
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Discard changes", xerr); clicon_rpc_generate_error("Discard changes", xerr);
goto done; goto done;
} }
@ -812,7 +812,7 @@ clicon_rpc_create_subscription(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, s0) < 0) if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Create subscription", xerr); clicon_rpc_generate_error("Create subscription", xerr);
goto done; goto done;
} }
@ -847,11 +847,11 @@ clicon_rpc_debug(clicon_handle h,
goto done; goto done;
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done; goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Debug",xerr); clicon_rpc_generate_error("Debug",xerr);
goto done; goto done;
} }
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){ if (xpath_first(xret, "//rpc-reply/ok") == NULL){
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */ clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
goto done; goto done;
} }

View file

@ -514,7 +514,7 @@ stream_notify1(clicon_handle h,
else{ /* xpath match */ else{ /* xpath match */
if (ss->ss_xpath == NULL || if (ss->ss_xpath == NULL ||
strlen(ss->ss_xpath)==0 || strlen(ss->ss_xpath)==0 ||
xpath_first(xevent, NULL, "%s", ss->ss_xpath) != NULL) xpath_first(xevent, "%s", ss->ss_xpath) != NULL)
if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0) if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0)
goto done; goto done;
ss = NEXTQ(struct stream_subscription *, ss); ss = NEXTQ(struct stream_subscription *, ss);

View file

@ -200,7 +200,7 @@ changelog_move(clicon_handle h,
int retval = -1; int retval = -1;
cxobj *xp; /* destination parent node */ cxobj *xp; /* destination parent node */
if ((xp = xpath_first(xt, nsc, "%s", dst)) == NULL){ if ((xp = xpath_first_nsc(xt, nsc, "%s", dst)) == NULL){
clicon_err(OE_XML, 0, "path required"); clicon_err(OE_XML, 0, "path required");
goto done; goto done;
} }
@ -253,7 +253,7 @@ changelog_op(clicon_handle h,
if ((wxpath = xml_find_body(xi, "where")) == NULL) if ((wxpath = xml_find_body(xi, "where")) == NULL)
goto ok; goto ok;
/* Get vector of target nodes meeting the where requirement */ /* Get vector of target nodes meeting the where requirement */
if (xpath_vec(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0) if (xpath_vec_nsc(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
goto done; goto done;
for (i=0; i<wlen; i++){ for (i=0; i<wlen; i++){
xw = wvec[i]; xw = wvec[i];
@ -328,7 +328,7 @@ changelog_iterate(clicon_handle h,
int ret; int ret;
int i; int i;
if (xpath_vec(xch, NULL, "step", &vec, &veclen) < 0) if (xpath_vec(xch, "step", &vec, &veclen) < 0)
goto done; goto done;
/* Iterate through changelog items */ /* Iterate through changelog items */
for (i=0; i<veclen; i++){ for (i=0; i<veclen; i++){
@ -392,7 +392,7 @@ xml_changelog_upgrade(clicon_handle h,
* - find all changelogs in the interval: [from, to] * - find all changelogs in the interval: [from, to]
* - note it t=0 then no changelog is applied * - note it t=0 then no changelog is applied
*/ */
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]", if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
&vec, &veclen, namespace) < 0) &vec, &veclen, namespace) < 0)
goto done; goto done;
/* Get all changelogs in the interval [from,to]*/ /* Get all changelogs in the interval [from,to]*/

View file

@ -287,7 +287,7 @@ validate_leafref(cxobj *xt,
/* XXX see comment above regarding typeref or not */ /* XXX see comment above regarding typeref or not */
if (xml_nsctx_yang(ytype, &nsc) < 0) if (xml_nsctx_yang(ytype, &nsc) < 0)
goto done; goto done;
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0) if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
goto done; goto done;
for (i = 0; i < xlen; i++) { for (i = 0; i < xlen; i++) {
x = xvec[i]; x = xvec[i];
@ -2781,7 +2781,7 @@ xml2xpath(cxobj *x,
xt = xml_parent(xt); xt = xml_parent(xt);
xcp = xml_parent(xt); xcp = xml_parent(xt);
xml_parent_set(xt, NULL); xml_parent_set(xt, NULL);
x2 = xpath_first(xt, NULL, "%s", xpath); /* +1: skip first / */ x2 = xpath_first(xt, "%s", xpath); /* +1: skip first / */
xml_parent_set(xt, xcp); xml_parent_set(xt, xcp);
assert(x2 && x==x2); assert(x2 && x==x2);
if (x==x2) if (x==x2)

View file

@ -183,17 +183,17 @@ xpath_tree_free(xpath_tree *xs)
/*! Given XML tree and xpath, parse xpath, eval it and return xpath context, /*! Given XML tree and xpath, parse xpath, eval it and return xpath context,
* This is a raw form of xpath where you can do type conversion, etc, * This is a raw form of xpath where you can do type conversion, etc,
* not just a nodeset. * not just a nodeset.
* @param[in] nsc XML Namespace context * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH 1.0 syntax * @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xptree Xpath-tree, parsed, structured XPATH, free:xpath_tree_free * @param[out] xptree Xpath-tree, parsed, structured XPATH, free:xpath_tree_free
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @code * @code
* xp_ctx *xc = NULL; * xpath_tree *xpt = NULL;
* if (xpath_vec_ctx(x, NULL, xpath, &xc) < 0) * if (xpath_parse(NULL, xpath, &xpt) < 0)
* err; * err;
* if (xc) * if (xpt)
* ctx_free(xc); * xptree_free(xpt);
* @endcode * @endcode
* @see xpath_tree_free * @see xpath_tree_free
*/ */
@ -238,7 +238,7 @@ xpath_parse(cvec *nsc,
* This is a raw form of xpath where you can do type conversion of the return * This is a raw form of xpath where you can do type conversion of the return
* value, etc, not just a nodeset. * value, etc, not just a nodeset.
* @param[in] xcur XML-tree where to search * @param[in] xcur XML-tree where to search
* @param[in] nsc XML Namespace context * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath String with XPATH 1.0 syntax * @param[in] xpath String with XPATH 1.0 syntax
* @param[out] xrp Return XPATH context * @param[out] xrp Return XPATH context
* @retval 0 OK * @retval 0 OK
@ -278,34 +278,32 @@ xpath_vec_ctx(cxobj *xcur,
done: done:
if (xptree) if (xptree)
xpath_tree_free(xptree); xpath_tree_free(xptree);
return retval; return retval;
} }
/*! Xpath nodeset function where only the first matching entry is returned /*! Xpath nodeset function where only the first matching entry is returned
* args: *
* @param[in] xcur XML tree where to search * @param[in] xcur XML tree where to search
* @param[in] nsc XML Namespace context * @param[in] nsc External XML namespace context, or NULL
* @param[in] format string with XPATH syntax * @param[in] xpformat Format string for XPATH syntax
* @retval xml-tree XML tree of first match * @retval xml-tree XML tree of first match
* @retval NULL Error or not found * @retval NULL Error or not found
* *
* @code * @code
* cxobj *x; * cxobj *x;
* cvec *nsc; // namespace context * cvec *nsc; // namespace context
* if ((x = xpath_first(xtop, nsc, "//symbol/foo")) != NULL) { * if ((x = xpath_first_nsc(xtop, nsc, "//symbol/foo")) != NULL) {
* ... * ...
* } * }
* @endcode * @endcode
* @note the returned pointer points into the original tree so should not be freed fter use. * @note the returned pointer points into the original tree so should not be freed after use.
* @note return value does not see difference between error and not found * @note return value does not see difference between error and not found
* @see also xpath_vec. * @see also xpath_vec.
* @experimental
*/ */
cxobj * cxobj *
xpath_first(cxobj *xcur, xpath_first_nsc(cxobj *xcur,
cvec *nsc, cvec *nsc,
char *format, char *xpformat,
...) ...)
{ {
cxobj *cx = NULL; cxobj *cx = NULL;
@ -314,8 +312,8 @@ xpath_first(cxobj *xcur,
char *xpath = NULL; char *xpath = NULL;
xp_ctx *xr = NULL; xp_ctx *xr = NULL;
va_start(ap, format); va_start(ap, xpformat);
len = vsnprintf(NULL, 0, format, ap); len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap); va_end(ap);
/* allocate a message string exactly fitting the message length */ /* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){ if ((xpath = malloc(len+1)) == NULL){
@ -323,8 +321,8 @@ xpath_first(cxobj *xcur,
goto done; goto done;
} }
/* second round: compute write message from reason and args */ /* second round: compute write message from reason and args */
va_start(ap, format); va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, format, ap) < 0){ if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf"); clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap); va_end(ap);
goto done; goto done;
@ -342,11 +340,68 @@ xpath_first(cxobj *xcur,
return cx; return cx;
} }
/*! Xpath nodeset function where only the first matching entry is returned
*
* @param[in] xcur XML tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @retval xml-tree XML tree of first match
* @retval NULL Error or not found
*
* @code
* cxobj *x;
* if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) {
* ...
* }
* @endcode
* @note the returned pointer points into the original tree so should not be freed after use.
* @note return value does not see difference between error and not found
* @see also xpath_vec.
* @see xpath_first_nsc which is more generic with namespace context
*/
cxobj *
xpath_first(cxobj *xcur,
char *xpformat,
...)
{
cxobj *cx = NULL;
va_list ap;
size_t len;
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, xpformat);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
goto done;
if (xr && xr->xc_type == XT_NODESET && xr->xc_size)
cx = xr->xc_nodeset[0];
done:
if (xr)
ctx_free(xr);
if (xpath)
free(xpath);
return cx;
}
/*! Given XML tree and xpath, returns nodeset as xml node vector /*! Given XML tree and xpath, returns nodeset as xml node vector
* If result is not nodeset, return empty nodeset * If result is not nodeset, return empty nodeset
* @param[in] xcur xml-tree where to search * @param[in] xcur xml-tree where to search
* @param[in] format stdarg string with XPATH 1.0 syntax * @param[in] nsc External XML namespace context, or NULL
* @param[in] nsc XML Namespace context for XPATH * @param[in] xpformat Format string for XPATH syntax
* @param[out] vec vector of xml-trees. Vector must be free():d after use * @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value * @param[out] veclen returns length of vector in return value
* @retval 0 OK * @retval 0 OK
@ -355,7 +410,7 @@ xpath_first(cxobj *xcur,
* cvec *nsc; // namespace context * cvec *nsc; // namespace context
* cxobj **vec; * cxobj **vec;
* size_t veclen; * size_t veclen;
* if (xpath_vec(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0) * if (xpath_vec_nsc(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
* goto err; * goto err;
* for (i=0; i<veclen; i++){ * for (i=0; i<veclen; i++){
* xn = vec[i]; * xn = vec[i];
@ -363,12 +418,11 @@ xpath_first(cxobj *xcur,
* } * }
* free(vec); * free(vec);
* @endcode * @endcode
* @note Namespace prefix checking is not properly implemented
*/ */
int int
xpath_vec(cxobj *xcur, xpath_vec_nsc(cxobj *xcur,
cvec *nsc, cvec *nsc,
char *format, char *xpformat,
cxobj ***vec, cxobj ***vec,
size_t *veclen, size_t *veclen,
...) ...)
@ -380,7 +434,7 @@ xpath_vec(cxobj *xcur,
xp_ctx *xr = NULL; xp_ctx *xr = NULL;
va_start(ap, veclen); va_start(ap, veclen);
len = vsnprintf(NULL, 0, format, ap); len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap); va_end(ap);
/* allocate a message string exactly fitting the message length */ /* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){ if ((xpath = malloc(len+1)) == NULL){
@ -389,7 +443,7 @@ xpath_vec(cxobj *xcur,
} }
/* second round: compute write message from reason and args */ /* second round: compute write message from reason and args */
va_start(ap, veclen); va_start(ap, veclen);
if (vsnprintf(xpath, len+1, format, ap) < 0){ if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf"); clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap); va_end(ap);
goto done; goto done;
@ -413,9 +467,77 @@ xpath_vec(cxobj *xcur,
return retval; return retval;
} }
/*! Given XML tree and xpath, returns nodeset as xml node vector
* If result is not nodeset, return empty nodeset
* @param[in] xcur xml-tree where to search
* @param[in] xpformat Format string for XPATH syntax
* @param[out] vec vector of xml-trees. Vector must be free():d after use
* @param[out] veclen returns length of vector in return value
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj **vec;
* size_t veclen;
* if (xpath_vec(xcur, "//symbol/foo", &vec, &veclen) < 0)
* goto err;
* for (i=0; i<veclen; i++){
* xn = vec[i];
* ...
* }
* free(vec);
* @endcode
* @see xpath_vec_nsc which is more generic with namespace context
*/
int
xpath_vec(cxobj *xcur,
char *xpformat,
cxobj ***vec,
size_t *veclen,
...)
{
int retval = -1;
va_list ap;
size_t len;
char *xpath = NULL;
xp_ctx *xr = NULL;
va_start(ap, veclen);
len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap);
/* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
/* second round: compute write message from reason and args */
va_start(ap, veclen);
if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap);
goto done;
}
va_end(ap);
*vec=NULL;
*veclen = 0;
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
goto done;
if (xr && xr->xc_type == XT_NODESET){
*vec = xr->xc_nodeset;
xr->xc_nodeset = NULL;
*veclen = xr->xc_size;
}
retval = 0;
done:
if (xr)
ctx_free(xr);
if (xpath)
free(xpath);
return retval;
}
/* Xpath that returns a vector of matches (only nodes marked with flags) /* Xpath that returns a vector of matches (only nodes marked with flags)
* @param[in] xcur xml-tree where to search * @param[in] xcur xml-tree where to search
* @param[in] xpath string with XPATH syntax * @param[in] xpformat Format string for XPATH syntax
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] flags Set of flags that return nodes must match (0 if all) * @param[in] flags Set of flags that return nodes must match (0 if all)
* @param[out] vec vector of xml-trees. Vector must be free():d after use * @param[out] vec vector of xml-trees. Vector must be free():d after use
@ -434,14 +556,13 @@ xpath_vec(cxobj *xcur,
* } * }
* free(vec); * free(vec);
* @endcode * @endcode
* @Note that although the returned vector must be freed after use, the returned xml * @Note that although the returned vector must be freed after use, the returned xml trees need not be.
* trees need not be.
* @see also xpath_vec This is a specialized version. * @see also xpath_vec This is a specialized version.
*/ */
int int
xpath_vec_flag(cxobj *xcur, xpath_vec_flag(cxobj *xcur,
cvec *nsc, cvec *nsc,
char *format, char *xpformat,
uint16_t flags, uint16_t flags,
cxobj ***vec, cxobj ***vec,
size_t *veclen, size_t *veclen,
@ -456,7 +577,7 @@ xpath_vec_flag(cxobj *xcur,
cxobj *x; cxobj *x;
va_start(ap, veclen); va_start(ap, veclen);
len = vsnprintf(NULL, 0, format, ap); len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap); va_end(ap);
/* allocate a message string exactly fitting the message length */ /* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){ if ((xpath = malloc(len+1)) == NULL){
@ -465,7 +586,7 @@ xpath_vec_flag(cxobj *xcur,
} }
/* second round: compute write message from reason and args */ /* second round: compute write message from reason and args */
va_start(ap, veclen); va_start(ap, veclen);
if (vsnprintf(xpath, len+1, format, ap) < 0){ if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf"); clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap); va_end(ap);
goto done; goto done;
@ -496,7 +617,7 @@ xpath_vec_flag(cxobj *xcur,
* Returns true if the nodeset is non-empty * Returns true if the nodeset is non-empty
* @param[in] xcur xml-tree where to search * @param[in] xcur xml-tree where to search
* @param[in] nsc External XML namespace context, or NULL * @param[in] nsc External XML namespace context, or NULL
* @param[in] xpath stdarg string with XPATH 1.0 syntax * @param[in] xpformat Format string for XPATH syntax
* @retval 1 True * @retval 1 True
* @retval 0 False * @retval 0 False
* @retval -1 Error * @retval -1 Error
@ -504,7 +625,7 @@ xpath_vec_flag(cxobj *xcur,
int int
xpath_vec_bool(cxobj *xcur, xpath_vec_bool(cxobj *xcur,
cvec *nsc, cvec *nsc,
char *format, char *xpformat,
...) ...)
{ {
int retval = -1; int retval = -1;
@ -513,8 +634,8 @@ xpath_vec_bool(cxobj *xcur,
char *xpath = NULL; char *xpath = NULL;
xp_ctx *xr = NULL; xp_ctx *xr = NULL;
va_start(ap, format); va_start(ap, xpformat);
len = vsnprintf(NULL, 0, format, ap); len = vsnprintf(NULL, 0, xpformat, ap);
va_end(ap); va_end(ap);
/* allocate a message string exactly fitting the message length */ /* allocate a message string exactly fitting the message length */
if ((xpath = malloc(len+1)) == NULL){ if ((xpath = malloc(len+1)) == NULL){
@ -522,8 +643,8 @@ xpath_vec_bool(cxobj *xcur,
goto done; goto done;
} }
/* second round: compute write message from reason and args */ /* second round: compute write message from reason and args */
va_start(ap, format); va_start(ap, xpformat);
if (vsnprintf(xpath, len+1, format, ap) < 0){ if (vsnprintf(xpath, len+1, xpformat, ap) < 0){
clicon_err(OE_UNIX, errno, "vsnprintf"); clicon_err(OE_UNIX, errno, "vsnprintf");
va_end(ap); va_end(ap);
goto done; goto done;

View file

@ -305,7 +305,7 @@ yang_modules_state_get(clicon_handle h,
/* xc is also original tree, need to copy it */ /* xc is also original tree, need to copy it */
if ((xw = xml_wrap(xc, "top")) == NULL) if ((xw = xml_wrap(xc, "top")) == NULL)
goto done; goto done;
if (xpath_first(xw, NULL, "%s", xpath)){ if (xpath_first(xw, "%s", xpath)){
if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */ if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */
goto done; goto done;
} }
@ -337,7 +337,7 @@ yang_modules_state_get(clicon_handle h,
if ((x = xml_wrap(x, "top")) < 0) if ((x = xml_wrap(x, "top")) < 0)
goto done; goto done;
/* extract xpath part of module-state tree */ /* extract xpath part of module-state tree */
if (xpath_vec(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) if (xpath_vec_nsc(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
goto done; goto done;
if (xvec != NULL){ if (xvec != NULL){
for (i=0; i<xlen; i++) for (i=0; i<xlen; i++)

View file

@ -154,7 +154,7 @@ main(int argc, char **argv)
} }
if (xml_apply(x0, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(x0, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((xb = xpath_first(x0, NULL, "%s", xpath)) == NULL){ if ((xb = xpath_first(x0, "%s", xpath)) == NULL){
clicon_err(OE_XML, 0, "xpath: %s not found in x0", xpath); clicon_err(OE_XML, 0, "xpath: %s not found in x0", xpath);
goto done; goto done;
} }
@ -169,7 +169,7 @@ main(int argc, char **argv)
} }
if (xml_apply(xi, CX_ELMNT, xml_spec_populate, yspec) < 0) if (xml_apply(xi, CX_ELMNT, xml_spec_populate, yspec) < 0)
goto done; goto done;
if ((xi = xpath_first(xi, NULL, "%s", xpath)) == NULL){ if ((xi = xpath_first(xi, "%s", xpath)) == NULL){
clicon_err(OE_XML, 0, "xpath: %s not found in xi", xpath); clicon_err(OE_XML, 0, "xpath: %s not found in xi", xpath);
goto done; goto done;
} }

View file

@ -194,7 +194,7 @@ main(int argc, char **argv)
/* If xpath0 given, position current x */ /* If xpath0 given, position current x */
if (xpath0){ if (xpath0){
if ((x = xpath_first(x0, NULL, "%s", xpath0)) == NULL){ if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
fprintf(stderr, "Error: xpath0 returned NULL\n"); fprintf(stderr, "Error: xpath0 returned NULL\n");
return -1; return -1;
} }