formalizing xmldb api

This commit is contained in:
Olof hagsand 2017-04-16 19:06:19 +02:00
parent 540cd96e74
commit ee9b74d735
13 changed files with 252 additions and 166 deletions

View file

@ -438,7 +438,7 @@ from_client_unlock(clicon_handle h,
goto ok; goto ok;
} }
else{ else{
xmldb_unlock(h, db, pid); xmldb_unlock(h, db);
if (cprintf(cbret, "<rpc-reply><ok/></rpc-reply>") < 0) if (cprintf(cbret, "<rpc-reply><ok/></rpc-reply>") < 0)
goto done; goto done;
} }
@ -496,7 +496,7 @@ from_client_kill_session(clicon_handle h,
if (1 || (kill (pid, 0) != 0 && errno == ESRCH)){ /* Nothing there */ if (1 || (kill (pid, 0) != 0 && errno == ESRCH)){ /* Nothing there */
/* clear from locks */ /* clear from locks */
if (xmldb_islocked(h, db) == pid) if (xmldb_islocked(h, db) == pid)
xmldb_unlock(h, db, pid); xmldb_unlock(h, db);
} }
else{ /* failed to kill client */ else{ /* failed to kill client */
cprintf(cbret, "<rpc-reply><rpc-error>" cprintf(cbret, "<rpc-reply><rpc-error>"

View file

@ -73,7 +73,7 @@
#include "backend_handle.h" #include "backend_handle.h"
/* Command line options to be passed to getopt(3) */ /* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pty:x:" #define BACKEND_OPTS "hD:f:d:b:Fzu:P:1IRCc:rg:py:x:"
/*! Terminate. Cannot use h after this */ /*! Terminate. Cannot use h after this */
static int static int
@ -129,6 +129,7 @@ usage(char *argv0, clicon_handle h)
" -D <level>\tdebug\n" " -D <level>\tdebug\n"
" -f <file>\tCLICON config file (mandatory)\n" " -f <file>\tCLICON config file (mandatory)\n"
" -d <dir>\tSpecify backend plugin directory (default: %s)\n" " -d <dir>\tSpecify backend plugin directory (default: %s)\n"
" -b <dir>\tSpecify XMLDB database directory\n"
" -z\t\tKill other config daemon and exit\n" " -z\t\tKill other config daemon and exit\n"
" -F\t\tforeground\n" " -F\t\tforeground\n"
" -1\t\tonce (dont wait for events)\n" " -1\t\tonce (dont wait for events)\n"
@ -140,7 +141,6 @@ usage(char *argv0, clicon_handle h)
" -c <file>\tLoad specified application config.\n" " -c <file>\tLoad specified application config.\n"
" -r\t\tReload running database\n" " -r\t\tReload running database\n"
" -p \t\tPrint database yang specification\n" " -p \t\tPrint database yang specification\n"
" -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n"
" -g <group>\tClient membership required to this group (default: %s)\n" " -g <group>\tClient membership required to this group (default: %s)\n"
" -y <file>\tOverride yang spec file (dont include .yang suffix)\n" " -y <file>\tOverride yang spec file (dont include .yang suffix)\n"
" -x <plugin>\tXMLDB plugin\n", " -x <plugin>\tXMLDB plugin\n",
@ -308,7 +308,6 @@ main(int argc, char **argv)
clicon_handle h; clicon_handle h;
int help = 0; int help = 0;
int printspec = 0; int printspec = 0;
int printalt = 0;
int pid; int pid;
char *pidfile; char *pidfile;
char *sock; char *sock;
@ -387,6 +386,11 @@ main(int argc, char **argv)
usage(argv[0], h); usage(argv[0], h);
clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg); clicon_option_str_set(h, "CLICON_BACKEND_DIR", optarg);
break; break;
case 'b': /* XMLDB database directory */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_XMLDB_DIR", optarg);
break;
case 'F' : /* foreground */ case 'F' : /* foreground */
foreground = 1; foreground = 1;
break; break;
@ -425,9 +429,6 @@ main(int argc, char **argv)
case 'p' : /* Print spec */ case 'p' : /* Print spec */
printspec++; printspec++;
break; break;
case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */
printalt++;
break;
case 'y' :{ /* yang module */ case 'y' :{ /* yang module */
/* Set revision to NULL, extract dir and module */ /* Set revision to NULL, extract dir and module */
char *str = strdup(optarg); char *str = strdup(optarg);

View file

@ -152,86 +152,19 @@ api_data_get_gen(clicon_handle h,
int head) int head)
{ {
int retval = -1; int retval = -1;
cg_var *cv;
char *val;
char *v;
int i;
cbuf *path = NULL; cbuf *path = NULL;
cbuf *path1 = NULL;
cbuf *cbx = NULL; cbuf *cbx = NULL;
cxobj **vec = NULL; cxobj **vec = NULL;
yang_spec *yspec; yang_spec *yspec;
yang_stmt *y = NULL;
yang_stmt *ykey;
char *name;
cvec *cvk = NULL; /* vector of index keys */
cg_var *cvi;
cxobj *xret = NULL; cxobj *xret = NULL;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
yspec = clicon_dbspec_yang(h); yspec = clicon_dbspec_yang(h);
if ((path = cbuf_new()) == NULL) if ((path = cbuf_new()) == NULL)
goto done; goto done;
if ((path1 = cbuf_new()) == NULL) /* without [] qualifiers */ if (xml_apipath2xpath(yspec, pcvec, pi, path) < 0){
goto done; notfound(r);
cv = NULL; goto done;
cprintf(path1, "/");
/* translate eg a/b=c -> a/[b=c] */
for (i=pi; i<cvec_len(pcvec); i++){
cv = cvec_i(pcvec, i);
name = cv_name_get(cv);
clicon_debug(1, "[%d] cvname:%s", i, name);
clicon_debug(1, "cv2str%d", cv2str(cv, NULL, 0));
if (i == pi){
if ((y = yang_find_topnode(yspec, name)) == NULL){
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
goto done;
}
}
else{
assert(y!=NULL);
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
goto done;
}
}
/* Check if has value, means '=' */
if (cv2str(cv, NULL, 0) > 0){
if ((val = cv2str_dup(cv)) == NULL)
goto done;
v = val;
/* XXX sync with yang */
while((v=index(v, ',')) != NULL){
*v = '\0';
v++;
}
/* Find keys */
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
__FUNCTION__, y->ys_argument);
notfound(r);
goto done;
}
clicon_debug(1, "ykey:%s", ykey->ys_argument);
/* The value is a list of keys: <key>[ <key>]* */
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
goto done;
cvi = NULL;
/* Iterate over individual yang keys */
cprintf(path, "/%s", name);
v = val;
while ((cvi = cvec_each(cvk, cvi)) != NULL){
cprintf(path, "[%s=%s]", cv_string_get(cvi), v);
v += strlen(v)+1;
}
if (val)
free(val);
}
else{
cprintf(path, "%s%s", (i==pi?"":"/"), name);
cprintf(path1, "/%s", name);
}
} }
clicon_debug(1, "%s path:%s", __FUNCTION__, cbuf_get(path)); clicon_debug(1, "%s path:%s", __FUNCTION__, cbuf_get(path));
if (clicon_rpc_get_config(h, "running", cbuf_get(path), &xret) < 0){ if (clicon_rpc_get_config(h, "running", cbuf_get(path), &xret) < 0){
@ -267,8 +200,6 @@ api_data_get_gen(clicon_handle h,
cbuf_free(cbx); cbuf_free(cbx);
if (path) if (path)
cbuf_free(path); cbuf_free(path);
if (path1)
cbuf_free(path1);
if (xret) if (xret)
xml_free(xret); xml_free(xret);
return retval; return retval;

View file

@ -35,8 +35,9 @@
./datastore_client -d candidate -b /usr/local/var/routing -p /home/olof/src/clixon/datastore/keyvalue/keyvalue.so -y /usr/local/share/routing/yang -m ietf-ip get / ./datastore_client -d candidate -b /usr/local/var/routing -p /home/olof/src/clixon/datastore/keyvalue/keyvalue.so -y /usr/local/share/routing/yang -m ietf-ip get /
sudo ./datastore_client -d candidate -b /usr/local/var/routing -p /home/olof/src/clixon/datastore/keyvalue/keyvalue.so -y /usr/local/share/routing/yang -m ietf-ip put merge /interfaces/interface=eth0 sudo ./datastore_client -d candidate -b /usr/local/var/routing -p /home/olof/src/clixon/datastore/keyvalue/keyvalue.so -y /usr/local/share/routing/yang -m ietf-ip put merge /interfaces/interface=eth66 '<config>eth66</config>'
<config>eth66</config>
sudo ./datastore_client -d candidate -b /usr/local/var/routing -p /home/olof/src/clixon/datastore/keyvalue/keyvalue.so -y /usr/local/share/routing/yang -m ietf-ip put merge / '<config><interfaces><interface><name>eth0</name><enabled>true</enabled></interface></interfaces></config>'
* *
*/ */
@ -89,10 +90,10 @@ usage(char *argv0)
"\t-m <module>\tYang module. Mandatory\n" "\t-m <module>\tYang module. Mandatory\n"
"and command is either:\n" "and command is either:\n"
"\tget <xpath>\n" "\tget <xpath>\n"
"\tput (set|merge|delete) <api_path> \tXML on stdin\n" "\tput (set|merge|delete) <api_path> <xml>\n"
"\tcopy <fromdb> <todb>\n" "\tcopy <todb>\n"
"\tlock <pid>\n" "\tlock <pid>\n"
"\tunlock <pid>\n" "\tunlock\n"
"\tunlock_all <pid>\n" "\tunlock_all <pid>\n"
"\tislocked\n" "\tislocked\n"
"\texists\n" "\texists\n"
@ -212,18 +213,18 @@ main(int argc, char **argv)
if (xmldb_setopt(h, "yangspec", yspec) < 0) if (xmldb_setopt(h, "yangspec", yspec) < 0)
goto done; goto done;
if (strcmp(cmd, "get")==0){ if (strcmp(cmd, "get")==0){
if (argc < 2) if (argc != 2)
usage(argv0); usage(argv0);
if (xmldb_get(h, db, argv[1], &xt, NULL, 0) < 0) if (xmldb_get(h, db, argv[1], &xt, NULL, 0) < 0)
goto done; goto done;
clicon_xml2file(stdout, xt, 0, 1); clicon_xml2file(stdout, xt, 0, 1);
} }
else if (strcmp(cmd, "put")==0){ else if (strcmp(cmd, "put")==0){
if (argc < 3) if (argc != 4)
usage(argv0); usage(argv0);
if (xml_operation(argv[1], &op) < 0) if (xml_operation(argv[1], &op) < 0)
usage(argv0); usage(argv0);
if (clicon_xml_parse_file(0, &xt, "</clicon>") < 0) if (clicon_xml_parse_str(argv[3], &xt) < 0)
goto done; goto done;
if (xml_rootchild(xt, 0, &xn) < 0) if (xml_rootchild(xt, 0, &xn) < 0)
goto done; goto done;
@ -233,50 +234,59 @@ main(int argc, char **argv)
xml_free(xn); xml_free(xn);
} }
else if (strcmp(cmd, "copy")==0){ else if (strcmp(cmd, "copy")==0){
if (argc < 3) if (argc != 2)
usage(argv0); usage(argv0);
if (xmldb_copy(h, argv[1], argv[2]) < 0) if (xmldb_copy(h, db, argv[1]) < 0)
goto done; goto done;
} }
else if (strcmp(cmd, "lock")==0){ else if (strcmp(cmd, "lock")==0){
if (argc < 2) if (argc != 2)
usage(argv0); usage(argv0);
pid = atoi(argv[1]); pid = atoi(argv[1]);
if (xmldb_lock(h, db, pid) < 0) if (xmldb_lock(h, db, pid) < 0)
goto done; goto done;
} }
else if (strcmp(cmd, "unlock")==0){ else if (strcmp(cmd, "unlock")==0){
if (argc < 2) if (argc != 1)
usage(argv0); usage(argv0);
pid = atoi(argv[1]); if (xmldb_unlock(h, db) < 0)
if (xmldb_unlock(h, db, pid) < 0)
goto done; goto done;
} }
else if (strcmp(cmd, "unlock_all")==0){ else if (strcmp(cmd, "unlock_all")==0){
if (argc < 2) if (argc != 2)
usage(argv0); usage(argv0);
pid = atoi(argv[1]); pid = atoi(argv[1]);
if (xmldb_unlock_all(h, pid) < 0) if (xmldb_unlock_all(h, pid) < 0)
goto done; goto done;
} }
else if (strcmp(cmd, "islocked")==0){ else if (strcmp(cmd, "islocked")==0){
if (argc != 1)
usage(argv0);
if ((ret = xmldb_islocked(h, db)) < 0) if ((ret = xmldb_islocked(h, db)) < 0)
goto done; goto done;
fprintf(stdout, "islocked: %d\n", ret); fprintf(stdout, "islocked: %d\n", ret);
} }
else if (strcmp(cmd, "exists")==0){ else if (strcmp(cmd, "exists")==0){
if (argc != 1)
usage(argv0);
if ((ret = xmldb_exists(h, db)) < 0) if ((ret = xmldb_exists(h, db)) < 0)
goto done; goto done;
fprintf(stdout, "exists: %d\n", ret); fprintf(stdout, "exists: %d\n", ret);
} }
else if (strcmp(cmd, "delete")==0){ else if (strcmp(cmd, "delete")==0){
if (argc != 1)
usage(argv0);
if (xmldb_delete(h, db) < 0) if (xmldb_delete(h, db) < 0)
goto done; goto done;
} }
else if (strcmp(cmd, "init")==0){ else if (strcmp(cmd, "init")==0){
if (argc != 1)
usage(argv0);
if (xmldb_init(h, db) < 0) if (xmldb_init(h, db) < 0)
goto done; goto done;
} }
else
clicon_err(OE_DB, 0, "Unrecognized command: %s", cmd);
done: done:
return 0; return 0;
} }

View file

@ -160,7 +160,7 @@ static int _startup_locked = 0;
* The filename reside in CLICON_XMLDB_DIR option * The filename reside in CLICON_XMLDB_DIR option
*/ */
static int static int
db2file(struct kv_handle *kh, kv_db2file(struct kv_handle *kh,
char *db, char *db,
char **filename) char **filename)
{ {
@ -180,7 +180,7 @@ db2file(struct kv_handle *kh,
strcmp(db, "candidate") != 0 && strcmp(db, "candidate") != 0 &&
strcmp(db, "startup") != 0 && strcmp(db, "startup") != 0 &&
strcmp(db, "tmp") != 0){ strcmp(db, "tmp") != 0){
clicon_err(OE_XML, 0, "Unexpected database: %s", db); clicon_err(OE_XML, 0, "No such database: %s", db);
goto done; goto done;
} }
cprintf(cb, "%s/%s_db", dir, db); cprintf(cb, "%s/%s_db", dir, db);
@ -616,7 +616,7 @@ kv_get(xmldb_handle xh,
clicon_debug(2, "%s", __FUNCTION__); clicon_debug(2, "%s", __FUNCTION__);
if (db2file(kh, db, &dbfile) < 0) if (kv_db2file(kh, db, &dbfile) < 0)
goto done; goto done;
if (dbfile==NULL){ if (dbfile==NULL){
clicon_err(OE_XML, 0, "dbfile NULL"); clicon_err(OE_XML, 0, "dbfile NULL");
@ -629,7 +629,7 @@ kv_get(xmldb_handle xh,
/* Read in complete database (this can be optimized) */ /* Read in complete database (this can be optimized) */
if ((npairs = db_regexp(dbfile, "", __FUNCTION__, &pairs, 0)) < 0) if ((npairs = db_regexp(dbfile, "", __FUNCTION__, &pairs, 0)) < 0)
goto done; goto done;
if ((xt = xml_new_spec("clicon", NULL, yspec)) == NULL) if ((xt = xml_new_spec("config", NULL, yspec)) == NULL)
goto done; goto done;
/* Translate to complete xml tree */ /* Translate to complete xml tree */
for (i = 0; i < npairs; i++) { for (i = 0; i < npairs; i++) {
@ -836,7 +836,7 @@ xmldb_put_xkey(struct kv_handle *kh,
clicon_err(OE_YANG, ENOENT, "No yang spec"); clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done; goto done;
} }
if (db2file(kh, db, &filename) < 0) if (kv_db2file(kh, db, &filename) < 0)
goto done; goto done;
if (xk == NULL || *xk!='/'){ if (xk == NULL || *xk!='/'){
clicon_err(OE_DB, 0, "Invalid key: %s", xk); clicon_err(OE_DB, 0, "Invalid key: %s", xk);
@ -852,6 +852,9 @@ xmldb_put_xkey(struct kv_handle *kh,
} }
if ((vec = clicon_strsep(xk, "/", &nvec)) == NULL) if ((vec = clicon_strsep(xk, "/", &nvec)) == NULL)
goto done; goto done;
/* Remove trailing '/'. Like in /a/ -> /a */
if (nvec > 1 && !strlen(vec[nvec-1]))
nvec--;
if (nvec < 2){ if (nvec < 2){
clicon_err(OE_XML, 0, "Malformed key: %s", xk); clicon_err(OE_XML, 0, "Malformed key: %s", xk);
goto done; goto done;
@ -1066,7 +1069,7 @@ xmldb_put_restconf_api_path(struct kv_handle *kh,
clicon_err(OE_YANG, ENOENT, "No yang spec"); clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done; goto done;
} }
if (db2file(kh, db, &filename) < 0) if (kv_db2file(kh, db, &filename) < 0)
goto done; goto done;
if (api_path == NULL || *api_path!='/'){ if (api_path == NULL || *api_path!='/'){
clicon_err(OE_DB, 0, "Invalid api path: %s", api_path); clicon_err(OE_DB, 0, "Invalid api path: %s", api_path);
@ -1082,6 +1085,9 @@ xmldb_put_restconf_api_path(struct kv_handle *kh,
} }
if ((vec = clicon_strsep(api_path, "/", &nvec)) == NULL) if ((vec = clicon_strsep(api_path, "/", &nvec)) == NULL)
goto done; goto done;
/* Remove trailing '/'. Like in /a/ -> /a */
if (nvec > 1 && !strlen(vec[nvec-1]))
nvec--;
if (nvec < 2){ if (nvec < 2){
clicon_err(OE_XML, 0, "Malformed key: %s", api_path); clicon_err(OE_XML, 0, "Malformed key: %s", api_path);
goto done; goto done;
@ -1266,13 +1272,14 @@ kv_put(xmldb_handle xh,
yang_spec *yspec; yang_spec *yspec;
char *dbfilename = NULL; char *dbfilename = NULL;
if (xml_child_nr(xt)==0 || xml_body(xt)!= NULL) if ((xml_child_nr(xt)==0 || xml_body(xt)!= NULL) &&
api_path && strlen(api_path) && strcmp(api_path,"/"))
return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt)); return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt));
if ((yspec = kh->kh_yangspec) == NULL){ if ((yspec = kh->kh_yangspec) == NULL){
clicon_err(OE_YANG, ENOENT, "No yang spec"); clicon_err(OE_YANG, ENOENT, "No yang spec");
goto done; goto done;
} }
if (db2file(kh, db, &dbfilename) < 0) if (kv_db2file(kh, db, &dbfilename) < 0)
goto done; goto done;
if (op == OP_REPLACE){ if (op == OP_REPLACE){
if (db_delete(dbfilename) < 0) if (db_delete(dbfilename) < 0)
@ -1281,7 +1288,8 @@ kv_put(xmldb_handle xh,
goto done; goto done;
} }
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){ while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
if (api_path && strlen(api_path)){ /* An api path that is not / */
if (api_path && strlen(api_path) && strcmp(api_path,"/")){
if (xmldb_put_restconf_api_path(kh, db, op, api_path, x) < 0) if (xmldb_put_restconf_api_path(kh, db, op, api_path, x) < 0)
goto done; goto done;
continue; continue;
@ -1323,9 +1331,9 @@ kv_copy(xmldb_handle xh,
char *tofile = NULL; char *tofile = NULL;
/* XXX lock */ /* XXX lock */
if (db2file(kh, from, &fromfile) < 0) if (kv_db2file(kh, from, &fromfile) < 0)
goto done; goto done;
if (db2file(kh, to, &tofile) < 0) if (kv_db2file(kh, to, &tofile) < 0)
goto done; goto done;
if (clicon_file_copy(fromfile, tofile) < 0) if (clicon_file_copy(fromfile, tofile) < 0)
goto done; goto done;
@ -1350,16 +1358,25 @@ kv_lock(xmldb_handle xh,
char *db, char *db,
int pid) int pid)
{ {
int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
fprintf(stderr, "%s %s %d\n", __FUNCTION__, db, pid);
if (strcmp("running", db) == 0) if (strcmp("running", db) == 0)
_running_locked = pid; _running_locked = pid;
else if (strcmp("candidate", db) == 0) else if (strcmp("candidate", db) == 0)
_candidate_locked = pid; _candidate_locked = pid;
else if (strcmp("startup", db) == 0) else if (strcmp("startup", db) == 0)
_startup_locked = pid; _startup_locked = pid;
else{
clicon_err(OE_DB, 0, "No such database: %s", db);
goto done;
}
clicon_debug(1, "%s: locked by %u", db, pid); clicon_debug(1, "%s: locked by %u", db, pid);
return 0; fprintf(stderr, "running:%d candidate:%d startup:%d\n",
_running_locked, _candidate_locked, _startup_locked);
retval = 0;
done:
return retval;
} }
/*! Unlock database /*! Unlock database
@ -1372,18 +1389,24 @@ kv_lock(xmldb_handle xh,
*/ */
int int
kv_unlock(xmldb_handle xh, kv_unlock(xmldb_handle xh,
char *db, char *db)
int pid)
{ {
int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
fprintf(stderr, "%s %s\n", __FUNCTION__, db);
if (strcmp("running", db) == 0) if (strcmp("running", db) == 0)
_running_locked = 0; _running_locked = 0;
else if (strcmp("candidate", db) == 0) else if (strcmp("candidate", db) == 0)
_candidate_locked = 0; _candidate_locked = 0;
else if (strcmp("startup", db) == 0) else if (strcmp("startup", db) == 0)
_startup_locked = 0; _startup_locked = 0;
return 0; else{
clicon_err(OE_DB, 0, "No such database: %s", db);
goto done;
}
retval = 0;
done:
return retval;
} }
/*! Unlock all databases locked by pid (eg process dies) /*! Unlock all databases locked by pid (eg process dies)
@ -1418,15 +1441,21 @@ int
kv_islocked(xmldb_handle xh, kv_islocked(xmldb_handle xh,
char *db) char *db)
{ {
int retval = -1;
// struct kv_handle *kh = handle(xh); // struct kv_handle *kh = handle(xh);
fprintf(stderr, "%s %s\n", __FUNCTION__, db);
fprintf(stderr, "running:%d candidate:%d startup:%d\n",
_running_locked, _candidate_locked, _startup_locked);
if (strcmp("running", db) == 0) if (strcmp("running", db) == 0)
return (_running_locked); retval = _running_locked;
else if (strcmp("candidate", db) == 0) else if (strcmp("candidate", db) == 0)
return(_candidate_locked); retval = _candidate_locked;
else if (strcmp("startup", db) == 0) else if (strcmp("startup", db) == 0)
return(_startup_locked); retval = _startup_locked;
return 0; else
clicon_err(OE_DB, 0, "No such database: %s", db);
return retval;
} }
/*! Check if db exists /*! Check if db exists
@ -1445,7 +1474,7 @@ kv_exists(xmldb_handle xh,
char *filename = NULL; char *filename = NULL;
struct stat sb; struct stat sb;
if (db2file(kh, db, &filename) < 0) if (kv_db2file(kh, db, &filename) < 0)
goto done; goto done;
if (lstat(filename, &sb) < 0) if (lstat(filename, &sb) < 0)
retval = 0; retval = 0;
@ -1471,7 +1500,7 @@ kv_delete(xmldb_handle xh,
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);
char *filename = NULL; char *filename = NULL;
if (db2file(kh, db, &filename) < 0) if (kv_db2file(kh, db, &filename) < 0)
goto done; goto done;
if (db_delete(filename) < 0) if (db_delete(filename) < 0)
goto done; goto done;
@ -1496,7 +1525,7 @@ kv_init(xmldb_handle xh,
struct kv_handle *kh = handle(xh); struct kv_handle *kh = handle(xh);
char *filename = NULL; char *filename = NULL;
if (db2file(kh, db, &filename) < 0) if (kv_db2file(kh, db, &filename) < 0)
goto done; goto done;
if (db_init(filename) < 0) if (db_init(filename) < 0)
goto done; goto done;

View file

@ -46,7 +46,7 @@ int kv_put(xmldb_handle h, char *db, enum operation_type op,
int kv_dump(FILE *f, char *dbfilename, char *rxkey); int kv_dump(FILE *f, char *dbfilename, char *rxkey);
int kv_copy(xmldb_handle h, char *from, char *to); int kv_copy(xmldb_handle h, char *from, char *to);
int kv_lock(xmldb_handle h, char *db, int pid); int kv_lock(xmldb_handle h, char *db, int pid);
int kv_unlock(xmldb_handle h, char *db, int pid); int kv_unlock(xmldb_handle h, char *db);
int kv_unlock_all(xmldb_handle h, int pid); int kv_unlock_all(xmldb_handle h, int pid);
int kv_islocked(xmldb_handle h, char *db); int kv_islocked(xmldb_handle h, char *db);
int kv_exists(xmldb_handle h, char *db); int kv_exists(xmldb_handle h, char *db);

View file

@ -106,7 +106,7 @@ static int _startup_locked = 0;
* The filename reside in CLICON_XMLDB_DIR option * The filename reside in CLICON_XMLDB_DIR option
*/ */
static int static int
db2file(struct text_handle *th, text_db2file(struct text_handle *th,
char *db, char *db,
char **filename) char **filename)
{ {
@ -126,7 +126,7 @@ db2file(struct text_handle *th,
strcmp(db, "candidate") != 0 && strcmp(db, "candidate") != 0 &&
strcmp(db, "startup") != 0 && strcmp(db, "startup") != 0 &&
strcmp(db, "tmp") != 0){ strcmp(db, "tmp") != 0){
clicon_err(OE_XML, 0, "Unexpected database: %s", db); clicon_err(OE_XML, 0, "No such database: %s", db);
goto done; goto done;
} }
cprintf(cb, "%s/%s_db", dir, db); cprintf(cb, "%s/%s_db", dir, db);
@ -292,7 +292,7 @@ text_get(xmldb_handle xh,
int i; int i;
struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
if (db2file(th, db, &dbfile) < 0) if (text_db2file(th, db, &dbfile) < 0)
goto done; goto done;
if (dbfile==NULL){ if (dbfile==NULL){
clicon_err(OE_XML, 0, "dbfile NULL"); clicon_err(OE_XML, 0, "dbfile NULL");
@ -348,7 +348,6 @@ text_get(xmldb_handle xh,
if (fd != -1) if (fd != -1)
close(fd); close(fd);
return retval; return retval;
} }
/*! Modify database provided an xml tree and an operation /*! Modify database provided an xml tree and an operation
@ -380,10 +379,37 @@ text_put(xmldb_handle xh,
cxobj *xt) cxobj *xt)
{ {
int retval = -1; int retval = -1;
// struct text_handle *th = handle(xh); struct text_handle *th = handle(xh);
char *dbfile = NULL;
int fd = -1;
cbuf *cb = NULL;
if (text_db2file(th, db, &dbfile) < 0)
goto done;
if (dbfile==NULL){
clicon_err(OE_XML, 0, "dbfile NULL");
goto done;
}
if ((fd = open(dbfile, O_WRONLY | O_CREAT)) == -1) {
clicon_err(OE_UNIX, errno, "open(%s)", dbfile);
goto done;
}
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new");
goto done;
}
if (clicon_xml2cbuf(cb, xt, 0, 0) < 0)
goto done;
if (write(fd, cbuf_get(cb), cbuf_len(cb)+1) < 0){
clicon_err(OE_UNIX, errno, "write(%s)", dbfile);
goto done;
}
retval = 0; retval = 0;
// done: done:
if (fd != -1)
close(fd);
if (cb)
cbuf_free(cb);
return retval; return retval;
} }
@ -441,8 +467,7 @@ text_lock(xmldb_handle xh,
*/ */
int int
text_unlock(xmldb_handle xh, text_unlock(xmldb_handle xh,
char *db, char *db)
int pid)
{ {
// struct text_handle *th = handle(xh); // struct text_handle *th = handle(xh);
@ -515,7 +540,7 @@ text_exists(xmldb_handle xh,
char *filename = NULL; char *filename = NULL;
struct stat sb; struct stat sb;
if (db2file(th, db, &filename) < 0) if (text_db2file(th, db, &filename) < 0)
goto done; goto done;
if (lstat(filename, &sb) < 0) if (lstat(filename, &sb) < 0)
retval = 0; retval = 0;

View file

@ -46,7 +46,7 @@ int text_put(xmldb_handle h, char *db, enum operation_type op,
int text_dump(FILE *f, char *dbfilename, char *rxkey); int text_dump(FILE *f, char *dbfilename, char *rxkey);
int text_copy(xmldb_handle h, char *from, char *to); int text_copy(xmldb_handle h, char *from, char *to);
int text_lock(xmldb_handle h, char *db, int pid); int text_lock(xmldb_handle h, char *db, int pid);
int text_unlock(xmldb_handle h, char *db, int pid); int text_unlock(xmldb_handle h, char *db);
int text_unlock_all(xmldb_handle h, int pid); int text_unlock_all(xmldb_handle h, int pid);
int text_islocked(xmldb_handle h, char *db); int text_islocked(xmldb_handle h, char *db);
int text_exists(xmldb_handle h, char *db); int text_exists(xmldb_handle h, char *db);

View file

@ -89,7 +89,7 @@ typedef int (xmldb_copy_t)(xmldb_handle xh, char *from, char *to);
typedef int (xmldb_lock_t)(xmldb_handle xh, char *db, int pid); typedef int (xmldb_lock_t)(xmldb_handle xh, char *db, int pid);
/* Type of xmldb unlock function */ /* Type of xmldb unlock function */
typedef int (xmldb_unlock_t)(xmldb_handle xh, char *db, int pid); typedef int (xmldb_unlock_t)(xmldb_handle xh, char *db);
/* Type of xmldb unlock_all function */ /* Type of xmldb unlock_all function */
typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid); typedef int (xmldb_unlock_all_t)(xmldb_handle xh, int pid);
@ -145,7 +145,7 @@ int xmldb_put(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt); char *api_path, cxobj *xt);
int xmldb_copy(clicon_handle h, char *from, char *to); int xmldb_copy(clicon_handle h, char *from, char *to);
int xmldb_lock(clicon_handle h, char *db, int pid); int xmldb_lock(clicon_handle h, char *db, int pid);
int xmldb_unlock(clicon_handle h, char *db, int pid); int xmldb_unlock(clicon_handle h, char *db);
int xmldb_unlock_all(clicon_handle h, int pid); int xmldb_unlock_all(clicon_handle h, int pid);
int xmldb_islocked(clicon_handle h, char *db); int xmldb_islocked(clicon_handle h, char *db);
int xmldb_exists(clicon_handle h, char *db); int xmldb_exists(clicon_handle h, char *db);

View file

@ -68,5 +68,6 @@ int xml_tree_prune_unmarked(cxobj *xt, int *upmark);
int xml_default(cxobj *x, void *arg); int xml_default(cxobj *x, void *arg);
int xml_order(cxobj *x, void *arg); int xml_order(cxobj *x, void *arg);
int xml_sanity(cxobj *x, void *arg); int xml_sanity(cxobj *x, void *arg);
int xml_apipath2xpath(yang_spec *yspec, cvec *pcvec, int pi, cbuf *path);
#endif /* _CLIXON_XML_MAP_H_ */ #endif /* _CLIXON_XML_MAP_H_ */

View file

@ -843,7 +843,7 @@ clicon_xml2file(FILE *f,
int level, int level,
int prettyprint) int prettyprint)
{ {
cbuf *cb; cbuf *cb = NULL;
int retval = -1; int retval = -1;
if ((cb = cbuf_new()) == NULL){ if ((cb = cbuf_new()) == NULL){

View file

@ -30,8 +30,8 @@
the terms of any one of the Apache License version 2 or the GPL. the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
*/
*/
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -169,7 +169,6 @@ xmldb_plugin_unload(clicon_handle h)
* datastore. Note also that the xmldb handle is hidden in the clicon * 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 * handle, the clixon user does not need to handle it. Note also that
* typically only the backend invokes the datastore. * typically only the backend invokes the datastore.
* XXX what args does connect have?
*/ */
int int
xmldb_connect(clicon_handle h) xmldb_connect(clicon_handle h)
@ -201,8 +200,8 @@ xmldb_connect(clicon_handle h)
int int
xmldb_disconnect(clicon_handle h) xmldb_disconnect(clicon_handle h)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -237,8 +236,8 @@ xmldb_getopt(clicon_handle h,
char *optname, char *optname,
void **value) void **value)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -270,8 +269,8 @@ xmldb_setopt(clicon_handle h,
char *optname, char *optname,
void *value) void *value)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -320,7 +319,6 @@ xmldb_setopt(clicon_handle h,
* @see xpath_vec * @see xpath_vec
* @see xmldb_get * @see xmldb_get
*/ */
int int
xmldb_get(clicon_handle h, xmldb_get(clicon_handle h,
char *db, char *db,
@ -329,8 +327,8 @@ xmldb_get(clicon_handle h,
cxobj ***xvec, cxobj ***xvec,
size_t *xlen) size_t *xlen)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -345,8 +343,16 @@ xmldb_get(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin"); clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done; goto done;
} }
clicon_log(LOG_WARNING, "%s: db:%s xpath:%s", __FUNCTION__, db, xpath);
retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen); retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
#if 0 /* XXX DEBUG */
if (retval == 0) {
cbuf *cb = cbuf_new();
clicon_xml2cbuf(cb, *xtop, 0, 0);
clicon_log(LOG_WARNING, "%s: db:%s xpath:%s xml:%s",
__FUNCTION__, db, xpath, cbuf_get(cb));
cbuf_free(cb);
}
#endif
done: done:
return retval; return retval;
} }
@ -379,8 +385,8 @@ xmldb_put(clicon_handle h,
char *api_path, char *api_path,
cxobj *xt) cxobj *xt)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -395,6 +401,7 @@ xmldb_put(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin"); clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done; goto done;
} }
#if 0 /* XXX DEBUG */
{ {
cbuf *cb = cbuf_new(); cbuf *cb = cbuf_new();
if (clicon_xml2cbuf(cb, xt, 0, 0) < 0) if (clicon_xml2cbuf(cb, xt, 0, 0) < 0)
@ -404,6 +411,7 @@ xmldb_put(clicon_handle h,
db, op, api_path, cbuf_get(cb)); db, op, api_path, cbuf_get(cb));
cbuf_free(cb); cbuf_free(cb);
} }
#endif
retval = xa->xa_put_fn(xh, db, op, api_path, xt); retval = xa->xa_put_fn(xh, db, op, api_path, xt);
done: done:
return retval; return retval;
@ -421,8 +429,8 @@ xmldb_copy(clicon_handle h,
char *from, char *from,
char *to) char *to)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -454,8 +462,8 @@ xmldb_lock(clicon_handle h,
char *db, char *db,
int pid) int pid)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -485,11 +493,10 @@ xmldb_lock(clicon_handle h,
*/ */
int int
xmldb_unlock(clicon_handle h, xmldb_unlock(clicon_handle h,
char *db, char *db)
int pid)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -504,7 +511,7 @@ xmldb_unlock(clicon_handle h,
clicon_err(OE_DB, 0, "Not connected to datastore plugin"); clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done; goto done;
} }
retval = xa->xa_unlock_fn(xh, db, pid); retval = xa->xa_unlock_fn(xh, db);
done: done:
return retval; return retval;
} }
@ -519,8 +526,8 @@ int
xmldb_unlock_all(clicon_handle h, xmldb_unlock_all(clicon_handle h,
int pid) int pid)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -551,8 +558,8 @@ int
xmldb_islocked(clicon_handle h, xmldb_islocked(clicon_handle h,
char *db) char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -583,8 +590,8 @@ int
xmldb_exists(clicon_handle h, xmldb_exists(clicon_handle h,
char *db) char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -614,8 +621,8 @@ int
xmldb_delete(clicon_handle h, xmldb_delete(clicon_handle h,
char *db) char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){
@ -645,8 +652,8 @@ int
xmldb_init(clicon_handle h, xmldb_init(clicon_handle h,
char *db) char *db)
{ {
int retval = -1; int retval = -1;
xmldb_handle xh; xmldb_handle xh;
struct xmldb_api *xa; struct xmldb_api *xa;
if ((xa = clicon_xmldb_api_get(h)) == NULL){ if ((xa = clicon_xmldb_api_get(h)) == NULL){

View file

@ -1248,3 +1248,85 @@ xml_sanity(cxobj *xt,
return retval; return retval;
} }
/*! Translate from restconf api-path to xml xpath
* eg a/b=c -> a/[b=c]
* @param[in] yspec Yang spec
* @param[in] pcvec api-path as cvec
* @param[in] pi Length of cvec
* @param[out] path The xpath as cligen bif variable string
*/
int
xml_apipath2xpath(yang_spec *yspec,
cvec *pcvec,
int pi,
cbuf *path)
{
int retval = -1;
int i;
cg_var *cv;
char *name;
cvec *cvk = NULL; /* vector of index keys */
yang_stmt *y = NULL;
char *val;
char *v;
yang_stmt *ykey;
cg_var *cvi;
for (i=pi; i<cvec_len(pcvec); i++){
cv = cvec_i(pcvec, i);
name = cv_name_get(cv);
clicon_debug(1, "[%d] cvname:%s", i, name);
clicon_debug(1, "cv2str%d", cv2str(cv, NULL, 0));
if (i == pi){
if ((y = yang_find_topnode(yspec, name)) == NULL){
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
goto done;
}
}
else{
assert(y!=NULL);
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
goto done;
}
}
/* Check if has value, means '=' */
if (cv2str(cv, NULL, 0) > 0){
if ((val = cv2str_dup(cv)) == NULL)
goto done;
v = val;
/* XXX sync with yang */
while((v=index(v, ',')) != NULL){
*v = '\0';
v++;
}
/* Find keys */
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
__FUNCTION__, y->ys_argument);
goto done;
}
clicon_debug(1, "ykey:%s", ykey->ys_argument);
/* The value is a list of keys: <key>[ <key>]* */
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
goto done;
cvi = NULL;
/* Iterate over individual yang keys */
cprintf(path, "/%s", name);
v = val;
while ((cvi = cvec_each(cvk, cvi)) != NULL){
cprintf(path, "[%s=%s]", cv_string_get(cvi), v);
v += strlen(v)+1;
}
if (val)
free(val);
}
else{
cprintf(path, "%s%s", (i==pi?"":"/"), name);
}
}
retval = 0;
done:
return retval;
}