clixon/lib/src/clixon_xml_db_rpc.c
2016-08-15 09:29:22 +02:00

566 lines
13 KiB
C

/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
CLIXON is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
CLIXON is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CLIXON; see the file LICENSE. If not, see
<http://www.gnu.org/licenses/>.
* XML database
* TODO: xmldb_del: or dbxml_put_xkey delete
*/
#ifdef HAVE_CONFIG_H
#include "clixon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <fnmatch.h>
#include <stdint.h>
#include <assert.h>
#include <syslog.h>
#include <arpa/inet.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include "clixon_err.h"
#include "clixon_log.h"
#include "clixon_queue.h"
#include "clixon_string.h"
#include "clixon_chunk.h"
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_qdb.h"
#include "clixon_yang.h"
#include "clixon_handle.h"
#include "clixon_yang.h"
#include "clixon_options.h"
#include "clixon_xml.h"
#include "clixon_xsl.h"
#include "clixon_xml_parse.h"
#include "clixon_xml_db.h"
#include "clixon_xml_db_rpc.h"
/*! Make an rpc call to xmldb daemon
*/
static int
xmldb_rpc(clicon_handle h,
char *data,
size_t len,
char *retdata,
size_t *retlen
)
{
int retval = -1;
char *dst;
uint16_t port;
int s = -1;
struct sockaddr_in addr;
if ((dst = clicon_xmldb_addr(h)) == NULL){
clicon_err(OE_CFG, errno, "CLICON_XMLDB_ADDR option not set");
goto done;
}
if ((port = clicon_xmldb_port(h)) == 0){
clicon_err(OE_CFG, errno, "CLICON_XMLDB_PORT option not set");
goto done;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1)
goto done; /* Could check getaddrinfo */
if ((s = socket(addr.sin_family, SOCK_STREAM, 0)) < 0) {
clicon_err(OE_CFG, errno, "socket");
return -1;
}
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0){
clicon_err(OE_CFG, errno, "connecting socket inet4");
close(s);
goto done;
}
if (write(s, data, len) < 0){
clicon_err(OE_UNIX, errno, "write");
goto done;
}
if ((*retlen = read(s, retdata, *retlen)) < 0){
clicon_err(OE_UNIX, errno, "write");
goto done;
}
retval = 0;
if (debug > 1)
fprintf(stderr, "%s: \"%s\"\n", __FUNCTION__, retdata);
done:
if (s != -1)
close(s);
return retval;
}
/*! Send put request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval 0
*/
int
xmldb_put_rpc(clicon_handle h,
char *db,
cxobj *xt,
enum operation_type op)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
char *opstr;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><put>");
cprintf(cb, "<target><%s/></target>", db);
if (op){
switch (op){
case OP_REPLACE:
opstr = "replace";
break;
case OP_MERGE:
opstr = "merge";
break;
case OP_NONE:
default:
opstr = "none";
break;
}
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
}
cprintf(cb, "<config>");
if (clicon_xml2cbuf(cb, xt, 0, 1) < 0)
goto done;
cprintf(cb, "</config>");
cprintf(cb, "</put></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! Send put xkey request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval 0
*/
int
xmldb_put_xkey_rpc(clicon_handle h,
char *db,
char *xk,
char *val,
enum operation_type op)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
char *opstr;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><put-xkey>");
cprintf(cb, "<target><%s/></target>", db);
if (op){
switch (op){
case OP_REPLACE:
opstr = "replace";
break;
case OP_MERGE:
opstr = "merge";
break;
case OP_NONE:
default:
opstr = "none";
break;
}
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
}
cprintf(cb, "<xkey>%s</xkey>", xk);
cprintf(cb, "<value>%s</value>", val);
cprintf(cb, "</put-xkey></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! Send get request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval 0
*/
int
xmldb_get_rpc(clicon_handle h,
char *db,
char *xpath,
int vector,
cxobj **xtop,
cxobj ***xvec,
size_t *xlen)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt=NULL;
cxobj *xc;
int i;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><get>");
cprintf(cb, "<source><%s/></source>", db);
if (xpath)
cprintf(cb, "<xpath>%s</xpath>", xpath);
if (vector)
cprintf(cb, "<vector/>");
cprintf(cb, "</get></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (vector){
i=0;
if ((*xvec = calloc(xml_child_nr(xt), sizeof(cxobj*))) ==NULL){
clicon_err(OE_UNIX, errno, "calloc");
goto done;
}
xc = NULL;
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
(*xvec)[i++] = xc;
}
*xlen = i;
*xtop = xt;
xt = NULL;
}
else{
if (xml_rootchild(xt, 0, xtop) < 0)
goto done;
xt = NULL;
}
retval = 0;
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Copy database
* @param[in] h Clicon handle
* @param[in] from Source database copy
* @param[in] to Destination database
* @retval -1 Error
* @retval 0 OK
*/
int
xmldb_copy_rpc(clicon_handle h,
char *from,
char *to)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt = NULL;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><copy>");
cprintf(cb, "<source><%s/></source>", from);
cprintf(cb, "<target><%s/></target>", to);
cprintf(cb, "</copy></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (xpath_first(xt, "//ok"))
retval = 0;
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Lock database
* @param[in] h Clicon handle
* @param[in] db Database
* @param[in] pid Process id
* @retval -1 Error
* @retval 0 OK
*/
int
xmldb_lock_rpc(clicon_handle h,
char *db,
int id)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt = NULL;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><lock>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "<id><%u/></id>", id);
cprintf(cb, "</lock></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (xpath_first(xt, "//ok"))
retval = 0;
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Unlock database
* @param[in] h Clicon handle
* @param[in] db Database
* @param[in] pid Process id
* @retval -1 Error
* @retval 0 OK
*/
int
xmldb_unlock_rpc(clicon_handle h,
char *db,
int id)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt = NULL;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><unlock>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "<id><%u/></id>", id);
cprintf(cb, "</unlock></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (xpath_first(xt, "//ok"))
retval = 0;
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Check if database is locked
* @param[in] h Clicon handle
* @param[in] db Database
* @retval -1 Error
* @retval pid Process id if locked
*/
int
xmldb_islocked_rpc(clicon_handle h,
char *db)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt = NULL;
cxobj *x;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><islocked>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "</islocked></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (xpath_first(xt, "//unlocked"))
retval = 0;
else
if ((x=xpath_first(xt, "//locked")) != NULL)
retval = atoi(xml_body(x));
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Send exists request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval -1 Error
* @retval 0 No it does not exist
* @retval 1 Yes it exists
*/
int
xmldb_exists_rpc(clicon_handle h,
char *db)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
cxobj *xt = NULL;
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><exists>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "</exists></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
if (clicon_xml_parse_str(rb, &xt) < 0)
goto done;
if (xpath_first(xt, "//ok"))
retval = 1;
else
retval = 0;
done:
if (xt)
xml_free(xt);
if (cb)
cbuf_free(cb);
return retval;
}
/*! Send delete request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval 0
*/
int
xmldb_delete_rpc(clicon_handle h,
char *db)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><delete>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "</delete></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! Send init request to backend daemon
* @param[in] h CLICON handle
* @param[in] db running|candidate
* @retval 0
*/
int
xmldb_init_rpc(clicon_handle h,
char *db)
{
int retval = -1;
cbuf *cb = NULL;
char retbuf[BUFSIZ];
char *rb = retbuf;
size_t retlen = sizeof(retbuf);
if ((cb = cbuf_new()) == NULL)
goto done;
cprintf(cb, "<rpc><init>");
cprintf(cb, "<target><%s/></target>", db);
cprintf(cb, "</init></rpc>]]>]]>");
if (xmldb_rpc(h,
cbuf_get(cb),
cbuf_len(cb)+1,
rb, &retlen) < 0)
goto done;
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}