getting legacy grideye application to work on clixon
This commit is contained in:
parent
6169ea6bed
commit
c1c1670a74
22 changed files with 952 additions and 805 deletions
|
|
@ -164,15 +164,17 @@ candidate_commit(clicon_handle h,
|
||||||
xn = td->td_dvec[i];
|
xn = td->td_dvec[i];
|
||||||
xml_flag_set(xn, XML_FLAG_DEL);
|
xml_flag_set(xn, XML_FLAG_DEL);
|
||||||
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_DEL);
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_DEL);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
}
|
}
|
||||||
for (i=0; i<td->td_alen; i++){ /* Also down */
|
for (i=0; i<td->td_alen; i++){ /* Also down */
|
||||||
xn = td->td_avec[i];
|
xn = td->td_avec[i];
|
||||||
xml_flag_set(xn, XML_FLAG_ADD);
|
xml_flag_set(xn, XML_FLAG_ADD);
|
||||||
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD);
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
}
|
}
|
||||||
for (i=0; i<td->td_clen; i++){ /* Also up */
|
for (i=0; i<td->td_clen; i++){ /* Also up */
|
||||||
xn = td->td_scvec[i];
|
xn = td->td_scvec[i];
|
||||||
xml_flag(xn, XML_FLAG_CHANGE);
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
xn = td->td_tcvec[i];
|
xn = td->td_tcvec[i];
|
||||||
xml_flag_set(xn, XML_FLAG_CHANGE);
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,10 @@ backend_handle_exit(clicon_handle h)
|
||||||
* @see also backend_notify_xml()
|
* @see also backend_notify_xml()
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
backend_notify(clicon_handle h, char *stream, int level, char *event)
|
backend_notify(clicon_handle h,
|
||||||
|
char *stream,
|
||||||
|
int level,
|
||||||
|
char *event)
|
||||||
{
|
{
|
||||||
struct client_entry *ce;
|
struct client_entry *ce;
|
||||||
struct client_subscription *su;
|
struct client_subscription *su;
|
||||||
|
|
@ -144,7 +147,7 @@ backend_notify(clicon_handle h, char *stream, int level, char *event)
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
|
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
|
||||||
* @param[in] level Event level (not used yet)
|
* @param[in] level Event level (not used yet)
|
||||||
* @param[in] event Actual message as xml tree
|
* @param[in] x Actual message as xml tree
|
||||||
*
|
*
|
||||||
* Stream is a string used to qualify the event-stream. Distribute the
|
* Stream is a string used to qualify the event-stream. Distribute the
|
||||||
* event to all clients registered to this backend.
|
* event to all clients registered to this backend.
|
||||||
|
|
@ -153,7 +156,10 @@ backend_notify(clicon_handle h, char *stream, int level, char *event)
|
||||||
* @see also backend_notify()
|
* @see also backend_notify()
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
backend_notify_xml(clicon_handle h, char *stream, int level, cxobj *x)
|
backend_notify_xml(clicon_handle h,
|
||||||
|
char *stream,
|
||||||
|
int level,
|
||||||
|
cxobj *x)
|
||||||
{
|
{
|
||||||
struct client_entry *ce;
|
struct client_entry *ce;
|
||||||
struct client_subscription *su;
|
struct client_subscription *su;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ transaction_id(transaction_data td)
|
||||||
return ((transaction_data_t *)td)->td_id;
|
return ((transaction_data_t *)td)->td_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get plugin/application specific callbackargument
|
/*! Get plugin/application specific callback argument
|
||||||
* @param[in] td transaction_data
|
* @param[in] td transaction_data
|
||||||
* @retval arg callback argument
|
* @retval arg callback argument
|
||||||
* @note NYI
|
* @note NYI
|
||||||
|
|
@ -73,7 +73,7 @@ transaction_arg(transaction_data td)
|
||||||
return ((transaction_data_t *)td)->td_arg;
|
return ((transaction_data_t *)td)->td_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get Source database xml tree
|
/*! Get source database xml tree
|
||||||
* @param[in] td transaction_data
|
* @param[in] td transaction_data
|
||||||
* @retval src source xml tree containing original state
|
* @retval src source xml tree containing original state
|
||||||
*/
|
*/
|
||||||
|
|
@ -160,7 +160,7 @@ transaction_scvec(transaction_data td)
|
||||||
cxobj **
|
cxobj **
|
||||||
transaction_tcvec(transaction_data td)
|
transaction_tcvec(transaction_data td)
|
||||||
{
|
{
|
||||||
return ((transaction_data_t *)td)->td_dvec;
|
return ((transaction_data_t *)td)->td_tcvec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Get length of changed xml vector
|
/*! Get length of changed xml vector
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
|
||||||
MYLIB = $(MYLIBLINK).$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
MYLIB = $(MYLIBLINK).$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
||||||
MYLIBSO = $(MYLIBLINK).$(CLIXON_MAJOR)
|
MYLIBSO = $(MYLIBLINK).$(CLIXON_MAJOR)
|
||||||
|
|
||||||
LIBSRC = cli_plugin.c cli_common.c cli_handle.c cli_generate.c
|
LIBSRC = cli_plugin.c cli_common.c cli_show.c cli_handle.c cli_generate.c
|
||||||
LIBOBJS = $(LIBSRC:.c=.o)
|
LIBOBJS = $(LIBSRC:.c=.o)
|
||||||
|
|
||||||
all: $(MYLIB) $(APPL) test
|
all: $(MYLIB) $(APPL) test
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,6 @@
|
||||||
|
|
||||||
#include "cli_common.h"
|
#include "cli_common.h"
|
||||||
|
|
||||||
static int xml2csv(FILE *f, cxobj *x, cvec *cvv);
|
|
||||||
//static int xml2csv_raw(FILE *f, cxobj *x);
|
|
||||||
|
|
||||||
/*! Initialize candidate database
|
/*! Initialize candidate database
|
||||||
* We have implemented these:
|
* We have implemented these:
|
||||||
* shared - all users share a common candidate db
|
* shared - all users share a common candidate db
|
||||||
|
|
@ -334,229 +331,6 @@ cli_validate(clicon_handle h, cvec *vars, cg_var *arg)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Completion callback primarily intended for automatically generated data model
|
|
||||||
*
|
|
||||||
* Returns an expand-type list of commands as used by cligen 'expand'
|
|
||||||
* functionality.
|
|
||||||
* arg is a string: "<dbname> <keypattern> <variable>".
|
|
||||||
* <dbname> is either running or candidate
|
|
||||||
* <pattern> matches a set of database keys following clicon_dbspec.
|
|
||||||
* Eg a[].b[] $!x $!y
|
|
||||||
* the last being the variable to expand for.
|
|
||||||
* Example:
|
|
||||||
* dbspec is a[].b[] $!x $!y
|
|
||||||
* clispec is a <x> b (<y>|<y expand_dbvar_auto()>;
|
|
||||||
* db contains entries:
|
|
||||||
* a.0 $x=5
|
|
||||||
* a.1 $x=10
|
|
||||||
* a.0.b.0 $x=5 $y=12
|
|
||||||
* a.0.b.1 $x=5 $y=20
|
|
||||||
* a.1.b.0 $x=10 $y=99
|
|
||||||
*
|
|
||||||
* The user types a 5 b <?> which produces the following output:
|
|
||||||
* <int>
|
|
||||||
* 12
|
|
||||||
* 20
|
|
||||||
*
|
|
||||||
* Assume callback given in a cligen spec: a <x:int expand_dbvar_auto("arg")
|
|
||||||
* @param[in] h clicon handle
|
|
||||||
* @param[in] name Name of this function (eg "expand_dbvar-auto")
|
|
||||||
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
|
||||||
* @param[in] arg Argument given at the callback "<db> <xmlkeyfmt>"
|
|
||||||
* @param[out] len len of return commands & helptxt
|
|
||||||
* @param[out] commands vector of function pointers to callback functions
|
|
||||||
* @param[out] helptxt vector of pointers to helptexts
|
|
||||||
* @see cli_expand_var_generate This is where arg is generated
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
expand_dbvar_dbxml(void *h,
|
|
||||||
char *name,
|
|
||||||
cvec *cvv,
|
|
||||||
cg_var *arg,
|
|
||||||
int *nr,
|
|
||||||
char ***commands,
|
|
||||||
char ***helptexts)
|
|
||||||
{
|
|
||||||
int nvec;
|
|
||||||
char **vec = NULL;
|
|
||||||
int retval = -1;
|
|
||||||
char *xkfmt;
|
|
||||||
char *str;
|
|
||||||
char *dbstr;
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
char *xk = NULL;
|
|
||||||
cxobj **xvec = NULL;
|
|
||||||
size_t xlen = 0;
|
|
||||||
cxobj *x;
|
|
||||||
char *bodystr;
|
|
||||||
int i;
|
|
||||||
int i0;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* In the example, str = "candidate a[].b[] $!x $!y" */
|
|
||||||
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
dbstr = vec[0];
|
|
||||||
if (strcmp(dbstr, "running") != 0 &&
|
|
||||||
strcmp(dbstr, "candidate") != 0){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
xkfmt = vec[1];
|
|
||||||
/* xkfmt = /interface/%s/address/%s
|
|
||||||
--> ^/interface/eth0/address/.*$
|
|
||||||
--> /interface/[name=eth0]/address
|
|
||||||
*/
|
|
||||||
if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0)
|
|
||||||
goto done;
|
|
||||||
if (xmldb_get(h, dbstr, xk, 1, &xt, &xvec, &xlen) < 0)
|
|
||||||
goto done;
|
|
||||||
i0 = *nr;
|
|
||||||
*nr += xlen;
|
|
||||||
if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) {
|
|
||||||
clicon_err(OE_UNIX, errno, "realloc: %s", strerror (errno));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
for (i = 0; i < xlen; i++) {
|
|
||||||
x = xvec[i];
|
|
||||||
if ((bodystr = xml_body(x)) == NULL){
|
|
||||||
clicon_err(OE_CFG, 0, "No xml body");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
(*commands)[i0+i] = strdup(bodystr);
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
if (xvec)
|
|
||||||
free(xvec);
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
if (xk)
|
|
||||||
free(xk);
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* expand_dir
|
|
||||||
* List files in a directory
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail)
|
|
||||||
{
|
|
||||||
DIR *dirp;
|
|
||||||
struct dirent *dp;
|
|
||||||
struct stat st;
|
|
||||||
char *str;
|
|
||||||
char *cmd;
|
|
||||||
int len;
|
|
||||||
int retval = -1;
|
|
||||||
struct passwd *pw;
|
|
||||||
char filename[MAXPATHLEN];
|
|
||||||
|
|
||||||
if ((dirp = opendir(dir)) == 0){
|
|
||||||
fprintf(stderr, "expand_dir: opendir(%s) %s\n",
|
|
||||||
dir, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*nr = 0;
|
|
||||||
while ((dp = readdir(dirp)) != NULL) {
|
|
||||||
if (
|
|
||||||
#if 0
|
|
||||||
strcmp(dp->d_name, ".") != 0 &&
|
|
||||||
strcmp(dp->d_name, "..") != 0
|
|
||||||
#else
|
|
||||||
dp->d_name[0] != '.'
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp->d_name);
|
|
||||||
if (lstat(filename, &st) == 0){
|
|
||||||
if ((st.st_mode & flags) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
#if EXPAND_RECURSIVE
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
int nrsav = *nr;
|
|
||||||
if(expand_dir(filename, nr, commands, detail) < 0)
|
|
||||||
goto quit;
|
|
||||||
while(nrsav < *nr) {
|
|
||||||
len = strlen(dp->d_name) + strlen((*commands)[nrsav]) + 2;
|
|
||||||
if((str = malloc(len)) == NULL) {
|
|
||||||
fprintf(stderr, "expand_dir: malloc: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
snprintf(str, len-1, "%s/%s",
|
|
||||||
dp->d_name, (*commands)[nrsav]);
|
|
||||||
free((*commands)[nrsav]);
|
|
||||||
(*commands)[nrsav] = str;
|
|
||||||
|
|
||||||
nrsav++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if ((cmd = strdup(dp->d_name)) == NULL) {
|
|
||||||
fprintf(stderr, "expand_dir: strdup: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
if (0 &&detail){
|
|
||||||
if ((pw = getpwuid(st.st_uid)) == NULL){
|
|
||||||
fprintf(stderr, "expand_dir: getpwuid(%d): %s\n",
|
|
||||||
st.st_uid, strerror(errno));
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
len = strlen(cmd) +
|
|
||||||
strlen(pw->pw_name) +
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
strlen(ctime(&st.st_mtimespec.tv_sec)) +
|
|
||||||
#else
|
|
||||||
strlen(ctime(&st.st_mtim.tv_sec)) +
|
|
||||||
#endif
|
|
||||||
|
|
||||||
strlen("{ by }") + 1 /* \0 */;
|
|
||||||
if ((str=realloc(cmd, strlen(cmd)+len)) == NULL) {
|
|
||||||
fprintf(stderr, "expand_dir: malloc: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
snprintf(str + strlen(dp->d_name),
|
|
||||||
len - strlen(dp->d_name),
|
|
||||||
"{%s by %s}",
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
ctime(&st.st_mtimespec.tv_sec),
|
|
||||||
#else
|
|
||||||
ctime(&st.st_mtim.tv_sec),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pw->pw_name
|
|
||||||
);
|
|
||||||
cmd = str;
|
|
||||||
}
|
|
||||||
if (((*commands) =
|
|
||||||
realloc(*commands, ((*nr)+1)*sizeof(char**))) == NULL){
|
|
||||||
perror("expand_dir: realloc");
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
(*commands)[(*nr)] = cmd;
|
|
||||||
(*nr)++;
|
|
||||||
if (*nr >= 128) /* Limit number of options */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
quit:
|
|
||||||
closedir(dirp);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Compare two dbs using XML. Write to file and run diff
|
/*! Compare two dbs using XML. Write to file and run diff
|
||||||
*/
|
*/
|
||||||
|
|
@ -949,250 +723,6 @@ discard_changes(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
return clicon_rpc_copy(h, "running", "candidate");
|
return clicon_rpc_copy(h, "running", "candidate");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Generic function for showing configurations.
|
|
||||||
* the callback differs.
|
|
||||||
* @param[in] h CLICON handle
|
|
||||||
* @param[in] cvv Vector of variables (not needed)
|
|
||||||
* @param[in] arg A string: <dbname> <xpath>
|
|
||||||
* <dbname> is either running or candidate
|
|
||||||
* <xpath> xpath expression as in nertconf get-config
|
|
||||||
* @param fn
|
|
||||||
* @param fnarg
|
|
||||||
* @code
|
|
||||||
* # cligen spec
|
|
||||||
* show config id <n:string>, show_conf_as("running interfaces/interface[name=eth*]");
|
|
||||||
* @endcode
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
show_conf_xmldb_as(clicon_handle h,
|
|
||||||
cvec *cvv,
|
|
||||||
cg_var *arg,
|
|
||||||
cxobj **xt) /* top xml */
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
char *db;
|
|
||||||
char **vec = NULL;
|
|
||||||
int nvec;
|
|
||||||
char *str;
|
|
||||||
char *xpath;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (nvec != 2){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "format error \"%s\" - expected <dbname> <xpath>", str);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Dont get attr here, take it from arg instead */
|
|
||||||
db = vec[0];
|
|
||||||
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) {
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", db);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
xpath = vec[1];
|
|
||||||
if (xmldb_get(h, db, xpath, 0, xt, NULL, NULL) < 0)
|
|
||||||
goto done;
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Show a configuration database on stdout using XML format
|
|
||||||
* Utility function used by cligen spec file
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
show_conf_as_xml1(clicon_handle h, cvec *cvv, cg_var *arg, int netconf)
|
|
||||||
{
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj *xc;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (show_conf_xmldb_as(h, cvv, arg, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
if (netconf) /* netconf prefix */
|
|
||||||
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
|
||||||
xc = NULL; /* Dont print xt itself */
|
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
|
||||||
clicon_xml2file(stdout, xc, netconf?2:0, 1);
|
|
||||||
if (netconf) /* netconf postfix */
|
|
||||||
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Show configuration as prettyprinted xml
|
|
||||||
* Utility function used by cligen spec file
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
show_conf_as_xml(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
return show_conf_as_xml1(h, cvv, arg, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Show configuration as prettyprinted xml with netconf hdr/tail
|
|
||||||
* Utility function used by cligen spec file
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
show_conf_as_netconf(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
return show_conf_as_xml1(h, cvv, arg, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Show configuration as JSON
|
|
||||||
* Utility function used by cligen spec file
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
show_conf_as_json(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj *xc;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (show_conf_xmldb_as(h, cvv, arg, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
xc = NULL; /* Dont print xt itself */
|
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
|
||||||
xml2json(stdout, xc, 1);
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
char *str;
|
|
||||||
char *xpath;
|
|
||||||
cg_var *cv;
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj **xv = NULL;
|
|
||||||
size_t xlen;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Dont get attr here, take it from arg instead */
|
|
||||||
if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){
|
|
||||||
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cv = cvec_find_var(cvv, "xpath");
|
|
||||||
xpath = cv_string_get(cv);
|
|
||||||
if (xmldb_get(h, str, xpath, 1, &xt, &xv, &xlen) < 0)
|
|
||||||
goto done;
|
|
||||||
for (i=0; i<xlen; i++)
|
|
||||||
clicon_xml2file(stdout, xv[i], 0, 1);
|
|
||||||
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xv)
|
|
||||||
free(xv);
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*! Show configuration as text
|
|
||||||
* Utility function used by cligen spec file
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
show_conf_as_text1(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj *xc;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if (show_conf_xmldb_as(h, cvv, arg, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
xc = NULL; /* Dont print xt itself */
|
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
|
||||||
xml2txt(stdout, xc, 0); /* tree-formed text */
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Show configuration as commands, ie not tree format but as one-line commands
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
show_conf_as_command(clicon_handle h, cvec *cvv, cg_var *arg, char *prepend)
|
|
||||||
{
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj *xc;
|
|
||||||
enum genmodel_type gt;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
if ((xt = xml_new("tmp", NULL)) == NULL)
|
|
||||||
goto done;
|
|
||||||
if (show_conf_xmldb_as(h, cvv, arg, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
xc = NULL; /* Dont print xt itself */
|
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
|
|
||||||
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
|
||||||
goto done;
|
|
||||||
xml2cli(stdout, xc, prepend, gt, __FUNCTION__); /* cli syntax */
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
show_conf_as_text(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
return show_conf_as_text1(h, cvv, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
show_conf_as_cli(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
return show_conf_as_command(h, cvv, arg, NULL); /* XXX: how to set prepend? */
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
show_yang(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
yang_node *yn;
|
|
||||||
char *str = NULL;
|
|
||||||
yang_spec *yspec;
|
|
||||||
|
|
||||||
yspec = clicon_dbspec_yang(h);
|
|
||||||
if (arg != NULL){
|
|
||||||
str = cv_string_get(arg);
|
|
||||||
yn = (yang_node*)yang_find((yang_node*)yspec, 0, str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
yn = (yang_node*)yspec;
|
|
||||||
yang_print(stdout, yn, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These are strings that can be used as 3rd argument to cli_setlog */
|
/* These are strings that can be used as 3rd argument to cli_setlog */
|
||||||
static const char *SHOWAS_TXT = "txt";
|
static const char *SHOWAS_TXT = "txt";
|
||||||
static const char *SHOWAS_XML = "xml";
|
static const char *SHOWAS_XML = "xml";
|
||||||
|
|
@ -1292,7 +822,9 @@ cli_notification_cb(int s, void *arg)
|
||||||
* XXX: format is a memory leak
|
* XXX: format is a memory leak
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_notify(clicon_handle h, cvec *cvv, cg_var *arg)
|
cli_notify(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
{
|
{
|
||||||
char *stream = NULL;
|
char *stream = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -1395,114 +927,3 @@ cli_notification_register(clicon_handle h,
|
||||||
unchunk_group(__FUNCTION__);
|
unchunk_group(__FUNCTION__);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef notused
|
|
||||||
/*! XML to CSV raw variant
|
|
||||||
* @see xml2csv
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml2csv_raw(FILE *f, cxobj *x)
|
|
||||||
{
|
|
||||||
cxobj *xc;
|
|
||||||
cxobj *xb;
|
|
||||||
int retval = -1;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
xc = NULL;
|
|
||||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
|
||||||
if (xml_child_nr(xc)){
|
|
||||||
xb = xml_child_i(xc, 0);
|
|
||||||
if (xml_type(xb) == CX_BODY){
|
|
||||||
if (i++)
|
|
||||||
fprintf(f, ";");
|
|
||||||
fprintf(f, "%s", xml_value(xb));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(f, "\n");
|
|
||||||
retval = 0;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! Translate XML -> CSV commands
|
|
||||||
* Can only be made in a 'flat tree', ie on the form:
|
|
||||||
* <X><A>B</A></X> -->
|
|
||||||
* Type, A
|
|
||||||
* X, B
|
|
||||||
* @param[in] f Output file
|
|
||||||
* @param[in] x XML tree
|
|
||||||
* @param[in] cvv A vector of field names present in XML
|
|
||||||
* This means that only fields in x that are listed in cvv will be printed.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
xml2csv(FILE *f, cxobj *x, cvec *cvv)
|
|
||||||
{
|
|
||||||
cxobj *xe, *xb;
|
|
||||||
int retval = -1;
|
|
||||||
cg_var *vs;
|
|
||||||
|
|
||||||
fprintf(f, "%s", xml_name(x));
|
|
||||||
xe = NULL;
|
|
||||||
|
|
||||||
vs = NULL;
|
|
||||||
while ((vs = cvec_each(cvv, vs))) {
|
|
||||||
if ((xe = xml_find(x, cv_name_get(vs))) == NULL){
|
|
||||||
fprintf(f, ";");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (xml_child_nr(xe)){
|
|
||||||
xb = xml_child_i(xe, 0);
|
|
||||||
fprintf(f, ";%s", xml_value(xb));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(f, "\n");
|
|
||||||
retval = 0;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
show_conf_as_csv1(clicon_handle h, cvec *cvv0, cg_var *arg)
|
|
||||||
{
|
|
||||||
cxobj *xt = NULL;
|
|
||||||
cxobj *xc;
|
|
||||||
int retval = -1;
|
|
||||||
cvec *cvv=NULL;
|
|
||||||
char *str;
|
|
||||||
|
|
||||||
if (show_conf_xmldb_as(h, cvv0, arg, &xt) < 0)
|
|
||||||
goto done;
|
|
||||||
xc = NULL; /* Dont print xt itself */
|
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
|
|
||||||
if ((str = chunk_sprintf(__FUNCTION__, "%s[]", xml_name(xc))) == NULL)
|
|
||||||
goto done;
|
|
||||||
#ifdef NOTYET /* yang-spec? */
|
|
||||||
if (ds==NULL && (ds = key2spec_key(dbspec, str)) != NULL){
|
|
||||||
cg_var *vs;
|
|
||||||
fprintf(stdout, "Type");
|
|
||||||
cvv = db_spec2cvec(ds);
|
|
||||||
vs = NULL;
|
|
||||||
while ((vs = cvec_each(cvv, vs)))
|
|
||||||
fprintf(stdout, ";%s", cv_name_get(vs));
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
} /* Now values just need to follow,... */
|
|
||||||
#endif /* yang-spec? */
|
|
||||||
if (cvv== NULL)
|
|
||||||
goto done;
|
|
||||||
xml2csv(stdout, xc, cvv); /* csv syntax */
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (xt)
|
|
||||||
xml_free(xt);
|
|
||||||
unchunk_group(__FUNCTION__);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
show_conf_as_csv(clicon_handle h, cvec *cvv, cg_var *arg)
|
|
||||||
{
|
|
||||||
return show_conf_as_csv1(h, cvv, arg);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
#define GENERATE_CALLBACK "cli_set"
|
#define GENERATE_CALLBACK "cli_set"
|
||||||
|
|
||||||
/* variable expand function */
|
/* variable expand function */
|
||||||
#define GENERATE_EXPAND_XMLDB "expand_dbvar_dbxml"
|
#define GENERATE_EXPAND_XMLDB "expand_dbvar"
|
||||||
|
|
||||||
/*=====================================================================
|
/*=====================================================================
|
||||||
* YANG generate CLI
|
* YANG generate CLI
|
||||||
|
|
@ -163,7 +163,7 @@ cvtype_max2str_dup(enum cv_type type)
|
||||||
* @param[in] ys yang_stmt of the node at hand
|
* @param[in] ys yang_stmt of the node at hand
|
||||||
* @param[in] cvtype Type of the cligen variable
|
* @param[in] cvtype Type of the cligen variable
|
||||||
* @param[in] cb0 The string where the result format string is inserted.
|
* @param[in] cb0 The string where the result format string is inserted.
|
||||||
* @see expand_dbvar_dbxml This is where the expand string is used
|
* @see expand_dbvar This is where the expand string is used
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cli_expand_var_generate(clicon_handle h,
|
cli_expand_var_generate(clicon_handle h,
|
||||||
|
|
|
||||||
692
apps/cli/cli_show.c
Normal file
692
apps/cli/cli_show.c
Normal file
|
|
@ -0,0 +1,692 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
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/>.
|
||||||
|
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#ifdef HAVE_CRYPT_H
|
||||||
|
#include <crypt.h>
|
||||||
|
#endif
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clicon */
|
||||||
|
#include <clixon/clixon.h>
|
||||||
|
|
||||||
|
/* Exported functions in this file are in clixon_cli_api.h */
|
||||||
|
#include "clixon_cli_api.h"
|
||||||
|
|
||||||
|
static int xml2csv(FILE *f, cxobj *x, cvec *cvv);
|
||||||
|
//static int xml2csv_raw(FILE *f, cxobj *x);
|
||||||
|
|
||||||
|
/*! Completion callback intended for automatically generated data model
|
||||||
|
*
|
||||||
|
* Returns an expand-type list of commands as used by cligen 'expand'
|
||||||
|
* functionality.
|
||||||
|
*
|
||||||
|
* Assume callback given in a cligen spec: a <x:int expand_dbvar_auto("arg")
|
||||||
|
* @param[in] h clicon handle
|
||||||
|
* @param[in] name Name of this function (eg "expand_dbvar-auto")
|
||||||
|
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
||||||
|
* @param[in] arg Argument given at the callback "<db> <xmlkeyfmt>"
|
||||||
|
* @param[out] len len of return commands & helptxt
|
||||||
|
* @param[out] commands vector of function pointers to callback functions
|
||||||
|
* @param[out] helptxt vector of pointers to helptexts
|
||||||
|
* @see cli_expand_var_generate This is where arg is generated
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
expand_dbvar(void *h,
|
||||||
|
char *name,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg,
|
||||||
|
int *nr,
|
||||||
|
char ***commands,
|
||||||
|
char ***helptexts)
|
||||||
|
{
|
||||||
|
int nvec;
|
||||||
|
char **vec = NULL;
|
||||||
|
int retval = -1;
|
||||||
|
char *xkfmt;
|
||||||
|
char *str;
|
||||||
|
char *dbstr;
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
char *xk = NULL;
|
||||||
|
cxobj **xvec = NULL;
|
||||||
|
size_t xlen = 0;
|
||||||
|
cxobj *x;
|
||||||
|
char *bodystr;
|
||||||
|
int i;
|
||||||
|
int i0;
|
||||||
|
|
||||||
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* In the example, str = "candidate a[].b[] $!x $!y" */
|
||||||
|
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
dbstr = vec[0];
|
||||||
|
if (strcmp(dbstr, "running") != 0 &&
|
||||||
|
strcmp(dbstr, "candidate") != 0){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", dbstr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xkfmt = vec[1];
|
||||||
|
/* xkfmt = /interface/%s/address/%s
|
||||||
|
--> ^/interface/eth0/address/.*$
|
||||||
|
--> /interface/[name=eth0]/address
|
||||||
|
*/
|
||||||
|
if (xmlkeyfmt2xpath(xkfmt, cvv, &xk) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xmldb_get(h, dbstr, xk, 1, &xt, &xvec, &xlen) < 0)
|
||||||
|
goto done;
|
||||||
|
i0 = *nr;
|
||||||
|
*nr += xlen;
|
||||||
|
if ((*commands = realloc(*commands, sizeof(char *) * (*nr))) == NULL) {
|
||||||
|
clicon_err(OE_UNIX, errno, "realloc: %s", strerror (errno));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
for (i = 0; i < xlen; i++) {
|
||||||
|
x = xvec[i];
|
||||||
|
if ((bodystr = xml_body(x)) == NULL){
|
||||||
|
clicon_err(OE_CFG, 0, "No xml body");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
(*commands)[i0+i] = strdup(bodystr);
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
if (xvec)
|
||||||
|
free(xvec);
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
if (xk)
|
||||||
|
free(xk);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! List files in a directory
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail)
|
||||||
|
{
|
||||||
|
DIR *dirp;
|
||||||
|
struct dirent *dp;
|
||||||
|
struct stat st;
|
||||||
|
char *str;
|
||||||
|
char *cmd;
|
||||||
|
int len;
|
||||||
|
int retval = -1;
|
||||||
|
struct passwd *pw;
|
||||||
|
char filename[MAXPATHLEN];
|
||||||
|
|
||||||
|
if ((dirp = opendir(dir)) == 0){
|
||||||
|
fprintf(stderr, "expand_dir: opendir(%s) %s\n",
|
||||||
|
dir, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*nr = 0;
|
||||||
|
while ((dp = readdir(dirp)) != NULL) {
|
||||||
|
if (
|
||||||
|
#if 0
|
||||||
|
strcmp(dp->d_name, ".") != 0 &&
|
||||||
|
strcmp(dp->d_name, "..") != 0
|
||||||
|
#else
|
||||||
|
dp->d_name[0] != '.'
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp->d_name);
|
||||||
|
if (lstat(filename, &st) == 0){
|
||||||
|
if ((st.st_mode & flags) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if EXPAND_RECURSIVE
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
int nrsav = *nr;
|
||||||
|
if(expand_dir(filename, nr, commands, detail) < 0)
|
||||||
|
goto quit;
|
||||||
|
while(nrsav < *nr) {
|
||||||
|
len = strlen(dp->d_name) + strlen((*commands)[nrsav]) + 2;
|
||||||
|
if((str = malloc(len)) == NULL) {
|
||||||
|
fprintf(stderr, "expand_dir: malloc: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
snprintf(str, len-1, "%s/%s",
|
||||||
|
dp->d_name, (*commands)[nrsav]);
|
||||||
|
free((*commands)[nrsav]);
|
||||||
|
(*commands)[nrsav] = str;
|
||||||
|
|
||||||
|
nrsav++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((cmd = strdup(dp->d_name)) == NULL) {
|
||||||
|
fprintf(stderr, "expand_dir: strdup: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
if (0 &&detail){
|
||||||
|
if ((pw = getpwuid(st.st_uid)) == NULL){
|
||||||
|
fprintf(stderr, "expand_dir: getpwuid(%d): %s\n",
|
||||||
|
st.st_uid, strerror(errno));
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
len = strlen(cmd) +
|
||||||
|
strlen(pw->pw_name) +
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
strlen(ctime(&st.st_mtimespec.tv_sec)) +
|
||||||
|
#else
|
||||||
|
strlen(ctime(&st.st_mtim.tv_sec)) +
|
||||||
|
#endif
|
||||||
|
|
||||||
|
strlen("{ by }") + 1 /* \0 */;
|
||||||
|
if ((str=realloc(cmd, strlen(cmd)+len)) == NULL) {
|
||||||
|
fprintf(stderr, "expand_dir: malloc: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
snprintf(str + strlen(dp->d_name),
|
||||||
|
len - strlen(dp->d_name),
|
||||||
|
"{%s by %s}",
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
ctime(&st.st_mtimespec.tv_sec),
|
||||||
|
#else
|
||||||
|
ctime(&st.st_mtim.tv_sec),
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pw->pw_name
|
||||||
|
);
|
||||||
|
cmd = str;
|
||||||
|
}
|
||||||
|
if (((*commands) =
|
||||||
|
realloc(*commands, ((*nr)+1)*sizeof(char**))) == NULL){
|
||||||
|
perror("expand_dir: realloc");
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
(*commands)[(*nr)] = cmd;
|
||||||
|
(*nr)++;
|
||||||
|
if (*nr >= 128) /* Limit number of options */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
quit:
|
||||||
|
closedir(dirp);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Generic function for showing configurations.
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath> [<varname>]
|
||||||
|
* @param[out] xt Configuration as xml tree.
|
||||||
|
* Format of arg:
|
||||||
|
* <dbname> "running", "candidate"
|
||||||
|
* <xpath> xpath expression
|
||||||
|
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
||||||
|
* @code
|
||||||
|
* show config id <n:string>, show_conf_as("running interfaces/interface[name=%s] n");
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
show_conf_as(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg,
|
||||||
|
cxobj **xt) /* top xml */
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *db;
|
||||||
|
char **vec = NULL;
|
||||||
|
int nvec;
|
||||||
|
char *str;
|
||||||
|
char *xpath;
|
||||||
|
char *attr = NULL;
|
||||||
|
cbuf *cbx = NULL;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
cg_var *cvattr;
|
||||||
|
char *val = NULL;
|
||||||
|
|
||||||
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((vec = clicon_strsplit(str, " ", &nvec, __FUNCTION__)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, errno, "clicon_strsplit");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (nvec != 2 && nvec != 3){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "format error \"%s\" - expected <dbname> <xpath> [<attr>]", str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Dont get attr here, take it from arg instead */
|
||||||
|
db = vec[0];
|
||||||
|
if (strcmp(db, "running") != 0 && strcmp(db, "candidate") != 0) {
|
||||||
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", db);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xpath = vec[1];
|
||||||
|
if ((cbx = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (nvec == 3){
|
||||||
|
attr = vec[2];
|
||||||
|
j = 0;
|
||||||
|
for (i=0; i<strlen(xpath); i++)
|
||||||
|
if (xpath[i] == '%')
|
||||||
|
j++;
|
||||||
|
if (j != 1){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have a single '%%'");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((cvattr = cvec_find_var(cvv, attr)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "attr '%s' not found in cligen var list", attr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((val = cv2str_dup(cvattr)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, errno, "cv2str_dup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cbx, xpath, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(cbx, "%s", xpath);
|
||||||
|
if (xmldb_get(h, db, cbuf_get(cbx), 0, xt, NULL, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (val)
|
||||||
|
free(val);
|
||||||
|
if (cbx)
|
||||||
|
cbuf_free(cbx);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Show a configuration database on stdout using XML format
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath> [<varname>]
|
||||||
|
* @param[in] netconf If set print as netconf edit-config, otherwise just xml
|
||||||
|
* @see show_conf_as the main function
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
show_conf_as_xml1(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg,
|
||||||
|
int netconf)
|
||||||
|
{
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (show_conf_as(h, cvv, arg, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
if (netconf) /* netconf prefix */
|
||||||
|
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
||||||
|
xc = NULL; /* Dont print xt itself */
|
||||||
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
|
clicon_xml2file(stdout, xc, netconf?2:0, 1);
|
||||||
|
if (netconf) /* netconf postfix */
|
||||||
|
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Show configuration as prettyprinted xml
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath> [<varname>]
|
||||||
|
* @see show_conf_as the main function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
show_conf_as_xml(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
|
{
|
||||||
|
return show_conf_as_xml1(h, cvv, arg, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Show configuration as prettyprinted xml with netconf hdr/tail
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath> [<varname>]
|
||||||
|
* @see show_conf_as the main function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
show_conf_as_netconf(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
|
{
|
||||||
|
return show_conf_as_xml1(h, cvv, arg, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Show configuration as JSON
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath> [<varname>]
|
||||||
|
* @see show_conf_as the main function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
show_conf_as_json(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
|
{
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (show_conf_as(h, cvv, arg, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
xc = NULL; /* Dont print xt itself */
|
||||||
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
|
xml2json(stdout, xc, 1);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Show configuration as text givebn an xpath
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
* @param[in] h CLICON handle
|
||||||
|
* @param[in] cvv Vector of variables from CLIgen command-line
|
||||||
|
* @param[in] arg A string: <dbname> <xpath>
|
||||||
|
* @note Hardcoded that a variable in cvv is named "xpath"
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
show_conf_xpath(clicon_handle h,
|
||||||
|
cvec *cvv,
|
||||||
|
cg_var *arg)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str;
|
||||||
|
char *xpath;
|
||||||
|
cg_var *cv;
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj **xv = NULL;
|
||||||
|
size_t xlen;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "%s: requires string argument", __FUNCTION__);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Dont get attr here, take it from arg instead */
|
||||||
|
if (strcmp(str, "running") != 0 && strcmp(str, "candidate") != 0){
|
||||||
|
clicon_err(OE_PLUGIN, 0, "No such db name: %s", str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cv = cvec_find_var(cvv, "xpath");
|
||||||
|
xpath = cv_string_get(cv);
|
||||||
|
if (xmldb_get(h, str, xpath, 1, &xt, &xv, &xlen) < 0)
|
||||||
|
goto done;
|
||||||
|
for (i=0; i<xlen; i++)
|
||||||
|
clicon_xml2file(stdout, xv[i], 0, 1);
|
||||||
|
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xv)
|
||||||
|
free(xv);
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*! Show configuration as text
|
||||||
|
* Utility function used by cligen spec file
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
show_conf_as_text1(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
|
{
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if (show_conf_as(h, cvv, arg, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
xc = NULL; /* Dont print xt itself */
|
||||||
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
|
xml2txt(stdout, xc, 0); /* tree-formed text */
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Show configuration as commands, ie not tree format but as one-line commands
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
show_conf_as_command(clicon_handle h, cvec *cvv, cg_var *arg, char *prepend)
|
||||||
|
{
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
enum genmodel_type gt;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
if ((xt = xml_new("tmp", NULL)) == NULL)
|
||||||
|
goto done;
|
||||||
|
if (show_conf_as(h, cvv, arg, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
xc = NULL; /* Dont print xt itself */
|
||||||
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
|
||||||
|
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
||||||
|
goto done;
|
||||||
|
xml2cli(stdout, xc, prepend, gt, __FUNCTION__); /* cli syntax */
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
show_conf_as_text(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
|
{
|
||||||
|
return show_conf_as_text1(h, cvv, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
show_conf_as_cli(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
|
{
|
||||||
|
return show_conf_as_command(h, cvv, arg, NULL); /* XXX: how to set prepend? */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
show_yang(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
|
{
|
||||||
|
yang_node *yn;
|
||||||
|
char *str = NULL;
|
||||||
|
yang_spec *yspec;
|
||||||
|
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (arg != NULL){
|
||||||
|
str = cv_string_get(arg);
|
||||||
|
yn = (yang_node*)yang_find((yang_node*)yspec, 0, str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
yn = (yang_node*)yspec;
|
||||||
|
yang_print(stdout, yn, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef notused
|
||||||
|
/*! XML to CSV raw variant
|
||||||
|
* @see xml2csv
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml2csv_raw(FILE *f, cxobj *x)
|
||||||
|
{
|
||||||
|
cxobj *xc;
|
||||||
|
cxobj *xb;
|
||||||
|
int retval = -1;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
xc = NULL;
|
||||||
|
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL) {
|
||||||
|
if (xml_child_nr(xc)){
|
||||||
|
xb = xml_child_i(xc, 0);
|
||||||
|
if (xml_type(xb) == CX_BODY){
|
||||||
|
if (i++)
|
||||||
|
fprintf(f, ";");
|
||||||
|
fprintf(f, "%s", xml_value(xb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
|
retval = 0;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Translate XML -> CSV commands
|
||||||
|
* Can only be made in a 'flat tree', ie on the form:
|
||||||
|
* <X><A>B</A></X> -->
|
||||||
|
* Type, A
|
||||||
|
* X, B
|
||||||
|
* @param[in] f Output file
|
||||||
|
* @param[in] x XML tree
|
||||||
|
* @param[in] cvv A vector of field names present in XML
|
||||||
|
* This means that only fields in x that are listed in cvv will be printed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml2csv(FILE *f, cxobj *x, cvec *cvv)
|
||||||
|
{
|
||||||
|
cxobj *xe, *xb;
|
||||||
|
int retval = -1;
|
||||||
|
cg_var *vs;
|
||||||
|
|
||||||
|
fprintf(f, "%s", xml_name(x));
|
||||||
|
xe = NULL;
|
||||||
|
|
||||||
|
vs = NULL;
|
||||||
|
while ((vs = cvec_each(cvv, vs))) {
|
||||||
|
if ((xe = xml_find(x, cv_name_get(vs))) == NULL){
|
||||||
|
fprintf(f, ";");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (xml_child_nr(xe)){
|
||||||
|
xb = xml_child_i(xe, 0);
|
||||||
|
fprintf(f, ";%s", xml_value(xb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(f, "\n");
|
||||||
|
retval = 0;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
show_conf_as_csv1(clicon_handle h, cvec *cvv0, cg_var *arg)
|
||||||
|
{
|
||||||
|
cxobj *xt = NULL;
|
||||||
|
cxobj *xc;
|
||||||
|
int retval = -1;
|
||||||
|
cvec *cvv=NULL;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if (show_conf_as(h, cvv0, arg, &xt) < 0)
|
||||||
|
goto done;
|
||||||
|
xc = NULL; /* Dont print xt itself */
|
||||||
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL){
|
||||||
|
if ((str = chunk_sprintf(__FUNCTION__, "%s[]", xml_name(xc))) == NULL)
|
||||||
|
goto done;
|
||||||
|
#ifdef NOTYET /* yang-spec? */
|
||||||
|
if (ds==NULL && (ds = key2spec_key(dbspec, str)) != NULL){
|
||||||
|
cg_var *vs;
|
||||||
|
fprintf(stdout, "Type");
|
||||||
|
cvv = db_spec2cvec(ds);
|
||||||
|
vs = NULL;
|
||||||
|
while ((vs = cvec_each(cvv, vs)))
|
||||||
|
fprintf(stdout, ";%s", cv_name_get(vs));
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
} /* Now values just need to follow,... */
|
||||||
|
#endif /* yang-spec? */
|
||||||
|
if (cvv== NULL)
|
||||||
|
goto done;
|
||||||
|
xml2csv(stdout, xc, cvv); /* csv syntax */
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (xt)
|
||||||
|
xml_free(xt);
|
||||||
|
unchunk_group(__FUNCTION__);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
show_conf_as_csv(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
|
{
|
||||||
|
return show_conf_as_csv1(h, cvv, arg);
|
||||||
|
}
|
||||||
|
|
@ -70,15 +70,22 @@ int cli_start_shell(clicon_handle h, cvec *vars, cg_var *argv);
|
||||||
int cli_quit(clicon_handle h, cvec *vars, cg_var *arg);
|
int cli_quit(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int cli_commit(clicon_handle h, cvec *vars, cg_var *arg);
|
int cli_commit(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int cli_validate(clicon_handle h, cvec *vars, cg_var *arg);
|
int cli_validate(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail);
|
|
||||||
int expand_dbvar_dbxml(void *h, char *name, cvec *cvv, cg_var *arg,
|
|
||||||
int *nr, char ***commands, char ***helptexts);
|
|
||||||
int compare_dbs(clicon_handle h, cvec *vars, cg_var *arg);
|
int compare_dbs(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
|
|
||||||
int load_config_file(clicon_handle h, cvec *vars, cg_var *arg);
|
int load_config_file(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int save_config_file(clicon_handle h, cvec *vars, cg_var *arg);
|
int save_config_file(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int delete_all(clicon_handle h, cvec *vars, cg_var *arg);
|
int delete_all(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int discard_changes(clicon_handle h, cvec *vars, cg_var *arg);
|
int discard_changes(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
|
int cli_notify(clicon_handle h, cvec *cvv, cg_var *arg);
|
||||||
|
int cli_notification_register(clicon_handle h, char *stream, enum format_enum format,
|
||||||
|
char *filter, int status,
|
||||||
|
int (*fn)(int, void*), void *arg);
|
||||||
|
|
||||||
|
/* In cli_show.c */
|
||||||
|
int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail);
|
||||||
|
int expand_dbvar(void *h, char *name, cvec *cvv, cg_var *arg,
|
||||||
|
int *nr, char ***commands, char ***helptexts);
|
||||||
|
|
||||||
int show_conf_as_xml(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_conf_as_xml(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int show_conf_as_netconf(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_conf_as_netconf(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int show_conf_as_json(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_conf_as_json(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
|
|
@ -86,8 +93,5 @@ int show_conf_as_text(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int show_conf_as_cli(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_conf_as_cli(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int show_conf_as_csv(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_conf_as_csv(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int show_yang(clicon_handle h, cvec *vars, cg_var *arg);
|
int show_yang(clicon_handle h, cvec *vars, cg_var *arg);
|
||||||
int cli_notification_register(clicon_handle h, char *stream, enum format_enum format,
|
|
||||||
char *filter, int status,
|
|
||||||
int (*fn)(int, void*), void *arg);
|
|
||||||
|
|
||||||
#endif /* _CLIXON_CLI_API_H_ */
|
#endif /* _CLIXON_CLI_API_H_ */
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ xml_filter2(cxobj *xfilter,
|
||||||
sprev = s = NULL;
|
sprev = s = NULL;
|
||||||
while ((s = xml_child_each(xparent, s, CX_ELMNT)) != NULL) {
|
while ((s = xml_child_each(xparent, s, CX_ELMNT)) != NULL) {
|
||||||
if ((f = xml_find(xfilter, xml_name(s))) == NULL){
|
if ((f = xml_find(xfilter, xml_name(s))) == NULL){
|
||||||
xml_prune(xparent, s, 1);
|
xml_purge(s);
|
||||||
s = sprev;
|
s = sprev;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +166,7 @@ xml_filter2(cxobj *xfilter,
|
||||||
if (xml_filter2(f, s, &remove_s) < 0)
|
if (xml_filter2(f, s, &remove_s) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (remove_s){
|
if (remove_s){
|
||||||
xml_prune(xparent, s, 1);
|
xml_purge(s);
|
||||||
s = sprev;
|
s = sprev;
|
||||||
}
|
}
|
||||||
sprev = s;
|
sprev = s;
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ netconf_filter_xmldb(clicon_handle h,
|
||||||
switch (foption){
|
switch (foption){
|
||||||
case FILTER_SUBTREE:
|
case FILTER_SUBTREE:
|
||||||
/* Get the whole database as xml */
|
/* Get the whole database as xml */
|
||||||
if (xmldb_get(h, source, NULL, 0, &xdb, NULL, NULL) < 0){
|
if (xmldb_get(h, source, "/", 0, &xdb, NULL, NULL) < 0){
|
||||||
netconf_create_rpc_error(cb_err, xorig,
|
netconf_create_rpc_error(cb_err, xorig,
|
||||||
"operation-failed",
|
"operation-failed",
|
||||||
"application",
|
"application",
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,9 @@ typedef int (xml_applyfn_t)(cxobj *yn, void *arg);
|
||||||
* xml_flag() flags:
|
* xml_flag() flags:
|
||||||
*/
|
*/
|
||||||
#define XML_FLAG_MARK 0x01 /* Marker for dynamic algorithms, eg expand */
|
#define XML_FLAG_MARK 0x01 /* Marker for dynamic algorithms, eg expand */
|
||||||
#define XML_FLAG_ADD 0x02 /* Node is added (commits) */
|
#define XML_FLAG_ADD 0x02 /* Node is added (commits) or parent added rec*/
|
||||||
#define XML_FLAG_DEL 0x04 /* Node is deleted (commits) */
|
#define XML_FLAG_DEL 0x04 /* Node is deleted (commits) or parent deleted rec */
|
||||||
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) */
|
#define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
|
|
@ -88,12 +88,18 @@ cxobj *xml_new_spec(char *name, cxobj *xn_parent, void *spec);
|
||||||
void *xml_spec(cxobj *x);
|
void *xml_spec(cxobj *x);
|
||||||
cxobj *xml_find(cxobj *xn_parent, char *name);
|
cxobj *xml_find(cxobj *xn_parent, char *name);
|
||||||
|
|
||||||
|
int xml_addsub(cxobj *xp, cxobj *xc);
|
||||||
|
cxobj *xml_insert(cxobj *xt, char *tag);
|
||||||
|
int xml_purge(cxobj *xc);
|
||||||
|
int xml_child_rm(cxobj *xp, int i);
|
||||||
|
int xml_rootchild(cxobj *xp, int i, cxobj **xcp);
|
||||||
|
|
||||||
char *xml_body(cxobj *xn);
|
char *xml_body(cxobj *xn);
|
||||||
char *xml_find_value(cxobj *xn_parent, char *name);
|
char *xml_find_value(cxobj *xn_parent, char *name);
|
||||||
char *xml_find_body(cxobj *xn, char *name);
|
char *xml_find_body(cxobj *xn, char *name);
|
||||||
|
|
||||||
int xml_free(cxobj *xn);
|
int xml_free(cxobj *xn);
|
||||||
int xml_prune(cxobj *xp, cxobj *xc, int freeit);
|
|
||||||
int clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint);
|
int clicon_xml2file(FILE *f, cxobj *xn, int level, int prettyprint);
|
||||||
int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint);
|
int clicon_xml2cbuf(cbuf *xf, cxobj *xn, int level, int prettyprint);
|
||||||
int clicon_xml_parse_file(int fd, cxobj **xml_top, char *endtag);
|
int clicon_xml_parse_file(int fd, cxobj **xml_top, char *endtag);
|
||||||
|
|
@ -101,8 +107,7 @@ int clicon_xml_parse_string(char **str, cxobj **xml_top);
|
||||||
|
|
||||||
int xml_copy(cxobj *x0, cxobj *x1);
|
int xml_copy(cxobj *x0, cxobj *x1);
|
||||||
cxobj *xml_dup(cxobj *x0);
|
cxobj *xml_dup(cxobj *x0);
|
||||||
int xml_addsub(cxobj *xp, cxobj *xc);
|
|
||||||
cxobj *xml_insert(cxobj *xt, char *tag);
|
|
||||||
int cxvec_dup(cxobj **vec0, size_t len0, cxobj ***vec1, size_t *len1);
|
int cxvec_dup(cxobj **vec0, size_t len0, cxobj ***vec1, size_t *len1);
|
||||||
int cxvec_append(cxobj *x, cxobj ***vec, size_t *len);
|
int cxvec_append(cxobj *x, cxobj ***vec, size_t *len);
|
||||||
int xml_apply(cxobj *xn, enum cxobj_type type, xml_applyfn_t fn, void *arg);
|
int xml_apply(cxobj *xn, enum cxobj_type type, xml_applyfn_t fn, void *arg);
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,10 @@ clicon_option_default(clicon_hash_t *copt)
|
||||||
if (hash_add(copt, "CLICON_CLI_GENMODEL_COMPLETION", "0", strlen("0")+1) < 0)
|
if (hash_add(copt, "CLICON_CLI_GENMODEL_COMPLETION", "0", strlen("0")+1) < 0)
|
||||||
goto catch;
|
goto catch;
|
||||||
}
|
}
|
||||||
|
if (!hash_lookup(copt, "CLICON_XMLDB_RPC")){
|
||||||
|
if (hash_add(copt, "CLICON_XMLDB_RPC", "0", strlen("0")+1) < 0)
|
||||||
|
goto catch;
|
||||||
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
catch:
|
catch:
|
||||||
unchunk_group(__FUNCTION__);
|
unchunk_group(__FUNCTION__);
|
||||||
|
|
@ -600,7 +604,7 @@ clicon_xmldb_rpc(clicon_handle h)
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
if ((s = clicon_option_str(h, "CLICON_XMLDB_RPC")) == NULL)
|
if ((s = clicon_option_str(h, "CLICON_XMLDB_RPC")) == NULL)
|
||||||
return -1;
|
return 0; /* default 0 */
|
||||||
return atoi(s);
|
return atoi(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ clicon_proc_sigint(int sig)
|
||||||
kill (_clicon_proc_child, SIGINT);
|
kill (_clicon_proc_child, SIGINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Fork a child process, setup a pipe between parent and child.
|
||||||
* Fork a child process, setup a pipe between parent and child, allowing
|
* Allowing parent to read the output of the child.
|
||||||
* parent to read the output of the child. If 'doerr' is non-zero, stderr
|
* @param[in] doerr If non-zero, stderr will be directed to the pipe as well.
|
||||||
* will be directed to the pipe as well. The pipe for the parent to write
|
* The pipe for the parent to write
|
||||||
* to the child is closed and cannot be used.
|
* to the child is closed and cannot be used.
|
||||||
*
|
*
|
||||||
* When child process is done with the pipe setup, execute the specified
|
* When child process is done with the pipe setup, execute the specified
|
||||||
|
|
@ -85,10 +85,13 @@ clicon_proc_sigint(int sig)
|
||||||
* until eof. The read output will be sent to the specified output callback,
|
* until eof. The read output will be sent to the specified output callback,
|
||||||
* 'outcb' function.
|
* 'outcb' function.
|
||||||
*
|
*
|
||||||
* Return number of matches (processes affected). -1 on error.
|
* @retval number Matches (processes affected).
|
||||||
|
* @retval -1 Error.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_proc_run (char *cmd, void (outcb)(char *), int doerr)
|
clicon_proc_run (char *cmd,
|
||||||
|
void (outcb)(char *),
|
||||||
|
int doerr)
|
||||||
{
|
{
|
||||||
char
|
char
|
||||||
**argv,
|
**argv,
|
||||||
|
|
@ -182,9 +185,7 @@ clicon_proc_run (char *cmd, void (outcb)(char *), int doerr)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Spawn command and report exit status
|
||||||
/*
|
|
||||||
* Spawm command and report exit status
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_proc_daemon (char *cmd)
|
clicon_proc_daemon (char *cmd)
|
||||||
|
|
@ -251,81 +252,6 @@ clicon_proc_daemon (char *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef moved_to_osr
|
|
||||||
#ifdef linux
|
|
||||||
/*
|
|
||||||
* Send 'sig' (if not 0) to all processes matching 'name'.
|
|
||||||
* Return the number of matches.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_proc_killbyname (const char *name, int sig)
|
|
||||||
{
|
|
||||||
/* XXXX FIXME. Should scan /proc/<pid>/status */
|
|
||||||
char buf[512];
|
|
||||||
snprintf (buf, sizeof (buf)-1, "pkill -%d %s", sig, name);
|
|
||||||
|
|
||||||
return clicon_proc_run (buf, NULL, 0);
|
|
||||||
}
|
|
||||||
#endif /* Linux */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef BSD
|
|
||||||
/*
|
|
||||||
* Send 'sig' (if not 0) to all processes matching 'name'.
|
|
||||||
* Return the number of matches.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
clicon_proc_killbyname (const char *name, int sig)
|
|
||||||
{
|
|
||||||
int
|
|
||||||
i,
|
|
||||||
nproc,
|
|
||||||
nmatch,
|
|
||||||
mib[3];
|
|
||||||
size_t
|
|
||||||
size;
|
|
||||||
struct proc
|
|
||||||
*p;
|
|
||||||
struct kinfo_proc
|
|
||||||
*kp = NULL;
|
|
||||||
|
|
||||||
mib[0] = CTL_KERN;
|
|
||||||
mib[1] = KERN_NPROCS; /* KERN_MACPROC, KERN_PROC */
|
|
||||||
size = sizeof (nproc);
|
|
||||||
if (sysctl(mib, 2, &nproc, &size, NULL, 0) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
size = nproc * sizeof(struct kinfo_proc);
|
|
||||||
kp = chunk(size * sizeof(char), "bsdkill");
|
|
||||||
if (kp == NULL)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
mib[1] = KERN_PROC;
|
|
||||||
mib[2] = KERN_PROC_ALL;
|
|
||||||
|
|
||||||
if (sysctl(mib, 3, kp, &size, NULL, 0) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
nproc = size / sizeof(struct kinfo_proc);
|
|
||||||
for (nmatch = i = 0; i < nproc; i++) {
|
|
||||||
p = (struct proc *)&kp[i].kp_proc;
|
|
||||||
if (!strcmp (name, p->p_comm)) {
|
|
||||||
nmatch++;
|
|
||||||
kill (p->p_pid, sig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unchunk (kp);
|
|
||||||
return nmatch;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (kp)
|
|
||||||
unchunk (kp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif /* BSD */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! Translate group name to gid. Return -1 if error or not found.
|
/*! Translate group name to gid. Return -1 if error or not found.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -464,7 +464,9 @@ send_msg_ok(int s)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
send_msg_notify(int s, int level, char *event)
|
send_msg_notify(int s,
|
||||||
|
int level,
|
||||||
|
char *event)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
struct clicon_msg *msg;
|
struct clicon_msg *msg;
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,15 @@ db_init_mode(char *file,
|
||||||
|
|
||||||
/* Open database for writing */
|
/* Open database for writing */
|
||||||
if ((dp = dpopen(file, omode | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, omode | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "db_init: dpopen(%s): %s",
|
clicon_err(OE_DB, errno, "dpopen(%s): %s",
|
||||||
file,
|
file,
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
clicon_debug(1, "db_init(%s)", file);
|
clicon_debug(1, "db_init(%s)", file);
|
||||||
if (dpclose(dp) == 0){
|
if (dpclose(dp) == 0){
|
||||||
clicon_err(OE_DB, 0, "db_set: dpclose: %s", dperrmsg(dpecode));
|
clicon_err(OE_DB, errno, "db_set: dpclose: %s",
|
||||||
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -138,7 +139,7 @@ db_set(char *file, char *key, void *data, size_t datalen)
|
||||||
|
|
||||||
/* Open database for writing */
|
/* Open database for writing */
|
||||||
if ((dp = dpopen(file, DP_OWRITER|DP_OLCKNB , 0)) == NULL){
|
if ((dp = dpopen(file, DP_OWRITER|DP_OLCKNB , 0)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "db_set: dpopen(%s): %s",
|
clicon_err(OE_DB, errno, "db_set: dpopen(%s): %s",
|
||||||
file,
|
file,
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -146,7 +147,7 @@ db_set(char *file, char *key, void *data, size_t datalen)
|
||||||
clicon_debug(2, "%s: db_put(%s, len:%d)",
|
clicon_debug(2, "%s: db_put(%s, len:%d)",
|
||||||
file, key, (int)datalen);
|
file, key, (int)datalen);
|
||||||
if (dpput(dp, key, -1, data, datalen, DP_DOVER) == 0){
|
if (dpput(dp, key, -1, data, datalen, DP_DOVER) == 0){
|
||||||
clicon_err(OE_DB, 0, "%s: db_set: dpput(%s, %d): %s",
|
clicon_err(OE_DB, errno, "%s: db_set: dpput(%s, %d): %s",
|
||||||
file,
|
file,
|
||||||
key,
|
key,
|
||||||
datalen,
|
datalen,
|
||||||
|
|
@ -181,7 +182,7 @@ db_get(char *file,
|
||||||
|
|
||||||
/* Open database for readinf */
|
/* Open database for readinf */
|
||||||
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, dpecode, "%s: db_get(%s, %d): dpopen: %s",
|
clicon_err(OE_DB, errno, "%s: db_get(%s, %d): dpopen: %s",
|
||||||
file,
|
file,
|
||||||
key,
|
key,
|
||||||
datalen,
|
datalen,
|
||||||
|
|
@ -195,7 +196,7 @@ db_get(char *file,
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
clicon_err(OE_DB, 0, "db_get: dpgetwb: %s (%d)",
|
clicon_err(OE_DB, errno, "db_get: dpgetwb: %s (%d)",
|
||||||
dperrmsg(dpecode), dpecode);
|
dperrmsg(dpecode), dpecode);
|
||||||
dpclose(dp);
|
dpclose(dp);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -205,7 +206,7 @@ db_get(char *file,
|
||||||
*datalen = len;
|
*datalen = len;
|
||||||
clicon_debug(2, "db_get(%s, %s)=%s", file, key, (char*)data);
|
clicon_debug(2, "db_get(%s, %s)=%s", file, key, (char*)data);
|
||||||
if (dpclose(dp) == 0){
|
if (dpclose(dp) == 0){
|
||||||
clicon_err(OE_DB, 0, "db_get: dpclose: %s", dperrmsg(dpecode));
|
clicon_err(OE_DB, errno, "db_get: dpclose: %s", dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -243,7 +244,7 @@ db_get_alloc(char *file,
|
||||||
|
|
||||||
/* Open database for writing */
|
/* Open database for writing */
|
||||||
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "%s: dpopen(%s): %s",
|
clicon_err(OE_DB, errno, "%s: dpopen(%s): %s",
|
||||||
__FUNCTION__,
|
__FUNCTION__,
|
||||||
file,
|
file,
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
|
|
@ -257,7 +258,7 @@ db_get_alloc(char *file,
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
/* No entry vs error? */
|
/* No entry vs error? */
|
||||||
clicon_err(OE_DB, 0, "db_get_alloc: dpgetwb: %s (%d)",
|
clicon_err(OE_DB, errno, "db_get_alloc: dpgetwb: %s (%d)",
|
||||||
dperrmsg(dpecode), dpecode);
|
dperrmsg(dpecode), dpecode);
|
||||||
dpclose(dp);
|
dpclose(dp);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -265,7 +266,7 @@ db_get_alloc(char *file,
|
||||||
}
|
}
|
||||||
*datalen = len;
|
*datalen = len;
|
||||||
if (dpclose(dp) == 0){
|
if (dpclose(dp) == 0){
|
||||||
clicon_err(OE_DB, 0, "db_get_alloc: dpclose: %s", dperrmsg(dpecode));
|
clicon_err(OE_DB, errno, "db_get_alloc: dpclose: %s", dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -286,7 +287,7 @@ db_del(char *file, char *key)
|
||||||
|
|
||||||
/* Open database for writing */
|
/* Open database for writing */
|
||||||
if ((dp = dpopen(file, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, 0, "db_del: dpopen(%s): %s",
|
clicon_err(OE_DB, errno, "db_del: dpopen(%s): %s",
|
||||||
file,
|
file,
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -295,7 +296,7 @@ db_del(char *file, char *key)
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
if (dpclose(dp) == 0){
|
if (dpclose(dp) == 0){
|
||||||
clicon_err(OE_DB, 0, "db_del: dpclose: %s", dperrmsg(dpecode));
|
clicon_err(OE_DB, errno, "db_del: dpclose: %s", dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
|
@ -316,18 +317,18 @@ db_exists(char *file, char *key)
|
||||||
|
|
||||||
/* Open database for reading */
|
/* Open database for reading */
|
||||||
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(file, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, dpecode, "%s: dpopen: %s",
|
clicon_err(OE_DB, errno, "%s: dpopen: %s",
|
||||||
__FUNCTION__, dperrmsg(dpecode));
|
__FUNCTION__, dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = dpvsiz(dp, key, -1);
|
len = dpvsiz(dp, key, -1);
|
||||||
if (len < 0 && dpecode != DP_ENOITEM)
|
if (len < 0 && dpecode != DP_ENOITEM)
|
||||||
clicon_err(OE_DB, 0, "^s: dpvsiz: %s (%d)",
|
clicon_err(OE_DB, errno, "^s: dpvsiz: %s (%d)",
|
||||||
__FUNCTION__, dperrmsg(dpecode), dpecode);
|
__FUNCTION__, dperrmsg(dpecode), dpecode);
|
||||||
|
|
||||||
if (dpclose(dp) == 0) {
|
if (dpclose(dp) == 0) {
|
||||||
clicon_err(OE_DB, 0, "%s: dpclose: %s", dperrmsg(dpecode),__FUNCTION__);
|
clicon_err(OE_DB, errno, "%s: dpclose: %s", dperrmsg(dpecode),__FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +379,7 @@ db_regexp(char *file,
|
||||||
if (regexp) {
|
if (regexp) {
|
||||||
if ((status = regcomp(&iterre, regexp, REG_EXTENDED)) != 0) {
|
if ((status = regcomp(&iterre, regexp, REG_EXTENDED)) != 0) {
|
||||||
regerror(status, &iterre, errbuf, sizeof(errbuf));
|
regerror(status, &iterre, errbuf, sizeof(errbuf));
|
||||||
clicon_err(OE_DB, 0, "%s: regcomp: %s", __FUNCTION__, errbuf);
|
clicon_err(OE_DB, errno, "%s: regcomp: %s", __FUNCTION__, errbuf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,7 +393,7 @@ db_regexp(char *file,
|
||||||
|
|
||||||
/* Initiate iterator */
|
/* Initiate iterator */
|
||||||
if(dpiterinit(iterdp) == 0) {
|
if(dpiterinit(iterdp) == 0) {
|
||||||
clicon_err(OE_DB, 0, "%s: dpiterinit: %s", __FUNCTION__, dperrmsg(dpecode));
|
clicon_err(OE_DB, errno, "%s: dpiterinit: %s", __FUNCTION__, dperrmsg(dpecode));
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -549,7 +550,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
else if (strcmp(verb, "openread")==0){
|
else if (strcmp(verb, "openread")==0){
|
||||||
if ((dp = dpopen(filename, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(filename, DP_OREADER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, dpecode, "dbopen: %s",
|
clicon_err(OE_DB, errno, "dbopen: %s",
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -557,7 +558,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
else if (strcmp(verb, "openwrite")==0){
|
else if (strcmp(verb, "openwrite")==0){
|
||||||
if ((dp = dpopen(filename, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
if ((dp = dpopen(filename, DP_OWRITER | DP_OLCKNB, 0)) == NULL){
|
||||||
clicon_err(OE_DB, dpecode, "dbopen: %s",
|
clicon_err(OE_DB, errno, "dbopen: %s",
|
||||||
dperrmsg(dpecode));
|
dperrmsg(dpecode));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ xml_value(cxobj *xn)
|
||||||
return xn->x_value;
|
return xn->x_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set value of xnode, value is copied
|
/*! Set value of xml node, value is copied
|
||||||
* @param[in] xn xml node
|
* @param[in] xn xml node
|
||||||
* @param[in] val new value, null-terminated string, copied by function
|
* @param[in] val new value, null-terminated string, copied by function
|
||||||
* @retval -1 on error with clicon-err set
|
* @retval -1 on error with clicon-err set
|
||||||
|
|
@ -230,7 +230,8 @@ xml_value_set(cxobj *xn, char *val)
|
||||||
* @retval new value
|
* @retval new value
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
xml_value_append(cxobj *xn, char *val)
|
xml_value_append(cxobj *xn,
|
||||||
|
char *val)
|
||||||
{
|
{
|
||||||
int len0;
|
int len0;
|
||||||
int len;
|
int len;
|
||||||
|
|
@ -263,7 +264,8 @@ xml_type(cxobj *xn)
|
||||||
* @retval type old type
|
* @retval type old type
|
||||||
*/
|
*/
|
||||||
enum cxobj_type
|
enum cxobj_type
|
||||||
xml_type_set(cxobj *xn, enum cxobj_type type)
|
xml_type_set(cxobj *xn,
|
||||||
|
enum cxobj_type type)
|
||||||
{
|
{
|
||||||
enum cxobj_type old = xn->x_type;
|
enum cxobj_type old = xn->x_type;
|
||||||
|
|
||||||
|
|
@ -289,7 +291,8 @@ xml_index(cxobj *xn)
|
||||||
* index/key is used in case of yang list constructs where one element is key
|
* index/key is used in case of yang list constructs where one element is key
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_index_set(cxobj *xn, int index)
|
xml_index_set(cxobj *xn,
|
||||||
|
int index)
|
||||||
{
|
{
|
||||||
int old = xn->x_index;
|
int old = xn->x_index;
|
||||||
|
|
||||||
|
|
@ -313,7 +316,8 @@ xml_child_nr(cxobj *xn)
|
||||||
* @retval child in XML tree, or NULL if no such child, or empty child
|
* @retval child in XML tree, or NULL if no such child, or empty child
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xml_child_i(cxobj *xn, int i)
|
xml_child_i(cxobj *xn,
|
||||||
|
int i)
|
||||||
{
|
{
|
||||||
if (i < xn->x_childvec_len)
|
if (i < xn->x_childvec_len)
|
||||||
return xn->x_childvec[i];
|
return xn->x_childvec[i];
|
||||||
|
|
@ -321,7 +325,9 @@ xml_child_i(cxobj *xn, int i)
|
||||||
}
|
}
|
||||||
|
|
||||||
cxobj *
|
cxobj *
|
||||||
xml_child_i_set(cxobj *xt, int i, cxobj *xc)
|
xml_child_i_set(cxobj *xt,
|
||||||
|
int i,
|
||||||
|
cxobj *xc)
|
||||||
{
|
{
|
||||||
if (i < xt->x_childvec_len)
|
if (i < xt->x_childvec_len)
|
||||||
xt->x_childvec[i] = xc;
|
xt->x_childvec[i] = xc;
|
||||||
|
|
@ -460,7 +466,8 @@ xml_spec(cxobj *x)
|
||||||
* @retval NULL if no such node found.
|
* @retval NULL if no such node found.
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xml_find(cxobj *x_up, char *name)
|
xml_find(cxobj *x_up,
|
||||||
|
char *name)
|
||||||
{
|
{
|
||||||
cxobj *x = NULL;
|
cxobj *x = NULL;
|
||||||
|
|
||||||
|
|
@ -478,14 +485,25 @@ xml_find(cxobj *x_up, char *name)
|
||||||
* @see xml_insert
|
* @see xml_insert
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_addsub(cxobj *xp, cxobj *xc)
|
xml_addsub(cxobj *xp,
|
||||||
|
cxobj *xc)
|
||||||
{
|
{
|
||||||
cxobj *oldp;
|
cxobj *oldp;
|
||||||
|
int i;
|
||||||
|
|
||||||
if ((oldp = xml_parent(xc)) != NULL)
|
if ((oldp = xml_parent(xc)) != NULL){
|
||||||
xml_prune(oldp, xc, 0);
|
/* Find child order i in old parent*/
|
||||||
|
for (i=0; i<xml_child_nr(oldp); i++)
|
||||||
|
if (xml_child_i(oldp, i) == xc)
|
||||||
|
break;
|
||||||
|
/* Remove xc from old parent */
|
||||||
|
if (i < xml_child_nr(oldp))
|
||||||
|
xml_child_rm(oldp, i);
|
||||||
|
}
|
||||||
|
/* Add xc to new parent */
|
||||||
if (xml_child_append(xp, xc) < 0)
|
if (xml_child_append(xp, xc) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
/* Set new parent in child */
|
||||||
xml_parent_set(xc, xp);
|
xml_parent_set(xc, xp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -515,6 +533,110 @@ xml_insert(cxobj *xp, char *tag)
|
||||||
return xc;
|
return xc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Remove and free an xml node child from xml parent
|
||||||
|
* @param[in] xparent xml parent node
|
||||||
|
* @param[in] xchild xml child node (to be renmoved and freed)
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1
|
||||||
|
* @note you cannot remove xchild in the loop (unless yoy keep track of xprev)
|
||||||
|
*
|
||||||
|
* @see xml_free Free, dont remove from parent
|
||||||
|
* @see xml_child_rm Only remove dont free
|
||||||
|
* Differs from xml_free it is removed from parent.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_purge(cxobj *xc)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
int i;
|
||||||
|
cxobj *xp;
|
||||||
|
|
||||||
|
if ((xp = xml_parent(xc)) != NULL){
|
||||||
|
/* Find child order i in parent*/
|
||||||
|
for (i=0; i<xml_child_nr(xp); i++)
|
||||||
|
if (xml_child_i(xp, i) == xc)
|
||||||
|
break;
|
||||||
|
/* Remove xc from parent */
|
||||||
|
if (i < xml_child_nr(xp))
|
||||||
|
if (xml_child_rm(xp, i) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xml_free(xc);
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Remove xml node from parent xml node. No freeing and child is new own root
|
||||||
|
* @param[in] xp xml parent node
|
||||||
|
* @param[in] i Number of xml child node (to remove)
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1
|
||||||
|
* @note you should not remove xchild in loop (unless yoy keep track of xprev)
|
||||||
|
*
|
||||||
|
* @see xml_rootchild
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_child_rm(cxobj *xp,
|
||||||
|
int i)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xc = NULL;
|
||||||
|
|
||||||
|
if ((xc = xml_child_i(xp, i)) == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "Child not found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
xp->x_childvec[i] = NULL;
|
||||||
|
xml_parent_set(xc, NULL);
|
||||||
|
xp->x_childvec_len--;
|
||||||
|
/* shift up, note same index i used but ok since we break */
|
||||||
|
for (; i<xp->x_childvec_len; i++)
|
||||||
|
xp->x_childvec[i] = xp->x_childvec[i+1];
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Return a child sub-tree, while removing parent and all other children
|
||||||
|
* Given a root xml node, and the i:th child, remove the child from its parent
|
||||||
|
* and return it, remove the parent and all other children.
|
||||||
|
* Before: xp-->[..xc..]
|
||||||
|
* After: xc
|
||||||
|
* @param[in] xp xml parent node. Will be deleted
|
||||||
|
* @param[in] i Child nr in parent child vector
|
||||||
|
* @param[out] xcp xml child node. New root
|
||||||
|
* @code
|
||||||
|
* @endcode
|
||||||
|
* @see xml_child_rm
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_rootchild(cxobj *xp,
|
||||||
|
int i,
|
||||||
|
cxobj **xcp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xc;
|
||||||
|
|
||||||
|
if (xml_parent(xp) != NULL){
|
||||||
|
clicon_err(OE_XML, 0, "Parent is not root");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((xc = xml_child_i(xp, i)) == NULL){
|
||||||
|
clicon_err(OE_XML, 0, "Child not found");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_child_rm(xp, i) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml_free(xp) < 0)
|
||||||
|
goto done;
|
||||||
|
*xcp = xc;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Get the first sub-node which is an XML body.
|
/*! Get the first sub-node which is an XML body.
|
||||||
* @param[in] xn xml tree node
|
* @param[in] xn xml tree node
|
||||||
* @retval The returned body as a pointer to the name string
|
* @retval The returned body as a pointer to the name string
|
||||||
|
|
@ -532,7 +654,6 @@ xml_body(cxobj *xn)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Find and return the value of a sub xml node
|
/*! Find and return the value of a sub xml node
|
||||||
*
|
*
|
||||||
* The value can be of an attribute or body.
|
* The value can be of an attribute or body.
|
||||||
|
|
@ -554,14 +675,13 @@ xml_find_value(cxobj *x_up, char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Find and return a body (string) of a sub xml node
|
/*! Find and return a body (string) of a sub xml node
|
||||||
* @param[in] xn xml tree node
|
* @param[in] xn xml tree node
|
||||||
* @param[in] name name of xml tree node
|
* @param[in] name name of xml tree node
|
||||||
* @retval The returned body as a pointer to the name string
|
* @retval The returned body as a pointer to the name string
|
||||||
* @retval NULL if no such node or no body in found node
|
* @retval NULL if no such node or no body in found node
|
||||||
* Note, make a copy of the return value to use it properly
|
* @note, make a copy of the return value to use it properly
|
||||||
* See also xml_find_value
|
* @see xml_find_value
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
xml_find_body(cxobj *xn, char *name)
|
xml_find_body(cxobj *xn, char *name)
|
||||||
|
|
@ -573,51 +693,9 @@ xml_find_body(cxobj *xn, char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Remove an xml node from a parent xml node.
|
|
||||||
* @param[in] xparent xml parent node
|
|
||||||
* @param[in] xchild xml child node (to remove)
|
|
||||||
* @param[in] purge if 1, free the child node, not just remove from parent
|
|
||||||
* @retval 0 OK
|
|
||||||
* @retval -1
|
|
||||||
* @note you cannot remove xchild in the loop (unless yoy keep track of xprev)
|
|
||||||
*
|
|
||||||
* @see xml_free
|
|
||||||
* Differs from xml_free in two ways:
|
|
||||||
* 1. It is removed from parent.
|
|
||||||
* 2. If you set the purge flag to 1, the child tree will be freed
|
|
||||||
* (otherwise it will not)
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xml_prune(cxobj *xparent,
|
|
||||||
cxobj *xchild,
|
|
||||||
int purge)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
cxobj *xc = NULL;
|
|
||||||
|
|
||||||
for (i=0; i<xml_child_nr(xparent); i++){
|
|
||||||
xc = xml_child_i(xparent, i);
|
|
||||||
if (xc != xchild)
|
|
||||||
continue;
|
|
||||||
/* matching child */
|
|
||||||
xparent->x_childvec[i] = NULL;
|
|
||||||
xml_parent_set(xc, NULL);
|
|
||||||
if (purge)
|
|
||||||
xml_free(xchild);
|
|
||||||
xparent->x_childvec_len--;
|
|
||||||
/* shift up, note same index i used but ok since we break */
|
|
||||||
for (;i<xparent->x_childvec_len; i++)
|
|
||||||
xparent->x_childvec[i] = xparent->x_childvec[i+1];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
clicon_err(OE_XML, 0, "%s: child not found", __FUNCTION__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Free an xl sub-tree recursively, but do not remove it from parent
|
/*! Free an xl sub-tree recursively, but do not remove it from parent
|
||||||
* @param[in] x the xml tree to be freed.
|
* @param[in] x the xml tree to be freed.
|
||||||
* @see xml_prune
|
* @see xml_purge where x is also removed from parent
|
||||||
* Differs from xml_prune in that it is _not_ removed from parent.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_free(cxobj *x)
|
xml_free(cxobj *x)
|
||||||
|
|
@ -662,7 +740,7 @@ clicon_xml2file(FILE *f,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (clicon_xml2cbuf(cb, xn, level, prettyprint) < 0)
|
if (clicon_xml2cbuf(cb, xn, level, prettyprint) < 0)
|
||||||
|
|
@ -864,7 +942,6 @@ clicon_xml_parse_file(int fd,
|
||||||
return (*cx)?0:-1;
|
return (*cx)?0:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Read an XML definition from string and parse it into a parse-tree.
|
/*! Read an XML definition from string and parse it into a parse-tree.
|
||||||
*
|
*
|
||||||
* @param[in] str Pointer to string containing XML definition. NOTE: destructively
|
* @param[in] str Pointer to string containing XML definition. NOTE: destructively
|
||||||
|
|
@ -1081,6 +1158,7 @@ xml_apply_ancestor(cxobj *xn,
|
||||||
goto done;
|
goto done;
|
||||||
if (xml_apply_ancestor(xp, fn, arg) < 0)
|
if (xml_apply_ancestor(xp, fn, arg) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
xn = xp;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,9 @@ db_islocked(char *db)
|
||||||
* @param[out] filename Filename. Unallocate after use with free()
|
* @param[out] filename Filename. Unallocate after use with free()
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
* @note Could need a way to extend which databases exists, eg to register new.
|
||||||
|
* The currently allowed databases are:
|
||||||
|
* candidate, tmp, running, result
|
||||||
* The filename reside in CLICON_XMLDB_DIR option
|
* The filename reside in CLICON_XMLDB_DIR option
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -410,6 +413,7 @@ db2file(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (strcmp(db, "running") != 0 &&
|
if (strcmp(db, "running") != 0 &&
|
||||||
strcmp(db, "candidate") != 0 &&
|
strcmp(db, "candidate") != 0 &&
|
||||||
|
strcmp(db, "result") != 0 &&
|
||||||
strcmp(db, "tmp") != 0){
|
strcmp(db, "tmp") != 0){
|
||||||
clicon_err(OE_XML, 0, "Unexpected database: %s", db);
|
clicon_err(OE_XML, 0, "Unexpected database: %s", db);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -539,7 +543,7 @@ xml_tree_prune_unmarked(cxobj *xt,
|
||||||
if (submark)
|
if (submark)
|
||||||
mark++;
|
mark++;
|
||||||
else{ /* Safe with xml_child_each if last */
|
else{ /* Safe with xml_child_each if last */
|
||||||
if (xml_prune(xt, x, 1) < 0)
|
if (xml_purge(x) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
x = xprev;
|
x = xprev;
|
||||||
}
|
}
|
||||||
|
|
@ -816,14 +820,16 @@ xmldb_get_tree(char *dbname,
|
||||||
}
|
}
|
||||||
if (xml_tree_prune_unmarked(xt, NULL) < 0)
|
if (xml_tree_prune_unmarked(xt, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
*xtop = xt;
|
*xtop = xt;
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (1)
|
if (1) /* sanity */
|
||||||
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (0)
|
if (debug)
|
||||||
clicon_xml2file(stdout, xt, 0, 1);
|
clicon_xml2file(stdout, xt, 0, 1);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -841,7 +847,7 @@ xmldb_get_tree(char *dbname,
|
||||||
* The function returns a minimal tree that includes all sub-trees that match
|
* The function returns a minimal tree that includes all sub-trees that match
|
||||||
* xpath.
|
* xpath.
|
||||||
* @param[in] dbname Name of database to search in (filename including dir path
|
* @param[in] dbname Name of database to search in (filename including dir path
|
||||||
* @param[in] xpath String with XPATH syntax (or NULL for all)
|
* @param[in] xpath String with XPATH syntax
|
||||||
* @param[in] yspec Yang specification
|
* @param[in] yspec Yang specification
|
||||||
* @param[out] xtop Single XML tree which xvec points to. Free with xml_free()
|
* @param[out] xtop Single XML tree which xvec points to. Free with xml_free()
|
||||||
* @param[out] xvec Vector of xml trees. Free after use
|
* @param[out] xvec Vector of xml trees. Free after use
|
||||||
|
|
@ -955,9 +961,9 @@ xmldb_get_local(clicon_handle h,
|
||||||
* xpath.
|
* xpath.
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] db running | candidate
|
* @param[in] db running | candidate
|
||||||
* @param[in] xpath String with XPATH syntax (or NULL for all)
|
* @param[in] xpath String with XPATH syntax
|
||||||
* @param[in] vector If set, return list of results in xvec, else single tree.
|
* @param[in] vector If set, return list of results in xvec, else single tree.
|
||||||
* @param[out] xtop XML tree. Freed by xml_free()
|
* @param[out] xtop XML tree. Freed by xml_free()p
|
||||||
* @param[out] xvec Vector of xml trees. Free after use
|
* @param[out] xvec Vector of xml trees. Free after use
|
||||||
* @param[out] xlen Length of vector.
|
* @param[out] xlen Length of vector.
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
|
|
@ -967,7 +973,7 @@ xmldb_get_local(clicon_handle h,
|
||||||
* cxobj **xvec;
|
* cxobj **xvec;
|
||||||
* size_t xlen;
|
* size_t xlen;
|
||||||
* yang_spec *yspec = clicon_dbspec_yang(h);
|
* yang_spec *yspec = clicon_dbspec_yang(h);
|
||||||
* if (xmldb_get(dbname, "/interfaces/interface[name="eth"]", yspec,
|
* if (xmldb_get("running", "/interfaces/interface[name="eth"]",
|
||||||
* 1, &xt, &xvec, &xlen) < 0)
|
* 1, &xt, &xvec, &xlen) < 0)
|
||||||
* err;
|
* err;
|
||||||
* for (i=0; i<xlen; i++){
|
* for (i=0; i<xlen; i++){
|
||||||
|
|
@ -989,6 +995,7 @@ xmldb_get(clicon_handle h,
|
||||||
cxobj ***xvec,
|
cxobj ***xvec,
|
||||||
size_t *xlen)
|
size_t *xlen)
|
||||||
{
|
{
|
||||||
|
assert(xpath);
|
||||||
if (clicon_xmldb_rpc(h))
|
if (clicon_xmldb_rpc(h))
|
||||||
return xmldb_get_rpc(h, db, xpath, vector, xtop, xvec, xlen);
|
return xmldb_get_rpc(h, db, xpath, vector, xtop, xvec, xlen);
|
||||||
else
|
else
|
||||||
|
|
@ -1729,10 +1736,8 @@ main(int argc, char **argv)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
if (clicon_xml_parse_file(0, &xt, "</clicon>") < 0)
|
if (clicon_xml_parse_file(0, &xt, "</clicon>") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
xn = xml_child_i(xt, 0);
|
if (xml_rootchild(xt, 0, &xn) < 0)
|
||||||
xml_prune(xt, xn, 0); /* kludge to remove top-level tag (eg top/clicon) */
|
goto done;
|
||||||
xml_parent_set(xn, NULL);
|
|
||||||
xml_free(xt);
|
|
||||||
if (strcmp(argv[5], "set") == 0)
|
if (strcmp(argv[5], "set") == 0)
|
||||||
op = OP_REPLACE;
|
op = OP_REPLACE;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@
|
||||||
#include "clixon_xml_db.h"
|
#include "clixon_xml_db.h"
|
||||||
#include "clixon_xml_db_rpc.h"
|
#include "clixon_xml_db_rpc.h"
|
||||||
|
|
||||||
|
/*! Make an rpc call to xmldb daemon
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
xmldb_rpc(clicon_handle h,
|
xmldb_rpc(clicon_handle h,
|
||||||
char *data,
|
char *data,
|
||||||
|
|
@ -273,13 +275,9 @@ xmldb_get_rpc(clicon_handle h,
|
||||||
xt = NULL;
|
xt = NULL;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if ((xc = xml_child_i(xt, 0)) != NULL){
|
if (xml_rootchild(xt, 0, xtop) < 0)
|
||||||
xml_prune(xt, xc, 0); /* kludge to remove top-level tag (eg top/clicon) */
|
goto done;
|
||||||
xml_parent_set(xc, NULL);
|
xt = NULL;
|
||||||
if (debug > 1)
|
|
||||||
clicon_xml2file(stderr, xc, 0, 1);
|
|
||||||
}
|
|
||||||
*xtop = xc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
|
||||||
|
|
@ -520,7 +520,9 @@ xml2cvec(cxobj *xt,
|
||||||
* @see cvec2xml This does more but has an internal xml2cvec translation
|
* @see cvec2xml This does more but has an internal xml2cvec translation
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cvec2xml_1(cvec *cvv, char *toptag, cxobj **xt0)
|
cvec2xml_1(cvec *cvv,
|
||||||
|
char *toptag,
|
||||||
|
cxobj **xt0)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
|
|
|
||||||
|
|
@ -784,14 +784,14 @@ xpath_each(cxobj *cxtop,
|
||||||
*
|
*
|
||||||
* @code
|
* @code
|
||||||
* cxobj **xv;
|
* cxobj **xv;
|
||||||
* int xlen;
|
* size_t xlen;
|
||||||
* if ((xv = xpath_vec(cxtop, "//symbol/foo", &xlen)) != NULL) {
|
* if (xpath_vec(cxtop, "//symbol/foo", &xv, &xlen) < 0)
|
||||||
|
* got err;
|
||||||
* for (i=0; i<xlen; i++){
|
* for (i=0; i<xlen; i++){
|
||||||
* xn = xv[i];
|
* xn = xv[i];
|
||||||
* ...
|
* ...
|
||||||
* }
|
* }
|
||||||
* free(xv);
|
* free(xv);
|
||||||
* }
|
|
||||||
* @endcode
|
* @endcode
|
||||||
* Note that although the returned vector must be freed after use, the returned xml
|
* Note that although the returned vector must be freed after use, the returned xml
|
||||||
* trees need not be.
|
* trees need not be.
|
||||||
|
|
|
||||||
|
|
@ -770,7 +770,8 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
*yrestype = NULL; /* Initialization of resolved type that may not be necessary */
|
*yrestype = NULL; /* Initialization of resolved type that may not be necessary */
|
||||||
type = ytype_id(ytype); /* This is the type to resolve */
|
type = ytype_id(ytype); /* This is the type to resolve */
|
||||||
prefix = ytype_prefix(ytype); /* And this its prefix */
|
prefix = ytype_prefix(ytype); /* And this its prefix */
|
||||||
if (ytype->ys_typecache != NULL){
|
/* Cache does not work for eg string length 32 */
|
||||||
|
if (!yang_builtin(type) && ytype->ys_typecache != NULL){
|
||||||
if (yang_type_cache_get(ytype->ys_typecache,
|
if (yang_type_cache_get(ytype->ys_typecache,
|
||||||
yrestype, options, mincv, maxcv, pattern, fraction) < 0)
|
yrestype, options, mincv, maxcv, pattern, fraction) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -803,7 +804,7 @@ yang_type_resolve(yang_stmt *ys,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
while (1){
|
while (1){
|
||||||
/* Check upwards in hierarchy for matcing typedefs */
|
/* Check upwards in hierarchy for matching typedefs */
|
||||||
if ((ys = ys_typedef_up(ys)) == NULL){ /* If reach top */
|
if ((ys = ys_typedef_up(ys)) == NULL){ /* If reach top */
|
||||||
*yrestype = NULL;
|
*yrestype = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue