570 lines
13 KiB
C
570 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"
|
|
|
|
static int
|
|
xmldb_rpc(clicon_handle h,
|
|
char *data,
|
|
size_t len,
|
|
char *retdata,
|
|
size_t *retlen
|
|
)
|
|
{
|
|
int retval = -1;
|
|
char *dst;
|
|
uint16_t port;
|
|
int s = -1;
|
|
struct sockaddr_in addr;
|
|
|
|
if ((dst = clicon_xmldb_addr(h)) == NULL){
|
|
clicon_err(OE_CFG, errno, "CLICON_XMLDB_ADDR option not set");
|
|
goto done;
|
|
}
|
|
if ((port = clicon_xmldb_port(h)) == 0){
|
|
clicon_err(OE_CFG, errno, "CLICON_XMLDB_PORT option not set");
|
|
goto done;
|
|
}
|
|
memset(&addr, 0, sizeof(addr));
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
if (inet_pton(addr.sin_family, dst, &addr.sin_addr) != 1)
|
|
goto done; /* Could check getaddrinfo */
|
|
if ((s = socket(addr.sin_family, SOCK_STREAM, 0)) < 0) {
|
|
clicon_err(OE_CFG, errno, "socket");
|
|
return -1;
|
|
}
|
|
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0){
|
|
clicon_err(OE_CFG, errno, "connecting socket inet4");
|
|
close(s);
|
|
goto done;
|
|
}
|
|
if (write(s, data, len) < 0){
|
|
clicon_err(OE_UNIX, errno, "write");
|
|
goto done;
|
|
}
|
|
if ((*retlen = read(s, retdata, *retlen)) < 0){
|
|
clicon_err(OE_UNIX, errno, "write");
|
|
goto done;
|
|
}
|
|
retval = 0;
|
|
if (debug > 1)
|
|
fprintf(stderr, "%s: \"%s\"\n", __FUNCTION__, retdata);
|
|
done:
|
|
if (s != -1)
|
|
close(s);
|
|
return retval;
|
|
}
|
|
|
|
/*! Send put request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval 0
|
|
*/
|
|
int
|
|
xmldb_put_rpc(clicon_handle h,
|
|
char *db,
|
|
cxobj *xt,
|
|
enum operation_type op)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
char *opstr;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><put>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
if (op){
|
|
switch (op){
|
|
case OP_REPLACE:
|
|
opstr = "replace";
|
|
break;
|
|
case OP_MERGE:
|
|
opstr = "merge";
|
|
break;
|
|
case OP_NONE:
|
|
opstr = "none";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
|
|
}
|
|
cprintf(cb, "<config>");
|
|
if (clicon_xml2cbuf(cb, xt, 0, 1) < 0)
|
|
goto done;
|
|
cprintf(cb, "</config>");
|
|
cprintf(cb, "</put></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
retval = 0;
|
|
done:
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Send put xkey request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval 0
|
|
*/
|
|
int
|
|
xmldb_put_xkey_rpc(clicon_handle h,
|
|
char *db,
|
|
char *xk,
|
|
char *val,
|
|
enum operation_type op)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
char *opstr;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><put-xkey>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
if (op){
|
|
switch (op){
|
|
case OP_REPLACE:
|
|
opstr = "replace";
|
|
break;
|
|
case OP_MERGE:
|
|
opstr = "merge";
|
|
break;
|
|
case OP_NONE:
|
|
opstr = "none";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
cprintf(cb, "<default-operation>%s</default-operation>", opstr);
|
|
}
|
|
cprintf(cb, "<xkey>%s</xkey>", xk);
|
|
cprintf(cb, "<value>%s</value>", val);
|
|
cprintf(cb, "</put-xkey></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
retval = 0;
|
|
done:
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Send get request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval 0
|
|
*/
|
|
int
|
|
xmldb_get_rpc(clicon_handle h,
|
|
char *db,
|
|
char *xpath,
|
|
int vector,
|
|
cxobj **xtop,
|
|
cxobj ***xvec,
|
|
size_t *xlen)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt=NULL;
|
|
cxobj *xc;
|
|
int i;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><get>");
|
|
cprintf(cb, "<source><%s/></source>", db);
|
|
if (xpath)
|
|
cprintf(cb, "<xpath>%s</xpath>", xpath);
|
|
if (vector)
|
|
cprintf(cb, "<vector/>");
|
|
cprintf(cb, "</get></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (vector){
|
|
i=0;
|
|
if ((*xvec = calloc(xml_child_nr(xt), sizeof(cxobj*))) ==NULL){
|
|
clicon_err(OE_UNIX, errno, "calloc");
|
|
goto done;
|
|
}
|
|
xc = NULL;
|
|
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) {
|
|
(*xvec)[i++] = xc;
|
|
}
|
|
*xlen = i;
|
|
*xtop = xt;
|
|
xt = NULL;
|
|
}
|
|
else{
|
|
if ((xc = xml_child_i(xt, 0)) != NULL){
|
|
xml_prune(xt, xc, 0); /* kludge to remove top-level tag (eg top/clicon) */
|
|
xml_parent_set(xc, NULL);
|
|
if (debug > 1)
|
|
clicon_xml2file(stderr, xc, 0, 1);
|
|
}
|
|
*xtop = xc;
|
|
}
|
|
|
|
retval = 0;
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Copy database
|
|
* @param[in] h Clicon handle
|
|
* @param[in] from Source database copy
|
|
* @param[in] to Destination database
|
|
* @retval -1 Error
|
|
* @retval 0 OK
|
|
*/
|
|
int
|
|
xmldb_copy_rpc(clicon_handle h,
|
|
char *from,
|
|
char *to)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt = NULL;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><copy>");
|
|
cprintf(cb, "<source><%s/></source>", from);
|
|
cprintf(cb, "<target><%s/></target>", to);
|
|
cprintf(cb, "</copy></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (xpath_first(xt, "//ok"))
|
|
retval = 0;
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Lock database
|
|
* @param[in] h Clicon handle
|
|
* @param[in] db Database
|
|
* @param[in] pid Process id
|
|
* @retval -1 Error
|
|
* @retval 0 OK
|
|
*/
|
|
int
|
|
xmldb_lock_rpc(clicon_handle h,
|
|
char *db,
|
|
int id)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt = NULL;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><lock>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "<id><%u/></id>", id);
|
|
cprintf(cb, "</lock></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (xpath_first(xt, "//ok"))
|
|
retval = 0;
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Unlock database
|
|
* @param[in] h Clicon handle
|
|
* @param[in] db Database
|
|
* @param[in] pid Process id
|
|
* @retval -1 Error
|
|
* @retval 0 OK
|
|
*/
|
|
int
|
|
xmldb_unlock_rpc(clicon_handle h,
|
|
char *db,
|
|
int id)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt = NULL;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><unlock>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "<id><%u/></id>", id);
|
|
cprintf(cb, "</unlock></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (xpath_first(xt, "//ok"))
|
|
retval = 0;
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Check if database is locked
|
|
* @param[in] h Clicon handle
|
|
* @param[in] db Database
|
|
* @retval -1 Error
|
|
* @retval pid Process id if locked
|
|
*/
|
|
int
|
|
xmldb_islocked_rpc(clicon_handle h,
|
|
char *db)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt = NULL;
|
|
cxobj *x;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><islocked>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "</islocked></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (xpath_first(xt, "//unlocked"))
|
|
retval = 0;
|
|
else
|
|
if ((x=xpath_first(xt, "//locked")) != NULL)
|
|
retval = atoi(xml_body(x));
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Send exists request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval -1 Error
|
|
* @retval 0 No it does not exist
|
|
* @retval 1 Yes it exists
|
|
*/
|
|
int
|
|
xmldb_exists_rpc(clicon_handle h,
|
|
char *db)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
cxobj *xt = NULL;
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><exists>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "</exists></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
if (clicon_xml_parse_string(&rb, &xt) < 0)
|
|
goto done;
|
|
if (xpath_first(xt, "//ok"))
|
|
retval = 1;
|
|
else
|
|
retval = 0;
|
|
done:
|
|
if (xt)
|
|
xml_free(xt);
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*! Send delete request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval 0
|
|
*/
|
|
int
|
|
xmldb_delete_rpc(clicon_handle h,
|
|
char *db)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><delete>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "</delete></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
retval = 0;
|
|
done:
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|
|
|
|
/*! Send init request to backend daemon
|
|
* @param[in] h CLICON handle
|
|
* @param[in] db running|candidate
|
|
* @retval 0
|
|
*/
|
|
int
|
|
xmldb_init_rpc(clicon_handle h,
|
|
char *db)
|
|
{
|
|
int retval = -1;
|
|
cbuf *cb = NULL;
|
|
char retbuf[BUFSIZ];
|
|
char *rb = retbuf;
|
|
size_t retlen = sizeof(retbuf);
|
|
|
|
if ((cb = cbuf_new()) == NULL)
|
|
goto done;
|
|
cprintf(cb, "<rpc><init>");
|
|
cprintf(cb, "<target><%s/></target>", db);
|
|
cprintf(cb, "</init></rpc>]]>]]>");
|
|
if (xmldb_rpc(h,
|
|
cbuf_get(cb),
|
|
cbuf_len(cb)+1,
|
|
rb, &retlen) < 0)
|
|
goto done;
|
|
retval = 0;
|
|
done:
|
|
if (cb)
|
|
cbuf_free(cb);
|
|
return retval;
|
|
}
|