Merge branch 'master' of https://github.com/clicon/clixon
This commit is contained in:
commit
241ae26e55
137 changed files with 1558 additions and 1405 deletions
|
|
@ -3,7 +3,6 @@ language: c
|
|||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
before_script:
|
||||
- sudo apt-get install -y libfcgi-dev
|
||||
- ./test/travis/before_script.sh
|
||||
|
|
|
|||
32
CHANGELOG.md
32
CHANGELOG.md
|
|
@ -1,5 +1,35 @@
|
|||
# Clixon Changelog
|
||||
|
||||
## 4.3.0 (Expected: December 2019)
|
||||
|
||||
### Minor changes
|
||||
* Added "canonical" global namespace context: `nsctx_global`
|
||||
* This is a normalized XML prefix:namespace pair vector computed from all loaded Yang modules. Useful when writing XML and XPATH expressions in callbacks.
|
||||
* Get it with `clicon_nsctx_global_get(h)`
|
||||
* Added wildcard `*` as a mode to `CLICON_MODE` in clispec files
|
||||
* If you set "CLICON_MODE="*";" in a clispec file it means that syntax will appear in all CLI spec modes.
|
||||
* State callbacks provided by user are validated. If they are invalid an internal error is returned.
|
||||
* Fixed multi-namespace for augmented state which was not covered in 4.2.0.
|
||||
|
||||
### API changes on existing features (you may need to change your code)
|
||||
* Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional).
|
||||
* Clixon and mandatory yang spec are always installed
|
||||
* Optional yang files are loaded only if configured with `--enable-optyangs` (flipped logic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests.
|
||||
* Optional yang files can be installed in a separate dir with `--with-opt-yang-installdir=DIR` (renamed from `with-std-yang-installdir`)
|
||||
* C-API
|
||||
* Added namespace-context parameter `nsc` to `xpath_first` and `xpath_vec`, (`xpath_vec_nsc` and xpath_first_nsc` are removed).
|
||||
* Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message
|
||||
* Added nsc parameter to `xmldb_get()`
|
||||
* The multi-namespace augment state may rearrange the XML namespace attributes.
|
||||
* Main example yang changed to incorporate augmented state, new revision is 2019-11-15.
|
||||
|
||||
### Corrected Bugs
|
||||
* [filter in netconf - one specific entry #100](https://github.com/clicon/clixon/issues/100)
|
||||
* [xpath_tree2cbuf() changes integers into floating point representations #99](https://github.com/clicon/clixon/issues/99)
|
||||
* [xml_parse_string() is slow for a long XML string #96](https://github.com/clicon/clixon/issues/96)
|
||||
* Mandatory variables can no longer be deleted.
|
||||
* [Add missing includes](https://github.com/clicon/clixon/pulls)
|
||||
|
||||
## 4.2.0 (October 27 2019)
|
||||
|
||||
### Summary
|
||||
|
|
@ -12,7 +42,7 @@ The main improvement in thus release concerns security in terms of priveleges an
|
|||
* use `-U <user>` clixon_backend command-line option to drop to `user`
|
||||
* Generic options are the following:
|
||||
* `CLICON_BACKEND_USER` sets the user to drop priveleges to
|
||||
* CLICON_BACKEND_PRIVELEGES can have the following values:
|
||||
* `CLICON_BACKEND_PRIVELEGES` can have the following values:
|
||||
* `none` Make no drop/change in privileges. This is currently the default.
|
||||
* `drop_perm` After initialization, drop privileges permanently
|
||||
* `drop_perm` After initialization, drop privileges temporarily (to a euid)
|
||||
|
|
|
|||
|
|
@ -170,8 +170,8 @@ client_get_capabilities(clicon_handle h,
|
|||
int retval = -1;
|
||||
cxobj *xrstate = NULL; /* xml restconf-state node */
|
||||
cxobj *xcap = NULL; /* xml capabilities node */
|
||||
|
||||
if ((xrstate = xpath_first(*xret, "restconf-state")) == NULL){
|
||||
|
||||
if ((xrstate = xpath_first(*xret, NULL, "restconf-state")) == NULL){
|
||||
clicon_err(OE_YANG, ENOENT, "restconf-state not found in config node");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -321,10 +321,10 @@ client_statedata(clicon_handle h,
|
|||
if (ret == 0)
|
||||
goto fail;
|
||||
/* Code complex to filter out anything that is outside of xpath
|
||||
* Actually this is a safety catch, should realy be done in plugins
|
||||
* Actually this is a safety catch, should really be done in plugins
|
||||
* and modules_state functions.
|
||||
*/
|
||||
if (xpath_vec_nsc(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* If vectors are specified then mark the nodes found and
|
||||
* then filter out everything else,
|
||||
|
|
@ -434,7 +434,7 @@ from_client_get_config(clicon_handle h,
|
|||
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* NACM datanode/module read validation */
|
||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||
|
|
@ -529,14 +529,14 @@ from_client_edit_config(clicon_handle h,
|
|||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
if ((x = xpath_first(xn, "default-operation")) != NULL){
|
||||
if ((x = xpath_first(xn, NULL, "default-operation")) != NULL){
|
||||
if (xml_operation(xml_body(x), &operation) < 0){
|
||||
if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
if ((xc = xpath_first(xn, "config")) == NULL){
|
||||
if ((xc = xpath_first(xn, NULL, "config")) == NULL){
|
||||
if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -967,7 +967,7 @@ from_client_get(clicon_handle h,
|
|||
if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* NACM datanode/module read validation */
|
||||
if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0)
|
||||
|
|
@ -1122,9 +1122,9 @@ from_client_create_subscription(clicon_handle h,
|
|||
|
||||
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL)
|
||||
goto done;
|
||||
if ((x = xpath_first_nsc(xe, nsc, "//stream")) != NULL)
|
||||
if ((x = xpath_first(xe, nsc, "//stream")) != NULL)
|
||||
stream = xml_find_value(x, "body");
|
||||
if ((x = xpath_first_nsc(xe, nsc, "//stopTime")) != NULL){
|
||||
if ((x = xpath_first(xe, nsc, "//stopTime")) != NULL){
|
||||
if ((stoptime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(stoptime, &stop) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0)
|
||||
|
|
@ -1132,7 +1132,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first_nsc(xe, nsc, "//startTime")) != NULL){
|
||||
if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){
|
||||
if ((starttime = xml_find_value(x, "body")) != NULL &&
|
||||
str2time(starttime, &start) < 0){
|
||||
if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0)
|
||||
|
|
@ -1140,7 +1140,7 @@ from_client_create_subscription(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
}
|
||||
if ((xfilter = xpath_first_nsc(xe, nsc, "//filter")) != NULL){
|
||||
if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){
|
||||
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
||||
/* Only accept xpath as filter type */
|
||||
if (strcmp(ftype, "xpath") != 0){
|
||||
|
|
@ -1367,8 +1367,8 @@ from_client_msg(clicon_handle h,
|
|||
goto reply;
|
||||
}
|
||||
|
||||
if ((x = xpath_first_nsc(xt, NULL, "/rpc")) == NULL){
|
||||
if ((x = xpath_first_nsc(xt, NULL, "/hello")) != NULL){
|
||||
if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){
|
||||
if ((x = xpath_first(xt, NULL, "/hello")) != NULL){
|
||||
if ((ret = from_client_hello(h, x, ce, cbret)) <0)
|
||||
goto done;
|
||||
goto reply;
|
||||
|
|
|
|||
|
|
@ -118,10 +118,14 @@ generic_validate(clicon_handle h,
|
|||
for (i=0; i<td->td_dlen; i++){
|
||||
x1 = td->td_dvec[i];
|
||||
ys = xml_spec(x1);
|
||||
if (ys && yang_mandatory(ys) && yang_config(ys)==0){
|
||||
if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "Missing mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
if (ys && yang_mandatory(ys) && yang_config(ys)==1){
|
||||
yang_stmt *yp =yang_parent_get(ys);
|
||||
if (yp== NULL ||
|
||||
(yang_keyword_get(yp)!=Y_MODULE && yang_keyword_get(yp)!=Y_SUBMODULE)){
|
||||
if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "May not remove mandatory variable") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* added entries */
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ backend_terminate(clicon_handle h)
|
|||
cxobj *x;
|
||||
struct stat st;
|
||||
int ss;
|
||||
cvec *nsctx;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((ss = clicon_socket_get(h)) != -1)
|
||||
|
|
@ -110,6 +111,8 @@ backend_terminate(clicon_handle h)
|
|||
yspec_free(yspec);
|
||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
if ((nsctx = clicon_nsctx_global_get(h)) != NULL)
|
||||
cvec_free(nsctx);
|
||||
if ((x = clicon_nacm_ext(h)) != NULL)
|
||||
xml_free(x);
|
||||
if ((x = clicon_conf_xml(h)) != NULL)
|
||||
|
|
@ -443,7 +446,6 @@ main(int argc,
|
|||
char *nacm_mode;
|
||||
int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR;
|
||||
yang_stmt *yspec = NULL;
|
||||
yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
char *str;
|
||||
int ss = -1; /* server socket */
|
||||
cbuf *cbret = NULL; /* startup cbuf if invalid */
|
||||
|
|
@ -451,6 +453,7 @@ main(int argc,
|
|||
int ret;
|
||||
char *dir;
|
||||
gid_t gid = -1;
|
||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||
|
||||
/* In the startup, logs to stderr & syslog and debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
|
@ -505,17 +508,13 @@ main(int argc,
|
|||
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst);
|
||||
clicon_debug_init(debug, NULL);
|
||||
|
||||
/* Create configure yang-spec */
|
||||
if ((yspecfg = yspec_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
/* Find and read configfile */
|
||||
if (clicon_options_main(h, yspecfg) < 0){
|
||||
if (clicon_options_main(h) < 0){
|
||||
if (help)
|
||||
usage(h, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
clicon_config_yang_set(h, yspecfg);
|
||||
|
||||
/* External NACM file? */
|
||||
nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE");
|
||||
if (nacm_mode && strcmp(nacm_mode, "external") == 0)
|
||||
|
|
@ -722,10 +721,10 @@ main(int argc,
|
|||
if ((str = clicon_yang_main_dir(h)) != NULL)
|
||||
if (yang_spec_load_dir(h, str, yspec) < 0)
|
||||
goto done;
|
||||
/* Load clixon lib yang module */
|
||||
/* Load clixon lib yang module */
|
||||
if (yang_spec_parse_module(h, "clixon-lib", NULL, yspec) < 0)
|
||||
goto done;
|
||||
/* Load yang module library, RFC7895 */
|
||||
/* Load yang module library, RFC7895 */
|
||||
if (yang_modules_init(h) < 0)
|
||||
goto done;
|
||||
/* Add netconf yang spec, used by netconf client and as internal protocol
|
||||
|
|
@ -736,13 +735,21 @@ main(int argc,
|
|||
if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0)
|
||||
goto done;
|
||||
/* Load yang Restconf stream discovery */
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
|
||||
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
|
||||
goto done;
|
||||
/* Load yang Netconf stream discovery */
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
|
||||
yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0)
|
||||
goto done;
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") &&
|
||||
yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0)
|
||||
goto done;
|
||||
/* Load yang Netconf stream discovery */
|
||||
if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") &&
|
||||
yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0)
|
||||
goto done;
|
||||
/* Here all modules are loaded
|
||||
* Compute and set canonical namespace context
|
||||
*/
|
||||
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
|
||||
goto done;
|
||||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
|
||||
/* Initialize server socket and save it to handle */
|
||||
if (backend_rpc_init(h) < 0)
|
||||
goto done;
|
||||
|
|
@ -895,7 +902,7 @@ main(int argc,
|
|||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
done:
|
||||
if (cbret)
|
||||
cbuf_free(cbret);
|
||||
clicon_log(LOG_NOTICE, "%s: %u Terminated retval:%d", __PROGRAM__, getpid(), retval);
|
||||
|
|
|
|||
|
|
@ -111,9 +111,11 @@ clixon_plugin_statedata(clicon_handle h,
|
|||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
cxobj *xerr = NULL;
|
||||
cxobj *x = NULL;
|
||||
clixon_plugin *cp = NULL;
|
||||
plgstatedata_t *fn; /* Plugin statedata fn */
|
||||
cbuf *cberr = NULL;
|
||||
|
||||
while ((cp = clixon_plugin_each(h, cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_statedata) == NULL)
|
||||
|
|
@ -124,6 +126,38 @@ clixon_plugin_statedata(clicon_handle h,
|
|||
goto fail; /* Dont quit here on user callbacks */
|
||||
if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
/* Check XML from state callback by validating it. return internal
|
||||
* error with error cause
|
||||
*/
|
||||
if ((ret = xml_yang_validate_all_top(h, x, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret > 0 && (ret = xml_yang_validate_add(h, x, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((cberr = cbuf_new()) ==NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cberr, "Internal error: state callback returned invalid XML: ");
|
||||
if (netconf_err2cb(xpath_first(xerr, NULL, "rpc-error"), cberr) < 0)
|
||||
goto done;
|
||||
if (*xret){
|
||||
xml_free(*xret);
|
||||
*xret = NULL;
|
||||
}
|
||||
if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr))< 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
#if 1
|
||||
if (debug){
|
||||
cbuf *ccc=cbuf_new();
|
||||
if (clicon_xml2cbuf(ccc, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s MERGE: %s", __FUNCTION__, cbuf_get(ccc));
|
||||
cbuf_free(ccc);
|
||||
}
|
||||
#endif
|
||||
if ((ret = netconf_trymerge(x, yspec, xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
|
|
@ -135,8 +169,12 @@ clixon_plugin_statedata(clicon_handle h,
|
|||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (cberr)
|
||||
cbuf_free(cberr);
|
||||
if (x)
|
||||
xml_free(x);
|
||||
if (xerr)
|
||||
xml_free(xerr);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -270,10 +270,12 @@ backend_accept_client(int fd,
|
|||
#error "Need getsockopt O_PEERCRED or getpeereid for unix socket peer cred"
|
||||
#endif
|
||||
if (name != NULL){
|
||||
if ((ce->ce_username = strdup(name)) == NULL){
|
||||
if ((ce->ce_username = name) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
name = NULL;
|
||||
goto done;
|
||||
}
|
||||
name = NULL;
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
|
|
@ -291,5 +293,7 @@ backend_accept_client(int fd,
|
|||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (name)
|
||||
free(name);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ startup_extraxml(clicon_handle h,
|
|||
* It should be empty if extra-xml is null and reset plugins did nothing
|
||||
* then skip validation.
|
||||
*/
|
||||
if (xmldb_get(h, tmp_db, NULL, &xt0) < 0)
|
||||
if (xmldb_get(h, tmp_db, NULL, NULL, &xt0) < 0)
|
||||
goto done;
|
||||
if (xt0==NULL || xml_child_nr(xt0)==0)
|
||||
goto ok;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <regex.h>
|
||||
|
|
|
|||
|
|
@ -714,13 +714,13 @@ compare_dbs(clicon_handle h,
|
|||
astext = 0;
|
||||
if (clicon_rpc_get_config(h, NULL, "running", "/", NULL, &xc1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_get_config(h, NULL, "candidate", "/", NULL, &xc2) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -884,7 +884,7 @@ save_config_file(clicon_handle h,
|
|||
clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */
|
||||
goto done;
|
||||
}
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -992,7 +992,7 @@ cli_notification_cb(int s,
|
|||
}
|
||||
if (clicon_msg_decode(reply, NULL, NULL, &xt) < 0) /* XXX pass yang_spec */
|
||||
goto done;
|
||||
if ((xe = xpath_first(xt, "//event")) != NULL){
|
||||
if ((xe = xpath_first(xt, NULL, "//event")) != NULL){
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
||||
switch (format){
|
||||
|
|
@ -1224,7 +1224,7 @@ cli_copy_config(clicon_handle h,
|
|||
/* Get from object configuration and store in x1 */
|
||||
if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, &x1) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1243,7 +1243,7 @@ cli_copy_config(clicon_handle h,
|
|||
xml_name_set(x2, "config");
|
||||
cprintf(cb, "/%s", keyname);
|
||||
|
||||
if ((x = xpath_first_nsc(x2, nsc, "%s", cbuf_get(cb))) == NULL){
|
||||
if ((x = xpath_first(x2, nsc, "%s", cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname);
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,10 +162,10 @@ cli_cligen(clicon_handle h)
|
|||
|
||||
int
|
||||
cli_parse_file(clicon_handle h,
|
||||
FILE *f,
|
||||
char *name, /* just for errs */
|
||||
parse_tree *pt,
|
||||
cvec *globals)
|
||||
FILE *f,
|
||||
char *name, /* just for errs */
|
||||
parse_tree *pt,
|
||||
cvec *globals)
|
||||
{
|
||||
cligen_handle ch = cligen(h);
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ cli_susp_hook(clicon_handle h,
|
|||
return cligen_susp_hook(ch, fn);
|
||||
}
|
||||
int
|
||||
cli_interrupt_hook(clicon_handle h,
|
||||
cli_interrupt_hook(clicon_handle h,
|
||||
cligen_interrupt_cb_t *fn)
|
||||
{
|
||||
cligen_handle ch = cligen(h);
|
||||
|
|
@ -200,14 +200,16 @@ cli_nomatch(clicon_handle h)
|
|||
}
|
||||
|
||||
int
|
||||
cli_prompt_set(clicon_handle h, char *prompt)
|
||||
cli_prompt_set(clicon_handle h,
|
||||
char *prompt)
|
||||
{
|
||||
cligen_handle ch = cligen(h);
|
||||
return cligen_prompt_set(ch, prompt);
|
||||
}
|
||||
|
||||
int
|
||||
cli_logsyntax_set(clicon_handle h, int status)
|
||||
cli_logsyntax_set(clicon_handle h,
|
||||
int status)
|
||||
{
|
||||
cligen_handle ch = cligen(h);
|
||||
return cligen_logsyntax_set(ch, status);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ static int
|
|||
cli_terminate(clicon_handle h)
|
||||
{
|
||||
yang_stmt *yspec;
|
||||
cvec *nsctx;
|
||||
cxobj *x;
|
||||
|
||||
clicon_rpc_close_session(h);
|
||||
|
|
@ -170,6 +171,8 @@ cli_terminate(clicon_handle h)
|
|||
yspec_free(yspec);
|
||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
if ((nsctx = clicon_nsctx_global_get(h)) != NULL)
|
||||
cvec_free(nsctx);
|
||||
if ((x = clicon_conf_xml(h)) != NULL)
|
||||
xml_free(x);
|
||||
cli_plugin_finish(h);
|
||||
|
|
@ -280,12 +283,12 @@ main(int argc, char **argv)
|
|||
int logdst = CLICON_LOG_STDERR;
|
||||
char *restarg = NULL; /* what remains after options */
|
||||
yang_stmt *yspec;
|
||||
yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
struct passwd *pw;
|
||||
char *str;
|
||||
int tabmode;
|
||||
char *dir;
|
||||
uint32_t id = 0;
|
||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||
|
||||
/* Defaults */
|
||||
once = 0;
|
||||
|
|
@ -348,16 +351,13 @@ main(int argc, char **argv)
|
|||
|
||||
clicon_debug_init(debug, NULL);
|
||||
|
||||
/* Create top-level yang spec and store as option */
|
||||
if ((yspecfg = yspec_new()) == NULL)
|
||||
goto done;
|
||||
/* Find and read configfile */
|
||||
if (clicon_options_main(h, yspecfg) < 0){
|
||||
/* Find, read and parse configfile */
|
||||
if (clicon_options_main(h) < 0){
|
||||
if (help)
|
||||
usage(h, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
clicon_config_yang_set(h, yspecfg);
|
||||
|
||||
/* Now rest of options */
|
||||
opterr = 0;
|
||||
optind = 1;
|
||||
|
|
@ -513,6 +513,14 @@ main(int argc, char **argv)
|
|||
if (netconf_module_load(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Here all modules are loaded
|
||||
* Compute and set canonical namespace context
|
||||
*/
|
||||
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
|
||||
goto done;
|
||||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
|
||||
/* Create tree generated from dataspec. If no other trees exists, this is
|
||||
* the only one.
|
||||
* The following code creates the tree @datamodel
|
||||
|
|
@ -533,7 +541,7 @@ main(int argc, char **argv)
|
|||
cligen_tree_add(cli_cligen(h), treeref, pt);
|
||||
|
||||
if (printgen)
|
||||
cligen_print(stdout, pt, 1);
|
||||
cligen_print(stdout, pt, 1); /* pt_print */
|
||||
}
|
||||
|
||||
/* Initialize cli syntax */
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
|
|
@ -209,27 +208,29 @@ clixon_str2fn(char *name,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*! Append to syntax mode from file
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] filename Name of file where syntax is specified (in syntax-group dir)
|
||||
* @param[in] dir Name of dir, or NULL
|
||||
/*! Load a file containing syntax and append to specified modes, also load C plugin
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] filename Name of file where syntax is specified (in syntax-group dir)
|
||||
* @param[in] dir Name of dir, or NULL
|
||||
* @param[out] allpt Universal CLIgen parse tree: apply to all modes
|
||||
*/
|
||||
static int
|
||||
cli_load_syntax(clicon_handle h,
|
||||
const char *filename,
|
||||
const char *dir)
|
||||
cli_load_syntax_file(clicon_handle h,
|
||||
const char *filename,
|
||||
const char *dir,
|
||||
parse_tree *ptall)
|
||||
{
|
||||
void *handle = NULL; /* Handle to plugin .so module */
|
||||
char *mode = NULL; /* Name of syntax mode to append new syntax */
|
||||
parse_tree pt = {0,};
|
||||
int retval = -1;
|
||||
FILE *f;
|
||||
char filepath[MAXPATHLEN];
|
||||
cvec *cvv = NULL;
|
||||
char *prompt = NULL;
|
||||
char **vec = NULL;
|
||||
int i, nvec;
|
||||
char *plgnam;
|
||||
void *handle = NULL; /* Handle to plugin .so module */
|
||||
char *mode = NULL; /* Name of syntax mode to append new syntax */
|
||||
parse_tree pt = {0,};
|
||||
int retval = -1;
|
||||
FILE *f;
|
||||
char filepath[MAXPATHLEN];
|
||||
cvec *cvv = NULL;
|
||||
char *prompt = NULL;
|
||||
char **vec = NULL;
|
||||
int i, nvec;
|
||||
char *plgnam;
|
||||
clixon_plugin *cp;
|
||||
|
||||
if (dir)
|
||||
|
|
@ -253,10 +254,18 @@ cli_load_syntax(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
fclose(f);
|
||||
/* Get CLICON specific global variables */
|
||||
/* Get CLICON specific global variables:
|
||||
* CLICON_MODE: which mode(s) this syntax applies to
|
||||
* CLICON_PROMPT: Cli prompt in this mode
|
||||
* CLICON_PLUGIN: Name of C API plugin
|
||||
* Note: the base case is that it is:
|
||||
* (1) a single mode or
|
||||
* (2) "*" all modes or "m1:m2" - a list of modes
|
||||
* but for (2), prompt and plgnam may have unclear semantics
|
||||
*/
|
||||
mode = cvec_find_str(cvv, "CLICON_MODE");
|
||||
prompt = cvec_find_str(cvv, "CLICON_PROMPT");
|
||||
plgnam = cvec_find_str(cvv, "CLICON_PLUGIN");
|
||||
mode = cvec_find_str(cvv, "CLICON_MODE");
|
||||
|
||||
if (plgnam != NULL) { /* Find plugin for callback resolving */
|
||||
if ((cp = clixon_plugin_find(h, plgnam)) != NULL)
|
||||
|
|
@ -288,8 +297,19 @@ cli_load_syntax(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
/* Find all modes in CLICON_MODE string: where to append the pt syntax tree */
|
||||
if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL)
|
||||
goto done;
|
||||
|
||||
if (nvec == 1 && strcmp(vec[0], "*") == 0){
|
||||
/* Special case: Add this to all modes. Add to special "universal" syntax
|
||||
* and add to all syntaxes after all files have been loaded. At this point
|
||||
* all modes may not be known (not yet loaded)
|
||||
*/
|
||||
if (cligen_parsetree_merge(ptall, NULL, pt) < 0)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < nvec; i++) {
|
||||
if (syntax_append(h,
|
||||
cli_syntax(h),
|
||||
|
|
@ -300,6 +320,7 @@ cli_load_syntax(clicon_handle h,
|
|||
if (prompt)
|
||||
cli_set_prompt(h, vec[i], prompt);
|
||||
}
|
||||
}
|
||||
|
||||
cligen_parsetree_free(pt, 1);
|
||||
retval = 0;
|
||||
|
|
@ -329,6 +350,7 @@ cli_syntax_load(clicon_handle h)
|
|||
cligen_susp_cb_t *fns = NULL;
|
||||
cligen_interrupt_cb_t *fni = NULL;
|
||||
clixon_plugin *cp;
|
||||
parse_tree ptall = {0,}; /* Universal CLIgen parse tree all modes */
|
||||
|
||||
/* Syntax already loaded. XXX should we re-load?? */
|
||||
if ((stx = cli_syntax(h)) != NULL)
|
||||
|
|
@ -347,30 +369,38 @@ cli_syntax_load(clicon_handle h)
|
|||
|
||||
cli_syntax_set(h, stx);
|
||||
|
||||
/* Load single specific clispec file */
|
||||
if (clispec_file){
|
||||
if (cli_load_syntax(h, clispec_file, NULL) < 0)
|
||||
if (cli_load_syntax_file(h, clispec_file, NULL, &ptall) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Load all clispec .cli files in directory */
|
||||
if (clispec_dir){
|
||||
/* load syntaxfiles */
|
||||
/* Get directory list of files */
|
||||
if ((ndp = clicon_file_dirent(clispec_dir, &dp, "(.cli)$", S_IFREG)) < 0)
|
||||
goto done;
|
||||
/* Load the rest */
|
||||
/* Load the syntax parse trees into cli_syntax stx structure */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
clicon_debug(1, "DEBUG: Loading syntax '%.*s'",
|
||||
(int)strlen(dp[i].d_name)-4, dp[i].d_name);
|
||||
if (cli_load_syntax(h, dp[i].d_name, clispec_dir) < 0)
|
||||
if (cli_load_syntax_file(h, dp[i].d_name, clispec_dir, &ptall) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* Did we successfully load any syntax modes? */
|
||||
/* Were any syntax modes successfully loaded? If not, leave */
|
||||
if (stx->stx_nmodes <= 0) {
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
/* Parse syntax tree for all modes */
|
||||
|
||||
/* Go thorugh all modes and :
|
||||
* 1) Add the universal syntax
|
||||
* 2) add syntax tree (of those modes - "activate" syntax from stx to CLIgen)
|
||||
*/
|
||||
m = stx->stx_modes;
|
||||
do {
|
||||
if (cligen_parsetree_merge(&m->csm_pt, NULL, ptall) < 0)
|
||||
return -1;
|
||||
if (gen_parse_tree(h, m) != 0)
|
||||
goto done;
|
||||
m = NEXTQ(cli_syntaxmode_t *, m);
|
||||
|
|
@ -389,13 +419,13 @@ cli_syntax_load(clicon_handle h)
|
|||
|
||||
/* All good. We can now proudly return a new group */
|
||||
retval = 0;
|
||||
|
||||
done:
|
||||
if (retval != 0) {
|
||||
clixon_plugin_exit(h);
|
||||
cli_syntax_unload(h);
|
||||
cli_syntax_set(h, NULL);
|
||||
}
|
||||
cligen_parsetree_free(ptall, 1);
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ expand_dbvar(void *h,
|
|||
/* Get configuration */
|
||||
if (clicon_rpc_get_config(h, NULL, dbstr, xpath, nsc, &xt) < 0) /* XXX */
|
||||
goto done;
|
||||
if ((xe = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xe);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -204,12 +204,12 @@ expand_dbvar(void *h,
|
|||
fprintf(stderr, "%s\n", reason);
|
||||
goto done;
|
||||
}
|
||||
if ((xcur = xpath_first_nsc(xt, nsc, "%s", xpath)) == NULL){
|
||||
if ((xcur = xpath_first(xt, nsc, "%s", xpath)) == NULL){
|
||||
clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (xpath_vec_nsc(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
|
||||
if (xpath_vec(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0)
|
||||
goto done;
|
||||
/* Loop for inserting into commands cvec.
|
||||
* Detect duplicates: for ordered-by system assume list is ordered, so you need
|
||||
|
|
@ -486,7 +486,7 @@ cli_show_config1(clicon_handle h,
|
|||
if (clicon_rpc_get(h, cbuf_get(cbxpath), nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -634,12 +634,12 @@ show_conf_xpath(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_get_config(h, NULL, str, xpath, nsc, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (xpath_vec_nsc(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
|
||||
if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
|
||||
goto done;
|
||||
for (i=0; i<xlen; i++)
|
||||
xml_print(stdout, xv[i]);
|
||||
|
|
@ -737,11 +737,11 @@ cli_show_auto1(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
|
||||
if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
if ((xp = xpath_first_nsc(xt, nsc, "%s", xpath)) != NULL)
|
||||
if ((xp = xpath_first(xt, nsc, "%s", xpath)) != NULL)
|
||||
/* Print configuration according to format */
|
||||
switch (format){
|
||||
case FORMAT_XML:
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ xml_filter_recursive(cxobj *xfilter,
|
|||
int remove_s;
|
||||
|
||||
*remove_me = 0;
|
||||
assert(xfilter && xparent && strcmp(xml_name(xfilter), xml_name(xparent))==0);
|
||||
/* 1. Check selection */
|
||||
if (xml_child_nr(xfilter) == 0)
|
||||
goto match;
|
||||
|
|
|
|||
|
|
@ -164,14 +164,14 @@ netconf_get_target(cxobj *xn,
|
|||
cxobj *x;
|
||||
char *target = NULL;
|
||||
|
||||
if ((x = xpath_first(xn, "%s", path)) != NULL){
|
||||
if (xpath_first(x, "candidate") != NULL)
|
||||
if ((x = xpath_first(xn, NULL, "%s", path)) != NULL){
|
||||
if (xpath_first(x, NULL, "candidate") != NULL)
|
||||
target = "candidate";
|
||||
else
|
||||
if (xpath_first(x, "running") != NULL)
|
||||
if (xpath_first(x, NULL, "running") != NULL)
|
||||
target = "running";
|
||||
else
|
||||
if (xpath_first(x, "startup") != NULL)
|
||||
if (xpath_first(x, NULL, "startup") != NULL)
|
||||
target = "startup";
|
||||
}
|
||||
return target;
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ netconf_hello_dispatch(cxobj *xn)
|
|||
cxobj *xp;
|
||||
int retval = -1;
|
||||
|
||||
if ((xp = xpath_first(xn, "//hello")) != NULL)
|
||||
if ((xp = xpath_first(xn, NULL, "//hello")) != NULL)
|
||||
retval = netconf_hello(xp);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ netconf_input_packet(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
free(str0);
|
||||
if ((xrpc=xpath_first(xreq, "//rpc")) != NULL){
|
||||
if ((xrpc=xpath_first(xreq, NULL, "//rpc")) != NULL){
|
||||
isrpc++;
|
||||
if (xml_spec_populate_rpc(h, xrpc, yspec) < 0)
|
||||
goto done;
|
||||
|
|
@ -160,7 +160,7 @@ netconf_input_packet(clicon_handle h,
|
|||
}
|
||||
}
|
||||
else
|
||||
if (xpath_first(xreq, "//hello") != NULL)
|
||||
if (xpath_first(xreq, NULL, "//hello") != NULL)
|
||||
;
|
||||
else{
|
||||
clicon_log(LOG_WARNING, "Invalid netconf msg: neither rpc or hello: dropped");
|
||||
|
|
@ -323,6 +323,7 @@ static int
|
|||
netconf_terminate(clicon_handle h)
|
||||
{
|
||||
yang_stmt *yspec;
|
||||
cvec *nsctx;
|
||||
cxobj *x;
|
||||
|
||||
clixon_plugin_exit(h);
|
||||
|
|
@ -332,6 +333,8 @@ netconf_terminate(clicon_handle h)
|
|||
yspec_free(yspec);
|
||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
if ((nsctx = clicon_nsctx_global_get(h)) != NULL)
|
||||
cvec_free(nsctx);
|
||||
if ((x = clicon_conf_xml(h)) != NULL)
|
||||
xml_free(x);
|
||||
event_exit();
|
||||
|
|
@ -392,9 +395,9 @@ main(int argc,
|
|||
struct passwd *pw;
|
||||
struct timeval tv = {0,}; /* timeout */
|
||||
yang_stmt *yspec = NULL;
|
||||
yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
char *str;
|
||||
uint32_t id;
|
||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||
|
||||
/* Create handle */
|
||||
if ((h = clicon_handle_init()) == NULL)
|
||||
|
|
@ -439,13 +442,10 @@ main(int argc,
|
|||
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst);
|
||||
clicon_debug_init(debug, NULL);
|
||||
|
||||
/* Create configure yang-spec */
|
||||
if ((yspecfg = yspec_new()) == NULL)
|
||||
goto done;
|
||||
/* Find and read configfile */
|
||||
if (clicon_options_main(h, yspecfg) < 0)
|
||||
/* Find, read and parse configfile */
|
||||
if (clicon_options_main(h) < 0)
|
||||
return -1;
|
||||
clicon_config_yang_set(h, yspecfg);
|
||||
|
||||
/* Now rest of options */
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
|
|
@ -554,6 +554,14 @@ main(int argc,
|
|||
/* Add netconf yang spec, used by netconf client and as internal protocol */
|
||||
if (netconf_module_load(h) < 0)
|
||||
goto done;
|
||||
/* Here all modules are loaded
|
||||
* Compute and set canonical namespace context
|
||||
*/
|
||||
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
|
||||
goto done;
|
||||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
|
||||
/* Call start function is all plugins before we go interactive */
|
||||
if (clixon_plugin_start(h) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,31 @@
|
|||
</rpc>
|
||||
*/
|
||||
|
||||
static int
|
||||
netconf_get_config_subtree(clicon_handle h,
|
||||
cxobj *xfilter,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xdata;
|
||||
|
||||
/* a subtree filter is comprised of zero or more element subtrees*/
|
||||
if ((xdata = xpath_first(*xret, NULL, "/rpc-reply/data")) == NULL)
|
||||
goto ok;
|
||||
if (xml_filter(xfilter, xdata) < 0){
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>applicatio</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>filtering</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
// done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get configuration
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xn Sub-tree (under xorig) at <rpc>...</rpc> level.
|
||||
|
|
@ -136,37 +161,22 @@ netconf_get_config(clicon_handle h,
|
|||
cxobj *xfilter; /* filter */
|
||||
int retval = -1;
|
||||
char *ftype = NULL;
|
||||
cxobj *xfilterconf;
|
||||
cxobj *xconf;
|
||||
|
||||
/* ie <filter>...</filter> */
|
||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
||||
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
|
||||
ftype = xml_find_value(xfilter, "type");
|
||||
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||
if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(ftype, "subtree")==0){
|
||||
/* Default rfc filter is subtree. I prefer xpath and use it internally.
|
||||
Get whole subtree and then filter aftwerwards. This is suboptimal.
|
||||
Therefore please use xpath.
|
||||
/* Get whole config first, then filter. This is suboptimal
|
||||
*/
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
if (xfilter &&
|
||||
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
|
||||
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
|
||||
/* xml_filter removes parts of xml tree not matching */
|
||||
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
||||
xml_filter(xfilterconf, xconf) < 0){
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>applicatio</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>filtering</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
}
|
||||
}
|
||||
/* Now filter on whole tree */
|
||||
if (netconf_get_config_subtree(h, xfilter, xret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
|
|
@ -208,7 +218,7 @@ get_edit_opts(cxobj *xn,
|
|||
cxobj *x;
|
||||
char *optstr;
|
||||
|
||||
if ((x = xpath_first(xn, "test-option")) != NULL){
|
||||
if ((x = xpath_first(xn, NULL, "test-option")) != NULL){
|
||||
if ((optstr = xml_body(x)) != NULL){
|
||||
if (strcmp(optstr, "test-then-set") == 0)
|
||||
*testopt = TEST_THEN_SET;
|
||||
|
|
@ -220,7 +230,7 @@ get_edit_opts(cxobj *xn,
|
|||
goto parerr;
|
||||
}
|
||||
}
|
||||
if ((x = xpath_first(xn, "error-option")) != NULL){
|
||||
if ((x = xpath_first(xn, NULL, "error-option")) != NULL){
|
||||
if ((optstr = xml_body(x)) != NULL){
|
||||
if (strcmp(optstr, "stop-on-error") == 0)
|
||||
*erropt = STOP_ON_ERROR;
|
||||
|
|
@ -348,37 +358,22 @@ netconf_get(clicon_handle h,
|
|||
cxobj *xfilter; /* filter */
|
||||
int retval = -1;
|
||||
char *ftype = NULL;
|
||||
cxobj *xfilterconf;
|
||||
cxobj *xconf;
|
||||
|
||||
/* ie <filter>...</filter> */
|
||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
||||
if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL)
|
||||
ftype = xml_find_value(xfilter, "type");
|
||||
if (ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||
if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(ftype, "subtree")==0){
|
||||
/* Default rfc filter is subtree. I prefer xpath and use it internally.
|
||||
Get whole subtree and then filter aftwerwards. This is suboptimal.
|
||||
Therefore please use xpath.
|
||||
/* Get whole config + state first, then filter. This is suboptimal
|
||||
*/
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0)
|
||||
goto done;
|
||||
if (xfilter &&
|
||||
(xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL &&
|
||||
(xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){
|
||||
/* xml_filter removes parts of xml tree not matching */
|
||||
if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) ||
|
||||
xml_filter(xfilterconf, xconf) < 0){
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
"<error-tag>operation-failed</error-tag>"
|
||||
"<error-type>applicatio</error-type>"
|
||||
"<error-severity>error</error-severity>"
|
||||
"<error-info>filtering</error-info>"
|
||||
"</rpc-error></rpc-reply>");
|
||||
}
|
||||
}
|
||||
/* Now filter on whole tree */
|
||||
if (netconf_get_config_subtree(h, xfilter, xret) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
|
|
@ -448,7 +443,7 @@ netconf_notification_cb(int s,
|
|||
|
||||
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL)
|
||||
goto done;
|
||||
if ((xn = xpath_first_nsc(xt, nsc, "notification")) == NULL)
|
||||
if ((xn = xpath_first(xt, nsc, "notification")) == NULL)
|
||||
goto ok;
|
||||
/* create netconf message */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
|
|
@ -500,7 +495,7 @@ netconf_create_subscription(clicon_handle h,
|
|||
int s;
|
||||
char *ftype;
|
||||
|
||||
if ((xfilter = xpath_first(xn, "//filter")) != NULL){
|
||||
if ((xfilter = xpath_first(xn, NULL, "//filter")) != NULL){
|
||||
if ((ftype = xml_find_value(xfilter, "type")) != NULL){
|
||||
if (strcmp(ftype, "xpath") != 0){
|
||||
xml_parse_va(xret, NULL, "<rpc-reply><rpc-error>"
|
||||
|
|
@ -516,7 +511,7 @@ netconf_create_subscription(clicon_handle h,
|
|||
}
|
||||
if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0)
|
||||
goto done;
|
||||
if (xpath_first(*xret, "rpc-reply/rpc-error") != NULL)
|
||||
if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL)
|
||||
goto ok;
|
||||
if (event_reg_fd(s,
|
||||
netconf_notification_cb,
|
||||
|
|
@ -622,7 +617,7 @@ netconf_application_rpc(clicon_handle h,
|
|||
*/
|
||||
if (0)
|
||||
if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){
|
||||
xoutput=xpath_first(*xret, "/");
|
||||
xoutput=xpath_first(*xret, NULL, "/");
|
||||
xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */
|
||||
if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ api_return_err(clicon_handle h,
|
|||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
goto done;
|
||||
if ((xtag = xpath_first(xerr, "//error-tag")) == NULL){
|
||||
if ((xtag = xpath_first(xerr, NULL, "//error-tag")) == NULL){
|
||||
restconf_notfound(r);
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -593,6 +593,7 @@ int
|
|||
restconf_terminate(clicon_handle h)
|
||||
{
|
||||
yang_stmt *yspec;
|
||||
cvec *nsctx;
|
||||
cxobj *x;
|
||||
int fs; /* fgcx socket */
|
||||
|
||||
|
|
@ -606,6 +607,8 @@ restconf_terminate(clicon_handle h)
|
|||
yspec_free(yspec);
|
||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||
yspec_free(yspec);
|
||||
if ((nsctx = clicon_nsctx_global_get(h)) != NULL)
|
||||
cvec_free(nsctx);
|
||||
if ((x = clicon_conf_xml(h)) != NULL)
|
||||
xml_free(x);
|
||||
clicon_handle_exit(h);
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ api_restconf(clicon_handle h,
|
|||
else{
|
||||
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -582,13 +582,13 @@ main(int argc,
|
|||
char *dir;
|
||||
int logdst = CLICON_LOG_SYSLOG;
|
||||
yang_stmt *yspec = NULL;
|
||||
yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */
|
||||
char *stream_path;
|
||||
int finish = 0;
|
||||
int start = 1;
|
||||
char *str;
|
||||
clixon_plugin *cp = NULL;
|
||||
uint32_t id = 0;
|
||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||
|
||||
/* In the startup, logs to stderr & debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
|
@ -641,13 +641,10 @@ main(int argc,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* Create configure yang-spec */
|
||||
if ((yspecfg = yspec_new()) == NULL)
|
||||
goto done;
|
||||
/* Find and read configfile */
|
||||
if (clicon_options_main(h, yspecfg) < 0)
|
||||
if (clicon_options_main(h) < 0)
|
||||
goto done;
|
||||
clicon_config_yang_set(h, yspecfg);
|
||||
|
||||
stream_path = clicon_option_str(h, "CLICON_STREAM_PATH");
|
||||
/* Now rest of options, some overwrite option file */
|
||||
optind = 1;
|
||||
|
|
@ -760,6 +757,14 @@ main(int argc,
|
|||
yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0)
|
||||
goto done;
|
||||
|
||||
/* Here all modules are loaded
|
||||
* Compute and set canonical namespace context
|
||||
*/
|
||||
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
|
||||
goto done;
|
||||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
|
||||
/* Dump configuration options on debug */
|
||||
if (debug)
|
||||
clicon_option_dump(h, debug);
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ api_data_write(clicon_handle h,
|
|||
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -296,7 +296,7 @@ api_data_write(clicon_handle h,
|
|||
"candidate", cbuf_get(cbpath), nsc, &xret) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -341,7 +341,7 @@ api_data_write(clicon_handle h,
|
|||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -358,7 +358,7 @@ api_data_write(clicon_handle h,
|
|||
if (data == NULL || strlen(data) == 0){
|
||||
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -373,7 +373,7 @@ api_data_write(clicon_handle h,
|
|||
if (xml_parse_string(data, yspec, &xdata0) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -392,7 +392,7 @@ api_data_write(clicon_handle h,
|
|||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -401,7 +401,7 @@ api_data_write(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -422,7 +422,7 @@ api_data_write(clicon_handle h,
|
|||
if (xml_child_nr(xdata0) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -450,7 +450,7 @@ api_data_write(clicon_handle h,
|
|||
if (ymoddata != ymodapi){
|
||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -493,7 +493,7 @@ api_data_write(clicon_handle h,
|
|||
if (strcmp(dname, xml_name(xbot))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -518,7 +518,7 @@ api_data_write(clicon_handle h,
|
|||
if (match_list_keys(ybot, xdata, xbot) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -542,7 +542,7 @@ api_data_write(clicon_handle h,
|
|||
if (parbod == NULL || strcmp(parbod, xml_body(xdata))){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -603,7 +603,7 @@ api_data_write(clicon_handle h,
|
|||
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)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -616,14 +616,14 @@ api_data_write(clicon_handle h,
|
|||
cprintf(cbx, "<commit/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
cbuf_reset(cbx);
|
||||
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
||||
cprintf(cbx, "<discard-changes/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||
goto done;
|
||||
/* log errors from discard, but ignore */
|
||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
||||
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||
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, media_out, 0) < 0)
|
||||
goto done;
|
||||
|
|
@ -646,7 +646,7 @@ api_data_write(clicon_handle h,
|
|||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
/* If copy-config failed, log and ignore (already committed) */
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
|
||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||
}
|
||||
|
|
@ -840,7 +840,7 @@ api_data_delete(clicon_handle h,
|
|||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -871,7 +871,7 @@ api_data_delete(clicon_handle h,
|
|||
cprintf(cbx, "</edit-config></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -885,14 +885,14 @@ api_data_delete(clicon_handle h,
|
|||
cprintf(cbx, "<commit/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
cbuf_reset(cbx);
|
||||
cprintf(cbx, "<rpc username=\"%s\">", clicon_nacm_recovery_user(h));
|
||||
cprintf(cbx, "<discard-changes/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||
goto done;
|
||||
/* log errors from discard, but ignore */
|
||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
||||
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||
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, media_out, 0) < 0)
|
||||
goto done;
|
||||
|
|
@ -915,7 +915,7 @@ api_data_delete(clicon_handle h,
|
|||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
/* If copy-config failed, log and ignore (already committed) */
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
|
||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ api_data_get2(clicon_handle h,
|
|||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"<bad-attribute>content</bad-attribute>", "Unrecognized value of content attribute") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ api_data_get2(clicon_handle h,
|
|||
if (netconf_bad_attribute_xml(&xerr, "application",
|
||||
"<bad-attribute>depth</bad-attribute>", "Unrecognized value of depth attribute") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -172,7 +172,7 @@ api_data_get2(clicon_handle h,
|
|||
if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -196,7 +196,7 @@ api_data_get2(clicon_handle h,
|
|||
if (ret < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
#endif
|
||||
/* Check if error return */
|
||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -247,10 +247,10 @@ api_data_get2(clicon_handle h,
|
|||
}
|
||||
}
|
||||
else{
|
||||
if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
|
||||
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){
|
||||
if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ api_data_post(clicon_handle h,
|
|||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ api_data_post(clicon_handle h,
|
|||
if (data == NULL || strlen(data) == 0){
|
||||
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -186,7 +186,7 @@ api_data_post(clicon_handle h,
|
|||
if (xml_parse_string(data, NULL, &xdata0) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -208,7 +208,7 @@ api_data_post(clicon_handle h,
|
|||
if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ api_data_post(clicon_handle h,
|
|||
goto ok;
|
||||
}
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -237,7 +237,7 @@ api_data_post(clicon_handle h,
|
|||
if (xml_child_nr(xdata0) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ api_data_post(clicon_handle h,
|
|||
if (ys_real_module(ydata) != ymoddata){
|
||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -282,7 +282,7 @@ api_data_post(clicon_handle h,
|
|||
if (ybot && yang_parent_get(ydata) != ybot){
|
||||
if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -338,7 +338,7 @@ api_data_post(clicon_handle h,
|
|||
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)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -352,14 +352,14 @@ api_data_post(clicon_handle h,
|
|||
cprintf(cbx, "<commit/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
cbuf_reset(cbx);
|
||||
cprintf(cbx, "<rpc username=\"%s\">", username?username:"");
|
||||
cprintf(cbx, "<discard-changes/></rpc>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0)
|
||||
goto done;
|
||||
/* log errors from discard, but ignore */
|
||||
if ((xpath_first(xretdis, "//rpc-error")) != NULL)
|
||||
if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL)
|
||||
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, media_out, 0) < 0) /* Use original xe */
|
||||
goto done;
|
||||
|
|
@ -382,7 +382,7 @@ api_data_post(clicon_handle h,
|
|||
if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0)
|
||||
goto done;
|
||||
/* If copy-config failed, log and ignore (already committed) */
|
||||
if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){
|
||||
|
||||
clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__);
|
||||
}
|
||||
|
|
@ -466,7 +466,7 @@ api_operations_post_input(clicon_handle h,
|
|||
if (xml_parse_string(data, yspec, &xdata) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -479,7 +479,7 @@ api_operations_post_input(clicon_handle h,
|
|||
if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){
|
||||
if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -488,7 +488,7 @@ api_operations_post_input(clicon_handle h,
|
|||
goto fail;
|
||||
}
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -527,7 +527,7 @@ api_operations_post_input(clicon_handle h,
|
|||
else
|
||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -601,7 +601,7 @@ api_operations_post_output(clicon_handle h,
|
|||
xml_child_nr_type(xret, CX_ELMNT) != 1){
|
||||
if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -639,7 +639,7 @@ api_operations_post_output(clicon_handle h,
|
|||
(ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-reply/rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -770,7 +770,7 @@ api_operations_post(clicon_handle h,
|
|||
if (oppath == NULL || strcmp(oppath,"/")==0){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -789,7 +789,7 @@ api_operations_post(clicon_handle h,
|
|||
if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){
|
||||
if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -800,7 +800,7 @@ api_operations_post(clicon_handle h,
|
|||
if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){
|
||||
if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -826,7 +826,7 @@ api_operations_post(clicon_handle h,
|
|||
if ((ret = api_path2xml(oppath, yspec, xtop, YC_SCHEMANODE, 1, &xbot, &y, &xerr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if ((xe = xpath_first(xerr, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -867,7 +867,7 @@ api_operations_post(clicon_handle h,
|
|||
if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if ((xe = xpath_first(xret, "rpc-error")) == NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
|
||||
goto ok;
|
||||
}
|
||||
|
|
@ -900,7 +900,7 @@ api_operations_post(clicon_handle h,
|
|||
if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0)
|
||||
goto done;
|
||||
/* Local error: return it and quit */
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -909,7 +909,7 @@ api_operations_post(clicon_handle h,
|
|||
else { /* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
|
|||
|
|
@ -187,11 +187,11 @@ restconf_stream_cb(int s,
|
|||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((xn = xpath_first(xtop, "notification")) == NULL)
|
||||
if ((xn = xpath_first(xtop, NULL, "notification")) == NULL)
|
||||
goto ok;
|
||||
#ifdef notused
|
||||
xt = xpath_first(xn, "eventTime");
|
||||
if ((xe = xpath_first(xn, "event")) == NULL) /* event can depend on yang? */
|
||||
xt = xpath_first(xn, NULL, "eventTime");
|
||||
if ((xe = xpath_first(xn, NULL, "event")) == NULL) /* event can depend on yang? */
|
||||
goto ok;
|
||||
|
||||
if (xt)
|
||||
|
|
@ -268,7 +268,7 @@ restconf_stream(clicon_handle h,
|
|||
cprintf(cb, "</create-subscription></rpc>]]>]]>");
|
||||
if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0)
|
||||
goto done;
|
||||
if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){
|
||||
if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xe, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
@ -417,7 +417,7 @@ api_stream(clicon_handle h,
|
|||
else{
|
||||
if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
if (api_return_err(h, r, xerr, pretty, media_out, 0) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
|
|
|
|||
59
configure
vendored
59
configure
vendored
|
|
@ -621,7 +621,7 @@ ac_includes_default="\
|
|||
|
||||
ac_subst_vars='LTLIBOBJS
|
||||
LIBOBJS
|
||||
STD_YANG_INSTALLDIR
|
||||
OPT_YANG_INSTALLDIR
|
||||
YANG_INSTALLDIR
|
||||
EGREP
|
||||
GREP
|
||||
|
|
@ -633,7 +633,7 @@ YACC
|
|||
CPP
|
||||
wwwuser
|
||||
wwwdir
|
||||
enable_stdyangs
|
||||
enable_optyangs
|
||||
with_restconf
|
||||
SH_SUFFIX
|
||||
CLIXON_DEFAULT_CONFIG
|
||||
|
|
@ -711,14 +711,14 @@ ac_user_opts='
|
|||
enable_option_checking
|
||||
enable_debug
|
||||
with_cligen
|
||||
enable_stdyangs
|
||||
enable_optyangs
|
||||
enable_publish
|
||||
with_restconf
|
||||
with_wwwuser
|
||||
with_configfile
|
||||
with_libxml2
|
||||
with_yang_installdir
|
||||
with_std_yang_installdir
|
||||
with_opt_yang_installdir
|
||||
'
|
||||
ac_precious_vars='build_alias
|
||||
host_alias
|
||||
|
|
@ -1355,8 +1355,8 @@ Optional Features:
|
|||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-debug Build with debug symbols, default: no
|
||||
--disable-stdyangs Include standard yang files in clixon install,
|
||||
default: yes
|
||||
--enable-optyangs Include standard yang files in clixon install,
|
||||
default: no
|
||||
--enable-publish Enable publish of notification streams using SSE and
|
||||
curl
|
||||
|
||||
|
|
@ -1369,7 +1369,7 @@ Optional Packages:
|
|||
--with-configfile=FILE set default path to config file
|
||||
--with-libxml2 use gnome/libxml2 regex engine
|
||||
--with-yang-installdir=DIR Install Clixon yang files here (default: ${prefix}/share/clixon)
|
||||
--with-std-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon)
|
||||
--with-opt-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon)
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
|
|
@ -2172,9 +2172,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
|||
: ${INSTALLFLAGS="-s"}
|
||||
|
||||
CLIXON_VERSION_MAJOR="4"
|
||||
CLIXON_VERSION_MINOR="2"
|
||||
CLIXON_VERSION_MINOR="3"
|
||||
CLIXON_VERSION_PATCH="0"
|
||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}.PRE\""
|
||||
|
||||
# Check CLIgen
|
||||
if test "$prefix" = "NONE"; then
|
||||
|
|
@ -4247,22 +4247,22 @@ fi
|
|||
# Disable/enable standard Yang files.
|
||||
# If enable - include yang/standard/*.yang in clixon yang files (default)
|
||||
# If disable - get standard yang files from elsewhere
|
||||
# Check whether --enable-stdyangs was given.
|
||||
if test "${enable_stdyangs+set}" = set; then :
|
||||
enableval=$enable_stdyangs;
|
||||
# Check whether --enable-optyangs was given.
|
||||
if test "${enable_optyangs+set}" = set; then :
|
||||
enableval=$enable_optyangs;
|
||||
if test "$enableval" = no; then
|
||||
enable_stdyangs=no
|
||||
enable_optyangs=no
|
||||
else
|
||||
enable_stdyangs=yes
|
||||
enable_optyangs=yes
|
||||
fi
|
||||
|
||||
else
|
||||
enable_stdyangs=yes
|
||||
enable_optyangs=no
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: stdyangs is $enable_stdyangs" >&5
|
||||
$as_echo "stdyangs is $enable_stdyangs" >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: optyangs is $enable_optyangs" >&5
|
||||
$as_echo "optyangs is $enable_optyangs" >&6; }
|
||||
|
||||
# Experimental: Curl publish notification stream to eg Nginx nchan.
|
||||
# Check whether --enable-publish was given.
|
||||
|
|
@ -4933,8 +4933,8 @@ $as_echo "Have getsockopt SO_PEERCRED" >&6; }
|
|||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
|
||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
||||
# (the files in in yang/clixon)
|
||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files and mandatory
|
||||
# standard yang files: the files in in yang/clixon and yang/mandatory
|
||||
# Each application designer may need to place YANG_INSTALLDIR in their config:
|
||||
# <CLICON_YANG_DIR>$YANG_INSTALLDIR</CLICON_YANG_DIR>
|
||||
|
||||
|
|
@ -4950,22 +4950,22 @@ fi
|
|||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Clixon yang files are installed in ${YANG_INSTALLDIR}" >&5
|
||||
$as_echo "Clixon yang files are installed in ${YANG_INSTALLDIR}" >&6; }
|
||||
|
||||
# STD_YANG_INSTALLDIR is where clixon installs standard yang files
|
||||
# (the files in in yang/standard)
|
||||
# OPT_YANG_INSTALLDIR is where clixon installs standard yang files
|
||||
# ( the files in in yang/standard)
|
||||
# that Clixon needs to run (or examples rely on). These may be retreived from
|
||||
# elsewhere (eg yangmodels repo)
|
||||
|
||||
# Check whether --with-std-yang-installdir was given.
|
||||
if test "${with_std_yang_installdir+set}" = set; then :
|
||||
withval=$with_std_yang_installdir; STD_YANG_INSTALLDIR="$withval"
|
||||
# Check whether --with-opt-yang-installdir was given.
|
||||
if test "${with_opt_yang_installdir+set}" = set; then :
|
||||
withval=$with_opt_yang_installdir; OPT_YANG_INSTALLDIR="$withval"
|
||||
else
|
||||
STD_YANG_INSTALLDIR="${prefix}/share/clixon"
|
||||
OPT_YANG_INSTALLDIR="${prefix}/share/clixon"
|
||||
|
||||
fi
|
||||
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Standard yang files are installed in ${STD_YANG_INSTALLDIR}" >&5
|
||||
$as_echo "Standard yang files are installed in ${STD_YANG_INSTALLDIR}" >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled)" >&5
|
||||
$as_echo "Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled)" >&6; }
|
||||
|
||||
# Default location for config file
|
||||
|
||||
|
|
@ -4976,7 +4976,7 @@ _ACEOF
|
|||
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/hello/Makefile extras/rpm/Makefile docker/Makefile docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile test/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/hello/Makefile extras/rpm/Makefile docker/Makefile docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/mandatory/Makefile yang/optional/Makefile doc/Makefile test/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
|
|
@ -5692,7 +5692,8 @@ do
|
|||
"util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;;
|
||||
"yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;;
|
||||
"yang/clixon/Makefile") CONFIG_FILES="$CONFIG_FILES yang/clixon/Makefile" ;;
|
||||
"yang/standard/Makefile") CONFIG_FILES="$CONFIG_FILES yang/standard/Makefile" ;;
|
||||
"yang/mandatory/Makefile") CONFIG_FILES="$CONFIG_FILES yang/mandatory/Makefile" ;;
|
||||
"yang/optional/Makefile") CONFIG_FILES="$CONFIG_FILES yang/optional/Makefile" ;;
|
||||
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
|
||||
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
|
||||
|
||||
|
|
|
|||
39
configure.ac
39
configure.ac
|
|
@ -43,9 +43,9 @@ AC_INIT(lib/clixon/clixon.h.in)
|
|||
: ${INSTALLFLAGS="-s"}
|
||||
|
||||
CLIXON_VERSION_MAJOR="4"
|
||||
CLIXON_VERSION_MINOR="2"
|
||||
CLIXON_VERSION_MINOR="3"
|
||||
CLIXON_VERSION_PATCH="0"
|
||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\""
|
||||
CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}.PRE\""
|
||||
|
||||
# Check CLIgen
|
||||
if test "$prefix" = "NONE"; then
|
||||
|
|
@ -89,7 +89,7 @@ AC_SUBST(CLIXON_DEFAULT_CONFIG)
|
|||
AC_SUBST(LIBS)
|
||||
AC_SUBST(SH_SUFFIX)
|
||||
AC_SUBST(with_restconf) # If yes, compile apps/restconf
|
||||
AC_SUBST(enable_stdyangs)
|
||||
AC_SUBST(enable_optyangs)
|
||||
AC_SUBST(wwwdir,/www-data)
|
||||
AC_SUBST(wwwuser,www-data)
|
||||
|
||||
|
|
@ -151,16 +151,16 @@ fi
|
|||
# Disable/enable standard Yang files.
|
||||
# If enable - include yang/standard/*.yang in clixon yang files (default)
|
||||
# If disable - get standard yang files from elsewhere
|
||||
AC_ARG_ENABLE(stdyangs, AS_HELP_STRING([--disable-stdyangs],[Include standard yang files in clixon install, default: yes]),[
|
||||
AC_ARG_ENABLE(optyangs, AS_HELP_STRING([--enable-optyangs],[Include optional yang files for examples and testing in clixon install, default: no]),[
|
||||
if test "$enableval" = no; then
|
||||
enable_stdyangs=no
|
||||
enable_optyangs=no
|
||||
else
|
||||
enable_stdyangs=yes
|
||||
enable_optyangs=yes
|
||||
fi
|
||||
],
|
||||
[ enable_stdyangs=yes])
|
||||
[ enable_optyangs=no])
|
||||
|
||||
AC_MSG_RESULT(stdyangs is $enable_stdyangs)
|
||||
AC_MSG_RESULT(optyangs is $enable_optyangs)
|
||||
|
||||
# Experimental: Curl publish notification stream to eg Nginx nchan.
|
||||
AC_ARG_ENABLE(publish, AS_HELP_STRING([--enable-publish],[Enable publish of notification streams using SSE and curl]),[
|
||||
|
|
@ -229,8 +229,8 @@ AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versi
|
|||
AC_TRY_COMPILE([#include <sys/socket.h>], [getsockopt(1, SOL_SOCKET, SO_PEERCRED, 0, 0);], [AC_DEFINE(HAVE_SO_PEERCRED, 1, [Have getsockopt SO_PEERCRED])
|
||||
AC_MSG_RESULT(Have getsockopt SO_PEERCRED)])
|
||||
|
||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files
|
||||
# (the files in in yang/clixon)
|
||||
# YANG_INSTALLDIR is where clixon installs the Clixon yang files and mandatory
|
||||
# standard yang files: the files in in yang/clixon and yang/mandatory
|
||||
# Each application designer may need to place YANG_INSTALLDIR in their config:
|
||||
# <CLICON_YANG_DIR>$YANG_INSTALLDIR</CLICON_YANG_DIR>
|
||||
AC_ARG_WITH(yang-installdir,
|
||||
|
|
@ -241,17 +241,17 @@ AC_ARG_WITH(yang-installdir,
|
|||
AC_SUBST(YANG_INSTALLDIR)
|
||||
AC_MSG_RESULT(Clixon yang files are installed in ${YANG_INSTALLDIR})
|
||||
|
||||
# STD_YANG_INSTALLDIR is where clixon installs standard yang files
|
||||
# (the files in in yang/standard)
|
||||
# OPT_YANG_INSTALLDIR is where clixon installs standard yang files
|
||||
# ( the files in in yang/standard)
|
||||
# that Clixon needs to run (or examples rely on). These may be retreived from
|
||||
# elsewhere (eg yangmodels repo)
|
||||
AC_ARG_WITH(std-yang-installdir,
|
||||
[ --with-std-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon) ],
|
||||
[STD_YANG_INSTALLDIR="$withval"],
|
||||
[STD_YANG_INSTALLDIR="${prefix}/share/clixon"]
|
||||
AC_ARG_WITH(opt-yang-installdir,
|
||||
[ --with-opt-yang-installdir=DIR Install optional yang files here (default: ${prefix}/share/clixon) ],
|
||||
[OPT_YANG_INSTALLDIR="$withval"],
|
||||
[OPT_YANG_INSTALLDIR="${prefix}/share/clixon"]
|
||||
)
|
||||
AC_SUBST(STD_YANG_INSTALLDIR)
|
||||
AC_MSG_RESULT(Standard yang files are installed in ${STD_YANG_INSTALLDIR})
|
||||
AC_SUBST(OPT_YANG_INSTALLDIR)
|
||||
AC_MSG_RESULT(Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled))
|
||||
|
||||
# Default location for config file
|
||||
AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${CLIXON_DEFAULT_CONFIG}",[Location for apps to find default config file])
|
||||
|
|
@ -280,7 +280,8 @@ AC_OUTPUT(Makefile
|
|||
util/Makefile
|
||||
yang/Makefile
|
||||
yang/clixon/Makefile
|
||||
yang/standard/Makefile
|
||||
yang/mandatory/Makefile
|
||||
yang/optional/Makefile
|
||||
doc/Makefile
|
||||
test/Makefile
|
||||
)
|
||||
|
|
|
|||
|
|
@ -122,6 +122,12 @@ After release:
|
|||
```
|
||||
* Run autoconf
|
||||
|
||||
Create release branch:
|
||||
```
|
||||
git checkout -b release-4.2 4.2.0
|
||||
git push origin release-4.2
|
||||
```
|
||||
|
||||
## Use of constants etc
|
||||
|
||||
Use MAXPATHLEN (not PATH_MAX)
|
||||
Use MAXPATHLEN (not PATH_MAX)
|
||||
|
|
|
|||
|
|
@ -77,12 +77,14 @@ One of the examples is [a hello world example](../example/hello). Please start w
|
|||
## How do you build and install Clixon?
|
||||
Clixon:
|
||||
```
|
||||
./configure;
|
||||
./configure --enable-optyang;
|
||||
make;
|
||||
sudo make install;
|
||||
sudo make install-include
|
||||
```
|
||||
The main example:
|
||||
(note: optyang enable only if you need to run the main example, otherwise it is not necessary).
|
||||
|
||||
The main example:
|
||||
```
|
||||
cd example;
|
||||
make;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ RUN adduser -D -H www-data
|
|||
RUN apk add --update nginx
|
||||
|
||||
# Configure, build and install clixon
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs
|
||||
RUN make
|
||||
RUN make install
|
||||
RUN make install-include
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ PORT=${PORT:-80}
|
|||
STORE=${STORE:-}
|
||||
|
||||
CONFIG0=$(cat <<EOF
|
||||
<config>
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>/usr/local/etc/example.xml</CLICON_CONFIGFILE>
|
||||
<CLICON_FEATURE>*:*</CLICON_FEATURE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||
|
|
@ -42,7 +42,7 @@ CONFIG0=$(cat <<EOF
|
|||
<CLICON_CLI_LINESCROLLING>0</CLICON_CLI_LINESCROLLING>
|
||||
<CLICON_STARTUP_MODE>init</CLICON_STARTUP_MODE>
|
||||
<CLICON_NACM_MODE>disabled</CLICON_NACM_MODE>
|
||||
</config>
|
||||
</clixon-config>
|
||||
EOF
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ Start restconf daemon
|
|||
|
||||
Start sending restconf commands (using Curl):
|
||||
```
|
||||
olof@vandal> curl -X POST http://localhost/restconf/data -d '{"clixon-hello:hello":{"world":null}}'
|
||||
olof@vandal> curl -X POST http://localhost/restconf/data -H "Content-Type: application/yang-data+json" -d '{"clixon-hello:hello":{"world":null}}'
|
||||
olof@vandal> curl -X GET http://localhost/restconf/data
|
||||
{
|
||||
"data": {
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ all: $(PLUGINS)
|
|||
|
||||
CLISPECS = $(APPNAME)_cli.cli
|
||||
|
||||
YANGSPECS = clixon-example@2019-07-23.yang
|
||||
YANGSPECS = clixon-example@2019-11-05.yang
|
||||
|
||||
# Backend plugin
|
||||
BE_SRC = $(APPNAME)_backend.c
|
||||
|
|
|
|||
|
|
@ -30,13 +30,14 @@ This directory contains a Clixon example used primarily for testing. It can be u
|
|||
* `example_netconf.c` Netconf callback plugin
|
||||
* `Makefile.in` Example makefile where plugins are built and installed
|
||||
|
||||
|
||||
## Compile and run
|
||||
|
||||
Before you start,
|
||||
* You must configure with: `--enable-optyangs` to run the main example.
|
||||
* Make [group setup](../../doc/FAQ.md#do-i-need-to-setup-anything-important)
|
||||
* Setup [restconf](../../doc/FAQ.md#how-do-i-use-restconf)
|
||||
|
||||
|
||||
```
|
||||
cd example
|
||||
make && sudo make install
|
||||
|
|
@ -206,7 +207,7 @@ clixon_netconf -qf /usr/local/etc/example.xml
|
|||
Restconf (assuming nginx started):
|
||||
```
|
||||
sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data&
|
||||
curl -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":"ipv4"}}'
|
||||
curl -X POST http://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"ipv4"}}'
|
||||
{
|
||||
"clixon-example:output": {
|
||||
"x": "ipv4",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ module clixon-example {
|
|||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
revision 2019-11-05 {
|
||||
description "Augment interface. Released in Clixon 4.3.0";
|
||||
}
|
||||
revision 2019-07-23 {
|
||||
description "Extension e4. Released in Clixon 4.1.0";
|
||||
}
|
||||
|
|
@ -42,6 +45,18 @@ module clixon-example {
|
|||
type string;
|
||||
}
|
||||
}
|
||||
augment "/if:interfaces/if:interface" {
|
||||
container my-status {
|
||||
config false;
|
||||
description "For testing augment+state";
|
||||
leaf int {
|
||||
type int32;
|
||||
}
|
||||
leaf str {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* yang extension implemented by the example backend code. */
|
||||
extension e4 {
|
||||
description
|
||||
|
|
@ -317,30 +317,23 @@ example_statedata(clicon_handle h,
|
|||
* state information. In this case adding dummy interface operation state
|
||||
* to configured interfaces.
|
||||
* Get config according to xpath */
|
||||
if (xmldb_get0(h, "running", nsc, xpath, 1, &xt, NULL) < 0)
|
||||
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
|
||||
goto done;
|
||||
|
||||
if (yang_find_module_by_namespace(yspec, "urn:ietf:params:xml:ns:yang:ietf-interfaces") != NULL){
|
||||
/* Here a separate namespace context nsc1 is created. The original nsc
|
||||
* created by the system cannot be used trivially, since we dont know
|
||||
* the prefixes, although we could by a complex mechanism find the prefix
|
||||
* (if it exists) and use that when creating our xpath.
|
||||
* But it is easier creating a new namespace context nsc1.
|
||||
*/
|
||||
if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL)
|
||||
goto done;
|
||||
if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
if (xlen){
|
||||
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
|
||||
for (i=0; i<xlen; i++){
|
||||
name = xml_body(xvec[i]);
|
||||
cprintf(cb, "<interface><name>%s</name><oper-status>up</oper-status></interface>", name);
|
||||
}
|
||||
cprintf(cb, "</interfaces>");
|
||||
if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0)
|
||||
goto done;
|
||||
if (xmldb_get0(h, "running", nsc1, "/interfaces/interface/name", 1, &xt, NULL) < 0)
|
||||
goto done;
|
||||
if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
if (xlen){
|
||||
cprintf(cb, "<interfaces xmlns=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">");
|
||||
for (i=0; i<xlen; i++){
|
||||
name = xml_body(xvec[i]);
|
||||
cprintf(cb, "<interface xmlns:ex=\"urn:example:clixon\"><name>%s</name><type>ex:eth</type><oper-status>up</oper-status>", name);
|
||||
cprintf(cb, "<ex:my-status><ex:int>42</ex:int><ex:str>foo</ex:str></ex:my-status>");
|
||||
cprintf(cb, "</interface>");
|
||||
}
|
||||
cprintf(cb, "</interfaces>");
|
||||
if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* State in test_yang.sh , test_restconf.sh and test_order.sh */
|
||||
if (yang_find_module_by_namespace(yspec, "urn:example:clixon") != NULL){
|
||||
|
|
@ -356,32 +349,14 @@ example_statedata(clicon_handle h,
|
|||
* (2) event-count is XOR on name, so is not 42 and 4
|
||||
*/
|
||||
if (yang_find_module_by_namespace(yspec, "urn:example:events") != NULL){
|
||||
if ((nsc2 = xml_nsctx_init(NULL, "urn:example:events")) == NULL)
|
||||
cbuf_reset(cb);
|
||||
cprintf(cb, "<events xmlns=\"urn:example:events\">");
|
||||
cprintf(cb, "<event><name>interface-down</name><event-count>90</event-count></event>");
|
||||
cprintf(cb, "<event><name>interface-up</name><event-count>77</event-count></event>");
|
||||
cprintf(cb, "</events>");
|
||||
if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0)
|
||||
goto done;
|
||||
if (xvec){
|
||||
free(xvec);
|
||||
xvec = NULL;
|
||||
}
|
||||
if (xpath_vec_nsc(xt, nsc2, "/events/event/name", &xvec, &xlen) < 0)
|
||||
goto done;
|
||||
if (xlen){
|
||||
int j = 0;
|
||||
int c;
|
||||
cprintf(cb, "<events xmlns=\"urn:example:events\">");
|
||||
|
||||
for (i=0; i<xlen; i++){
|
||||
name = xml_body(xvec[i]);
|
||||
c = 0;
|
||||
for (j=0; j<strlen(name); j++)
|
||||
c ^= name[j];
|
||||
cprintf(cb, "<event><name>%s</name><event-count>%d</event-count></event>", name, c);
|
||||
}
|
||||
cprintf(cb, "</events>");
|
||||
if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -500,7 +475,7 @@ upgrade_2016(clicon_handle h,
|
|||
if ((name = xml_find_body(xi, "name")) == NULL)
|
||||
continue; /* shouldnt happen */
|
||||
/* Get corresponding /interfaces/interface entry */
|
||||
xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name);
|
||||
xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name);
|
||||
/* - Move /if:interfaces-state/if:interface/if:admin-status to
|
||||
* /if:interfaces/if:interface/ */
|
||||
if ((x = xml_find(xi, "admin-status")) != NULL && xif){
|
||||
|
|
@ -603,7 +578,7 @@ upgrade_2018(clicon_handle h,
|
|||
/* Change type /interfaces/interface/statistics/in-octets to
|
||||
* decimal64 with fraction-digits 3 and divide values with 1000
|
||||
*/
|
||||
if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){
|
||||
if ((x = xpath_first(xi, NULL, "statistics/in-octets")) != NULL){
|
||||
if ((xb = xml_body_get(x)) != NULL){
|
||||
uint64_t u64;
|
||||
cbuf *cb = cbuf_new();
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ nacm_validate(clicon_handle h,
|
|||
if (_transaction_log){
|
||||
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||
if (_transaction_error_toggle==0 &&
|
||||
xpath_first(transaction_target(td), "%s", _transaction_xpath)){
|
||||
xpath_first(transaction_target(td), NULL, "%s", _transaction_xpath)){
|
||||
_transaction_error_toggle=1; /* toggle if triggered */
|
||||
clicon_err(OE_XML, 0, "User error");
|
||||
return -1; /* induce fail */
|
||||
|
|
@ -116,7 +116,7 @@ nacm_commit(clicon_handle h,
|
|||
if (_transaction_log){
|
||||
transaction_log(h, td, LOG_NOTICE, __FUNCTION__);
|
||||
if (_transaction_error_toggle==1 &&
|
||||
xpath_first(target, "%s", _transaction_xpath)){
|
||||
xpath_first(target, NULL, "%s", _transaction_xpath)){
|
||||
_transaction_error_toggle=0; /* toggle if triggered */
|
||||
clicon_err(OE_XML, 0, "User error");
|
||||
return -1; /* induce fail */
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fnmatch.h> /* matching strings */
|
||||
#include <signal.h> /* matching strings */
|
||||
|
||||
/* clicon */
|
||||
|
|
@ -110,7 +109,7 @@ example_client_rpc(clicon_handle h,
|
|||
/* Send to backend */
|
||||
if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Get configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,20 +51,14 @@
|
|||
#include <sys/param.h> /* MAXPATHLEN */
|
||||
|
||||
/*
|
||||
* CLIXON version macros
|
||||
* CLIXON version macros, set in configure and resolved when expanding to
|
||||
* clixon.h
|
||||
*/
|
||||
|
||||
#undef CLIXON_VERSION_STRING
|
||||
#undef CLIXON_VERSION_MAJOR
|
||||
#undef CLIXON_VERSION_MINOR
|
||||
#undef CLIXON_VERSION_PATCH
|
||||
|
||||
/*
|
||||
* Use this constant to disable some prototypes that should not be visible outside the lib.
|
||||
* This is an alternative to use separate internal include files.
|
||||
*/
|
||||
#define LIBCLIXON_API 1
|
||||
|
||||
#include <clixon/clixon_sig.h>
|
||||
#include <clixon/clixon_uid.h>
|
||||
#include <clixon/clixon_err.h>
|
||||
|
|
|
|||
|
|
@ -40,12 +40,6 @@
|
|||
#ifndef _CLIXON_DATA_H_
|
||||
#define _CLIXON_DATA_H_
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
/* default group membership to access config unix socket */
|
||||
#define CLICON_SOCK_GROUP "clicon"
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
|
@ -61,12 +55,15 @@ typedef struct {
|
|||
yang_stmt * clicon_dbspec_yang(clicon_handle h);
|
||||
int clicon_dbspec_yang_set(clicon_handle h, yang_stmt *ys);
|
||||
|
||||
cxobj * clicon_nacm_ext(clicon_handle h);
|
||||
int clicon_nacm_ext_set(clicon_handle h, cxobj *xn);
|
||||
|
||||
yang_stmt * clicon_config_yang(clicon_handle h);
|
||||
int clicon_config_yang_set(clicon_handle h, yang_stmt *ys);
|
||||
|
||||
cvec *clicon_nsctx_global_get(clicon_handle h);
|
||||
int clicon_nsctx_global_set(clicon_handle h, cvec *nsctx);
|
||||
|
||||
cxobj * clicon_nacm_ext(clicon_handle h);
|
||||
int clicon_nacm_ext_set(clicon_handle h, cxobj *xn);
|
||||
|
||||
cxobj *clicon_conf_xml(clicon_handle h);
|
||||
int clicon_conf_xml_set(clicon_handle h, cxobj *x);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ int xmldb_validate_db(const char *db);
|
|||
int xmldb_connect(clicon_handle h);
|
||||
int xmldb_disconnect(clicon_handle h);
|
||||
/* in clixon_datastore_read.[ch] */
|
||||
int xmldb_get(clicon_handle h, const char *db, char *xpath, cxobj **xtop);
|
||||
int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop);
|
||||
int xmldb_get0(clicon_handle h, const char *db,
|
||||
cvec *nc, char *xpath,
|
||||
cvec *nsc, char *xpath,
|
||||
int copy, cxobj **xtop, modstate_diff_t *msd);
|
||||
int xmldb_get0_clear(clicon_handle h, cxobj *x);
|
||||
int xmldb_get0_free(clicon_handle h, cxobj **xp);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ int netconf_trymerge(cxobj *x, yang_stmt *yspec, cxobj **xret);
|
|||
int netconf_module_features(clicon_handle h);
|
||||
int netconf_module_load(clicon_handle h);
|
||||
char *netconf_db_find(cxobj *xn, char *name);
|
||||
int netconf_err2cb(cxobj *xerr, cbuf **cberr);
|
||||
int netconf_err2cb(cxobj *xerr, cbuf *cberr);
|
||||
const netconf_content netconf_content_str2int(char *str);
|
||||
const char *netconf_content_int2str(netconf_content nr);
|
||||
int netconf_hello_server(clicon_handle h, cbuf *cb, uint32_t session_id);
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@
|
|||
#ifndef _CLIXON_OPTIONS_H_
|
||||
#define _CLIXON_OPTIONS_H_
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
/* default group membership to access config unix socket */
|
||||
#define CLICON_SOCK_GROUP "clicon"
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
|
@ -115,7 +109,7 @@ int clicon_option_dump(clicon_handle h, int dblevel);
|
|||
int clicon_option_add(clicon_handle h, char *name, char *value);
|
||||
|
||||
/* Initialize options: set defaults, read config-file, etc */
|
||||
int clicon_options_main(clicon_handle h, yang_stmt *yspec);
|
||||
int clicon_options_main(clicon_handle h);
|
||||
|
||||
/*! Check if a clicon option has a value */
|
||||
int clicon_option_exists(clicon_handle h, const char *name);
|
||||
|
|
|
|||
|
|
@ -69,14 +69,17 @@ struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...);
|
|||
#endif
|
||||
int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml);
|
||||
|
||||
int clicon_connect_unix(char *sockpath);
|
||||
int clicon_connect_unix(clicon_handle h, char *sockpath);
|
||||
|
||||
int clicon_rpc_connect_unix(struct clicon_msg *msg,
|
||||
|
||||
int clicon_rpc_connect_unix(clicon_handle h,
|
||||
struct clicon_msg *msg,
|
||||
char *sockpath,
|
||||
char **ret,
|
||||
int *sock0);
|
||||
|
||||
int clicon_rpc_connect_inet(struct clicon_msg *msg,
|
||||
int clicon_rpc_connect_inet(clicon_handle h,
|
||||
struct clicon_msg *msg,
|
||||
char *dst,
|
||||
uint16_t port,
|
||||
char **ret,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
|||
int *sock0);
|
||||
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
|
||||
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
||||
int clicon_rpc_generate_error(char *format, cxobj *xerr);
|
||||
int clicon_rpc_generate_error(const char *format, cxobj *xerr);
|
||||
int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, cxobj **xret);
|
||||
int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op,
|
||||
char *xml);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ typedef struct map_str2int map_str2int;
|
|||
/*! A malloc version that aligns on 4 bytes. To avoid warning from valgrind */
|
||||
#define align4(s) (((s)/4)*4 + 4)
|
||||
|
||||
/* Required for the inline to compile */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*! A strdup version that aligns on 4 bytes. To avoid warning from valgrind */
|
||||
static inline char * strdup4(char *str)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ int xml_flag_reset(cxobj *xn, uint16_t flag);
|
|||
|
||||
char *xml_value(cxobj *xn);
|
||||
int xml_value_set(cxobj *xn, char *val);
|
||||
char *xml_value_append(cxobj *xn, char *val);
|
||||
int xml_value_append(cxobj *xn, char *val);
|
||||
enum cxobj_type xml_type(cxobj *xn);
|
||||
int xml_type_set(cxobj *xn, enum cxobj_type type);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
|
|||
|
||||
int xml2xpath(cxobj *x, char **xpath);
|
||||
int xml2api_path_1(cxobj *x, cbuf *cb);
|
||||
int check_namespaces(cxobj *x0, cxobj *x1, cxobj *x1p);
|
||||
int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
|
||||
int yang_enum_int_value(cxobj *node, int32_t *val);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,5 +55,6 @@ int xml_nsctx_get_prefix(cvec *cvv, char *namespace, char **prefix);
|
|||
int xml_nsctx_add(cvec *nsc, char *prefix, char *namespace);
|
||||
int xml_nsctx_node(cxobj *x, cvec **ncp);
|
||||
int xml_nsctx_yang(yang_stmt *yn, cvec **ncp);
|
||||
int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp);
|
||||
|
||||
#endif /* _CLIXON_XML_NSCTX_H */
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ struct xpath_tree{
|
|||
enum xp_type xs_type;
|
||||
int xs_int; /* step-> axis-type */
|
||||
double xs_double;
|
||||
char *xs_strnr; /* original string xs_double: numeric value */
|
||||
char *xs_s0;
|
||||
char *xs_s1;
|
||||
struct xpath_tree *xs_c0; /* child 0 */
|
||||
|
|
@ -142,21 +143,13 @@ int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags,
|
|||
* 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)));
|
||||
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
int xpath_vec(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, ...);
|
||||
cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *xpformat, ...);
|
||||
int xpath_vec(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
|
||||
int xpath2canonical(char *xpath0, cvec *nsc0, yang_stmt *yspec, char **xpath1, cvec **nsc1);
|
||||
|
||||
#endif /* _CLIXON_XPATH_H */
|
||||
|
|
|
|||
|
|
@ -73,8 +73,11 @@
|
|||
#include "clixon_xpath.h"
|
||||
#include "clixon_data.h"
|
||||
|
||||
/*! Get YANG specification for application
|
||||
/*! Get YANG specification for application specs
|
||||
* Must use hash functions directly since they are not strings.
|
||||
* @param[in] h Clicon handle
|
||||
* @retval yspec Yang spec
|
||||
* @see clicon_config_yang for the configuration yang
|
||||
*/
|
||||
yang_stmt *
|
||||
clicon_dbspec_yang(clicon_handle h)
|
||||
|
|
@ -88,8 +91,10 @@ clicon_dbspec_yang(clicon_handle h)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*! Set yang specification for application
|
||||
* ys must be a malloced pointer
|
||||
/*! Set yang specification for application specifications
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] yspec Yang spec (malloced pointer)
|
||||
* @see clicon_config_yang_set for the configuration yang
|
||||
*/
|
||||
int
|
||||
clicon_dbspec_yang_set(clicon_handle h,
|
||||
|
|
@ -105,6 +110,82 @@ clicon_dbspec_yang_set(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Get YANG specification for clixon config (separate from application yangs)
|
||||
* @param[in] h Clicon handle
|
||||
* @retval yspec Yang spec
|
||||
* @see clicon_dbspec_yang for the application specs
|
||||
*/
|
||||
yang_stmt *
|
||||
clicon_config_yang(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
if ((p = clicon_hash_value(cdat, "control_yang", &len)) != NULL)
|
||||
return *(yang_stmt **)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Set yang specification for configuration
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] yspec Yang spec (malloced pointer)
|
||||
* @see clicon_dbspec_yang_set for the application specs
|
||||
*/
|
||||
int
|
||||
clicon_config_yang_set(clicon_handle h,
|
||||
yang_stmt *ys)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
/* It is the pointer to ys that should be copied by hash,
|
||||
so we send a ptr to the ptr to indicate what to copy.
|
||||
*/
|
||||
if (clicon_hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get Global "canonical" namespace context
|
||||
* Canonical: use prefix and namespace specified in the yang modules.
|
||||
* @param[in] h Clicon handle
|
||||
* @retval nsctx Namespace context (malloced)
|
||||
* @code
|
||||
* cvec *nsctx;
|
||||
* nsctx = clicon_nsctx_global_get(h);
|
||||
* @endcode
|
||||
*/
|
||||
cvec *
|
||||
clicon_nsctx_global_get(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
if ((p = clicon_hash_value(cdat, "nsctx_global", &len)) != NULL)
|
||||
return *(cvec **)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Set global "canonical" namespace context
|
||||
* Canonical: use prefix and namespace specified in the yang modules.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] nsctx Namespace context (malloced)
|
||||
*/
|
||||
int
|
||||
clicon_nsctx_global_set(clicon_handle h,
|
||||
cvec *nsctx)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
/* It is the pointer to cvec that should be copied by hash,
|
||||
so we send a ptr to the ptr to indicate what to copy.
|
||||
*/
|
||||
if (clicon_hash_add(cdat, "nsctx_global", &nsctx, sizeof(nsctx)) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get NACM (rfc 8341) XML parse tree if external not in std xml config
|
||||
* @param[in] h Clicon handle
|
||||
* @retval xn XML NACM tree, or NULL
|
||||
|
|
@ -146,41 +227,6 @@ clicon_nacm_ext_set(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 1 /* Temporary function until "Top-level Yang symbol cannot be called "config"" is fixed */
|
||||
/*! Get YANG specification for clixon config
|
||||
* Must use hash functions directly since they are not strings.
|
||||
*/
|
||||
yang_stmt *
|
||||
clicon_config_yang(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
if ((p = clicon_hash_value(cdat, "control_yang", &len)) != NULL)
|
||||
return *(yang_stmt **)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Set yang specification for control
|
||||
* ys must be a malloced pointer
|
||||
*/
|
||||
int
|
||||
clicon_config_yang_set(clicon_handle h,
|
||||
yang_stmt *ys)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
|
||||
/* It is the pointer to ys that should be copied by hash,
|
||||
so we send a ptr to the ptr to indicate what to copy.
|
||||
*/
|
||||
if (clicon_hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! Get YANG specification for Clixon system options and features
|
||||
* Must use hash functions directly since they are not strings.
|
||||
* Example: features are typically accessed directly in the config tree.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -264,7 +263,7 @@ text_read_modstate(clicon_handle h,
|
|||
if ((name = xml_find_body(xm, "name")) == NULL)
|
||||
continue;
|
||||
/* 3a) There is no such module in the system */
|
||||
if ((xs = xpath_first(xmcache, "module[name=\"%s\"]", name)) == NULL){
|
||||
if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){
|
||||
// fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name);
|
||||
if ((xm2 = xml_dup(xm)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -426,7 +425,7 @@ xmldb_get_nocache(clicon_handle h,
|
|||
goto done;
|
||||
/* Here xt looks like: <config>...</config> */
|
||||
/* Given the xpath, return a vector of matches in xvec */
|
||||
if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
|
||||
/* If vectors are specified then mark the nodes found with all ancestors
|
||||
|
|
@ -532,7 +531,7 @@ xmldb_get_cache(clicon_handle h,
|
|||
*/
|
||||
|
||||
/* Here xt looks like: <config>...</config> */
|
||||
if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
|
||||
/* Make new tree by copying top-of-tree from x0t to x1t */
|
||||
|
|
@ -621,7 +620,7 @@ xmldb_get_zerocopy(clicon_handle h,
|
|||
else
|
||||
x0t = de->de_xml;
|
||||
/* Here xt looks like: <config>...</config> */
|
||||
if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
/* Iterate through the match vector
|
||||
* For every node found in x0, mark the tree up to t1
|
||||
|
|
@ -648,12 +647,13 @@ xmldb_get_zerocopy(clicon_handle h,
|
|||
/*! Get content of datastore and return a copy of the XML tree
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] db Name of database to search in (filename including dir path
|
||||
* @param[in] nsc XML namespace context for XPATH
|
||||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", &xt) < 0)
|
||||
* if (xmldb_get(xh, "running", NULL, "/interfaces/interface[name="eth"]", &xt) < 0)
|
||||
* err;
|
||||
* xml_free(xt);
|
||||
* @endcode
|
||||
|
|
@ -662,10 +662,11 @@ xmldb_get_zerocopy(clicon_handle h,
|
|||
int
|
||||
xmldb_get(clicon_handle h,
|
||||
const char *db,
|
||||
cvec *nsc,
|
||||
char *xpath,
|
||||
cxobj **xret)
|
||||
{
|
||||
return xmldb_get0(h, db, NULL, xpath, 1, xret, NULL);
|
||||
return xmldb_get0(h, db, nsc, xpath, 1, xret, NULL);
|
||||
}
|
||||
|
||||
/*! Zero-copy variant of get content of database
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -133,138 +132,6 @@ attr_ns_value(cxobj *x,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Given a src node x0 and a target node x1, assign (optional) prefix and namespace
|
||||
* @param[in] x0 Source XML tree
|
||||
* @param[in] x1 Target XML tree
|
||||
* 1. Find N=namespace(x0)
|
||||
* 2. Detect if N is declared in x1 parent
|
||||
* 3. If yes, assign prefix to x1
|
||||
* 4. If no, create new prefix/namespace binding and assign that to x1p (x1 if x1p is root)
|
||||
* 5. Add prefix to x1, if any
|
||||
* 6. Ensure x1 cache is updated
|
||||
* @note switch use of x0 and x1 compared to datastore text_modify
|
||||
* @see xml2ns
|
||||
* XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
|
||||
goto done;
|
||||
*/
|
||||
static int
|
||||
check_namespaces(cxobj *x0,
|
||||
cxobj *x1,
|
||||
cxobj *x1p)
|
||||
{
|
||||
int retval = -1;
|
||||
char *namespace = NULL;
|
||||
char *prefix0 = NULL;;
|
||||
char *prefix10 = NULL; /* extra just for malloc problem */
|
||||
char *prefix1 = NULL;;
|
||||
char *prefixb = NULL; /* identityref body prefix */
|
||||
cvec *nsc0 = NULL;
|
||||
cvec *nsc = NULL;
|
||||
cxobj *xa = NULL;
|
||||
cxobj *x;
|
||||
int isroot;
|
||||
|
||||
/* XXX: need to identify root better than hiereustics and strcmp,... */
|
||||
isroot = xml_parent(x1p)==NULL &&
|
||||
strcmp(xml_name(x1p), "config") == 0 &&
|
||||
xml_prefix(x1p)==NULL;
|
||||
|
||||
/* 1. Find N=namespace(x0) */
|
||||
prefix0 = xml_prefix(x0);
|
||||
if (xml2ns(x0, prefix0, &namespace) < 0)
|
||||
goto done;
|
||||
if (namespace == NULL){
|
||||
clicon_err(OE_XML, ENOENT, "No namespace found for prefix:%s",
|
||||
prefix0?prefix0:"NULL");
|
||||
goto done;
|
||||
}
|
||||
/* 2. Detect if namespace is declared in x1:s parent */
|
||||
if (xml2prefix(x1p, namespace, &prefix10) == 1){
|
||||
if (prefix10){
|
||||
if ((prefix1 = strdup(prefix10)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
prefix1 = NULL;
|
||||
/* 3. If yes, assign prefix to x1 */
|
||||
if (prefix1 && xml_prefix_set(x1, prefix1) < 0)
|
||||
goto done;
|
||||
/* And copy namespace context from parent to child */
|
||||
if ((nsc0 = nscache_get_all(x1p)) != NULL){
|
||||
if ((nsc = cvec_dup(nsc0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
nscache_replace(x1, nsc);
|
||||
}
|
||||
/* Just in case */
|
||||
if (nscache_set(x1, prefix1, namespace) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
/* 4. If no, create new prefix/namespace binding and assign that to x1p
|
||||
* use modules own default prefix (some chance for clash)
|
||||
*/
|
||||
if (prefix0 == NULL && !isroot){
|
||||
assert(xml_spec(x1) != NULL);
|
||||
prefix0 = yang_find_myprefix(xml_spec(x1));
|
||||
}
|
||||
if (prefix0)
|
||||
if ((prefix1 = strdup(prefix0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Add binding to x1p. We add to parent due to heurestics, so we dont
|
||||
* end up in adding it to large number of siblings
|
||||
*/
|
||||
if (isroot)
|
||||
x = x1;
|
||||
else
|
||||
x = x1p;
|
||||
if (nscache_set(x, prefix1, namespace) < 0)
|
||||
goto done;
|
||||
if (x == x1p){
|
||||
if ((nsc0 = nscache_get_all(x1p)) != NULL)
|
||||
if ((nsc = cvec_dup(nsc0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
/* Copy x1p cache to x1 */
|
||||
nscache_replace(x1, nsc);
|
||||
}
|
||||
/* Create xmlns attribute to x1p/x1 XXX same code v */
|
||||
if (prefix1){
|
||||
if ((xa = xml_new(prefix1, x, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_prefix_set(xa, "xmlns") < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if ((xa = xml_new("xmlns", x, NULL)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, namespace) < 0)
|
||||
goto done;
|
||||
xml_sort(x, NULL); /* Ensure attr is first / XXX xml_insert? */
|
||||
|
||||
/* 5. Add prefix to x1, if any */
|
||||
if (prefix1 && xml_prefix_set(x1, prefix1) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */
|
||||
retval = 0;
|
||||
done:
|
||||
if (prefixb)
|
||||
free(prefixb);
|
||||
if (prefix1)
|
||||
free(prefix1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
check_identityref(cxobj *x0,
|
||||
cxobj *x1,
|
||||
|
|
@ -1020,7 +887,7 @@ xmldb_put(clicon_handle h,
|
|||
if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL)
|
||||
goto done;
|
||||
if (xnacm0 != NULL &&
|
||||
(xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) != NULL){
|
||||
(xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){
|
||||
/* Pre-NACM access step, if permit, then dont do any nacm checks in
|
||||
* text_modify_* below */
|
||||
if ((permit = nacm_access(h, mode, xnacm, username)) < 0)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ json_current_body(struct clicon_json_yacc_arg *jy,
|
|||
if ((xn = xml_new("body", jy->jy_current, NULL)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xn, CX_BODY);
|
||||
if (value && xml_value_append(xn, value)==NULL)
|
||||
if (value && xml_value_append(xn, value) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
|
@ -214,7 +213,7 @@ nacm_rpc(char *rpc,
|
|||
goto step10;
|
||||
|
||||
/* User's group */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
goto done;
|
||||
/* 5. If no groups are found, continue with step 10. */
|
||||
if (glen == 0)
|
||||
|
|
@ -223,14 +222,14 @@ nacm_rpc(char *rpc,
|
|||
configuration. If a rule-list's "group" leaf-list does not
|
||||
match any of the user's groups, proceed to the next rule-list
|
||||
entry. */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
goto done;
|
||||
for (i=0; i<rlistlen; i++){
|
||||
rlist = rlistvec[i];
|
||||
/* Loop through user's group to find match in this rule-list */
|
||||
for (j=0; j<glen; j++){
|
||||
gname = xml_find_body(gvec[j], "name");
|
||||
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
break; /* found */
|
||||
}
|
||||
if (j==glen) /* not found */
|
||||
|
|
@ -239,7 +238,7 @@ nacm_rpc(char *rpc,
|
|||
until a rule that matches the requested access operation is
|
||||
found.
|
||||
*/
|
||||
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
goto done;
|
||||
for (j=0; j<rlen; j++){
|
||||
xrule = rvec[j];
|
||||
|
|
@ -390,7 +389,7 @@ nacm_rule_datanode(cxobj *xt,
|
|||
}
|
||||
/* Here module is matched, now check for path if any NYI */
|
||||
if (path){
|
||||
if ((xpath = xpath_first_nsc(xt, nsc, "%s", path)) == NULL)
|
||||
if ((xpath = xpath_first(xt, nsc, "%s", path)) == NULL)
|
||||
goto nomatch;
|
||||
/* The requested node xr is the node specified by the path or is a
|
||||
* descendant node of the path:
|
||||
|
|
@ -447,7 +446,7 @@ nacm_data_read_xr(cxobj *xt,
|
|||
/* Loop through user's group to find match in this rule-list */
|
||||
for (j=0; j<glen; j++){
|
||||
gname = xml_find_body(gvec[j], "name");
|
||||
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
break; /* found */
|
||||
}
|
||||
if (j==glen) /* not found */
|
||||
|
|
@ -456,7 +455,7 @@ nacm_data_read_xr(cxobj *xt,
|
|||
until a rule that matches the requested access operation is
|
||||
found. (see 6 sub rules in nacm_rule_datanode
|
||||
*/
|
||||
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
goto done;
|
||||
for (j=0; j<rlen; j++){ /* Loop through rules */
|
||||
xrule = rvec[j];
|
||||
|
|
@ -588,7 +587,7 @@ nacm_datanode_read(cxobj *xt,
|
|||
if (username == NULL)
|
||||
goto step9;
|
||||
/* User's group */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
goto done;
|
||||
/* 4. If no groups are found (glen=0), continue and check read-default
|
||||
in step 11. */
|
||||
|
|
@ -596,7 +595,7 @@ nacm_datanode_read(cxobj *xt,
|
|||
configuration. If a rule-list's "group" leaf-list does not
|
||||
match any of the user's groups, proceed to the next rule-list
|
||||
entry. */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
goto done;
|
||||
/* read-default has default permit so should never be NULL */
|
||||
if ((read_default = xml_find_body(xnacm, "read-default")) == NULL){
|
||||
|
|
@ -713,7 +712,7 @@ nacm_datanode_write(cxobj *xt,
|
|||
if (username == NULL)
|
||||
goto step9;
|
||||
/* User's group */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0)
|
||||
goto done;
|
||||
/* 4. If no groups are found, continue with step 9. */
|
||||
if (glen == 0)
|
||||
|
|
@ -722,19 +721,19 @@ nacm_datanode_write(cxobj *xt,
|
|||
configuration. If a rule-list's "group" leaf-list does not
|
||||
match any of the user's groups, proceed to the next rule-list
|
||||
entry. */
|
||||
if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0)
|
||||
goto done;
|
||||
for (i=0; i<rlistlen; i++){
|
||||
rlist = rlistvec[i];
|
||||
/* Loop through user's group to find match in this rule-list */
|
||||
for (j=0; j<glen; j++){
|
||||
gname = xml_find_body(gvec[j], "name");
|
||||
if (xpath_first_nsc(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
if (xpath_first(rlist, nsc, ".[group='%s']", gname)!=NULL)
|
||||
break; /* found */
|
||||
}
|
||||
if (j==glen) /* not found */
|
||||
continue;
|
||||
if (xpath_vec_nsc(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
if (xpath_vec(rlist, nsc, "rule", &rvec, &rlen) < 0)
|
||||
goto done;
|
||||
/* 6. For each rule-list entry found, process all rules, in order,
|
||||
until a rule that matches the requested access operation is
|
||||
|
|
@ -863,7 +862,7 @@ nacm_access(clicon_handle h,
|
|||
* RFC8341 3.4 */
|
||||
/* 1. If the "enable-nacm" leaf is set to "false", then the protocol
|
||||
operation is permitted. */
|
||||
if ((x = xpath_first_nsc(xnacm, nsc, "enable-nacm")) == NULL)
|
||||
if ((x = xpath_first(xnacm, nsc, "enable-nacm")) == NULL)
|
||||
goto permit;
|
||||
enabled = xml_body(x);
|
||||
if (strcmp(enabled, "true") != 0)
|
||||
|
|
@ -938,7 +937,7 @@ nacm_access_pre(clicon_handle h,
|
|||
if (xnacm0 == NULL)
|
||||
goto permit;
|
||||
/* If config does not exist then the operation is permitted(?) */
|
||||
if ((xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) == NULL)
|
||||
if ((xnacm = xpath_first(xnacm0, nsc, "nacm")) == NULL)
|
||||
goto permit;
|
||||
if (xml_rootchild_node(xnacm0, xnacm) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
@ -1339,41 +1338,37 @@ netconf_db_find(cxobj *xn,
|
|||
}
|
||||
|
||||
/*! Generate netconf error msg to cbuf to use in string printout or logs
|
||||
* @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error>
|
||||
* @param[out] cberr Translation from netconf err to cbuf. Free with cbuf_free.
|
||||
* @param[in] xerr Netconf error message on the level: <rpc-error>
|
||||
* @param[in,out] cberr Translation from netconf err to cbuf.
|
||||
* @retval 0 OK, with cberr set
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* cbuf *cb = NULL;
|
||||
* if (netconf_err2cb(xerr, &cb) < 0)
|
||||
* cbuf *cb = NULL;
|
||||
* if ((cb = cbuf_new()) ==NULL){
|
||||
* err;
|
||||
* if (netconf_err2cb(xerr, cb) < 0)
|
||||
* err;
|
||||
* printf("%s", cbuf_get(cb));
|
||||
* cbuf_free(cb);
|
||||
* @endcode
|
||||
* @see clicon_rpc_generate_error
|
||||
*/
|
||||
int
|
||||
netconf_err2cb(cxobj *xerr,
|
||||
cbuf **cberr)
|
||||
cbuf *cberr)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
cxobj *x;
|
||||
|
||||
if ((cb = cbuf_new()) ==NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((x=xpath_first(xerr, "error-type"))!=NULL)
|
||||
cprintf(cb, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
|
||||
cprintf(cb, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
||||
cprintf(cb, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
||||
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0, -1);
|
||||
*cberr = cb;
|
||||
if ((x=xpath_first(xerr, NULL, "error-type"))!=NULL)
|
||||
cprintf(cberr, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, NULL, "error-tag"))!=NULL)
|
||||
cprintf(cberr, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, NULL, "error-message"))!=NULL)
|
||||
cprintf(cberr, "%s ", xml_body(x));
|
||||
if ((x=xpath_first(xerr, NULL, "error-info"))!=NULL)
|
||||
clicon_xml2cbuf(cberr, xml_child_i(x,0), 0, 0, -1);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ parse_configfile(clicon_handle h,
|
|||
/* Hard-coded config for < 3.10 and clixon-config for >= 3.10 */
|
||||
if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL)
|
||||
goto done;
|
||||
if ((xc = xpath_first_nsc(xt, nsc, "clixon-config")) == NULL){
|
||||
if ((xc = xpath_first(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\">", filename, CLIXON_CONF_NS);
|
||||
|
||||
goto done;
|
||||
|
|
@ -256,7 +256,11 @@ parse_configfile(clicon_handle h,
|
|||
if ((ret = xml_yang_validate_add(h, xc, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
if (netconf_err2cb(xret, &cbret) < 0)
|
||||
if ((cbret = cbuf_new()) ==NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (netconf_err2cb(xret, cbret) < 0)
|
||||
goto done;
|
||||
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
|
||||
goto done;
|
||||
|
|
@ -351,8 +355,7 @@ clicon_option_add(clicon_handle h,
|
|||
* other yang modules.
|
||||
*/
|
||||
int
|
||||
clicon_options_main(clicon_handle h,
|
||||
yang_stmt *yspec)
|
||||
clicon_options_main(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
char *configfile;
|
||||
|
|
@ -360,7 +363,11 @@ clicon_options_main(clicon_handle h,
|
|||
char *suffix;
|
||||
char xml = 0; /* Configfile is xml, otherwise legacy */
|
||||
cxobj *xconfig = NULL;
|
||||
yang_stmt *yspec = NULL;
|
||||
|
||||
/* Create configure yang-spec */
|
||||
if ((yspec = yspec_new()) == NULL)
|
||||
goto done;
|
||||
/*
|
||||
* Set configure file if not set by command-line above
|
||||
*/
|
||||
|
|
@ -409,8 +416,12 @@ clicon_options_main(clicon_handle h,
|
|||
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;
|
||||
}
|
||||
/* Set yang config spec (must store to free at exit, since conf_xml below uses it) */
|
||||
if (clicon_config_yang_set(h, yspec) < 0)
|
||||
goto done;
|
||||
/* Set clixon_conf pointer to handle */
|
||||
clicon_conf_xml_set(h, xconfig);
|
||||
if (clicon_conf_xml_set(h, xconfig) < 0)
|
||||
goto done;
|
||||
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#include "clixon_yang.h"
|
||||
#include "clixon_sig.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_proto.h"
|
||||
|
||||
static int _atomicio_sig = 0;
|
||||
|
|
@ -191,12 +192,14 @@ clicon_msg_decode(struct clicon_msg *msg,
|
|||
}
|
||||
|
||||
/*! Open local connection using unix domain sockets
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] sockpath Unix domain file path
|
||||
* @retval s socket
|
||||
* @retval -1 error
|
||||
* @retval s socket
|
||||
* @retval -1 error
|
||||
*/
|
||||
int
|
||||
clicon_connect_unix(char *sockpath)
|
||||
clicon_connect_unix(clicon_handle h,
|
||||
char *sockpath)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int retval = -1;
|
||||
|
|
@ -213,9 +216,9 @@ clicon_connect_unix(char *sockpath)
|
|||
clicon_debug(2, "%s: connecting to %s", __FUNCTION__, addr.sun_path);
|
||||
if (connect(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){
|
||||
if (errno == EACCES)
|
||||
clicon_err(OE_CFG, errno, "connecting unix socket: %s."
|
||||
"Client should be member of group $CLICON_SOCK_GROUP: ",
|
||||
sockpath);
|
||||
clicon_err(OE_CFG, errno, "connecting unix socket: %s. "
|
||||
"Is user not member of group: \"%s\"?",
|
||||
sockpath, clicon_sock_group(h));
|
||||
else
|
||||
clicon_err(OE_CFG, errno, "connecting unix socket: %s", sockpath);
|
||||
close(s);
|
||||
|
|
@ -394,6 +397,7 @@ clicon_msg_rcv(int s,
|
|||
|
||||
/*! Connect to server, send a clicon_msg message and wait for result using unix socket
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] msg CLICON msg data structure. It has fixed header and variable body.
|
||||
* @param[in] sockpath Unix domain file path
|
||||
* @param[out] retdata Returned data as string netconf xml tree.
|
||||
|
|
@ -403,7 +407,8 @@ clicon_msg_rcv(int s,
|
|||
* @see clicon_rpc But this is one-shot rpc: open, send, get reply and close.
|
||||
*/
|
||||
int
|
||||
clicon_rpc_connect_unix(struct clicon_msg *msg,
|
||||
clicon_rpc_connect_unix(clicon_handle h,
|
||||
struct clicon_msg *msg,
|
||||
char *sockpath,
|
||||
char **retdata,
|
||||
int *sock0)
|
||||
|
|
@ -422,7 +427,7 @@ clicon_rpc_connect_unix(struct clicon_msg *msg,
|
|||
clicon_err(OE_PROTO, EIO, "%s: Not unix socket", sockpath);
|
||||
goto done;
|
||||
}
|
||||
if ((s = clicon_connect_unix(sockpath)) < 0)
|
||||
if ((s = clicon_connect_unix(h, sockpath)) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc(s, msg, retdata) < 0)
|
||||
goto done;
|
||||
|
|
@ -436,7 +441,8 @@ clicon_rpc_connect_unix(struct clicon_msg *msg,
|
|||
}
|
||||
|
||||
/*! Connect to server, send a clicon_msg message and wait for result using an inet socket
|
||||
* This uses unix domain socket communication
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] msg CLICON msg data structure. It has fixed header and variable body.
|
||||
* @param[in] dst IPv4 address
|
||||
* @param[in] port TCP port
|
||||
|
|
@ -447,7 +453,8 @@ clicon_rpc_connect_unix(struct clicon_msg *msg,
|
|||
* @see clicon_rpc But this is one-shot rpc: open, send, get reply and close.
|
||||
*/
|
||||
int
|
||||
clicon_rpc_connect_inet(struct clicon_msg *msg,
|
||||
clicon_rpc_connect_inet(clicon_handle h,
|
||||
struct clicon_msg *msg,
|
||||
char *dst,
|
||||
uint16_t port,
|
||||
char **retdata,
|
||||
|
|
@ -597,9 +604,9 @@ send_msg_notify(int s,
|
|||
|
||||
/*! Send a clicon_msg NOTIFY message asynchronously to client
|
||||
*
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] s Socket to communicate with client
|
||||
* @param[in] level
|
||||
* @param[in] xml Event as XML
|
||||
* @param[in] xev Event as XML
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see send_msg_notify XXX beauty contest
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ clicon_rpc_msg(clicon_handle h,
|
|||
/* What to do if inet socket? */
|
||||
switch (clicon_sock_family(h)){
|
||||
case AF_UNIX:
|
||||
if (clicon_rpc_connect_unix(msg, sock, &retdata, sock0) < 0){
|
||||
if (clicon_rpc_connect_unix(h, msg, sock, &retdata, sock0) < 0){
|
||||
#if 0
|
||||
if (errno == ESHUTDOWN)
|
||||
/* Maybe could reconnect on a higher layer, but lets fail
|
||||
|
|
@ -127,7 +127,7 @@ clicon_rpc_msg(clicon_handle h,
|
|||
clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_rpc_connect_inet(msg, sock, port, &retdata, sock0) < 0)
|
||||
if (clicon_rpc_connect_inet(h, msg, sock, port, &retdata, sock0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
|
@ -227,16 +227,20 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
|||
|
||||
/*! Generate and log clicon error function call from Netconf error message
|
||||
* @param[in] prefix Print this string (if given) before: "<prefix>: <error>"
|
||||
* @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error>
|
||||
* @param[in] xerr Netconf error message on the level: <rpc-error>
|
||||
*/
|
||||
int
|
||||
clicon_rpc_generate_error(char *prefix,
|
||||
cxobj *xerr)
|
||||
clicon_rpc_generate_error(const char *prefix,
|
||||
cxobj *xerr)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if (netconf_err2cb(xerr, &cb) < 0)
|
||||
if ((cb = cbuf_new()) ==NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (netconf_err2cb(xerr, cb) < 0)
|
||||
goto done;
|
||||
if (prefix)
|
||||
clicon_log(LOG_ERR, "%s: %s", prefix, cbuf_get(cb));
|
||||
|
|
@ -268,7 +272,7 @@ clicon_rpc_generate_error(char *prefix,
|
|||
* err;
|
||||
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error("", xerr);
|
||||
* err;
|
||||
* }
|
||||
|
|
@ -324,9 +328,9 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
/* Send xml error back: first check error, then ok */
|
||||
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
|
||||
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
|
||||
xd = xml_parent(xd); /* point to rpc-reply */
|
||||
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
|
||||
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
|
||||
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xt){
|
||||
|
|
@ -390,7 +394,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Editing configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -437,7 +441,7 @@ clicon_rpc_copy_config(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Copying configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -477,7 +481,7 @@ clicon_rpc_delete_config(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Deleting configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -513,7 +517,7 @@ clicon_rpc_lock(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Locking configuration", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -548,7 +552,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Configuration unlock", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -582,7 +586,7 @@ clicon_rpc_unlock(clicon_handle h,
|
|||
* err;
|
||||
* if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
* err;
|
||||
* if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){
|
||||
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
* clicon_rpc_generate_error(xerr);
|
||||
* err;
|
||||
* }
|
||||
|
|
@ -646,9 +650,9 @@ clicon_rpc_get(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
/* Send xml error back: first check error, then ok */
|
||||
if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL)
|
||||
if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
|
||||
xd = xml_parent(xd); /* point to rpc-reply */
|
||||
else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL)
|
||||
else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL)
|
||||
if ((xd = xml_new("data", NULL, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xt){
|
||||
|
|
@ -689,7 +693,7 @@ clicon_rpc_close_session(clicon_handle h)
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Close session", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -725,7 +729,7 @@ clicon_rpc_kill_session(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Kill session", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -760,7 +764,7 @@ clicon_rpc_validate(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -793,7 +797,7 @@ clicon_rpc_commit(clicon_handle h)
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -826,7 +830,7 @@ clicon_rpc_discard_changes(clicon_handle h)
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Discard changes", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -872,7 +876,7 @@ clicon_rpc_create_subscription(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Create subscription", xerr);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -907,11 +911,11 @@ clicon_rpc_debug(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Debug",xerr);
|
||||
goto done;
|
||||
}
|
||||
if (xpath_first(xret, "//rpc-reply/ok") == NULL){
|
||||
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){
|
||||
clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -950,11 +954,11 @@ clicon_hello_req(clicon_handle h,
|
|||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
|
||||
clicon_rpc_generate_error("Hello", xerr);
|
||||
goto done;
|
||||
}
|
||||
if ((x = xpath_first(xret, "hello/session-id")) == NULL){
|
||||
if ((x = xpath_first(xret, NULL, "hello/session-id")) == NULL){
|
||||
clicon_err(OE_XML, 0, "hello session-id");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ stream_notify1(clicon_handle h,
|
|||
else{ /* xpath match */
|
||||
if (ss->ss_xpath == NULL ||
|
||||
strlen(ss->ss_xpath)==0 ||
|
||||
xpath_first(xevent, "%s", ss->ss_xpath) != NULL)
|
||||
xpath_first(xevent, NULL, "%s", ss->ss_xpath) != NULL)
|
||||
if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0)
|
||||
goto done;
|
||||
ss = NEXTQ(struct stream_subscription *, ss);
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ name2uid(const char *name,
|
|||
|
||||
/*! Translate uid to user name
|
||||
* @param[in] uid User id
|
||||
* @param[out] name User name
|
||||
* @param[out] name User name (Malloced, need to be freed)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error. or not found
|
||||
*/
|
||||
|
|
@ -131,7 +131,7 @@ uid2name(const uid_t uid,
|
|||
{
|
||||
int retval = -1;
|
||||
char buf[1024];
|
||||
struct passwd pwbuf;
|
||||
struct passwd pwbuf = {0,};
|
||||
struct passwd *pwbufp = NULL;
|
||||
|
||||
if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){
|
||||
|
|
@ -139,17 +139,21 @@ uid2name(const uid_t uid,
|
|||
goto done;
|
||||
}
|
||||
if (pwbufp == NULL){
|
||||
clicon_err(OE_UNIX, 0, "No such user: %u", uid);
|
||||
clicon_err(OE_UNIX, ENOENT, "No such user: %u", uid);
|
||||
goto done;
|
||||
}
|
||||
if (name)
|
||||
*name = pwbufp->pw_name;
|
||||
|
||||
if (name){
|
||||
if ((*name = strdup(pwbufp->pw_name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Privileges drop perm, temp and restore
|
||||
* @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
@ -79,6 +78,8 @@
|
|||
#define XML_TOP_SYMBOL "top"
|
||||
/* How many XML children to start with if any (and then add exponentialy) */
|
||||
#define XML_CHILDVEC_MAX_DEFAULT 4
|
||||
/* Initial length of x_value malloced string */
|
||||
#define XML_VALUE_MAX_DEFAULT 32
|
||||
|
||||
/*
|
||||
* Types
|
||||
|
|
@ -125,7 +126,7 @@ struct xml{
|
|||
int x_childvec_len;/* Number of children */
|
||||
int x_childvec_max;/* Length of allocated vector */
|
||||
enum cxobj_type x_type; /* type of node: element, attribute, body */
|
||||
char *x_value; /* attribute and body nodes have values */
|
||||
cbuf *x_value_cb; /* attribute and body nodes have values */
|
||||
int x_flags; /* Flags according to XML_FLAG_* */
|
||||
yang_stmt *x_spec; /* Pointer to specification, eg yang, by
|
||||
reference, dont free */
|
||||
|
|
@ -150,7 +151,6 @@ static const map_str2int xsmap[] = {
|
|||
{NULL, -1}
|
||||
};
|
||||
|
||||
|
||||
/*! Translate from xml type in enum form to string keyword
|
||||
* @param[in] type Xml type
|
||||
* @retval str String keyword
|
||||
|
|
@ -400,7 +400,7 @@ xml2ns(cxobj *x,
|
|||
/*! Add a namespace attribute to an XML node, either default or specific prefix
|
||||
* @param[in] x XML tree
|
||||
* @param[in] prefix prefix/ns localname. If NULL then set default xmlns
|
||||
* @param[out] namespace URI namespace (or NULL). Will be copied
|
||||
* @param[in] ns URI namespace (or NULL). Will be copied
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see xml2ns
|
||||
|
|
@ -621,7 +621,7 @@ xml_flag_reset(cxobj *xn,
|
|||
char*
|
||||
xml_value(cxobj *xn)
|
||||
{
|
||||
return xn->x_value;
|
||||
return xn->x_value_cb?cbuf_get(xn->x_value_cb):NULL;
|
||||
}
|
||||
|
||||
/*! Set value of xml node, value is copied
|
||||
|
|
@ -634,17 +634,20 @@ int
|
|||
xml_value_set(cxobj *xn,
|
||||
char *val)
|
||||
{
|
||||
if (xn->x_value){
|
||||
free(xn->x_value);
|
||||
xn->x_value = NULL;
|
||||
}
|
||||
if (val){
|
||||
if ((xn->x_value = strdup(val)) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
return -1;
|
||||
int retval = -1;
|
||||
|
||||
if (xn->x_value_cb == NULL){
|
||||
if ((xn->x_value_cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
else
|
||||
cbuf_reset(xn->x_value_cb);
|
||||
cprintf(xn->x_value_cb, "%s", val);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Append value of xnode, value is copied
|
||||
|
|
@ -653,23 +656,25 @@ xml_value_set(cxobj *xn,
|
|||
* @retval NULL on error with clicon-err set, or if value is set to NULL
|
||||
* @retval new value
|
||||
*/
|
||||
char *
|
||||
int
|
||||
xml_value_append(cxobj *xn,
|
||||
char *val)
|
||||
{
|
||||
int len0;
|
||||
int len;
|
||||
int retval = -1;
|
||||
|
||||
len0 = xn->x_value?strlen(xn->x_value):0;
|
||||
if (val){
|
||||
len = len0 + strlen(val);
|
||||
if ((xn->x_value = realloc(xn->x_value, len+1)) == NULL){
|
||||
clicon_err(OE_XML, errno, "realloc");
|
||||
return NULL;
|
||||
if (xn->x_value_cb == NULL){
|
||||
if ((xn->x_value_cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
strncpy(xn->x_value + len0, val, len-len0+1);
|
||||
}
|
||||
return xn->x_value;
|
||||
if (cprintf(xn->x_value_cb, "%s", val) < 0){
|
||||
clicon_err(OE_XML, errno, "cprintf");
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Get type of xnode
|
||||
|
|
@ -1594,8 +1599,8 @@ xml_free(cxobj *x)
|
|||
|
||||
if (x->x_name)
|
||||
free(x->x_name);
|
||||
if (x->x_value)
|
||||
free(x->x_value);
|
||||
if (x->x_value_cb)
|
||||
cbuf_free(x->x_value_cb);
|
||||
if (x->x_prefix)
|
||||
free(x->x_prefix);
|
||||
for (i=0; i<x->x_childvec_len; i++){
|
||||
|
|
@ -2142,22 +2147,23 @@ int
|
|||
xml_copy_one(cxobj *x0,
|
||||
cxobj *x1)
|
||||
{
|
||||
int retval = -1;
|
||||
char *s;
|
||||
|
||||
xml_type_set(x1, xml_type(x0));
|
||||
if ((s = xml_value(x0))){ /* malloced string */
|
||||
if ((x1->x_value = strdup(s)) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
return -1;
|
||||
}
|
||||
if (xml_value_set(x1, s) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((s = xml_name(x0))) /* malloced string */
|
||||
if ((xml_name_set(x1, s)) < 0)
|
||||
return -1;
|
||||
goto done;
|
||||
if ((s = xml_prefix(x0))) /* malloced string */
|
||||
if ((xml_prefix_set(x1, s)) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Copy xml tree x0 to other existing tree x1
|
||||
|
|
@ -2618,8 +2624,10 @@ clicon_log_xml(int level,
|
|||
int retval = -1;
|
||||
|
||||
/* Print xml as cbuf */
|
||||
if ((cb = cbuf_new()) == NULL)
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, x, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -200,7 +199,7 @@ changelog_move(clicon_handle h,
|
|||
int retval = -1;
|
||||
cxobj *xp; /* destination parent node */
|
||||
|
||||
if ((xp = xpath_first_nsc(xt, nsc, "%s", dst)) == NULL){
|
||||
if ((xp = xpath_first(xt, nsc, "%s", dst)) == NULL){
|
||||
clicon_err(OE_XML, 0, "path required");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -253,7 +252,7 @@ changelog_op(clicon_handle h,
|
|||
if ((wxpath = xml_find_body(xi, "where")) == NULL)
|
||||
goto ok;
|
||||
/* Get vector of target nodes meeting the where requirement */
|
||||
if (xpath_vec_nsc(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
|
||||
if (xpath_vec(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0)
|
||||
goto done;
|
||||
for (i=0; i<wlen; i++){
|
||||
xw = wvec[i];
|
||||
|
|
@ -328,7 +327,7 @@ changelog_iterate(clicon_handle h,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
if (xpath_vec(xch, "step", &vec, &veclen) < 0)
|
||||
if (xpath_vec(xch, NULL, "step", &vec, &veclen) < 0)
|
||||
goto done;
|
||||
/* Iterate through changelog items */
|
||||
for (i=0; i<veclen; i++){
|
||||
|
|
@ -392,7 +391,7 @@ xml_changelog_upgrade(clicon_handle h,
|
|||
* - find all changelogs in the interval: [from, to]
|
||||
* - note it t=0 then no changelog is applied
|
||||
*/
|
||||
if (xpath_vec(xchlog, "changelog[namespace=\"%s\"]",
|
||||
if (xpath_vec(xchlog, NULL, "changelog[namespace=\"%s\"]",
|
||||
&vec, &veclen, namespace) < 0)
|
||||
goto done;
|
||||
/* Get all changelogs in the interval [from,to]*/
|
||||
|
|
@ -452,7 +451,11 @@ clixon_xml_changelog_init(clicon_handle h)
|
|||
if (ret==1 && (ret = xml_yang_validate_add(h, xt, &xret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* validation failed */
|
||||
if (netconf_err2cb(xret, &cbret) < 0)
|
||||
if ((cbret = cbuf_new()) ==NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (netconf_err2cb(xret, cbret) < 0)
|
||||
goto done;
|
||||
clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret));
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ validate_leafref(cxobj *xt,
|
|||
/* XXX see comment above regarding typeref or not */
|
||||
if (xml_nsctx_yang(ytype, &nsc) < 0)
|
||||
goto done;
|
||||
if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
|
||||
if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, yang_argument_get(ypath)) < 0)
|
||||
goto done;
|
||||
for (i = 0; i < xlen; i++) {
|
||||
x = xvec[i];
|
||||
|
|
@ -2153,6 +2153,46 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Add prefix:namespace pair to xml node, set cache, prefix, etc
|
||||
*/
|
||||
static int
|
||||
add_namespace(cxobj *x1, /* target */
|
||||
cxobj *x1p,
|
||||
char *prefix1,
|
||||
char *namespace)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xa = NULL;
|
||||
|
||||
/* Add binding to x1p. We add to parent due to heurestics, so we dont
|
||||
* end up in adding it to large number of siblings
|
||||
*/
|
||||
if (nscache_set(x1, prefix1, namespace) < 0)
|
||||
goto done;
|
||||
/* Create xmlns attribute to x1p/x1 XXX same code v */
|
||||
if (prefix1){
|
||||
if ((xa = xml_new(prefix1, x1, NULL)) == NULL)
|
||||
goto done;
|
||||
if (xml_prefix_set(xa, "xmlns") < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if ((xa = xml_new("xmlns", x1, NULL)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, namespace) < 0)
|
||||
goto done;
|
||||
xml_sort(x1, NULL); /* Ensure attr is first / XXX xml_insert? */
|
||||
|
||||
/* 5. Add prefix to x1, if any */
|
||||
if (prefix1 && xml_prefix_set(x1, prefix1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Add default values (if not set)
|
||||
* @param[in] xt XML tree with some node marked
|
||||
* @param[in] arg Ignored
|
||||
|
|
@ -2175,6 +2215,7 @@ xml_default(cxobj *xt,
|
|||
int added=0;
|
||||
char *namespace;
|
||||
char *prefix;
|
||||
int ret;
|
||||
|
||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||
retval = 0;
|
||||
|
|
@ -2195,9 +2236,20 @@ xml_default(cxobj *xt,
|
|||
/* assign right prefix */
|
||||
if ((namespace = yang_find_mynamespace(y)) != NULL){
|
||||
prefix = NULL;
|
||||
if (xml2prefix(xt, namespace, &prefix))
|
||||
if ((ret = xml2prefix(xt, namespace, &prefix)) < 0)
|
||||
goto done;
|
||||
if (ret){
|
||||
if (xml_prefix_set(xc, prefix) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{ /* namespace does not exist in target, use source prefix */
|
||||
if ((prefix = yang_find_myprefix(y)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
if (add_namespace(xc, xt, prefix, namespace) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
xml_flag_set(xc, XML_FLAG_DEFAULT);
|
||||
|
|
@ -3190,6 +3242,124 @@ xmlns_assign(cxobj *x)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Given a src node x0 and a target node x1, assign (optional) prefix and namespace
|
||||
* @param[in] x0 Source XML tree
|
||||
* @param[in] x1 Target XML tree
|
||||
* 1. Find N=namespace(x0)
|
||||
* 2. Detect if N is declared in x1 parent
|
||||
* 3. If yes, assign prefix to x1
|
||||
* 4. If no, create new prefix/namespace binding and assign that to x1p (x1 if x1p is root)
|
||||
* 5. Add prefix to x1, if any
|
||||
* 6. Ensure x1 cache is updated
|
||||
* @note switch use of x0 and x1 compared to datastore text_modify
|
||||
* @see xml2ns
|
||||
* XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0)
|
||||
goto done;
|
||||
*/
|
||||
int
|
||||
check_namespaces(cxobj *x0, /* source */
|
||||
cxobj *x1, /* target */
|
||||
cxobj *x1p)
|
||||
{
|
||||
int retval = -1;
|
||||
char *namespace = NULL;
|
||||
char *prefix0 = NULL;;
|
||||
char *prefix1 = NULL;
|
||||
char *prefixb = NULL; /* identityref body prefix */
|
||||
cvec *nsc0 = NULL;
|
||||
cvec *nsc = NULL;
|
||||
int isroot;
|
||||
char *pexist = NULL;
|
||||
yang_stmt *y;
|
||||
|
||||
/* XXX: need to identify root better than hiereustics and strcmp,... */
|
||||
isroot = xml_parent(x1p)==NULL &&
|
||||
(strcmp(xml_name(x1p), "config") == 0 || strcmp(xml_name(x1p), "top") == 0)&&
|
||||
xml_prefix(x1p)==NULL;
|
||||
|
||||
/* 1. Find N=namespace(x0) */
|
||||
prefix0 = xml_prefix(x0);
|
||||
if (xml2ns(x0, prefix0, &namespace) < 0)
|
||||
goto done;
|
||||
if (namespace == NULL){
|
||||
clicon_err(OE_XML, ENOENT, "No namespace found for prefix:%s",
|
||||
prefix0?prefix0:"NULL");
|
||||
goto done;
|
||||
}
|
||||
/* 2a. Detect if namespace is declared in x1 target parent */
|
||||
if (xml2prefix(x1p, namespace, &pexist) == 1){
|
||||
/* Yes, and it has prefix pexist */
|
||||
if (pexist){
|
||||
if ((prefix1 = strdup(pexist)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
prefix1 = NULL;
|
||||
/* 3. If yes, assign prefix to x1 */
|
||||
if (prefix1 && xml_prefix_set(x1, prefix1) < 0)
|
||||
goto done;
|
||||
/* And copy namespace context from parent to child */
|
||||
if ((nsc0 = nscache_get_all(x1p)) != NULL){
|
||||
if ((nsc = cvec_dup(nsc0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
nscache_replace(x1, nsc);
|
||||
}
|
||||
/* Just in case */
|
||||
if (nscache_set(x1, prefix1, namespace) < 0)
|
||||
goto done;
|
||||
}
|
||||
else{ /* No, namespace does not exist in x1 _parent_
|
||||
* Check if it is exists in x1 itself */
|
||||
if (nscache_get_prefix(x1, namespace, &pexist) == 1){
|
||||
/* Yes it exists, but is it equal? */
|
||||
if ((pexist == NULL && prefix0 == NULL) ||
|
||||
(pexist && prefix0 &&
|
||||
strcmp(pexist, prefix0)==0)){ /* Equal, reuse */
|
||||
;
|
||||
}
|
||||
else{ /* namespace exist, but not equal, use existing */
|
||||
/* Add prefix to x1, if any */
|
||||
if (pexist && xml_prefix_set(x1, pexist) < 0)
|
||||
goto done;
|
||||
}
|
||||
goto ok; /* skip */
|
||||
}
|
||||
else
|
||||
{ /* namespace does not exist in target x1, use source prefix
|
||||
* use the prefix defined in the module
|
||||
*/
|
||||
if (isroot){
|
||||
if (prefix0 && (prefix1 = strdup(prefix0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
y = xml_spec(x0);
|
||||
if ((prefix1 = strdup(yang_find_myprefix(y))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add_namespace(x1, x1p, prefix1, namespace) < 0)
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
/* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */
|
||||
retval = 0;
|
||||
done:
|
||||
if (prefixb)
|
||||
free(prefixb);
|
||||
if (prefix1)
|
||||
free(prefix1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Merge a base tree x0 with x1 with yang spec y
|
||||
* @param[in] x0 Base xml tree (can be NULL in add scenarios)
|
||||
* @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL
|
||||
|
|
@ -3201,20 +3371,18 @@ xmlns_assign(cxobj *x)
|
|||
* Assume x0 and x1 are same on entry and that y is the spec
|
||||
*/
|
||||
static int
|
||||
xml_merge1(cxobj *x0,
|
||||
xml_merge1(cxobj *x0, /* the target */
|
||||
yang_stmt *y0,
|
||||
cxobj *x0p,
|
||||
cxobj *x1,
|
||||
cxobj *x1, /* the source */
|
||||
char **reason)
|
||||
{
|
||||
int retval = -1;
|
||||
char *x1name;
|
||||
char *x1cname; /* child name */
|
||||
cxobj *x0c; /* base child */
|
||||
cxobj *x0b; /* base body */
|
||||
cxobj *x1c; /* mod child */
|
||||
cxobj *x0a; /* x0 xmlns attribute */
|
||||
cxobj *x1a; /* x1 xmlns attribute */
|
||||
char *x1name;
|
||||
char *x1bstr; /* mod body string */
|
||||
yang_stmt *yc; /* yang child */
|
||||
cbuf *cbr = NULL; /* Reason buffer */
|
||||
|
|
@ -3243,13 +3411,16 @@ xml_merge1(cxobj *x0,
|
|||
if (xml_value_set(x0b, x1bstr) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (check_namespaces(x1, x0, x0p) < 0)
|
||||
goto done;
|
||||
} /* if LEAF|LEAF_LIST */
|
||||
else { /* eg Y_CONTAINER, Y_LIST */
|
||||
if (x0==NULL){
|
||||
if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL)
|
||||
if ((x0 = xml_new(x1name, NULL, (yang_stmt*)y0)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
if (check_namespaces(x1, x0, x0p) < 0)
|
||||
goto done;
|
||||
/* Loop through children of the modification tree */
|
||||
x1c = NULL;
|
||||
while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -3277,19 +3448,11 @@ xml_merge1(cxobj *x0,
|
|||
goto done;
|
||||
if (*reason != NULL)
|
||||
goto ok;
|
||||
}
|
||||
} /* while */
|
||||
if (xml_parent(x0) == NULL &&
|
||||
xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0)
|
||||
goto done;
|
||||
} /* else Y_CONTAINER */
|
||||
assert(x0);
|
||||
/* Copy xmlns attributes (if it does not already exist) */
|
||||
if ((x1a = xml_find_type(x1, NULL, "xmlns", CX_ATTR)) != NULL)
|
||||
if (xml_find_type(x0, NULL, "xmlns", CX_ATTR)==NULL){
|
||||
if ((x0a = xml_dup(x1a)) == NULL)
|
||||
goto done;
|
||||
if (xml_addsub(x0, x0a) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
@ -183,7 +182,6 @@ xml_nsctx_add(cvec *cvv,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xml_nsctx_node1(cxobj *xn,
|
||||
cvec *nsc)
|
||||
|
|
@ -269,10 +267,10 @@ xml_nsctx_node(cxobj *xn,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize XML namespace from Yang node
|
||||
/*! Create and initialize XML namespace context from Yang node
|
||||
* Primary use is Yang path statements, eg leafrefs and others
|
||||
* Fully explore all prefix:namespace pairs from context of one node
|
||||
* @param[in] xn XML node
|
||||
* @param[in] yn Yang statement in module tree (or module itself)
|
||||
* @param[out] ncp XML namespace context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -355,3 +353,47 @@ xml_nsctx_yang(yang_stmt *yn,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Create and initialize XML namespace context from Yang spec
|
||||
*
|
||||
* That is, create a "canonical" XML namespace mapping from all loaded yang
|
||||
* modules which are children of the yang specification.
|
||||
* ALso add netconf base namespace: nc , urn:ietf:params:xml:ns:netconf:base:1.0
|
||||
* Fully explore all prefix:namespace pairs of all yang modules
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[out] ncp XML namespace context
|
||||
*/
|
||||
int
|
||||
xml_nsctx_yangspec(yang_stmt *yspec,
|
||||
cvec **ncp)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *nc = NULL;
|
||||
yang_stmt *ymod = NULL;
|
||||
yang_stmt *yprefix;
|
||||
yang_stmt *ynamespace;
|
||||
|
||||
if ((nc = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_XML, errno, "cvec_new");
|
||||
goto done;
|
||||
}
|
||||
ymod = NULL;
|
||||
while ((ymod = yn_each(yspec, ymod)) != NULL){
|
||||
if (yang_keyword_get(ymod) != Y_MODULE)
|
||||
continue;
|
||||
if ((yprefix = yang_find(ymod, Y_PREFIX, NULL)) == NULL)
|
||||
continue;
|
||||
if ((ynamespace = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL)
|
||||
continue;
|
||||
if (xml_nsctx_add(nc, yang_argument_get(yprefix), yang_argument_get(ynamespace)) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Add base netconf namespace as default and "nc" prefix */
|
||||
if (xml_nsctx_add(nc, NULL, NETCONF_BASE_NAMESPACE) < 0)
|
||||
goto done;
|
||||
if (xml_nsctx_add(nc, NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE) < 0)
|
||||
goto done;
|
||||
*ncp = nc;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ ncname {namestart}{namechar}*
|
|||
%s STATEA
|
||||
%s AMPERSAND
|
||||
%s CDATA
|
||||
%s CDATAEND
|
||||
%s CMNT
|
||||
%s STR
|
||||
%s TEXTDECL
|
||||
|
|
@ -145,9 +146,13 @@ ncname {namestart}{namechar}*
|
|||
<AMPERSAND>"apos;" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;}
|
||||
<AMPERSAND>"quot;" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;}
|
||||
|
||||
<CDATA>. { clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||
<CDATA>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
|
||||
<CDATA>"]]>" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||
<CDATA>\] { BEGIN(CDATAEND);clixon_xml_parselval.string = yytext;return (CHARDATA);}
|
||||
<CDATA>[^]\n]+ { clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||
|
||||
<CDATAEND>\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);}
|
||||
<CDATAEND>"]>" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;}
|
||||
<CDATAEND>. { BEGIN(CDATA); clixon_xml_parselval.string = yytext;return (CHARDATA);}
|
||||
|
||||
<CMNT>"-->" { BEGIN(START); return ECOMMENT; }
|
||||
<CMNT>.
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ xml_parse_content(struct xml_parse_yacc_arg *ya,
|
|||
goto done;
|
||||
xml_type_set(xn, CX_BODY);
|
||||
}
|
||||
if (xml_value_append(xn, str)==NULL)
|
||||
if (xml_value_append(xn, str) < 0)
|
||||
goto done;
|
||||
ya->ya_xelement = xn;
|
||||
retval = 0;
|
||||
|
|
@ -140,7 +140,7 @@ xml_parse_whitespace(struct xml_parse_yacc_arg *ya,
|
|||
goto done;
|
||||
xml_type_set(xn, CX_BODY);
|
||||
}
|
||||
if (xml_value_append(xn, str)==NULL)
|
||||
if (xml_value_append(xn, str) < 0)
|
||||
goto done;
|
||||
ya->ya_xelement = xn;
|
||||
ok:
|
||||
|
|
@ -148,7 +148,6 @@ xml_parse_whitespace(struct xml_parse_yacc_arg *ya,
|
|||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xml_parse_version(struct xml_parse_yacc_arg *ya,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
|
@ -539,7 +538,7 @@ xml_insert_userorder(cxobj *xp,
|
|||
else{
|
||||
switch (yang_keyword_get(yn)){
|
||||
case Y_LEAF_LIST:
|
||||
if ((xc = xpath_first_nsc(xp, nsc_key, "%s[.='%s']", xml_name(xn), key_val)) == NULL)
|
||||
if ((xc = xpath_first(xp, nsc_key, "%s[.='%s']", xml_name(xn), key_val)) == NULL)
|
||||
clicon_err(OE_YANG, 0, "bad-attribute: value, missing-instance: %s", key_val);
|
||||
else {
|
||||
if ((i = xml_child_order(xp, xc)) < 0)
|
||||
|
|
@ -549,7 +548,7 @@ xml_insert_userorder(cxobj *xp,
|
|||
}
|
||||
break;
|
||||
case Y_LIST:
|
||||
if ((xc = xpath_first_nsc(xp, nsc_key, "%s%s", xml_name(xn), key_val)) == NULL)
|
||||
if ((xc = xpath_first(xp, nsc_key, "%s%s", xml_name(xn), key_val)) == NULL)
|
||||
clicon_err(OE_YANG, 0, "bad-attribute: key, missing-instance: %s", key_val);
|
||||
else {
|
||||
if ((i = xml_child_order(xp, xc)) < 0)
|
||||
|
|
@ -618,8 +617,8 @@ xml_insert2(cxobj *xp,
|
|||
xc = xml_child_i(xp, mid);
|
||||
if ((yc = xml_spec(xc)) == NULL){
|
||||
if (xml_type(xc) != CX_ELMNT)
|
||||
clicon_err(OE_XML, 0, "No spec found %s (wrong xml type:%d)",
|
||||
xml_name(xc), xml_type(xc));
|
||||
clicon_err(OE_XML, 0, "No spec found %s (wrong xml type:%s)",
|
||||
xml_name(xc), xml_type2str(xml_type(xc)));
|
||||
else
|
||||
clicon_err(OE_XML, 0, "No spec found %s", xml_name(xc));
|
||||
goto done;
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -65,7 +65,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
|
@ -181,8 +180,8 @@ xpath_tree_print0(cbuf *cb,
|
|||
cprintf(cb, "%d ", xs->xs_int);
|
||||
break;
|
||||
}
|
||||
if (xs->xs_double)
|
||||
cprintf(cb,"%lf ", xs->xs_double);
|
||||
if (xs->xs_strnr)
|
||||
cprintf(cb,"%s ", xs->xs_strnr);
|
||||
cprintf(cb, "\n");
|
||||
if (xs->xs_c0)
|
||||
xpath_tree_print0(cb, xs->xs_c0,level+1);
|
||||
|
|
@ -229,7 +228,7 @@ xpath_tree_print(FILE *f,
|
|||
|
||||
/*! Create an xpath string from an xpath tree, ie "unparsing"
|
||||
* @param[in] xs XPATH tree
|
||||
* @param[out] xpath Xpath string as CLIgen buf
|
||||
* @param[out] xpath XPath string as CLIgen buf
|
||||
* @see xpath_tree_print
|
||||
* @note NOT COMPLETE, just simple xpaths eg a/b
|
||||
*/
|
||||
|
|
@ -254,7 +253,7 @@ xpath_tree2cbuf(xpath_tree *xs,
|
|||
cprintf(xcb, "'%s'", xs->xs_s0);
|
||||
break;
|
||||
case XP_PRIME_NR:
|
||||
cprintf(xcb, "%lf", xs->xs_double);
|
||||
cprintf(xcb, "%s", xs->xs_strnr?xs->xs_strnr:"0");
|
||||
break;
|
||||
case XP_STEP:
|
||||
switch (xs->xs_int){
|
||||
|
|
@ -314,6 +313,8 @@ xpath_tree2cbuf(xpath_tree *xs,
|
|||
int
|
||||
xpath_tree_free(xpath_tree *xs)
|
||||
{
|
||||
if (xs->xs_strnr)
|
||||
free(xs->xs_strnr);
|
||||
if (xs->xs_s0)
|
||||
free(xs->xs_s0);
|
||||
if (xs->xs_s1)
|
||||
|
|
@ -328,7 +329,7 @@ xpath_tree_free(xpath_tree *xs)
|
|||
|
||||
/*! Given xpath, parse it, and return structured xpath tree
|
||||
* @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 -1 Error
|
||||
* @code
|
||||
|
|
@ -427,7 +428,7 @@ xpath_vec_ctx(cxobj *xcur,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Xpath nodeset function where only the first matching entry is returned
|
||||
/*! XPath nodeset function where only the first matching entry is returned
|
||||
*
|
||||
* @param[in] xcur XML tree where to search
|
||||
* @param[in] nsc External XML namespace context, or NULL
|
||||
|
|
@ -438,7 +439,7 @@ xpath_vec_ctx(cxobj *xcur,
|
|||
* @code
|
||||
* cxobj *x;
|
||||
* cvec *nsc; // namespace context
|
||||
* if ((x = xpath_first_nsc(xtop, nsc, "//symbol/foo")) != NULL) {
|
||||
* if ((x = xpath_first(xtop, nsc, "//symbol/foo")) != NULL) {
|
||||
* ...
|
||||
* }
|
||||
* @endcode
|
||||
|
|
@ -447,65 +448,8 @@ xpath_vec_ctx(cxobj *xcur,
|
|||
* @see also xpath_vec.
|
||||
*/
|
||||
cxobj *
|
||||
xpath_first_nsc(cxobj *xcur,
|
||||
cvec *nsc,
|
||||
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, nsc, 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;
|
||||
}
|
||||
|
||||
/*! 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,
|
||||
cvec *nsc,
|
||||
char *xpformat,
|
||||
...)
|
||||
{
|
||||
|
|
@ -531,7 +475,7 @@ xpath_first(cxobj *xcur,
|
|||
goto done;
|
||||
}
|
||||
va_end(ap);
|
||||
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
|
||||
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||
goto done;
|
||||
if (xr && xr->xc_type == XT_NODESET && xr->xc_size)
|
||||
cx = xr->xc_nodeset[0];
|
||||
|
|
@ -556,7 +500,7 @@ xpath_first(cxobj *xcur,
|
|||
* cvec *nsc; // namespace context
|
||||
* cxobj **vec;
|
||||
* size_t veclen;
|
||||
* if (xpath_vec_nsc(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
|
||||
* if (xpath_vec(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0)
|
||||
* goto err;
|
||||
* for (i=0; i<veclen; i++){
|
||||
* xn = vec[i];
|
||||
|
|
@ -566,76 +510,8 @@ xpath_first(cxobj *xcur,
|
|||
* @endcode
|
||||
*/
|
||||
int
|
||||
xpath_vec_nsc(cxobj *xcur,
|
||||
cvec *nsc,
|
||||
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, nsc, 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;
|
||||
}
|
||||
|
||||
/*! 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,
|
||||
cvec *nsc,
|
||||
char *xpformat,
|
||||
cxobj ***vec,
|
||||
size_t *veclen,
|
||||
|
|
@ -665,7 +541,7 @@ xpath_vec(cxobj *xcur,
|
|||
va_end(ap);
|
||||
*vec=NULL;
|
||||
*veclen = 0;
|
||||
if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0)
|
||||
if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0)
|
||||
goto done;
|
||||
if (xr && xr->xc_type == XT_NODESET){
|
||||
*vec = xr->xc_nodeset;
|
||||
|
|
@ -681,7 +557,7 @@ xpath_vec(cxobj *xcur,
|
|||
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] xpformat Format string for XPATH syntax
|
||||
* @param[in] nsc External XML namespace context, or NULL
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
|||
|
||||
<TOKEN>\" { BEGIN(QLITERAL); return QUOTE; }
|
||||
<TOKEN>\' { BEGIN(ALITERAL); return APOST; }
|
||||
<TOKEN>\-?({integer}|{real}) { sscanf(yytext,"%lf",&clixon_xpath_parselval.dval); return NUMBER;}
|
||||
<TOKEN>\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; }
|
||||
<TOKEN>[0-9A-Za-z_\-]+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||
return NAME; /* rather be catch-all */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
|
||||
%union {
|
||||
int intval;
|
||||
double dval;
|
||||
char *string;
|
||||
void *stack; /* xpath_tree */
|
||||
}
|
||||
|
|
@ -54,8 +53,7 @@
|
|||
%token <intval> ADDOP
|
||||
%token <intval> RELOP
|
||||
|
||||
%token <dval> NUMBER
|
||||
|
||||
%token <string> NUMBER
|
||||
%token <string> X_EOF
|
||||
%token <string> QUOTE
|
||||
%token <string> APOST
|
||||
|
|
@ -105,7 +103,6 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -162,13 +159,13 @@ xpath_parse_exit(struct clicon_xpath_yacc_arg *xy)
|
|||
static xpath_tree *
|
||||
xp_new(enum xp_type type,
|
||||
int i0,
|
||||
double d0,
|
||||
char *numstr,
|
||||
char *s0,
|
||||
char *s1,
|
||||
xpath_tree *c0,
|
||||
xpath_tree *c1)
|
||||
{
|
||||
xpath_tree *xs = NULL;
|
||||
xpath_tree *xs = NULL;
|
||||
|
||||
if ((xs = malloc(sizeof(xpath_tree))) == NULL){
|
||||
clicon_err(OE_XML, errno, "malloc");
|
||||
|
|
@ -177,7 +174,15 @@ xp_new(enum xp_type type,
|
|||
memset(xs, 0, sizeof(*xs));
|
||||
xs->xs_type = type;
|
||||
xs->xs_int = i0;
|
||||
xs->xs_double = d0;
|
||||
if (numstr){
|
||||
xs->xs_strnr = numstr;
|
||||
if (sscanf(numstr, "%lf", &xs->xs_double) == EOF){
|
||||
clicon_err(OE_XML, errno, "sscanf");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
xs->xs_double = 0.0;
|
||||
xs->xs_s0 = s0;
|
||||
xs->xs_s1 = s1;
|
||||
xs->xs_c0 = c0;
|
||||
|
|
@ -197,50 +202,50 @@ start : expr X_EOF { _XY->xy_top=$1;clicon_debug(2,"start->expr");
|
|||
| locationpath X_EOF { _XY->xy_top=$1;clicon_debug(2,"start->locationpath"); YYACCEPT; }
|
||||
;
|
||||
|
||||
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"expr->expr or andexpr"); }
|
||||
| andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"expr-> andexpr"); }
|
||||
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"expr->expr or andexpr"); }
|
||||
| andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"expr-> andexpr"); }
|
||||
;
|
||||
|
||||
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"andexpr-> andexpr and relexpr"); }
|
||||
| relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"andexpr-> relexpr"); }
|
||||
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"andexpr-> andexpr and relexpr"); }
|
||||
| relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"andexpr-> relexpr"); }
|
||||
;
|
||||
|
||||
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"relexpr-> relexpr relop addexpr"); }
|
||||
| addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"relexpr-> addexpr"); }
|
||||
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"relexpr-> relexpr relop addexpr"); }
|
||||
| addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"relexpr-> addexpr"); }
|
||||
;
|
||||
|
||||
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"addexpr-> addexpr ADDOP unionexpr"); }
|
||||
| unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"addexpr-> unionexpr"); }
|
||||
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"addexpr-> addexpr ADDOP unionexpr"); }
|
||||
| unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"addexpr-> unionexpr"); }
|
||||
;
|
||||
|
||||
/* node-set */
|
||||
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(2,"unionexpr-> unionexpr | pathexpr"); }
|
||||
| pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"unionexpr-> pathexpr"); }
|
||||
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(2,"unionexpr-> unionexpr | pathexpr"); }
|
||||
| pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"unionexpr-> pathexpr"); }
|
||||
;
|
||||
|
||||
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> locationpath"); }
|
||||
| primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> primaryexpr"); }
|
||||
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> locationpath"); }
|
||||
| primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> primaryexpr"); }
|
||||
;
|
||||
|
||||
/* location path returns a node-set */
|
||||
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> rellocpath"); }
|
||||
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> abslocpath"); }
|
||||
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> rellocpath"); }
|
||||
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> abslocpath"); }
|
||||
;
|
||||
|
||||
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(2,"abslocpath-> /"); }
|
||||
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(2,"abslocpath->/ rellocpath");}
|
||||
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,NULL, NULL);clicon_debug(2,"abslocpath-> /"); }
|
||||
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,$2, NULL);clicon_debug(2,"abslocpath->/ rellocpath");}
|
||||
/* // is short for /descendant-or-self::node()/ */
|
||||
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$2, NULL); clicon_debug(2,"abslocpath-> // rellocpath"); }
|
||||
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); clicon_debug(2,"abslocpath-> // rellocpath"); }
|
||||
;
|
||||
|
||||
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"rellocpath-> step"); }
|
||||
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(2,"rellocpath-> rellocpath / step"); }
|
||||
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(2,"rellocpath-> rellocpath // step"); }
|
||||
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"rellocpath-> step"); }
|
||||
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(2,"rellocpath-> rellocpath / step"); }
|
||||
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); clicon_debug(2,"rellocpath-> rellocpath // step"); }
|
||||
;
|
||||
|
||||
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(2,"step->axisspec(%d) nodetest", $1); }
|
||||
| '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(2,"step-> ."); }
|
||||
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, $2); clicon_debug(2,"step-> .."); }
|
||||
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);clicon_debug(2,"step->axisspec(%d) nodetest", $1); }
|
||||
| '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); clicon_debug(2,"step-> ."); }
|
||||
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); clicon_debug(2,"step-> .."); }
|
||||
;
|
||||
|
||||
axisspec : AXISNAME { clicon_debug(2,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;}
|
||||
|
|
@ -248,31 +253,31 @@ axisspec : AXISNAME { clicon_debug(2,"axisspec-> AXISNAME(%d) ::", $1); $$=$1
|
|||
| { clicon_debug(2,"axisspec-> "); $$=A_CHILD;}
|
||||
;
|
||||
|
||||
nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(2,"nodetest-> *"); }
|
||||
| NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(2,"nodetest-> name(%s)",$1); }
|
||||
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : name(%s)", $1, $3); }
|
||||
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : *", $1); }
|
||||
| NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype():%s", $1); }
|
||||
nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(2,"nodetest-> *"); }
|
||||
| NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); clicon_debug(2,"nodetest-> name(%s)",$1); }
|
||||
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : name(%s)", $1, $3); }
|
||||
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : *", $1); }
|
||||
| NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,NULL, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype():%s", $1); }
|
||||
;
|
||||
|
||||
/* evaluates to boolean */
|
||||
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(2,"predicates-> [ expr ]"); }
|
||||
| { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(2,"predicates->"); }
|
||||
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); clicon_debug(2,"predicates-> [ expr ]"); }
|
||||
| { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(2,"predicates->"); }
|
||||
;
|
||||
|
||||
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(2,"primaryexpr-> ( expr )"); }
|
||||
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> NUMBER(%lf)", $1); }
|
||||
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" string \""); }
|
||||
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" \""); }
|
||||
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' string '"); }
|
||||
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' '"); }
|
||||
| FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); }
|
||||
| FUNCTIONNAME '(' args ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, $3, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); }
|
||||
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); clicon_debug(2,"primaryexpr-> ( expr )"); }
|
||||
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> NUMBER(%s)", $1); /*XXX*/}
|
||||
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" string \""); }
|
||||
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" \""); }
|
||||
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' string '"); }
|
||||
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' '"); }
|
||||
| FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,NULL, $1, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); }
|
||||
| FUNCTIONNAME '(' args ')' { $$=xp_new(XP_PRIME_FN,A_NAN,NULL, $1, NULL, $3, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); }
|
||||
;
|
||||
|
||||
args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, $3);
|
||||
args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3);
|
||||
clicon_debug(2,"args -> args expr");}
|
||||
| expr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);
|
||||
| expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);
|
||||
clicon_debug(2,"args -> expr "); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ yang_find_myprefix(yang_stmt *ys)
|
|||
}
|
||||
if ((yprefix = yang_find(ymod, Y_PREFIX, NULL)) == NULL)
|
||||
goto done;
|
||||
prefix = yprefix->ys_argument;
|
||||
prefix = yang_argument_get(yprefix);
|
||||
done:
|
||||
return prefix;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ yang_modules_state_get(clicon_handle h,
|
|||
/* xc is also original tree, need to copy it */
|
||||
if ((xw = xml_wrap(xc, "top")) == NULL)
|
||||
goto done;
|
||||
if (xpath_first(xw, "%s", xpath)){
|
||||
if (xpath_first(xw, NULL, "%s", xpath)){
|
||||
if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -338,7 +338,7 @@ yang_modules_state_get(clicon_handle h,
|
|||
if ((x = xml_wrap(x, "top")) < 0)
|
||||
goto done;
|
||||
/* extract xpath part of module-state tree */
|
||||
if (xpath_vec_nsc(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
if (xpath_vec(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0)
|
||||
goto done;
|
||||
if (xvec != NULL){
|
||||
for (i=0; i<xlen; i++)
|
||||
|
|
|
|||
|
|
@ -1490,6 +1490,7 @@ notification_substmt : if_feature_stmt { clicon_debug(2,"notification-substmt -
|
|||
| typedef_stmt { clicon_debug(2,"notification-substmt -> typedef-stmt"); }
|
||||
| grouping_stmt { clicon_debug(2,"notification-substmt -> grouping-stmt"); }
|
||||
| data_def_stmt { clicon_debug(2,"notification-substmt -> data-def-stmt"); }
|
||||
| unknown_stmt { clicon_debug(2,"notification-substmt -> unknown-stmt");}
|
||||
| { clicon_debug(2,"notification-substmt -> "); }
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ start_restconf(){
|
|||
}
|
||||
|
||||
stop_restconf(){
|
||||
sudo pkill -u $wwwuser -f "$clixon_restconf"
|
||||
sudo pkill -u $wwwuser -f clixon_restconf # Dont use $clixon_restoconf doesnt work in valgrind
|
||||
if [ $valgrindtest -eq 3 ]; then
|
||||
sleep 1
|
||||
checkvalgrind
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
# 2. example-augment - urn:example:augment - mymod
|
||||
# (augmented): mandatory-leaf, me, other,
|
||||
# (uses/grouping): ip, port, lid, lport
|
||||
# Note augment+state not tested here (need plugin), simple test in test_restconf.sh
|
||||
#
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
|
|
@ -167,7 +169,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
@ -217,13 +219,12 @@ new "restconf get augment json"
|
|||
expectpart "$(curl -s -i -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK
' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}
'
|
||||
|
||||
new "restconf get augment xml"
|
||||
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK
' '<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface><interface xmlns:mymod="urn:example:augment"><name>e2</name><type>fddi</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:other>if:fddi</mymod:other><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface><interface xmlns:mymod="urn:example:augment"><name>e3</name><type>fddi</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:me>mymod:you</mymod:me><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface></interfaces>'
|
||||
|
||||
expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK
' '<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><mymod:port>80</mymod:port><mymod:lport>8080</mymod:lport></interface><interface><name>e2</name><type>fddi</type><mymod:mandatory-leaf xmlns:mymod="urn:example:augment">true</mymod:mandatory-leaf><mymod:other xmlns:mymod="urn:example:augment">if:fddi</mymod:other><mymod:port xmlns:mymod="urn:example:augment">80</mymod:port><mymod:lport xmlns:mymod="urn:example:augment">8080</mymod:lport></interface><interface><name>e3</name><type>fddi</type><mymod:mandatory-leaf xmlns:mymod="urn:example:augment">true</mymod:mandatory-leaf><mymod:me xmlns:mymod="urn:example:augment">mymod:you</mymod:me><mymod:port xmlns:mymod="urn:example:augment">80</mymod:port><mymod:lport xmlns:mymod="urn:example:augment">8080</mymod:lport></interface></interfaces>'
|
||||
|
||||
#<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e1</name><ospf xmlns="urn:example:augment"><reference-bandwidth>23</reference-bandwidth></ospf></interface>'
|
||||
|
||||
XML=$(cat <<EOF
|
||||
<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><name>e1</name><ospf xmlns="urn:example:augment"><reference-bandwidth>23</reference-bandwidth></ospf></interface>'
|
||||
<interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces" xmlns:mymod="urn:example:augment"><name>e1</name><type>mymod:some-new-iftype</type><mymod:mandatory-leaf>true</mymod:mandatory-leaf><ospf xmlns="urn:example:augment"><reference-bandwidth>23</reference-bandwidth></ospf></interface>'
|
||||
EOF
|
||||
)
|
||||
|
||||
|
|
@ -240,10 +241,10 @@ new "restconf POST augment multi-namespace path e2 (middle path)"
|
|||
expectpart "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e2 -d "$XML" )" 0 ''
|
||||
|
||||
new "restconf GET augment multi-namespace top"
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","example-augment:ospf":{"reference-bandwidth":23},"example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}'
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}'
|
||||
|
||||
new "restconf GET augment multi-namespace level 1"
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"e1","example-augment:ospf":{"reference-bandwidth":23},"example-augment:port":80,"example-augment:lport":8080}\]}'
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080}\]}'
|
||||
|
||||
new "restconf GET augment multi-namespace cross"
|
||||
expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1/example-augment:ospf)" 0 'HTTP/1.1 200 OK' '{"example-augment:ospf":{"reference-bandwidth":23}}'
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
|
|
@ -121,7 +121,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
125
test/test_cli_submodes.sh
Executable file
125
test/test_cli_submodes.sh
Executable file
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env bash
|
||||
# CLIgen mode tests
|
||||
# Have two modes: AAA and BBB
|
||||
# Have the following clispec files with syntax for:
|
||||
# 1) * 2) AAA, 3) BBB, 4) CCC, 5) AAA:BBB, 6) BBB:CCC
|
||||
# Verify then that modes AAA and BBB have right syntax (also negative)
|
||||
# AAA should have syntax from 1,2,5 (and not 3,4,6)
|
||||
# BBB should have syntax from 1,3,5,6 (and not 2,4)
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
# include err() and new() functions and creates $dir
|
||||
|
||||
cfg=$dir/conf_yang.xml
|
||||
clidir=$dir/clidir
|
||||
|
||||
if [ ! -d $clidir ]; then
|
||||
mkdir $clidir
|
||||
fi
|
||||
|
||||
# Use yang in example
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$IETFRFC</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MODULE_MAIN>clixon-example</CLICON_YANG_MODULE_MAIN>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_CLISPEC_DIR>$clidir</CLICON_CLISPEC_DIR>
|
||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
# clispec files 1..6 for submodes AAA and BBB as described in top comment
|
||||
|
||||
cat <<EOF > $clidir/cli1.cli
|
||||
CLICON_MODE="*";
|
||||
cmd1;
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clidir/cli2.cli
|
||||
CLICON_MODE="AAA";
|
||||
cmd2;
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clidir/cli3.cli
|
||||
CLICON_MODE="BBB";
|
||||
cmd3;
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clidir/cli4.cli
|
||||
CLICON_MODE="CCC";
|
||||
cmd4;
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clidir/cli5.cli
|
||||
CLICON_MODE="AAA:BBB";
|
||||
cmd5;
|
||||
EOF
|
||||
|
||||
cat <<EOF > $clidir/cli6.cli
|
||||
CLICON_MODE="BBB:CCC";
|
||||
cmd6;
|
||||
EOF
|
||||
|
||||
new "test params: -f $cfg"
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -z -f $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
fi
|
||||
|
||||
|
||||
m=AAA
|
||||
# Tests using mode AAA that should pass
|
||||
for c in 1 2 5; do
|
||||
new "cli mode $m 1 cmd$c OK"
|
||||
expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 0 "^$"
|
||||
done
|
||||
# Tests using mode AAA that should fail
|
||||
for c in 3 4 6; do
|
||||
new "cli mode $m 1 cmd$c Not OK"
|
||||
expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 255 "^$"
|
||||
done
|
||||
|
||||
m=BBB
|
||||
# Tests using mode BBB that should pass
|
||||
for c in 1 3 5 6; do
|
||||
new "cli mode $m 1 cmd$c OK"
|
||||
expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 0 "^$"
|
||||
done
|
||||
# Tests using mode BBB that should fail
|
||||
for c in 2 4; do
|
||||
new "cli mode $m 1 cmd$c Not OK"
|
||||
expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 255 "^$"
|
||||
done
|
||||
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
pid=$(pgrep -u root -f clixon_backend)
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
stop_backend -f $cfg
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -155,7 +155,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ EOF
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable http basic auth)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon (-a is enable basic authentication)"
|
||||
start_restconf -f $cfg -- -a
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ cat <<EOF > $tmp # new
|
|||
EOF
|
||||
|
||||
new "netconf get config xpath"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
|
||||
# Too many quotes
|
||||
cat <<EOF > $tmp # new
|
||||
|
|
@ -110,7 +110,7 @@ cat <<EOF > $tmp # new
|
|||
EOF
|
||||
|
||||
new "netconf get config xpath parent"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><name>eth1</name><enabled>true</enabled><ip:ipv4><ip:enabled>true</ip:enabled><ip:forwarding>false</ip:forwarding><ip:address><ip:ip>9.2.3.4</ip:ip><ip:prefix-length>24</ip:prefix-length></ip:address></ip:ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ip:ipv4 xmlns:ip="urn:ietf:params:xml:ns:yang:ietf-ip"><ip:enabled>true</ip:enabled><ip:forwarding>false</ip:forwarding><ip:address><ip:ip>9.2.3.4</ip:ip><ip:prefix-length>24</ip:prefix-length></ip:address></ip:ipv4></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "netconf validate missing type"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
|
@ -136,7 +136,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><validate><source><candidate/></sou
|
|||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf edit config merge"
|
||||
new "netconf edit config merge eth2"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth2</name><type>ex:eth</type></interface></interfaces></config><default-operation>merge</default-operation></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# Note, the type here is non-existant identityref, fails on validation
|
||||
|
|
@ -163,7 +163,7 @@ new "netconf edit state operation should fail"
|
|||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e0</name><oper-status>up</oper-status></interface></interfaces></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag><error-severity>error</error-severity><error-message>State data not allowed</error-message></rpc-error></rpc-reply>]]>]]>"
|
||||
|
||||
new "netconf get state operation"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" /></get></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" /></get></rpc>]]>]]>" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>eth1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status><ex:my-status xmlns:ex="urn:example:clixon"><ex:int>42</ex:int><ex:str>foo</ex:str></ex:my-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "netconf lock/unlock"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
|
|||
96
test/test_netconf_filter.sh
Executable file
96
test/test_netconf_filter.sh
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
#!/usr/bin/env bash
|
||||
# Test netconf filter, subtree and xpath
|
||||
# Note subtree namespaces not implemented
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
cfg=$dir/conf_yang.xml
|
||||
fyang=$dir/filter.yang
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
|
||||
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
|
||||
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
|
||||
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module filter{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:filter";
|
||||
prefix fi;
|
||||
container x{
|
||||
list y {
|
||||
key a;
|
||||
leaf a{
|
||||
type string;
|
||||
}
|
||||
leaf b{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
new "test params: -f $cfg"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
fi
|
||||
|
||||
new "waiting"
|
||||
wait_backend
|
||||
|
||||
new "Add two entries"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><x xmlns="urn:example:filter"><y><a>1</a><b>1</b></y><y><a>2</a><b>2</b></y></x></config></edit-config></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
|
||||
|
||||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "wrong filter type"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type='foo'><x xmlns='urn:example:filter'><y><a>1</a></y></x></filter></get></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-tag>operation-failed</error-tag><error-type>applicatio</error-type><error-severity>error</error-severity><error-message>filter type not supported</error-message><error-info>type</error-info></rpc-error></rpc-reply>]]>]]>$'
|
||||
|
||||
new "get-config subtree one"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get-config><source><running/></source><filter type='subtree'><x xmlns='urn:example:filter'><y><a>1</a></y></x></filter></get-config></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:filter"><y><a>1</a><b>1</b></y></x></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "get subtree one"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type='subtree'><x xmlns='urn:example:filter'><y><a>1</a></y></x></filter></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:filter"><y><a>1</a><b>1</b></y></x></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "get-config xpath one"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type='xpath' select=\"/fi:x/fi:y[fi:a='1']\" xmlns:fi='urn:example:filter' /></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:filter"><y><a>1</a><b>1</b></y></x></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "get xpath one"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type='xpath' select=\"/fi:x/fi:y[fi:a='1']\" xmlns:fi='urn:example:filter' /></get></rpc>]]>]]>" '^<rpc-reply><data><x xmlns="urn:example:filter"><y><a>1</a><b>1</b></y></x></data></rpc-reply>]]>]]>$'
|
||||
|
||||
if [ $BE -eq 0 ]; then
|
||||
exit # BE
|
||||
fi
|
||||
|
||||
new "Kill backend"
|
||||
# Check if premature kill
|
||||
pid=$(pgrep -u root -f clixon_backend)
|
||||
if [ -z "$pid" ]; then
|
||||
err "backend already dead"
|
||||
fi
|
||||
# kill backend
|
||||
stop_backend -f $cfg
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -37,6 +37,7 @@ cat <<EOF > $cfg
|
|||
<CLICON_YANG_DIR>$OCDIR/lacp</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/lldp</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/local-routing</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/macsec</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/mpls</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/multicast</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>$OCDIR/network-instance</CLICON_YANG_DIR>
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
@ -90,7 +90,7 @@ expecteof "time $clixon_netconf -qf $cfg" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-
|
|||
new "netconf get test single req"
|
||||
sel="/if:interfaces/if:interface[if:name='e1']"
|
||||
msg="<rpc><get><filter type=\"xpath\" select=\"$sel\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\"/></get></rpc>]]>]]>"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^<rpc-reply><data><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>e1</name><type>ex:eth</type><enabled>true</enabled><oper-status>up</oper-status><ex:my-status xmlns:ex="urn:example:clixon"><ex:int>42</ex:int><ex:str>foo</ex:str></ex:my-status></interface></interfaces></data></rpc-reply>]]>]]>$'
|
||||
|
||||
new "netconf get $perfreq single reqs"
|
||||
{ time -p for (( i=0; i<$perfreq; i++ )); do
|
||||
|
|
@ -101,7 +101,7 @@ done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}'
|
|||
|
||||
# RESTCONF get
|
||||
new "restconf get test single req"
|
||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface":[{"name":"e1","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}
|
||||
expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface":[{"name":"e1","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]}
|
||||
'
|
||||
|
||||
new "restconf get $perfreq single reqs"
|
||||
|
|
|
|||
28
test/test_perf_xml.sh
Executable file
28
test/test_perf_xml.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# Test: XML performance test
|
||||
# See https://github.com/clicon/clixon/issues/96
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
: ${clixon_util_xml:="clixon_util_xml"}
|
||||
|
||||
# Number of list/leaf-list entries in file
|
||||
: ${perfnr:=30000}
|
||||
|
||||
fxml=$dir/long.xml
|
||||
|
||||
new "generate long file $fxml"
|
||||
echo -n "<rpc-reply><stdout><![CDATA[" > $fxml
|
||||
for (( i=0; i<$perfnr; i++ )); do
|
||||
echo "*>i10.0.0.$i/32 10.255.0.20 0 100 0 i" >> $fxml
|
||||
done
|
||||
echo "]]></stdout></rpc-reply>" >> $fxml
|
||||
|
||||
# 32-bit i386:
|
||||
#0.37user 1.94system 0:02.47elapsed 93%CPU (0avgtext+0avgdata 9336maxresident)k
|
||||
#256inputs+0outputs (2major+2049minor)pagefaults 0swa
|
||||
new "xml parse long CDATA"
|
||||
expecteof_file "time $clixon_util_xml" 0 "$fxml"
|
||||
|
||||
rm -rf $dir
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ testrun(){
|
|||
err
|
||||
fi
|
||||
# Kill all backends regardless of user or pid files (we mess with them in this test)
|
||||
sudo pkill clixon_backend
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
# start backend as user
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
new "start backend -s init -f $cfg -- -s"
|
||||
start_backend -s init -f $cfg -- -s
|
||||
fi
|
||||
|
|
@ -52,7 +52,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
@ -194,12 +194,16 @@ new "restconf Add interfaces subtree eth/0/0 using POST"
|
|||
expectpart "$(curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 ""
|
||||
|
||||
new "restconf Check eth/0/0 added config"
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}\]}}
|
||||
'
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}'
|
||||
|
||||
new "restconf Check eth/0/0 GET augmented state level 1"
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 '{"ietf-interfaces:interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}'
|
||||
|
||||
new "restconf Check eth/0/0 GET augmented state level 2"
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0/clixon-example:my-status)" 0 '{"clixon-example:my-status":{"int":42,"str":"foo"}}'
|
||||
|
||||
new "restconf Check eth/0/0 added state"
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":\["42","41","43"\]}}
|
||||
'
|
||||
expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":\["42","41","43"\]}}'
|
||||
|
||||
new "restconf Re-post eth/0/0 which should generate error"
|
||||
expectpart "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}}
'
|
||||
|
|
@ -211,7 +215,7 @@ new "Add nothing using POST (expect fail)"
|
|||
expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body MUST contain exactly one instance of the expected data resource"}}}'
|
||||
|
||||
new "restconf Check description added"
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}}
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]}}
|
||||
'
|
||||
|
||||
new "restconf delete eth/0/0"
|
||||
|
|
@ -227,7 +231,7 @@ new "restconf Add subtree eth/0/0 using PUT"
|
|||
expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 ""
|
||||
|
||||
new "restconf get subtree"
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}}
|
||||
expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]}}
|
||||
'
|
||||
|
||||
new "restconf rpc using POST json"
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
fi
|
||||
|
|
@ -83,7 +83,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
fi
|
||||
|
|
@ -129,7 +129,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
new "start backend -s init -f $cfg -- -s"
|
||||
start_backend -s init -f "$cfg" -- -s
|
||||
fi
|
||||
|
|
@ -78,7 +78,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
@ -99,7 +99,7 @@ expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://loca
|
|||
# This just catches the header and the jukebox module, the RFC has foo and bar which
|
||||
# seems wrong to recreate
|
||||
new "B.1.2. Retrieve the Server Module Information"
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":' '"module":\[{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}'
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2019-08-13","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"clixon-rfc5277","revision":"2008-07-01","namespace":"urn:ietf:params:xml:ns:netmod:notification","conformance-type":"implement"},{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"'
|
||||
|
||||
new "B.1.3. Retrieve the Server Capability Information"
|
||||
expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' '<capabilities xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring"><capability>urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=explicit</capability><capability>urn:ietf:params:restconf:capability:depth</capability>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ if [ $BE -ne 0 ]; then
|
|||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
sudo pkill clixon_backend # to be sure
|
||||
sudo pkill -f clixon_backend # to be sure
|
||||
|
||||
new "start backend -s init -f $cfg"
|
||||
start_backend -s init -f $cfg
|
||||
|
|
@ -81,7 +81,7 @@ new "waiting"
|
|||
wait_backend
|
||||
|
||||
new "kill old restconf daemon"
|
||||
sudo pkill -u $wwwuser clixon_restconf
|
||||
sudo pkill -u $wwwuser -f clixon_restconf
|
||||
|
||||
new "start restconf daemon"
|
||||
start_restconf -f $cfg
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue