Ongoing: xmldb datastore plugin framework

This commit is contained in:
Olof hagsand 2017-04-08 20:39:04 +02:00
parent 05edace630
commit 4169bd8d30
18 changed files with 2588 additions and 1924 deletions

View file

@ -29,6 +29,8 @@
#
# ***** END LICENSE BLOCK *****
- Ongoiing: xmldb datastore plugin framework
- cli_copy_config added as generic cli command
- cli_show_config added as generic cli command
Replace all show_confv*() and show_conf*() with cli_show_config()

View file

@ -52,7 +52,7 @@ LIBS = @LIBS@
INCLUDES = -I. -I@srcdir@ @INCLUDES@
SHELL = /bin/sh
SUBDIRS = lib apps include etc
SUBDIRS = lib apps include etc datastore
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status docker

View file

@ -73,7 +73,7 @@
#include "backend_handle.h"
/* Command line options to be passed to getopt(3) */
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pty:"
#define BACKEND_OPTS "hD:f:d:Fzu:P:1IRCc:rg:pty:x:"
/*! Terminate. Cannot use h after this */
static int
@ -143,7 +143,8 @@ usage(char *argv0, clicon_handle h)
" -p \t\tPrint database yang specification\n"
" -t \t\tPrint alternate spec translation (eg if YANG print KEY, if KEY print YANG)\n"
" -g <group>\tClient membership required to this group (default: %s)\n"
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n",
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
"\t-x <plugin>\tXMLDB plugin\n",
argv0,
plgdir ? plgdir : "none",
confsock ? confsock : "none",
@ -314,6 +315,7 @@ main(int argc, char **argv)
char *pidfile;
char *sock;
int sockfamily;
char *xmldb_plugin;
/* In the startup, logs to stderr & syslog and debug flag set later */
@ -437,6 +439,10 @@ main(int argc, char **argv)
clicon_option_str_set(h, "CLICON_YANG_DIR", strdup(dir));
break;
}
case 'x' :{ /* xmldb plugin */
clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg);
break;
}
default:
usage(argv[0], h);
break;
@ -502,6 +508,13 @@ main(int argc, char **argv)
return -1;
}
if ((xmldb_plugin = clicon_xmldb_plugin(h)) == NULL){
clicon_log(LOG_ERR, "No xmldb plugin given (specify option CLICON_XMLDB_PLUGIN).\n");
goto done;
}
if (xmldb_plugin_load(xmldb_plugin) < 0)
goto done;
/* Parse db spec file */
if (yang_spec_main(h, stdout, printspec) < 0)
goto done;

4
configure vendored
View file

@ -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 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 datastore/Makefile datastore/keyvalue/Makefile doc/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -5030,6 +5030,8 @@ do
"docker/backend/Dockerfile") CONFIG_FILES="$CONFIG_FILES docker/backend/Dockerfile" ;;
"docker/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES docker/netconf/Makefile" ;;
"docker/netconf/Dockerfile") CONFIG_FILES="$CONFIG_FILES docker/netconf/Dockerfile" ;;
"datastore/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/Makefile" ;;
"datastore/keyvalue/Makefile") CONFIG_FILES="$CONFIG_FILES datastore/keyvalue/Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;

View file

@ -201,6 +201,8 @@ AC_OUTPUT(Makefile
docker/backend/Dockerfile
docker/netconf/Makefile
docker/netconf/Dockerfile
datastore/Makefile
datastore/keyvalue/Makefile
doc/Makefile
)

78
datastore/Makefile.in Normal file
View file

@ -0,0 +1,78 @@
#
# ***** 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 *****
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
SHELL = /bin/sh
SUBDIRS = keyvalue
.PHONY: all clean depend install $(SUBDIRS)
all: $(SUBDIRS)
depend:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
$(SUBDIRS):
(cd $@; $(MAKE) $(MFLAGS) all)
install-include:
for i in $(SUBDIRS); \
do (cd $$i ; $(MAKE) $(MFLAGS) $@); done;
install:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
uninstall:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
clean:
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
distclean: clean
rm -f Makefile *~ .depend
for i in $(SUBDIRS); \
do (cd $$i; $(MAKE) $(MFLAGS) $@); done
tags:
find $(srcdir) -name '*.[chyl]' -print | etags -

View file

@ -0,0 +1,100 @@
#
# ***** 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 *****
#
prefix = @prefix@
datarootdir = @datarootdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
dbdir = @prefix@/db
mandir = @mandir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
VPATH = @srcdir@
CC = @CC@
CFLAGS = @CFLAGS@ -rdynamic -fPIC
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
DATASTORE = keyvalue
CPPFLAGS = @CPPFLAGS@
INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$(top_srcdir)
PLUGIN = $(DATASTORE).so
SRC = clixon_keyvalue.c clixon_qdb.c
OBJS = $(SRC:.c=.o)
all: $(PLUGIN)
-include $(DESTDIR)$(datarootdir)/clixon/clixon.mk
#grideye_sysinfo.so.1: grideye_sysinfo.c
# $(CC) $(CFLAGS) -shared -o $@ -lc $^ -lm
$(PLUGIN): $(SRC)
$(CC) $(CPPFLAGS) $(INCLUDES) $(CFLAGS) -shared -o $@ -lc $^ $(LIBS)
clean:
rm -f $(PLUGIN) $(OBJS) *.core
distclean: clean
rm -f Makefile *~ .depend
.SUFFIXES:
.SUFFIXES: .c .o
.c.o: $(SRC)
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c $<
install: $(PLUGIN)
install -d $(DESTDIR)$(clixon_LIBDIR)/xmldb
install $(PLUGIN) $(DESTDIR)$(clixon_LIBDIR)/xmldb;
install-include:
uninstall:
rm -rf $(DESTDIR)$(clixon_LIBDIR)/xmldb/$(PLUGIN);
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) > .depend
#include .depend

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,56 @@
/*
*
***** 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 *****
Key-value store
*/
#ifndef _CLIXON_KEYVALUE_H
#define _CLIXON_KEYVALUE_H
/*
* Prototypes
*/
int kv_get(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen);
int kv_put(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt);
int kv_dump(FILE *f, char *dbfilename, char *rxkey);
int kv_copy(clicon_handle h, char *from, char *to);
int kv_lock(clicon_handle h, char *db, int pid);
int kv_unlock(clicon_handle h, char *db, int pid);
int kv_unlock_all(clicon_handle h, int pid);
int kv_islocked(clicon_handle h, char *db);
int kv_exists(clicon_handle h, char *db);
int kv_delete(clicon_handle h, char *db);
int kv_init(clicon_handle h, char *db);
#endif /* _CLIXON_KEYVALUE_H */

View file

@ -93,6 +93,7 @@ char *clicon_clispec_dir(clicon_handle h);
char *clicon_netconf_dir(clicon_handle h);
char *clicon_restconf_dir(clicon_handle h);
char *clicon_archive_dir(clicon_handle h);
char *clicon_xmldb_plugin(clicon_handle h);
int clicon_sock_family(clicon_handle h);
char *clicon_sock(clicon_handle h);
int clicon_sock_port(clicon_handle h);

View file

@ -30,18 +30,83 @@
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* XML support functions.
*/
#ifndef _CLIXON_XML_DB_H
#define _CLIXON_XML_DB_H
/* Version of clixon datastore plugin API. */
#define XMLDB_API_VERSION 1
/* Magic to ensure plugin sanity. */
#define XMLDB_API_MAGIC 0xf386f730
/* Name of plugin init function (must be called this) */
#define XMLDB_PLUGIN_INIT_FN "clixon_xmldb_plugin_init"
/* Type of plugin init function */
typedef void * (plugin_init_t)(int version);
/* Type of plugin exit function */
typedef int (plugin_exit_t)(void);
/* Type of xmldb get function */
typedef int (xmldb_get_t)(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen);
/* Type of xmldb put function */
typedef int (xmldb_put_t)(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt);
/* Type of xmldb dump function */
typedef int (xmldb_dump_t)(FILE *f, char *dbfilename, char *rxkey);
/* Type of xmldb copy function */
typedef int (xmldb_copy_t)(clicon_handle h, char *from, char *to);
/* Type of xmldb lock function */
typedef int (xmldb_lock_t)(clicon_handle h, char *db, int pid);
/* Type of xmldb unlock function */
typedef int (xmldb_unlock_t)(clicon_handle h, char *db, int pid);
/* Type of xmldb unlock_all function */
typedef int (xmldb_unlock_all_t)(clicon_handle h, int pid);
/* Type of xmldb islocked function */
typedef int (xmldb_islocked_t)(clicon_handle h, char *db);
/* Type of xmldb exists function */
typedef int (xmldb_exists_t)(clicon_handle h, char *db);
/* Type of xmldb delete function */
typedef int (xmldb_delete_t)(clicon_handle h, char *db);
/* Type of xmldb init function */
typedef int (xmldb_init_t)(clicon_handle h, char *db);
/* grideye agent plugin init struct for the api */
struct xmldb_api{
int xa_version;
int xa_magic;
plugin_init_t *xa_plugin_init_fn; /* XMLDB_PLUGIN_INIT_FN */
plugin_exit_t *xa_plugin_exit_fn;
xmldb_get_t *xa_get_fn;
xmldb_put_t *xa_put_fn;
xmldb_dump_t *xa_dump_fn;
xmldb_copy_t *xa_copy_fn;
xmldb_lock_t *xa_lock_fn;
xmldb_unlock_t *xa_unlock_fn;
xmldb_unlock_all_t *xa_unlock_all_fn;
xmldb_islocked_t *xa_islocked_fn;
xmldb_exists_t *xa_exists_fn;
xmldb_delete_t *xa_delete_fn;
xmldb_init_t *xa_init_fn;
};
/*
* Prototypes
*/
int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
int xmldb_plugin_load(char *filename);
int xmldb_get(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen);

