xmldb
This commit is contained in:
parent
ca18b7f49e
commit
0a812696c2
47 changed files with 1818 additions and 1783 deletions
|
|
@ -27,7 +27,7 @@ LIBS = @LIBS@
|
||||||
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
SUBDIRS = cli backend dbctrl netconf
|
SUBDIRS = cli backend dbctrl netconf xmldb
|
||||||
|
|
||||||
.PHONY: all clean depend install $(SUBDIRS)
|
.PHONY: all clean depend install $(SUBDIRS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/inclu
|
||||||
|
|
||||||
# Not accessible from plugin
|
# Not accessible from plugin
|
||||||
APPSRC = backend_main.c backend_socket.c backend_client.c \
|
APPSRC = backend_main.c backend_socket.c backend_client.c \
|
||||||
backend_lock.c backend_commit.c backend_plugin.c
|
backend_commit.c backend_plugin.c
|
||||||
|
|
||||||
APPOBJ = $(APPSRC:.c=.o)
|
APPOBJ = $(APPSRC:.c=.o)
|
||||||
APPL = clixon_backend
|
APPL = clixon_backend
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@
|
||||||
#include <clixon/clixon.h>
|
#include <clixon/clixon.h>
|
||||||
|
|
||||||
#include "backend_commit.h"
|
#include "backend_commit.h"
|
||||||
#include "backend_lock.h"
|
|
||||||
#include "backend_plugin.h"
|
#include "backend_plugin.h"
|
||||||
#include "backend_client.h"
|
#include "backend_client.h"
|
||||||
#include "backend_handle.h"
|
#include "backend_handle.h"
|
||||||
|
|
@ -163,7 +162,6 @@ backend_client_rm(clicon_handle h,
|
||||||
return backend_client_delete(h, ce); /* actually purge it */
|
return backend_client_delete(h, ce); /* actually purge it */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Internal message: Change entry set/delete in database xmldb variant
|
/*! Internal message: Change entry set/delete in database xmldb variant
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] s Socket where request arrived, and where replies are sent
|
* @param[in] s Socket where request arrived, and where replies are sent
|
||||||
|
|
@ -183,15 +181,14 @@ from_client_change(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
char *xk;
|
char *xk;
|
||||||
char *dbname;
|
char *db;
|
||||||
enum operation_type op;
|
enum operation_type op;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *candidate_db;
|
|
||||||
char *val=NULL;
|
char *val=NULL;
|
||||||
yang_spec *yspec;
|
int piddb;
|
||||||
|
|
||||||
if (clicon_msg_change_decode(msg,
|
if (clicon_msg_change_decode(msg,
|
||||||
&dbname,
|
&db,
|
||||||
&op,
|
&op,
|
||||||
&xk,
|
&xk,
|
||||||
&val,
|
&val,
|
||||||
|
|
@ -201,25 +198,17 @@ from_client_change(clicon_handle h,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* candidate is locked by other client */
|
/* candidate is locked by other client */
|
||||||
if (strcmp(dbname, candidate_db) == 0 &&
|
if (strcmp(db, "candidate") == 0){
|
||||||
db_islocked(h) &&
|
piddb = xmldb_islocked(h, db);
|
||||||
pid != db_islocked(h)){
|
if (piddb && pid != piddb){
|
||||||
send_msg_err(s, OE_DB, 0,
|
send_msg_err(s, OE_DB, 0,
|
||||||
"lock failed: locked by %d", db_islocked(h));
|
"lock failed: locked by %d", piddb);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update database */
|
/* Update database */
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if (xmldb_put_xkey(h, db, xk, val, op) < 0){
|
||||||
clicon_err(OE_XML, 0, "yang spec not found");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (xmldb_put_xkey(dbname, xk, val, yspec, op) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -233,8 +222,6 @@ from_client_change(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*! Internal message: Change entries as XML
|
/*! Internal message: Change entries as XML
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] s Socket where request arrived, and where replies are sent
|
* @param[in] s Socket where request arrived, and where replies are sent
|
||||||
|
|
@ -252,19 +239,16 @@ from_client_xmlput(clicon_handle h,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *dbname;
|
char *db;
|
||||||
enum operation_type op;
|
enum operation_type op;
|
||||||
cvec *cvv = NULL;
|
cvec *cvv = NULL;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
yang_spec *ys;
|
|
||||||
char *candidate_db;
|
|
||||||
cxobj *xt;
|
cxobj *xt;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
if ((ys = clicon_dbspec_yang(h)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_msg_xmlput_decode(msg,
|
if (clicon_msg_xmlput_decode(msg,
|
||||||
&dbname,
|
&db,
|
||||||
&op,
|
&op,
|
||||||
&xml,
|
&xml,
|
||||||
label) < 0){
|
label) < 0){
|
||||||
|
|
@ -272,24 +256,21 @@ from_client_xmlput(clicon_handle h,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* candidate is locked by other client */
|
/* candidate is locked by other client */
|
||||||
if (strcmp(dbname, candidate_db) == 0 &&
|
if (strcmp(db, "candidate") == 0){
|
||||||
db_islocked(h) &&
|
piddb = xmldb_islocked(h, db);
|
||||||
pid != db_islocked(h)){
|
if (piddb && pid != piddb){
|
||||||
send_msg_err(s, OE_DB, 0,
|
send_msg_err(s, OE_DB, 0,
|
||||||
"lock failed: locked by %d", db_islocked(h));
|
"lock failed: locked by %d", piddb);
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (clicon_xml_parse_string(&xml, &xt) < 0){
|
if (clicon_xml_parse_string(&xml, &xt) < 0){
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xmldb_put(dbname, xt, ys, op) < 0){
|
if (xmldb_put(h, db, xt, op) < 0){
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -312,7 +293,7 @@ from_client_xmlput(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
config_snapshot(clicon_handle h,
|
config_snapshot(clicon_handle h,
|
||||||
char *dbname,
|
char *db,
|
||||||
char *dir)
|
char *dir)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -322,7 +303,6 @@ config_snapshot(clicon_handle h,
|
||||||
int i;
|
int i;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
yang_spec *yspec = clicon_dbspec_yang(h);
|
|
||||||
|
|
||||||
if (stat(dir, &st) < 0){
|
if (stat(dir, &st) < 0){
|
||||||
clicon_err(OE_CFG, errno, "%s: stat(%s): %s\n",
|
clicon_err(OE_CFG, errno, "%s: stat(%s): %s\n",
|
||||||
|
|
@ -354,7 +334,7 @@ config_snapshot(clicon_handle h,
|
||||||
clicon_err(OE_CFG, errno, "Creating file %s", filename0);
|
clicon_err(OE_CFG, errno, "Creating file %s", filename0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (xmldb_get(dbname, "/", yspec, &xn) < 0)
|
if (xmldb_get(h, db, "/", 0, &xn, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_xml2file(f, xn, 0, 1) < 0)
|
if (clicon_xml2file(f, xn, 0, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -389,7 +369,6 @@ from_client_save(clicon_handle h,
|
||||||
uint32_t snapshot;
|
uint32_t snapshot;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
cxobj *xn = NULL;
|
cxobj *xn = NULL;
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
if (clicon_msg_save_decode(msg,
|
if (clicon_msg_save_decode(msg,
|
||||||
&db,
|
&db,
|
||||||
|
|
@ -400,6 +379,10 @@ from_client_save(clicon_handle h,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0){
|
||||||
|
clicon_err(OE_XML, 0, "Expected running or candidate, got %s", db);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (snapshot){
|
if (snapshot){
|
||||||
if ((archive_dir = clicon_archive_dir(h)) == NULL){
|
if ((archive_dir = clicon_archive_dir(h)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined");
|
clicon_err(OE_PLUGIN, 0, "snapshot set and clicon_archive_dir not defined");
|
||||||
|
|
@ -417,8 +400,7 @@ from_client_save(clicon_handle h,
|
||||||
clicon_err(OE_CFG, errno, "Creating file %s", filename);
|
clicon_err(OE_CFG, errno, "Creating file %s", filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, db, "/", 0, &xn, NULL, NULL) < 0)
|
||||||
if (xmldb_get(db, "/", yspec, &xn) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_xml2file(f, xn, 0, 1) < 0)
|
if (clicon_xml2file(f, xn, 0, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -453,40 +435,41 @@ from_client_load(clicon_handle h,
|
||||||
{
|
{
|
||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *dbname = NULL;
|
char *db = NULL;
|
||||||
int replace = 0;
|
int replace = 0;
|
||||||
char *candidate_db;
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
yang_spec *yspec;
|
int piddb;
|
||||||
|
|
||||||
if (clicon_msg_load_decode(msg,
|
if (clicon_msg_load_decode(msg,
|
||||||
&replace,
|
&replace,
|
||||||
&dbname,
|
&db,
|
||||||
&filename,
|
&filename,
|
||||||
label) < 0){
|
label) < 0){
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0){
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
clicon_err(OE_XML, 0, "Expected running or candidate, got %s", db);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* candidate is locked by other client */
|
/* candidate is locked by other client */
|
||||||
if (strcmp(dbname, candidate_db) == 0 &&
|
if (strcmp(db, "candidate") == 0){
|
||||||
db_islocked(h) &&
|
piddb = xmldb_islocked(h, db);
|
||||||
pid != db_islocked(h)){
|
if (piddb && pid != piddb){
|
||||||
send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h));
|
send_msg_err(s, OE_DB, 0,
|
||||||
goto done;
|
"lock failed: locked by %d", piddb);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (replace){
|
if (replace){
|
||||||
if (unlink(dbname) < 0){
|
if (xmldb_delete(h, db) < 0){
|
||||||
send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename, strerror(errno));
|
send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename, strerror(errno));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (xmldb_init(dbname) < 0)
|
if (xmldb_init(h, db) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,9 +484,8 @@ from_client_load(clicon_handle h,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if ((xn = xml_child_i(xt, 0)) != NULL){
|
if ((xn = xml_child_i(xt, 0)) != NULL){
|
||||||
if (xmldb_put(dbname, xn, yspec, replace?OP_REPLACE:OP_MERGE) < 0){
|
if (xmldb_put(h, db, xn, replace?OP_REPLACE:OP_MERGE) < 0){
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -520,270 +502,6 @@ from_client_load(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Internal message: Initialize database
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] s Socket where request arrived, and where replies are sent
|
|
||||||
* @param[in] pid Unix process id
|
|
||||||
* @param[in] msg Message
|
|
||||||
* @param[in] label Memory chunk
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error. Send error message back to client.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
from_client_initdb(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char *filename1;
|
|
||||||
int retval = -1;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if (clicon_msg_initdb_decode(msg,
|
|
||||||
&filename1,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* candidate is locked by other client */
|
|
||||||
if (strcmp(filename1, candidate_db) == 0 &&
|
|
||||||
db_islocked(h) &&
|
|
||||||
pid != db_islocked(h)){
|
|
||||||
send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xmldb_init(filename1) < 0)
|
|
||||||
goto done;
|
|
||||||
/* Change mode if shared candidate. XXXX full rights for all is no good */
|
|
||||||
if (strcmp(filename1, candidate_db) == 0)
|
|
||||||
chmod(filename1, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
|
||||||
|
|
||||||
if (send_msg_ok(s) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Remove file
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] s Socket where request arrived, and where replies are sent
|
|
||||||
* @param[in] pid Unix process id
|
|
||||||
* @param[in] msg Message
|
|
||||||
* @param[in] label Memory chunk
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error. Send error message back to client.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
from_client_rm(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char *filename1;
|
|
||||||
int retval = -1;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if (clicon_msg_rm_decode(msg,
|
|
||||||
&filename1,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* candidate is locked by other client */
|
|
||||||
if (strcmp(filename1, candidate_db) == 0 &&
|
|
||||||
db_islocked(h) &&
|
|
||||||
pid != db_islocked(h)){
|
|
||||||
send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlink(filename1) < 0){
|
|
||||||
send_msg_err(s, OE_UNIX, 0, "rm %s %s", filename1, strerror(errno));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (send_msg_ok(s) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Copy file from file1 to file2
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] s Socket where request arrived, and where replies are sent
|
|
||||||
* @param[in] pid Unix process id
|
|
||||||
* @param[in] msg Message
|
|
||||||
* @param[in] label Memory chunk
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error. Send error message back to client.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
from_client_copy(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char *filename1;
|
|
||||||
char *filename2;
|
|
||||||
int retval = -1;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if (clicon_msg_copy_decode(msg,
|
|
||||||
&filename1,
|
|
||||||
&filename2,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* candidate is locked by other client */
|
|
||||||
if (strcmp(filename2, candidate_db) == 0 &&
|
|
||||||
db_islocked(h) &&
|
|
||||||
pid != db_islocked(h)){
|
|
||||||
send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_cp(filename1, filename2) < 0){
|
|
||||||
send_msg_err(s, OE_UNIX, errno, "copy %s to %s", filename1, filename2);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Change mode if shared candidate. XXXX full rights for all is no good */
|
|
||||||
if (strcmp(filename2, candidate_db) == 0)
|
|
||||||
chmod(filename2, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
|
||||||
if (send_msg_ok(s) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Lock database
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] s Client socket where request arrived, and where replies are sent
|
|
||||||
* @param[in] pid Client unix process id
|
|
||||||
* @param[in] msg Message
|
|
||||||
* @param[in] label Memory chunk
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error. Send error message back to client.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
from_client_lock(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char *db;
|
|
||||||
int retval = -1;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
|
|
||||||
if (clicon_msg_lock_decode(msg,
|
|
||||||
&db,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (strcmp(db, candidate_db)){
|
|
||||||
send_msg_err(s, OE_DB, 0, "can not lock %s, only %s",
|
|
||||||
db, candidate_db);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (db_islocked(h)){
|
|
||||||
if (pid == db_islocked(h))
|
|
||||||
;
|
|
||||||
else{
|
|
||||||
send_msg_err(s, OE_DB, 0, "lock failed: locked by %d", db_islocked(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
db_lock(h, pid);
|
|
||||||
if (send_msg_ok(s) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Unlock database
|
|
||||||
* @param[in] h Clicon handle
|
|
||||||
* @param[in] s Client socket where request arrived, and where replies are sent
|
|
||||||
* @param[in] pid Client unix process id
|
|
||||||
* @param[in] msg Message
|
|
||||||
* @param[in] label Memory chunk
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error. Send error message back to client.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
from_client_unlock(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
char *db;
|
|
||||||
int retval = -1;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if (clicon_msg_unlock_decode(msg,
|
|
||||||
&db,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
send_msg_err(s, 0, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(db, candidate_db)){
|
|
||||||
send_msg_err(s, OE_DB, 0, "can not unlock %s, only %s",
|
|
||||||
db, clicon_candidate_db(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (db_islocked(h)){
|
|
||||||
if (pid == db_islocked(h))
|
|
||||||
db_unlock(h);
|
|
||||||
else{
|
|
||||||
send_msg_err(s, OE_DB, 0, "unlock failed: locked by %d", db_islocked(h));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (send_msg_ok(s) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Kill session (Kill the process)
|
/*! Internal message: Kill session (Kill the process)
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] s Client socket where request arrived, and where replies are sent
|
* @param[in] s Client socket where request arrived, and where replies are sent
|
||||||
|
|
@ -798,9 +516,10 @@ from_client_kill(clicon_handle h,
|
||||||
struct clicon_msg *msg,
|
struct clicon_msg *msg,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
uint32_t pid; /* other pid */
|
int retval = -1;
|
||||||
int retval = -1;
|
uint32_t pid; /* other pid */
|
||||||
struct client_entry *ce;
|
struct client_entry *ce;
|
||||||
|
char *db = "running"; /* XXX */
|
||||||
|
|
||||||
if (clicon_msg_kill_decode(msg,
|
if (clicon_msg_kill_decode(msg,
|
||||||
&pid,
|
&pid,
|
||||||
|
|
@ -823,8 +542,8 @@ from_client_kill(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 (db_islocked(h) == pid)
|
if (xmldb_islocked(h, db) == pid)
|
||||||
db_unlock(h);
|
xmldb_unlock(h, db, pid);
|
||||||
}
|
}
|
||||||
else{ /* failed to kill client */
|
else{ /* failed to kill client */
|
||||||
send_msg_err(s, OE_DB, 0, "failed to kill %d", pid);
|
send_msg_err(s, OE_DB, 0, "failed to kill %d", pid);
|
||||||
|
|
@ -1017,26 +736,6 @@ from_client(int s, void* arg)
|
||||||
if (from_client_load(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
if (from_client_load(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case CLICON_MSG_RM:
|
|
||||||
if (from_client_rm(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case CLICON_MSG_INITDB:
|
|
||||||
if (from_client_initdb(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case CLICON_MSG_COPY:
|
|
||||||
if (from_client_copy(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case CLICON_MSG_LOCK:
|
|
||||||
if (from_client_lock(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case CLICON_MSG_UNLOCK:
|
|
||||||
if (from_client_unlock(h, ce->ce_s, ce->ce_pid, msg, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case CLICON_MSG_KILL:
|
case CLICON_MSG_KILL:
|
||||||
if (from_client_kill(h, ce->ce_s, msg, __FUNCTION__) < 0)
|
if (from_client_kill(h, ce->ce_s, msg, __FUNCTION__) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -117,18 +117,14 @@ generic_validate(yang_spec *yspec,
|
||||||
* fails, we just ignore the errors and proceed. Maybe we should
|
* fails, we just ignore the errors and proceed. Maybe we should
|
||||||
* do something more drastic?
|
* do something more drastic?
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] running The current database. The original backend state
|
|
||||||
* @param[in] candidate: The candidate database. The wanted backend state
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
candidate_commit(clicon_handle h,
|
candidate_commit(clicon_handle h,
|
||||||
char *candidate,
|
char *candidate)
|
||||||
char *running)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
struct stat sb;
|
|
||||||
void *firsterr = NULL;
|
void *firsterr = NULL;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
transaction_data_t *td = NULL;
|
transaction_data_t *td = NULL;
|
||||||
|
|
@ -137,24 +133,15 @@ candidate_commit(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Sanity checks that databases exists. */
|
|
||||||
if (stat(running, &sb) < 0){
|
|
||||||
clicon_err(OE_DB, errno, "%s", running);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (stat(candidate, &sb) < 0){
|
|
||||||
clicon_err(OE_DB, errno, "%s", candidate);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 1. Start transaction */
|
/* 1. Start transaction */
|
||||||
if ((td = transaction_new()) == NULL)
|
if ((td = transaction_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 2. Parse xml trees */
|
/* 2. Parse xml trees */
|
||||||
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
|
if (xmldb_get(h, "running", "/", 0, &td->td_src, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
|
if (xmldb_get(h, candidate, "/", 0, &td->td_target, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 3. Compute differences */
|
/* 3. Compute differences */
|
||||||
|
|
@ -212,18 +199,15 @@ candidate_commit(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 8. Success: Copy candidate to running */
|
/* 8. Success: Copy candidate to running */
|
||||||
if (file_cp(candidate, running) < 0){
|
if (xmldb_copy(h, candidate, "running") < 0)
|
||||||
clicon_err(OE_UNIX, errno, "file_cp(candidate; running)");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
/* 9. Call plugin transaction end callbacks */
|
/* 9. Call plugin transaction end callbacks */
|
||||||
plugin_transaction_end(h, td);
|
plugin_transaction_end(h, td);
|
||||||
|
|
||||||
/* 8. Copy running back to running in case end functions updated running */
|
/* 8. Copy running back to candidate in case end functions updated running */
|
||||||
if (file_cp(running, candidate) < 0){
|
if (xmldb_copy(h, "running", candidate) < 0){
|
||||||
/* ignore errors or signal major setback ? */
|
/* ignore errors or signal major setback ? */
|
||||||
clicon_err(OE_UNIX, errno, "file_cp(running, candidate)");
|
|
||||||
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
clicon_log(LOG_NOTICE, "Error in rollback, trying to continue");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -243,16 +227,13 @@ candidate_commit(clicon_handle h,
|
||||||
/*! Do a diff between candidate and running, then start a validate transaction
|
/*! Do a diff between candidate and running, then start a validate transaction
|
||||||
*
|
*
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] running The current database. The original backend state
|
|
||||||
* @param[in] candidate: The candidate database. The wanted backend state
|
* @param[in] candidate: The candidate database. The wanted backend state
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
candidate_validate(clicon_handle h,
|
candidate_validate(clicon_handle h,
|
||||||
char *candidate,
|
char *candidate)
|
||||||
char *running)
|
{
|
||||||
{
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct stat sb;
|
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
transaction_data_t *td = NULL;
|
transaction_data_t *td = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -262,24 +243,15 @@ candidate_validate(clicon_handle h,
|
||||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Sanity checks that databases exists. */
|
|
||||||
if (stat(running, &sb) < 0){
|
|
||||||
clicon_err(OE_DB, errno, "%s", running);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (stat(candidate, &sb) < 0){
|
|
||||||
clicon_err(OE_DB, errno, "%s", candidate);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 1. Start transaction */
|
/* 1. Start transaction */
|
||||||
if ((td = transaction_new()) == NULL)
|
if ((td = transaction_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 2. Parse xml trees */
|
/* 2. Parse xml trees */
|
||||||
if (xmldb_get(running, "/", yspec, &td->td_src) < 0)
|
if (xmldb_get(h, "running", "/", 0, &td->td_src, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xmldb_get(candidate, "/", yspec, &td->td_target) < 0)
|
if (xmldb_get(h, "candidate", "/", 0, &td->td_target, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* 3. Compute differences */
|
/* 3. Compute differences */
|
||||||
|
|
@ -346,25 +318,36 @@ candidate_validate(clicon_handle h,
|
||||||
* the commit has succeeded but an error message is returned.
|
* the commit has succeeded but an error message is returned.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_commit(clicon_handle h,
|
from_client_commit(clicon_handle h,
|
||||||
int s,
|
int s,
|
||||||
struct clicon_msg *msg,
|
struct clicon_msg *msg,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *candidate;
|
char *candidate;
|
||||||
char *running;
|
char *running;
|
||||||
uint32_t snapshot;
|
uint32_t snapshot;
|
||||||
uint32_t startup;
|
uint32_t startup;
|
||||||
char *snapshot_0;
|
|
||||||
char *archive_dir;
|
char *archive_dir;
|
||||||
char *startup_config;
|
char *startup_config;
|
||||||
|
|
||||||
if (clicon_msg_commit_decode(msg, &candidate, &running,
|
if (clicon_msg_commit_decode(msg,
|
||||||
&snapshot, &startup, label) < 0)
|
&candidate,
|
||||||
|
&running,
|
||||||
|
&snapshot,
|
||||||
|
&startup,
|
||||||
|
label) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (candidate_commit(h, candidate, running) < 0){
|
if (strcmp(candidate, "candidate") && strcmp(candidate, "tmp")){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (strcmp(running, "running")){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "running db is not \"running\"");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (candidate_commit(h, "candidate") < 0){
|
||||||
clicon_debug(1, "Commit %s failed", candidate);
|
clicon_debug(1, "Commit %s failed", candidate);
|
||||||
retval = 0; /* We ignore errors from commit, but maybe
|
retval = 0; /* We ignore errors from commit, but maybe
|
||||||
we should fail on fatal errors? */
|
we should fail on fatal errors? */
|
||||||
|
|
@ -389,8 +372,7 @@ from_client_commit(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined");
|
clicon_err(OE_PLUGIN, 0, "startup set but startup_config not defined");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
snapshot_0 = chunk_sprintf(__FUNCTION__, "%s/0", archive_dir);
|
if (clicon_file_copy("snapshot", "startup") < 0){
|
||||||
if (file_cp(snapshot_0, startup_config) < 0){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: Error when creating startup",
|
clicon_err(OE_PROTO, errno, "%s: Error when creating startup",
|
||||||
__FUNCTION__);
|
__FUNCTION__);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -412,32 +394,31 @@ from_client_commit(clicon_handle h,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*! Handle an incoming validate message from a client.
|
||||||
* Call backend plugin
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_validate(clicon_handle h,
|
from_client_validate(clicon_handle h,
|
||||||
int s,
|
int s,
|
||||||
struct clicon_msg *msg,
|
struct clicon_msg *msg,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
char *dbname;
|
int retval = -1;
|
||||||
char *running_db;
|
char *candidate;
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (clicon_msg_validate_decode(msg, &dbname, label) < 0){
|
if (clicon_msg_validate_decode(msg,
|
||||||
|
&candidate,
|
||||||
|
label) < 0){
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
send_msg_err(s, clicon_errno, clicon_suberrno,
|
||||||
clicon_err_reason);
|
clicon_err_reason);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
if (strcmp(candidate, "candidate") != 0 && strcmp(candidate, "tmp") != 0){
|
||||||
clicon_debug(1, "Validate %s", dbname);
|
clicon_err(OE_PLUGIN, 0, "candidate is not \"candidate\" or tmp");
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
goto err;
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
if (candidate_validate(h, dbname, running_db) < 0){
|
clicon_debug(1, "Validate %s", candidate);
|
||||||
clicon_debug(1, "Validate %s failed", dbname);
|
if (candidate_validate(h, candidate) < 0){
|
||||||
|
clicon_debug(1, "Validate %s failed", candidate);
|
||||||
retval = 0; /* We ignore errors from commit, but maybe
|
retval = 0; /* We ignore errors from commit, but maybe
|
||||||
we should fail on fatal errors? */
|
we should fail on fatal errors? */
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,6 @@
|
||||||
*/
|
*/
|
||||||
int from_client_validate(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
int from_client_validate(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
||||||
int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
int from_client_commit(clicon_handle h, int s, struct clicon_msg *msg, const char *label);
|
||||||
int candidate_commit(clicon_handle h, char *candidate, char *running);
|
int candidate_commit(clicon_handle h, char *candidate);
|
||||||
|
|
||||||
#endif /* _BACKEND_COMMIT_H_ */
|
#endif /* _BACKEND_COMMIT_H_ */
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
|
||||||
|
|
||||||
This file is part of CLIXON.
|
|
||||||
|
|
||||||
CLIXON is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
CLIXON is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with CLIXON; see the file LICENSE. If not, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
|
|
||||||
/* cligen */
|
|
||||||
#include <cligen/cligen.h>
|
|
||||||
|
|
||||||
/* clicon */
|
|
||||||
#include <clixon/clixon.h>
|
|
||||||
|
|
||||||
#include "backend_lock.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Easy way out: store an integer for candidate db which contains
|
|
||||||
* the session-id of the client holding the lock.
|
|
||||||
* more general: any database
|
|
||||||
* we dont make any sanity check on who is locking.
|
|
||||||
*/
|
|
||||||
static int _db_locked = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* db_lock
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
db_lock(clicon_handle h, int id)
|
|
||||||
{
|
|
||||||
_db_locked = id;
|
|
||||||
clicon_debug(1, "%s: lock db by %u", __FUNCTION__, id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* db_unlock
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
db_unlock(clicon_handle h)
|
|
||||||
{
|
|
||||||
if (!_db_locked )
|
|
||||||
return 0;
|
|
||||||
_db_locked = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* db_islocked
|
|
||||||
* returns id of locker
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
db_islocked(clicon_handle h)
|
|
||||||
{
|
|
||||||
return _db_locked;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
|
||||||
|
|
||||||
This file is part of CLIXON.
|
|
||||||
|
|
||||||
CLIXON is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
CLIXON is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with CLIXON; see the file LICENSE. If not, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*
|
|
||||||
* Database logical lock functions.
|
|
||||||
* Only one lock (candidate_db)
|
|
||||||
* Not persistent (needs another db)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _BACKEND_LOCK_H_
|
|
||||||
#define _BACKEND_LOCK_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prototypes
|
|
||||||
*/
|
|
||||||
int db_lock(clicon_handle h, int id);
|
|
||||||
int db_unlock(clicon_handle h);
|
|
||||||
int db_islocked(clicon_handle h);
|
|
||||||
|
|
||||||
#endif /* _BACKEND_LOCK_H_ */
|
|
||||||
|
|
@ -59,9 +59,9 @@
|
||||||
#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:pt"
|
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc::rg:ptx:"
|
||||||
|
|
||||||
/* Cannot use h after this */
|
/*! Terminate. Cannot use h after this */
|
||||||
static int
|
static int
|
||||||
config_terminate(clicon_handle h)
|
config_terminate(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -85,10 +85,8 @@ config_terminate(clicon_handle h)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Unlink pidfile and quit
|
||||||
config_sig_term
|
*/
|
||||||
Unlink pidfile and quit
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
config_sig_term(int arg)
|
config_sig_term(int arg)
|
||||||
{
|
{
|
||||||
|
|
@ -130,7 +128,8 @@ usage(char *argv0, clicon_handle h)
|
||||||
" -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"
|
" -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"
|
||||||
|
" -x <status>\tSet CLICON_XMLDB_RPC to 0 or 1.\n",
|
||||||
argv0,
|
argv0,
|
||||||
plgdir ? plgdir : "none",
|
plgdir ? plgdir : "none",
|
||||||
confsock ? confsock : "none",
|
confsock ? confsock : "none",
|
||||||
|
|
@ -138,19 +137,16 @@ usage(char *argv0, clicon_handle h)
|
||||||
startup ? startup : "none",
|
startup ? startup : "none",
|
||||||
group ? group : "none"
|
group ? group : "none"
|
||||||
);
|
);
|
||||||
exit(0);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rundb_init(clicon_handle h, char *running_db)
|
rundb_init(clicon_handle h)
|
||||||
{
|
{
|
||||||
if (unlink(running_db) != 0 && errno != ENOENT) {
|
if (xmldb_delete(h, "running") != 0 && errno != ENOENT)
|
||||||
clicon_err(OE_UNIX, errno, "unlink");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
if (xmldb_init(h, "running") < 0)
|
||||||
if (xmldb_init(running_db) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,19 +160,16 @@ rundb_init(clicon_handle h, char *running_db)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
rundb_main(clicon_handle h,
|
rundb_main(clicon_handle h,
|
||||||
char *app_config_file,
|
char *app_config_file)
|
||||||
char *running_db)
|
|
||||||
{
|
{
|
||||||
char *tmp = NULL;
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
yang_spec *yspec;
|
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
|
|
||||||
if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL)
|
if (xmldb_init(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (file_cp(running_db, tmp) < 0){
|
if (xmldb_copy(h, "running", "tmp") < 0){
|
||||||
clicon_err(OE_UNIX, errno, "file copy");
|
clicon_err(OE_UNIX, errno, "file copy");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -186,16 +179,15 @@ rundb_main(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if ((xn = xml_child_i(xt, 0)) != NULL)
|
if ((xn = xml_child_i(xt, 0)) != NULL)
|
||||||
if (xmldb_put(tmp, xn, yspec, OP_MERGE) < 0)
|
if (xmldb_put(h, "tmp", xn, OP_MERGE) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (candidate_commit(h, tmp, running_db) < 0)
|
if (candidate_commit(h, "tmp") < 0)
|
||||||
|
goto done;
|
||||||
|
if (xmldb_delete(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (tmp)
|
|
||||||
unlink(tmp);
|
|
||||||
if (xt)
|
if (xt)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
|
|
@ -204,31 +196,24 @@ done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
candb_reset(clicon_handle h, char *running_db)
|
candb_reset(clicon_handle h)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *tmp = NULL;
|
|
||||||
|
|
||||||
if ((tmp = clicon_tmpfile(__FUNCTION__)) == NULL)
|
if (xmldb_copy(h, "running", "tmp") < 0){
|
||||||
goto done;
|
|
||||||
if (file_cp(running_db, tmp) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "file copy");
|
clicon_err(OE_UNIX, errno, "file copy");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Request plugins to reset system state, eg initiate running from system
|
/* Request plugins to reset system state, eg initiate running from system
|
||||||
* -R
|
* -R
|
||||||
*/
|
*/
|
||||||
if (plugin_reset_state(h, tmp) < 0)
|
if (plugin_reset_state(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (candidate_commit(h, tmp, running_db) < 0)
|
if (candidate_commit(h, "tmp") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (tmp)
|
|
||||||
unlink(tmp);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,8 +284,6 @@ main(int argc, char **argv)
|
||||||
int foreground;
|
int foreground;
|
||||||
int once;
|
int once;
|
||||||
int init_rundb;
|
int init_rundb;
|
||||||
char *running_db;
|
|
||||||
char *candidate_db;
|
|
||||||
int reload_running;
|
int reload_running;
|
||||||
int reset_state_running;
|
int reset_state_running;
|
||||||
int reset_state_candidate;
|
int reset_state_candidate;
|
||||||
|
|
@ -431,6 +414,14 @@ main(int argc, char **argv)
|
||||||
case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */
|
case 't' : /* Print alternative dbspec format (eg if YANG, print KEY) */
|
||||||
printalt++;
|
printalt++;
|
||||||
break;
|
break;
|
||||||
|
case 'x' : /* set xmldb rpc on */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (sscanf(optarg, "%d", &i) != 1)
|
||||||
|
usage(argv[0], h);
|
||||||
|
clicon_option_int_set(h, "CLICON_XMLDB_RPC", i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0], h);
|
usage(argv[0], h);
|
||||||
break;
|
break;
|
||||||
|
|
@ -462,7 +453,7 @@ main(int argc, char **argv)
|
||||||
unlink(pidfile);
|
unlink(pidfile);
|
||||||
if (sockfamily==AF_UNIX && lstat(sock, &st) == 0)
|
if (sockfamily==AF_UNIX && lstat(sock, &st) == 0)
|
||||||
unlink(sock);
|
unlink(sock);
|
||||||
exit(0);
|
exit(0); /* OK */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (pid){
|
if (pid){
|
||||||
|
|
@ -500,31 +491,21 @@ main(int argc, char **argv)
|
||||||
if (yang_spec_main(h, stdout, printspec) < 0)
|
if (yang_spec_main(h, stdout, printspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* If running exists and reload_running set, make a copy to candidate */
|
/* If running exists and reload_running set, make a copy to candidate */
|
||||||
if (reload_running){
|
if (reload_running){
|
||||||
if (stat(running_db, &st) && errno == ENOENT){
|
if (xmldb_exists(h, "running") != 1){
|
||||||
clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
|
clicon_log(LOG_NOTICE, "%s: -r (reload running) option given but no running_db found, proceeding without", __PROGRAM__);
|
||||||
reload_running = 0; /* void it, so we dont commit candidate below */
|
reload_running = 0; /* void it, so we dont commit candidate below */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (file_cp(running_db, candidate_db) < 0){
|
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||||
clicon_err(OE_UNIX, errno, "FATAL: file_cp");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Init running db
|
/* Init running db
|
||||||
* -I
|
* -I or if it isnt there
|
||||||
*/
|
*/
|
||||||
if (init_rundb || (stat(running_db, &st) && errno == ENOENT))
|
if (init_rundb || xmldb_exists(h, "running") != 1)
|
||||||
if (rundb_init(h, running_db) < 0)
|
if (rundb_init(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Initialize plugins
|
/* Initialize plugins
|
||||||
|
|
@ -533,12 +514,12 @@ main(int argc, char **argv)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (reset_state_candidate){
|
if (reset_state_candidate){
|
||||||
if (candb_reset(h, running_db) < 0)
|
if (candb_reset(h) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (reset_state_running){
|
if (reset_state_running){
|
||||||
if (plugin_reset_state(h, running_db) < 0)
|
if (plugin_reset_state(h, "running") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Call plugin_start */
|
/* Call plugin_start */
|
||||||
|
|
@ -549,7 +530,7 @@ main(int argc, char **argv)
|
||||||
*(argv-1) = tmp;
|
*(argv-1) = tmp;
|
||||||
|
|
||||||
if (reload_running){
|
if (reload_running){
|
||||||
if (candidate_commit(h, candidate_db, running_db) < 0)
|
if (candidate_commit(h, "candidate") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -558,17 +539,16 @@ main(int argc, char **argv)
|
||||||
-r replace running (obsolete)
|
-r replace running (obsolete)
|
||||||
*/
|
*/
|
||||||
if (app_config_file)
|
if (app_config_file)
|
||||||
if (rundb_main(h, app_config_file, running_db) < 0)
|
if (rundb_main(h, app_config_file) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Initiate the shared candidate. Maybe we should not do this? */
|
/* Initiate the shared candidate. Maybe we should not do this? */
|
||||||
if (file_cp(running_db, candidate_db) < 0){
|
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||||
clicon_err(OE_UNIX, errno, "FATAL: file_cp");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
#ifdef OBSOLETE
|
||||||
/* XXX Hack for now. Change mode so that we all can write. Security issue*/
|
/* XXX Hack for now. Change mode so that we all can write. Security issue*/
|
||||||
chmod(candidate_db, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
chmod(candidate_db, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||||
|
#endif
|
||||||
if (once)
|
if (once)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
@ -579,7 +559,7 @@ main(int argc, char **argv)
|
||||||
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG);
|
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG);
|
||||||
if (daemon(0, 0) < 0){
|
if (daemon(0, 0) < 0){
|
||||||
fprintf(stderr, "config: daemon");
|
fprintf(stderr, "config: daemon");
|
||||||
exit(0);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Write pid-file */
|
/* Write pid-file */
|
||||||
|
|
|
||||||
|
|
@ -69,57 +69,17 @@ static int xml2csv(FILE *f, cxobj *x, cvec *cvv);
|
||||||
* shared - all users share a common candidate db
|
* shared - all users share a common candidate db
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
init_candidate_db(clicon_handle h, enum candidate_db_type type)
|
init_candidate_db(clicon_handle h)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct stat sb;
|
|
||||||
char *running_db;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
if (xmldb_exists(h, "running") != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: RUNNING_CANDIDATE_DB option not set", __FUNCTION__);
|
clicon_err(OE_FATAL, 0, "Running db does not exist");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
if (xmldb_exists(h, "candidate") != 1)
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: CLICON_CANDIDATE_DB option not set", __FUNCTION__);
|
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
cli_set_candidate_type(h, type);
|
|
||||||
switch(type){
|
|
||||||
case CANDIDATE_DB_NONE:
|
|
||||||
break;
|
|
||||||
case CANDIDATE_DB_PRIVATE:
|
|
||||||
if (lstat(candidate_db, &sb) < 0){
|
|
||||||
if (file_cp(running_db, candidate_db) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "Error when copying %s to %s",
|
|
||||||
running_db, candidate_db);
|
|
||||||
unlink(candidate_db);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANDIDATE_DB_SHARED:
|
|
||||||
if (lstat(running_db, &sb) < 0){
|
|
||||||
clicon_err(OE_FATAL, 0, "Running db (%s) does not exist",
|
|
||||||
running_db);
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
if (lstat(candidate_db, &sb) < 0){
|
|
||||||
if (cli_send2backend(h)) {
|
|
||||||
clicon_rpc_copy(h, running_db, candidate_db);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (file_cp(running_db, candidate_db) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "Error when copying %s to %s",
|
|
||||||
running_db, candidate_db);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANDIDATE_DB_CURRENT:
|
|
||||||
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", running_db);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
err:
|
err:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -132,18 +92,6 @@ init_candidate_db(clicon_handle h, enum candidate_db_type type)
|
||||||
int
|
int
|
||||||
exit_candidate_db(clicon_handle h)
|
exit_candidate_db(clicon_handle h)
|
||||||
{
|
{
|
||||||
// struct stat sb;
|
|
||||||
|
|
||||||
switch(cli_candidate_type(h)){
|
|
||||||
case CANDIDATE_DB_PRIVATE:
|
|
||||||
#if 0 /* XXX: maybe we should remove it, but I want several cli:s to edit it */
|
|
||||||
if (lstat(clicon_candidate_db(h), &sb) == 0)
|
|
||||||
unlink(clicon_candidate_db(h));
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,10 +113,8 @@ cli_debug(clicon_handle h, cvec *vars, cg_var *arg)
|
||||||
/* cli */
|
/* cli */
|
||||||
clicon_debug_init(level, NULL); /* 0: dont debug, 1:debug */
|
clicon_debug_init(level, NULL); /* 0: dont debug, 1:debug */
|
||||||
/* config daemon */
|
/* config daemon */
|
||||||
if (cli_send2backend(h)) {
|
if (clicon_rpc_debug(h, level) < 0)
|
||||||
if (clicon_rpc_debug(h, level) < 0)
|
goto done;
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
done:
|
done:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -351,29 +297,20 @@ cli_quit(clicon_handle h, cvec *vars, cg_var *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Generic commit callback
|
||||||
* Generic commit callback
|
* @param[in] arg If 1, then snapshot and copy to startup config
|
||||||
* if arg is 1, then snapshot and copy to startup config
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_commit(clicon_handle h, cvec *vars, cg_var *arg)
|
cli_commit(clicon_handle h,
|
||||||
|
cvec *vars,
|
||||||
|
cg_var *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int snapshot = arg?cv_int32_get(arg):0;
|
int snapshot = arg?cv_int32_get(arg):0;
|
||||||
char *candidate;
|
|
||||||
char *running;
|
|
||||||
|
|
||||||
if ((running = clicon_running_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((retval = clicon_rpc_commit(h,
|
if ((retval = clicon_rpc_commit(h,
|
||||||
running,
|
"running",
|
||||||
candidate,
|
"candidate",
|
||||||
snapshot, /* snapshot */
|
snapshot, /* snapshot */
|
||||||
snapshot)) < 0){ /* startup */
|
snapshot)) < 0){ /* startup */
|
||||||
cli_output(stderr, "Commit failed. Edit and try again or discard changes\n");
|
cli_output(stderr, "Commit failed. Edit and try again or discard changes\n");
|
||||||
|
|
@ -390,17 +327,10 @@ cli_commit(clicon_handle h, cvec *vars, cg_var *arg)
|
||||||
int
|
int
|
||||||
cli_validate(clicon_handle h, cvec *vars, cg_var *arg)
|
cli_validate(clicon_handle h, cvec *vars, cg_var *arg)
|
||||||
{
|
{
|
||||||
char *candidate_db;
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
if ((retval = clicon_rpc_validate(h, "candidate")) < 0)
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
cli_output(stderr, "Validate failed. Edit and try again or discard changes\n");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (cli_send2backend(h)) {
|
|
||||||
if ((retval = clicon_rpc_validate(h, candidate_db)) < 0)
|
|
||||||
cli_output(stderr, "Validate failed. Edit and try again or discard changes\n");
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -447,7 +377,6 @@ expand_dbvar_dbxml(void *h,
|
||||||
char ***commands,
|
char ***commands,
|
||||||
char ***helptexts)
|
char ***helptexts)
|
||||||
{
|
{
|
||||||
char *dbname;
|
|
||||||
int nvec;
|
int nvec;
|
||||||
char **vec = NULL;
|
char **vec = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -457,10 +386,11 @@ expand_dbvar_dbxml(void *h,
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
char *xk = NULL;
|
char *xk = NULL;
|
||||||
cxobj **xvec = NULL;
|
cxobj **xvec = NULL;
|
||||||
|
size_t xlen = 0;
|
||||||
|
cxobj *x;
|
||||||
|
char *bodystr;
|
||||||
int i;
|
int i;
|
||||||
int i0;
|
int i0;
|
||||||
size_t xlen;
|
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
|
@ -472,37 +402,34 @@ expand_dbvar_dbxml(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
dbstr = vec[0];
|
dbstr = vec[0];
|
||||||
if (strcmp(dbstr, "running") == 0)
|
if (strcmp(dbstr, "running") != 0 &&
|
||||||
dbname = clicon_running_db(h);
|
strcmp(dbstr, "candidate") != 0){
|
||||||
else
|
|
||||||
if (strcmp(dbstr, "candidate") == 0)
|
|
||||||
dbname = clicon_candidate_db(h);
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (dbname == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
xkfmt = vec[1];
|
xkfmt = vec[1];
|
||||||
/* xkfmt = /interface/%s/address/%s
|
/* xkfmt = /interface/%s/address/%s
|
||||||
--> ^/interface/eth0/address/.*$
|
--> ^/interface/eth0/address/.*$
|
||||||
--> /interface/[name=eth0]/address
|
--> /interface/[name=eth0]/address
|
||||||
*/
|
*/
|
||||||
if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0)
|
if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, dbstr, xk, 1, &xt, &xvec, &xlen) < 0)
|
||||||
if (xmldb_get_vec(dbname, xk, yspec, &xt, &xvec, &xlen) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
i0 = *nr;
|
i0 = *nr;
|
||||||
*nr += xlen;
|
*nr += xlen;
|
||||||
if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) {
|
if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) {
|
||||||
clicon_err(OE_UNDEF, errno, "realloc: %s", strerror (errno));
|
clicon_err(OE_UNIX, errno, "realloc: %s", strerror (errno));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
for (i = 0; i < xlen; i++)
|
for (i = 0; i < xlen; i++) {
|
||||||
(*commands)[i0+i] = strdup(xml_body(xvec[i]));
|
x = xvec[i];
|
||||||
|
if ((bodystr = xml_body(x)) == NULL){
|
||||||
|
clicon_err(OE_CFG, 0, "No xml body");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*commands)[i0+i] = strdup(bodystr);
|
||||||
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
unchunk_group(__FUNCTION__);
|
unchunk_group(__FUNCTION__);
|
||||||
|
|
@ -634,14 +561,16 @@ expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail)
|
||||||
/*! Compare two dbs using XML. Write to file and run diff
|
/*! Compare two dbs using XML. Write to file and run diff
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
compare_xmls(cxobj *xc1, cxobj *xc2, int astext)
|
compare_xmls(cxobj *xc1,
|
||||||
|
cxobj *xc2,
|
||||||
|
int astext)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
char filename1[MAXPATHLEN];
|
char filename1[MAXPATHLEN];
|
||||||
char filename2[MAXPATHLEN];
|
char filename2[MAXPATHLEN];
|
||||||
char cmd[MAXPATHLEN];
|
char cmd[MAXPATHLEN];
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
|
|
||||||
snprintf(filename1, sizeof(filename1), "/tmp/cliconXXXXXX");
|
snprintf(filename1, sizeof(filename1), "/tmp/cliconXXXXXX");
|
||||||
|
|
@ -701,20 +630,10 @@ compare_dbs(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
cxobj *xc1 = NULL; /* running xml */
|
cxobj *xc1 = NULL; /* running xml */
|
||||||
cxobj *xc2 = NULL; /* candidate xml */
|
cxobj *xc2 = NULL; /* candidate xml */
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *running;
|
|
||||||
char *candidate;
|
|
||||||
|
|
||||||
if ((running = clicon_running_db(h)) == NULL){
|
if (xmldb_get(h, "running", "/", 0, &xc1, NULL, NULL) < 0)
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
if (xmldb_get(h, "candidate", "/", 0, &xc2, NULL, NULL) < 0)
|
||||||
if ((candidate = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (xmldb_get(running, "/", clicon_dbspec_yang(h), &xc1) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xmldb_get(candidate, "/", clicon_dbspec_yang(h), &xc2) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if (compare_xmls(xc1, xc2, arg?cv_int32_get(arg):0) < 0) /* astext? */
|
if (compare_xmls(xc1, xc2, arg?cv_int32_get(arg):0) < 0) /* astext? */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -752,13 +671,10 @@ cli_dbxml(clicon_handle h,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *candidate;
|
|
||||||
char *running;
|
|
||||||
char *xkfmt; /* xml key format */
|
char *xkfmt; /* xml key format */
|
||||||
char *xk = NULL; /* xml key */
|
char *xk = NULL; /* xml key */
|
||||||
cg_var *cval;
|
cg_var *cval;
|
||||||
char *val = NULL;
|
char *val = NULL;
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clicon_rpc_xmlput(h, db, MERGE,"<interfaces><interface><name>eth0</name><type>hej</type></interface><interfaces>");
|
* clicon_rpc_xmlput(h, db, MERGE,"<interfaces><interface><name>eth0</name><type>hej</type></interface><interfaces>");
|
||||||
|
|
@ -772,14 +688,6 @@ cli_dbxml(clicon_handle h,
|
||||||
* Where is arg computed? In eg yang2cli_leaf, otherwise in yang_parse,..
|
* Where is arg computed? In eg yang2cli_leaf, otherwise in yang_parse,..
|
||||||
* Create string using cbuf and save that.
|
* Create string using cbuf and save that.
|
||||||
*/
|
*/
|
||||||
if ((candidate = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if ((running = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
xkfmt = cv_string_get(arg);
|
xkfmt = cv_string_get(arg);
|
||||||
if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0)
|
if (xmlkeyfmt2key(xkfmt, cvv, &xk) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -788,20 +696,11 @@ cli_dbxml(clicon_handle h,
|
||||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cli_send2backend(h)) {
|
if (clicon_rpc_change(h, "candidate", op, xk, val) < 0)
|
||||||
if (clicon_rpc_change(h, candidate, op, xk, val) < 0)
|
goto done;
|
||||||
|
if (clicon_autocommit(h)) {
|
||||||
|
if (clicon_rpc_commit(h, "running", "candidate", 0, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_autocommit(h)) {
|
|
||||||
if (clicon_rpc_commit(h, running, candidate, 0, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if (xmldb_put_xkey(candidate, xk, val, yspec, op) < 0)
|
|
||||||
goto done;
|
|
||||||
if (clicon_autocommit(h))
|
|
||||||
clicon_log(LOG_WARNING, "Cant combine no backend and autocommit");
|
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -863,7 +762,9 @@ cli_del(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
* @see save_config_file
|
* @see save_config_file
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
load_config_file(clicon_handle h, cvec *cvv, cg_var *arg)
|
load_config_file(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
@ -871,7 +772,6 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
char **vecp;
|
char **vecp;
|
||||||
char *filename;
|
char *filename;
|
||||||
int replace;
|
int replace;
|
||||||
char *dbname;
|
|
||||||
char *str;
|
char *str;
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
int nvec;
|
int nvec;
|
||||||
|
|
@ -882,7 +782,6 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
cxobj *xn;
|
cxobj *xn;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cbuf *cbxml;
|
cbuf *cbxml;
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
|
@ -916,57 +815,30 @@ load_config_file(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
filename = vecp[0];
|
filename = vecp[0];
|
||||||
if ((dbname = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (stat(filename, &st) < 0){
|
if (stat(filename, &st) < 0){
|
||||||
clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s\n",
|
clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s\n",
|
||||||
filename, strerror(errno));
|
filename, strerror(errno));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cli_send2backend(h)) {
|
/* Open and parse local file into xml */
|
||||||
/* Open and parse local file into xml */
|
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename);
|
||||||
clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename);
|
goto done;
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
|
||||||
goto done;
|
|
||||||
if ((xn = xml_child_i(xt, 0)) != NULL){
|
|
||||||
if ((cbxml = cbuf_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
x = NULL;
|
|
||||||
while ((x = xml_child_each(xn, x, -1)) != NULL)
|
|
||||||
if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_xmlput(h, dbname,
|
|
||||||
replace?OP_REPLACE:OP_MERGE,
|
|
||||||
cbuf_get(cbxml)) < 0)
|
|
||||||
goto done;
|
|
||||||
cbuf_free(cbxml);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else{
|
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
||||||
if (replace){
|
goto done;
|
||||||
if (unlink(dbname) < 0){
|
if ((xn = xml_child_i(xt, 0)) != NULL){
|
||||||
clicon_err(OE_UNIX, 0, "rm %s %s", filename, strerror(errno));
|
if ((cbxml = cbuf_new()) == NULL)
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (xmldb_init(dbname) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "%s: open(%s)", __FUNCTION__, filename);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
x = NULL;
|
||||||
if (clicon_xml_parse_file(fd, &xt, "</clicon>") < 0)
|
while ((x = xml_child_each(xn, x, -1)) != NULL)
|
||||||
goto done;
|
if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0)
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if ((xn = xml_child_i(xt, 0)) != NULL){
|
|
||||||
if (xmldb_put(dbname, xn, yspec, replace?OP_REPLACE:OP_MERGE) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
if (clicon_rpc_xmlput(h, "candidate",
|
||||||
|
replace?OP_REPLACE:OP_MERGE,
|
||||||
|
cbuf_get(cbxml)) < 0)
|
||||||
|
goto done;
|
||||||
|
cbuf_free(cbxml);
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -1001,7 +873,6 @@ save_config_file(clicon_handle h,
|
||||||
char **vec;
|
char **vec;
|
||||||
char **vecp;
|
char **vecp;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *dbname;
|
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
int nvec;
|
int nvec;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
@ -1009,7 +880,6 @@ save_config_file(clicon_handle h,
|
||||||
char *varstr;
|
char *varstr;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
FILE *f = NULL;
|
FILE *f = NULL;
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
|
@ -1025,20 +895,10 @@ save_config_file(clicon_handle h,
|
||||||
}
|
}
|
||||||
dbstr = vec[0];
|
dbstr = vec[0];
|
||||||
varstr = vec[1];
|
varstr = vec[1];
|
||||||
if (strcmp(dbstr, "running") == 0)
|
if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0) {
|
||||||
dbname = clicon_running_db(h);
|
|
||||||
else
|
|
||||||
if (strcmp(dbstr, "candidate") == 0)
|
|
||||||
dbname = clicon_candidate_db(h);
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (dbname == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "dbname not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cv = cvec_find_var(cvv, varstr)) == NULL){
|
if ((cv = cvec_find_var(cvv, varstr)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1048,8 +908,7 @@ save_config_file(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
filename = vecp[0];
|
filename = vecp[0];
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, dbstr, "/", 0, &xt, NULL, NULL) < 0)
|
||||||
if (xmldb_get(dbname, "/", yspec, &xt) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
if ((f = fopen(filename, "wb")) == NULL){
|
if ((f = fopen(filename, "wb")) == NULL){
|
||||||
clicon_err(OE_CFG, errno, "Creating file %s", filename);
|
clicon_err(OE_CFG, errno, "Creating file %s", filename);
|
||||||
|
|
@ -1074,7 +933,6 @@ save_config_file(clicon_handle h,
|
||||||
int
|
int
|
||||||
delete_all(clicon_handle h, cvec *cvv, cg_var *arg)
|
delete_all(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
{
|
{
|
||||||
char *dbname;
|
|
||||||
char *dbstr;
|
char *dbstr;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -1082,31 +940,14 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strcmp(dbstr, "running") == 0)
|
if (strcmp(dbstr, "running") != 0 && strcmp(dbstr, "candidate") != 0){
|
||||||
dbname = clicon_running_db(h);
|
|
||||||
else
|
|
||||||
if (strcmp(dbstr, "candidate") == 0)
|
|
||||||
dbname = clicon_candidate_db(h);
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (dbname == NULL){
|
if (xmldb_delete(h, dbstr) < 0)
|
||||||
clicon_err(OE_FATAL, 0, "dbname not set");
|
goto done;
|
||||||
|
if (xmldb_init(h, dbstr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
if (cli_send2backend(h)) {
|
|
||||||
clicon_rpc_rm(h, dbname);
|
|
||||||
clicon_rpc_initdb(h, dbname);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if (unlink(dbname) < 0){
|
|
||||||
clicon_err(OE_FATAL, errno, "unlink(%s)", dbname);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (xmldb_init(dbname) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -1118,22 +959,7 @@ delete_all(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
int
|
int
|
||||||
discard_changes(clicon_handle h, cvec *cvv, cg_var *arg)
|
discard_changes(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
{
|
{
|
||||||
char *running_db;
|
return xmldb_copy(h, "running", "candidate");
|
||||||
char *candidate_db;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
clicon_rpc_copy(h, running_db, candidate_db);
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic function for showing configurations.
|
/*! Generic function for showing configurations.
|
||||||
|
|
@ -1157,12 +983,11 @@ show_conf_xmldb_as(clicon_handle h,
|
||||||
cxobj **xt) /* top xml */
|
cxobj **xt) /* top xml */
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *dbname;
|
char *db;
|
||||||
char **vec = NULL;
|
char **vec = NULL;
|
||||||
int nvec;
|
int nvec;
|
||||||
char *str;
|
char *str;
|
||||||
char *xpath;
|
char *xpath;
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
|
@ -1177,22 +1002,13 @@ show_conf_xmldb_as(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Dont get attr here, take it from arg instead */
|
/* Dont get attr here, take it from arg instead */
|
||||||
if (strcmp(vec[0], "running") == 0) /* XXX: hardcoded */
|
db = vec[0];
|
||||||
dbname = clicon_running_db(h);
|
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) {
|
||||||
else
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", db);
|
||||||
if (strcmp(vec[0], "candidate") == 0) /* XXX: hardcoded */
|
|
||||||
dbname = clicon_candidate_db(h);
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", vec[0]);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (dbname == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "dbname not set");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
xpath = vec[1];
|
xpath = vec[1];
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, db, xpath, 0, xt, NULL, NULL) < 0)
|
||||||
if (xmldb_get(dbname, xpath, yspec, xt) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -1272,11 +1088,8 @@ int
|
||||||
show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *dbname;
|
|
||||||
char **vec = NULL;
|
|
||||||
char *str;
|
char *str;
|
||||||
char *xpath;
|
char *xpath;
|
||||||
yang_spec *yspec;
|
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj **xv = NULL;
|
cxobj **xv = NULL;
|
||||||
|
|
@ -1288,23 +1101,13 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Dont get attr here, take it from arg instead */
|
/* Dont get attr here, take it from arg instead */
|
||||||
if (strcmp(str, "running") == 0) /* XXX: hardcoded */
|
if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){
|
||||||
dbname = clicon_running_db(h);
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
||||||
else
|
|
||||||
if (strcmp(str, "candidate") == 0) /* XXX: hardcoded */
|
|
||||||
dbname = clicon_candidate_db(h);
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", vec[0]);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (dbname == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "dbname not set");
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cv = cvec_find_var(cvv, "xpath");
|
cv = cvec_find_var(cvv, "xpath");
|
||||||
xpath = cv_string_get(cv);
|
xpath = cv_string_get(cv);
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, str, xpath, 1, &xt, &xv, &xlen) < 0)
|
||||||
if (xmldb_get_vec(dbname, xpath, yspec, &xt, &xv, &xlen) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<xlen; i++)
|
for (i=0; i<xlen; i++)
|
||||||
clicon_xml2file(stdout, xv[i], 0, 1);
|
clicon_xml2file(stdout, xv[i], 0, 1);
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,6 @@ struct cli_handle {
|
||||||
/* ------ end of common handle ------ */
|
/* ------ end of common handle ------ */
|
||||||
cligen_handle cl_cligen; /* cligen handle */
|
cligen_handle cl_cligen; /* cligen handle */
|
||||||
|
|
||||||
int cl_send2backend; /* Send changes to configuration daemon */
|
|
||||||
enum candidate_db_type cl_candidate_type;
|
|
||||||
cli_syntax_t *cl_stx; /* syntax structure */
|
cli_syntax_t *cl_stx; /* syntax structure */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -96,7 +94,6 @@ cli_handle_init(void)
|
||||||
}
|
}
|
||||||
cligen_userhandle_set(clih, cl);
|
cligen_userhandle_set(clih, cl);
|
||||||
cl->cl_cligen = clih;
|
cl->cl_cligen = clih;
|
||||||
cl->cl_candidate_type = CANDIDATE_DB_SHARED;
|
|
||||||
h = (clicon_handle)cl;
|
h = (clicon_handle)cl;
|
||||||
done:
|
done:
|
||||||
return h;
|
return h;
|
||||||
|
|
@ -120,43 +117,8 @@ cli_handle_exit(clicon_handle h)
|
||||||
/*----------------------------------------------------------
|
/*----------------------------------------------------------
|
||||||
* cli-specific handle access functions
|
* cli-specific handle access functions
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
/*! Send changes to configuration daemon or let client handle it itself. Default is 1 */
|
|
||||||
int
|
|
||||||
cli_set_send2backend(clicon_handle h, int send2backend)
|
|
||||||
{
|
|
||||||
struct cli_handle *cl = handle(h);
|
|
||||||
|
|
||||||
cl->cl_send2backend = send2backend;
|
/*! Get current syntax-group */
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Get status of whether to send changes to configuration daemon. */
|
|
||||||
int
|
|
||||||
cli_send2backend(clicon_handle h)
|
|
||||||
{
|
|
||||||
struct cli_handle *cl = handle(h);
|
|
||||||
|
|
||||||
return cl->cl_send2backend;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum candidate_db_type
|
|
||||||
cli_candidate_type(clicon_handle h)
|
|
||||||
{
|
|
||||||
struct cli_handle *cl = handle(h);
|
|
||||||
|
|
||||||
return cl->cl_candidate_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
cli_set_candidate_type(clicon_handle h, enum candidate_db_type type)
|
|
||||||
{
|
|
||||||
struct cli_handle *cl = handle(h);
|
|
||||||
|
|
||||||
cl->cl_candidate_type = type;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Current syntax-group */
|
|
||||||
cli_syntax_t *
|
cli_syntax_t *
|
||||||
cli_syntax(clicon_handle h)
|
cli_syntax(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -164,8 +126,10 @@ cli_syntax(clicon_handle h)
|
||||||
return cl->cl_stx;
|
return cl->cl_stx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Set current syntax-group */
|
||||||
int
|
int
|
||||||
cli_syntax_set(clicon_handle h, cli_syntax_t *stx)
|
cli_syntax_set(clicon_handle h,
|
||||||
|
cli_syntax_t *stx)
|
||||||
{
|
{
|
||||||
struct cli_handle *cl = handle(h);
|
struct cli_handle *cl = handle(h);
|
||||||
cl->cl_stx = stx;
|
cl->cl_stx = stx;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
#include "cli_handle.h"
|
#include "cli_handle.h"
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define CLI_OPTS "hD:f:F:1u:d:m:cP:qpGLl:"
|
#define CLI_OPTS "hD:f:F:1u:d:m:qpGLl:"
|
||||||
|
|
||||||
/*! terminate cli application */
|
/*! terminate cli application */
|
||||||
static int
|
static int
|
||||||
|
|
@ -92,6 +92,7 @@ cli_signal_init (clicon_handle h)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Interactive CLI command loop
|
/*! Interactive CLI command loop
|
||||||
|
* @param[in] h CLICON handle
|
||||||
* @see cligen_loop
|
* @see cligen_loop
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
|
|
@ -132,8 +133,6 @@ usage(char *argv0, clicon_handle h)
|
||||||
"\t-u <sockpath>\tconfig UNIX domain path (default: %s)\n"
|
"\t-u <sockpath>\tconfig UNIX domain path (default: %s)\n"
|
||||||
"\t-d <dir>\tSpecify plugin directory (default: %s)\n"
|
"\t-d <dir>\tSpecify plugin directory (default: %s)\n"
|
||||||
"\t-m <mode>\tSpecify plugin syntax mode\n"
|
"\t-m <mode>\tSpecify plugin syntax mode\n"
|
||||||
"\t-c \t\tWrite to candidate db directly, not via config backend\n"
|
|
||||||
"\t-P <dbname> \tWrite to private database\n"
|
|
||||||
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
|
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
|
||||||
"\t-p \t\tPrint database yang specification\n"
|
"\t-p \t\tPrint database yang specification\n"
|
||||||
"\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n"
|
"\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n"
|
||||||
|
|
@ -152,8 +151,6 @@ int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
enum candidate_db_type dbtype;
|
|
||||||
char private_db[MAXPATHLEN];
|
|
||||||
int once;
|
int once;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
char *argv0 = argv[0];
|
char *argv0 = argv[0];
|
||||||
|
|
@ -163,8 +160,8 @@ main(int argc, char **argv)
|
||||||
int logclisyntax = 0;
|
int logclisyntax = 0;
|
||||||
int help = 0;
|
int help = 0;
|
||||||
char *treename;
|
char *treename;
|
||||||
char *running_db;
|
|
||||||
int logdst = CLICON_LOG_STDERR;
|
int logdst = CLICON_LOG_STDERR;
|
||||||
|
char *restarg; /* what remains after options */
|
||||||
|
|
||||||
/* Defaults */
|
/* Defaults */
|
||||||
|
|
||||||
|
|
@ -175,10 +172,7 @@ main(int argc, char **argv)
|
||||||
goto done;
|
goto done;
|
||||||
if (cli_plugin_init(h) != 0)
|
if (cli_plugin_init(h) != 0)
|
||||||
goto done;
|
goto done;
|
||||||
dbtype = CANDIDATE_DB_SHARED;
|
|
||||||
once = 0;
|
once = 0;
|
||||||
private_db[0] = '\0';
|
|
||||||
cli_set_send2backend(h, 1); /* send changes to config daemon */
|
|
||||||
cli_set_comment(h, '#'); /* Default to handle #! clicon_cli scripts */
|
cli_set_comment(h, '#'); /* Default to handle #! clicon_cli scripts */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -269,13 +263,6 @@ main(int argc, char **argv)
|
||||||
usage(argv[0], h);
|
usage(argv[0], h);
|
||||||
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
|
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
|
||||||
break;
|
break;
|
||||||
case 'c' : /* No config daemon (used in bootstrapping and file load) */
|
|
||||||
cli_set_send2backend(h, 0);
|
|
||||||
break;
|
|
||||||
case 'P' : /* load to private database with given name */
|
|
||||||
dbtype = CANDIDATE_DB_PRIVATE;
|
|
||||||
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", optarg); /* override default */
|
|
||||||
break;
|
|
||||||
case 'q' : /* Quiet mode */
|
case 'q' : /* Quiet mode */
|
||||||
clicon_option_str_set(h, "CLICON_QUIET", "on");
|
clicon_option_str_set(h, "CLICON_QUIET", "on");
|
||||||
break;
|
break;
|
||||||
|
|
@ -359,25 +346,12 @@ main(int argc, char **argv)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize databases */
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (strlen(private_db))
|
|
||||||
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", private_db);
|
|
||||||
|
|
||||||
if (!cli_send2backend(h))
|
|
||||||
if (xmldb_init(running_db) < 0){
|
|
||||||
fprintf (stderr, "FATAL: Could not init running_db. (Run as root?)\n");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* A client does not have access to the candidate (and running)
|
/* A client does not have access to the candidate (and running)
|
||||||
databases if both these conditions are true:
|
databases if both these conditions are true:
|
||||||
1. clicon_sock_family(h) == AF_INET[6]
|
1. clicon_sock_family(h) == AF_INET[6]
|
||||||
2. cli_send2backend(h) == 1
|
|
||||||
*/
|
*/
|
||||||
if (clicon_sock_family(h) == AF_UNIX || cli_send2backend(h)==0)
|
if (clicon_sock_family(h) == AF_UNIX)
|
||||||
if (init_candidate_db(h, dbtype) < 0)
|
if (init_candidate_db(h) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (logclisyntax)
|
if (logclisyntax)
|
||||||
|
|
@ -386,19 +360,29 @@ main(int argc, char **argv)
|
||||||
if (debug)
|
if (debug)
|
||||||
clicon_option_dump(h, debug);
|
clicon_option_dump(h, debug);
|
||||||
|
|
||||||
|
|
||||||
|
/* Join rest of argv to a single command */
|
||||||
|
restarg = clicon_strjoin(argc, argv, " ", __FUNCTION__);
|
||||||
|
|
||||||
/* Call start function in all plugins before we go interactive
|
/* Call start function in all plugins before we go interactive
|
||||||
Pass all args after the standard options to plugin_start
|
Pass all args after the standard options to plugin_start
|
||||||
*/
|
*/
|
||||||
|
|
||||||
tmp = *(argv-1);
|
tmp = *(argv-1);
|
||||||
*(argv-1) = argv0;
|
*(argv-1) = argv0;
|
||||||
cli_plugin_start(h, argc+1, argv-1);
|
cli_plugin_start(h, argc+1, argv-1);
|
||||||
*(argv-1) = tmp;
|
*(argv-1) = tmp;
|
||||||
|
|
||||||
/* Launch interfactive event loop, unless -1 */
|
/* Launch interfactive event loop, unless -1 */
|
||||||
if (once == 0)
|
if (restarg != NULL && strlen(restarg)){
|
||||||
|
char *mode = cli_syntax_mode(h);
|
||||||
|
int result;
|
||||||
|
clicon_parse(h, restarg, &mode, &result);
|
||||||
|
}
|
||||||
|
/* Go into event-loop unless -1 command-line */
|
||||||
|
if (!once)
|
||||||
cli_interactive(h);
|
cli_interactive(h);
|
||||||
done:
|
done:
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
// Gets in your face if we log on stderr
|
// Gets in your face if we log on stderr
|
||||||
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
|
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
|
||||||
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
|
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
|
||||||
|
|
|
||||||
|
|
@ -31,18 +31,6 @@
|
||||||
#define CLI_PROMPT_LEN 64
|
#define CLI_PROMPT_LEN 64
|
||||||
#define CLI_DEFAULT_PROMPT ">"
|
#define CLI_DEFAULT_PROMPT ">"
|
||||||
|
|
||||||
/*
|
|
||||||
* Types
|
|
||||||
*/
|
|
||||||
//typedef void *cli_handle; /* clicon cli handle, see struct cli_handle */
|
|
||||||
enum candidate_db_type{
|
|
||||||
CANDIDATE_DB_NONE, /* No candidate */
|
|
||||||
CANDIDATE_DB_PRIVATE, /* Create a private candidate_db */
|
|
||||||
CANDIDATE_DB_SHARED, /* Share the candidate with everyone else */
|
|
||||||
CANDIDATE_DB_CURRENT /* Dont create candidate, use current directly */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function Declarations
|
* Function Declarations
|
||||||
*/
|
*/
|
||||||
|
|
@ -62,16 +50,12 @@ char cli_set_comment(clicon_handle h, char c);
|
||||||
char cli_comment(clicon_handle h);
|
char cli_comment(clicon_handle h);
|
||||||
int cli_set_exiting(clicon_handle h, int exiting);
|
int cli_set_exiting(clicon_handle h, int exiting);
|
||||||
int cli_exiting(clicon_handle h);
|
int cli_exiting(clicon_handle h);
|
||||||
int cli_set_send2backend(clicon_handle h, int send2backend);
|
|
||||||
int cli_send2backend(clicon_handle h);
|
|
||||||
clicon_handle cli_handle_init(void);
|
clicon_handle cli_handle_init(void);
|
||||||
int cli_handle_exit(clicon_handle h);
|
int cli_handle_exit(clicon_handle h);
|
||||||
cligen_handle cli_cligen(clicon_handle h);
|
cligen_handle cli_cligen(clicon_handle h);
|
||||||
enum candidate_db_type cli_candidate_type(clicon_handle h);
|
|
||||||
int cli_set_candidate_type(clicon_handle h, enum candidate_db_type type);
|
|
||||||
|
|
||||||
/* cli_common.c */
|
/* cli_common.c */
|
||||||
int init_candidate_db(clicon_handle h, enum candidate_db_type type);
|
int init_candidate_db(clicon_handle h);
|
||||||
int exit_candidate_db(clicon_handle h);
|
int exit_candidate_db(clicon_handle h);
|
||||||
#define cli_output cligen_output
|
#define cli_output cligen_output
|
||||||
int cli_set (clicon_handle h, cvec *vars, cg_var *arg);
|
int cli_set (clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
#include <clixon/clixon.h>
|
#include <clixon/clixon.h>
|
||||||
|
|
||||||
/* Command line options to be passed to getopt(3) */
|
/* Command line options to be passed to getopt(3) */
|
||||||
#define DBCTRL_OPTS "hDd:pbn:r:m:Zi"
|
#define DBCTRL_OPTS "hDSd:pbn:r:m:Zi"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove_entry
|
* remove_entry
|
||||||
|
|
@ -65,8 +65,7 @@ remove_entry(char *dbname, char *key)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! usage
|
||||||
* usage
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
usage(char *argv0)
|
usage(char *argv0)
|
||||||
|
|
@ -75,7 +74,8 @@ usage(char *argv0)
|
||||||
"where options are\n"
|
"where options are\n"
|
||||||
"\t-h\t\tHelp\n"
|
"\t-h\t\tHelp\n"
|
||||||
"\t-D\t\tDebug\n"
|
"\t-D\t\tDebug\n"
|
||||||
"\t-d <dbname>\tDatabase name (default: running_db)\n"
|
"\t-S\t\tLog on syslog\n"
|
||||||
|
"\t-d <db>\tDatabase name (default: running)\n"
|
||||||
"\t-p\t\tDump database on stdout\n"
|
"\t-p\t\tDump database on stdout\n"
|
||||||
"\t-b\t\tBrief output, just print keys. Combine with -p or -m\n"
|
"\t-b\t\tBrief output, just print keys. Combine with -p or -m\n"
|
||||||
"\t-n \"<key> <val>\" Add database entry\n"
|
"\t-n \"<key> <val>\" Add database entry\n"
|
||||||
|
|
@ -101,9 +101,8 @@ main(int argc, char **argv)
|
||||||
char *addstr;
|
char *addstr;
|
||||||
char rmkey[MAXPATHLEN];
|
char rmkey[MAXPATHLEN];
|
||||||
int brief;
|
int brief;
|
||||||
char dbname[MAXPATHLEN] = {0,};
|
char db[MAXPATHLEN] = {0,};
|
||||||
int use_syslog;
|
int use_syslog;
|
||||||
yang_spec *yspec;
|
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
|
|
||||||
/* In the startup, logs to stderr & debug flag set later */
|
/* In the startup, logs to stderr & debug flag set later */
|
||||||
|
|
@ -118,6 +117,7 @@ main(int argc, char **argv)
|
||||||
brief = 0;
|
brief = 0;
|
||||||
use_syslog = 0;
|
use_syslog = 0;
|
||||||
addstr = NULL;
|
addstr = NULL;
|
||||||
|
memcpy(db, "running", strlen("running")+1);
|
||||||
memset(rmkey, '\0', sizeof(rmkey));
|
memset(rmkey, '\0', sizeof(rmkey));
|
||||||
|
|
||||||
if ((h = clicon_handle_init()) == NULL)
|
if ((h = clicon_handle_init()) == NULL)
|
||||||
|
|
@ -143,6 +143,7 @@ main(int argc, char **argv)
|
||||||
use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR);
|
use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR);
|
||||||
clicon_debug_init(debug, NULL);
|
clicon_debug_init(debug, NULL);
|
||||||
|
|
||||||
|
|
||||||
/* Now rest of options */
|
/* Now rest of options */
|
||||||
optind = 1;
|
optind = 1;
|
||||||
while ((c = getopt(argc, argv, DBCTRL_OPTS)) != -1)
|
while ((c = getopt(argc, argv, DBCTRL_OPTS)) != -1)
|
||||||
|
|
@ -159,8 +160,8 @@ main(int argc, char **argv)
|
||||||
case 'b': /* Dump/print/match database brief (combone w -p or -m) */
|
case 'b': /* Dump/print/match database brief (combone w -p or -m) */
|
||||||
brief++;
|
brief++;
|
||||||
break;
|
break;
|
||||||
case 'd': /* dbname */
|
case 'd': /* db either db filename or symbolic: running|candidate */
|
||||||
if (!optarg || sscanf(optarg, "%s", dbname) != 1)
|
if (!optarg || sscanf(optarg, "%s", db) != 1)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
break;
|
break;
|
||||||
case 'n': /* add database entry */
|
case 'n': /* add database entry */
|
||||||
|
|
@ -189,33 +190,32 @@ main(int argc, char **argv)
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
if (*dbname == '\0'){
|
if (*db == '\0'){
|
||||||
clicon_err(OE_FATAL, 0, "database not specified (with -d <db>): %s");
|
clicon_err(OE_FATAL, 0, "database not specified (with -d <db>): %s");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if (dumpdb){
|
if (dumpdb){
|
||||||
if (xmldb_dump(stdout, dbname, matchkey)) {
|
/* Here db must be local file-path */
|
||||||
|
if (xmldb_dump(stdout, db, matchkey)) {
|
||||||
fprintf(stderr, "Match error\n");
|
fprintf(stderr, "Match error\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addent) /* add entry */
|
if (addent) /* add entry */
|
||||||
if (xmldb_put_xkey(dbname, addstr, NULL, yspec, OP_REPLACE) < 0)
|
if (xmldb_put_xkey(h, db, addstr, NULL, OP_REPLACE) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (rment)
|
if (rment)
|
||||||
if (remove_entry(dbname, rmkey) < 0)
|
if (remove_entry(db, rmkey) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (zapdb) /* remove databases */
|
if (zapdb) /* remove databases */
|
||||||
/* XXX This assumes direct access to database */
|
/* XXX This assumes direct access to database */
|
||||||
if (unlink(dbname) < 0){
|
if (xmldb_delete(h, db) < 0){
|
||||||
clicon_err(OE_FATAL, errno, "unlink %s", dbname);
|
clicon_err(OE_FATAL, errno, "xmldb_delete %s", db);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (initdb)
|
if (initdb)
|
||||||
if (xmldb_init(dbname) < 0)
|
if (xmldb_init(h, db) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,56 +173,25 @@ detect_endtag(char *tag, char ch, int *state)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* target_locked
|
|
||||||
* return 1 if locked, 0 if not.
|
|
||||||
* return clientid if locked.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
target_locked(enum target_type target, int *client)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* unlock_target
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
unlock_target(enum target_type target)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
lock_target(enum target_type target)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Get "target" attribute, return actual database given candidate or running
|
/*! Get "target" attribute, return actual database given candidate or running
|
||||||
* Caller must do error handling
|
* Caller must do error handling
|
||||||
* @retval dbname Actual database file name
|
* @retval dbname Actual database file name
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
netconf_get_target(clicon_handle h, cxobj *xn, char *path)
|
netconf_get_target(clicon_handle h,
|
||||||
|
cxobj *xn,
|
||||||
|
char *path)
|
||||||
{
|
{
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *target = NULL;
|
char *target = NULL;
|
||||||
char *running_db;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if ((x = xpath_first(xn, path)) != NULL){
|
if ((x = xpath_first(xn, path)) != NULL){
|
||||||
if (xpath_first(x, "candidate") != NULL)
|
if (xpath_first(x, "candidate") != NULL)
|
||||||
target = candidate_db;
|
target = "candidate";
|
||||||
else
|
else
|
||||||
if (xpath_first(x, "running") != NULL)
|
if (xpath_first(x, "running") != NULL)
|
||||||
target = running_db;
|
target = "running";
|
||||||
}
|
}
|
||||||
done:
|
|
||||||
return target;
|
return target;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,11 @@
|
||||||
|
|
||||||
/*! Process incoming packet
|
/*! Process incoming packet
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xf Packet buffer
|
* @param[in] cb Packet buffer
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
process_incoming_packet(clicon_handle h,
|
process_incoming_packet(clicon_handle h,
|
||||||
cbuf *xf)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
char *str0;
|
char *str0;
|
||||||
|
|
@ -76,23 +76,23 @@ process_incoming_packet(clicon_handle h,
|
||||||
cbuf *xf1;
|
cbuf *xf1;
|
||||||
|
|
||||||
clicon_debug(1, "RECV");
|
clicon_debug(1, "RECV");
|
||||||
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(xf));
|
clicon_debug(2, "%s: RCV: \"%s\"", __FUNCTION__, cbuf_get(cb));
|
||||||
if ((str0 = strdup(cbuf_get(xf))) == NULL){
|
if ((str0 = strdup(cbuf_get(cb))) == NULL){
|
||||||
clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno));
|
clicon_log(LOG_ERR, "%s: strdup: %s", __FUNCTION__, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
str = str0;
|
str = str0;
|
||||||
/* Parse incoming XML message */
|
/* Parse incoming XML message */
|
||||||
if (clicon_xml_parse_string(&str, &xml_req) < 0){
|
if (clicon_xml_parse_string(&str, &xml_req) < 0){
|
||||||
if ((xf = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
netconf_create_rpc_error(xf, NULL,
|
netconf_create_rpc_error(cb, NULL,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"rpc", "error",
|
"rpc", "error",
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
netconf_output(1, xf, "rpc-error");
|
netconf_output(1, cb, "rpc-error");
|
||||||
cbuf_free(xf);
|
cbuf_free(cb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
|
clicon_log(LOG_ERR, "%s: cbuf_new", __FUNCTION__);
|
||||||
|
|
@ -181,12 +181,12 @@ netconf_input_cb(int s,
|
||||||
unsigned char buf[BUFSIZ];
|
unsigned char buf[BUFSIZ];
|
||||||
int i;
|
int i;
|
||||||
int len;
|
int len;
|
||||||
static cbuf *xf; /* XXX: should use ce state? */
|
static cbuf *cb; /* XXX: should use ce state? */
|
||||||
int xml_state = 0;
|
int xml_state = 0;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (xf == NULL)
|
if (cb == NULL)
|
||||||
if ((xf = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
@ -209,22 +209,22 @@ netconf_input_cb(int s,
|
||||||
for (i=0; i<len; i++){
|
for (i=0; i<len; i++){
|
||||||
if (buf[i] == 0)
|
if (buf[i] == 0)
|
||||||
continue; /* Skip NULL chars (eg from terminals) */
|
continue; /* Skip NULL chars (eg from terminals) */
|
||||||
cprintf(xf, "%c", buf[i]);
|
cprintf(cb, "%c", buf[i]);
|
||||||
if (detect_endtag("]]>]]>",
|
if (detect_endtag("]]>]]>",
|
||||||
buf[i],
|
buf[i],
|
||||||
&xml_state)) {
|
&xml_state)) {
|
||||||
/* OK, we have an xml string from a client */
|
/* OK, we have an xml string from a client */
|
||||||
if (process_incoming_packet(h, xf) < 0){
|
if (process_incoming_packet(h, cb) < 0){
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cc_closed)
|
if (cc_closed)
|
||||||
break;
|
break;
|
||||||
cbuf_reset(xf);
|
cbuf_reset(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
// cbuf_free(xf);
|
// cbuf_free(cb);
|
||||||
if (cc_closed)
|
if (cc_closed)
|
||||||
retval = -1;
|
retval = -1;
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -255,16 +255,15 @@ send_hello(int s)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from init_candidate_db() and clicon_rpc_copy() */
|
/*! Initialize candidate database */
|
||||||
static int
|
static int
|
||||||
init_candidate_db(clicon_handle h, char *running_db, char *candidate_db)
|
init_candidate_db(clicon_handle h)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
/* init shared candidate */
|
/* init shared candidate */
|
||||||
if (lstat(candidate_db, &sb) < 0){
|
if (xmldb_exists(h, "candidate") != 1){
|
||||||
if (clicon_rpc_copy(h, running_db, candidate_db) < 0)
|
if (xmldb_copy(h, "running", "candidate") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -316,8 +315,6 @@ main(int argc, char **argv)
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
clicon_handle h;
|
clicon_handle h;
|
||||||
int use_syslog;
|
int use_syslog;
|
||||||
char *running_db;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
/* Defaults */
|
/* Defaults */
|
||||||
use_syslog = 0;
|
use_syslog = 0;
|
||||||
|
|
@ -390,15 +387,7 @@ main(int argc, char **argv)
|
||||||
if (netconf_plugin_load(h) < 0)
|
if (netconf_plugin_load(h) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
if (init_candidate_db(h) < 0)
|
||||||
clicon_err(OE_FATAL, 0, "running db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
clicon_err(OE_FATAL, 0, "candidate db not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (init_candidate_db(h, running_db, candidate_db) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
/* Call start function is all plugins before we go interactive */
|
/* Call start function is all plugins before we go interactive */
|
||||||
tmp = *(argv-1);
|
tmp = *(argv-1);
|
||||||
|
|
|
||||||
|
|
@ -108,14 +108,13 @@ netconf_filter_xmldb(clicon_handle h,
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
cxobj *xfilterconf = NULL;
|
cxobj *xfilterconf = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_spec *ys = clicon_dbspec_yang(h);
|
|
||||||
char *selector;
|
char *selector;
|
||||||
|
|
||||||
/* Default subtree filter */
|
/* Default subtree filter */
|
||||||
switch (foption){
|
switch (foption){
|
||||||
case FILTER_SUBTREE:
|
case FILTER_SUBTREE:
|
||||||
/* Get the whole database as xml */
|
/* Get the whole database as xml */
|
||||||
if (xmldb_get(source, NULL, ys, &xdb) < 0){
|
if (xmldb_get(h, source, NULL, 0, &xdb, NULL, NULL) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"application",
|
"application",
|
||||||
|
|
@ -154,7 +153,7 @@ netconf_filter_xmldb(clicon_handle h,
|
||||||
break;
|
break;
|
||||||
case FILTER_XPATH:
|
case FILTER_XPATH:
|
||||||
selector = xml_find_value(xfilter, "select");
|
selector = xml_find_value(xfilter, "select");
|
||||||
if (xmldb_get(source, selector, ys, &xdb) < 0){
|
if (xmldb_get(h, source, selector, 0, &xdb, NULL, NULL) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"application",
|
"application",
|
||||||
|
|
@ -202,13 +201,13 @@ netconf_filter_xmldb(clicon_handle h,
|
||||||
|
|
||||||
<get-config>
|
<get-config>
|
||||||
<source>
|
<source>
|
||||||
<( candidate | running )/>
|
<candidate/> | <running/>
|
||||||
</source>
|
</source>
|
||||||
</get-config>
|
</get-config>
|
||||||
|
|
||||||
<get-config>
|
<get-config>
|
||||||
<source>
|
<source>
|
||||||
<( candidate | running )/>
|
<candidate/> | <running/>
|
||||||
</source>
|
</source>
|
||||||
<filter type="subtree">
|
<filter type="subtree">
|
||||||
<configuration>
|
<configuration>
|
||||||
|
|
@ -220,24 +219,6 @@ netconf_filter_xmldb(clicon_handle h,
|
||||||
<rpc><get-config><source><running /></source>
|
<rpc><get-config><source><running /></source>
|
||||||
<filter type="xpath" select="//SenderTwampIpv4"/>
|
<filter type="xpath" select="//SenderTwampIpv4"/>
|
||||||
</get-config></rpc>]]>]]>
|
</get-config></rpc>]]>]]>
|
||||||
* Call graph, client to backend and formats
|
|
||||||
* netconf_input_cb # client
|
|
||||||
* read
|
|
||||||
* process_incoming_packet #
|
|
||||||
* clicon_xml_parse_string #
|
|
||||||
* netconf_rpc_dispatch
|
|
||||||
* netconf_get_config #
|
|
||||||
* xpath_first
|
|
||||||
* netconf_filter #
|
|
||||||
* db2xml_key # "^.*$"
|
|
||||||
* clicon_dbitems # (db)
|
|
||||||
* db_regexp # (lvec)
|
|
||||||
* lvec2cvec # (cvec)
|
|
||||||
* cvec2xml # (xml)
|
|
||||||
* clicon_xml2cbuf # (xml->char*)
|
|
||||||
* wanted:
|
|
||||||
* netconf_get_config
|
|
||||||
* xpath(db, filter)
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_get_config(clicon_handle h,
|
netconf_get_config(clicon_handle h,
|
||||||
|
|
@ -276,7 +257,7 @@ netconf_get_config(clicon_handle h,
|
||||||
|
|
||||||
/*! Get options from netconf edit-config
|
/*! Get options from netconf edit-config
|
||||||
* <edit-config>
|
* <edit-config>
|
||||||
* <config>XXX</config>
|
* <config>...</config>
|
||||||
* <default-operation>(merge | none | replace)</default-operation>
|
* <default-operation>(merge | none | replace)</default-operation>
|
||||||
* <error-option>(stop-on-error | continue-on-error )</error-option>
|
* <error-option>(stop-on-error | continue-on-error )</error-option>
|
||||||
* <test-option>(set | test-then-set | test-only)</test-option>
|
* <test-option>(set | test-then-set | test-only)</test-option>
|
||||||
|
|
@ -418,20 +399,12 @@ netconf_edit_config(clicon_handle h,
|
||||||
cxobj *xc; /* config */
|
cxobj *xc; /* config */
|
||||||
cxobj *xcc; /* child of config */
|
cxobj *xcc; /* child of config */
|
||||||
char *target; /* db */
|
char *target; /* db */
|
||||||
char *candidate_db;
|
|
||||||
cbuf *cbxml = NULL;
|
cbuf *cbxml = NULL;
|
||||||
char *xmlstr;
|
char *xmlstr;
|
||||||
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* must have target, and it should be candidate */
|
/* must have target, and it should be candidate */
|
||||||
if ((target = netconf_get_target(h, xn, "target")) == NULL ||
|
if ((target = netconf_get_target(h, xn, "target")) == NULL ||
|
||||||
strcmp(target, candidate_db)){
|
strcmp(target, "candidate")){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"missing-element",
|
"missing-element",
|
||||||
"protocol",
|
"protocol",
|
||||||
|
|
@ -532,7 +505,7 @@ netconf_copy_config(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (clicon_rpc_copy(h, source, target) < 0){
|
if (xmldb_copy(h, source, target) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"protocol", "error",
|
"protocol", "error",
|
||||||
|
|
@ -546,7 +519,7 @@ netconf_copy_config(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Delete configuration
|
||||||
<delete-config>
|
<delete-config>
|
||||||
<target>
|
<target>
|
||||||
<candidate/>
|
<candidate/>
|
||||||
|
|
@ -564,15 +537,6 @@ netconf_delete_config(clicon_handle h,
|
||||||
{
|
{
|
||||||
char *target; /* filenames */
|
char *target; /* filenames */
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((target = netconf_get_target(h, xn, "target")) == NULL){
|
if ((target = netconf_get_target(h, xn, "target")) == NULL){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
|
|
@ -583,7 +547,7 @@ netconf_delete_config(clicon_handle h,
|
||||||
"<bad-element>target</bad-element>");
|
"<bad-element>target</bad-element>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (strcmp(target, candidate_db)){
|
if (strcmp(target, "candidate")){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"bad-element",
|
"bad-element",
|
||||||
"protocol",
|
"protocol",
|
||||||
|
|
@ -592,14 +556,14 @@ netconf_delete_config(clicon_handle h,
|
||||||
"<bad-element>target</bad-element>");
|
"<bad-element>target</bad-element>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_rm(h, target) < 0){
|
if (xmldb_delete(h, target) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"protocol", "error",
|
"protocol", "error",
|
||||||
NULL, "Internal error");
|
NULL, "Internal error");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_rpc_initdb(h, target) < 0){
|
if (xmldb_init(h, target) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"protocol", "error",
|
"protocol", "error",
|
||||||
|
|
@ -612,7 +576,7 @@ netconf_delete_config(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Close a (user) session
|
||||||
<close-session/>
|
<close-session/>
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -626,12 +590,13 @@ netconf_close_session(cxobj *xn,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Lock a database
|
||||||
<lock>
|
<lock>
|
||||||
<target>
|
<target>
|
||||||
<candidate/>
|
<candidate/>
|
||||||
</target>
|
</target>
|
||||||
</lock>
|
</lock>
|
||||||
|
XXX
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_lock(clicon_handle h,
|
netconf_lock(clicon_handle h,
|
||||||
|
|
@ -652,40 +617,20 @@ netconf_lock(clicon_handle h,
|
||||||
"<bad-element>source</bad-element>");
|
"<bad-element>source</bad-element>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#ifdef notyet
|
|
||||||
if (target_locked(&client) > 0){
|
|
||||||
snprintf(info, 64, "<session-id>%d</session-id>", client);
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"lock-denied",
|
|
||||||
"protocol",
|
|
||||||
"error",
|
|
||||||
"Lock failed, lock is already held",
|
|
||||||
info);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lock_target(target) < 0){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"lock-denied",
|
|
||||||
"protocol",
|
|
||||||
"error",
|
|
||||||
"Lock failed, lock is already held",
|
|
||||||
NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
netconf_ok_set(1);
|
netconf_ok_set(1);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Unlock a database
|
||||||
<unlock>
|
<unlock>
|
||||||
<target>
|
<target>
|
||||||
<candidate/>
|
<candidate/>
|
||||||
</target>
|
</target>
|
||||||
</unlock>
|
</unlock>
|
||||||
|
XXX
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_unlock(clicon_handle h,
|
netconf_unlock(clicon_handle h,
|
||||||
|
|
@ -705,47 +650,18 @@ netconf_unlock(clicon_handle h,
|
||||||
"<bad-element>target</bad-element>");
|
"<bad-element>target</bad-element>");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#ifdef notyet
|
/* XXX notyet */
|
||||||
if (target_locked(&client) == 0){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"lock-denied",
|
|
||||||
"protocol",
|
|
||||||
"error",
|
|
||||||
"Unlock failed, lock is not held",
|
|
||||||
NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != ce_nr){
|
|
||||||
snprintf(info, 64, "<session-id>%d</session-id>", client);
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"lock-denied",
|
|
||||||
"protocol",
|
|
||||||
"error",
|
|
||||||
"Unlock failed, lock is held by other entity",
|
|
||||||
info);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (unlock_target(target) < 0){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"lock-denied",
|
|
||||||
"protocol",
|
|
||||||
"error",
|
|
||||||
"Unlock failed, unkown reason",
|
|
||||||
NULL);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif /* notyet */
|
|
||||||
netconf_ok_set(1);
|
netconf_ok_set(1);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Kill other user sessions
|
||||||
<kill-session>
|
<kill-session>
|
||||||
<session-id>PID</session-id>
|
<session-id>PID</session-id>
|
||||||
</kill-session>
|
</kill-session>
|
||||||
|
XXX
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
netconf_kill_session(cxobj *xn, cbuf *cb, cbuf *cb_err, cxobj *xorig)
|
netconf_kill_session(cxobj *xn, cbuf *cb, cbuf *cb_err, cxobj *xorig)
|
||||||
|
|
@ -793,7 +709,7 @@ netconf_kill_session(cxobj *xn, cbuf *cb, cbuf *cb_err, cxobj *xorig)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Commit candidate -> running
|
||||||
<commit/>
|
<commit/>
|
||||||
:candidate
|
:candidate
|
||||||
*/
|
*/
|
||||||
|
|
@ -805,25 +721,8 @@ netconf_commit(clicon_handle h,
|
||||||
cxobj *xorig)
|
cxobj *xorig)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *candidate_db;
|
|
||||||
char *running_db;
|
|
||||||
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
if (clicon_rpc_commit(h, "candidate", "running",
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error: candidate not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error: running not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (clicon_rpc_commit(h, candidate_db,
|
|
||||||
running_db,
|
|
||||||
1, 1) < 0){
|
1, 1) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
|
|
@ -838,7 +737,7 @@ netconf_commit(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Discard all changes in candidate / revert to running
|
||||||
<discard-changes/>
|
<discard-changes/>
|
||||||
:candidate
|
:candidate
|
||||||
*/
|
*/
|
||||||
|
|
@ -850,24 +749,8 @@ netconf_discard_changes(clicon_handle h,
|
||||||
cxobj *xorig)
|
cxobj *xorig)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *running_db;
|
|
||||||
char *candidate_db;
|
|
||||||
|
|
||||||
if ((running_db = clicon_running_db(h)) == NULL){
|
if (xmldb_copy(h, "running", "candidate") < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error: running not set");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((candidate_db = clicon_candidate_db(h)) == NULL){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
|
||||||
"operation-failed",
|
|
||||||
"protocol", "error",
|
|
||||||
NULL, "Internal error");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (clicon_rpc_copy(h, running_db, candidate_db) < 0){
|
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"protocol", "error",
|
"protocol", "error",
|
||||||
|
|
@ -881,7 +764,7 @@ netconf_discard_changes(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Check the semantic consistency of candidate
|
||||||
<validate/>
|
<validate/>
|
||||||
:validate
|
:validate
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,6 @@ CLICON_YANG_DIR prefix/share/APPNAME/yang
|
||||||
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
# This option is only relevant if CLICON_DBSPEC_TYPE is YANG
|
||||||
CLICON_YANG_MODULE_REVISION
|
CLICON_YANG_MODULE_REVISION
|
||||||
|
|
||||||
# Candidate qdbm database
|
|
||||||
CLICON_CANDIDATE_DB localstatedir/APPNAME/candidate_db
|
|
||||||
|
|
||||||
# Running qdbm database
|
|
||||||
CLICON_RUNNING_DB localstatedir/APPNAME/running_db
|
|
||||||
|
|
||||||
# Location of backend .so plugins
|
# Location of backend .so plugins
|
||||||
CLICON_BACKEND_DIR libdir/APPNAME/backend
|
CLICON_BACKEND_DIR libdir/APPNAME/backend
|
||||||
|
|
||||||
|
|
@ -108,8 +102,18 @@ CLICON_BACKEND_PIDFILE localstatedir/APPNAME/APPNAME.pidfile
|
||||||
# How to generate and show CLI syntax: VARS|ALL
|
# How to generate and show CLI syntax: VARS|ALL
|
||||||
# CLICON_CLI_GENMODEL_TYPE VARS
|
# CLICON_CLI_GENMODEL_TYPE VARS
|
||||||
|
|
||||||
# Comment character in CLI
|
# Directory where "running" and "candidate" are placed
|
||||||
# CLICON_CLI_COMMENT #
|
CLICON_XMLDB_DIR localstatedir/APPNAME
|
||||||
|
|
||||||
|
# Set if xmldb runs in a separate process (clixon_xmldb).
|
||||||
|
# If set, also set xmldb_addr and xmldb_port below
|
||||||
|
# CLICON_XMLDB_RPC 0
|
||||||
|
|
||||||
|
# xmldb inet address (if CLICON_XMLDB_RPC)
|
||||||
|
# CLICON_XMLDB_ADDR
|
||||||
|
|
||||||
|
# xmldb tcp port (if CLICON_XMLDB_RPC)
|
||||||
|
# CLICON_XMLDB_PORT
|
||||||
|
|
||||||
# Dont include keys in cvec in cli vars callbacks, ie a & k in 'a <b> k <c>' ignored
|
# Dont include keys in cvec in cli vars callbacks, ie a & k in 'a <b> k <c>' ignored
|
||||||
# CLICON_CLI_VARONLY 1
|
# CLICON_CLI_VARONLY 1
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,19 @@ clixon_DBSPECDIR=prefix/share/$(APPNAME)
|
||||||
clixon_SYSCONFDIR=sysconfdir
|
clixon_SYSCONFDIR=sysconfdir
|
||||||
clixon_LOCALSTATEDIR=localstatedir/$(APPNAME)
|
clixon_LOCALSTATEDIR=localstatedir/$(APPNAME)
|
||||||
clixon_LIBDIR=libdir/$(APPNAME)
|
clixon_LIBDIR=libdir/$(APPNAME)
|
||||||
clixon_DATADIR=datadir/clicon
|
clixon_DATADIR=datadir/clixon
|
||||||
|
|
||||||
# Rules for the clicon application configuration file.
|
# Rules for the clixon application configuration file.
|
||||||
# The clicon applications should be started with this fileas its -f argument.
|
# The clixon applications should be started with this fileas its -f argument.
|
||||||
# Typically installed in sysconfdir
|
# Typically installed in sysconfdir
|
||||||
# Example: APPNAME=myapp --> clixon_cli -f /usr/local/etc/myapp.conf
|
# Example: APPNAME=myapp --> clixon_cli -f /usr/local/etc/myapp.conf
|
||||||
# The two variants are if there is a .conf.local file or not
|
# The two variants are if there is a .conf.local file or not
|
||||||
.PHONY: $(APPNAME).conf
|
.PHONY: $(APPNAME).conf
|
||||||
ifneq (,$(wildcard ${APPNAME}.conf.local))
|
ifneq (,$(wildcard ${APPNAME}.conf.local))
|
||||||
${APPNAME}.conf: ${clixon_DATADIR}/clicon.conf.cpp ${APPNAME}.conf.local
|
${APPNAME}.conf: ${clixon_DATADIR}/clixon.conf.cpp ${APPNAME}.conf.local
|
||||||
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
|
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
|
||||||
cat ${APPNAME}.conf.local >> $@
|
cat ${APPNAME}.conf.local >> $@
|
||||||
else
|
else
|
||||||
${APPNAME}.conf: ${clixon_DATADIR}/clicon.conf.cpp
|
${APPNAME}.conf: ${clixon_DATADIR}/clixon.conf.cpp
|
||||||
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
|
$(CPP) -P -x assembler-with-cpp -DAPPNAME=$(APPNAME) $< > $@
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
3
configure
vendored
3
configure
vendored
|
|
@ -4193,7 +4193,7 @@ fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/dbctrl/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/docker/Makefile docker/Makefile docker/cli/Makefile docker/cli/Dockerfile docker/backend/Makefile docker/backend/Dockerfile docker/netconf/Makefile docker/netconf/Dockerfile doc/Makefile"
|
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/dbctrl/Makefile apps/xmldb/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/docker/Makefile docker/Makefile docker/cli/Makefile docker/cli/Dockerfile docker/backend/Makefile docker/backend/Dockerfile docker/netconf/Makefile docker/netconf/Dockerfile doc/Makefile"
|
||||||
|
|
||||||
cat >confcache <<\_ACEOF
|
cat >confcache <<\_ACEOF
|
||||||
# This file is a shell script that caches the results of configure
|
# This file is a shell script that caches the results of configure
|
||||||
|
|
@ -4895,6 +4895,7 @@ do
|
||||||
"apps/backend/Makefile") CONFIG_FILES="$CONFIG_FILES apps/backend/Makefile" ;;
|
"apps/backend/Makefile") CONFIG_FILES="$CONFIG_FILES apps/backend/Makefile" ;;
|
||||||
"apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;;
|
"apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;;
|
||||||
"apps/dbctrl/Makefile") CONFIG_FILES="$CONFIG_FILES apps/dbctrl/Makefile" ;;
|
"apps/dbctrl/Makefile") CONFIG_FILES="$CONFIG_FILES apps/dbctrl/Makefile" ;;
|
||||||
|
"apps/xmldb/Makefile") CONFIG_FILES="$CONFIG_FILES apps/xmldb/Makefile" ;;
|
||||||
"include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
|
"include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
|
||||||
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
||||||
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ AC_OUTPUT(Makefile
|
||||||
apps/backend/Makefile
|
apps/backend/Makefile
|
||||||
apps/netconf/Makefile
|
apps/netconf/Makefile
|
||||||
apps/dbctrl/Makefile
|
apps/dbctrl/Makefile
|
||||||
|
apps/xmldb/Makefile
|
||||||
include/Makefile
|
include/Makefile
|
||||||
etc/Makefile
|
etc/Makefile
|
||||||
etc/clixonrc
|
etc/clixonrc
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,14 @@ CLICON_CLI_GENMODEL_COMPLETION 1
|
||||||
# How to generate and show CLI syntax: VARS|ALL
|
# How to generate and show CLI syntax: VARS|ALL
|
||||||
# CLICON_CLI_GENMODEL_TYPE VARS
|
# CLICON_CLI_GENMODEL_TYPE VARS
|
||||||
CLICON_CLI_GENMODEL_TYPE VARS
|
CLICON_CLI_GENMODEL_TYPE VARS
|
||||||
|
|
||||||
|
# Set if xmldb runs in a separate process (clixon_xmldb).
|
||||||
|
# Also set addr and port below
|
||||||
|
CLICON_XMLDB_RPC 0
|
||||||
|
|
||||||
|
# xmldb inet address (if CLICON_XMLDB_RPC)
|
||||||
|
CLICON_XMLDB_ADDR 127.0.0.1
|
||||||
|
|
||||||
|
# xmldb tcp port (if CLICON_XMLDB_RPC)
|
||||||
|
CLICON_XMLDB_PORT 7878
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ mycallback(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
yang_spec *yspec;
|
|
||||||
cg_var *myvar;
|
cg_var *myvar;
|
||||||
|
|
||||||
/* Access cligen callback variables */
|
/* Access cligen callback variables */
|
||||||
|
|
@ -70,11 +69,10 @@ mycallback(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
cli_output(stderr, "arg = %s\n", cv_string_get(arg)); /* get string value */
|
cli_output(stderr, "arg = %s\n", cv_string_get(arg)); /* get string value */
|
||||||
|
|
||||||
/* Show eth0 interfaces config using XPATH */
|
/* Show eth0 interfaces config using XPATH */
|
||||||
yspec = clicon_dbspec_yang(h);
|
if (xmldb_get(h, "candidate",
|
||||||
if (xmldb_get(clicon_candidate_db(h),
|
|
||||||
"/interfaces/interface[name=eth0]",
|
"/interfaces/interface[name=eth0]",
|
||||||
yspec,
|
0,
|
||||||
&xt) < 0)
|
&xt, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_xml2file(stdout, xt, 0, 1);
|
clicon_xml2file(stdout, xt, 0, 1);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,6 @@ int clicon_file_dirent(const char *dir, struct dirent **ent,
|
||||||
|
|
||||||
char *clicon_tmpfile(const char *label);
|
char *clicon_tmpfile(const char *label);
|
||||||
|
|
||||||
int file_cp(char *src, char *target);
|
int clicon_file_copy(char *src, char *target);
|
||||||
|
|
||||||
#endif /* _CLIXON_FILE_H_ */
|
#endif /* _CLIXON_FILE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,6 @@ char *clicon_configfile(clicon_handle h);
|
||||||
char *clicon_yang_dir(clicon_handle h);
|
char *clicon_yang_dir(clicon_handle h);
|
||||||
char *clicon_yang_module_main(clicon_handle h);
|
char *clicon_yang_module_main(clicon_handle h);
|
||||||
char *clicon_yang_module_revision(clicon_handle h);
|
char *clicon_yang_module_revision(clicon_handle h);
|
||||||
char *clicon_running_db(clicon_handle h);
|
|
||||||
char *clicon_candidate_db(clicon_handle h);
|
|
||||||
char *clicon_backend_dir(clicon_handle h);
|
char *clicon_backend_dir(clicon_handle h);
|
||||||
char *clicon_cli_dir(clicon_handle h);
|
char *clicon_cli_dir(clicon_handle h);
|
||||||
char *clicon_clispec_dir(clicon_handle h);
|
char *clicon_clispec_dir(clicon_handle h);
|
||||||
|
|
@ -97,6 +95,11 @@ int clicon_cli_varonly(clicon_handle h);
|
||||||
int clicon_cli_varonly_set(clicon_handle h, int val);
|
int clicon_cli_varonly_set(clicon_handle h, int val);
|
||||||
int clicon_cli_genmodel_completion(clicon_handle h);
|
int clicon_cli_genmodel_completion(clicon_handle h);
|
||||||
|
|
||||||
|
char *clicon_xmldb_dir(clicon_handle h);
|
||||||
|
int clicon_xmldb_rpc(clicon_handle h);
|
||||||
|
char *clicon_xmldb_addr(clicon_handle h);
|
||||||
|
uint16_t clicon_xmldb_port(clicon_handle h);
|
||||||
|
|
||||||
char *clicon_quiet_mode(clicon_handle h);
|
char *clicon_quiet_mode(clicon_handle h);
|
||||||
enum genmodel_type clicon_cli_genmodel_type(clicon_handle h);
|
enum genmodel_type clicon_cli_genmodel_type(clicon_handle h);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,16 +39,16 @@ enum clicon_msg_type{
|
||||||
current state, set running_db. Body is:
|
current state, set running_db. Body is:
|
||||||
1. uint32: (1)snapshot while doing commit, (0) dont
|
1. uint32: (1)snapshot while doing commit, (0) dont
|
||||||
2. uint32: (1)save to startup-config, (0) dont
|
2. uint32: (1)save to startup-config, (0) dont
|
||||||
3. string: name of 'from' database (eg candidate)
|
3. string: name of 'from' database (eg "candidate")
|
||||||
4. string: name of 'to' database (eg current)
|
4. string: name of 'to' database (eg "running")
|
||||||
*/
|
*/
|
||||||
CLICON_MSG_VALIDATE, /* Validate settings in a database. Body is:
|
CLICON_MSG_VALIDATE, /* Validate settings in a database. Body is:
|
||||||
1. string: name of database
|
1. string: name of database (eg "candidate")
|
||||||
*/
|
*/
|
||||||
CLICON_MSG_CHANGE, /* Change a (single) database entry:
|
CLICON_MSG_CHANGE, /* Change a (single) database entry:
|
||||||
1. uint32: operation: OP_MERGE/OP_REPLACE/OP_REMOVE
|
1. uint32: operation: OP_MERGE/OP_REPLACE/OP_REMOVE
|
||||||
2. uint32: length of value string
|
2. uint32: length of value string
|
||||||
3. string: name of database to change (eg current)
|
3. string: name of database to change (eg "running")
|
||||||
4. string: key
|
4. string: key
|
||||||
5. string: value
|
5. string: value
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,26 +71,6 @@ enum clicon_msg_type{
|
||||||
3. string: filename to load from
|
3. string: filename to load from
|
||||||
|
|
||||||
*/
|
*/
|
||||||
CLICON_MSG_COPY, /* Copy from file to file in backend. Body is:
|
|
||||||
1. string: filename to copy from
|
|
||||||
2. string: filename to copy to
|
|
||||||
*/
|
|
||||||
CLICON_MSG_RM , /* Delete file. Body is:
|
|
||||||
1. string: filename to delete
|
|
||||||
*/
|
|
||||||
|
|
||||||
CLICON_MSG_INITDB , /* (Re-)Initialize a database. Body is:
|
|
||||||
1. string: filename of db to initialize
|
|
||||||
*/
|
|
||||||
CLICON_MSG_LOCK , /* Lock a database. Body is
|
|
||||||
1. name of db
|
|
||||||
The reply will be OK, or ERROR. If error is
|
|
||||||
lock-denied, the session-id of the locking
|
|
||||||
entity is returned (cf netconf)
|
|
||||||
*/
|
|
||||||
CLICON_MSG_UNLOCK , /* Unlock a database. Body is:
|
|
||||||
1. name of db *
|
|
||||||
*/
|
|
||||||
CLICON_MSG_KILL, /* Kill (other) session:
|
CLICON_MSG_KILL, /* Kill (other) session:
|
||||||
1. session-id
|
1. session-id
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,6 @@ int clicon_rpc_dbitems(clicon_handle h, char *db, char *rx,
|
||||||
cvec ***cvv, size_t *cvvlen);
|
cvec ***cvv, size_t *cvvlen);
|
||||||
int clicon_rpc_save(clicon_handle h, char *dbname, int snapshot, char *filename);
|
int clicon_rpc_save(clicon_handle h, char *dbname, int snapshot, char *filename);
|
||||||
int clicon_rpc_load(clicon_handle h, int replace, char *db, char *filename);
|
int clicon_rpc_load(clicon_handle h, int replace, char *db, char *filename);
|
||||||
int clicon_rpc_copy(clicon_handle h, char *filename1, char *filename2);
|
|
||||||
int clicon_rpc_rm(clicon_handle h, char *filename);
|
|
||||||
int clicon_rpc_initdb(clicon_handle h, char *filename);
|
|
||||||
int clicon_rpc_lock(clicon_handle h, char *dbname);
|
|
||||||
int clicon_rpc_unlock(clicon_handle h, char *dbname);
|
|
||||||
int clicon_rpc_kill(clicon_handle h, int session_id);
|
int clicon_rpc_kill(clicon_handle h, int session_id);
|
||||||
int clicon_rpc_debug(clicon_handle h, int level);
|
int clicon_rpc_debug(clicon_handle h, int level);
|
||||||
int clicon_rpc_call(clicon_handle h, uint16_t op, char *plugin, char *func,
|
int clicon_rpc_call(clicon_handle h, uint16_t op, char *plugin, char *func,
|
||||||
|
|
|
||||||
|
|
@ -100,40 +100,6 @@ int
|
||||||
clicon_msg_load_decode(struct clicon_msg *msg,
|
clicon_msg_load_decode(struct clicon_msg *msg,
|
||||||
int *replace, char **db, char **filename,
|
int *replace, char **db, char **filename,
|
||||||
const char *label);
|
const char *label);
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_initdb_encode(char *filename_src, const char *label);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_initdb_decode(struct clicon_msg *msg, char **filename_src,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_rm_encode(char *filename_src, const char *label);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_rm_decode(struct clicon_msg *msg, char **filename_src,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_copy_encode(char *filename_src, char *filename_dst,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_copy_decode(struct clicon_msg *msg,
|
|
||||||
char **filename_src, char **filename_dst,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_lock_encode(char *db, const char *label);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_lock_decode(struct clicon_msg *msg, char **db, const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_unlock_encode(char *db, const char *label);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_unlock_decode(struct clicon_msg *msg, char **db, const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
struct clicon_msg *
|
||||||
clicon_msg_kill_encode(uint32_t session_id, const char *label);
|
clicon_msg_kill_encode(uint32_t session_id, const char *label);
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,19 @@
|
||||||
int yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt);
|
int yang2xmlkeyfmt(yang_stmt *ys, char **xkfmt);
|
||||||
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
|
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
|
||||||
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
|
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
|
||||||
int xmlkey2xml(char *xkey, yang_spec *yspec, char **xml);
|
int xmldb_get(clicon_handle h, char *db, char *xpath, int vector,
|
||||||
int xmldb_get(char *dbname, char *xpath,
|
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
||||||
yang_spec *yspec, cxobj **xtop);
|
int xmldb_put(clicon_handle h, char *db, cxobj *xt, enum operation_type op);
|
||||||
int xmldb_get_vec(char *dbname, char *xpath, yang_spec *yspec,
|
int xmldb_put_xkey(clicon_handle h, char *db,
|
||||||
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
char *xkey, char *val,
|
||||||
int xmldb_put( char *dbname, cxobj *xt,
|
|
||||||
yang_spec *yspec, enum operation_type op);
|
|
||||||
int xmldb_put_xkey(char *dbname, char *xkey, char *val, yang_spec *yspec,
|
|
||||||
enum operation_type op);
|
enum operation_type op);
|
||||||
int xmldb_dump(FILE *f, char *dbname, char *rxkey);
|
int xmldb_dump(FILE *f, char *dbfilename, char *rxkey);
|
||||||
int xmldb_init(char *file);
|
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);
|
||||||
|
int xmldb_islocked(clicon_handle h, char *db);
|
||||||
|
int xmldb_exists(clicon_handle h, char *db);
|
||||||
|
int xmldb_delete(clicon_handle h, char *db);
|
||||||
|
int xmldb_init(clicon_handle h, char *db);
|
||||||
|
|
||||||
#endif /* _CLIXON_XML_DB_H */
|
#endif /* _CLIXON_XML_DB_H */
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ SRC = clixon_sig.c clixon_qdb.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_yang.c clixon_yang_type.c \
|
clixon_yang.c clixon_yang_type.c \
|
||||||
clixon_hash.c clixon_options.c clixon_plugin.c \
|
clixon_hash.c clixon_options.c clixon_plugin.c \
|
||||||
clixon_proto.c clixon_proto_encode.c clixon_proto_client.c \
|
clixon_proto.c clixon_proto_encode.c clixon_proto_client.c \
|
||||||
clixon_xsl.c clixon_sha1.c clixon_xml_db.c
|
clixon_xsl.c clixon_sha1.c clixon_xml_db.c clixon_xml_db_rpc.c
|
||||||
|
|
||||||
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
||||||
lex.clixon_yang_parse.o clixon_yang_parse.tab.o
|
lex.clixon_yang_parse.o clixon_yang_parse.tab.o
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ clicon_err_reset(void)
|
||||||
* - Logs to syslog with LOG_ERR
|
* - Logs to syslog with LOG_ERR
|
||||||
* - Set global error variable name clicon_errno
|
* - Set global error variable name clicon_errno
|
||||||
* - Set global reason string clicon_err_reason
|
* - Set global reason string clicon_err_reason
|
||||||
* NOTE: err direction (syslog and/or stderr) controlled by clicon_log_init()
|
* @note: err direction (syslog and/or stderr) controlled by clicon_log_init()
|
||||||
*
|
*
|
||||||
* @param fn Inline function name (when called from clicon_err() macro)
|
* @param fn Inline function name (when called from clicon_err() macro)
|
||||||
* @param line Inline file line number (when called from clicon_err() macro)
|
* @param line Inline file line number (when called from clicon_err() macro)
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ clicon_file_dirent(const char *dir,
|
||||||
clicon_err(OE_UNIX, 0, "chunk: %s", strerror(errno));
|
clicon_err(OE_UNIX, 0, "chunk: %s", strerror(errno));
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
res = lstat (filename, &st);
|
res = lstat(filename, &st);
|
||||||
unchunk (filename);
|
unchunk (filename);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
clicon_err(OE_UNIX, 0, "lstat: %s", strerror(errno));
|
clicon_err(OE_UNIX, 0, "lstat: %s", strerror(errno));
|
||||||
|
|
@ -287,12 +287,13 @@ clicon_tmpfile(const char *label)
|
||||||
return (char *)chunkdup(file, strlen(file)+1, label);
|
return (char *)chunkdup(file, strlen(file)+1, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Make a copy of file src
|
||||||
* Make a copy of file src
|
* @retval 0 OK
|
||||||
* On error returns -1 and sets errno.
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
file_cp(char *src, char *target)
|
clicon_file_copy(char *src,
|
||||||
|
char *target)
|
||||||
{
|
{
|
||||||
int inF = 0, ouF = 0;
|
int inF = 0, ouF = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
@ -301,16 +302,22 @@ file_cp(char *src, char *target)
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if (stat(src, &st) != 0)
|
if (stat(src, &st) != 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "stat");
|
||||||
return -1;
|
return -1;
|
||||||
if((inF = open(src, O_RDONLY)) == -1)
|
}
|
||||||
|
if((inF = open(src, O_RDONLY)) == -1) {
|
||||||
|
clicon_err(OE_UNIX, errno, "open");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
if((ouF = open(target, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) {
|
if((ouF = open(target, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) {
|
||||||
|
clicon_err(OE_UNIX, errno, "open");
|
||||||
err = errno;
|
err = errno;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
while((bytes = read(inF, line, sizeof(line))) > 0)
|
while((bytes = read(inF, line, sizeof(line))) > 0)
|
||||||
if (write(ouF, line, bytes) < 0){
|
if (write(ouF, line, bytes) < 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "write");
|
||||||
err = errno;
|
err = errno;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,11 @@ static FILE *_debugfile = NULL;
|
||||||
* @param[in] ident prefix that appears on syslog (eg 'cli')
|
* @param[in] ident prefix that appears on syslog (eg 'cli')
|
||||||
* @param[in] upto log priority, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG (see syslog(3)).
|
* @param[in] upto log priority, eg LOG_DEBUG,LOG_INFO,...,LOG_EMERG (see syslog(3)).
|
||||||
* @param[in] flags bitmask: if CLICON_LOG_STDERR, then print logs to stderr
|
* @param[in] flags bitmask: if CLICON_LOG_STDERR, then print logs to stderr
|
||||||
if CLICON_LOG_SYSLOG, then print logs to syslog
|
* if CLICON_LOG_SYSLOG, then print logs to syslog
|
||||||
You can do a combination of both
|
* You can do a combination of both
|
||||||
|
* @code
|
||||||
|
* clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR);
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_log_init(char *ident, int upto, int flags)
|
clicon_log_init(char *ident, int upto, int flags)
|
||||||
|
|
|
||||||
|
|
@ -212,14 +212,6 @@ clicon_option_sanity(clicon_hash_t *copt)
|
||||||
clicon_err(OE_UNIX, 0, "CLICON_NETCONF_DIR not defined in config file");
|
clicon_err(OE_UNIX, 0, "CLICON_NETCONF_DIR not defined in config file");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!hash_lookup(copt, "CLICON_RUNNING_DB")){
|
|
||||||
clicon_err(OE_UNIX, 0, "CLICON_RUNNING_DB not defined in config file");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!hash_lookup(copt, "CLICON_CANDIDATE_DB")){
|
|
||||||
clicon_err(OE_UNIX, 0, "CLICON_CANDIDATE_DB not defined in config file");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!hash_lookup(copt, "CLICON_YANG_DIR")){
|
if (!hash_lookup(copt, "CLICON_YANG_DIR")){
|
||||||
clicon_err(OE_UNIX, 0, "CLICON_YANG_DIR not defined in config file");
|
clicon_err(OE_UNIX, 0, "CLICON_YANG_DIR not defined in config file");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -404,20 +396,6 @@ clicon_yang_module_revision(clicon_handle h)
|
||||||
return clicon_option_str(h, "CLICON_YANG_MODULE_REVISION");
|
return clicon_option_str(h, "CLICON_YANG_MODULE_REVISION");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* candidate database: get name */
|
|
||||||
char *
|
|
||||||
clicon_candidate_db(clicon_handle h)
|
|
||||||
{
|
|
||||||
return clicon_option_str(h, "CLICON_CANDIDATE_DB");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* running database: get name */
|
|
||||||
char *
|
|
||||||
clicon_running_db(clicon_handle h)
|
|
||||||
{
|
|
||||||
return clicon_option_str(h, "CLICON_RUNNING_DB");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
char *
|
||||||
clicon_backend_dir(clicon_handle h)
|
clicon_backend_dir(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -472,14 +450,14 @@ clicon_sock_family(clicon_handle h)
|
||||||
return AF_UNIX; /* default */
|
return AF_UNIX; /* default */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get information about socket: unix domain filepath, or addr:path */
|
/*! Get information about socket: unix domain filepath, or addr:path */
|
||||||
char *
|
char *
|
||||||
clicon_sock(clicon_handle h)
|
clicon_sock(clicon_handle h)
|
||||||
{
|
{
|
||||||
return clicon_option_str(h, "CLICON_SOCK");
|
return clicon_option_str(h, "CLICON_SOCK");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get port for backend socket in case of AF_INET or AF_INET6 */
|
/*! Get port for backend socket in case of AF_INET or AF_INET6 */
|
||||||
int
|
int
|
||||||
clicon_sock_port(clicon_handle h)
|
clicon_sock_port(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -608,8 +586,43 @@ clicon_cli_genmodel_completion(clicon_handle h)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Where are "running" and "candidate" databases? */
|
||||||
* Get dbspec (YANG variant)
|
char *
|
||||||
|
clicon_xmldb_dir(clicon_handle h)
|
||||||
|
{
|
||||||
|
return clicon_option_str(h, "CLICON_XMLDB_DIR");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Set if xmldb runs in a separate process (clixon_xmldb). */
|
||||||
|
int
|
||||||
|
clicon_xmldb_rpc(clicon_handle h)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if ((s = clicon_option_str(h, "CLICON_XMLDB_RPC")) == NULL)
|
||||||
|
return -1;
|
||||||
|
return atoi(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get xmldb inet address */
|
||||||
|
char *
|
||||||
|
clicon_xmldb_addr(clicon_handle h)
|
||||||
|
{
|
||||||
|
return clicon_option_str(h, "CLICON_XMLDB_ADDR");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get port for xmldb address in case of AF_INET or AF_INET6 */
|
||||||
|
uint16_t
|
||||||
|
clicon_xmldb_port(clicon_handle h)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if ((s = clicon_option_str(h, "CLICON_XMLDB_PORT")) == NULL)
|
||||||
|
return -1;
|
||||||
|
return atoi(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get YANG specification
|
||||||
* Must use hash functions directly since they are not strings.
|
* Must use hash functions directly since they are not strings.
|
||||||
*/
|
*/
|
||||||
yang_spec *
|
yang_spec *
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,6 @@ static const struct map_type2str msgmap[] = {
|
||||||
{CLICON_MSG_CHANGE, "change"},
|
{CLICON_MSG_CHANGE, "change"},
|
||||||
{CLICON_MSG_SAVE, "save"},
|
{CLICON_MSG_SAVE, "save"},
|
||||||
{CLICON_MSG_LOAD, "load"},
|
{CLICON_MSG_LOAD, "load"},
|
||||||
{CLICON_MSG_COPY, "copy"},
|
|
||||||
{CLICON_MSG_RM, "rm"},
|
|
||||||
{CLICON_MSG_INITDB, "initdb"},
|
|
||||||
{CLICON_MSG_LOCK, "lock"},
|
|
||||||
{CLICON_MSG_UNLOCK, "unlock"},
|
|
||||||
{CLICON_MSG_KILL, "kill"},
|
{CLICON_MSG_KILL, "kill"},
|
||||||
{CLICON_MSG_DEBUG, "debug"},
|
{CLICON_MSG_DEBUG, "debug"},
|
||||||
{CLICON_MSG_CALL, "call"},
|
{CLICON_MSG_CALL, "call"},
|
||||||
|
|
@ -193,7 +188,8 @@ msg_dump(struct clicon_msg *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
clicon_msg_send(int s, struct clicon_msg *msg)
|
clicon_msg_send(int s,
|
||||||
|
struct clicon_msg *msg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
|
@ -337,8 +333,8 @@ clicon_rpc_connect_inet(struct clicon_msg *msg,
|
||||||
int *sock0,
|
int *sock0,
|
||||||
const char *label)
|
const char *label)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int s = -1;
|
int s = -1;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
clicon_debug(1, "Send %s msg to %s:%hu",
|
clicon_debug(1, "Send %s msg to %s:%hu",
|
||||||
|
|
|
||||||
|
|
@ -284,116 +284,6 @@ clicon_rpc_load(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send a request to backend to copy a file from one location to another
|
|
||||||
* Note this assumes the backend can access these files and (usually) assumes
|
|
||||||
* clients and servers have the access to the same filesystem.
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] filename1 src file
|
|
||||||
* @param[in] filename2 dst file
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_copy(clicon_handle h,
|
|
||||||
char *filename1,
|
|
||||||
char *filename2)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
|
|
||||||
if ((msg=clicon_msg_copy_encode(filename1, filename2,
|
|
||||||
__FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a request to remove a file from backend file system
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] filename File to remove
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_rm(clicon_handle h,
|
|
||||||
char *filename)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
|
|
||||||
if ((msg=clicon_msg_rm_encode(filename, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a database initialization request to backend server
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] db Name of database
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_initdb(clicon_handle h,
|
|
||||||
char *db)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
|
|
||||||
if ((msg=clicon_msg_initdb_encode(db, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a database lock request to backend server
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] db Name of database
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_lock(clicon_handle h,
|
|
||||||
char *db)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
|
|
||||||
if ((msg=clicon_msg_lock_encode(db, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a database unlock request to backend server
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] db Name of database
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_unlock(clicon_handle h,
|
|
||||||
char *db)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
|
|
||||||
if ((msg=clicon_msg_unlock_encode(db, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL, NULL, __FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a kill session request to backend server
|
/*! Send a kill session request to backend server
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] session_id Id of session to kill
|
* @param[in] session_id Id of session to kill
|
||||||
|
|
|
||||||
|
|
@ -58,52 +58,6 @@
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
#include "clixon_proto_encode.h"
|
#include "clixon_proto_encode.h"
|
||||||
|
|
||||||
/* Generic encode/decode functions for exactly one C-string (str)
|
|
||||||
*/
|
|
||||||
static struct clicon_msg *
|
|
||||||
clicon_msg_1str_encode(char *str, enum clicon_msg_type op, const char *label)
|
|
||||||
{
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
int hdrlen = sizeof(*msg);
|
|
||||||
uint16_t len;
|
|
||||||
int p;
|
|
||||||
|
|
||||||
assert(str);
|
|
||||||
p = 0;
|
|
||||||
len = sizeof(*msg) + strlen(str) + 1;
|
|
||||||
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(msg, 0, len);
|
|
||||||
/* hdr */
|
|
||||||
msg->op_type = htons(op);
|
|
||||||
msg->op_len = htons(len);
|
|
||||||
/* body */
|
|
||||||
strncpy(msg->op_body+p, str, len-p-hdrlen);
|
|
||||||
p += strlen(str)+1;
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
clicon_msg_1str_decode(struct clicon_msg *msg,
|
|
||||||
char **str,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
|
|
||||||
p = 0;
|
|
||||||
/* body */
|
|
||||||
if ((*str = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += strlen(*str)+1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct clicon_msg *
|
struct clicon_msg *
|
||||||
clicon_msg_commit_encode(char *dbsrc, char *dbdst,
|
clicon_msg_commit_encode(char *dbsrc, char *dbdst,
|
||||||
uint32_t snapshot, uint32_t startup,
|
uint32_t snapshot, uint32_t startup,
|
||||||
|
|
@ -544,141 +498,6 @@ clicon_msg_load_decode(struct clicon_msg *msg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_initdb_encode(char *filename, const char *label)
|
|
||||||
{
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, filename);
|
|
||||||
return clicon_msg_1str_encode(filename, CLICON_MSG_INITDB, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_initdb_decode(struct clicon_msg *msg,
|
|
||||||
char **filename,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = clicon_msg_1str_decode(msg, filename, label);
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, *filename);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_rm_encode(char *filename, const char *label)
|
|
||||||
{
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, filename);
|
|
||||||
return clicon_msg_1str_encode(filename, CLICON_MSG_RM, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_rm_decode(struct clicon_msg *msg,
|
|
||||||
char **filename,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = clicon_msg_1str_decode(msg, filename, label);
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, *filename);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_copy_encode(char *filename_src, char *filename_dst,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
int hdrlen = sizeof(*msg);
|
|
||||||
uint16_t len;
|
|
||||||
int p;
|
|
||||||
|
|
||||||
clicon_debug(2, "%s: filename_src: %s filename_dst: %s",
|
|
||||||
__FUNCTION__,
|
|
||||||
filename_src, filename_dst);
|
|
||||||
p = 0;
|
|
||||||
len = hdrlen + strlen(filename_src) + 1 + strlen(filename_dst) + 1;
|
|
||||||
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(msg, 0, len);
|
|
||||||
/* hdr */
|
|
||||||
msg->op_type = htons(CLICON_MSG_COPY);
|
|
||||||
msg->op_len = htons(len);
|
|
||||||
/* body */
|
|
||||||
strncpy(msg->op_body+p, filename_src, len-p-hdrlen);
|
|
||||||
p += strlen(filename_src)+1;
|
|
||||||
strncpy(msg->op_body+p, filename_dst, len-p-hdrlen);
|
|
||||||
p += strlen(filename_dst)+1;
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_copy_decode(struct clicon_msg *msg,
|
|
||||||
char **filename_src, char **filename_dst,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
|
|
||||||
p = 0;
|
|
||||||
/* body */
|
|
||||||
if ((*filename_src = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += strlen(*filename_src)+1;
|
|
||||||
|
|
||||||
if ((*filename_dst = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += strlen(*filename_dst)+1;
|
|
||||||
clicon_debug(2, "%s: filename_src: %s filename_dst: %s",
|
|
||||||
__FUNCTION__,
|
|
||||||
*filename_src, *filename_dst);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_lock_encode(char *db, const char *label)
|
|
||||||
{
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, db);
|
|
||||||
return clicon_msg_1str_encode(db, CLICON_MSG_LOCK, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_lock_decode(struct clicon_msg *msg,
|
|
||||||
char **db,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = clicon_msg_1str_decode(msg, db, label);
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, *db);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_unlock_encode(char *db, const char *label)
|
|
||||||
{
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, db);
|
|
||||||
return clicon_msg_1str_encode(db, CLICON_MSG_UNLOCK, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_unlock_decode(struct clicon_msg *msg,
|
|
||||||
char **db,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = clicon_msg_1str_decode(msg, db, label);
|
|
||||||
clicon_debug(2, "%s: db: %s", __FUNCTION__, *db);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
struct clicon_msg *
|
||||||
clicon_msg_kill_encode(uint32_t session_id, const char *label)
|
clicon_msg_kill_encode(uint32_t session_id, const char *label)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,25 @@
|
||||||
along with CLIXON; see the file LICENSE. If not, see
|
along with CLIXON; see the file LICENSE. If not, see
|
||||||
<http://www.gnu.org/licenses/>.
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
* @note Some unclarities with locking. man dpopen defines the following flags
|
||||||
|
* with dpopen:
|
||||||
|
* `DP_ONOLCK', which means it opens a database file without
|
||||||
|
* file locking,
|
||||||
|
* `DP_OLCKNB', which means locking is performed without blocking.
|
||||||
|
*
|
||||||
|
* While connecting as a writer, an exclusive lock is invoked to
|
||||||
|
* the database file. While connecting as a reader, a shared lock is
|
||||||
|
* invoked to the database file. The thread blocks until the lock is
|
||||||
|
* achieved. If `DP_ONOLCK' is used, the application is responsible
|
||||||
|
* for exclusion control.
|
||||||
|
* The code below uses for
|
||||||
|
* write, delete: DP_OLCKNB
|
||||||
|
* read: DP_OLCKNB
|
||||||
|
* This means that a write fails if one or many reads are occurring, and
|
||||||
|
* a read or write fails if a write is occurring, and
|
||||||
|
* QDBM allows a single write _or_ multiple readers, but
|
||||||
|
* not both. This is obviously extremely limiting.
|
||||||
|
* NOTE, the locking in netconf and xmldb is a write lock.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
|
@ -33,10 +52,10 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
#if defined(HAVE_DEPOT_H) || defined(HAVE_QDBM_DEPOT_H)
|
|
||||||
#ifdef HAVE_DEPOT_H
|
#ifdef HAVE_DEPOT_H
|
||||||
#include <depot.h> /* qdb api */
|
#include <depot.h> /* qdb api */
|
||||||
#else /* HAVE_QDBM_DEPOT_H */
|
#else /* HAVE_QDBM_DEPOT_H */
|
||||||
|
|
@ -57,7 +76,8 @@
|
||||||
* @param[in] omode see man dpopen
|
* @param[in] omode see man dpopen
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
db_init_mode(char *file, int omode)
|
db_init_mode(char *file,
|
||||||
|
int omode)
|
||||||
{
|
{
|
||||||
DEPOT *dp;
|
DEPOT *dp;
|
||||||
|
|
||||||
|
|
@ -85,6 +105,16 @@ db_init(char *file)
|
||||||
return db_init_mode(file, DP_OWRITER | DP_OCREAT ); /* DP_OTRUNC? */
|
return db_init_mode(file, DP_OWRITER | DP_OCREAT ); /* DP_OTRUNC? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
db_delete(char *file)
|
||||||
|
{
|
||||||
|
if (unlink(file) < 0){
|
||||||
|
clicon_err(OE_DB, errno, "unlink %s", file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Write data to database
|
/*! Write data to database
|
||||||
* @param[in] file database file
|
* @param[in] file database file
|
||||||
* @param[in] key database key
|
* @param[in] key database key
|
||||||
|
|
@ -99,7 +129,7 @@ db_set(char *file, char *key, void *data, size_t datalen)
|
||||||
DEPOT *dp;
|
DEPOT *dp;
|
||||||
|
|
||||||
/* Open database for writing */
|
/* Open database for writing */
|
||||||
if ((dp = dpopen(file, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, DP_OWRITER|DP_OLCKNB , 0)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "db_set: dpopen(%s): %s",
|
clicon_err(OE_DB, 0, "db_set: dpopen(%s): %s",
|
||||||
file,
|
file,
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
|
|
@ -263,7 +293,6 @@ db_del(char *file, char *key)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Check if entry in database exists
|
/*! Check if entry in database exists
|
||||||
* @param[in] file database file
|
* @param[in] file database file
|
||||||
* @param[in] key database key
|
* @param[in] key database key
|
||||||
|
|
@ -457,6 +486,78 @@ db_sanitize(char *rx, const char *label)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 /* Test program */
|
||||||
|
/*
|
||||||
|
* Turn this on to get an xpath test program
|
||||||
|
* Usage: clicon_xpath [<xpath>]
|
||||||
|
* read xml from input
|
||||||
|
* Example compile:
|
||||||
|
gcc -g -o qdb -I. -I../clixon ./clixon_qdb.c -lclixon -lcligen -lqdbm
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
usage(char *argv0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage:\n");
|
||||||
|
fprintf(stderr, "\t%s init <filename>\n", argv0);
|
||||||
|
fprintf(stderr, "\t%s read <filename> <key>\n", argv0);
|
||||||
|
fprintf(stderr, "\t%s write <filename> <key> <val>\n", argv0);
|
||||||
|
fprintf(stderr, "\t%s openread <filename>\n", argv0);
|
||||||
|
fprintf(stderr, "\t%s openwrite <filename>\n", argv0);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *verb;
|
||||||
|
char *filename;
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
size_t len;
|
||||||
|
DEPOT *dp;
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
usage(argv[0]);
|
||||||
|
clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR);
|
||||||
|
verb = argv[1];
|
||||||
|
filename = argv[2];
|
||||||
|
if (strcmp(verb, "init")==0){
|
||||||
|
db_init(filename);
|
||||||
|
}
|
||||||
|
else if (strcmp(verb, "read")==0){
|
||||||
|
if (argc < 4)
|
||||||
|
usage(argv[0]);
|
||||||
|
key = argv[3];
|
||||||
|
db_get_alloc(filename, key, (void**)&val, &len);
|
||||||
|
fprintf(stdout, "%s\n", val);
|
||||||
|
}
|
||||||
|
else if (strcmp(verb, "write")==0){
|
||||||
|
if (argc < 5)
|
||||||
|
usage(argv[0]);
|
||||||
|
key = argv[3];
|
||||||
|
val = argv[4];
|
||||||
|
db_set(filename, key, val, strlen(val)+1);
|
||||||
|
}
|
||||||
|
else if (strcmp(verb, "openread")==0){
|
||||||
|
if ((dp = dpopen(filename, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
||||||
|
clicon_err(OE_DB, dpecode, "dbopen: %s",
|
||||||
|
dperrmsg(dpecode));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sleep(1000000);
|
||||||
|
}
|
||||||
|
else if (strcmp(verb, "openwrite")==0){
|
||||||
|
if ((dp = dpopen(filename, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
||||||
|
clicon_err(OE_DB, dpecode, "dbopen: %s",
|
||||||
|
dperrmsg(dpecode));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sleep(1000000);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* Test program */
|
||||||
|
|
||||||
#endif /* DEPOT */
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ struct db_pair {
|
||||||
*/
|
*/
|
||||||
int db_init(char *file);
|
int db_init(char *file);
|
||||||
|
|
||||||
|
int db_delete(char *file);
|
||||||
|
|
||||||
int db_set(char *file, char *key, void *data, size_t datalen);
|
int db_set(char *file, char *key, void *data, size_t datalen);
|
||||||
|
|
||||||
int db_get(char *file, char *key, void *data, size_t *datalen);
|
int db_get(char *file, char *key, void *data, size_t *datalen);
|
||||||
|
|
|
||||||
|
|
@ -45,19 +45,23 @@
|
||||||
* The given string is split into a vector where the delimiter can be
|
* The given string is split into a vector where the delimiter can be
|
||||||
* any of the characters in the specified delimiter string.
|
* any of the characters in the specified delimiter string.
|
||||||
*
|
*
|
||||||
* See also clicon_strsplit() which is similar by operates on a full string
|
|
||||||
* delimiter rather than individual character delimiters.
|
|
||||||
*
|
|
||||||
* The vector returned is one single memory chunk that must be unchunked
|
* The vector returned is one single memory chunk that must be unchunked
|
||||||
* by the caller
|
* by the caller
|
||||||
*
|
*
|
||||||
* @param string String to be split
|
* @param[in] string String to be split
|
||||||
* @param delim String of delimiter characters
|
* @param[in] delim String of delimiter characters
|
||||||
* @param nvec Number of entries in returned vector
|
* @param[out] nvec Number of entries in returned vector
|
||||||
* @param label Chunk label for returned vector
|
* @param[in] label Chunk label for returned vector
|
||||||
|
* @retval vec Vector of strings. Free with unchunk
|
||||||
|
* @retval NULL Error
|
||||||
|
* @see clicon_strsplit Operates on full string delimiters rather than
|
||||||
|
* individual character delimiters.
|
||||||
*/
|
*/
|
||||||
char **
|
char **
|
||||||
clicon_sepsplit (char *string, char *delim, int *nvec, const char *label)
|
clicon_sepsplit (char *string,
|
||||||
|
char *delim,
|
||||||
|
int *nvec,
|
||||||
|
const char *label)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
size_t siz;
|
size_t siz;
|
||||||
|
|
@ -94,19 +98,25 @@ clicon_sepsplit (char *string, char *delim, int *nvec, const char *label)
|
||||||
* the full delimiter string. The matched delimiters are not part of the
|
* the full delimiter string. The matched delimiters are not part of the
|
||||||
* resulting vector.
|
* resulting vector.
|
||||||
*
|
*
|
||||||
* See also clicon_sepsplit() which is similar by operates on individual
|
* See also clicon_sepsplit() which is similar
|
||||||
* character delimiters rather then a full string delimiter.
|
|
||||||
*
|
*
|
||||||
* The vector returned is one single memory chunk that must be unchunked
|
* The vector returned is one single memory chunk that must be unchunked
|
||||||
* by the caller
|
* by the caller
|
||||||
*
|
*
|
||||||
* @param string String to be split
|
* @param[in] string String to be split
|
||||||
* @param delim String of delimiter characters
|
* @param[in] delim String of delimiter characters
|
||||||
* @param nvec Number of entries in returned vector
|
* @param[out] nvec Number of entries in returned vector
|
||||||
* @param label Chunk label for returned vector
|
* @param[in] label Chunk label for returned vector
|
||||||
|
* @retval vec Vector of strings. Free with unchunk
|
||||||
|
* @retval NULL Error
|
||||||
|
* @see clicon_sepsplit Operates on individual character delimiters rather
|
||||||
|
* than full string delimiter.
|
||||||
*/
|
*/
|
||||||
char **
|
char **
|
||||||
clicon_strsplit (char *string, char *delim, int *nvec, const char *label)
|
clicon_strsplit (char *string,
|
||||||
|
char *delim,
|
||||||
|
int *nvec,
|
||||||
|
const char *label)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
size_t siz;
|
size_t siz;
|
||||||
|
|
@ -142,15 +152,18 @@ clicon_strsplit (char *string, char *delim, int *nvec, const char *label)
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Concatenate elements of a string array into a string.
|
||||||
/*
|
* An optional delimiter string can be specified which will be inserted betwen
|
||||||
* Concatenate elements of a string array into a string. An optiona delimiter
|
* each element.
|
||||||
* string can be specified which will be inserted betwen each element.
|
* @param[in] label Chunk label for returned vector
|
||||||
* Resulting string is chunk:ed using the specified group label and need to be
|
* @retval str Joined string. Free with unchunk()
|
||||||
* unchunked by the caller
|
* @retval NULL Failure
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
clicon_strjoin (int argc, char **argv, char *delim, const char *label)
|
clicon_strjoin (int argc,
|
||||||
|
char **argv,
|
||||||
|
char *delim,
|
||||||
|
const char *label)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -176,12 +189,15 @@ clicon_strjoin (int argc, char **argv, char *delim, const char *label)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Trim whitespace in beginning and end of string.
|
||||||
* Trim of whitespace in beginning and end of string.
|
*
|
||||||
* A new string is returned, chunked with specified label
|
* @param[in] label Chunk label for returned vector
|
||||||
|
* @retval str Trimmed string. Free with unchunk()
|
||||||
|
* @retval NULL Failure
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
clicon_strtrim(char *str, const char *label)
|
clicon_strtrim(char *str,
|
||||||
|
const char *label)
|
||||||
{
|
{
|
||||||
char *start, *end, *new;
|
char *start, *end, *new;
|
||||||
|
|
||||||
|
|
@ -200,15 +216,18 @@ clicon_strtrim(char *str, const char *label)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Given a string s, on format: a[b], separate it into two parts: a and b
|
||||||
* clicon_sep
|
|
||||||
* given a string s, on format: a[b], separate it into two parts: a and b
|
|
||||||
* [] are separators.
|
* [] are separators.
|
||||||
* alterative use:
|
* alterative use:
|
||||||
* a/b -> a and b (where sep = "/")
|
* a/b -> a and b (where sep = "/")
|
||||||
|
* @param[in] label Chunk label for returned vector
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_sep(char *s, const char sep[2], const char *label, char**a0, char **b0)
|
clicon_sep(char *s,
|
||||||
|
const char sep[2],
|
||||||
|
const char *label,
|
||||||
|
char **a0,
|
||||||
|
char **b0)
|
||||||
{
|
{
|
||||||
char *a = NULL;
|
char *a = NULL;
|
||||||
char *b = NULL;
|
char *b = NULL;
|
||||||
|
|
@ -246,12 +265,12 @@ clicon_sep(char *s, const char sep[2], const char *label, char**a0, char **b0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*! strndup() for systems without it, such as xBSD
|
||||||
* strndup() for systems without it, such as xBSD
|
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *
|
char *
|
||||||
clicon_strndup (const char *str, size_t len)
|
clicon_strndup (const char *str,
|
||||||
|
size_t len)
|
||||||
{
|
{
|
||||||
char *new;
|
char *new;
|
||||||
size_t slen;
|
size_t slen;
|
||||||
|
|
@ -270,16 +289,19 @@ clicon_strndup (const char *str, size_t len)
|
||||||
}
|
}
|
||||||
#endif /* ! HAVE_STRNDUP */
|
#endif /* ! HAVE_STRNDUP */
|
||||||
|
|
||||||
/*
|
/*! Match string against regexp.
|
||||||
* clicon_strmatch - Match string against regexp.
|
|
||||||
*
|
*
|
||||||
* Returns -1 on failure, 0 on no matach or >0 (length of matching substring)
|
* If a match pointer is given, the matching substring
|
||||||
* in case of a match. If a match pointer is given, the matching substring
|
|
||||||
* will be allocated 'match' will be pointing to it. The match string must
|
* will be allocated 'match' will be pointing to it. The match string must
|
||||||
* be free:ed by the application.
|
* be free:ed by the application.
|
||||||
|
* @retval -1 Failure
|
||||||
|
* @retval 0 No match
|
||||||
|
* @retval >0 Match: Length of matching substring
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_strmatch(const char *str, const char *regexp, char **match)
|
clicon_strmatch(const char *str,
|
||||||
|
const char *regexp,
|
||||||
|
char **match)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
int status;
|
int status;
|
||||||
|
|
@ -316,12 +338,14 @@ clicon_strmatch(const char *str, const char *regexp, char **match)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Substitute pattern in string.
|
||||||
* clicon_strsub - substitute pattern in string.
|
* @retval str Malloc:ed string on success, use free to deallocate
|
||||||
* Returns new malloc:ed string on success or NULL on failure.
|
* @retval NULL Failure.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
clicon_strsub(char *str, char *from, char *to)
|
clicon_strsub(char *str,
|
||||||
|
char *from,
|
||||||
|
char *to)
|
||||||
{
|
{
|
||||||
char **vec;
|
char **vec;
|
||||||
int nvec;
|
int nvec;
|
||||||
|
|
|
||||||
|
|
@ -588,7 +588,9 @@ xml_find_body(cxobj *xn, char *name)
|
||||||
* (otherwise it will not)
|
* (otherwise it will not)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_prune(cxobj *xparent, cxobj *xchild, int purge)
|
xml_prune(cxobj *xparent,
|
||||||
|
cxobj *xchild,
|
||||||
|
int purge)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
cxobj *xc = NULL;
|
cxobj *xc = NULL;
|
||||||
|
|
@ -648,10 +650,13 @@ xml_free(cxobj *x)
|
||||||
* @param[in] xn clicon xml tree
|
* @param[in] xn clicon xml tree
|
||||||
* @param[in] level how many spaces to insert before each line
|
* @param[in] level how many spaces to insert before each line
|
||||||
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
* See also clicon_xml2cbuf
|
* @see clicon_xml2cbuf
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint)
|
clicon_xml2file(FILE *f,
|
||||||
|
cxobj *xn,
|
||||||
|
int level,
|
||||||
|
int prettyprint)
|
||||||
{
|
{
|
||||||
cbuf *cb;
|
cbuf *cb;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -689,7 +694,10 @@ clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint)
|
||||||
* See also clicon_xml2file
|
* See also clicon_xml2file
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_xml2cbuf(cbuf *cb, cxobj *cx, int level, int prettyprint)
|
clicon_xml2cbuf(cbuf *cb,
|
||||||
|
cxobj *cx,
|
||||||
|
int level,
|
||||||
|
int prettyprint)
|
||||||
{
|
{
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
|
|
||||||
|
|
@ -797,7 +805,9 @@ FSM(char *tag, char ch, int state)
|
||||||
* May block
|
* May block
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_xml_parse_file(int fd, cxobj **cx, char *endtag)
|
clicon_xml_parse_file(int fd,
|
||||||
|
cxobj **cx,
|
||||||
|
char *endtag)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
@ -869,7 +879,8 @@ clicon_xml_parse_file(int fd, cxobj **cx, char *endtag)
|
||||||
* cxobj *cx = NULL;
|
* cxobj *cx = NULL;
|
||||||
* str = strdup(...);
|
* str = strdup(...);
|
||||||
* str0 = str;
|
* str0 = str;
|
||||||
* clicon_xml_parse_string(&str0, &cx)
|
* if (clicon_xml_parse_string(&str0, &cx) < 0)
|
||||||
|
* err;
|
||||||
* free(str0);
|
* free(str0);
|
||||||
* xml_free(cx);
|
* xml_free(cx);
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
* XML database
|
* XML database
|
||||||
* TODO: xmldb_del: or dbxml_put_xkey delete
|
* TODO: xmldb_del: or dbxml_put_xkey delete
|
||||||
* TODO: xmldb_get: xpath: only load partial tree
|
|
||||||
*/
|
*/
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
|
@ -34,6 +33,9 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
|
@ -43,6 +45,7 @@
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_file.h"
|
||||||
#include "clixon_queue.h"
|
#include "clixon_queue.h"
|
||||||
#include "clixon_string.h"
|
#include "clixon_string.h"
|
||||||
#include "clixon_chunk.h"
|
#include "clixon_chunk.h"
|
||||||
|
|
@ -52,8 +55,10 @@
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_options.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
#include "clixon_xml_parse.h"
|
#include "clixon_xml_parse.h"
|
||||||
|
#include "clixon_xml_db_rpc.h"
|
||||||
#include "clixon_xml_db.h"
|
#include "clixon_xml_db.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -331,7 +336,95 @@ xmlkeyfmt2xpath(char *xkfmt,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Database locking for candidate and running non-persistent
|
||||||
|
* Store an integer for running and candidate containing
|
||||||
|
* the session-id of the client holding the lock.
|
||||||
|
*/
|
||||||
|
static int _running_locked = 0;
|
||||||
|
static int _candidate_locked = 0;
|
||||||
|
|
||||||
|
/*! Lock database
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
db_lock(char *db,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
if (strcmp("running", db) == 0)
|
||||||
|
_running_locked = pid;
|
||||||
|
else if (strcmp("candidate", db) == 0)
|
||||||
|
_candidate_locked = pid;
|
||||||
|
clicon_debug(1, "%s: locked by %u", db, pid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unlock database
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
db_unlock(char *db)
|
||||||
|
{
|
||||||
|
if (strcmp("running", db) == 0)
|
||||||
|
_running_locked = 0;
|
||||||
|
else if (strcmp("candidate", db) == 0)
|
||||||
|
_candidate_locked = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! returns id of locker
|
||||||
|
* @retval 0 Not locked
|
||||||
|
* @retval >0 Id of locker
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
db_islocked(char *db)
|
||||||
|
{
|
||||||
|
if (strcmp("running", db) == 0)
|
||||||
|
return (_running_locked);
|
||||||
|
else if (strcmp("candidate", db) == 0)
|
||||||
|
return(_candidate_locked);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Translate from symbolic database name to actual filename in file-system
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Symbolic database name, eg "candidate", "running"
|
||||||
|
* @param[out] filename Filename. Unallocate after use with free()
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* The filename reside in CLICON_XMLDB_DIR option
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
db2file(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
char **filename)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb;
|
||||||
|
char *dir;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((dir = clicon_xmldb_dir(h)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "CLICON_XMLDB_DIR not set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (strcmp(db, "running") != 0 &&
|
||||||
|
strcmp(db, "candidate") != 0 &&
|
||||||
|
strcmp(db, "tmp") != 0){
|
||||||
|
clicon_err(OE_XML, 0, "Unexpected database: %s", db);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cb, "%s/%s_db", dir, db);
|
||||||
|
if ((*filename = strdup(cbuf_get(cb))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Help function to append key values from an xml list to a cbuf
|
/*! Help function to append key values from an xml list to a cbuf
|
||||||
* Example, a yang node x with keys a and b results in "x/a/b"
|
* Example, a yang node x with keys a and b results in "x/a/b"
|
||||||
|
|
@ -415,7 +508,6 @@ create_keyvalues(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Prune everything that has not been marked
|
/*! Prune everything that has not been marked
|
||||||
* @param[in] xt XML tree with some node marked
|
* @param[in] xt XML tree with some node marked
|
||||||
* @param[out] upmark Set if a child (recursively) has marked set.
|
* @param[out] upmark Set if a child (recursively) has marked set.
|
||||||
|
|
@ -672,22 +764,16 @@ xml_default(cxobj *x,
|
||||||
* @param[in] dbname Name of database to search in (filename including dir path
|
* @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[in] xpath String with XPATH syntax (or NULL for all)
|
||||||
* @param[in] yspec Yang specification
|
* @param[in] yspec Yang specification
|
||||||
|
* @param[in] vector If set, return list of results in xvec
|
||||||
* @param[out] xtop XML tree. Freed by xml_free()
|
* @param[out] xtop XML tree. Freed by xml_free()
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @code
|
|
||||||
* cxobj *xt;
|
|
||||||
* yang_spec *yspec = clicon_dbspec_yang(h);
|
|
||||||
* if (xmldb_get(dbname, "/interfaces/interface[name="eth*"]", yspec, &xt) < 0)
|
|
||||||
* err;
|
|
||||||
* xml_free(xt);
|
|
||||||
* @endcode
|
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
xmldb_get(char *dbname,
|
xmldb_get_tree(char *dbname,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
yang_spec *yspec,
|
yang_spec *yspec,
|
||||||
cxobj **xtop)
|
cxobj **xtop)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -780,7 +866,7 @@ xmldb_get(char *dbname,
|
||||||
* @see xpath_vec
|
* @see xpath_vec
|
||||||
* @see xmldb_get
|
* @see xmldb_get
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
xmldb_get_vec(char *dbname,
|
xmldb_get_vec(char *dbname,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
yang_spec *yspec,
|
yang_spec *yspec,
|
||||||
|
|
@ -803,6 +889,7 @@ xmldb_get_vec(char *dbname,
|
||||||
for (i = 0; i < npairs; i++)
|
for (i = 0; i < npairs; i++)
|
||||||
fprintf(stderr, "%s %s\n", pairs[i].dp_key, pairs[i].dp_val?pairs[i].dp_val:"");
|
fprintf(stderr, "%s %s\n", pairs[i].dp_key, pairs[i].dp_val?pairs[i].dp_val:"");
|
||||||
|
|
||||||
|
/* Read in whole tree */
|
||||||
for (i = 0; i < npairs; i++) {
|
for (i = 0; i < npairs; i++) {
|
||||||
if (get(dbname,
|
if (get(dbname,
|
||||||
yspec,
|
yspec,
|
||||||
|
|
@ -827,7 +914,86 @@ xmldb_get_vec(char *dbname,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_get */
|
||||||
|
static int
|
||||||
|
xmldb_get_local(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
char *xpath,
|
||||||
|
int vector,
|
||||||
|
cxobj **xtop,
|
||||||
|
cxobj ***xvec,
|
||||||
|
size_t *xlen)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_spec *yspec;
|
||||||
|
char *dbname = NULL;
|
||||||
|
|
||||||
|
if (db2file(h, db, &dbname) < 0)
|
||||||
|
goto done;
|
||||||
|
if (dbname==NULL){
|
||||||
|
clicon_err(OE_XML, 0, "dbname NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (vector){
|
||||||
|
if (xmldb_get_vec(dbname, xpath, yspec, xtop, xvec, xlen) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (xmldb_get_tree(dbname, xpath, yspec, xtop) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (dbname)
|
||||||
|
free(dbname);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Get content of database using xpath.
|
||||||
|
* The function returns a minimal tree that includes all sub-trees that match
|
||||||
|
* xpath.
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db running | candidate
|
||||||
|
* @param[in] xpath String with XPATH syntax (or NULL for all)
|
||||||
|
* @param[in] vector If set, return list of results in xvec, else single tree.
|
||||||
|
* @param[out] xtop XML tree. Freed by 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;
|
||||||
|
* yang_spec *yspec = clicon_dbspec_yang(h);
|
||||||
|
* if (xmldb_get(dbname, "/interfaces/interface[name="eth"]", yspec,
|
||||||
|
* 1, &xt, &xvec, &xlen) < 0)
|
||||||
|
* err;
|
||||||
|
* for (i=0; i<xlen; i++){
|
||||||
|
* xn = xv[i];
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* xml_free(xt);
|
||||||
|
* free(xvec);
|
||||||
|
* @endcode
|
||||||
|
* @see xpath_vec
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_get(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
char *xpath,
|
||||||
|
int vector,
|
||||||
|
cxobj **xtop,
|
||||||
|
cxobj ***xvec,
|
||||||
|
size_t *xlen)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_get_rpc(h, db, xpath, vector, xtop, xvec, xlen);
|
||||||
|
else
|
||||||
|
return xmldb_get_local(h, db, xpath, vector, xtop, xvec, xlen);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Get value of the "operation" attribute and change op if given
|
/*! Get value of the "operation" attribute and change op if given
|
||||||
* @param[in] xn XML node
|
* @param[in] xn XML node
|
||||||
|
|
@ -950,13 +1116,57 @@ put(char *dbname,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_put */
|
||||||
|
static int
|
||||||
|
xmldb_put_local(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cxobj *xt,
|
||||||
|
enum operation_type op)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x = NULL;
|
||||||
|
yang_stmt *ys;
|
||||||
|
yang_spec *yspec;
|
||||||
|
char *dbfilename = NULL;
|
||||||
|
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (db2file(h, db, &dbfilename) < 0)
|
||||||
|
goto done;
|
||||||
|
if (op == OP_REPLACE){
|
||||||
|
if (db_delete(dbfilename) < 0)
|
||||||
|
goto done;
|
||||||
|
if (db_init(dbfilename) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
|
||||||
|
if ((ys = yang_find_topnode(yspec, xml_name(x))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", xml_name(x));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (put(dbfilename, /* database name */
|
||||||
|
x, /* xml root node */
|
||||||
|
ys, /* yang statement of xml node */
|
||||||
|
op, /* operation, eg merge/delete */
|
||||||
|
"" /* aggregate xml key */
|
||||||
|
) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (dbfilename)
|
||||||
|
free(dbfilename);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Modify database provided an xml tree and an operation
|
/*! Modify database provided an xml tree and an operation
|
||||||
* @param[in] dbname Name of database to search in (filename including dir path)
|
* @param[in] dbname Name of database to search in (filename including dir path)
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running or candidate
|
||||||
* @param[in] xt xml-tree. Top-level symbol is dummy
|
* @param[in] xt xml-tree. Top-level symbol is dummy
|
||||||
* @param[in] yspec Yang specification
|
|
||||||
* @param[in] op OP_MERGE: just add it.
|
* @param[in] op OP_MERGE: just add it.
|
||||||
OP_REPLACE: first delete whole database
|
* OP_REPLACE: first delete whole database
|
||||||
OP_NONE: operation attribute in xml determines operation
|
* OP_NONE: operation attribute in xml determines operation
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* The xml may contain the "operation" attribute which defines the operation.
|
* The xml may contain the "operation" attribute which defines the operation.
|
||||||
|
|
@ -968,59 +1178,24 @@ put(char *dbname,
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmldb_put(char *dbname,
|
xmldb_put(clicon_handle h,
|
||||||
|
char *db,
|
||||||
cxobj *xt,
|
cxobj *xt,
|
||||||
yang_spec *yspec,
|
|
||||||
enum operation_type op)
|
enum operation_type op)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
if (clicon_xmldb_rpc(h))
|
||||||
cxobj *x = NULL;
|
return xmldb_put_rpc(h, db, xt, op);
|
||||||
yang_stmt *ys;
|
else
|
||||||
|
return xmldb_put_local(h, db, xt, op);
|
||||||
if (op == OP_REPLACE){
|
|
||||||
unlink(dbname);
|
|
||||||
if (db_init(dbname) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL){
|
|
||||||
if ((ys = yang_find_topnode(yspec, xml_name(x))) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", xml_name(x));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (put(dbname, /* database name */
|
|
||||||
x, /* xml root node */
|
|
||||||
ys, /* yang statement of xml node */
|
|
||||||
op, /* operation, eg merge/delete */
|
|
||||||
"" /* aggregate xml key */
|
|
||||||
) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_put_xkey */
|
||||||
/*! Modify database provided an XML database key and an operation
|
static int
|
||||||
* @param[in] dbname Name of database to search in (filename including dir path)
|
xmldb_put_xkey_local(clicon_handle h,
|
||||||
* @param[in] xk XML Key, eg /aa/bb/17/name
|
char *db,
|
||||||
* @param[in] val Key value, eg "17"
|
char *xk,
|
||||||
* @param[in] yspec Yang specification
|
char *val,
|
||||||
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
enum operation_type op)
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @code
|
|
||||||
* yang_spec *yspec = clicon_dbspec_yang(h);
|
|
||||||
* if (xmldb_put_xkey(dbname, "/aa/bb/17/name", "17", yspec, OP_MERGE) < 0)
|
|
||||||
* err;
|
|
||||||
* @endcode
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xmldb_put_xkey(char *dbname,
|
|
||||||
char *xk,
|
|
||||||
char *val,
|
|
||||||
yang_spec *yspec,
|
|
||||||
enum operation_type op)
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
|
|
@ -1040,7 +1215,12 @@ xmldb_put_xkey(char *dbname,
|
||||||
int exists;
|
int exists;
|
||||||
int npairs;
|
int npairs;
|
||||||
struct db_pair *pairs;
|
struct db_pair *pairs;
|
||||||
|
yang_spec *yspec;
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (db2file(h, db, &filename) < 0)
|
||||||
|
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);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1109,13 +1289,13 @@ xmldb_put_xkey(char *dbname,
|
||||||
cbuf_reset(csubkey);
|
cbuf_reset(csubkey);
|
||||||
cprintf(csubkey, "%s/%s", cbuf_get(ckey), keyname);
|
cprintf(csubkey, "%s/%s", cbuf_get(ckey), keyname);
|
||||||
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
||||||
if (db_set(dbname, cbuf_get(csubkey), val2, strlen(val2)+1) < 0)
|
if (db_set(filename, cbuf_get(csubkey), val2, strlen(val2)+1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
||||||
if (db_set(dbname, cbuf_get(ckey), NULL, 0) < 0)
|
if (db_set(filename, cbuf_get(ckey), NULL, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1124,7 +1304,7 @@ xmldb_put_xkey(char *dbname,
|
||||||
/* final key */
|
/* final key */
|
||||||
switch (op){
|
switch (op){
|
||||||
case OP_CREATE:
|
case OP_CREATE:
|
||||||
if ((exists = db_exists(dbname, xk)) < 0)
|
if ((exists = db_exists(filename, xk)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (exists == 1){
|
if (exists == 1){
|
||||||
clicon_err(OE_DB, 0, "OP_CREATE: %s already exists in database", xk);
|
clicon_err(OE_DB, 0, "OP_CREATE: %s already exists in database", xk);
|
||||||
|
|
@ -1133,15 +1313,15 @@ xmldb_put_xkey(char *dbname,
|
||||||
case OP_MERGE:
|
case OP_MERGE:
|
||||||
case OP_REPLACE:
|
case OP_REPLACE:
|
||||||
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
||||||
if (db_set(dbname, xk, val, strlen(val)+1) < 0)
|
if (db_set(filename, xk, val, strlen(val)+1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (db_set(dbname, xk, NULL, 0) < 0)
|
if (db_set(filename, xk, NULL, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case OP_DELETE:
|
case OP_DELETE:
|
||||||
if ((exists = db_exists(dbname, xk)) < 0)
|
if ((exists = db_exists(filename, xk)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (exists == 0){
|
if (exists == 0){
|
||||||
clicon_err(OE_DB, 0, "OP_DELETE: %s does not exists in database", xk);
|
clicon_err(OE_DB, 0, "OP_DELETE: %s does not exists in database", xk);
|
||||||
|
|
@ -1152,10 +1332,10 @@ xmldb_put_xkey(char *dbname,
|
||||||
if ((crx = cbuf_new()) == NULL)
|
if ((crx = cbuf_new()) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(crx, "^%s.*$", xk);
|
cprintf(crx, "^%s.*$", xk);
|
||||||
if ((npairs = db_regexp(dbname, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0)
|
if ((npairs = db_regexp(filename, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i = 0; i < npairs; i++) {
|
for (i = 0; i < npairs; i++) {
|
||||||
if (db_del(dbname, pairs[i].dp_key) < 0)
|
if (db_del(filename, pairs[i].dp_key) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1164,6 +1344,8 @@ xmldb_put_xkey(char *dbname,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (filename)
|
||||||
|
free(filename);
|
||||||
if (ckey)
|
if (ckey)
|
||||||
cbuf_free(ckey);
|
cbuf_free(ckey);
|
||||||
if (csubkey)
|
if (csubkey)
|
||||||
|
|
@ -1174,17 +1356,45 @@ xmldb_put_xkey(char *dbname,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Raw dump of database, just keys and values, no xml interpretation
|
|
||||||
* param[in] f File
|
/*! Modify database provided an XML database key and an operation
|
||||||
* param[in] dbname Name of database
|
* @param[in] dbname Name of database to search in (filename including dir path)
|
||||||
* param[in] rxkey Key regexp, eg "^.*$"
|
* @param[in] xk XML Key, eg /aa/bb/17/name
|
||||||
|
* @param[in] val Key value, eg "17"
|
||||||
|
* @param[in] yspec Yang specification
|
||||||
|
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* if (xmldb_put_xkey(h, db, "/aa/bb/17/name", "17", OP_MERGE) < 0)
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmldb_dump(FILE *f,
|
xmldb_put_xkey(clicon_handle h,
|
||||||
char *dbname,
|
char *db,
|
||||||
char *rxkey)
|
char *xk,
|
||||||
|
char *val,
|
||||||
|
enum operation_type op)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_put_xkey_rpc(h, db, xk, val, op);
|
||||||
|
else
|
||||||
|
return xmldb_put_xkey_local(h, db, xk, val, op);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Raw dump of database, just keys and values, no xml interpretation
|
||||||
|
* @param[in] f File
|
||||||
|
* @param[in] dbfile File-name of database. This is a local file
|
||||||
|
* @param[in] rxkey Key regexp, eg "^.*$"
|
||||||
|
* @note This function can only be called locally.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_dump(FILE *f,
|
||||||
|
char *dbfilename,
|
||||||
|
char *rxkey)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
int npairs;
|
int npairs;
|
||||||
struct db_pair *pairs;
|
struct db_pair *pairs;
|
||||||
|
|
||||||
|
|
@ -1193,29 +1403,270 @@ xmldb_dump(FILE *f,
|
||||||
rxkey = "^.*$";
|
rxkey = "^.*$";
|
||||||
|
|
||||||
/* Get all keys/values for vector */
|
/* Get all keys/values for vector */
|
||||||
if ((npairs = db_regexp(dbname, rxkey, __FUNCTION__, &pairs, 0)) < 0)
|
if ((npairs = db_regexp(dbfilename, rxkey, __FUNCTION__, &pairs, 0)) < 0)
|
||||||
return -1;
|
goto done;
|
||||||
|
|
||||||
for (npairs--; npairs >= 0; npairs--)
|
for (npairs--; npairs >= 0; npairs--)
|
||||||
fprintf(f, "%s %s\n", pairs[npairs].dp_key,
|
fprintf(f, "%s %s\n", pairs[npairs].dp_key,
|
||||||
pairs[npairs].dp_val?pairs[npairs].dp_val:"");
|
pairs[npairs].dp_val?pairs[npairs].dp_val:"");
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
unchunk_group(__FUNCTION__);
|
unchunk_group(__FUNCTION__);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
/*! Local variant of xmldb_copy */
|
||||||
xmldb_init(char *file)
|
static int
|
||||||
|
xmldb_copy_local(clicon_handle h,
|
||||||
|
char *from,
|
||||||
|
char *to)
|
||||||
{
|
{
|
||||||
return db_init(file);
|
int retval = -1;
|
||||||
|
char *fromfile = NULL;
|
||||||
|
char *tofile = NULL;
|
||||||
|
|
||||||
|
/* XXX lock */
|
||||||
|
if (db2file(h, from, &fromfile) < 0)
|
||||||
|
goto done;
|
||||||
|
if (db2file(h, to, &tofile) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_file_copy(fromfile, tofile) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (fromfile)
|
||||||
|
free(fromfile);
|
||||||
|
if (tofile)
|
||||||
|
free(tofile);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1 /* Test program */
|
/*! Copy database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] from Source database copy
|
||||||
|
* @param[in] to Destination database
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_copy(clicon_handle h,
|
||||||
|
char *from,
|
||||||
|
char *to)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_copy_rpc(h, from, to);
|
||||||
|
else
|
||||||
|
return xmldb_copy_local(h, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Local variant of xmldb_lock */
|
||||||
|
static int
|
||||||
|
xmldb_lock_local(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (db_islocked(db)){
|
||||||
|
if (pid != db_islocked(db)){
|
||||||
|
clicon_err(OE_DB, 0, "lock failed: locked by %d", db_islocked(db));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
db_lock(db, pid);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Lock database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @param[in] pid Process id
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_lock(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_lock_rpc(h, db, pid);
|
||||||
|
else
|
||||||
|
return xmldb_lock_local(h, db, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_unlock */
|
||||||
|
static int
|
||||||
|
xmldb_unlock_local(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int pid1;
|
||||||
|
|
||||||
|
pid1 = db_islocked(db);
|
||||||
|
if (pid1){
|
||||||
|
if (pid == pid1)
|
||||||
|
db_unlock(db);
|
||||||
|
else{
|
||||||
|
clicon_err(OE_DB, 0, "unlock failed: locked by %d", pid1);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unlock database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @param[in] pid Process id
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_unlock(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int pid)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_unlock_rpc(h, db, pid);
|
||||||
|
else
|
||||||
|
return xmldb_unlock_local(h, db, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_islocked */
|
||||||
|
static int
|
||||||
|
xmldb_islocked_local(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
return db_islocked(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check if database is locked
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 Not locked
|
||||||
|
* @retval >0 Id of locker
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_islocked(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_islocked_rpc(h, db);
|
||||||
|
else
|
||||||
|
return xmldb_islocked_local(h, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_exists */
|
||||||
|
static int
|
||||||
|
xmldb_exists_local(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *filename = NULL;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (db2file(h, db, &filename) < 0)
|
||||||
|
goto done;
|
||||||
|
if (lstat(filename, &sb) < 0)
|
||||||
|
retval = 0;
|
||||||
|
else
|
||||||
|
retval = 1;
|
||||||
|
done:
|
||||||
|
if (filename)
|
||||||
|
free(filename);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check if db exists
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 No it does not exist
|
||||||
|
* @retval 1 Yes it exists
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_exists(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_exists_rpc(h, db);
|
||||||
|
else
|
||||||
|
return xmldb_exists_local(h, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_delete */
|
||||||
|
static int
|
||||||
|
xmldb_delete_local(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
|
if (db2file(h, db, &filename) < 0)
|
||||||
|
goto done;
|
||||||
|
if (db_delete(filename) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (filename)
|
||||||
|
free(filename);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Delete database. Remove file */
|
||||||
|
int
|
||||||
|
xmldb_delete(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_delete_rpc(h, db);
|
||||||
|
else
|
||||||
|
return xmldb_delete_local(h, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Local variant of xmldb_init */
|
||||||
|
static int
|
||||||
|
xmldb_init_local(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
|
if (db2file(h, db, &filename) < 0)
|
||||||
|
goto done;
|
||||||
|
if (db_init(filename) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (filename)
|
||||||
|
free(filename);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Initialize database */
|
||||||
|
int
|
||||||
|
xmldb_init(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
if (clicon_xmldb_rpc(h))
|
||||||
|
return xmldb_init_rpc(h, db);
|
||||||
|
else
|
||||||
|
return xmldb_init_local(h, db);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /* Test program */
|
||||||
/*
|
/*
|
||||||
* Turn this on to get an xpath test program
|
* Turn this on to get an xpath test program
|
||||||
* Usage: clicon_xpath [<xpath>]
|
* Usage: clicon_xpath [<xpath>]
|
||||||
* read xml from input
|
* read xml from input
|
||||||
* Example compile:
|
* Example compile:
|
||||||
gcc -g -o xmldb -I. -I../clicon ./clicon_xmldb.c -lclicon -lcligen
|
gcc -g -o xmldb -I. -I../clixon ./clixon_xmldb.c -lclixon -lcligen
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -1260,7 +1711,7 @@ main(int argc, char **argv)
|
||||||
if (argc < 5)
|
if (argc < 5)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
xpath = argc>5?argv[5]:NULL;
|
xpath = argc>5?argv[5]:NULL;
|
||||||
if (xmldb_get(db, xpath, yspec, &xt) < 0)
|
if (xmldb_get(h, db, xpath, 0, &xt, NULL, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
clicon_xml2file(stdout, xt, 0, 1);
|
clicon_xml2file(stdout, xt, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -1283,7 +1734,7 @@ main(int argc, char **argv)
|
||||||
op = OP_REMOVE;
|
op = OP_REMOVE;
|
||||||
else
|
else
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
if (xmldb_put(db, xn, yspec, op) < 0)
|
if (xmldb_put(h, db, xn, op) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
570
lib/src/clixon_xml_db_rpc.c
Normal file
570
lib/src/clixon_xml_db_rpc.c
Normal file
|
|
@ -0,0 +1,570 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
||||||
|
|
||||||
|
This file is part of CLIXON.
|
||||||
|
|
||||||
|
CLIXON is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
CLIXON is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with CLIXON; see the file LICENSE. If not, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
* XML database
|
||||||
|
* TODO: xmldb_del: or dbxml_put_xkey delete
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clicon */
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_chunk.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_qdb.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_options.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xsl.h"
|
||||||
|
#include "clixon_xml_parse.h"
|
||||||
|
#include "clixon_xml_db.h"
|
||||||
|
#include "clixon_xml_db_rpc.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
xmldb_rpc(clicon_handle h,
|
||||||
|
char *data,
|
||||||
|
size_t len,
|
||||||
|
char *retdata,
|
||||||
|
size_t *retlen
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *dst;
|
||||||
|
uint16_t port;
|
||||||
|
int s = -1;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
if ((dst = clicon_xmldb_addr(h)) == NULL){
|
||||||
|
clicon_err(OE_CFG, errno, "CLICON_XMLDB_ADDR option not set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((port = clicon_xmldb_port(h)) == 0){
|
||||||
|
clicon_err(OE_CFG, errno, "CLICON_XMLDB_PORT option not set");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1)
|
||||||
|
goto done; /* Could check getaddrinfo */
|
||||||
|
if ((s = socket(addr.sin_family, SOCK_STREAM, 0)) < 0) {
|
||||||
|
clicon_err(OE_CFG, errno, "socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0){
|
||||||
|
clicon_err(OE_CFG, errno, "connecting socket inet4");
|
||||||
|
close(s);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (write(s, data, len) < 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "write");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((*retlen = read(s, retdata, *retlen)) < 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "write");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
if (debug > 1)
|
||||||
|
fprintf(stderr, "%s: \"%s\"\n", __FUNCTION__, retdata);
|
||||||
|
done:
|
||||||
|
if (s != -1)
|
||||||
|
close(s);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Send put request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_put_rpc(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
cxobj *xt,
|
||||||
|
enum operation_type op)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
char *opstr;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><put>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
if (op){
|
||||||
|
switch (op){
|
||||||
|
case OP_REPLACE:
|
||||||
|
opstr = "replace";
|
||||||
|
break;
|
||||||
|
case OP_MERGE:
|
||||||
|
opstr = "merge";
|
||||||
|
break;
|
||||||
|
case OP_NONE:
|
||||||
|
opstr = "none";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
|
||||||
|
}
|
||||||
|
cprintf(cb, "<config>");
|
||||||
|
if (clicon_xml2cbuf(cb, xt, 0, 1) < 0)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "</config>");
|
||||||
|
cprintf(cb, "</put></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Send put xkey request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_put_xkey_rpc(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
char *xk,
|
||||||
|
char *val,
|
||||||
|
enum operation_type op)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
char *opstr;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><put-xkey>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
if (op){
|
||||||
|
switch (op){
|
||||||
|
case OP_REPLACE:
|
||||||
|
opstr = "replace";
|
||||||
|
break;
|
||||||
|
case OP_MERGE:
|
||||||
|
opstr = "merge";
|
||||||
|
break;
|
||||||
|
case OP_NONE:
|
||||||
|
opstr = "none";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
|
||||||
|
}
|
||||||
|
cprintf(cb, "<xkey>%s</xkey>", xk);
|
||||||
|
cprintf(cb, "<value>%s</value>", val);
|
||||||
|
cprintf(cb, "</put-xkey></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Send get request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_get_rpc(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
char *xpath,
|
||||||
|
int vector,
|
||||||
|
cxobj **xtop,
|
||||||
|
cxobj ***xvec,
|
||||||
|
size_t *xlen)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt=NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><get>");
|
||||||
|
cprintf(cb, "<source><%s/></source>", db);
|
||||||
|
if (xpath)
|
||||||
|
cprintf(cb, "<xpath>%s</xpath>", xpath);
|
||||||
|
if (vector)
|
||||||
|
cprintf(cb, "<vector/>");
|
||||||
|
cprintf(cb, "</get></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (vector){
|
||||||
|
i=0;
|
||||||
|
if ((*xvec = calloc(xml_child_nr(xt), sizeof(cxobj*))) ==NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "calloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
|
||||||
|
(*xvec)[i++] = xc;
|
||||||
|
}
|
||||||
|
*xlen = i;
|
||||||
|
*xtop = xt;
|
||||||
|
xt = NULL;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if ((xc = xml_child_i(xt, 0)) != NULL){
|
||||||
|
xml_prune(xt, xc, 0); /* kludge to remove top-level tag (eg top/clicon) */
|
||||||
|
xml_parent_set(xc, NULL);
|
||||||
|
if (debug > 1)
|
||||||
|
clicon_xml2file(stderr, xc, 0, 1);
|
||||||
|
}
|
||||||
|
*xtop = xc;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Copy database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] from Source database copy
|
||||||
|
* @param[in] to Destination database
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_copy_rpc(clicon_handle h,
|
||||||
|
char *from,
|
||||||
|
char *to)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><copy>");
|
||||||
|
cprintf(cb, "<source><%s/></source>", from);
|
||||||
|
cprintf(cb, "<target><%s/></target>", to);
|
||||||
|
cprintf(cb, "</copy></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xt, "//ok"))
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Lock database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @param[in] pid Process id
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_lock_rpc(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><lock>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "<id><%u/></id>", id);
|
||||||
|
cprintf(cb, "</lock></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xt, "//ok"))
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Unlock database
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @param[in] pid Process id
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_unlock_rpc(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
int id)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><unlock>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "<id><%u/></id>", id);
|
||||||
|
cprintf(cb, "</unlock></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xt, "//ok"))
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Check if database is locked
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] db Database
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval pid Process id if locked
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_islocked_rpc(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *x;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><islocked>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "</islocked></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xt, "//unlocked"))
|
||||||
|
retval = 0;
|
||||||
|
else
|
||||||
|
if ((x=xpath_first(xt, "//locked")) != NULL)
|
||||||
|
retval = atoi(xml_body(x));
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Send exists request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval -1 Error
|
||||||
|
* @retval 0 No it does not exist
|
||||||
|
* @retval 1 Yes it exists
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_exists_rpc(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><exists>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "</exists></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xt, "//ok"))
|
||||||
|
retval = 1;
|
||||||
|
else
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Send delete request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_delete_rpc(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><delete>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "</delete></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Send init request to backend daemon
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db running|candidate
|
||||||
|
* @retval 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xmldb_init_rpc(clicon_handle h,
|
||||||
|
char *db)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
char retbuf[BUFSIZ];
|
||||||
|
char *rb = retbuf;
|
||||||
|
size_t retlen = sizeof(retbuf);
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "<rpc><init>");
|
||||||
|
cprintf(cb, "<target><%s/></target>", db);
|
||||||
|
cprintf(cb, "</init></rpc>]]>]]>");
|
||||||
|
if (xmldb_rpc(h,
|
||||||
|
cbuf_get(cb),
|
||||||
|
cbuf_len(cb)+1,
|
||||||
|
rb, &retlen) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
@ -1910,7 +1910,6 @@ yang_config(yang_stmt *ys)
|
||||||
* @param f file to print to (if one of print options are enabled)
|
* @param f file to print to (if one of print options are enabled)
|
||||||
* @param printspec print database (YANG) specification as read from file
|
* @param printspec print database (YANG) specification as read from file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
yang_spec_main(clicon_handle h,
|
yang_spec_main(clicon_handle h,
|
||||||
FILE *f,
|
FILE *f,
|
||||||
|
|
|
||||||
8
test/README
Normal file
8
test/README
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
Some test cases:
|
||||||
|
With and without xmldb_rpc:
|
||||||
|
set a list entry
|
||||||
|
set a nested entry
|
||||||
|
Completion
|
||||||
|
validate with missing mandatory variable
|
||||||
|
commit
|
||||||
|
delete all
|
||||||
11
test/all.sh
Executable file
11
test/all.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh
|
||||||
|
for test in test*.sh; do
|
||||||
|
echo "Running $test"
|
||||||
|
./$test
|
||||||
|
errcode=$?
|
||||||
|
if [ $errcode -ne 0 ]; then
|
||||||
|
echo "Error in $test errcode=$errcode"
|
||||||
|
exit $errcode
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
32
test/lib.sh
Executable file
32
test/lib.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
testnr=0
|
||||||
|
testnname=
|
||||||
|
clixon_cf=/usr/local/etc/routing.conf
|
||||||
|
# error and exit
|
||||||
|
err(){
|
||||||
|
echo "Error in Test$testnr [$testname] $1"
|
||||||
|
exit $testnr
|
||||||
|
}
|
||||||
|
|
||||||
|
# Increment test number and print a nice string
|
||||||
|
new(){
|
||||||
|
testnr=`expr $testnr + 1`
|
||||||
|
testname=$1
|
||||||
|
echo "Test$testnr [$1]"
|
||||||
|
# sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# clicon_cli tester. First arg is command and second is expected outcome
|
||||||
|
clifn(){
|
||||||
|
cmd=$1
|
||||||
|
expect=$2
|
||||||
|
ret=`$cmd`
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
if [ "$ret" != "$expect" ]; then
|
||||||
|
err "\nExpected:\t\"$expect\"\nGot:\t\"$ret\""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
32
test/test1.sh
Executable file
32
test/test1.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# include err() and new() functions
|
||||||
|
. ./lib.sh
|
||||||
|
|
||||||
|
# kill old backend (if any)
|
||||||
|
new "kill old backend"
|
||||||
|
sudo clixon_backend -zf $clixon_cf
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "start backend"
|
||||||
|
# start new backend
|
||||||
|
sudo clixon_backend -If $clixon_cf -x 0
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
new "cli configure"
|
||||||
|
clifn "clixon_cli -1f $clixon_cf set interfaces interface eth0" ""
|
||||||
|
|
||||||
|
new "cli show configuration"
|
||||||
|
clifn "clixon_cli -1f $clixon_cf show conf cli" "interfaces interface name eth0
|
||||||
|
interfaces interface enabled htrue"
|
||||||
|
|
||||||
|
new "Kill backend"
|
||||||
|
# kill backend
|
||||||
|
sudo clixon_backend -zf $clixon_cf
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
err
|
||||||
|
fi
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue