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
|
|
@ -154,7 +154,7 @@ candidate_commit(clicon_handle h,
|
|||
&td->td_avec, /* added: only in candidate */
|
||||
&td->td_alen,
|
||||
&td->td_scvec, /* changed: original values */
|
||||
&td->td_tcvec, /* changed: wanted values */
|
||||
&td->td_tcvec, /* changed: wanted values */
|
||||
&td->td_clen) < 0)
|
||||
goto done;
|
||||
if (debug)
|
||||
|
|
@ -164,15 +164,17 @@ candidate_commit(clicon_handle h,
|
|||
xn = td->td_dvec[i];
|
||||
xml_flag_set(xn, 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 */
|
||||
xn = td->td_avec[i];
|
||||
xml_flag_set(xn, 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 */
|
||||
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);
|
||||
xn = td->td_tcvec[i];
|
||||
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,10 @@ backend_handle_exit(clicon_handle h)
|
|||
* @see also backend_notify_xml()
|
||||
*/
|
||||
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_subscription *su;
|
||||
|
|
@ -144,7 +147,7 @@ backend_notify(clicon_handle h, char *stream, int level, char *event)
|
|||
* @param[in] h Clicon handle
|
||||
* @param[in] stream Name of event stream. CLICON is predefined as LOG stream
|
||||
* @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
|
||||
* 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()
|
||||
*/
|
||||
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_subscription *su;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ transaction_id(transaction_data td)
|
|||
return ((transaction_data_t *)td)->td_id;
|
||||
}
|
||||
|
||||
/*! Get plugin/application specific callbackargument
|
||||
/*! Get plugin/application specific callback argument
|
||||
* @param[in] td transaction_data
|
||||
* @retval arg callback argument
|
||||
* @note NYI
|
||||
|
|
@ -73,7 +73,7 @@ transaction_arg(transaction_data td)
|
|||
return ((transaction_data_t *)td)->td_arg;
|
||||
}
|
||||
|
||||
/*! Get Source database xml tree
|
||||
/*! Get source database xml tree
|
||||
* @param[in] td transaction_data
|
||||
* @retval src source xml tree containing original state
|
||||
*/
|
||||
|
|
@ -160,7 +160,7 @@ transaction_scvec(transaction_data td)
|
|||
cxobj **
|
||||
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
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
|
|||
MYLIB = $(MYLIBLINK).$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
||||
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)
|
||||
|
||||
all: $(MYLIB) $(APPL) test
|
||||
|
|
|
|||
|
|
@ -61,9 +61,6 @@
|
|||
|
||||
#include "cli_common.h"
|
||||
|
||||
static int xml2csv(FILE *f, cxobj *x, cvec *cvv);
|
||||
//static int xml2csv_raw(FILE *f, cxobj *x);
|
||||
|
||||
/*! Initialize candidate database
|
||||
* We have implemented these:
|
||||
* shared - all users share a common candidate db
|
||||
|
|
@ -334,229 +331,6 @@ cli_validate(clicon_handle h, cvec *vars, cg_var *arg)
|
|||
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
|
||||
*/
|
||||
|
|
@ -949,250 +723,6 @@ discard_changes(clicon_handle h, cvec *cvv, cg_var *arg)
|
|||
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 */
|
||||
static const char *SHOWAS_TXT = "txt";
|
||||
static const char *SHOWAS_XML = "xml";
|
||||
|
|
@ -1292,7 +822,9 @@ cli_notification_cb(int s, void *arg)
|
|||
* XXX: format is a memory leak
|
||||
*/
|
||||
int
|
||||
cli_notify(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||
cli_notify(clicon_handle h,
|
||||
cvec *cvv,
|
||||
cg_var *arg)
|
||||
{
|
||||
char *stream = NULL;
|
||||
int retval = -1;
|
||||
|
|
@ -1395,114 +927,3 @@ cli_notification_register(clicon_handle h,
|
|||
unchunk_group(__FUNCTION__);
|
||||
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"
|
||||
|
||||
/* variable expand function */
|
||||
#define GENERATE_EXPAND_XMLDB "expand_dbvar_dbxml"
|
||||
#define GENERATE_EXPAND_XMLDB "expand_dbvar"
|
||||
|
||||
/*=====================================================================
|
||||
* 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] cvtype Type of the cligen variable
|
||||
* @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
|
||||
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_commit(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 load_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 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_netconf(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_csv(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_ */
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ xml_filter2(cxobj *xfilter,
|
|||
sprev = s = NULL;
|
||||
while ((s = xml_child_each(xparent, s, CX_ELMNT)) != NULL) {
|
||||
if ((f = xml_find(xfilter, xml_name(s))) == NULL){
|
||||
xml_prune(xparent, s, 1);
|
||||
xml_purge(s);
|
||||
s = sprev;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ xml_filter2(cxobj *xfilter,
|
|||
if (xml_filter2(f, s, &remove_s) < 0)
|
||||
return -1;
|
||||
if (remove_s){
|
||||
xml_prune(xparent, s, 1);
|
||||
xml_purge(s);
|
||||
s = sprev;
|
||||
}
|
||||
sprev = s;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ netconf_filter_xmldb(clicon_handle h,
|
|||
switch (foption){
|
||||
case FILTER_SUBTREE:
|
||||
/* 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,
|
||||
"operation-failed",
|
||||
"application",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue