Merge branch 'master' of https://github.com/clicon/clixon
This commit is contained in:
commit
a529546c88
45 changed files with 1913 additions and 708 deletions
|
|
@ -878,7 +878,7 @@ nacm_access_pre(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
else if (strcmp(mode, "internal")==0){
|
||||
if (xmldb_get(h, "running", "nacm", 0, &xnacm0) < 0)
|
||||
if (xmldb_get(h, "running", "nacm", 0, &xnacm0, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -889,6 +889,36 @@ clicon_username_set(clicon_handle h,
|
|||
return hash_add(cdat, "username", username, strlen(username)+1)==NULL?-1:0;
|
||||
}
|
||||
|
||||
/*! Get backend daemon startup status
|
||||
* @param[in] h Clicon handle
|
||||
* @retval status Startup status
|
||||
*/
|
||||
enum startup_status
|
||||
clicon_startup_status_get(clicon_handle h)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
void *p;
|
||||
|
||||
if ((p = hash_value(cdat, "startup_status", NULL)) != NULL)
|
||||
return *(enum startup_status *)p;
|
||||
return STARTUP_ERR;
|
||||
}
|
||||
|
||||
/*! Set backend daemon startup status
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] status Startup status
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error (when setting value)
|
||||
*/
|
||||
int
|
||||
clicon_startup_status_set(clicon_handle h,
|
||||
enum startup_status status)
|
||||
{
|
||||
clicon_hash_t *cdat = clicon_data(h);
|
||||
if (hash_add(cdat, "startup_status", &status, sizeof(status))==NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get socket fd (ie backend server socket / restconf fcgx socket)
|
||||
* @param[in] h Clicon handle
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ plugin_load_one(clicon_handle h,
|
|||
clicon_err_reset();
|
||||
if ((api = initfn(h)) == NULL) {
|
||||
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
|
||||
clicon_log(LOG_WARNING, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||
clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
|
||||
dlclose(handle);
|
||||
}
|
||||
else{
|
||||
|
|
|
|||
|
|
@ -133,10 +133,13 @@ struct xml{
|
|||
/*
|
||||
* Variables
|
||||
*/
|
||||
/* Iterate through modules to find the matching datanode
|
||||
/* If set to 1 which is default, strict namespace checking of XML is made.
|
||||
* If set to 0, "loose" namespace semantics is applied.
|
||||
* This means: iterate through all yang modules to find matching datanode
|
||||
* or rpc if no xmlns attribute specifies namespace.
|
||||
* This is loose semantics of finding namespaces.
|
||||
* And it is wrong, but is the way Clixon originally was written."
|
||||
* This is _wrong_, but is the way Clixon originally was written, and some
|
||||
* code still relies on it.
|
||||
* This, of course, should change.
|
||||
* @see CLICON_XML_NS_STRICT clixon configure option
|
||||
*/
|
||||
int _CLICON_XML_NS_STRICT = 1;
|
||||
|
|
@ -1129,6 +1132,7 @@ xml_find_type_value(cxobj *xt,
|
|||
* @code
|
||||
* cxobj *x = xml_find_type(x, "prefix", "name", CX_ATTR);
|
||||
* @endcode
|
||||
* @see xml_find which finds any child given name
|
||||
* @see xml_find_value where a body can be found as well
|
||||
*/
|
||||
cxobj *
|
||||
|
|
@ -1708,7 +1712,7 @@ xml_parse_file(int fd,
|
|||
* cxobj *xt = NULL;
|
||||
* if (xml_parse_string(str, yspec, &xt) < 0)
|
||||
* err;
|
||||
* if (xml_root_child(xt, 0, &xt) < 0) # If you want to remove TOP
|
||||
* if (xml_rootchild(xt, 0, &xt) < 0) # If you want to remove TOP
|
||||
* err;
|
||||
* @endcode
|
||||
* @see xml_parse_file
|
||||
|
|
@ -1778,7 +1782,11 @@ xml_parse_va(cxobj **xtop,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Copy single xml node frm x0 to x1 without copying children
|
||||
/*! Copy single xml node from x0 to x1 without copying children
|
||||
* @param[in] x0 Source XML tree
|
||||
* @param[in] x1 Destination XML tree (must exist)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
xml_copy_one(cxobj *x0,
|
||||
|
|
@ -1806,6 +1814,10 @@ xml_copy_one(cxobj *x0,
|
|||
*
|
||||
* x1 should be a created placeholder. If x1 is non-empty,
|
||||
* the copied tree is appended to the existing tree.
|
||||
* @param[in] x0 Source XML tree
|
||||
* @param[in] x1 Destination XML tree (must exist)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* x1 = xml_new("new", xparent, NULL);
|
||||
* if (xml_copy(x0, x1) < 0)
|
||||
|
|
|
|||
|
|
@ -325,11 +325,12 @@ xmldb_setopt(clicon_handle h,
|
|||
* @param[in] xpath String with XPATH syntax. or NULL for all
|
||||
* @param[in] config If set only configuration data, else also state
|
||||
* @param[out] xret Single return XML tree. Free with xml_free()
|
||||
* @param[out] xms If set, return modules-state differences
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @code
|
||||
* cxobj *xt;
|
||||
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", 1, &xt) < 0)
|
||||
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", 1, &xt, NULL) < 0)
|
||||
* err;
|
||||
* xml_free(xt);
|
||||
* @endcode
|
||||
|
|
@ -341,7 +342,8 @@ xmldb_get(clicon_handle h,
|
|||
const char *db,
|
||||
char *xpath,
|
||||
int config,
|
||||
cxobj **xret)
|
||||
cxobj **xret,
|
||||
cxobj **xms)
|
||||
{
|
||||
int retval = -1;
|
||||
xmldb_handle xh;
|
||||
|
|
@ -359,7 +361,7 @@ xmldb_get(clicon_handle h,
|
|||
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
|
||||
goto done;
|
||||
}
|
||||
retval = xa->xa_get_fn(xh, db, xpath, config, xret);
|
||||
retval = xa->xa_get_fn(xh, db, xpath, config, xret, xms);
|
||||
#if DEBUG
|
||||
if (retval == 0) {
|
||||
cbuf *cb = cbuf_new();
|
||||
|
|
|
|||
|
|
@ -228,8 +228,10 @@ xml2cli(FILE *f,
|
|||
if (ys->ys_keyword == Y_LIST){
|
||||
if ((match = yang_key_match((yang_node*)ys, xml_name(xe))) < 0)
|
||||
goto done;
|
||||
if (match)
|
||||
continue;
|
||||
if (match){
|
||||
fprintf(f, "%s\n", cbuf_get(cbpre));
|
||||
continue; /* Not key itself */
|
||||
}
|
||||
}
|
||||
if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0)
|
||||
goto done;
|
||||
|
|
@ -1135,8 +1137,8 @@ xml_diff1(yang_stmt *ys,
|
|||
|
||||
/*! Compute differences between two xml trees
|
||||
* @param[in] yspec Yang specification
|
||||
* @param[in] x1 First XML tree
|
||||
* @param[in] x2 Second XML tree
|
||||
* @param[in] x1 First XML tree
|
||||
* @param[in] x2 Second XML tree
|
||||
* @param[out] first Pointervector to XML nodes existing in only first tree
|
||||
* @param[out] firstlen Length of first vector
|
||||
* @param[out] second Pointervector to XML nodes existing in only second tree
|
||||
|
|
@ -1572,7 +1574,7 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
cxobj *xprev;
|
||||
|
||||
x = NULL;
|
||||
xprev = x = NULL;
|
||||
xprev = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
if (xml_flag(x, flag) == test?flag:0){ /* Pass test means purge */
|
||||
if (xml_purge(x) < 0)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
void
|
||||
clixon_xml_parseerror(void *_ya, char *s)
|
||||
{
|
||||
clicon_err(OE_XML, 0, "xml_parse: line %d: %s: at or before: %s",
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "xml_parse: line %d: %s: at or before: %s",
|
||||
_YA->ya_linenum, s, clixon_xml_parsetext);
|
||||
return;
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ xml_parse_version(struct xml_parse_yacc_arg *ya,
|
|||
char *ver)
|
||||
{
|
||||
if(strcmp(ver, "1.0")){
|
||||
clicon_err(OE_XML, errno, "Wrong XML version %s expected 1.0", ver);
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Wrong XML version %s expected 1.0", ver);
|
||||
free(ver);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -224,12 +224,12 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
|
|||
cxobj *xc;
|
||||
|
||||
if (strcmp(xml_name(x), name)){
|
||||
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s vs %s",
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "XML parse sanity check failed: %s vs %s",
|
||||
xml_name(x), name);
|
||||
goto done;
|
||||
}
|
||||
if (xml_prefix(x)!=NULL){
|
||||
clicon_err(OE_XML, 0, "XML parse sanity check failed: %s:%s vs %s",
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "XML parse sanity check failed: %s:%s vs %s",
|
||||
xml_prefix(x), xml_name(x), name);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -267,7 +267,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
|||
cxobj *xc;
|
||||
|
||||
if (strcmp(xml_name(x), name)){
|
||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s:%s vs %s:%s",
|
||||
xml_prefix(x),
|
||||
xml_name(x),
|
||||
namespace,
|
||||
|
|
@ -276,7 +276,7 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
|||
}
|
||||
if (xml_prefix(x)==NULL ||
|
||||
strcmp(xml_prefix(x), namespace)){
|
||||
clicon_err(OE_XML, 0, "Sanity check failed: %s:%s vs %s:%s",
|
||||
clicon_err(OE_XML, XMLPARSE_ERRNO, "Sanity check failed: %s:%s vs %s:%s",
|
||||
xml_prefix(x),
|
||||
xml_name(x),
|
||||
namespace,
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ modules_state_cache_set(clicon_handle h,
|
|||
* @param[in] h Clicon handle
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] xpath XML Xpath
|
||||
* @param[in] brief Just name,revision and uri (no cache)
|
||||
* @param[in,out] xret Existing XML tree, merge x into this
|
||||
* @retval -1 Error (fatal)
|
||||
* @retval 0 OK
|
||||
|
|
@ -212,10 +213,149 @@ x +--ro namespace inet:uri
|
|||
+--ro schema? inet:uri
|
||||
* @see netconf_create_hello
|
||||
*/
|
||||
#if 1
|
||||
/*! Actually build the yang modules state XML tree
|
||||
*/
|
||||
static int
|
||||
yms_build(clicon_handle h,
|
||||
yang_spec *yspec,
|
||||
char *msid,
|
||||
int brief,
|
||||
cbuf *cb)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ylib = NULL; /* ietf-yang-library */
|
||||
char *module = "ietf-yang-library";
|
||||
yang_stmt *ys;
|
||||
yang_stmt *yc;
|
||||
yang_stmt *ymod; /* generic module */
|
||||
yang_stmt *yns = NULL; /* namespace */
|
||||
|
||||
if ((ylib = yang_find((yang_node*)yspec, Y_MODULE, module)) == NULL &&
|
||||
(ylib = yang_find((yang_node*)yspec, Y_SUBMODULE, module)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "%s not found", module);
|
||||
goto done;
|
||||
}
|
||||
if ((yns = yang_find((yang_node*)ylib, Y_NAMESPACE, NULL)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "%s yang namespace not found", module);
|
||||
goto done;
|
||||
}
|
||||
|
||||
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
|
||||
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
|
||||
|
||||
ymod = NULL;
|
||||
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
|
||||
if (ymod->ys_keyword != Y_MODULE &&
|
||||
ymod->ys_keyword != Y_SUBMODULE)
|
||||
continue;
|
||||
cprintf(cb,"<module>");
|
||||
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
|
||||
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
|
||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<revision></revision>");
|
||||
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
|
||||
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<namespace></namespace>");
|
||||
/* This follows order in rfc 7895: feature, conformance-type,
|
||||
submodules */
|
||||
if (!brief){
|
||||
yc = NULL;
|
||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||
switch(yc->ys_keyword){
|
||||
case Y_FEATURE:
|
||||
if (yc->ys_cv && cv_bool_get(yc->ys_cv))
|
||||
cprintf(cb,"<feature>%s</feature>", yc->ys_argument);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
||||
}
|
||||
yc = NULL;
|
||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||
switch(yc->ys_keyword){
|
||||
case Y_SUBMODULE:
|
||||
cprintf(cb,"<submodule>");
|
||||
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
||||
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
|
||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<revision></revision>");
|
||||
cprintf(cb,"</submodule>");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
cprintf(cb,"</module>");
|
||||
}
|
||||
cprintf(cb,"</modules-state>");
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
yang_modules_state_get(clicon_handle h,
|
||||
yang_spec *yspec,
|
||||
char *xpath,
|
||||
int brief,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x = NULL;
|
||||
char *msid; /* modules-set-id */
|
||||
cxobj *x1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
msid = clicon_option_str(h, "CLICON_MODULE_SET_ID");
|
||||
if (!brief && modules_state_cache_get(h, msid, &x) < 0)
|
||||
goto done;
|
||||
if (x != NULL){ /* Yes a cache (but no duplicate) */
|
||||
if (xpath_first(x, "%s", xpath)){
|
||||
if ((x1 = xml_dup(x)) == NULL)
|
||||
goto done;
|
||||
x = x1;
|
||||
}
|
||||
else
|
||||
x = NULL;
|
||||
}
|
||||
else { /* No cache -> build the tree */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, 0, "clicon buffer");
|
||||
goto done;
|
||||
}
|
||||
if (yms_build(h, yspec, msid, brief, cb) < 0)
|
||||
goto done;
|
||||
if (xml_parse_string(cbuf_get(cb), yspec, &x) < 0){
|
||||
if (netconf_operation_failed_xml(xret, "protocol", clicon_err_reason)< 0)
|
||||
goto done;
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
if (!brief && modules_state_cache_set(h, x) < 0) /* move to fn above? */
|
||||
goto done;
|
||||
}
|
||||
if (x && netconf_trymerge(x, yspec, xret) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (x)
|
||||
xml_free(x);
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
int
|
||||
yang_modules_state_get(clicon_handle h,
|
||||
yang_spec *yspec,
|
||||
char *xpath,
|
||||
int brief,
|
||||
cxobj **xret)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -259,6 +399,7 @@ yang_modules_state_get(clicon_handle h,
|
|||
cprintf(cb,"<modules-state xmlns=\"%s\">", yns->ys_argument);
|
||||
cprintf(cb,"<module-set-id>%s</module-set-id>", msid);
|
||||
|
||||
<<<<<<< HEAD
|
||||
ymod = NULL;
|
||||
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
|
||||
if (ymod->ys_keyword != Y_MODULE &&
|
||||
|
|
@ -270,12 +411,33 @@ yang_modules_state_get(clicon_handle h,
|
|||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<revision></revision>");
|
||||
=======
|
||||
ymod = NULL;
|
||||
while ((ymod = yn_each((yang_node*)yspec, ymod)) != NULL) {
|
||||
if (ymod->ys_keyword != Y_MODULE &&
|
||||
ymod->ys_keyword != Y_SUBMODULE)
|
||||
continue;
|
||||
cprintf(cb,"<module>");
|
||||
cprintf(cb,"<name>%s</name>", ymod->ys_argument);
|
||||
if ((ys = yang_find((yang_node*)ymod, Y_REVISION, NULL)) != NULL)
|
||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<revision></revision>");
|
||||
if (!brief){
|
||||
>>>>>>> modules-state
|
||||
if ((ys = yang_find((yang_node*)ymod, Y_NAMESPACE, NULL)) != NULL)
|
||||
cprintf(cb,"<namespace>%s</namespace>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<namespace></namespace>");
|
||||
<<<<<<< HEAD
|
||||
/* This follows order in rfc 7895: feature, conformance-type, submodules */
|
||||
yc = NULL;
|
||||
=======
|
||||
}
|
||||
/* This follows order in rfc 7895: feature, conformance-type, submodules */
|
||||
yc = NULL;
|
||||
if (!brief)
|
||||
>>>>>>> modules-state
|
||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||
switch(yc->ys_keyword){
|
||||
case Y_FEATURE:
|
||||
|
|
@ -286,6 +448,7 @@ yang_modules_state_get(clicon_handle h,
|
|||
break;
|
||||
}
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
||||
yc = NULL;
|
||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||
|
|
@ -302,6 +465,25 @@ yang_modules_state_get(clicon_handle h,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
=======
|
||||
if (!brief)
|
||||
cprintf(cb, "<conformance-type>implement</conformance-type>");
|
||||
yc = NULL;
|
||||
if (!brief)
|
||||
while ((yc = yn_each((yang_node*)ymod, yc)) != NULL) {
|
||||
switch(yc->ys_keyword){
|
||||
case Y_SUBMODULE:
|
||||
cprintf(cb,"<submodule>");
|
||||
cprintf(cb,"<name>%s</name>", yc->ys_argument);
|
||||
if ((ys = yang_find((yang_node*)yc, Y_REVISION, NULL)) != NULL)
|
||||
cprintf(cb,"<revision>%s</revision>", ys->ys_argument);
|
||||
else
|
||||
cprintf(cb,"<revision></revision>");
|
||||
cprintf(cb,"</submodule>");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
>>>>>>> modules-state
|
||||
}
|
||||
cprintf(cb,"</module>");
|
||||
}
|
||||
|
|
@ -326,3 +508,4 @@ yang_modules_state_get(clicon_handle h,
|
|||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue