* New XML parsing API:

* `clixon_xml_parse_string()`
   * `clixon_xml_parse_file()`
* New JSON parsing API, with same signature as XML parsing:
   * `clixon_json_parse_string()`
   * `clixon_xml_parse_file()`
* XML YANG binding API have been rearranged as follows:
   * `xml_bind_yang_rpc()`
   * `xml_bind_yang_rpc_reply()`
   * `xml_bind_yang()`
   * `xml_bind_yang0()`
This commit is contained in:
Olof hagsand 2020-03-19 21:32:27 +01:00
parent c4b0491754
commit 09a2e09848
54 changed files with 590 additions and 711 deletions

View file

@ -250,11 +250,13 @@ text_read_modstate(clicon_handle h,
else if (xmcache && msd){
msd->md_status = 1; /* There is module state in the file */
/* Create diff trees */
if (xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>", yspec, &msd->md_del) < 0)
if (clixon_xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>",
YB_MODULE, yspec, &msd->md_del, NULL) < 0)
goto done;
if (xml_rootchild(msd->md_del, 0, &msd->md_del) < 0)
goto done;
if (xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>", yspec, &msd->md_mod) < 0)
if (clixon_xml_parse_string("<modules-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-yang-library\"/>",
YB_MODULE, yspec, &msd->md_mod, NULL) < 0)
goto done;
if (xml_rootchild(msd->md_mod, 0, &msd->md_mod) < 0)
goto done;
@ -349,10 +351,10 @@ xmldb_readfile(clicon_handle h,
goto done;
}
if (strcmp(format, "json")==0){
if ((ret = json_parse_file(fd, yspec, &x0, NULL)) < 0) /* XXX: ret == 0*/
if ((ret = clixon_json_parse_file(fd, YB_MODULE, yspec, &x0, NULL)) < 0) /* XXX: ret == 0*/
goto done;
}
else if ((xml_parse_file2(fd, YB_TOP, yspec, "</config>", &x0, NULL)) < 0)
else if ((clixon_xml_parse_file(fd, YB_MODULE, yspec, "</config>", &x0, NULL)) < 0)
goto done;
/* Always assert a top-level called "config".

View file

@ -808,7 +808,7 @@ xml_container_presence(cxobj *x,
* @code
* cxobj *xt;
* cxobj *xret = NULL;
* if (xml_parse_string("<a>17</a>", yspec, &xt) < 0)
* if (clixon_xml_parse_string("<a>17</a>", YB_NONE, NULL, &xt, NULL) < 0)
* err;
* if ((ret = xmldb_put(h, "running", OP_MERGE, xt, username, cbret)) < 0)
* err;

View file

@ -139,17 +139,16 @@ clicon_err_reset(void)
*
* @param[in] fn Inline function name (when called from clicon_err() macro)
* @param[in] line Inline file line number (when called from clicon_err() macro)
* @param[in] err Error number, typically errno
* @param[in] suberr Sub-error number
* @param[in] category See enum clicon_err
* @param[in] errno Error number, typically errno
* @param[in] reason Error string, format with argv
* @see clicon_err_reser Resetting the global error variables.
*/
int
clicon_err_fn(const char *fn,
const int line,
int category,
int suberr,
char *reason, ...)
int clicon_err_fn(const char *fn,
const int line,
int category,
int err,
char *format, ...)
{
va_list args;
int len;
@ -158,11 +157,11 @@ clicon_err_fn(const char *fn,
/* Set the global variables */
clicon_errno = category;
clicon_suberrno = suberr;
clicon_suberrno = errno;
/* first round: compute length of error message */
va_start(args, reason);
len = vsnprintf(NULL, 0, reason, args);
va_start(args, format);
len = vsnprintf(NULL, 0, format, args);
va_end(args);
/* allocate a message string exactly fitting the message length */
@ -171,9 +170,9 @@ clicon_err_fn(const char *fn,
goto done;
}
/* second round: compute write message from reason and args */
va_start(args, reason);
if (vsnprintf(msg, len+1, reason, args) < 0){
/* second round: compute write message from format and args */
va_start(args, format);
if (vsnprintf(msg, len+1, format, args) < 0){
va_end(args);
fprintf(stderr, "vsnprintf: %s\n", strerror(errno)); /* dont use clicon_err here due to recursion */
goto done;
@ -182,14 +181,14 @@ clicon_err_fn(const char *fn,
strncpy(clicon_err_reason, msg, ERR_STRLEN-1);
/* Actually log it */
if (suberr){
/* Here we could take care of specific suberr, like application-defined errors */
if (errno){
/* Here we could take care of specific errno, like application-defined errors */
clicon_log(LOG_ERR, "%s: %d: %s: %s: %s",
fn,
line,
clicon_strerror(category),
msg,
suberr==XMLPARSE_ERRNO?"XML parse error":strerror(suberr));
errno==XMLPARSE_ERRNO?"XML parse error":strerror(errno));
}
else
clicon_log(LOG_ERR, "%s: %d: %s: %s",

View file

@ -1169,11 +1169,11 @@ json_xmlns_translate(yang_stmt *yspec,
* @see RFC 7951
*/
static int
_json_parse(char *str,
enum yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
cxobj **xerr)
_json_parse(char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
cxobj **xerr)
{
int retval = -1;
clixon_json_yacc jy = {0,};
@ -1223,22 +1223,32 @@ _json_parse(char *str,
* XXX should be xml_bind_yang0_parent() sometimes.
*/
switch (yb){
case YB_RPC:
case YB_UNKNOWN:
case YB_NONE:
break;
case YB_PARENT:
if ((ret = xml_bind_yang0_parent(x, xerr)) < 0)
if ((ret = xml_bind_yang0(x, yb, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
break;
case YB_TOP:
if (xml_bind_yang0(x, yspec, xerr) < 0)
goto done;
case YB_MODULE:
#ifdef XMLDB_CONFIG_HACK
if (strcmp(xml_name(x),"config") == 0 ||
strcmp(xml_name(x),"data") == 0){
/* xt:<top> nospec
* x: <config>
* <a> <-- populate from modules
*/
if ((ret = xml_bind_yang(x, yb, yspec, xerr)) < 0)
goto done;
}
else
#endif
if ((ret = xml_bind_yang0(x, yb, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
break;
case YB_NONE:
break;
}
/* Now find leafs with identityrefs (+transitive) and translate
* prefixes in values to XML namespaces */
@ -1247,9 +1257,12 @@ _json_parse(char *str,
if (ret == 0) /* XXX necessary? */
goto fail;
}
if (failed)
goto fail;
/* This fails if xt is not bound to yang */
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
goto done;
retval = (failed==0) ? 1 : 0;
retval = 1;
done:
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
if (cberr)
@ -1267,29 +1280,30 @@ _json_parse(char *str,
/*! Parse string containing JSON and return an XML tree
*
* @param[in] str String containing JSON
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] yspec Yang specification, mandatory to make module->xmlns translation
* @param[in,out] xt Top object, if not exists, on success it is created with name 'top'
* @param[out] xerr Reason for invalid returned as netconf err msg
*
* @code
* cxobj *cx = NULL;
* if (json_parse_str(str, yspec, &cx, &xerr) < 0)
* err;
* xml_free(cx);
* @endcode
* @note you need to free the xml parse tree after use, using xml_free()
* @see json_parse_file
* @retval 1 OK and valid
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
* @see json_parse_file with a file descriptor (and more description)
*
* @code
* cxobj *x = NULL;
* if (clixon_json_parse_string(str, YB_MODULE, yspec, &x, &xerr) < 0)
* err;
* xml_free(x);
* @endcode
* @note you need to free the xml parse tree after use, using xml_free()
* @see clixon_xml_parse_string XML instead of JSON
* @see clixon_json_parse_file From a file
*/
int
json_parse_str2(char *str,
enum yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
clixon_json_parse_string(char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
clicon_debug(1, "%s", __FUNCTION__);
if (xt==NULL){
@ -1303,31 +1317,6 @@ json_parse_str2(char *str,
return _json_parse(str, yb, yspec, *xt, xerr);
}
int
json_parse_str(char *str,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
enum yang_bind yb = YB_PARENT;
clicon_debug(1, "%s", __FUNCTION__);
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (*xt == NULL){
yb = YB_TOP; /* ad-hoc #1 */
if ((*xt = xml_new("top", NULL, CX_ELMNT)) == NULL)
return -1;
}
else{
if (xml_spec(*xt) == NULL)
yb = YB_TOP; /* ad-hoc #2 */
}
return _json_parse(str, yb, yspec, *xt, xerr);
}
/*! Read a JSON definition from file and parse it into a parse-tree.
*
* File will be parsed as follows:
@ -1347,7 +1336,7 @@ json_parse_str(char *str,
*
* @code
* cxobj *xt = NULL;
* if (json_parse_file(0, yspec, &xt) < 0)
* if (clixon_json_parse_file(0, YB_MODULE, yspec, &xt) < 0)
* err;
* xml_free(xt);
* @endcode
@ -1359,31 +1348,29 @@ json_parse_str(char *str,
* @retval 0 Invalid (only if yang spec) w xerr set
* @retval -1 Error with clicon_err called
*
* @see json_parse_str
* @see clixon_json_parse_string
* @see RFC7951
*/
int
json_parse_file(int fd,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
clixon_json_parse_file(int fd,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
int retval = -1;
int ret;
char *jsonbuf = NULL;
int jsonbuflen = BUFLEN; /* start size */
int oldjsonbuflen;
char *ptr;
char ch;
int len = 0;
enum yang_bind yb = YB_PARENT;
int retval = -1;
int ret;
char *jsonbuf = NULL;
int jsonbuflen = BUFLEN; /* start size */
int oldjsonbuflen;
char *ptr;
char ch;
int len = 0;
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (*xt==NULL)
yb = YB_TOP;
if ((jsonbuf = malloc(jsonbuflen)) == NULL){
clicon_err(OE_XML, errno, "malloc");
goto done;

View file

@ -134,15 +134,16 @@ netconf_invalid_value_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>invalid-value</error-tag>"
"<error-severity>error</error-severity>", type) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-type>%s</error-type>"
"<error-tag>invalid-value</error-tag>"
"<error-severity>error</error-severity>", type) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-message>%s</error-message>", encstr) < 0)
goto done;
}
retval = 0;
@ -314,16 +315,16 @@ netconf_bad_attribute_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>bad-attribute</error-tag>"
"<error-info>%s</error-info>"
"<error-severity>error</error-severity>", type, info) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>bad-attribute</error-tag>"
"<error-info>%s</error-info>"
"<error-severity>error</error-severity>", type, info) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
@ -403,17 +404,17 @@ netconf_common_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>%s</error-tag>"
"<error-info><%s>%s</%s></error-info>"
"<error-severity>error</error-severity>",
type, tag, infotag, element, infotag) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>%s</error-tag>"
"<error-info><%s>%s</%s></error-info>"
"<error-severity>error</error-severity>",
type, tag, infotag, element, infotag) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
@ -653,15 +654,15 @@ netconf_access_denied_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>access-denied</error-tag>"
"<error-severity>error</error-severity>", type) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>access-denied</error-tag>"
"<error-severity>error</error-severity>", type) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
@ -883,24 +884,24 @@ netconf_data_missing_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL,
"<error-type>application</error-type>"
"<error-tag>data-missing</error-tag>") < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-type>application</error-type>"
"<error-tag>data-missing</error-tag>") < 0)
goto done;
if (missing_choice) /* NYI: RFC7950: 15.6 <error-path> */
if (xml_parse_va(&xerr, NULL,
"<error-app-tag>missing-choice</error-app-tag>"
"<error-info><missing-choice>%s</missing-choice></error-info>",
missing_choice) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-app-tag>missing-choice</error-app-tag>"
"<error-info><missing-choice>%s</missing-choice></error-info>",
missing_choice) < 0)
goto done;
if (xml_parse_va(&xerr, NULL,
"<error-severity>error</error-severity>") < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-severity>error</error-severity>") < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL,
"<error-message>%s</error-message>", encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-message>%s</error-message>", encstr) < 0)
goto done;
}
retval = 0;
@ -1011,16 +1012,16 @@ netconf_operation_failed_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-severity>error</error-severity>",
type) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>%s</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-severity>error</error-severity>",
type) < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
@ -1090,15 +1091,15 @@ netconf_malformed_message_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>rpc</error-type>"
"<error-tag>malformed-message</error-tag>"
"<error-severity>error</error-severity>") < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>rpc</error-type>"
"<error-tag>malformed-message</error-tag>"
"<error-severity>error</error-severity>") < 0)
goto done;
if (message){
if (xml_chardata_encode(&encstr, "%s", message) < 0)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-message>%s</error-message>",
encstr) < 0)
goto done;
}
retval = 0;
@ -1137,10 +1138,11 @@ netconf_data_not_unique_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>protocol</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-app-tag>data-not-unique</error-app-tag>"
"<error-severity>error</error-severity>") < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL,
"<error-type>protocol</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-app-tag>data-not-unique</error-app-tag>"
"<error-severity>error</error-severity>") < 0)
goto done;
if (cvec_len(cvk)){
if ((xinfo = xml_new("error-info", xerr, CX_ELMNT)) == NULL)
@ -1153,7 +1155,8 @@ netconf_data_not_unique_xml(cxobj **xret,
if ((xi = xml_find(x, cv_string_get(cvi))) == NULL)
continue; /* ignore, shouldnt happen */
clicon_xml2cbuf(cb, xi, 0, 0, -1);
if (xml_parse_va(&xinfo, NULL, "<non-unique>%s</non-unique>", cbuf_get(cb)) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &xinfo, NULL,
"<non-unique>%s</non-unique>", cbuf_get(cb)) < 0)
goto done;
cbuf_reset(cb);
}
@ -1190,13 +1193,13 @@ netconf_minmax_elements_xml(cxobj **xret,
goto done;
if ((xerr = xml_new("rpc-error", *xret, CX_ELMNT)) == NULL)
goto done;
if (xml_parse_va(&xerr, NULL, "<error-type>protocol</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-app-tag>too-%s-elements</error-app-tag>"
"<error-severity>error</error-severity>"
"<error-path>%s</error-path>",
max?"many":"few",
xml_name(x)) < 0) /* XXX should be xml2xpath */
if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "<error-type>protocol</error-type>"
"<error-tag>operation-failed</error-tag>"
"<error-app-tag>too-%s-elements</error-app-tag>"
"<error-severity>error</error-severity>"
"<error-path>%s</error-path>",
max?"many":"few",
xml_name(x)) < 0) /* XXX should be xml2xpath */
goto done;
retval = 0;
done:
@ -1264,19 +1267,20 @@ netconf_module_features(clicon_handle h)
{
int retval = -1;
cxobj *xc;
yang_stmt *yspec;
yspec = clicon_dbspec_yang(h);
if ((xc = clicon_conf_xml(h)) == NULL){
clicon_err(OE_CFG, ENOENT, "Clicon configuration not loaded");
goto done;
}
/* Enable features (hardcoded here) */
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:candidate</CLICON_FEATURE>", yspec, &xc) < 0)
if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:candidate</CLICON_FEATURE>",
YB_PARENT, NULL, &xc, NULL) < 0)
goto done;
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:validate</CLICON_FEATURE>", yspec, &xc) < 0)
if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:validate</CLICON_FEATURE>",
YB_PARENT, NULL, &xc, NULL) < 0)
goto done;
if (xml_parse_string("<CLICON_FEATURE>ietf-netconf:xpath</CLICON_FEATURE>", yspec, &xc) < 0)
if (clixon_xml_parse_string("<CLICON_FEATURE>ietf-netconf:xpath</CLICON_FEATURE>",
YB_PARENT, NULL, &xc, NULL) < 0)
goto done;
retval = 0;
done:
@ -1320,7 +1324,7 @@ netconf_module_load(clicon_handle h)
* @code
* cxobj *xt = NULL;
* char *db;
* xml_parse_string("<x><target>source</target></x>", NULL, &xt);
* clixon_xml_parse_string("<x><target>source</target></x>", YB_NONE, NULL, &xt, NULL);
* db = netconf_db_find(xt, "target");
* @endcode
*/
@ -1355,7 +1359,7 @@ netconf_db_find(cxobj *xn,
* printf("%s", cbuf_get(cb));
* cbuf_free(cb);
* @endcode
* @see clicon_rpc_generate_error
* @see clixon_netconf_error
*/
int
netconf_err2cb(cxobj *xerr,
@ -1496,3 +1500,46 @@ netconf_hello_req(clicon_handle h,
retval = 0;
return retval;
}
/*! Generate clicon error from Netconf error message
*
* Get a text error message from netconf error message and generate error on the form:
* <msg>: "<arg>": <netconf-error> or <msg>: <netconf-error>
* @param[in] fn Inline function name (when called from clicon_err() macro)
* @param[in] line Inline file line number (when called from clicon_err() macro)
* @param[in] err Error number, typically errno
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
* @param[in] format Format string
* @param[in] arg String argument to format (optional)
*/
int
clixon_netconf_error_fn(const char *fn,
const int line,
int category,
cxobj *xerr,
const char *msg,
const char *arg)
{
int retval = -1;
cbuf *cb = NULL;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (msg){
cprintf(cb, "%s", msg);
if (arg)
cprintf(cb, " \"%s\" ", arg);
cprintf(cb, ": ");
}
if (netconf_err2cb(xerr, cb) < 0)
goto done;
clicon_err_fn(fn, line, category, 0, "%s", cbuf_get(cb));
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}

View file

@ -214,7 +214,7 @@ parse_configfile(clicon_handle h,
char *body;
clicon_hash_t *copt = clicon_options(h);
cbuf *cbret = NULL;
cxobj *xret = NULL;
cxobj *xerr = NULL;
int ret;
cvec *nsc = NULL;
@ -236,8 +236,18 @@ parse_configfile(clicon_handle h,
}
clicon_debug(2, "%s: Reading config file %s", __FUNCTION__, filename);
fd = fileno(f);
if (xml_parse_file(fd, yspec, &xt) < 0)
if ((ret = clixon_xml_parse_file(fd, yspec?YB_MODULE:YB_NONE, yspec, NULL, &xt, &xerr)) < 0)
goto done;
if (ret == 0){
if ((cbret = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (netconf_err2cb(xerr, cbret) < 0)
goto done;
clixon_netconf_error(OE_CFG, xerr, NULL, NULL);
goto done;
}
if (xml_child_nr(xt)==1 && xml_child_nr_type(xt, CX_BODY)==1){
clicon_err(OE_CFG, 0, "Config file %s: Expected XML but is probably old sh style", filename);
goto done;
@ -252,14 +262,14 @@ parse_configfile(clicon_handle h,
}
if (xml_apply0(xc, CX_ELMNT, xml_default, h) < 0)
goto done;
if ((ret = xml_yang_validate_add(h, xc, &xret)) < 0)
if ((ret = xml_yang_validate_add(h, xc, &xerr)) < 0)
goto done;
if (ret == 0){
if ((cbret = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (netconf_err2cb(xret, cbret) < 0)
if (netconf_err2cb(xerr, cbret) < 0)
goto done;
clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret));
goto done;
@ -296,8 +306,8 @@ parse_configfile(clicon_handle h,
xml_nsctx_free(nsc);
if (cbret)
cbuf_free(cbret);
if (xret)
xml_free(xret);
if (xerr)
xml_free(xerr);
if (xt)
xml_free(xt);
if (f)
@ -330,8 +340,8 @@ clicon_option_add(clicon_handle h,
clicon_err(OE_UNIX, ENOENT, "option %s not found (clicon_conf_xml_set has not been called?)", name);
goto done;
}
if (xml_parse_va(&x, NULL, "<%s>%s</%s>",
name, value, name) < 0)
if (clixon_xml_parse_va(YB_NONE, NULL, &x, NULL, "<%s>%s</%s>",
name, value, name) < 0)
goto done;
}
if (clicon_hash_add(copt,
@ -394,7 +404,7 @@ clicon_options_main(clicon_handle h)
* - no default values
* - no sanity checks
*/
if (parse_configfile(h, configfile, yspec, &xconfig) < 0)
if (parse_configfile(h, configfile, NULL, &xconfig) < 0)
goto done;
if (xml_rootchild(xconfig, 0, &xconfig) < 0)
goto done;

View file

@ -184,7 +184,7 @@ clicon_msg_decode(struct clicon_msg *msg,
/* body */
xmlstr = msg->op_body;
clicon_debug(1, "%s %s", __FUNCTION__, xmlstr);
if (xml_parse_string(xmlstr, yspec, xml) < 0)
if (clixon_xml_parse_string(xmlstr, yspec?YB_MODULE:YB_NONE, yspec, xml, NULL) < 0)
goto done;
retval = 0;
done:

View file

@ -143,7 +143,7 @@ clicon_rpc_msg(clicon_handle h,
/* Cannot populate xret here because need to know RPC name (eg "lock") in order to associate yang
* to reply.
*/
if (xml_parse_string2(retdata, YB_NONE, NULL, &xret, NULL) < 0)
if (clixon_xml_parse_string(retdata, YB_NONE, NULL, &xret, NULL) < 0)
goto done;
}
if (xret0){
@ -280,38 +280,6 @@ clicon_rpc_netconf_xml(clicon_handle h,
return retval;
}
/*! Generate clicon error from Netconf error message
*
* Get a text error message from netconf error message and generate error on the form:
* <msg>: "<arg>": <netconf-error> or <msg>: <netconf-error>
* @param[in] xerr Netconf error xml tree on the form: <rpc-error>
* @param[in] format Format string
* @param[in] arg String argument to format (optional)
*/
int
clicon_rpc_generate_error(cxobj *xerr,
const char *msg,
const char *arg)
{
int retval = -1;
cbuf *cb = NULL;
if ((cb = cbuf_new()) ==NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (netconf_err2cb(xerr, cb) < 0)
goto done;
cprintf(cb, ". %s", msg);
if (arg)
cprintf(cb, " \"%s\" ", arg);
clicon_err(OE_NETCONF, 0, "%s", cbuf_get(cb));
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! Get database configuration
* Same as clicon_proto_change just with a cvec instead of lvec
@ -333,7 +301,7 @@ clicon_rpc_generate_error(cxobj *xerr,
* if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr, "msg", "/hello/world");
* clixon_netconf_error(OE_NETCONF, xerr, "msg", "/hello/world");
* err;
* }
* if (xt)
@ -342,7 +310,7 @@ clicon_rpc_generate_error(cxobj *xerr,
* xml_nsctx_free(nsc);
* @endcode
* @see clicon_rpc_get
* @see clicon_rpc_generate_error
* @see clixon_netconf_error
* @note the netconf return message is yang populated, as well as the return data
*/
int
@ -403,7 +371,7 @@ clicon_rpc_get_config(clicon_handle h,
}
else{
yspec = clicon_dbspec_yang(h);
if ((ret = xml_bind_yang(xd, yspec, &xerr)) < 0)
if ((ret = xml_bind_yang(xd, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
if ((xd = xpath_first(xerr, NULL, "rpc-error")) == NULL){
@ -477,7 +445,7 @@ clicon_rpc_edit_config(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Editing configuration", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Editing configuration", NULL);
goto done;
}
retval = 0;
@ -527,7 +495,7 @@ clicon_rpc_copy_config(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Copying configuration", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Copying configuration", NULL);
goto done;
}
retval = 0;
@ -570,7 +538,7 @@ clicon_rpc_delete_config(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Deleting configuration", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Deleting configuration", NULL);
goto done;
}
retval = 0;
@ -609,7 +577,7 @@ clicon_rpc_lock(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Locking configuration", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Locking configuration", NULL);
goto done;
}
retval = 0;
@ -647,7 +615,7 @@ clicon_rpc_unlock(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Configuration unlock", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Configuration unlock", NULL);
goto done;
}
retval = 0;
@ -681,7 +649,7 @@ clicon_rpc_unlock(clicon_handle h,
* if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0)
* err;
* if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
* clicon_rpc_generate_error(xerr, "clicon_rpc_get", NULL);
* clixon_netconf_error(OE_NETCONF, xerr, "clicon_rpc_get", NULL);
* err;
* }
* if (xt)
@ -690,7 +658,7 @@ clicon_rpc_unlock(clicon_handle h,
* xml_nsctx_free(nsc);
* @endcode
* @see clicon_rpc_get_config which is almost the same as with content=config, but you can also select dbname
* @see clicon_rpc_generate_error
* @see clixon_netconf_error
* @note the netconf return message is yang populated, as well as the return data
*/
int
@ -759,7 +727,7 @@ clicon_rpc_get(clicon_handle h,
}
else{
yspec = clicon_dbspec_yang(h);
if ((ret = xml_bind_yang(xd, yspec, &xerr)) < 0)
if ((ret = xml_bind_yang(xd, YB_MODULE, yspec, &xerr)) < 0)
goto done;
if (ret == 0){
if ((xd = xpath_first(xerr, NULL, "rpc-error")) == NULL){
@ -811,7 +779,7 @@ clicon_rpc_close_session(clicon_handle h)
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Close session", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Close session", NULL);
goto done;
}
retval = 0;
@ -850,7 +818,7 @@ clicon_rpc_kill_session(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Kill session", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Kill session", NULL);
goto done;
}
retval = 0;
@ -888,7 +856,7 @@ clicon_rpc_validate(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL);
clixon_netconf_error(OE_NETCONF, xerr, CLIXON_ERRSTR_VALIDATE_FAILED, NULL);
goto done;
}
retval = 0;
@ -924,7 +892,7 @@ clicon_rpc_commit(clicon_handle h)
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL);
clixon_netconf_error(OE_NETCONF, xerr, CLIXON_ERRSTR_COMMIT_FAILED, NULL);
goto done;
}
retval = 0;
@ -960,7 +928,7 @@ clicon_rpc_discard_changes(clicon_handle h)
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Discard changes", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Discard changes", NULL);
goto done;
}
retval = 0;
@ -1010,7 +978,7 @@ clicon_rpc_create_subscription(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Create subscription", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Create subscription", NULL);
goto done;
}
retval = 0;
@ -1048,7 +1016,7 @@ clicon_rpc_debug(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Debug", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Debug", NULL);
goto done;
}
if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){
@ -1091,7 +1059,7 @@ clicon_hello_req(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){
clicon_rpc_generate_error(xerr, "Hello", NULL);
clixon_netconf_error(OE_NETCONF, xerr, "Hello", NULL);
goto done;
}
if ((x = xpath_first(xret, NULL, "hello/session-id")) == NULL){

View file

@ -584,7 +584,7 @@ stream_notify(clicon_handle h,
/* From RFC5277 */
cprintf(cb, "<notification xmlns=\"%s\"><eventTime>%s</eventTime>%s</notification>",
NOTIFICATION_RFC5277_NAMESPACE, timestr, str);
if (xml_parse_string(cbuf_get(cb), yspec, &xev) < 0)
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, &xev, NULL) < 0)
goto done;
if (xml_rootchild(xev, 0, &xev) < 0)
goto done;
@ -649,7 +649,7 @@ stream_notify_xml(clicon_handle h,
cprintf(cb, "<notification xmlns=\"%s\"><eventTime>%s</eventTime>NULL</notification>",
NOTIFICATION_RFC5277_NAMESPACE,
timestr); /* XXX str is always NULL */
if (xml_parse_string(cbuf_get(cb), yspec, &xev) < 0)
if (clixon_xml_parse_string(cbuf_get(cb), YB_NONE, yspec, &xev, NULL) < 0)
goto done;
if (xml_rootchild(xev, 0, &xev) < 0)
goto done;

View file

@ -1416,7 +1416,7 @@ xml_rm_children(cxobj *xp,
* @retval -1 Error
* @code
* cxobj *xt = NULL;
* if (xml_parse_string("<a>2</a>", NULL, &xt) < 0)
* if (clixon_xml_parse_string("<a>2</a>", YB_NONE, NULL, &xt, NULL) < 0)
* err;
* # Here xt will be: <top><a>2</a></top>
* if (xml_rootchild(xt, 0, &xt) < 0)

View file

@ -447,7 +447,7 @@ clixon_xml_changelog_init(clicon_handle h)
clicon_err(OE_UNIX, errno, "open(%s)", filename);
goto done;
}
if (xml_parse_file(fd, yspec, &xt) < 0)
if (clixon_xml_parse_file(fd, YB_MODULE, yspec, NULL, &xt, NULL) < 0)
goto done;
if (xml_rootchild(xt, 0, &xt) < 0)
goto done;

View file

@ -372,18 +372,17 @@ xmltree2cbuf(cbuf *cb,
* @retval 1 Parse OK and all yang assignment made
* @retval 0 Parse OK but yang assigment not made (or only partial) and xerr set
* @retval -1 Error with clicon_err called. Includes parse error
* @see xml_parse_file
* @see xml_parse_string
* @see xml_parse_va
* @see clixon_xml_parse_file
* @see clixon_xml_parse_string
* @see _json_parse
* @note special case is empty XML where the parser is not invoked.
*/
static int
_xml_parse(const char *str,
enum yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
cxobj **xerr)
_xml_parse(const char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj *xt,
cxobj **xerr)
{
int retval = -1;
clixon_xml_yacc xy = {0,};
@ -423,21 +422,19 @@ _xml_parse(const char *str,
/* Populate, ie associate xml nodes with yang specs
*/
switch (yb){
case YB_RPC:
case YB_UNKNOWN:
case YB_NONE:
break;
case YB_PARENT:
/* xt:n Has spec
* x: <a> <-- populate from parent
*/
if ((ret = xml_bind_yang0_parent(x, xerr)) < 0)
if ((ret = xml_bind_yang0(x, YB_PARENT, NULL, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
break;
case YB_TOP:
case YB_MODULE:
/* xt:<top> nospec
* x: <a> <-- populate from modules
*/
@ -448,22 +445,25 @@ _xml_parse(const char *str,
* x: <config>
* <a> <-- populate from modules
*/
if ((ret = xml_bind_yang(x, yspec, xerr)) < 0)
if ((ret = xml_bind_yang(x, YB_MODULE, yspec, xerr)) < 0)
goto done;
}
else
#endif
if ((ret = xml_bind_yang0(x, yspec, xerr)) < 0)
if ((ret = xml_bind_yang0(x, YB_MODULE, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
break;
}
}
if (failed)
goto fail;
/* This fails if xt is not bound to yang */
/* Sort the complete tree after parsing. Sorting is less meaningful if Yang not bound */
if (xml_apply0(xt, CX_ELMNT, xml_sort, NULL) < 0)
goto done;
retval = (failed==0) ? 1 : 0;
retval = 1;
done:
clixon_xml_parsel_exit(&xy);
if (xy.xy_parse_string != NULL)
@ -471,43 +471,9 @@ _xml_parse(const char *str,
if (xy.xy_xvec)
free(xy.xy_xvec);
return retval;
}
/*! Read an XML definition from file and parse it into a parse-tree.
*
* @param[in] fd A file descriptor containing the XML file (as ASCII characters)
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xt Pointer to XML parse tree. If empty, create.
* @retval 1 Parse OK and all yang assignment made
* @retval 0 Parse OK but yang assigment not made (or only partial)
* @retval -1 Error with clicon_err called. Includes parse error *
* @code
* cxobj *xt = NULL;
* int fd;
* fd = open(filename, O_RDONLY);
* xml_parse_file(fd, yspec, &xt);
* xml_free(xt);
* @endcode
* @see xml_parse_string
* @see xml_parse_va
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
* @note May block on file I/O
* @see xml_parse_file2 for a more advanced API
*/
int
xml_parse_file(int fd,
yang_stmt *yspec,
cxobj **xt)
{
enum yang_bind yb = YB_PARENT;
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (*xt==NULL)
yb = YB_TOP;
return xml_parse_file2(fd, yb, yspec, NULL, xt, NULL);
fail: /* invalid */
retval = 0;
goto done;
}
/*! FSM to detect substring
@ -539,22 +505,22 @@ FSM(char *tag,
* cxobj *xerr = NULL;
* int fd;
* fd = open(filename, O_RDONLY);
* if ((ret = xml_parse_file2(fd, YB_TOP, yspec, "</config>", &xt, &xerr)) < 0)
* if ((ret = clixon_xml_parse_file(fd, YB_MODULE, yspec, "</config>", &xt, &xerr)) < 0)
* err;
* xml_free(xt);
* @endcode
* @see xml_parse_string
* @see xml_parse_file
* @see clixon_xml_parse_string
* @see clixon_json_parse_file
* @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
* @note May block on file I/O
*/
int
xml_parse_file2(int fd,
enum yang_bind yb,
yang_stmt *yspec,
char *endtag,
cxobj **xt,
cxobj **xerr)
clixon_xml_parse_file(int fd,
yang_bind yb,
yang_stmt *yspec,
char *endtag,
cxobj **xt,
cxobj **xerr)
{
int retval = -1;
int ret;
@ -568,6 +534,14 @@ xml_parse_file2(int fd,
int oldxmlbuflen;
int failed = 0;
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (yb == YB_MODULE && yspec == NULL){
clicon_err(OE_XML, EINVAL, "yspec is required if yb == YB_MODULE");
return -1;
}
if (endtag != NULL)
endtaglen = strlen(endtag);
if ((xmlbuf = malloc(xmlbuflen)) == NULL){
@ -635,27 +609,31 @@ xml_parse_file2(int fd,
* @code
* cxobj *xt = NULL;
* cxobj *xerr = NULL;
* if (xml_parse_string2(str, YB_TOP, yspec, &xt, &xerr) < 0)
* if (clixon_xml_parse_string(str, YB_MODULE, yspec, &xt, &xerr) < 0)
* err;
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
* err;
* @endcode
* @see xml_parse_file
* @see xml_parse_va
* @see clixon_xml_parse_file
* @see clixon_xml_parse_va
* @note You need to free the xml parse tree after use, using xml_free()
* @note If empty on entry, a new TOP xml will be created named "top"
*/
int
xml_parse_string2(const char *str,
enum yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
clixon_xml_parse_string(const char *str,
yang_bind yb,
yang_stmt *yspec,
cxobj **xt,
cxobj **xerr)
{
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (yb == YB_MODULE && yspec == NULL){
clicon_err(OE_XML, EINVAL, "yspec is required if yb == YB_MODULE");
return -1;
}
if (*xt == NULL){
if ((*xt = xml_new(XML_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
return -1;
@ -663,57 +641,15 @@ xml_parse_string2(const char *str,
return _xml_parse(str, yb, yspec, *xt, xerr);
}
/*! Read an XML definition from string and parse it into a parse-tree
*
* @param[in] str String containing XML definition.
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xt Pointer to XML parse tree. If empty will be created.
* @retval 1 Parse OK and all yang assignment made
* @retval 0 Parse OK but yang assigment not made (or only partial)
* @retval -1 Error with clicon_err called. Includes parse error
*
* @code
* cxobj *xt = NULL;
* if (xml_parse_string(str, yspec, &xt) < 0)
* err;
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
* err;
* @endcode
* @see xml_parse_file
* @see xml_parse_va
* @note You need to free the xml parse tree after use, using xml_free()
* @note If xt is empty on entry, a new TOP xml will be created named "top" and yang binding
* assumed to be TOP
*/
int
xml_parse_string(const char *str,
yang_stmt *yspec,
cxobj **xt)
{
enum yang_bind yb = YB_PARENT;
if (xt==NULL){
clicon_err(OE_XML, EINVAL, "xt is NULL");
return -1;
}
if (*xt == NULL){
yb = YB_TOP; /* ad-hoc #1 */
if ((*xt = xml_new(XML_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
return -1;
}
else{
if (xml_spec(*xt) == NULL)
yb = YB_TOP; /* ad-hoc #2 */
}
return _xml_parse(str, yb, yspec, *xt, NULL);
}
/*! Read XML from var-arg list and parse it into xml tree
*
* Utility function using stdarg instead of static string.
* @param[in,out] xtop Top of XML parse tree. If it is NULL, top element
called 'top' will be created. Call xml_free() after use
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] yspec Yang specification, or NULL
* @param[in,out] xtop Top of XML parse tree. If it is NULL, top element
* called 'top' will be created. Call xml_free() after use
* @param[out] xerr Reason for failure (yang assignment not made)
* @param[in] format Format string for stdarg according to printf(3)
* @retval 1 Parse OK and all yang assignment made
* @retval 0 Parse OK but yang assigment not made (or only partial)
@ -721,18 +657,20 @@ xml_parse_string(const char *str,
*
* @code
* cxobj *xt = NULL;
* if (xml_parse_va(&xt, NULL, "<xml>%d</xml>", 22) < 0)
* if (clixon_xml_parse_va(YB_NONE, NULL, &xt, NULL, "<xml>%d</xml>", 22) < 0)
* err;
* xml_free(xt);
* @endcode
* @see xml_parse_string
* @see xml_parse_file
* @note If vararg list is empty, consider using xml_parse_string()
* @see clixon_xml_parse_string
* @see clixon_xml_parse_file
* @note If vararg list is empty, consider using clixon_xml_parse_string()
*/
int
xml_parse_va(cxobj **xtop,
yang_stmt *yspec,
const char *format, ...)
clixon_xml_parse_va(yang_bind yb,
yang_stmt *yspec,
cxobj **xtop,
cxobj **xerr,
const char *format, ...)
{
int retval = -1;
va_list args;
@ -750,104 +688,10 @@ xml_parse_va(cxobj **xtop,
va_start(args, format);
len = vsnprintf(str, len, format, args) + 1;
va_end(args);
retval = xml_parse_string(str, yspec, xtop); /* xml_parse_string2 */
retval = clixon_xml_parse_string(str, yb, yspec, xtop, xerr);
done:
if (str)
free(str);
return retval;
}
#ifdef NOTUSED
/*! Generic parse function for xml values
* @param[in] xb xml tree body node, ie containing a value to be parsed
* @param[in] type Type of value to be parsed in value
* @param[out] cvp CLIgen variable containing the parsed value
* @note free cv with cv_free after use.
* @see xml_body_int32 etc, for type-specific parse functions
* @note range check failure returns 0
*/
static int
xml_body_parse(cxobj *xb,
enum cv_type type,
cg_var **cvp)
{
int retval = -1;
cg_var *cv = NULL;
int cvret;
char *bstr;
char *reason = NULL;
if ((bstr = xml_body(xb)) == NULL){
clicon_err(OE_XML, 0, "No body found");
goto done;
}
if ((cv = cv_new(type)) == NULL){
clicon_err(OE_XML, errno, "cv_new");
goto done;
}
if ((cvret = cv_parse1(bstr, cv, &reason)) < 0){
clicon_err(OE_XML, errno, "cv_parse");
goto done;
}
if (cvret == 0){ /* parsing failed */
clicon_err(OE_XML, errno, "Parsing CV: %s", reason);
if (reason)
free(reason);
}
*cvp = cv;
retval = 0;
done:
if (retval < 0 && cv != NULL)
cv_free(cv);
return retval;
}
/*! Parse an xml body as int32
* The real parsing functions are in the cligen code
* @param[in] xb xml tree body node, ie containing a value to be parsed
* @param[out] val Value after parsing
* @retval 0 OK, parsed value in 'val'
* @retval -1 Error, one of: body not found, parse error,
* alloc error.
* @note extend to all other cligen var types and generalize
* @note use yang type info?
* @note range check failure returns 0
*/
int
xml_body_int32(cxobj *xb,
int32_t *val)
{
cg_var *cv = NULL;
if (xml_body_parse(xb, CGV_INT32, &cv) < 0)
return -1;
*val = cv_int32_get(cv);
cv_free(cv);
return 0;
}
/*! Parse an xml body as uint32
* The real parsing functions are in the cligen code
* @param[in] xb xml tree body node, ie containing a value to be parsed
* @param[out] val Value after parsing
* @retval 0 OK, parsed value in 'val'
* @retval -1 Error, one of: body not found, parse error,
* alloc error.
* @note extend to all other cligen var types and generalize
* @note use yang type info?
* @note range check failure returns 0
*/
int
xml_body_uint32(cxobj *xb,
uint32_t *val)
{
cg_var *cv = NULL;
if (xml_body_parse(xb, CGV_UINT32, &cv) < 0)
return -1;
*val = cv_uint32_get(cv);
cv_free(cv);
return 0;
}
#endif /* NOTUSED */

View file

@ -1201,18 +1201,17 @@ strip_whitespace(cxobj *xt)
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
* @retval -1 Error
* @code
* if (xml_bind_yang(x, yspec, NULL) < 0)
* if (xml_bind_yang(x, YB_MODULE, yspec, NULL) < 0)
* err;
* @endcode
* @note For subs to anyxml nodes will not have spec set
* There are several functions in the API family
* @see xml_bind_yang_rpc for incoming rpc
* @see xml_bind_yang_parent Not top-level and parent is properly yang populated
* @see xml_bind_yang0 If the calling xml object should also be populated
* @see xml_bind_yang0_parent
*/
int
xml_bind_yang(cxobj *xt,
yang_bind yb,
yang_stmt *yspec,
cxobj **xerr)
{
@ -1224,33 +1223,7 @@ xml_bind_yang(cxobj *xt,
strip_whitespace(xt);
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
if ((ret = xml_bind_yang0(xc, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
}
retval = (failed==0) ? 1 : 0;
done:
return retval;
}
/*! Find yang spec association of tree of XML nodes
*
* Populate xt:s children outgoing from that xt is populated
*/
int
xml_bind_yang_parent(cxobj *xt,
cxobj **xerr)
{
int retval = -1;
cxobj *xc; /* xml child */
int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
strip_whitespace(xt);
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
if ((ret = xml_bind_yang0_parent(xc, xerr)) < 0)
if ((ret = xml_bind_yang0(xc, yb, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
@ -1263,15 +1236,22 @@ xml_bind_yang_parent(cxobj *xt,
fail:
retval = 0;
goto done;
}
/*! Find yang spec association of tree of XML nodes
*
* @param[in] xt XML tree node
* @param[in] yb How to bind yang to XML top-level when parsing
* @param[in] yspec Yang spec
* @param[out] xerr Reason for failure, or NULL
* @retval 1 OK yang assignment made
* @retval 0 Partial or no yang assigment made (at least one failed) and xerr set
* @retval -1 Error
* Populate xt as top-level node
*/
int
xml_bind_yang0(cxobj *xt,
yang_bind yb,
yang_stmt *yspec,
cxobj **xerr)
{
@ -1280,49 +1260,26 @@ xml_bind_yang0(cxobj *xt,
int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
if ((ret = populate_self_top(xt, yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
strip_whitespace(xt);
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
if ((ret = xml_bind_yang0_parent(xc, xerr)) < 0)
switch (yb){
case YB_MODULE:
if ((ret = populate_self_top(xt, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
}
if (failed)
goto fail;
retval = 1;
done:
return retval;
fail:
retval = 0;
goto done;
}
/*! Find yang spec association of tree of XML nodes
*
* Populate xt as if xt:s parent is populated
*/
int
xml_bind_yang0_parent(cxobj *xt,
cxobj **xerr)
{
int retval = -1;
cxobj *xc; /* xml child */
int ret;
int failed = 0; /* we continue loop after failure, should we stop at fail?`*/
if ((ret = populate_self_parent(xt, xerr)) < 0)
break;
case YB_PARENT:
if ((ret = populate_self_parent(xt, xerr)) < 0)
goto done;
break;
default:
clicon_err(OE_XML, EINVAL, "Invalid yang binding: %d", yb);
goto done;
break;
}
if (ret == 0)
goto fail;
strip_whitespace(xt);
xc = NULL; /* Apply on children */
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
if ((ret = xml_bind_yang0_parent(xc, xerr)) < 0)
if ((ret = xml_bind_yang0(xc, YB_PARENT, yspec, xerr)) < 0)
goto done;
if (ret == 0)
failed++;
@ -1356,8 +1313,8 @@ xml_bind_yang0_parent(cxobj *xt,
*/
int
xml_bind_yang_rpc(cxobj *xrpc,
yang_stmt *yspec,
cxobj **xerr)
yang_stmt *yspec,
cxobj **xerr)
{
int retval = -1;
yang_stmt *yrpc = NULL; /* yang node */
@ -1385,7 +1342,7 @@ xml_bind_yang_rpc(cxobj *xrpc,
* recursive population to work. Therefore, assign input yang
* to rpc level although not 100% intuitive */
xml_spec_set(x, yi);
if ((ret = xml_bind_yang_parent(x, xerr)) < 0)
if ((ret = xml_bind_yang(x, YB_PARENT, NULL, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;
@ -1452,7 +1409,7 @@ xml_bind_yang_rpc_reply(cxobj *xrpc,
}
if (yo != NULL){
xml_spec_set(xrpc, yo);
if ((ret = xml_bind_yang(xrpc, yspec, xerr)) < 0)
if ((ret = xml_bind_yang(xrpc, YB_MODULE, yspec, xerr)) < 0)
goto done;
if (ret == 0)
goto fail;

View file

@ -100,8 +100,10 @@ xml_cv_cache(cxobj *x,
body="";
if ((cv = xml_cv(x)) != NULL)
goto ok;
if ((y = xml_spec(x)) == NULL)
goto ok;
if ((y = xml_spec(x)) == NULL){
clicon_err(OE_XML, EFAULT, "Yang binding missing for xml symbol %s, body:%s", xml_name(x), body);
goto done;
}
if (yang_type_get(y, NULL, &yrestype, &options, NULL, NULL, NULL, &fraction) < 0)
goto done;
yang2cv_type(yang_argument_get(yrestype), &cvtype);
@ -195,8 +197,8 @@ xml_cmp(cxobj *x1,
char *b1;
char *b2;
char *keyname;
cg_var *cv1;
cg_var *cv2;
cg_var *cv1 = NULL;
cg_var *cv2 = NULL;
int nr1 = 0;
int nr2 = 0;
cxobj *x1b;
@ -1324,7 +1326,7 @@ xml_find_index_yang(cxobj *xp,
if (revert)
goto revert;
#endif
if (xml_parse_string(cbuf_get(cb), yc, &xc) < 0)
if (clixon_xml_parse_string(cbuf_get(cb), YB_NONE, NULL, &xc, NULL) < 0)
goto done;
if (xml_rootchild(xc, 0, &xc) < 0)
goto done;

View file

@ -327,7 +327,7 @@ yang_modules_state_get(clicon_handle h,
/* Parse cb, x is on the form: <top><modules-state>...
* Note, list is not sorted since it is state (should not be)
*/
if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
if (clixon_xml_parse_string(cbuf_get(cb), YB_MODULE, yspec, &x, NULL) < 0){
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
goto done;
goto fail;