Added connect/disconnect/getopt/setopt and handle to xmldb API; Added datastore 'text'; Moved apps/dbctrl to datastore/
This commit is contained in:
parent
85af4342dc
commit
d26a801bc0
25 changed files with 1501 additions and 912 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue