Added connect/disconnect/getopt/setopt and handle to xmldb API; Added datastore 'text'; Moved apps/dbctrl to datastore/

This commit is contained in:
Olof hagsand 2017-04-15 13:53:58 +02:00
parent 85af4342dc
commit d26a801bc0
25 changed files with 1501 additions and 912 deletions

View file

@ -71,4 +71,10 @@ clicon_hash_t *clicon_options(clicon_handle h);
/* Return internal clicon data (hash-array) given a handle.*/
clicon_hash_t *clicon_data(clicon_handle h);
/* Set or reset XMLDB storage handle */
int clicon_handle_xmldb_set(clicon_handle h, void *xh); /* ie xmldb_handle */
/* Get XMLDB storage handle */
void *clicon_handle_xmldb_get(clicon_handle h);
#endif /* _CLIXON_HANDLE_H_ */

View file

@ -34,6 +34,19 @@
#ifndef _CLIXON_XML_DB_H
#define _CLIXON_XML_DB_H
/* The XMLDB has a handle to keep connected state. To users of the API it is
* a void* but it may have structure within a specific plugin.
* The handle is independent from clicon so that (in principle) the datastore
* can work in other contexts than clicon.
* The connect API call sets the handle and disconnect resets it. In principle
* there can be several handles at one time.
*/
#if 1 /* SANITY CHECK */
typedef struct {int16_t a;} *xmldb_handle;
#else
typedef void *xmldb_handle;
#endif
/* Version of clixon datastore plugin API. */
#define XMLDB_API_VERSION 1
@ -49,40 +62,49 @@ typedef void * (plugin_init_t)(int version);
/* Type of plugin exit function */
typedef int (plugin_exit_t)(void);
/* Type of xmldb connect function */
typedef xmldb_handle (xmldb_connect_t)(void);
/* Type of xmldb disconnect function */
typedef int (xmldb_disconnect_t)(xmldb_handle xh);
/* Type of xmldb getopt function */
typedef int (xmldb_getopt_t)(xmldb_handle xh, char *optname, void **value);
/* Type of xmldb setopt function */
typedef int (xmldb_setopt_t)(xmldb_handle xh, char *optname, void *value);
/* Type of xmldb get function */
typedef int (xmldb_get_t)(clicon_handle h, char *db, char *xpath,
typedef int (xmldb_get_t)(xmldb_handle xh, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen);
/* Type of xmldb put function */
typedef int (xmldb_put_t)(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt);
/* Type of xmldb dump function */
typedef int (xmldb_dump_t)(FILE *f, char *dbfilename, char *rxkey);
typedef int (xmldb_put_t)(xmldb_handle xh, char *db, enum operation_type op,
char *api_path, cxobj *xt);
/* Type of xmldb copy function */
typedef int (xmldb_copy_t)(clicon_handle h, char *from, char *to);
typedef int (xmldb_copy_t)(xmldb_handle xh, char *from, char *to);
/* Type of xmldb lock function */
typedef int (xmldb_lock_t)(clicon_handle h, char *db, int pid);
typedef int (xmldb_lock_t)(xmldb_handle xh, char *db, int pid);
/* Type of xmldb unlock function */
typedef int (xmldb_unlock_t)(clicon_handle h, char *db, int pid);
typedef int (xmldb_unlock_t)(xmldb_handle xh, char *db, int pid);
/* Type of xmldb unlock_all function */
typedef int (xmldb_unlock_all_t)(clicon_handle h, int pid);
typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid);
/* Type of xmldb islocked function */
typedef int (xmldb_islocked_t)(clicon_handle h, char *db);
typedef int (xmldb_islocked_t)(xmldb_handle xh, char *db);
/* Type of xmldb exists function */
typedef int (xmldb_exists_t)(clicon_handle h, char *db);
typedef int (xmldb_exists_t)(xmldb_handle xh, char *db);
/* Type of xmldb delete function */
typedef int (xmldb_delete_t)(clicon_handle h, char *db);
typedef int (xmldb_delete_t)(xmldb_handle xh, char *db);
/* Type of xmldb init function */
typedef int (xmldb_init_t)(clicon_handle h, char *db);
typedef int (xmldb_init_t)(xmldb_handle xh, char *db);
/* grideye agent plugin init struct for the api */
struct xmldb_api{
@ -90,9 +112,12 @@ struct xmldb_api{
int xa_magic;
plugin_init_t *xa_plugin_init_fn; /* XMLDB_PLUGIN_INIT_FN */
plugin_exit_t *xa_plugin_exit_fn;
xmldb_connect_t *xa_connect_fn;
xmldb_disconnect_t *xa_disconnect_fn;
xmldb_getopt_t *xa_getopt_fn;
xmldb_setopt_t *xa_setopt_fn;
xmldb_get_t *xa_get_fn;
xmldb_put_t *xa_put_fn;
xmldb_dump_t *xa_dump_fn;
xmldb_copy_t *xa_copy_fn;
xmldb_lock_t *xa_lock_fn;
xmldb_unlock_t *xa_unlock_fn;
@ -105,14 +130,19 @@ struct xmldb_api{
/*
* Prototypes
* API
*/
int xmldb_plugin_load(char *filename);
int xmldb_plugin_load(clicon_handle h, char *filename);
int xmldb_plugin_unload(clicon_handle h);
int xmldb_connect(clicon_handle h);
int xmldb_disconnect(clicon_handle h);
int xmldb_getopt(clicon_handle h, char *optname, void **value);
int xmldb_setopt(clicon_handle h, char *optname, void *value);
int xmldb_get(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen);
int xmldb_put(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt);
int xmldb_dump(FILE *f, char *dbfilename, char *rxkey);
int xmldb_copy(clicon_handle h, char *from, char *to);
int xmldb_lock(clicon_handle h, char *db, int pid);
int xmldb_unlock(clicon_handle h, char *db, int pid);

View file

@ -64,5 +64,9 @@ int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
int xml_tree_prune_unmarked(cxobj *xt, int *upmark);
int xml_default(cxobj *x, void *arg);
int xml_order(cxobj *x, void *arg);
int xml_sanity(cxobj *x, void *arg);
#endif /* _CLIXON_XML_MAP_H_ */

View file

@ -58,18 +58,17 @@
#define handle(h) (assert(clicon_handle_check(h)==0),(struct clicon_handle *)(h))
/*
* clicon_handle
* Internal structire of basic handle. Also header of all other handles.
* see struct clicon_cli_handle, struct clicon_backend_handle, etc
/*! Internal structure of basic handle. Also header of all other handles.
* @note If you change here, you must also change the structs below:
* @see struct cli_handle, struct backend_handle
*/
struct clicon_handle {
int ch_magic; /* magic (HDR) */
clicon_hash_t *ch_copt; /* clicon option list (HDR) */
clicon_hash_t *ch_data; /* internal clicon data (HDR) */
void *ch_xmldb; /* XMLDB storage handle, uie xmldb_handle */
};
/*! Internal call to allocate a CLICON handle.
*
* There may be different variants of handles with some common options.
@ -166,3 +165,31 @@ clicon_data(clicon_handle h)
return ch->ch_data;
}
/*! Set or reset XMLDB storage handle
* @param[in] h Clicon handle
* @param[in] xh XMLDB storage handle. If NULL reset it
* @note Just keep note of it, dont allocate it or so.
*/
int
clicon_handle_xmldb_set(clicon_handle h,
void *xh)
{
struct clicon_handle *ch = handle(h);
ch->ch_xmldb = xh;
return 0;
}
/*! Get XMLDB storage handle
* @param[in] h Clicon handle
* @retval xh XMLDB storage handle. If not connected return NULL
*/
void *
clicon_handle_xmldb_get(clicon_handle h)
{
struct clicon_handle *ch = handle(h);
return ch->ch_xmldb;
}

View file

@ -1008,6 +1008,7 @@ FSM(char *tag,
* Note, xt will add a top-level symbol called "top" meaning that <tree../> will look as:
* <top><tree.../></tree>
* XXX: There is a potential leak here on some return values.
* XXX: What happens if endtag is different?
* May block
*/
int
@ -1023,15 +1024,16 @@ clicon_xml_parse_file(int fd,
int maxbuf = BUFLEN;
int endtaglen = strlen(endtag);
int state = 0;
int oldmaxbuf;
if (endtag == NULL){
clicon_err(OE_XML, 0, "%s: endtag required\n", __FUNCTION__);
return -1;
goto done;
}
*cx = NULL;
if ((xmlbuf = malloc(maxbuf)) == NULL){
clicon_err(OE_XML, errno, "%s: malloc", __FUNCTION__);
return -1;
goto done;
}
memset(xmlbuf, 0, maxbuf);
ptr = xmlbuf;
@ -1050,24 +1052,33 @@ clicon_xml_parse_file(int fd,
state = 0;
if ((*cx = xml_new("top", NULL)) == NULL)
break;
if (xml_parse(ptr, *cx) < 0)
if (xml_parse(ptr, *cx) < 0){
goto done;
return -1;
}
break;
}
if (len>=maxbuf-1){ /* Space: one for the null character */
int oldmaxbuf = maxbuf;
oldmaxbuf = maxbuf;
maxbuf *= 2;
if ((xmlbuf = realloc(xmlbuf, maxbuf)) == NULL){
clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__);
return -1;
goto done;
}
memset(xmlbuf+oldmaxbuf, 0, maxbuf-oldmaxbuf);
ptr = xmlbuf;
}
} /* while */
free(xmlbuf);
return (*cx)?0:-1;
retval = 0;
done:
if (retval < 0 && *cx){
free(*cx);
*cx = NULL;
}
if (xmlbuf)
free(xmlbuf);
return retval;
// return (*cx)?0:-1;
}
/*! Read an XML definition from string and parse it into a parse-tree.
@ -1461,8 +1472,12 @@ xml_body_uint32(cxobj *xb,
}
/*! Map xml operation from string to enumeration
* @param[in] xn XML node
* @param[out] op "operation" attribute may change operation
* @param[in] opstr String, eg "merge"
* @param[out] op Enumeration, eg OP_MERGE
* @code
* enum operation_type op;
* xml_operation("replace", &op)
* @endcode
*/
int
xml_operation(char *opstr,
@ -1487,6 +1502,14 @@ xml_operation(char *opstr,
return 0;
}
/*! Map xml operation from enumeration to string
* @param[in] op enumeration operation, eg OP_MERGE,...
* @retval str String, eg "merge". Static string, no free necessary
* @code
* enum operation_type op;
* xml_operation("replace", &op)
* @endcode
*/
char *
xml_operation2str(enum operation_type op)
{
@ -1510,3 +1533,4 @@ xml_operation2str(enum operation_type op)
return "none";
}
}

View file

@ -58,6 +58,8 @@
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_xml.h"
#include "clixon_yang.h"
#include "clixon_options.h"
#include "clixon_xml_db.h"
static struct xmldb_api *_xa_api = NULL;
@ -65,12 +67,13 @@ static struct xmldb_api *_xa_api = NULL;
/*! Load a specific plugin, call its init function and add it to plugins list
* If init function fails (not found, wrong version, etc) print a log and dont
* add it.
* @param[in] name Name of plugin
* @param[in] name Filename (complete path) of plugin
* @param[in] filename Actual filename with path
* @param[out] plugin Plugin data structure for invoking. Dealloc with free
*/
int
xmldb_plugin_load(char *filename)
xmldb_plugin_load(clicon_handle h,
char *filename)
{
int retval = -1;
char *dlerrcode;
@ -117,11 +120,179 @@ xmldb_plugin_load(char *filename)
goto done;
}
int
xmldb_get(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen)
/*! XXX: fixme */
int
xmldb_plugin_unload(clicon_handle h)
{
int retval = -1;
return 0;
}
/*! Connect to a datastore plugin
* @retval handle Use this handle for other API calls
* @retval NULL Error
* @note You can do several connects, and have multiple connections to the same
* datastore. Note also that the xmldb handle is hidden in the clicon
* handle, the clixon user does not need to handle it. Note also that
* typically only the backend invokes the datastore.
* XXX what args does connect have?
*/
int
xmldb_connect(clicon_handle h)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_connect_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = _xa_api->xa_connect_fn()) == NULL)
goto done;
clicon_handle_xmldb_set(h, xh);
retval = 0;
done:
return retval;
}
/*! Disconnect from a datastore plugin and deallocate handle
* @param[in] handle Disconect and deallocate from this handle
* @retval 0 OK
*/
int
xmldb_disconnect(clicon_handle h)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_disconnect_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Already disconnected from datastore plugin");
goto done;
}
if (_xa_api->xa_disconnect_fn(xh) < 0)
goto done;
clicon_handle_xmldb_set(h, NULL);
retval = 0;
done:
return retval;
}
/*! Get value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] optname Option name
* @param[out] value Pointer to Value of option
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_getopt(clicon_handle h,
char *optname,
void **value)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_getopt_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_getopt_fn(xh, optname, value);
done:
return retval;
}
/*! Set value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] optname Option name
* @param[in] value Value of option
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_setopt(clicon_handle h,
char *optname,
void *value)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_setopt_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_setopt_fn(xh, optname, value);
done:
return retval;
}
/*! Get content of database using xpath. return a set of matching sub-trees
* The function returns a minimal tree that includes all sub-trees that match
* xpath.
* @param[in] h Clicon handle
* @param[in] dbname Name of database to search in (filename including dir path
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xtop Single XML tree which xvec points to. Free with xml_free()
* @param[out] xvec Vector of xml trees. Free after use.
* @param[out] xlen Length of vector.
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xt;
* cxobj **xvec;
* size_t xlen;
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]",
* &xt, &xvec, &xlen) < 0)
* err;
* for (i=0; i<xlen; i++){
* xn = xv[i];
* ...
* }
* xml_free(xt);
* free(xvec);
* @endcode
* @note if xvec is given, then purge tree, if not return whole tree.
* @see xpath_vec
* @see xmldb_get
*/
int
xmldb_get(clicon_handle h,
char *db,
char *xpath,
cxobj **xtop,
cxobj ***xvec,
size_t *xlen)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -131,7 +302,11 @@ xmldb_get(clicon_handle h, char *db, char *xpath,
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_get_fn(h, db, xpath, xtop, xvec, xlen);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
done:
return retval;
}
@ -152,16 +327,20 @@ xmldb_get(clicon_handle h, char *db, char *xpath,
* cxobj *xt;
* if (clicon_xml_parse_str("<a>17</a>", &xt) < 0)
* err;
* if (xmldb_put(h, "running", OP_MERGE, NULL, xt) < 0)
* if (xmldb_put(xh, "running", OP_MERGE, NULL, xt) < 0)
* err;
* @endcode
* @see xmldb_put_xkey for single key
*/
int
xmldb_put(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt)
xmldb_put(clicon_handle h,
char *db,
enum operation_type op,
char *api_path,
cxobj *xt)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -171,32 +350,11 @@ xmldb_put(clicon_handle h, char *db, enum operation_type op,
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_put_fn(h, db, op, api_path, xt);
done:
return retval;
}
/*! Raw dump of database, in internal format (depends on datastore)
* @param[in] f File
* @param[in] dbfile File-name of database. This is a local file
* @param[in] pattern Key regexp, eg "^.*$"
*/
int
xmldb_dump(FILE *f,
char *dbfilename,
char *pattern)
{
int retval = -1;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
if (_xa_api->xa_dump_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_dump_fn(f, dbfilename, pattern);
retval = _xa_api->xa_put_fn(xh, db, op, api_path, xt);
done:
return retval;
}
@ -209,9 +367,12 @@ xmldb_dump(FILE *f,
* @retval 0 OK
*/
int
xmldb_copy(clicon_handle h, char *from, char *to)
xmldb_copy(clicon_handle h,
char *from,
char *to)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -221,7 +382,11 @@ xmldb_copy(clicon_handle h, char *from, char *to)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_copy_fn(h, from, to);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_copy_fn(xh, from, to);
done:
return retval;
}
@ -234,9 +399,12 @@ xmldb_copy(clicon_handle h, char *from, char *to)
* @retval 0 OK
*/
int
xmldb_lock(clicon_handle h, char *db, int pid)
xmldb_lock(clicon_handle h,
char *db,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -246,7 +414,11 @@ xmldb_lock(clicon_handle h, char *db, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_lock_fn(h, db, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_lock_fn(xh, db, pid);
done:
return retval;
}
@ -260,9 +432,12 @@ xmldb_lock(clicon_handle h, char *db, int pid)
* Assume all sanity checks have been made
*/
int
xmldb_unlock(clicon_handle h, char *db, int pid)
xmldb_unlock(clicon_handle h,
char *db,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -272,7 +447,11 @@ xmldb_unlock(clicon_handle h, char *db, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_unlock_fn(h, db, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_unlock_fn(xh, db, pid);
done:
return retval;
}
@ -284,9 +463,11 @@ xmldb_unlock(clicon_handle h, char *db, int pid)
* @retval 0 OK
*/
int
xmldb_unlock_all(clicon_handle h, int pid)
xmldb_unlock_all(clicon_handle h,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -296,7 +477,11 @@ xmldb_unlock_all(clicon_handle h, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval =_xa_api->xa_unlock_all_fn(h, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval =_xa_api->xa_unlock_all_fn(xh, pid);
done:
return retval;
}
@ -309,9 +494,11 @@ xmldb_unlock_all(clicon_handle h, int pid)
* @retval >0 Id of locker
*/
int
xmldb_islocked(clicon_handle h, char *db)
xmldb_islocked(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -321,7 +508,11 @@ xmldb_islocked(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval =_xa_api->xa_islocked_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval =_xa_api->xa_islocked_fn(xh, db);
done:
return retval;
}
@ -334,9 +525,11 @@ xmldb_islocked(clicon_handle h, char *db)
* @retval 1 Yes it exists
*/
int
xmldb_exists(clicon_handle h, char *db)
xmldb_exists(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -346,7 +539,11 @@ xmldb_exists(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_exists_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_exists_fn(xh, db);
done:
return retval;
}
@ -358,9 +555,11 @@ xmldb_exists(clicon_handle h, char *db)
* @retval 0 OK
*/
int
xmldb_delete(clicon_handle h, char *db)
xmldb_delete(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -370,21 +569,27 @@ xmldb_delete(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_delete_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_delete_fn(xh, db);
done:
return retval;
}
/*! Initialize database
/*! Initialize database. Open database for writing.
* @param[in] h Clicon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_init(clicon_handle h, char *db)
xmldb_init(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -394,7 +599,11 @@ xmldb_init(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_init_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_init_fn(xh, db);
done:
return retval;
}

View file

@ -1074,3 +1074,176 @@ xmlkeyfmt2xpath(char *xkfmt,
cbuf_free(cb);
return retval;
}
/*! Prune everything that has not been marked
* @param[in] xt XML tree with some node marked
* @param[out] upmark Set if a child (recursively) has marked set.
* The function removes all branches that does not contain a marked child
* XXX: maybe key leafs should not be purged if list is not purged?
* XXX: consider move to clicon_xml
*/
int
xml_tree_prune_unmarked(cxobj *xt,
int *upmark)
{
int retval = -1;
int submark;
int mark;
cxobj *x;
cxobj *xprev;
mark = 0;
x = NULL;
xprev = x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if (xml_flag(x, XML_FLAG_MARK)){
mark++;
xprev = x;
continue; /* mark and stop here */
}
if (xml_tree_prune_unmarked(x, &submark) < 0)
goto done;
if (submark)
mark++;
else{ /* Safe with xml_child_each if last */
if (xml_purge(x) < 0)
goto done;
x = xprev;
}
xprev = x;
}
retval = 0;
done:
if (upmark)
*upmark = mark;
return retval;
}
/*! Add default values (if not set)
* @param[in] xt XML tree with some node marked
*/
int
xml_default(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *ys;
yang_stmt *y;
int i;
cxobj *xc;
cxobj *xb;
char *str;
ys = (yang_stmt*)xml_spec(xt);
/* Check leaf defaults */
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LIST){
for (i=0; i<ys->ys_len; i++){
y = ys->ys_stmt[i];
if (y->ys_keyword != Y_LEAF)
continue;
assert(y->ys_cv);
if (!cv_flag(y->ys_cv, V_UNSET)){ /* Default value exists */
if (!xml_find(xt, y->ys_argument)){
if ((xc = xml_new_spec(y->ys_argument, xt, y)) == NULL)
goto done;
if ((xb = xml_new("body", xc)) == NULL)
goto done;
xml_type_set(xb, CX_BODY);
if ((str = cv2str_dup(y->ys_cv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
if (xml_value_set(xb, str) < 0)
goto done;
free(str);
}
}
}
}
retval = 0;
done:
return retval;
}
/*! Order XML children according to YANG
* @param[in] xt XML top of tree
*/
int
xml_order(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *y;
yang_stmt *yc;
int i;
int j0;
int j;
cxobj *xc;
cxobj *xj;
char *yname; /* yang child name */
char *xname; /* xml child name */
y = (yang_stmt*)xml_spec(xt);
j0 = 0;
/* Go through xml children and ensure they are same order as yspec children */
for (i=0; i<y->ys_len; i++){
yc = y->ys_stmt[i];
if (!yang_is_syntax(yc))
continue;
yname = yc->ys_argument;
/* First go thru xml children with same name */
for (; j0<xml_child_nr(xt); j0++){
xc = xml_child_i(xt, j0);
if (xml_type(xc) != CX_ELMNT)
continue;
xname = xml_name(xc);
if (strcmp(xname, yname))
break;
}
/* Now we have children not with same name */
for (j=j0; j<xml_child_nr(xt); j++){
xc = xml_child_i(xt, j);
if (xml_type(xc) != CX_ELMNT)
continue;
xname = xml_name(xc);
if (strcmp(xname, yname))
continue;
/* reorder */
xj = xml_child_i(xt, j0);
xml_child_i_set(xt, j0, xc);
xml_child_i_set(xt, j, xj);
j0++;
}
}
retval = 0;
// done:
return retval;
}
/*! Sanitize an xml tree: xml node has matching yang_stmt pointer
* @param[in] xt XML top of tree
*/
int
xml_sanity(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *ys;
char *name;
ys = (yang_stmt*)xml_spec(xt);
name = xml_name(xt);
if (ys==NULL){
clicon_err(OE_XML, 0, "No spec for xml node %s", name);
goto done;
}
if (strstr(ys->ys_argument, name)==NULL){
clicon_err(OE_XML, 0, "xml node name '%s' does not match yang spec arg '%s'",
name, ys->ys_argument);
goto done;
}
retval = 0;
done:
return retval;
}

View file

@ -1540,11 +1540,11 @@ yang_parse1(clicon_handle h,
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
*
* @param h CLICON handle
* @param yang_dir Directory where all YANG module files reside
* @param module Name of main YANG module. More modules may be parsed if imported
* @param revision Optional module revision date
* @param ysp Yang specification. Should ave been created by caller using yspec_new
* @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside
* @param[in] module Name of main YANG module. More modules may be parsed if imported
* @param[in] revision Optional module revision date
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
* @retval 0 Everything OK
* @retval -1 Error encountered
* The database symbols are inserted in alphabetical order.