- New netconf-specific uint32 parse functions
- Added failure handling to xpath traverse_canonical - Started pagination cli code
This commit is contained in:
parent
390b0886ed
commit
a046306270
16 changed files with 410 additions and 241 deletions
|
|
@ -1841,3 +1841,111 @@ clixon_netconf_internal_error(cxobj *xerr,
|
|||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Parse string into uint32 and return netconf bad-element msg on error
|
||||
*
|
||||
* @param[in] name Name of attribute (for error msg)
|
||||
* @param[in] valstr Value string to be parsed
|
||||
* @param[in] defaultstr If given, default string which is accepted and sets value to 0
|
||||
* @param[in,out] cbret Output buffer for internal RPC message if invalid
|
||||
* @param[out] value Value if valid
|
||||
* @retval -1 Error
|
||||
* @retval 0 Invalid, cbret set
|
||||
* @retval 1 OK
|
||||
* @code
|
||||
* char *name = "a";
|
||||
* char *valstr = "322";
|
||||
* char *defaultstr = "unbounded";
|
||||
* cbuf *cbret = cbuf_new();
|
||||
* uint32_t value = 0;
|
||||
*
|
||||
* if ((ret = netconf_parse_uint32(name, valstr, defaultstr, cbret, &value) < 0)
|
||||
* goto err;
|
||||
* if (ret == 0)
|
||||
* // cbret contains netconf errmsg
|
||||
* else
|
||||
* // value contains uin32
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
netconf_parse_uint32(char *name,
|
||||
char *valstr,
|
||||
char *defaultstr,
|
||||
uint32_t defaultvalue,
|
||||
cbuf *cbret,
|
||||
uint32_t *value)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char *reason = NULL;
|
||||
|
||||
if (valstr == NULL){
|
||||
clicon_err(OE_NETCONF, EINVAL, "valstr is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (defaultstr && strcmp(valstr, defaultstr) == 0)
|
||||
*value = defaultvalue;
|
||||
else {
|
||||
if ((ret = parse_uint32(valstr, value, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_uint32");
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0){
|
||||
if (netconf_bad_element(cbret, "application",
|
||||
name, "Unrecognized value") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (reason)
|
||||
free(reason);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Parse string into uint32 and return netconf bad-element msg on error xml variant
|
||||
* @see netconf_parse_uint32_xml
|
||||
*/
|
||||
int
|
||||
netconf_parse_uint32_xml(char *name,
|
||||
char *valstr,
|
||||
char *defaultstr,
|
||||
uint32_t defaultvalue,
|
||||
cxobj **xerr,
|
||||
uint32_t *value)
|
||||
{
|
||||
int retval = -1;
|
||||
int ret;
|
||||
char *reason = NULL;
|
||||
|
||||
if (valstr == NULL){
|
||||
clicon_err(OE_NETCONF, EINVAL, "valstr is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (defaultstr && strcmp(valstr, defaultstr) == 0)
|
||||
*value = defaultvalue;
|
||||
else {
|
||||
if ((ret = parse_uint32(valstr, value, &reason)) < 0){
|
||||
clicon_err(OE_XML, errno, "parse_uint32");
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0){
|
||||
if (netconf_bad_element_xml(xerr, "application",
|
||||
name, "Unrecognized value") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (reason)
|
||||
free(reason);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL;
|
||||
cxobj *xd;
|
||||
cxobj *xd = NULL;
|
||||
uint32_t session_id;
|
||||
int ret;
|
||||
yang_stmt *yspec;
|
||||
|
|
@ -488,7 +488,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (xt){
|
||||
if (xt && xd){
|
||||
if (xml_rm(xd) < 0)
|
||||
goto done;
|
||||
*xt = xd;
|
||||
|
|
@ -799,7 +799,7 @@ clicon_rpc_get(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL;
|
||||
cxobj *xd;
|
||||
cxobj *xd = NULL;
|
||||
char *username;
|
||||
uint32_t session_id;
|
||||
int ret;
|
||||
|
|
@ -860,7 +860,7 @@ clicon_rpc_get(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (xt){
|
||||
if (xt && xd){
|
||||
if (xml_rm(xd) < 0)
|
||||
goto done;
|
||||
*xt = xd;
|
||||
|
|
@ -882,14 +882,12 @@ clicon_rpc_get(clicon_handle h,
|
|||
/*! Get database configuration and state data collection
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] xpath To identify a list/leaf-list
|
||||
* @param[in] yli Yang-stmt of list/leaf-list of collection, if given yang populate return
|
||||
* xt and make sanity check
|
||||
* @param[in] namespace Namespace associated w xpath
|
||||
* @param[in] nsc Namespace context for filter
|
||||
* @param[in] content Clixon extension: all, config, noconfig. -1 means all
|
||||
* @param[in] depth Nr of XML levels to get, -1 is all, 0 is none
|
||||
* @param[in] limit Collection/clixon extension
|
||||
* @param[in] offset Collection/clixon extension
|
||||
* @param[in] offset uint32, 0 means none
|
||||
* @param[in] limit uint32, 0 means unbounded
|
||||
* @param[in] direction Collection/clixon extension
|
||||
* @param[in] sort Collection/clixon extension
|
||||
* @param[in] where Collection/clixon extension
|
||||
|
|
@ -905,12 +903,11 @@ int
|
|||
clicon_rpc_get_pageable_list(clicon_handle h,
|
||||
char *datastore,
|
||||
char *xpath,
|
||||
yang_stmt *yli,
|
||||
cvec *nsc, /* namespace context for xpath */
|
||||
netconf_content content,
|
||||
int32_t depth,
|
||||
char *limit,
|
||||
char *offset,
|
||||
uint32_t offset,
|
||||
uint32_t limit,
|
||||
char *direction,
|
||||
char *sort,
|
||||
char *where,
|
||||
|
|
@ -921,8 +918,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
|
|||
cbuf *cb = NULL;
|
||||
cxobj *xret = NULL;
|
||||
cxobj *xerr = NULL;
|
||||
cxobj *xr; /* return msg */
|
||||
cxobj *xd; /* return data */
|
||||
cxobj *xd = NULL; /* return data */
|
||||
char *username;
|
||||
uint32_t session_id;
|
||||
int ret;
|
||||
|
|
@ -963,10 +959,10 @@ clicon_rpc_get_pageable_list(clicon_handle h,
|
|||
}
|
||||
/* Explicit use of list-pagination */
|
||||
cprintf(cb, "<cp:list-pagination>true</cp:list-pagination>");
|
||||
if (limit)
|
||||
cprintf(cb, "<cp:limit>%s</cp:limit>", limit);
|
||||
if (offset)
|
||||
cprintf(cb, "<cp:offset>%s</cp:offset>", offset);
|
||||
if (offset != 0)
|
||||
cprintf(cb, "<cp:offset>%u</cp:offset>", offset);
|
||||
if (limit != 0)
|
||||
cprintf(cb, "<cp:limit>%u</cp:limit>", limit);
|
||||
if (direction)
|
||||
cprintf(cb, "<cp:direction>%s</cp:direction>", direction);
|
||||
if (sort)
|
||||
|
|
@ -980,8 +976,8 @@ clicon_rpc_get_pageable_list(clicon_handle h,
|
|||
if (clicon_rpc_msg(h, msg, &xret) < 0)
|
||||
goto done;
|
||||
/* Send xml error back: first check error, then ok */
|
||||
if ((xr = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL)
|
||||
xr = xml_parent(xr); /* point to rpc-reply */
|
||||
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, NULL, "/rpc-reply/data")) == NULL){
|
||||
if ((xd = xml_new(NETCONF_OUTPUT_DATA, NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1001,7 +997,7 @@ clicon_rpc_get_pageable_list(clicon_handle h,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (xt){
|
||||
if (xt && xd){
|
||||
if (xml_rm(xd) < 0)
|
||||
goto done;
|
||||
*xt = xd;
|
||||
|
|
|
|||
|
|
@ -930,37 +930,64 @@ xpath_vec_bool(cxobj *xcur,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
|
||||
*
|
||||
* @param[in] xs Parsed xpath - xpath_tree
|
||||
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
||||
* @param[in] nsc0 Input namespace context
|
||||
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
||||
* @param[out] reason Error reason if result is 0 - failed
|
||||
* @retval 1 OK with nsc1 containing the transformed nsc
|
||||
* @retval 0 XPath failure with reason set to why
|
||||
* @retval -1 Fatal Error
|
||||
*/
|
||||
static int
|
||||
traverse_canonical(xpath_tree *xs,
|
||||
yang_stmt *yspec,
|
||||
cvec *nsc0,
|
||||
cvec *nsc1)
|
||||
cvec *nsc1,
|
||||
cbuf **reason)
|
||||
{
|
||||
int retval = -1;
|
||||
char *prefix0;
|
||||
char *prefix1;
|
||||
char *namespace;
|
||||
yang_stmt *ymod;
|
||||
cbuf *cb = NULL;
|
||||
int ret;
|
||||
|
||||
switch (xs->xs_type){
|
||||
case XP_NODE: /* s0 is namespace prefix, s1 is name */
|
||||
prefix0 = xs->xs_s0;
|
||||
if ((namespace = xml_nsctx_get(nsc0, prefix0)) == NULL){
|
||||
clicon_err(OE_XML, ENOENT, "No namespace found for prefix: %s",
|
||||
prefix0);
|
||||
goto done;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "No namespace found for prefix: %s", prefix0);
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
}
|
||||
if ((ymod = yang_find_module_by_namespace(yspec, namespace)) == NULL){
|
||||
clicon_err(OE_XML, ENOENT, "No modules found for namespace: %s",
|
||||
namespace);
|
||||
goto done;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "No modules found for namespace: %s", namespace);
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
}
|
||||
if ((prefix1 = yang_find_myprefix(ymod)) == NULL){
|
||||
clicon_err(OE_XML, ENOENT, "No prefix found in module: %s",
|
||||
yang_argument_get(ymod));
|
||||
goto done;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "No prefix found in module: %s", yang_argument_get(ymod));
|
||||
if (reason)
|
||||
*reason = cb;
|
||||
goto failed;
|
||||
}
|
||||
if (xml_nsctx_get(nsc1, prefix1) == NULL)
|
||||
if (xml_nsctx_add(nsc1, prefix1, namespace) < 0)
|
||||
|
|
@ -977,25 +1004,36 @@ traverse_canonical(xpath_tree *xs,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (xs->xs_c0)
|
||||
if (traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1) < 0)
|
||||
if (xs->xs_c0){
|
||||
if ((ret = traverse_canonical(xs->xs_c0, yspec, nsc0, nsc1, reason)) < 0)
|
||||
goto done;
|
||||
if (xs->xs_c1)
|
||||
if (traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1) < 0)
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
}
|
||||
if (xs->xs_c1){
|
||||
if ((ret = traverse_canonical(xs->xs_c1, yspec, nsc0, nsc1, reason)) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
failed:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Translate an xpath/nsc pair to a "canonical" form using yang prefixes
|
||||
*
|
||||
* @param[in] xpath0 Input xpath
|
||||
* @param[in] nsc0 Input namespace context
|
||||
* @param[in] yspec Yang spec containing all modules, associated with namespaces
|
||||
* @param[out] xpath1 Output xpath. Free after use with free
|
||||
* @param[out] nsc1 Output namespace context. Free after use with xml_nsctx_free
|
||||
* @retval 0 OK, xpath1 and nsc1 allocated
|
||||
* @retval -1 Error
|
||||
* @retval 1 OK, xpath1 and nsc1 allocated
|
||||
* @retval 0 XPath failure with reason set to why
|
||||
* @retval -1 Fatal Error
|
||||
* Example:
|
||||
* Module A has prefix a and namespace urn:example:a and symbols x
|
||||
* Module B with prefix b and namespace urn:example:b and symbols y
|
||||
|
|
@ -1008,7 +1046,8 @@ traverse_canonical(xpath_tree *xs,
|
|||
* @code
|
||||
* char *xpath1 = NULL;
|
||||
* cvec *nsc1 = NULL;
|
||||
* if (xpath2canonical(xpath0, nsc0, yspec, &xpath1, &nsc1) < 0)
|
||||
* cbuf *reason = NULL;
|
||||
* if ((ret = xpath2canonical(xpath0, nsc0, yspec, &xpath1, &nsc1, &reason)) < 0)
|
||||
* err;
|
||||
* ...
|
||||
* if (xpath1) free(xpath1);
|
||||
|
|
@ -1017,15 +1056,17 @@ traverse_canonical(xpath_tree *xs,
|
|||
*/
|
||||
int
|
||||
xpath2canonical(const char *xpath0,
|
||||
cvec *nsc0,
|
||||
yang_stmt *yspec,
|
||||
char **xpath1,
|
||||
cvec **nsc1p)
|
||||
cvec *nsc0,
|
||||
yang_stmt *yspec,
|
||||
char **xpath1,
|
||||
cvec **nsc1p,
|
||||
cbuf **cbreason)
|
||||
{
|
||||
int retval = -1;
|
||||
xpath_tree *xpt = NULL;
|
||||
cvec *nsc1 = NULL;
|
||||
cbuf *xcb = NULL;
|
||||
int ret;
|
||||
|
||||
/* Parse input xpath into an xpath-tree */
|
||||
if (xpath_parse(xpath0, &xpt) < 0)
|
||||
|
|
@ -1036,8 +1077,10 @@ xpath2canonical(const char *xpath0,
|
|||
/* Traverse tree to find prefixes, transform them to canonical form and
|
||||
* create a canonical network namespace
|
||||
*/
|
||||
if (traverse_canonical(xpt, yspec, nsc0, nsc1) < 0)
|
||||
if ((ret = traverse_canonical(xpt, yspec, nsc0, nsc1, cbreason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto failed;
|
||||
/* Print tree with new prefixes */
|
||||
if ((xcb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
|
|
@ -1055,7 +1098,7 @@ xpath2canonical(const char *xpath0,
|
|||
*nsc1p = nsc1;
|
||||
nsc1 = NULL;
|
||||
}
|
||||
retval = 0;
|
||||
retval = 1;
|
||||
done:
|
||||
if (xcb)
|
||||
cbuf_free(xcb);
|
||||
|
|
@ -1064,6 +1107,9 @@ xpath2canonical(const char *xpath0,
|
|||
if (xpt)
|
||||
xpath_tree_free(xpt);
|
||||
return retval;
|
||||
failed:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Return a count(xpath)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue