internal netconf mods
This commit is contained in:
parent
2fcefda831
commit
eec5896797
22 changed files with 665 additions and 1205 deletions
|
|
@ -252,126 +252,49 @@ from_client_get_config(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef notused
|
|
||||||
/*! Internal message: Change entries as XML
|
|
||||||
* @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_xmlput(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
char *db;
|
|
||||||
enum operation_type op;
|
|
||||||
cvec *cvv = NULL;
|
|
||||||
char *str = NULL;
|
|
||||||
char *api_path = NULL;
|
|
||||||
char *xml = NULL;
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
int piddb;
|
|
||||||
cxobj *x;
|
|
||||||
|
|
||||||
if (clicon_msg_xmlput_decode(msg,
|
|
||||||
&db,
|
|
||||||
&op,
|
|
||||||
&api_path,
|
|
||||||
&xml,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* candidate is locked by other client */
|
|
||||||
if (strcmp(db, "candidate") == 0){
|
|
||||||
piddb = xmldb_islocked(h, db);
|
|
||||||
if (piddb && pid != piddb){
|
|
||||||
send_msg_err(s, OE_DB, 0,
|
|
||||||
"lock failed: locked by %d", piddb);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (clicon_xml_parse_string(&xml, &xt) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (strlen(api_path)){
|
|
||||||
if (xt && xml_child_nr(xt)){
|
|
||||||
x = NULL;
|
|
||||||
while ((x = xml_child_each(xt, x, -1)) != NULL) {
|
|
||||||
if (xmldb_put(h, db, op, api_path, x) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (xmldb_put(h, db, op, api_path, NULL) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (xmldb_put(h, db, op, NULL, xt) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (send_msg_netconf_reply(s, "<rpc-reply><ok/></rpc-reply>") < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (str)
|
|
||||||
free(str);
|
|
||||||
if (cvv)
|
|
||||||
cvec_free (cvv);
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*! Internal message: edit-config
|
/*! Internal message: edit-config
|
||||||
*
|
*
|
||||||
|
* @param[in] h Clicon handle
|
||||||
* @param[in] h Clicon handle
|
* @param[in] xe Netconf request xml tree
|
||||||
* @param[in] xe Netconf request xml tree
|
* @param[in] mypid Process/session id of calling client
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @see from_client_xmlput
|
|
||||||
* CLIXON addition:
|
* CLIXON addition:
|
||||||
* <filter type="restconf" select="/data/profile=a" />
|
* <filter type="restconf" select="/data/profile=a" />
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_edit_config(clicon_handle h,
|
from_client_edit_config(clicon_handle h,
|
||||||
cxobj *xn,
|
cxobj *xn,
|
||||||
|
int mypid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *target;
|
char *target;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xc;
|
cxobj *xc;
|
||||||
cxobj *xfilter;
|
cxobj *xfilter;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
enum operation_type operation = OP_MERGE;
|
enum operation_type operation = OP_MERGE;
|
||||||
char *api_path = NULL;
|
char *api_path = NULL;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
if ((target = netconf_db_find(xn, "target")) == NULL){
|
if ((target = netconf_db_find(xn, "target")) == NULL){
|
||||||
clicon_err(OE_XML, 0, "db not found");
|
clicon_err(OE_XML, 0, "db not found");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
/* Check if target locked by other client */
|
||||||
|
piddb = xmldb_islocked(h, target);
|
||||||
|
if (piddb && mypid != piddb){
|
||||||
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
"<error-tag>lock-denied</error-tag>"
|
||||||
|
"<error-type>protocol</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>Operation failed, lock is already held</error-message>"
|
||||||
|
"<error-info><session-id>%d</session-id></error-info>"
|
||||||
|
"</rpc-error></rpc-reply>",
|
||||||
|
piddb);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
/* ie <filter type="restconf" select=<api-path> /> */
|
/* ie <filter type="restconf" select=<api-path> /> */
|
||||||
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
if ((xfilter = xpath_first(xn, "filter")) != NULL)
|
||||||
api_path = xml_find_value(xfilter, "select");
|
api_path = xml_find_value(xfilter, "select");
|
||||||
|
|
@ -387,26 +310,6 @@ from_client_edit_config(clicon_handle h,
|
||||||
}
|
}
|
||||||
if ((xc = xpath_first(xn, "config")) != NULL){
|
if ((xc = xpath_first(xn, "config")) != NULL){
|
||||||
/* XXX see from_client_xmlput() */
|
/* XXX see from_client_xmlput() */
|
||||||
if (api_path){
|
|
||||||
cbuf *cb;
|
|
||||||
cb=cbuf_new();
|
|
||||||
clicon_xml2cbuf(cb, xc, 0, 1);
|
|
||||||
fprintf(stderr, "%s: api_path:%s xml:%s\n",
|
|
||||||
__FUNCTION__, api_path, cbuf_get(cb));
|
|
||||||
cbuf_free(cb);
|
|
||||||
}
|
|
||||||
if (xml_body(xc)!= NULL){
|
|
||||||
if (xmldb_put_xkey(h, target, operation, api_path, xml_body(xc)) < 0){
|
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
|
||||||
"<error-tag>operation-failed</error-tag>"
|
|
||||||
"<error-type>protocol</error-type>"
|
|
||||||
"<error-severity>error</error-severity>"
|
|
||||||
"<error-message>%s</error-message>"
|
|
||||||
"</rpc-error></rpc-reply>", clicon_err_reason);
|
|
||||||
goto ok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
if (xmldb_put(h, target, operation, api_path, xc) < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
|
|
@ -440,14 +343,14 @@ from_client_edit_config(clicon_handle h,
|
||||||
/*! Internal message: Lock database
|
/*! Internal message: Lock database
|
||||||
*
|
*
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] pid Unix process id
|
|
||||||
* @param[in] xe Netconf request xml tree
|
* @param[in] xe Netconf request xml tree
|
||||||
|
* @param[in] pid Unix process id
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_lock(clicon_handle h,
|
from_client_lock(clicon_handle h,
|
||||||
int pid,
|
|
||||||
cxobj *xe,
|
cxobj *xe,
|
||||||
|
int pid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -494,14 +397,14 @@ from_client_lock(clicon_handle h,
|
||||||
/*! Internal message: Unlock database
|
/*! Internal message: Unlock database
|
||||||
*
|
*
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] pid Unix process id
|
|
||||||
* @param[in] xe Netconf request xml tree
|
* @param[in] xe Netconf request xml tree
|
||||||
|
* @param[in] pid Unix process id
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_unlock(clicon_handle h,
|
from_client_unlock(clicon_handle h,
|
||||||
int pid,
|
|
||||||
cxobj *xe,
|
cxobj *xe,
|
||||||
|
int pid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -614,23 +517,25 @@ from_client_kill_session(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Internal message: Copy database from db1 to db2
|
/*! Internal message: Copy database from db1 to db2
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xe Netconf request xml tree
|
* @param[in] xe Netconf request xml tree
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[in] mypid Process/session id of calling client
|
||||||
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error. Send error message back to client.
|
* @retval -1 Error. Send error message back to client.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_copy_config(clicon_handle h,
|
from_client_copy_config(clicon_handle h,
|
||||||
cxobj *xe,
|
cxobj *xe,
|
||||||
|
int mypid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
char *db1;
|
char *source;
|
||||||
char *db2;
|
char *target;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
if ((db1 = netconf_db_find(xe, "source")) == NULL){
|
if ((source = netconf_db_find(xe, "source")) == NULL){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>missing-element</error-tag>"
|
"<error-tag>missing-element</error-tag>"
|
||||||
"<error-type>protocol</error-type>"
|
"<error-type>protocol</error-type>"
|
||||||
|
|
@ -639,7 +544,7 @@ from_client_copy_config(clicon_handle h,
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if ((db2 = netconf_db_find(xe, "target")) == NULL){
|
if ((target = netconf_db_find(xe, "target")) == NULL){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>missing-element</error-tag>"
|
"<error-tag>missing-element</error-tag>"
|
||||||
"<error-type>protocol</error-type>"
|
"<error-type>protocol</error-type>"
|
||||||
|
|
@ -648,7 +553,21 @@ from_client_copy_config(clicon_handle h,
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
if (xmldb_copy(h, db1, db2) < 0){
|
/* Check if target locked by other client */
|
||||||
|
piddb = xmldb_islocked(h, target);
|
||||||
|
if (piddb && mypid != piddb){
|
||||||
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
"<error-tag>lock-denied</error-tag>"
|
||||||
|
"<error-type>protocol</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>Operation failed, lock is already held</error-message>"
|
||||||
|
"<error-info><session-id>%d</session-id></error-info>"
|
||||||
|
"</rpc-error></rpc-reply>",
|
||||||
|
piddb);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmldb_copy(h, source, target) < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
"<error-type>application</error-type>"
|
"<error-type>application</error-type>"
|
||||||
|
|
@ -667,18 +586,20 @@ from_client_copy_config(clicon_handle h,
|
||||||
/*! Internal message: Delete database
|
/*! Internal message: Delete database
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] xe Netconf request xml tree
|
* @param[in] xe Netconf request xml tree
|
||||||
|
* @param[in] mypid Process/session id of calling client
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
|
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error. Send error message back to client.
|
* @retval -1 Error. Send error message back to client.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_delete_config(clicon_handle h,
|
from_client_delete_config(clicon_handle h,
|
||||||
cxobj *xe,
|
cxobj *xe,
|
||||||
|
int mypid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
{
|
{
|
||||||
char *target;
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
char *target;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
if ((target = netconf_db_find(xe, "target")) == NULL||
|
if ((target = netconf_db_find(xe, "target")) == NULL||
|
||||||
strcmp(target, "running")==0){
|
strcmp(target, "running")==0){
|
||||||
|
|
@ -690,6 +611,20 @@ from_client_delete_config(clicon_handle h,
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
/* Check if target locked by other client */
|
||||||
|
piddb = xmldb_islocked(h, target);
|
||||||
|
if (piddb && mypid != piddb){
|
||||||
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
"<error-tag>lock-denied</error-tag>"
|
||||||
|
"<error-type>protocol</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>Operation failed, lock is already held</error-message>"
|
||||||
|
"<error-info><session-id>%d</session-id></error-info>"
|
||||||
|
"</rpc-error></rpc-reply>",
|
||||||
|
piddb);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
if (xmldb_delete(h, target) < 0){
|
if (xmldb_delete(h, target) < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
|
|
@ -807,30 +742,28 @@ from_client_debug(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Internal clicon netconf message has arrived from a client.
|
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
||||||
* @param[in] h Socket where message arrived. read from this.
|
* @param[in] s Socket where message arrived. read from this.
|
||||||
* @param[in] ce Client session entry
|
* @param[in] arg Client entry (from).
|
||||||
* @param[in] msg Clicon message. Contains internal netconf xml message.
|
* @retval 0 OK
|
||||||
* @retval 0 OK. May be ok or error netconf reply
|
* @retval -1 Error Terminates backend and is never called). Instead errors are
|
||||||
* @retval -1 Error
|
* propagated back to client.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
from_client_netconf(clicon_handle h,
|
from_client_msg(clicon_handle h,
|
||||||
struct client_entry *ce,
|
struct client_entry *ce,
|
||||||
struct clicon_msg *msg)
|
struct clicon_msg *msg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cxobj *xe;
|
cxobj *xe;
|
||||||
char *name;
|
char *name;
|
||||||
char *db;
|
char *db;
|
||||||
cbuf *cbret; /* Return cligen buffer */
|
cbuf *cbret = NULL; /* return message */
|
||||||
int s;
|
int pid;
|
||||||
int pid;
|
int ret;
|
||||||
int ret;
|
|
||||||
|
|
||||||
s = ce->ce_s;
|
|
||||||
pid = ce->ce_pid;
|
pid = ce->ce_pid;
|
||||||
/* Return netconf message. Should be filled in by the dispatch(sub) functions
|
/* Return netconf message. Should be filled in by the dispatch(sub) functions
|
||||||
* as wither rpc-error or by positive response.
|
* as wither rpc-error or by positive response.
|
||||||
|
|
@ -839,7 +772,7 @@ from_client_netconf(clicon_handle h,
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_msg_netconf_decode(msg, &xt) < 0){
|
if (clicon_msg_decode(msg, &xt) < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
"<error-type>rpc</error-type>"
|
"<error-type>rpc</error-type>"
|
||||||
|
|
@ -847,7 +780,7 @@ from_client_netconf(clicon_handle h,
|
||||||
"<error-message>rpc expected</error-message>"
|
"<error-message>rpc expected</error-message>"
|
||||||
"<error-info>Not recognized</error-info>"
|
"<error-info>Not recognized</error-info>"
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto reply;
|
||||||
}
|
}
|
||||||
if ((x = xpath_first(xt, "/rpc")) == NULL){
|
if ((x = xpath_first(xt, "/rpc")) == NULL){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
|
@ -857,7 +790,7 @@ from_client_netconf(clicon_handle h,
|
||||||
"<error-message>rpc expected</error-message>"
|
"<error-message>rpc expected</error-message>"
|
||||||
"<error-info>Not recognized</error-info>"
|
"<error-info>Not recognized</error-info>"
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto reply;
|
||||||
}
|
}
|
||||||
xe = NULL;
|
xe = NULL;
|
||||||
while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) {
|
while ((xe = xml_child_each(x, xe, CX_ELMNT)) != NULL) {
|
||||||
|
|
@ -867,23 +800,23 @@ from_client_netconf(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "edit-config") == 0){
|
else if (strcmp(name, "edit-config") == 0){
|
||||||
if (from_client_edit_config(h, xe, cbret) <0)
|
if (from_client_edit_config(h, xe, pid, cbret) <0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "copy-config") == 0){
|
else if (strcmp(name, "copy-config") == 0){
|
||||||
if (from_client_copy_config(h, xe, cbret) <0)
|
if (from_client_copy_config(h, xe, pid, cbret) <0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "delete-config") == 0){
|
else if (strcmp(name, "delete-config") == 0){
|
||||||
if (from_client_delete_config(h, xe, cbret) <0)
|
if (from_client_delete_config(h, xe, pid, cbret) <0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "lock") == 0){
|
else if (strcmp(name, "lock") == 0){
|
||||||
if (from_client_lock(h, pid, xe, cbret) < 0)
|
if (from_client_lock(h, xe, pid, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "unlock") == 0){
|
else if (strcmp(name, "unlock") == 0){
|
||||||
if (from_client_unlock(h, pid, xe, cbret) < 0)
|
if (from_client_unlock(h, xe, pid, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "close-session") == 0){
|
else if (strcmp(name, "close-session") == 0){
|
||||||
|
|
@ -902,17 +835,17 @@ from_client_netconf(clicon_handle h,
|
||||||
"<error-severity>error</error-severity>"
|
"<error-severity>error</error-severity>"
|
||||||
"<error-info><bad-element>source</bad-element></error-info>"
|
"<error-info><bad-element>source</bad-element></error-info>"
|
||||||
"</rpc-error></rpc-reply>");
|
"</rpc-error></rpc-reply>");
|
||||||
goto ok;
|
goto reply;
|
||||||
}
|
}
|
||||||
if (from_client_validate(h, db, cbret) < 0)
|
if (from_client_validate(h, db, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "commit") == 0){
|
else if (strcmp(name, "commit") == 0){
|
||||||
if (from_client_commit(h, cbret) < 0)
|
if (from_client_commit(h, pid, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "discard-changes") == 0){
|
else if (strcmp(name, "discard-changes") == 0){
|
||||||
if (from_client_discard_changes(h, cbret) < 0)
|
if (from_client_discard_changes(h, pid, cbret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(name, "create-subscription") == 0){
|
else if (strcmp(name, "create-subscription") == 0){
|
||||||
|
|
@ -937,82 +870,21 @@ from_client_netconf(clicon_handle h,
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok:
|
reply:
|
||||||
assert(cbuf_len(cbret));
|
assert(cbuf_len(cbret));
|
||||||
if (send_msg_reply(s, CLICON_MSG_NETCONF,
|
if (send_msg_reply(ce->ce_s, cbuf_get(cbret), cbuf_len(cbret)+1) < 0){
|
||||||
cbuf_get(cbret), cbuf_len(cbret)+1) < 0){
|
|
||||||
if (errno == ECONNRESET)
|
if (errno == ECONNRESET)
|
||||||
clicon_log(LOG_WARNING, "client rpc reset");
|
clicon_log(LOG_WARNING, "client rpc reset");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
// ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xt)
|
if (xt)
|
||||||
xml_free(xt);
|
xml_free(xt);
|
||||||
if (cbret)
|
if (cbret)
|
||||||
cbuf_free(cbret);
|
cbuf_free(cbret);
|
||||||
return retval;
|
return retval;// -1 here terminates backend
|
||||||
}
|
|
||||||
|
|
||||||
/*! Internal message: Change entry set/delete in database xmldb variant
|
|
||||||
* @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_change(clicon_handle h,
|
|
||||||
int s,
|
|
||||||
int pid,
|
|
||||||
struct clicon_msg *msg,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
uint32_t len;
|
|
||||||
char *xk;
|
|
||||||
char *db;
|
|
||||||
enum operation_type op;
|
|
||||||
char *str = NULL;
|
|
||||||
char *val=NULL;
|
|
||||||
int piddb;
|
|
||||||
|
|
||||||
if (clicon_msg_change_decode(msg,
|
|
||||||
&db,
|
|
||||||
&op,
|
|
||||||
&xk,
|
|
||||||
&val,
|
|
||||||
&len,
|
|
||||||
label) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "%s api_path:%s val:%s\n", __FUNCTION__, xk, val);
|
|
||||||
/* candidate is locked by other client */
|
|
||||||
if (strcmp(db, "candidate") == 0){
|
|
||||||
piddb = xmldb_islocked(h, db);
|
|
||||||
if (piddb && pid != piddb){
|
|
||||||
send_msg_err(s, OE_DB, 0,
|
|
||||||
"lock failed: locked by %d", piddb);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Update database */
|
|
||||||
if (xmldb_put_xkey(h, db, op, xk, val) < 0){
|
|
||||||
send_msg_err(s, clicon_errno, clicon_suberrno,
|
|
||||||
clicon_err_reason);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (send_msg_ok(s, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (str)
|
|
||||||
free(str);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
||||||
|
|
@ -1027,42 +899,22 @@ from_client(int s,
|
||||||
void* arg)
|
void* arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
struct clicon_msg *msg = NULL;
|
||||||
struct client_entry *ce = (struct client_entry *)arg;
|
struct client_entry *ce = (struct client_entry *)arg;
|
||||||
clicon_handle h = ce->ce_handle;
|
clicon_handle h = ce->ce_handle;
|
||||||
struct clicon_msg *msg = NULL;
|
|
||||||
enum clicon_msg_type type;
|
|
||||||
int eof;
|
int eof;
|
||||||
|
|
||||||
assert(s == ce->ce_s);
|
// assert(s == ce->ce_s);
|
||||||
if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0)
|
if (clicon_msg_rcv(ce->ce_s, &msg, &eof) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (eof){
|
if (eof)
|
||||||
// xmldb_unlock_all(h, ce->ce_pid);
|
|
||||||
backend_client_rm(h, ce);
|
backend_client_rm(h, ce);
|
||||||
goto ok;
|
else
|
||||||
}
|
if (from_client_msg(h, ce, msg) < 0)
|
||||||
type = ntohs(msg->op_type);
|
|
||||||
switch (type){
|
|
||||||
case CLICON_MSG_NETCONF:
|
|
||||||
if (from_client_netconf(h, ce, msg) < 0)
|
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
|
||||||
case CLICON_MSG_CHANGE:
|
|
||||||
if (from_client_change(h, ce->ce_s, ce->ce_pid, msg,
|
|
||||||
(char *)__FUNCTION__) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
send_msg_err(s, OE_PROTO, 0, "Unexpected message: %d", type);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
ok:
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (msg)
|
if (msg)
|
||||||
free(msg);
|
free(msg);
|
||||||
unchunk_group(__FUNCTION__);
|
return retval;
|
||||||
if (0) return retval;
|
|
||||||
return 0; // -1 here terminates
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ candidate_commit(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Discard all changes in candidate / revert to running
|
/*! Commit changes from candidate to running
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||||
|
|
@ -264,10 +264,25 @@ candidate_commit(clicon_handle h,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_commit(clicon_handle h,
|
from_client_commit(clicon_handle h,
|
||||||
|
int mypid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
|
/* Check if target locked by other client */
|
||||||
|
piddb = xmldb_islocked(h, "running");
|
||||||
|
if (piddb && mypid != piddb){
|
||||||
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
"<error-tag>lock-denied</error-tag>"
|
||||||
|
"<error-type>protocol</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>Operation failed, lock is already held</error-message>"
|
||||||
|
"<error-info><session-id>%d</session-id></error-info>"
|
||||||
|
"</rpc-error></rpc-reply>",
|
||||||
|
piddb);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
if (candidate_commit(h, "candidate") < 0){
|
if (candidate_commit(h, "candidate") < 0){
|
||||||
clicon_debug(1, "Commit candidate failed");
|
clicon_debug(1, "Commit candidate failed");
|
||||||
|
|
@ -290,17 +305,32 @@ from_client_commit(clicon_handle h,
|
||||||
|
|
||||||
/*! Discard all changes in candidate / revert to running
|
/*! Discard all changes in candidate / revert to running
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] mypid Process/session id of calling client
|
||||||
* @param[out] cbret Return xml value cligen buffer
|
* @param[out] cbret Return xml value cligen buffer
|
||||||
* @retval 0 OK. This may indicate both ok and err msg back to client
|
* @retval 0 OK. This may indicate both ok and err msg back to client
|
||||||
* @retval -1 (Local) Error
|
* @retval -1 (Local) Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
from_client_discard_changes(clicon_handle h,
|
from_client_discard_changes(clicon_handle h,
|
||||||
|
int mypid,
|
||||||
cbuf *cbret)
|
cbuf *cbret)
|
||||||
|
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
int piddb;
|
||||||
|
|
||||||
|
/* Check if target locked by other client */
|
||||||
|
piddb = xmldb_islocked(h, "candidate");
|
||||||
|
if (piddb && mypid != piddb){
|
||||||
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
|
"<error-tag>lock-denied</error-tag>"
|
||||||
|
"<error-type>protocol</error-type>"
|
||||||
|
"<error-severity>error</error-severity>"
|
||||||
|
"<error-message>Operation failed, lock is already held</error-message>"
|
||||||
|
"<error-info><session-id>%d</session-id></error-info>"
|
||||||
|
"</rpc-error></rpc-reply>",
|
||||||
|
piddb);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
if (xmldb_copy(h, "running", "candidate") < 0){
|
if (xmldb_copy(h, "running", "candidate") < 0){
|
||||||
cprintf(cbret, "<rpc-reply><rpc-error>"
|
cprintf(cbret, "<rpc-reply><rpc-error>"
|
||||||
"<error-tag>operation-failed</error-tag>"
|
"<error-tag>operation-failed</error-tag>"
|
||||||
|
|
@ -317,8 +347,6 @@ from_client_discard_changes(clicon_handle h,
|
||||||
return retval; /* may be zero if we ignoring errors from commit */
|
return retval; /* may be zero if we ignoring errors from commit */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*! Handle an incoming validate message from a client.
|
/*! Handle an incoming validate message from a client.
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db Database name
|
* @param[in] db Database name
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
int from_client_validate(clicon_handle h, char *db, cbuf *cbret);
|
||||||
int from_client_commit(clicon_handle h, cbuf *cbret);
|
int from_client_commit(clicon_handle h, int pid, cbuf *cbret);
|
||||||
int from_client_discard_changes(clicon_handle h, cbuf *cbret);
|
int from_client_discard_changes(clicon_handle h, int pid, cbuf *cbret);
|
||||||
int candidate_commit(clicon_handle h, char *db);
|
int candidate_commit(clicon_handle h, char *db);
|
||||||
|
|
||||||
#endif /* _BACKEND_COMMIT_H_ */
|
#endif /* _BACKEND_COMMIT_H_ */
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ cli_dbxmlv(clicon_handle h,
|
||||||
cg_var *cval;
|
cg_var *cval;
|
||||||
int len;
|
int len;
|
||||||
cg_var *arg;
|
cg_var *arg;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
if (cvec_len(argv) != 1){
|
if (cvec_len(argv) != 1){
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be xml key format string", __FUNCTION__);
|
clicon_err(OE_PLUGIN, 0, "%s: Requires one element to be xml key format string", __FUNCTION__);
|
||||||
|
|
@ -225,7 +226,15 @@ cli_dbxmlv(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clicon_rpc_change(h, "candidate", op, xk, str) < 0)
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (str)
|
||||||
|
cprintf(cb, "<config>%s</config>", str);
|
||||||
|
else
|
||||||
|
cprintf(cb, "<config/>");
|
||||||
|
if (clicon_rpc_edit_config(h, "candidate", op, xk, cbuf_get(cb)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_autocommit(h)) {
|
if (clicon_autocommit(h)) {
|
||||||
if (clicon_rpc_commit(h) < 0)
|
if (clicon_rpc_commit(h) < 0)
|
||||||
|
|
@ -233,6 +242,8 @@ cli_dbxmlv(clicon_handle h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
if (str)
|
if (str)
|
||||||
free(str);
|
free(str);
|
||||||
if (xk)
|
if (xk)
|
||||||
|
|
@ -771,7 +782,7 @@ discard_changesv(clicon_handle h,
|
||||||
cvec *cvv,
|
cvec *cvv,
|
||||||
cvec *argv)
|
cvec *argv)
|
||||||
{
|
{
|
||||||
return clicon_rpc_copy_config(h, "running", "candidate");
|
return clicon_rpc_discard_changes(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Copy from one database to another, eg running->startup
|
/*! Copy from one database to another, eg running->startup
|
||||||
|
|
@ -805,7 +816,6 @@ cli_notification_cb(int s,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
struct clicon_msg *reply = NULL;
|
struct clicon_msg *reply = NULL;
|
||||||
enum clicon_msg_type type;
|
|
||||||
int eof;
|
int eof;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *eventstr = NULL;
|
char *eventstr = NULL;
|
||||||
|
|
@ -826,17 +836,14 @@ cli_notification_cb(int s,
|
||||||
}
|
}
|
||||||
if (format == NULL)
|
if (format == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
type = ntohs(reply->op_type);
|
if (clicon_msg_decode(reply, &xt) < 0)
|
||||||
switch (type){
|
goto done;
|
||||||
case CLICON_MSG_NETCONF:
|
if ((xe = xpath_first(xt, "//event")) != NULL)
|
||||||
if (clicon_msg_netconf_decode(reply, &xt) < 0)
|
eventstr = xml_body(xe);
|
||||||
goto done;
|
if (strcmp(format, SHOWAS_TXT) == 0){
|
||||||
if ((xe = xpath_first(xt, "//event")) != NULL)
|
fprintf(stdout, "%s\n", eventstr);
|
||||||
eventstr = xml_body(xe);
|
}
|
||||||
if (strcmp(format, SHOWAS_TXT) == 0){
|
else
|
||||||
fprintf(stdout, "%s\n", eventstr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (strcmp(format, SHOWAS_XML) == 0){
|
if (strcmp(format, SHOWAS_XML) == 0){
|
||||||
if (clicon_xml_parse_string(&eventstr, &xt) < 0)
|
if (clicon_xml_parse_string(&eventstr, &xt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -857,12 +864,7 @@ cli_notification_cb(int s,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
clicon_err(OE_PROTO, 0, "unexpected reply: %d", type);
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xt)
|
if (xt)
|
||||||
|
|
|
||||||
|
|
@ -214,9 +214,17 @@ main(int argc, char **argv)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (addent) /* add entry */
|
if (addent){ /* add entry */
|
||||||
if (xmldb_put_xkey(h, db, OP_REPLACE, NULL, addstr) < 0)
|
cxobj *xml = NULL;
|
||||||
|
|
||||||
|
if (clicon_xml_parse(&xml, "<config>%s</config>", addstr) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (xmldb_put(h, db, OP_REPLACE, NULL, xml) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml)
|
||||||
|
xml_free(xml);
|
||||||
|
|
||||||
|
}
|
||||||
if (rment)
|
if (rment)
|
||||||
if (remove_entry(db, rmkey) < 0)
|
if (remove_entry(db, rmkey) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -684,7 +684,6 @@ netconf_notification_cb(int s,
|
||||||
cbuf *cb;
|
cbuf *cb;
|
||||||
cxobj *xe = NULL; /* event xml */
|
cxobj *xe = NULL; /* event xml */
|
||||||
cxobj *xt = NULL; /* top xml */
|
cxobj *xt = NULL; /* top xml */
|
||||||
enum clicon_msg_type type;
|
|
||||||
|
|
||||||
if (0){
|
if (0){
|
||||||
fprintf(stderr, "%s\n", __FUNCTION__); /* debug */
|
fprintf(stderr, "%s\n", __FUNCTION__); /* debug */
|
||||||
|
|
@ -703,47 +702,35 @@ netconf_notification_cb(int s,
|
||||||
xml_free(xfilter);
|
xml_free(xfilter);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* multiplex on message type: we only expect notify */
|
if (clicon_msg_decode(reply, &xt) < 0)
|
||||||
type = ntohs(reply->op_type);
|
|
||||||
switch (type){
|
|
||||||
case CLICON_MSG_NETCONF:
|
|
||||||
if (clicon_msg_netconf_decode(reply, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
if ((xe = xpath_first(xt, "//event")) != NULL)
|
|
||||||
event = xml_body(xe);
|
|
||||||
|
|
||||||
/* parse event */
|
|
||||||
if (0){ /* XXX CLICON events are not xml */
|
|
||||||
/* find and apply filter */
|
|
||||||
if ((selector = xml_find_value(xfilter, "select")) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (xpath_first(xe, selector) == NULL) {
|
|
||||||
fprintf(stderr, "%s no match\n", __FUNCTION__); /* debug */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* create netconf message */
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, errno, "%s: cbuf_new", __FUNCTION__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
add_preamble(cb); /* Make it well-formed netconf xml */
|
|
||||||
cprintf(cb, "<notification><event>%s</event></notification>", event);
|
|
||||||
add_postamble(cb);
|
|
||||||
/* Send it to listening client on stdout */
|
|
||||||
if (netconf_output(1, cb, "notification") < 0){
|
|
||||||
cbuf_free(cb);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
fflush(stdout);
|
|
||||||
cbuf_free(cb);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
clicon_err(OE_PROTO, 0, "%s: unexpected reply: %d",
|
|
||||||
__FUNCTION__, type);
|
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
if ((xe = xpath_first(xt, "//event")) != NULL)
|
||||||
|
event = xml_body(xe);
|
||||||
|
|
||||||
|
/* parse event */
|
||||||
|
if (0){ /* XXX CLICON events are not xml */
|
||||||
|
/* find and apply filter */
|
||||||
|
if ((selector = xml_find_value(xfilter, "select")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (xpath_first(xe, selector) == NULL) {
|
||||||
|
fprintf(stderr, "%s no match\n", __FUNCTION__); /* debug */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* create netconf message */
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, errno, "%s: cbuf_new", __FUNCTION__);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
add_preamble(cb); /* Make it well-formed netconf xml */
|
||||||
|
cprintf(cb, "<notification><event>%s</event></notification>", event);
|
||||||
|
add_postamble(cb);
|
||||||
|
/* Send it to listening client on stdout */
|
||||||
|
if (netconf_output(1, cb, "notification") < 0){
|
||||||
|
cbuf_free(cb);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
cbuf_free(cb);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (xt != NULL)
|
if (xt != NULL)
|
||||||
|
|
|
||||||
3
configure
vendored
3
configure
vendored
|
|
@ -4315,7 +4315,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/restconf/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"
|
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/restconf/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"
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -5018,7 +5018,6 @@ do
|
||||||
"apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;;
|
"apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;;
|
||||||
"apps/restconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/restconf/Makefile" ;;
|
"apps/restconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/restconf/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" ;;
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ downcall(clicon_handle h,
|
||||||
if ((cv = cvec_i(vars, 1)) != NULL)
|
if ((cv = cvec_i(vars, 1)) != NULL)
|
||||||
str = cv_string_get(cv);
|
str = cv_string_get(cv);
|
||||||
}
|
}
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><myrouting>%s</myrouting></rpc>", str)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><myrouting>%s</myrouting></rpc>", str)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ commit("Commit the changes"), cli_commitv();
|
||||||
quit("Quit Hello"), cli_quitv();
|
quit("Quit Hello"), cli_quitv();
|
||||||
delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_allv("candidate");
|
delete("Delete a configuration item") all("Delete whole candidate configuration"), delete_allv("candidate");
|
||||||
|
|
||||||
startup("Store running as startup config"), db_copy("running","startup");
|
startup("Store running as startup config"), db_copy("running", "startup");
|
||||||
no("Negate or remove") debug("Debugging parts of the system"), cli_debug_cliv((int32)0);
|
no("Negate or remove") debug("Debugging parts of the system"), cli_debug_cliv((int32)0);
|
||||||
debug("Debugging parts of the system"), cli_debug_cliv((int32)1);{
|
debug("Debugging parts of the system"), cli_debug_cliv((int32)1);{
|
||||||
level("Set debug level: 1..n") <level:int32>("Set debug level (0..n)"), cli_debug_backendv();
|
level("Set debug level: 1..n") <level:int32>("Set debug level (0..n)"), cli_debug_backendv();
|
||||||
|
|
@ -29,23 +29,23 @@ show("Show a particular state of the system"){
|
||||||
xml("Show comparison in xml"), compare_dbsv((int32)0);
|
xml("Show comparison in xml"), compare_dbsv((int32)0);
|
||||||
text("Show comparison in text"), compare_dbsv((int32)1);
|
text("Show comparison in text"), compare_dbsv((int32)1);
|
||||||
}
|
}
|
||||||
configuration("Show configuration"), show_confv_as_text("candidate","/");{
|
configuration("Show configuration"), show_confv_as_text("candidate", "/");{
|
||||||
xml("Show configuration as XML"), show_confv_as_xml("candidate","/");
|
xml("Show configuration as XML"), show_confv_as_xml("candidate", "/");
|
||||||
netconf("Show configuration as netconf edit-config operation"), show_confv_as_netconf("candidate","/");
|
netconf("Show configuration as netconf edit-config operation"), show_confv_as_netconf("candidate", "/");
|
||||||
text("Show configuration as text"), show_confv_as_text("candidate","/");
|
text("Show configuration as text"), show_confv_as_text("candidate","/");
|
||||||
cli("Show configuration as cli commands"), show_confv_as_cli("candidate","/");
|
cli("Show configuration as cli commands"), show_confv_as_cli("candidate", "/");
|
||||||
json("Show configuration as cli commands"), show_confv_as_json("candidate","/");
|
json("Show configuration as cli commands"), show_confv_as_json("candidate", "/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save("Save candidate configuration to XML file") <filename:string>("Filename (local filename)"), save_config_filev("candidate","filename");
|
save("Save candidate configuration to XML file") <filename:string>("Filename (local filename)"), save_config_filev("candidate","filename");
|
||||||
load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_filev("filename","replace");{
|
load("Load configuration from XML file") <filename:string>("Filename (local filename)"),load_config_filev("filename", "replace");{
|
||||||
replace("Replace candidate with file contents"), load_config_filev("filename","replace");
|
replace("Replace candidate with file contents"), load_config_filev("filename", "replace");
|
||||||
merge("Merge file with existent candidate"), load_config_filev("filename","merge");
|
merge("Merge file with existent candidate"), load_config_filev("filename", "merge");
|
||||||
}
|
}
|
||||||
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
|
example("This is a comment") <var:int32>("Just a random number"), mycallback("myarg");
|
||||||
downcall("This is a downcall") <str:rest>, downcall();
|
downcall("This is a downcall") <str:rest>, downcall();
|
||||||
notify("Get notifications from backend"), cli_notifyv("ROUTING","1","txt");
|
notify("Get notifications from backend"), cli_notifyv("ROUTING", "1", "txt");
|
||||||
no("Negate") notify("Get notifications from backend"), cli_notifyv("ROUTING","0","xml");
|
no("Negate") notify("Get notifications from backend"), cli_notifyv("ROUTING", "0", "xml");
|
||||||
lock,cli_lock("candidate");
|
lock,cli_lock("candidate");
|
||||||
unlock,cli_unlock("candidate");
|
unlock,cli_unlock("candidate");
|
||||||
|
|
@ -46,31 +46,18 @@ enum format_enum{
|
||||||
MSG_NOTIFY_XML, /* means filter works on xml */
|
MSG_NOTIFY_XML, /* means filter works on xml */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* See also map_type2str in clicon_proto.c */
|
|
||||||
enum clicon_msg_type{
|
|
||||||
CLICON_MSG_NETCONF = 1, /* Generic netconf message (lock/unlock/..) can all
|
|
||||||
msgs go to this?
|
|
||||||
1. string: netconf message
|
|
||||||
*/
|
|
||||||
CLICON_MSG_CHANGE, /* Change a (single) database entry:
|
|
||||||
1. uint32: operation: OP_MERGE/OP_REPLACE/OP_REMOVE
|
|
||||||
2. uint32: length of value string
|
|
||||||
3. string: name of database to change (eg "running")
|
|
||||||
4. string: key
|
|
||||||
5. string: value (can be NULL)
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Protocol message header */
|
/* Protocol message header */
|
||||||
struct clicon_msg {
|
struct clicon_msg {
|
||||||
uint16_t op_len; /* length of message. */
|
uint16_t op_len; /* length of message. */
|
||||||
uint16_t op_type; /* message type, see enum clicon_msg_type */
|
|
||||||
char op_body[0]; /* rest of message, actual data */
|
char op_body[0]; /* rest of message, actual data */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
struct clicon_msg *clicon_msg_encode(char *format, ...);
|
||||||
|
int clicon_msg_decode(struct clicon_msg *msg, cxobj **xml);
|
||||||
|
|
||||||
int clicon_connect_unix(char *sockpath);
|
int clicon_connect_unix(char *sockpath);
|
||||||
|
|
||||||
int clicon_rpc_connect_unix(struct clicon_msg *msg,
|
int clicon_rpc_connect_unix(struct clicon_msg *msg,
|
||||||
|
|
@ -92,13 +79,6 @@ int clicon_msg_rcv(int s, struct clicon_msg **msg, int *eof);
|
||||||
|
|
||||||
int send_msg_notify(int s, int level, char *event);
|
int send_msg_notify(int s, int level, char *event);
|
||||||
|
|
||||||
int send_msg_reply(int s, uint16_t type, char *data, uint16_t datalen);
|
int send_msg_reply(int s, char *data, uint16_t datalen);
|
||||||
|
|
||||||
int send_msg_ok(int s, char *data);
|
|
||||||
|
|
||||||
int send_msg_err(int s, int err, int suberr, char *format, ...);
|
|
||||||
|
|
||||||
int send_msg_netconf_reply(int s, char *format, ...);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _CLIXON_PROTO_H_ */
|
#endif /* _CLIXON_PROTO_H_ */
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0,
|
||||||
int *sock0);
|
int *sock0);
|
||||||
|
int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp);
|
||||||
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp);
|
||||||
int clicon_rpc_generate_error(cxobj *xerr);
|
int clicon_rpc_generate_error(cxobj *xerr);
|
||||||
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret);
|
int clicon_rpc_get_config(clicon_handle h, char *db, char *xpath, cxobj **xret);
|
||||||
|
|
@ -55,7 +56,7 @@ int clicon_rpc_close_session(clicon_handle h);
|
||||||
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
int clicon_rpc_kill_session(clicon_handle h, int session_id);
|
||||||
int clicon_rpc_validate(clicon_handle h, char *db);
|
int clicon_rpc_validate(clicon_handle h, char *db);
|
||||||
int clicon_rpc_commit(clicon_handle h);
|
int clicon_rpc_commit(clicon_handle h);
|
||||||
// discard-changes
|
int clicon_rpc_discard_changes(clicon_handle h);
|
||||||
int clicon_rpc_create_subscription(clicon_handle h, char *stream, char *filter,
|
int clicon_rpc_create_subscription(clicon_handle h, char *stream, char *filter,
|
||||||
int *s);
|
int *s);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
***** BEGIN LICENSE BLOCK *****
|
|
||||||
|
|
||||||
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
|
|
||||||
|
|
||||||
This file is part of CLIXON.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
Alternatively, the contents of this file may be used under the terms of
|
|
||||||
the GNU General Public License Version 3 or later (the "GPL"),
|
|
||||||
in which case the provisions of the GPL are applicable instead
|
|
||||||
of those above. If you wish to allow use of your version of this file only
|
|
||||||
under the terms of the GPL, and not to allow others to
|
|
||||||
use your version of this file under the terms of Apache License version 2,
|
|
||||||
indicate your decision by deleting the provisions above and replace them with
|
|
||||||
the notice and other provisions required by the GPL. If you do not delete
|
|
||||||
the provisions above, a recipient may use your version of this file under
|
|
||||||
the terms of any one of the Apache License version 2 or the GPL.
|
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
|
||||||
|
|
||||||
*
|
|
||||||
* Protocol to communicate between clients (eg clixon_cli, clixon_netconf)
|
|
||||||
* and server (clicon_backend)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CLIXON_PROTO_ENCODE_H_
|
|
||||||
#define _CLIXON_PROTO_ENCODE_H_
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prototypes
|
|
||||||
*/
|
|
||||||
struct clicon_msg *clicon_msg_netconf_encode(char *format, ...);
|
|
||||||
struct clicon_msg *clicon_msg_netconf_encode_xml(cxobj *xml);
|
|
||||||
|
|
||||||
int clicon_msg_netconf_decode(struct clicon_msg *msg, cxobj **xml);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_change_encode(char *db, uint32_t op, char *key,
|
|
||||||
char *lvec, uint32_t lvec_len);
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_change_decode(struct clicon_msg *msg,
|
|
||||||
char **db, uint32_t *op, char **key,
|
|
||||||
char **lvec, uint32_t *lvec_len,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_dbitems_get_reply_encode(cvec **cvecv,
|
|
||||||
int cveclen);
|
|
||||||
int
|
|
||||||
clicon_msg_dbitems_get_reply_decode(char *data,
|
|
||||||
uint16_t datalen,
|
|
||||||
cvec ***cvecv,
|
|
||||||
size_t *cveclen,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
#endif /* _CLIXON_PROTO_ENCODE_H_ */
|
|
||||||
|
|
@ -47,9 +47,6 @@ int xmldb_get(clicon_handle h, char *db, char *xpath,
|
||||||
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
||||||
int xmldb_put(clicon_handle h, char *db, enum operation_type op,
|
int xmldb_put(clicon_handle h, char *db, enum operation_type op,
|
||||||
char *api_path, cxobj *xt);
|
char *api_path, cxobj *xt);
|
||||||
int xmldb_put_xkey(clicon_handle h, char *db, enum operation_type op,
|
|
||||||
char *xkey, char *val);
|
|
||||||
|
|
||||||
int xmldb_dump(FILE *f, char *dbfilename, char *rxkey);
|
int xmldb_dump(FILE *f, char *dbfilename, char *rxkey);
|
||||||
int xmldb_copy(clicon_handle h, char *from, char *to);
|
int xmldb_copy(clicon_handle h, char *from, char *to);
|
||||||
int xmldb_lock(clicon_handle h, char *db, int pid);
|
int xmldb_lock(clicon_handle h, char *db, int pid);
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ SRC = clixon_sig.c clixon_qdb.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_json.c \
|
clixon_json.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_client.c \
|
||||||
clixon_xsl.c clixon_sha1.c clixon_xml_db.c
|
clixon_xsl.c clixon_sha1.c clixon_xml_db.c
|
||||||
|
|
||||||
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ static struct errvec EV[] = {
|
||||||
{"UNIX error", OE_UNIX},
|
{"UNIX error", OE_UNIX},
|
||||||
{"Syslog error", OE_SYSLOG},
|
{"Syslog error", OE_SYSLOG},
|
||||||
{"Routing demon error", OE_ROUTING},
|
{"Routing demon error", OE_ROUTING},
|
||||||
|
{"XML error", OE_XML},
|
||||||
{"Plugins", OE_PLUGIN},
|
{"Plugins", OE_PLUGIN},
|
||||||
{"Yang error", OE_YANG},
|
{"Yang error", OE_YANG},
|
||||||
{"FATAL", OE_FATAL},
|
{"FATAL", OE_FATAL},
|
||||||
|
|
|
||||||
|
|
@ -71,31 +71,59 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
#include "clixon_proto_encode.h"
|
|
||||||
|
|
||||||
static int _atomicio_sig = 0;
|
static int _atomicio_sig = 0;
|
||||||
|
|
||||||
struct map_type2str{
|
/*! Encode a clicon netconf message
|
||||||
enum clicon_msg_type mt_type;
|
* @param[in] param Variable agrument list format an XML netconf string
|
||||||
char *mt_str; /* string as in 4.2.4 in RFC 6020 */
|
* @retval msg Clicon message to send to eg clicon_msg_send()
|
||||||
};
|
*/
|
||||||
|
struct clicon_msg *
|
||||||
/* Mapping between yang keyword string <--> clicon constants */
|
clicon_msg_encode(char *format, ...)
|
||||||
static const struct map_type2str msgmap[] = {
|
|
||||||
{CLICON_MSG_NETCONF, "netconf"},
|
|
||||||
{CLICON_MSG_CHANGE, "change"},
|
|
||||||
{-1, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
static char *
|
|
||||||
msg_type2str(enum clicon_msg_type type)
|
|
||||||
{
|
{
|
||||||
const struct map_type2str *mt;
|
va_list args;
|
||||||
|
int xmllen;
|
||||||
|
int len;
|
||||||
|
struct clicon_msg *msg = NULL;
|
||||||
|
int hdrlen = sizeof(*msg);
|
||||||
|
|
||||||
for (mt = &msgmap[0]; mt->mt_str; mt++)
|
va_start(args, format);
|
||||||
if (mt->mt_type == type)
|
xmllen = vsnprintf(NULL, 0, format, args) + 1;
|
||||||
return mt->mt_str;
|
va_end(args);
|
||||||
return NULL;
|
|
||||||
|
len = hdrlen + xmllen;
|
||||||
|
if ((msg = (struct clicon_msg *)malloc(len)) == NULL){
|
||||||
|
clicon_err(OE_PROTO, errno, "malloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(msg, 0, len);
|
||||||
|
/* hdr */
|
||||||
|
msg->op_len = htons(len);
|
||||||
|
|
||||||
|
/* body */
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(msg->op_body, xmllen, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Decode a clicon netconf message
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_msg_decode(struct clicon_msg *msg,
|
||||||
|
cxobj **xml)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *xmlstr;
|
||||||
|
|
||||||
|
/* body */
|
||||||
|
xmlstr = msg->op_body;
|
||||||
|
if (clicon_xml_parse_str(xmlstr, xml) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Open local connection using unix domain sockets
|
/*! Open local connection using unix domain sockets
|
||||||
|
|
@ -198,8 +226,8 @@ clicon_msg_send(int s,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
clicon_debug(2, "%s: send msg seq=%d len=%d",
|
clicon_debug(2, "%s: send msg len=%d",
|
||||||
__FUNCTION__, ntohs(msg->op_type), ntohs(msg->op_len));
|
__FUNCTION__, ntohs(msg->op_len));
|
||||||
if (debug > 2)
|
if (debug > 2)
|
||||||
msg_dump(msg);
|
msg_dump(msg);
|
||||||
if (atomicio((ssize_t (*)(int, void *, size_t))write,
|
if (atomicio((ssize_t (*)(int, void *, size_t))write,
|
||||||
|
|
@ -258,8 +286,8 @@ clicon_msg_rcv(int s,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
mlen = ntohs(hdr.op_len);
|
mlen = ntohs(hdr.op_len);
|
||||||
clicon_debug(2, "%s: rcv msg seq=%d, len=%d",
|
clicon_debug(2, "%s: rcv msg len=%d",
|
||||||
__FUNCTION__, ntohs(hdr.op_type), mlen);
|
__FUNCTION__, mlen);
|
||||||
if ((*msg = (struct clicon_msg *)malloc(mlen)) == NULL){
|
if ((*msg = (struct clicon_msg *)malloc(mlen)) == NULL){
|
||||||
clicon_err(OE_CFG, errno, "malloc");
|
clicon_err(OE_CFG, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -303,8 +331,7 @@ clicon_rpc_connect_unix(struct clicon_msg *msg,
|
||||||
int s = -1;
|
int s = -1;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
clicon_debug(1, "Send %s msg on %s",
|
clicon_debug(1, "Send msg on %s", sockpath);
|
||||||
msg_type2str(ntohs(msg->op_type)), sockpath);
|
|
||||||
/* special error handling to get understandable messages (otherwise ENOENT) */
|
/* special error handling to get understandable messages (otherwise ENOENT) */
|
||||||
if (stat(sockpath, &sb) < 0){
|
if (stat(sockpath, &sb) < 0){
|
||||||
clicon_err(OE_PROTO, errno, "%s: config daemon not running?", sockpath);
|
clicon_err(OE_PROTO, errno, "%s: config daemon not running?", sockpath);
|
||||||
|
|
@ -349,8 +376,7 @@ clicon_rpc_connect_inet(struct clicon_msg *msg,
|
||||||
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 msg to %s:%hu", dst, port);
|
||||||
msg_type2str(ntohs(msg->op_type)), dst, port);
|
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
|
|
@ -400,7 +426,6 @@ clicon_rpc(int s,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *reply;
|
struct clicon_msg *reply;
|
||||||
int eof;
|
int eof;
|
||||||
enum clicon_msg_type type;
|
|
||||||
char *data = NULL;
|
char *data = NULL;
|
||||||
cxobj *cx = NULL;
|
cxobj *cx = NULL;
|
||||||
|
|
||||||
|
|
@ -414,17 +439,7 @@ clicon_rpc(int s,
|
||||||
errno = ESHUTDOWN;
|
errno = ESHUTDOWN;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
type = ntohs(reply->op_type);
|
data = reply->op_body; /* assume string */
|
||||||
switch (type){
|
|
||||||
case CLICON_MSG_NETCONF: /* ok or rpc-error expected */
|
|
||||||
data = reply->op_body; /* assume string */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
clicon_err(OE_PROTO, 0, "%s: unexpected reply: %s",
|
|
||||||
__FUNCTION__, msg_type2str(type));
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ret && data)
|
if (ret && data)
|
||||||
if ((*ret = strdup(data)) == NULL){
|
if ((*ret = strdup(data)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "strdup");
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
|
@ -442,7 +457,6 @@ clicon_rpc(int s,
|
||||||
/*! Send a clicon_msg message as reply to a clicon rpc request
|
/*! Send a clicon_msg message as reply to a clicon rpc request
|
||||||
*
|
*
|
||||||
* @param[in] s Socket to communicate with client
|
* @param[in] s Socket to communicate with client
|
||||||
* @param[in] type Clicon msg operation, see enum clicon_msg_type
|
|
||||||
* @param[in] data Returned data as byte-string.
|
* @param[in] data Returned data as byte-string.
|
||||||
* @param[in] datalen Length of returned data XXX may be unecessary if always string?
|
* @param[in] datalen Length of returned data XXX may be unecessary if always string?
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -450,7 +464,6 @@ clicon_rpc(int s,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
send_msg_reply(int s,
|
send_msg_reply(int s,
|
||||||
uint16_t type,
|
|
||||||
char *data,
|
char *data,
|
||||||
uint16_t datalen)
|
uint16_t datalen)
|
||||||
{
|
{
|
||||||
|
|
@ -462,7 +475,6 @@ send_msg_reply(int s,
|
||||||
if ((reply = (struct clicon_msg *)chunk(len, __FUNCTION__)) == NULL)
|
if ((reply = (struct clicon_msg *)chunk(len, __FUNCTION__)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
memset(reply, 0, len);
|
memset(reply, 0, len);
|
||||||
reply->op_type = htons(type);
|
|
||||||
reply->op_len = htons(len);
|
reply->op_len = htons(len);
|
||||||
if (datalen > 0)
|
if (datalen > 0)
|
||||||
memcpy(reply->op_body, data, datalen);
|
memcpy(reply->op_body, data, datalen);
|
||||||
|
|
@ -490,7 +502,7 @@ send_msg_notify(int s,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *msg = NULL;
|
struct clicon_msg *msg = NULL;
|
||||||
|
|
||||||
if ((msg=clicon_msg_netconf_encode("<notification><event>%s</event></notification>", event)) == NULL)
|
if ((msg=clicon_msg_encode("<notification><event>%s</event></notification>", event)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_msg_send(s, msg) < 0)
|
if (clicon_msg_send(s, msg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -500,134 +512,3 @@ send_msg_notify(int s,
|
||||||
free(msg);
|
free(msg);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send a clicon_msg OK message as reply to a clicon rpc request
|
|
||||||
*
|
|
||||||
* @param[in] s Socket to communicate with client
|
|
||||||
* @param[in] data Returned data as byte-string.
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @note send as netconf message XXX remove clicon header
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
send_msg_ok(int s,
|
|
||||||
char *data)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cbuf *cb = NULL;
|
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (data)
|
|
||||||
cprintf(cb, "<rpc-reply><ok>%s</ok></rpc-reply>", data);
|
|
||||||
else
|
|
||||||
cprintf(cb, "<rpc-reply><ok/></rpc-reply>");
|
|
||||||
if (send_msg_reply(s, CLICON_MSG_NETCONF, cbuf_get(cb), cbuf_len(cb)+1) < 0){
|
|
||||||
if (errno == ECONNRESET)
|
|
||||||
clicon_log(LOG_WARNING, "client rpc reset");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval=0;
|
|
||||||
done:
|
|
||||||
if (cb)
|
|
||||||
cbuf_free(cb);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a clicon_msg Error message as reply to a clicon rpc request
|
|
||||||
*
|
|
||||||
* @param[in] s Socket to communicate with client
|
|
||||||
* @param[in] data Returned data as byte-string.
|
|
||||||
* @param[in] datalen Length of returned data
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @note send as netconf message XXX remove clicon header
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
send_msg_err(int s,
|
|
||||||
int err,
|
|
||||||
int suberr,
|
|
||||||
char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
char *info = NULL;
|
|
||||||
int len;
|
|
||||||
int retval = -1;
|
|
||||||
cbuf *cb = NULL;
|
|
||||||
|
|
||||||
va_start(args, format);
|
|
||||||
len = vsnprintf(NULL, 0, format, args) + 1;
|
|
||||||
va_end(args);
|
|
||||||
if ((info = malloc(len)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
memset(info, 0, len);
|
|
||||||
va_start(args, format);
|
|
||||||
vsnprintf(info, len, format, args);
|
|
||||||
va_end(args);
|
|
||||||
if ((cb = cbuf_new()) == NULL)
|
|
||||||
goto done;
|
|
||||||
cprintf(cb, "<rpc-reply><rpc-error>"
|
|
||||||
"<error-type>clixon</error-type>"
|
|
||||||
"<error-tag>%d</error-tag>"
|
|
||||||
"<error-message>%d</error-message>"
|
|
||||||
"<error-info>%s</error-info>"
|
|
||||||
"</rpc-error></rpc-reply>",
|
|
||||||
err, suberr, info);
|
|
||||||
if (send_msg_reply(s, CLICON_MSG_NETCONF, cbuf_get(cb), cbuf_len(cb)+1) < 0){
|
|
||||||
if (errno == ECONNRESET)
|
|
||||||
clicon_log(LOG_WARNING, "client rpc reset");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (cb)
|
|
||||||
cbuf_free(cb);
|
|
||||||
if (info)
|
|
||||||
free(info);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Send a clicon_msg Error message as reply to a clicon rpc request
|
|
||||||
*
|
|
||||||
* @param[in] s Socket to communicate with client
|
|
||||||
* @param[in] data Returned data as byte-string.
|
|
||||||
* @param[in] datalen Length of returned data
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @note send as netconf message XXX remove clicon header
|
|
||||||
* XXX: see clicon_xml_parse
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
send_msg_netconf_reply(int s,
|
|
||||||
char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
char *str = NULL;
|
|
||||||
int len;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
va_start(args, format);
|
|
||||||
len = vsnprintf(NULL, 0, format, args) + 1;
|
|
||||||
va_end(args);
|
|
||||||
if ((str = malloc(len)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
memset(str, 0, len);
|
|
||||||
va_start(args, format);
|
|
||||||
len = vsnprintf(str, len, format, args);
|
|
||||||
va_end(args);
|
|
||||||
if (send_msg_reply(s, CLICON_MSG_NETCONF, str, len) < 0){
|
|
||||||
if (errno == ECONNRESET)
|
|
||||||
clicon_log(LOG_WARNING, "client rpc reset");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (str)
|
|
||||||
free(str);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,9 @@
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
#include "clixon_proto_encode.h"
|
|
||||||
#include "clixon_proto_client.h"
|
#include "clixon_proto_client.h"
|
||||||
|
|
||||||
/*! Internal rpc function
|
/*! Send internal netconf rpc from client to backend
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] msg Encoded message. Deallocate woth free
|
* @param[in] msg Encoded message. Deallocate woth free
|
||||||
* @param[out] xret Return value from backend as netconf xml tree. Free w xml_free
|
* @param[out] xret Return value from backend as netconf xml tree. Free w xml_free
|
||||||
|
|
@ -88,11 +87,6 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
int port;
|
int port;
|
||||||
char *retdata = NULL;
|
char *retdata = NULL;
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *x;
|
|
||||||
uint32_t err;
|
|
||||||
uint32_t suberr;
|
|
||||||
char *errmsg = NULL;
|
|
||||||
char *etype = NULL;
|
|
||||||
|
|
||||||
if ((sock = clicon_sock(h)) == NULL){
|
if ((sock = clicon_sock(h)) == NULL){
|
||||||
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
clicon_err(OE_FATAL, 0, "CLICON_SOCK option not set");
|
||||||
|
|
@ -124,38 +118,9 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (retdata &&
|
||||||
#if 1 /* Parse return data and intercept clixon errors */
|
clicon_xml_parse_str(retdata, &xret) < 0)
|
||||||
if (retdata) {
|
goto done;
|
||||||
if (clicon_xml_parse_str(retdata, &xret) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xpath_first(xret, "/rpc-reply/ok") != NULL ||
|
|
||||||
xpath_first(xret, "/rpc-reply/data") != NULL)
|
|
||||||
;
|
|
||||||
else if (xpath_first(xret, "/rpc-reply/rpc-error") != NULL){
|
|
||||||
if ((x=xpath_first(xret, "//error-type"))!=NULL)
|
|
||||||
etype = xml_body(x);
|
|
||||||
if (etype&&strcmp(etype, "clixon")==0){
|
|
||||||
if ((x=xpath_first(xret, "//error-tag"))!=NULL)
|
|
||||||
err = atoi(xml_body(x));
|
|
||||||
if ((x=xpath_first(xret, "//error-message"))!=NULL)
|
|
||||||
suberr = atoi(xml_body(x));
|
|
||||||
if ((x=xpath_first(xret, "//error-info"))!=NULL)
|
|
||||||
errmsg = xml_body(x);
|
|
||||||
if (debug)
|
|
||||||
clicon_err(err, suberr, "%s msgtype:%hu", errmsg, ntohs(msg->op_type));
|
|
||||||
else
|
|
||||||
clicon_err(err, suberr, "%s", errmsg);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
clicon_err(OE_PROTO, 0, "%s: unexpected reply",
|
|
||||||
__FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (xret0){
|
if (xret0){
|
||||||
*xret0 = xret;
|
*xret0 = xret;
|
||||||
xret = NULL;
|
xret = NULL;
|
||||||
|
|
@ -172,20 +137,21 @@ clicon_rpc_msg(clicon_handle h,
|
||||||
/*! Generic xml netconf clicon rpc
|
/*! Generic xml netconf clicon rpc
|
||||||
* Want to go over to use netconf directly between client and server,...
|
* Want to go over to use netconf directly between client and server,...
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] xi XML netconf tree
|
* @param[in] xmlstr XML netconf tree as string
|
||||||
* @param[out] xret Return XML, error or OK
|
* @param[out] xret Return XML netconf tree, error or OK
|
||||||
* @param[out] sp Socket pointer for notification, otherwise NULL
|
* @param[out] sp Socket pointer for notification, otherwise NULL
|
||||||
|
* @see clicon_rpc_netconf_xml xml as tree instead of string
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_netconf_xml(clicon_handle h,
|
clicon_rpc_netconf(clicon_handle h,
|
||||||
cxobj *xin,
|
char *xmlstr,
|
||||||
cxobj **xret,
|
cxobj **xret,
|
||||||
int *sp)
|
int *sp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *msg = NULL;
|
struct clicon_msg *msg = NULL;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode_xml(xin)) == NULL)
|
if ((msg = clicon_msg_encode("%s", xmlstr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, xret, sp) < 0)
|
if (clicon_rpc_msg(h, msg, xret, sp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -196,25 +162,64 @@ clicon_rpc_netconf_xml(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Generic xml netconf clicon rpc
|
||||||
|
* Want to go over to use netconf directly between client and server,...
|
||||||
|
* @param[in] h clicon handle
|
||||||
|
* @param[in] xml XML netconf tree
|
||||||
|
* @param[out] xret Return XML netconf tree, error or OK
|
||||||
|
* @param[out] sp Socket pointer for notification, otherwise NULL
|
||||||
|
* @see clicon_rpc_netconf xml as string instead of tree
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_rpc_netconf_xml(clicon_handle h,
|
||||||
|
cxobj *xml,
|
||||||
|
cxobj **xret,
|
||||||
|
int *sp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (clicon_xml2cbuf(cb, xml, 0, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Generate clicon error function call from Netconf error message
|
||||||
|
* @param[in] xerr Netconf error message on the level: <rpc-reply><rpc-error>
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_generate_error(cxobj *xerr)
|
clicon_rpc_generate_error(cxobj *xerr)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
char *etype="";
|
|
||||||
char *etag="";
|
|
||||||
char *emsg="";
|
|
||||||
char *einfo="";
|
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) ==NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((x=xpath_first(xerr, "error-type"))!=NULL)
|
if ((x=xpath_first(xerr, "error-type"))!=NULL)
|
||||||
etype = xml_body(x);
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
|
if ((x=xpath_first(xerr, "error-tag"))!=NULL)
|
||||||
etag = xml_body(x);
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
if ((x=xpath_first(xerr, "error-message"))!=NULL)
|
||||||
emsg = xml_body(x);
|
cprintf(cb, "%s ", xml_body(x));
|
||||||
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
if ((x=xpath_first(xerr, "error-info"))!=NULL)
|
||||||
einfo = xml_body(x);
|
clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0);
|
||||||
clicon_err(OE_XML, 0, "%s %s %s %s", etype, etag, emsg, einfo);
|
clicon_err_fn("Clixon", 0, OE_XML, 0, "%s", cbuf_get(cb));
|
||||||
return 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get database configuration
|
/*! Get database configuration
|
||||||
|
|
@ -252,7 +257,7 @@ clicon_rpc_get_config(clicon_handle h,
|
||||||
if (xpath && strlen(xpath))
|
if (xpath && strlen(xpath))
|
||||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||||
cprintf(cb, "</get-config></rpc>");
|
cprintf(cb, "</get-config></rpc>");
|
||||||
if ((msg = clicon_msg_netconf_encode(cbuf_get(cb))) == NULL)
|
if ((msg = clicon_msg_encode(cbuf_get(cb))) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -280,14 +285,14 @@ clicon_rpc_get_config(clicon_handle h,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send database entries as XML to backend daemon
|
/*! Send database entries as XML to backend daemon
|
||||||
* Same as clicon_proto_change just with a cvec instead of lvec
|
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] db Name of database
|
* @param[in] db Name of database
|
||||||
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
|
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
|
||||||
* @param[in] api_path restconf API Path (or "")
|
* @param[in] api_path restconf API Path (or "")
|
||||||
* @param[in] xml XML string. Ex: <a>..</a><b>...</b>
|
* @param[in] xml XML string. Ex: <config><a>..</a><b>...</b></config>
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
* @note xml arg need to have <config> as top element
|
||||||
* @code
|
* @code
|
||||||
* if (clicon_rpc_edit_config(h, "running", OP_MERGE, "/",
|
* if (clicon_rpc_edit_config(h, "running", OP_MERGE, "/",
|
||||||
* "<config><a>4</a></config>") < 0)
|
* "<config><a>4</a></config>") < 0)
|
||||||
|
|
@ -299,7 +304,7 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
char *db,
|
char *db,
|
||||||
enum operation_type op,
|
enum operation_type op,
|
||||||
char *api_path,
|
char *api_path,
|
||||||
char *xml)
|
char *xmlstr)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *msg = NULL;
|
struct clicon_msg *msg = NULL;
|
||||||
|
|
@ -314,10 +319,10 @@ clicon_rpc_edit_config(clicon_handle h,
|
||||||
xml_operation2str(op));
|
xml_operation2str(op));
|
||||||
if (api_path && strlen(api_path))
|
if (api_path && strlen(api_path))
|
||||||
cprintf(cb, "<filter type=\"restconf\" select=\"%s\"/>", api_path);
|
cprintf(cb, "<filter type=\"restconf\" select=\"%s\"/>", api_path);
|
||||||
if (xml)
|
if (xmlstr)
|
||||||
cprintf(cb, "%s", xml);
|
cprintf(cb, "%s", xmlstr);
|
||||||
cprintf(cb, "</edit-config></rpc>");
|
cprintf(cb, "</edit-config></rpc>");
|
||||||
if ((msg = clicon_msg_netconf_encode(cbuf_get(cb))) == NULL)
|
if ((msg = clicon_msg_encode(cbuf_get(cb))) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -357,7 +362,7 @@ clicon_rpc_copy_config(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>", db1, db2)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><copy-config><source><%s/></source><target><%s/></target></copy-config></rpc>", db1, db2)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -391,7 +396,7 @@ clicon_rpc_delete_config(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><delete-config><target><%s/></target></delete-config></rpc>", db)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><delete-config><target><%s/></target></delete-config></rpc>", db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -408,6 +413,10 @@ clicon_rpc_delete_config(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Lock a database
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db database, eg "running"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_lock(clicon_handle h,
|
clicon_rpc_lock(clicon_handle h,
|
||||||
char *db)
|
char *db)
|
||||||
|
|
@ -417,7 +426,7 @@ clicon_rpc_lock(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><lock><target><%s/></target></lock></rpc>", db)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><lock><target><%s/></target></lock></rpc>", db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -434,6 +443,10 @@ clicon_rpc_lock(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Unlock a database
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db database, eg "running"
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_unlock(clicon_handle h,
|
clicon_rpc_unlock(clicon_handle h,
|
||||||
char *db)
|
char *db)
|
||||||
|
|
@ -443,7 +456,7 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><unlock><target><%s/></target></unlock></rpc>", db)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><unlock><target><%s/></target></unlock></rpc>", db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -460,6 +473,9 @@ clicon_rpc_unlock(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Close a (user) session
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_close_session(clicon_handle h)
|
clicon_rpc_close_session(clicon_handle h)
|
||||||
{
|
{
|
||||||
|
|
@ -468,7 +484,7 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><close-session/></rpc>")) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><close-session/></rpc>")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -485,6 +501,10 @@ clicon_rpc_close_session(clicon_handle h)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Kill other user sessions
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] session_id Session id of other user session
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clicon_rpc_kill_session(clicon_handle h,
|
clicon_rpc_kill_session(clicon_handle h,
|
||||||
int session_id)
|
int session_id)
|
||||||
|
|
@ -494,7 +514,7 @@ clicon_rpc_kill_session(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><kill-session><session-id>%d</session-id></kill-session></rpc>", session_id)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><kill-session><session-id>%d</session-id></kill-session></rpc>", session_id)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -511,7 +531,6 @@ clicon_rpc_kill_session(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Send validate request to backend daemon
|
/*! Send validate request to backend daemon
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] db Name of database
|
* @param[in] db Name of database
|
||||||
|
|
@ -527,7 +546,7 @@ clicon_rpc_validate(clicon_handle h,
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><validate><source><%s/></source></validate></rpc>", db)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><validate><source><%s/></source></validate></rpc>", db)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -547,8 +566,6 @@ clicon_rpc_validate(clicon_handle h,
|
||||||
|
|
||||||
/*! Commit changes send a commit request to backend daemon
|
/*! Commit changes send a commit request to backend daemon
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] from name of 'from' database (eg "candidate")
|
|
||||||
* @param[in] db name of 'to' database (eg "running")
|
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
@ -559,7 +576,36 @@ clicon_rpc_commit(clicon_handle h)
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><commit/></rpc>")) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><commit/></rpc>")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
|
||||||
|
clicon_rpc_generate_error(xerr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xret)
|
||||||
|
xml_free(xret);
|
||||||
|
if (msg)
|
||||||
|
free(msg);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Discard all changes in candidate / revert to running
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @retval 0 OK
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_rpc_discard_changes(clicon_handle h)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
struct clicon_msg *msg = NULL;
|
||||||
|
cxobj *xret = NULL;
|
||||||
|
cxobj *xerr;
|
||||||
|
|
||||||
|
if ((msg = clicon_msg_encode("<rpc><discard_changes/></rpc>")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -594,11 +640,11 @@ clicon_rpc_create_subscription(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><create-subscription>"
|
if ((msg = clicon_msg_encode("<rpc><create-subscription>"
|
||||||
"<stream>%s</stream>"
|
"<stream>%s</stream>"
|
||||||
"<filter>%s</filter>"
|
"<filter>%s</filter>"
|
||||||
"</create-subscription></rpc>",
|
"</create-subscription></rpc>",
|
||||||
stream?stream:"", filter?filter:"")) == NULL)
|
stream?stream:"", filter?filter:"")) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, s0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -615,43 +661,6 @@ clicon_rpc_create_subscription(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Send database change request to backend daemon, variant for xmldb
|
|
||||||
* Same as clicon_proto_change just with a string
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] db Name of database
|
|
||||||
* @param[in] op Operation on database item: set, delete, (merge?)
|
|
||||||
* @param[in] key Database key
|
|
||||||
* @param[in] value value as string
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @note special case: remove all: key:"/" op:OP_REMOVE
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_rpc_change(clicon_handle h,
|
|
||||||
char *db,
|
|
||||||
enum operation_type op,
|
|
||||||
char *key,
|
|
||||||
char *val)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
struct clicon_msg *msg = NULL;
|
|
||||||
|
|
||||||
if ((msg = clicon_msg_change_encode(db,
|
|
||||||
op,
|
|
||||||
key,
|
|
||||||
val,
|
|
||||||
val?strlen(val)+1:0)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (clicon_rpc_msg(h, msg, NULL, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (msg)
|
|
||||||
free(msg);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Send a debug request to backend server
|
/*! Send a debug request to backend server
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
* @param[in] level Debug level
|
* @param[in] level Debug level
|
||||||
|
|
@ -665,7 +674,7 @@ clicon_rpc_debug(clicon_handle h,
|
||||||
cxobj *xret = NULL;
|
cxobj *xret = NULL;
|
||||||
cxobj *xerr;
|
cxobj *xerr;
|
||||||
|
|
||||||
if ((msg = clicon_msg_netconf_encode("<rpc><debug><level>%d</level></debug></rpc>", level)) == NULL)
|
if ((msg = clicon_msg_encode("<rpc><debug><level>%d</level></debug></rpc>", level)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -1,244 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
***** BEGIN LICENSE BLOCK *****
|
|
||||||
|
|
||||||
Copyright (C) 2009-2017 Olof Hagsand and Benny Holmgren
|
|
||||||
|
|
||||||
This file is part of CLIXON.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
Alternatively, the contents of this file may be used under the terms of
|
|
||||||
the GNU General Public License Version 3 or later (the "GPL"),
|
|
||||||
in which case the provisions of the GPL are applicable instead
|
|
||||||
of those above. If you wish to allow use of your version of this file only
|
|
||||||
under the terms of the GPL, and not to allow others to
|
|
||||||
use your version of this file under the terms of Apache License version 2,
|
|
||||||
indicate your decision by deleting the provisions above and replace them with
|
|
||||||
the notice and other provisions required by the GPL. If you do not delete
|
|
||||||
the provisions above, a recipient may use your version of this file under
|
|
||||||
the terms of any one of the Apache License version 2 or the GPL.
|
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
|
||||||
|
|
||||||
*
|
|
||||||
* Protocol to communicate between clients (eg clicon_cli, clicon_netconf)
|
|
||||||
* and server (clicon_backend)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.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_chunk.h"
|
|
||||||
#include "clixon_sig.h"
|
|
||||||
#include "clixon_hash.h"
|
|
||||||
#include "clixon_handle.h"
|
|
||||||
#include "clixon_xml.h"
|
|
||||||
#include "clixon_proto.h"
|
|
||||||
#include "clixon_proto_encode.h"
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_netconf_encode(char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
int xmllen;
|
|
||||||
int len;
|
|
||||||
struct clicon_msg *msg = NULL;
|
|
||||||
int hdrlen = sizeof(*msg);
|
|
||||||
|
|
||||||
va_start(args, format);
|
|
||||||
xmllen = vsnprintf(NULL, 0, format, args) + 1;
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
len = hdrlen + xmllen;
|
|
||||||
if ((msg = (struct clicon_msg *)malloc(len)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "malloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(msg, 0, len);
|
|
||||||
/* hdr */
|
|
||||||
msg->op_type = htons(CLICON_MSG_NETCONF);
|
|
||||||
msg->op_len = htons(len);
|
|
||||||
|
|
||||||
/* body */
|
|
||||||
va_start(args, format);
|
|
||||||
vsnprintf(msg->op_body, xmllen, format, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_netconf_encode_xml(cxobj *xml)
|
|
||||||
{
|
|
||||||
struct clicon_msg *msg = NULL;
|
|
||||||
cbuf *cb = NULL;
|
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (clicon_xml2cbuf(cb, xml, 0, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
if ((msg = clicon_msg_netconf_encode("%s", cbuf_get(cb))) < 0)
|
|
||||||
goto done;
|
|
||||||
done:
|
|
||||||
if (cb)
|
|
||||||
cbuf_free(cb);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_netconf_decode(struct clicon_msg *msg,
|
|
||||||
cxobj **xml)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
char *xmlstr;
|
|
||||||
|
|
||||||
/* body */
|
|
||||||
xmlstr = msg->op_body;
|
|
||||||
if (clicon_xml_parse_str(xmlstr, xml) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct clicon_msg *
|
|
||||||
clicon_msg_change_encode(char *db,
|
|
||||||
uint32_t op,
|
|
||||||
char *key,
|
|
||||||
char *str,
|
|
||||||
uint32_t str_len)
|
|
||||||
{
|
|
||||||
struct clicon_msg *msg;
|
|
||||||
uint16_t len;
|
|
||||||
int hdrlen = sizeof(*msg);
|
|
||||||
int p;
|
|
||||||
uint32_t tmp;
|
|
||||||
|
|
||||||
clicon_debug(2, "%s: op: %d str_len: %d db: %s key: '%s'",
|
|
||||||
__FUNCTION__,
|
|
||||||
op, str_len, db, key);
|
|
||||||
p = 0;
|
|
||||||
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(db) + 1 +
|
|
||||||
strlen(key) + str_len;
|
|
||||||
if (str_len)
|
|
||||||
len++; /* if str not null add end of string */
|
|
||||||
if ((msg = (struct clicon_msg *)malloc(len)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "malloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
memset(msg, 0, len);
|
|
||||||
/* hdr */
|
|
||||||
msg->op_type = htons(CLICON_MSG_CHANGE);
|
|
||||||
msg->op_len = htons(len);
|
|
||||||
|
|
||||||
/* body */
|
|
||||||
tmp = htonl(op);
|
|
||||||
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
||||||
p += sizeof(uint32_t);
|
|
||||||
|
|
||||||
tmp = htonl(str_len);
|
|
||||||
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
||||||
p += sizeof(uint32_t);
|
|
||||||
strncpy(msg->op_body+p, db, len-p-hdrlen);
|
|
||||||
p += strlen(db)+1;
|
|
||||||
strncpy(msg->op_body+p, key, len-p-hdrlen);
|
|
||||||
p += strlen(key)+1;
|
|
||||||
if (str_len){
|
|
||||||
memcpy(msg->op_body+p, str, str_len);
|
|
||||||
p += str_len;
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
clicon_msg_change_decode(struct clicon_msg *msg,
|
|
||||||
char **db,
|
|
||||||
uint32_t *op,
|
|
||||||
char **key,
|
|
||||||
char **str,
|
|
||||||
uint32_t *str_len,
|
|
||||||
const char *label)
|
|
||||||
{
|
|
||||||
int p;
|
|
||||||
uint32_t tmp;
|
|
||||||
|
|
||||||
p = 0;
|
|
||||||
/* body */
|
|
||||||
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
||||||
*op = ntohl(tmp);
|
|
||||||
p += sizeof(uint32_t);
|
|
||||||
|
|
||||||
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
||||||
*str_len = ntohl(tmp);
|
|
||||||
p += sizeof(uint32_t);
|
|
||||||
|
|
||||||
if ((*db = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += strlen(*db)+1;
|
|
||||||
if ((*key = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
p += strlen(*key)+1;
|
|
||||||
|
|
||||||
if (*str_len){
|
|
||||||
if ((*str = chunk(*str_len, label)) == NULL){
|
|
||||||
clicon_err(OE_PROTO, errno, "%s: chunk",
|
|
||||||
__FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memcpy(*str, msg->op_body+p, *str_len);
|
|
||||||
p += *str_len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*str = NULL;
|
|
||||||
clicon_debug(2, "%s: op: %d str_len: %d db: %s key: '%s'",
|
|
||||||
__FUNCTION__,
|
|
||||||
*op, *str_len, *db, *key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1110,7 +1110,7 @@ clicon_xml_parse_str(char *str,
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* cxobj *cx = NULL;
|
* cxobj *cx = NULL;
|
||||||
* if (clicon_xml_parse(&cx, "<xml>%s</xml", 22) < 0)
|
* if (clicon_xml_parse(&cx, "<xml>%d</xml>", 22) < 0)
|
||||||
* err;
|
* err;
|
||||||
* xml_free(cx);
|
* xml_free(cx);
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ yang2xmlkeyfmt(yang_stmt *ys,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Transform an xml key format and a vector of values to an XML key
|
/*! Transform an xml key format and a vector of values to an XML key
|
||||||
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
|
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
|
||||||
* Example:
|
* Example:
|
||||||
|
|
@ -1183,6 +1184,225 @@ put(char *dbname,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Modify database provided an XML database key and an operation
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] db Database name
|
||||||
|
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
||||||
|
* @param[in] xk XML Key, eg /aa/bb=17/name
|
||||||
|
* @param[in] val Key value, eg "17"
|
||||||
|
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @code
|
||||||
|
* if (xmldb_put_xkey(h, db, OP_MERGE, "/aa/bb=17/name", "17") < 0)
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
|
* @see xmldb_put with xml-tree, no path
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xmldb_put_xkey(clicon_handle h,
|
||||||
|
char *db,
|
||||||
|
enum operation_type op,
|
||||||
|
char *xk,
|
||||||
|
char *val)
|
||||||
|
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *x = NULL;
|
||||||
|
yang_stmt *y = NULL;
|
||||||
|
yang_stmt *ykey;
|
||||||
|
char **vec;
|
||||||
|
int nvec;
|
||||||
|
char **valvec;
|
||||||
|
int nvalvec;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
char *name;
|
||||||
|
char *restval;
|
||||||
|
cg_var *cvi;
|
||||||
|
cvec *cvk = NULL; /* vector of index keys */
|
||||||
|
char *val2 = NULL;
|
||||||
|
cbuf *ckey=NULL; /* partial keys */
|
||||||
|
cbuf *csubkey=NULL; /* partial keys */
|
||||||
|
cbuf *crx=NULL; /* partial keys */
|
||||||
|
char *keyname;
|
||||||
|
int exists;
|
||||||
|
int npairs;
|
||||||
|
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!='/'){
|
||||||
|
clicon_err(OE_DB, 0, "Invalid key: %s", xk);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((ckey = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((csubkey = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((vec = clicon_strsplit(xk, "/", &nvec, __FUNCTION__)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (nvec < 2){
|
||||||
|
clicon_err(OE_XML, 0, "Malformed key: %s", xk);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
i = 1;
|
||||||
|
while (i<nvec){
|
||||||
|
name = vec[i]; /* E.g "x=1,2" -> name:x restval=1,2 */
|
||||||
|
if ((restval = index(name, '=')) != NULL){
|
||||||
|
*restval = '\0';
|
||||||
|
restval++;
|
||||||
|
}
|
||||||
|
if (i==1){
|
||||||
|
if (strlen(name)==0 && (op==OP_DELETE || op == OP_REMOVE)){
|
||||||
|
/* Special handling of "/" */
|
||||||
|
cprintf(ckey, "/");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ((y = yang_find_topnode(yspec, name)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", x?xml_name(x):"");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((op==OP_DELETE || op == OP_REMOVE) &&
|
||||||
|
y->ys_keyword == Y_LEAF &&
|
||||||
|
y->ys_parent->yn_keyword == Y_LIST &&
|
||||||
|
yang_key_match(y->ys_parent, y->ys_argument))
|
||||||
|
/* Special rule if key, dont write last key-name, rm whole*/;
|
||||||
|
else
|
||||||
|
cprintf(ckey, "/%s", name);
|
||||||
|
i++;
|
||||||
|
switch (y->ys_keyword){
|
||||||
|
case Y_LEAF_LIST:
|
||||||
|
if (restval==NULL){
|
||||||
|
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(ckey, "=%s", restval);
|
||||||
|
break;
|
||||||
|
case Y_LIST:
|
||||||
|
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||||
|
__FUNCTION__, y->ys_argument);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* The value is a list of keys: <key>[ <key>]* */
|
||||||
|
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (restval==NULL){
|
||||||
|
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((valvec = clicon_strsplit(restval, ",", &nvalvec, __FUNCTION__)) == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (cvec_len(cvk) != nvalvec){
|
||||||
|
clicon_err(OE_XML, errno, "List %s key length mismatch", name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cvi = NULL;
|
||||||
|
/* Iterate over individual yang keys */
|
||||||
|
j = 0;
|
||||||
|
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||||
|
keyname = cv_string_get(cvi);
|
||||||
|
if (j)
|
||||||
|
cprintf(ckey, ",");
|
||||||
|
else
|
||||||
|
cprintf(ckey, "=");
|
||||||
|
val2 = valvec[j++];
|
||||||
|
|
||||||
|
cprintf(ckey, "%s", val2);
|
||||||
|
cbuf_reset(csubkey);
|
||||||
|
cprintf(csubkey, "%s/%s", cbuf_get(ckey), keyname);
|
||||||
|
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
||||||
|
if (db_set(filename, cbuf_get(csubkey), val2, strlen(val2)+1) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (cvk){
|
||||||
|
cvec_free(cvk);
|
||||||
|
cvk = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
||||||
|
if (db_set(filename, cbuf_get(ckey), NULL, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xk = cbuf_get(ckey);
|
||||||
|
/* final key */
|
||||||
|
switch (op){
|
||||||
|
case OP_CREATE:
|
||||||
|
if ((exists = db_exists(filename, xk)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (exists == 1){
|
||||||
|
clicon_err(OE_DB, 0, "OP_CREATE: %s already exists in database", xk);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
case OP_MERGE:
|
||||||
|
case OP_REPLACE:
|
||||||
|
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
||||||
|
if (db_set(filename, xk, val, val?strlen(val)+1:0) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (db_set(filename, xk, NULL, 0) < 0)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
case OP_DELETE:
|
||||||
|
if ((exists = db_exists(filename, xk)) < 0)
|
||||||
|
goto done;
|
||||||
|
if (exists == 0){
|
||||||
|
clicon_err(OE_DB, 0, "OP_DELETE: %s does not exists in database", xk);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
case OP_REMOVE:
|
||||||
|
/* Read in complete database (this can be optimized) */
|
||||||
|
if ((crx = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(crx, "^%s.*$", xk);
|
||||||
|
if ((npairs = db_regexp(filename, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0)
|
||||||
|
goto done;
|
||||||
|
for (i = 0; i < npairs; i++) {
|
||||||
|
if (db_del(filename, pairs[i].dp_key) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (filename)
|
||||||
|
free(filename);
|
||||||
|
if (ckey)
|
||||||
|
cbuf_free(ckey);
|
||||||
|
if (csubkey)
|
||||||
|
cbuf_free(csubkey);
|
||||||
|
if (crx)
|
||||||
|
cbuf_free(crx);
|
||||||
|
if (cvk)
|
||||||
|
cvec_free(cvk);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Modify database provided an xml tree, a restconf api_path and an operation
|
/*! Modify database provided an xml tree, a restconf api_path and an operation
|
||||||
*
|
*
|
||||||
* @param[in] h CLICON handle
|
* @param[in] h CLICON handle
|
||||||
|
|
@ -1430,6 +1650,8 @@ xmldb_put(clicon_handle h,
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
char *dbfilename = NULL;
|
char *dbfilename = NULL;
|
||||||
|
|
||||||
|
if (xml_child_nr(xt)==0 || xml_body(xt)!= NULL)
|
||||||
|
return xmldb_put_xkey(h, db, op, api_path, xml_body(xt));
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if (db2file(h, db, &dbfilename) < 0)
|
if (db2file(h, db, &dbfilename) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -1464,224 +1686,6 @@ xmldb_put(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Modify database provided an XML database key and an operation
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] db Database name
|
|
||||||
* @param[in] op OP_MERGE, OP_REPLACE, OP_REMOVE, etc
|
|
||||||
* @param[in] xk XML Key, eg /aa/bb=17/name
|
|
||||||
* @param[in] val Key value, eg "17"
|
|
||||||
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1 Error
|
|
||||||
* @code
|
|
||||||
* if (xmldb_put_xkey(h, db, OP_MERGE, "/aa/bb=17/name", "17") < 0)
|
|
||||||
* err;
|
|
||||||
* @endcode
|
|
||||||
* @see xmldb_put with xml-tree, no path
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xmldb_put_xkey(clicon_handle h,
|
|
||||||
char *db,
|
|
||||||
enum operation_type op,
|
|
||||||
char *xk,
|
|
||||||
char *val)
|
|
||||||
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
cxobj *x = NULL;
|
|
||||||
yang_stmt *y = NULL;
|
|
||||||
yang_stmt *ykey;
|
|
||||||
char **vec;
|
|
||||||
int nvec;
|
|
||||||
char **valvec;
|
|
||||||
int nvalvec;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
char *name;
|
|
||||||
char *restval;
|
|
||||||
cg_var *cvi;
|
|
||||||
cvec *cvk = NULL; /* vector of index keys */
|
|
||||||
char *val2 = NULL;
|
|
||||||
cbuf *ckey=NULL; /* partial keys */
|
|
||||||
cbuf *csubkey=NULL; /* partial keys */
|
|
||||||
cbuf *crx=NULL; /* partial keys */
|
|
||||||
char *keyname;
|
|
||||||
int exists;
|
|
||||||
int npairs;
|
|
||||||
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!='/'){
|
|
||||||
clicon_err(OE_DB, 0, "Invalid key: %s", xk);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((ckey = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((csubkey = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((vec = clicon_strsplit(xk, "/", &nvec, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (nvec < 2){
|
|
||||||
clicon_err(OE_XML, 0, "Malformed key: %s", xk);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
i = 1;
|
|
||||||
while (i<nvec){
|
|
||||||
name = vec[i]; /* E.g "x=1,2" -> name:x restval=1,2 */
|
|
||||||
if ((restval = index(name, '=')) != NULL){
|
|
||||||
*restval = '\0';
|
|
||||||
restval++;
|
|
||||||
}
|
|
||||||
if (i==1){
|
|
||||||
if (strlen(name)==0 && (op==OP_DELETE || op == OP_REMOVE)){
|
|
||||||
/* Special handling of "/" */
|
|
||||||
cprintf(ckey, "/");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ((y = yang_find_topnode(yspec, name)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", x?xml_name(x):"");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ((y = yang_find_syntax((yang_node*)y, name)) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((op==OP_DELETE || op == OP_REMOVE) &&
|
|
||||||
y->ys_keyword == Y_LEAF &&
|
|
||||||
y->ys_parent->yn_keyword == Y_LIST &&
|
|
||||||
yang_key_match(y->ys_parent, y->ys_argument))
|
|
||||||
/* Special rule if key, dont write last key-name, rm whole*/;
|
|
||||||
else
|
|
||||||
cprintf(ckey, "/%s", name);
|
|
||||||
i++;
|
|
||||||
switch (y->ys_keyword){
|
|
||||||
case Y_LEAF_LIST:
|
|
||||||
if (restval==NULL){
|
|
||||||
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cprintf(ckey, "=%s", restval);
|
|
||||||
break;
|
|
||||||
case Y_LIST:
|
|
||||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
|
||||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
|
||||||
__FUNCTION__, y->ys_argument);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* The value is a list of keys: <key>[ <key>]* */
|
|
||||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (restval==NULL){
|
|
||||||
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((valvec = clicon_strsplit(restval, ",", &nvalvec, __FUNCTION__)) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (cvec_len(cvk) != nvalvec){
|
|
||||||
clicon_err(OE_XML, errno, "List %s key length mismatch", name);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cvi = NULL;
|
|
||||||
/* Iterate over individual yang keys */
|
|
||||||
j = 0;
|
|
||||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
|
||||||
keyname = cv_string_get(cvi);
|
|
||||||
if (j)
|
|
||||||
cprintf(ckey, ",");
|
|
||||||
else
|
|
||||||
cprintf(ckey, "=");
|
|
||||||
val2 = valvec[j++];
|
|
||||||
|
|
||||||
cprintf(ckey, "%s", val2);
|
|
||||||
cbuf_reset(csubkey);
|
|
||||||
cprintf(csubkey, "%s/%s", cbuf_get(ckey), keyname);
|
|
||||||
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
|
||||||
if (db_set(filename, cbuf_get(csubkey), val2, strlen(val2)+1) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (cvk){
|
|
||||||
cvec_free(cvk);
|
|
||||||
cvk = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (op == OP_MERGE || op == OP_REPLACE || op == OP_CREATE)
|
|
||||||
if (db_set(filename, cbuf_get(ckey), NULL, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xk = cbuf_get(ckey);
|
|
||||||
/* final key */
|
|
||||||
switch (op){
|
|
||||||
case OP_CREATE:
|
|
||||||
if ((exists = db_exists(filename, xk)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (exists == 1){
|
|
||||||
clicon_err(OE_DB, 0, "OP_CREATE: %s already exists in database", xk);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
case OP_MERGE:
|
|
||||||
case OP_REPLACE:
|
|
||||||
if (y->ys_keyword == Y_LEAF || y->ys_keyword == Y_LEAF_LIST){
|
|
||||||
if (db_set(filename, xk, val, val?strlen(val)+1:0) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (db_set(filename, xk, NULL, 0) < 0)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
case OP_DELETE:
|
|
||||||
if ((exists = db_exists(filename, xk)) < 0)
|
|
||||||
goto done;
|
|
||||||
if (exists == 0){
|
|
||||||
clicon_err(OE_DB, 0, "OP_DELETE: %s does not exists in database", xk);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
case OP_REMOVE:
|
|
||||||
/* Read in complete database (this can be optimized) */
|
|
||||||
if ((crx = cbuf_new()) == NULL){
|
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cprintf(crx, "^%s.*$", xk);
|
|
||||||
if ((npairs = db_regexp(filename, cbuf_get(crx), __FUNCTION__, &pairs, 0)) < 0)
|
|
||||||
goto done;
|
|
||||||
for (i = 0; i < npairs; i++) {
|
|
||||||
if (db_del(filename, pairs[i].dp_key) < 0)
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (filename)
|
|
||||||
free(filename);
|
|
||||||
if (ckey)
|
|
||||||
cbuf_free(ckey);
|
|
||||||
if (csubkey)
|
|
||||||
cbuf_free(csubkey);
|
|
||||||
if (crx)
|
|
||||||
cbuf_free(crx);
|
|
||||||
if (cvk)
|
|
||||||
cvec_free(cvk);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Raw dump of database, just keys and values, no xml interpretation
|
/*! Raw dump of database, just keys and values, no xml interpretation
|
||||||
* @param[in] f File
|
* @param[in] f File
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ EOF
|
||||||
fi
|
fi
|
||||||
match=`echo "$ret" | grep -Eo "$expect"`
|
match=`echo "$ret" | grep -Eo "$expect"`
|
||||||
if [ -z "$match" ]; then
|
if [ -z "$match" ]; then
|
||||||
err "
|
err "\nExpected:\t\"$expect\"\nGot:\t\"$ret\""
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,18 @@ sudo clixon_backend -If $clixon_cf
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
err
|
err
|
||||||
fi
|
fi
|
||||||
|
new "cli configure top"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf set interfaces" ""
|
||||||
|
|
||||||
|
new "cli show configuration top"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf show conf cli" "^interfaces$"
|
||||||
|
|
||||||
|
new "cli configure delete top"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf delete interfaces" ""
|
||||||
|
|
||||||
|
new "cli show configuration delete top"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf show conf cli" ""
|
||||||
|
|
||||||
new "cli configure"
|
new "cli configure"
|
||||||
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0" ""
|
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0" ""
|
||||||
|
|
||||||
|
|
@ -34,8 +46,21 @@ expectfn "clixon_cli -1f $clixon_cf -l o validate" "Missing mandatory variable"
|
||||||
|
|
||||||
new "cli configure more"
|
new "cli configure more"
|
||||||
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0 ipv4 address 1.2.3.4 prefix-length 24" ""
|
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0 ipv4 address 1.2.3.4 prefix-length 24" ""
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0 description mydesc" ""
|
||||||
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0 type bgp" ""
|
expectfn "clixon_cli -1f $clixon_cf set interfaces interface eth0 type bgp" ""
|
||||||
|
|
||||||
|
new "cli show xpath description"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" "<description>mydesc</description>"
|
||||||
|
|
||||||
|
new "cli delete description"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf -l o delete interfaces interface eth0 description mydesc"
|
||||||
|
|
||||||
|
new "cli show xpath no description"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf -l o show xpath /interfaces/interface/description" ""
|
||||||
|
|
||||||
|
new "cli success validate"
|
||||||
|
expectfn "clixon_cli -1f $clixon_cf -l o validate" ""
|
||||||
|
|
||||||
new "cli commit"
|
new "cli commit"
|
||||||
expectfn "clixon_cli -1f $clixon_cf -l o commit" ""
|
expectfn "clixon_cli -1f $clixon_cf -l o commit" ""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue