/* * 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 . * XML database * TODO: xmldb_del: or dbxml_put_xkey delete */ #ifdef HAVE_CONFIG_H #include "clixon_config.h" /* generated by config & autoconf */ #endif #include #include #include #include #include #include #include #include #include #include #include /* cligen */ #include /* 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, ""); cprintf(cb, "<%s/>", 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, "%s", opstr); } cprintf(cb, ""); if (clicon_xml2cbuf(cb, xt, 0, 1) < 0) goto done; cprintf(cb, ""); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", 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, "%s", opstr); } cprintf(cb, "%s", xk); cprintf(cb, "%s", val); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); if (xpath) cprintf(cb, "%s", xpath); if (vector) cprintf(cb, ""); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", from); cprintf(cb, "<%s/>", to); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "<%u/>", id); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "<%u/>", id); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "]]>]]>"); 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, ""); cprintf(cb, "<%s/>", db); cprintf(cb, "]]>]]>"); 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; }