View file

@ -61,5 +61,8 @@ int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2,
cxobj ***first, size_t *firstlen,
cxobj ***second, size_t *secondlen,
cxobj ***changed1, cxobj ***changed2, size_t *changedlen);
int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt);
int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk);
int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk);
#endif /* _CLIXON_XML_MAP_H_ */

View file

@ -61,15 +61,14 @@ CPPFLAGS = @CPPFLAGS@
INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$(top_srcdir)
SRC = clixon_sig.c clixon_qdb.c clixon_log.c clixon_err.c clixon_event.c \
SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
clixon_chunk.c clixon_proc.c \
clixon_string.c clixon_handle.c \
clixon_xml.c clixon_xml_map.c clixon_file.c \
clixon_json.c \
clixon_yang.c clixon_yang_type.c \
clixon_json.c clixon_yang.c clixon_yang_type.c \
clixon_hash.c clixon_options.c clixon_plugin.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 \
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \

View file

@ -237,6 +237,10 @@ clicon_option_sanity(clicon_hash_t *copt)
clicon_err(OE_UNIX, 0, "CLICON_ARCHIVE_DIR not defined in config file");
goto done;
}
if (!hash_lookup(copt, "CLICON_XMLDB_DIR")){
clicon_err(OE_UNIX, 0, "CLICON_XMLDB_DIR not defined in config file");
goto done;
}
if (!hash_lookup(copt, "CLICON_SOCK")){
clicon_err(OE_UNIX, 0, "CLICON_SOCK not defined in config file");
goto done;
@ -453,6 +457,12 @@ clicon_archive_dir(clicon_handle h)
return clicon_option_str(h, "CLICON_ARCHIVE_DIR");
}
char *
clicon_xmldb_plugin(clicon_handle h)
{
return clicon_option_str(h, "CLICON_XMLDB_PLUGIN");
}
/* get family of backend socket: AF_UNIX, AF_INET or AF_INET6 */
int
clicon_sock_family(clicon_handle h)

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,7 @@
#include <syslog.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <curl/curl.h>
/* cligen */
#include <cligen/cligen.h>
@ -89,9 +90,6 @@
/* Something to do with reverse engineering of junos syntax? */
#undef SPECIAL_TREATMENT_OF_NAME
/*
* A node is a leaf if it contains a body.
*/
@ -791,3 +789,288 @@ xml_diff(yang_spec *yspec,
done:
return retval;
}
/*! Construct an xml key format from yang statement using wildcards for keys
* Recursively construct it to the top.
* Example:
* yang: container a -> list b -> key c -> leaf d
* xpath: /a/b/%s/d
* @param[in] ys Yang statement
* @param[in] inclkey If inclkey then include key leaf (eg last leaf d in ex)
* @param[out] cbuf keyfmt
*/
static int
yang2xmlkeyfmt_1(yang_stmt *ys,
int inclkey,
cbuf *cb)
{
yang_node *yp; /* parent */
yang_stmt *ykey;
int i;
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
yp = ys->ys_parent;
if (yp != NULL &&
yp->yn_keyword != Y_MODULE &&
yp->yn_keyword != Y_SUBMODULE){
if (yang2xmlkeyfmt_1((yang_stmt *)yp, 1, cb) < 0)
goto done;
}
if (inclkey){
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
cprintf(cb, "/%s", ys->ys_argument);
}
else{
if (ys->ys_keyword == Y_LEAF && yp && yp->yn_keyword == Y_LIST){
if (yang_key_match(yp, ys->ys_argument) == 0)
cprintf(cb, "/%s", ys->ys_argument); /* Not if leaf and key */
}
else
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
cprintf(cb, "/%s", ys->ys_argument);
}
switch (ys->ys_keyword){
case Y_LIST:
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
__FUNCTION__, ys->ys_argument);
goto done;
}
/* The value is a list of keys: <key>[ <key>]* */
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
goto done;
if (cvec_len(cvk))
cprintf(cb, "=");
/* Iterate over individual keys */
for (i=0; i<cvec_len(cvk); i++){
if (i)
cprintf(cb, ",");
cprintf(cb, "%%s");
}
break;
case Y_LEAF_LIST:
cprintf(cb, "=%%s");
break;
default:
break;
} /* switch */
retval = 0;
done:
if (cvk)
cvec_free(cvk);
return retval;
}
/*! Construct an xml key format from yang statement using wildcards for keys
* Recursively construct it to the top.
* Example:
* yang: container a -> list b -> key c -> leaf d
* xpath: /a/b=%s/d
* @param[in] ys Yang statement
* @param[in] inclkey If !inclkey then dont include key leaf
* @param[out] xkfmt XML key format. Needs to be freed after use.
*/
int
yang2xmlkeyfmt(yang_stmt *ys,
int inclkey,
char **xkfmt)
{
int retval = -1;
cbuf *cb = NULL;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
if (yang2xmlkeyfmt_1(ys, inclkey, cb) < 0)
goto done;
if ((*xkfmt = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! 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()
* Example:
* xmlkeyfmt: /aaa/%s
* cvv: key=17
* xmlkey: /aaa/17
* @param[in] xkfmt XML key format, eg /aaa/%s
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
* @param[out] xk XML key, eg /aaa/17. Free after use
* @note first and last elements of cvv are not used,..
* @see cli_dbxml where this function is called
*/
int
xmlkeyfmt2key(char *xkfmt,
cvec *cvv,
char **xk)
{
int retval = -1;
char c;
int esc=0;
cbuf *cb = NULL;
int i;
int j;
char *str;
char *strenc=NULL;
/* Sanity check */
#if 1
j = 0; /* Count % */
for (i=0; i<strlen(xkfmt); i++)
if (xkfmt[i] == '%')
j++;
if (j+2 < cvec_len(cvv)) {
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s",
xkfmt,
j,
cvec_len(cvv),
cv_string_get(cvec_i(cvv, 0)));
goto done;
}
#endif
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
j = 1; /* j==0 is cli string */
for (i=0; i<strlen(xkfmt); i++){
c = xkfmt[i];
if (esc){
esc = 0;
if (c!='s')
continue;
if ((str = cv2str_dup(cvec_i(cvv, j++))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
if ((strenc = curl_easy_escape(NULL, str, 0)) == NULL){
clicon_err(OE_UNIX, errno, "curl_easy_escape");
goto done;
}
cprintf(cb, "%s", strenc);
curl_free(strenc);
free(str);
}
else
if (c == '%')
esc++;
else
cprintf(cb, "%c", c);
}
if ((*xk = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}
/*! Transform an xml key format and a vector of values to an XML path
* Used to input xmldb_get() or xmldb_get_vec
* Add .* in last %s position.
* Example:
* xmlkeyfmt: /interface/%s/address/%s OLDXXX
* xmlkeyfmt: /interface=%s/address=%s
* cvv: name=eth0
* xmlkey: /interface/[name=eth0]/address
* Example2:
* xmlkeyfmt: /ip/me/%s (if key)
* cvv: -
* xmlkey: /ipv4/me/a
* @param[in] xkfmt XML key format
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
* @param[out] xk XPATH
*/
int
xmlkeyfmt2xpath(char *xkfmt,
cvec *cvv,
char **xk)
{
int retval = -1;
char c;
int esc=0;
cbuf *cb = NULL;
int i;
int j;
char *str;
cg_var *cv;
int skip = 0;
/* Sanity check: count '%' */
#if 1
j = 0; /* Count % */
for (i=0; i<strlen(xkfmt); i++)
if (xkfmt[i] == '%')
j++;
if (j < cvec_len(cvv)-1) {
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s",
xkfmt,
j,
cvec_len(cvv),
cv_string_get(cvec_i(cvv, 0)));
// goto done;
}
#endif
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new");
goto done;
}
j = 1; /* j==0 is cli string */
for (i=0; i<strlen(xkfmt); i++){
c = xkfmt[i];
if (esc){
esc = 0;
if (c!='s')
continue;
if (j == cvec_len(cvv)) /* last element */
//skip++;
;
else{
cv = cvec_i(cvv, j++);
if ((str = cv2str_dup(cv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
cprintf(cb, "[%s=%s]", cv_name_get(cv), str);
free(str);
}
}
else /* regular char */
if (c == '%')
esc++;
else{
if (skip)
skip=0;
else
if ((c == '=' || c == ',') && xkfmt[i+1]=='%')
; /* skip */
else
cprintf(cb, "%c", c);
}
}
if ((*xk = strdup4(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
}