for (eg cli_commitv). See clixon_cli_api.h for new names. Use restconf format for internal xmldb keys. Eg /a/b=3,4 Changed example to use multiple cli callbacks
576 lines
13 KiB
C
576 lines
13 KiB
C
/*
|
|
*
|
|
***** 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 *****
|
|
|
|
* 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,
|
|
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);
|
|
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 (xvec){
|
|
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;
|
|
}
|