Inital commit

This commit is contained in:
Olof hagsand 2016-02-22 22:17:30 +01:00
parent edc5e091bb
commit d6e393ea58
145 changed files with 58117 additions and 0 deletions

134
apps/cli/Makefile.in Normal file
View file

@ -0,0 +1,134 @@
#
# Makefile
#
# Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
#
# This file is part of CLICON.
#
# CLICON 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.
#
# CLICON 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 CLICON; see the file COPYING. If not, see
# <http://www.gnu.org/licenses/>.
#
#
VPATH = @srcdir@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
CC = @CC@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
prefix = @prefix@
datarootdir = @datarootdir@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
mandir = @mandir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
sysconfdir = @sysconfdir@
includedir = @includedir@
SH_SUFFIX = @SH_SUFFIX@
CLICON_MAJOR = @CLICON_VERSION_MAJOR@
CLICON_MINOR = @CLICON_VERSION_MINOR@
# Use this clicon lib for linking
CLICON_LIB = libclicon.so.$(CLICON_MAJOR).$(CLICON_MINOR)
# Location of system plugins
CLICON_CLI_SYSDIR = $(libdir)/clicon/plugins/cli
# For dependency. A little strange that we rely on it being built in the src dir
# even though it may exist in $(libdir). But the new version may not have been installed yet.
LIBDEPS = $(top_srcdir)/lib/src/$(CLICON_LIB)
LIBS = -L$(top_srcdir)/lib/src @LIBS@ -l:$(CLICON_LIB) -lpthread
CPPFLAGS = @CPPFLAGS@ -fPIC
INCLUDES = -I. -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
APPL = clicon_cli
SRC = cli_main.c
OBJS = $(SRC:.c=.o)
MYNAME = clicon_cli
MYLIBLINK = lib$(MYNAME)$(SH_SUFFIX)
MYLIB = $(MYLIBLINK).$(CLICON_MAJOR).$(CLICON_MINOR)
MYLIBSO = $(MYLIBLINK).$(CLICON_MAJOR)
LIBSRC = cli_plugin.c cli_common.c cli_handle.c cli_generate.c
LIBOBJS = $(LIBSRC:.c=.o)
all: $(MYLIB) $(APPL) test
clean:
rm -f $(OBJS) $(LIBOBJS) *.core $(APPL) $(MYLIB) $(MYLIBSO) $(MYLIBLINK)
distclean: clean
rm -f Makefile *~ .depend
# Put daemon in bin
# Put other executables in libexec/
# Also create a libexec/ directory for writeable/temporary files.
# Put config file in etc/
install: install-lib $(APPL)
install -d $(DESTDIR)$(bindir)
install $(APPL) $(DESTDIR)$(bindir)
install-lib: $(MYLIB)
install -d $(DESTDIR)$(libdir)
install $(MYLIB) $(DESTDIR)$(libdir)
ln -sf $(MYLIB) $(DESTDIR)$(libdir)/$(MYLIBSO) # -l:libclicon_cli.so.2
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclicon_cli.so
install -d $(DESTDIR)$(libdir)/clicon/plugins/cli
install-include: clicon_cli.h clicon_cli_api.h
install -d $(DESTDIR)$(includedir)/clicon
install -m 644 $^ $(DESTDIR)$(includedir)/clicon
uninstall:
rm -f $(bindir)/$(APPL)
rm -f $(libdir)/$(MYLIB)
rm -f $(includedir)/clicon/*
.SUFFIXES:
.SUFFIXES: .c .o
.c.o:
$(CC) $(INCLUDES) $(CPPFLAGS) -D__PROGRAM__=\"$(APPL)\" -DCLICON_CLI_SYSDIR=\"$(CLICON_CLI_SYSDIR)\" $(CFLAGS) -c $<
# Just link test programs
test.c :
echo "main(){}" > $@
test: test.c $(LIBOBJ)
$(CC) $(INCLUDES) $(LDFLAGS) $< $(LIBOBJ) -L. -l:$(MYLIB) $(LIBS) -o $@
$(APPL): $(OBJS) $(MYLIBLINK) $(LIBDEPS)
$(CC) $(LDFLAGS) $(OBJS) -L. -l:$(MYLIB) $(LIBS) -o $@
$(MYLIB) : $(LIBOBJS)
$(CC) -shared -Wl,-soname,$(MYLIBSO) -o $@ $(LIBOBJS) $(LIBS) -Wl,-soname=$(MYLIBSO)
# link-name is needed for application linking, eg for clicon_cli and clicon_config
$(MYLIBLINK) : $(MYLIB)
# ln -sf $(MYLIB) $(MYLIBSO)
# ln -sf $(MYLIB) $@
TAGS:
find . -name '*.[chyl]' -print | etags -
depend:
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(SRC) $(APPSRC) > .depend
#include .depend

1930
apps/cli/cli_common.c Normal file

File diff suppressed because it is too large Load diff

33
apps/cli/cli_common.h Normal file
View file

@ -0,0 +1,33 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifndef _CLI_COMMON_H_
#define _CLI_COMMON_H_
void cli_signal_block(clicon_handle h);
void cli_signal_unblock(clicon_handle h);
/* If you do not find a function here it may be in clicon_cli_api.h which is
the external API */
#endif /* _CLI_COMMON_H_ */

689
apps/cli/cli_generate.c Normal file
View file

@ -0,0 +1,689 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
* Translation between database specs
* dbspec_key yang_spec CLIgen parse_tree
* +-------------+ key2yang +-------------+ yang2cli +-------------+
* | keyspec | -------------> | | ------------> | cli |
* | A[].B !$a | yang2key | list{key A;}| | syntax |
* +-------------+ <------------ +-------------+ +-------------+
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/param.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_generate.h"
/* This is the default callback function. But this is typically overwritten */
#define GENERATE_CALLBACK "cli_set"
/* variable expand function */
#define GENERATE_EXPAND_LVEC "expand_dbvar_auto"
#define GENERATE_EXPAND_XMLDB "expand_dbvar_dbxml"
/*=====================================================================
* YANG generate CLI
*=====================================================================*/
#if 0 /* examples/ntp */
ntp("Network Time Protocol"),cli_set("ntp");{
logging("Configure NTP message logging"),cli_set("ntp.logging");{
status (<status:bool>),cli_set("ntp.logging $status:bool");
}
server("Configure NTP Server") (<ipv4addr:ipv4addr>("IPv4 address of peer")),cli_set("ntp.server[] $!ipv4addr:ipv4addr");
}
#endif
#if 0 /* examples/datamodel */
WITH COMPLETION:
a (<x:number>|<x:number expand_dbvar_auto("candidate a[] $!x")>),cli_set("a[] $!x");{
b,cli_set("a[].b $!x");{
y (<y:string>|<y:string expand_dbvar_auto("candidate a[].b $!x $y")>),cli_set("a[].b $!x $y");
}
z (<z:string>|<z:string expand_dbvar_auto("candidate a[] $!x $z")>),cli_set("a[] $!x $z");
}
#endif
#ifndef HAVE_CLIGEN_MAX2STR /* XXX cligen 3.6 feature */
/*! Print max value of a CLIgen variable type as string
* @param[in] type CLIgen variable type
* @param[out] str Max value printed in this string
* @param[in] size Length of 'str'
* @retval len How many bytes printed
* @see cvtype_max2str_dup
* You can use str=NULL to get the expected length.
* The number of (potentially if str=NULL) written bytes is returned.
*/
static int
cvtype_max2str(enum cv_type type, char *str, size_t size)
{
int len = 0;
switch (type){
case CGV_INT8:
len = snprintf(str, size, "%" PRId8, INT8_MAX);
break;
case CGV_INT16:
len = snprintf(str, size, "%" PRId16, INT16_MAX);
break;
case CGV_INT32:
len = snprintf(str, size, "%" PRId32, INT32_MAX);
break;
case CGV_INT64:
len = snprintf(str, size, "%" PRId64, INT64_MAX);
break;
case CGV_UINT8:
len = snprintf(str, size, "%" PRIu8, UINT8_MAX);
break;
case CGV_UINT16:
len = snprintf(str, size, "%" PRIu16, UINT16_MAX);
break;
case CGV_UINT32:
len = snprintf(str, size, "%" PRIu32, UINT32_MAX);
break;
case CGV_UINT64:
len = snprintf(str, size, "%" PRIu64, UINT64_MAX);
break;
case CGV_DEC64:
len = snprintf(str, size, "%" PRId64 ".0", INT64_MAX);
break;
case CGV_BOOL:
len = snprintf(str, size, "true");
break;
default:
break;
}
return len;
}
/*! Print max value of a CLIgen variable type as string
*
* The string should be freed after use.
* @param[in] type CLIgen variable type
* @retval str Malloced string containing value. Should be freed after use.
* @see cvtype_max2str
*/
static char *
cvtype_max2str_dup(enum cv_type type)
{
int len;
char *str;
if ((len = cvtype_max2str(type, NULL, 0)) < 0)
return NULL;
if ((str = (char *)malloc (len+1)) == NULL)
return NULL;
memset (str, '\0', len+1);
if ((cvtype_max2str(type, str, len+1)) < 0){
free(str);
return NULL;
}
return str;
}
#endif /* HAVE_CLIGEN_MAX2STR */
/*! Create cligen variable expand entry with xmlkey format string as argument
* @param[in] h clicon handle
* @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
*/
static int
cli_expand_var_generate(clicon_handle h,
yang_stmt *ys,
enum cv_type cvtype,
cbuf *cb0)
{
int retval = -1;
char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0)
goto done;
cprintf(cb0, "|<%s:%s %s(\"candidate %s\")>",
ys->ys_argument,
cv_type2str(cvtype),
GENERATE_EXPAND_XMLDB,
xkfmt);
retval = 0;
done:
if (xkfmt)
free(xkfmt);
return retval;
}
/*! Create callback with xmlkey format string as argument
* @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand
* @param[in] cb0 The string where the result format string is inserted.
* @see cli_dbxml This is where the xmlkeyfmt string is used
*/
static int
cli_callback_generate(clicon_handle h,
yang_stmt *ys,
cbuf *cb0)
{
int retval = -1;
char *xkfmt = NULL;
if (yang2xmlkeyfmt(ys, &xkfmt) < 0)
goto done;
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, xkfmt);
retval = 0;
done:
if (xkfmt)
free(xkfmt);
return retval;
}
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
cbuf *cb0,
enum genmodel_type gt,
int level);
/*
* Check for completion (of already existent values), ranges (eg range[min:max]) and
* patterns, (eg regexp:"[0.9]*").
*/
static int
yang2cli_var_sub(clicon_handle h,
yang_stmt *ys,
cbuf *cb0,
char *description,
enum cv_type cvtype,
yang_stmt *ytype, /* resolved type */
int options,
cg_var *mincv,
cg_var *maxcv,
char *pattern,
uint8_t fraction_digits
)
{
int retval = -1;
char *type;
char *r;
yang_stmt *yi = NULL;
int i = 0;
char *cvtypestr;
int completion;
/* enumeration already gives completion */
if (cvtype == CGV_VOID){
retval = 0;
goto done;
}
type = ytype?ytype->ys_argument:NULL;
if (type)
completion = clicon_cli_genmodel_completion(h) &&
strcmp(type, "enumeration") != 0 &&
strcmp(type, "bits") != 0;
else
completion = clicon_cli_genmodel_completion(h);
if (completion)
cprintf(cb0, "(");
cvtypestr = cv_type2str(cvtype);
cprintf(cb0, "<%s:%s", ys->ys_argument, cvtypestr);
#if 0
if (type && (strcmp(type, "identityref") == 0)){
yang_stmt *ybase;
if ((ybase = yang_find((yang_node*)ytype, Y_BASE, NULL)) != NULL){
cprintf(cb0, " choice:");
i = 0;
/* for every found identity derived from base-type , do: */
{
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
continue;
if (i)
cprintf(cb0, "|");
cprintf(cb0, "%s", yi->ys_argument);
i++;
}
}
}
#endif
if (type && (strcmp(type, "enumeration") == 0 || strcmp(type, "bits") == 0)){
cprintf(cb0, " choice:");
i = 0;
while ((yi = yn_each((yang_node*)ytype, yi)) != NULL){
if (yi->ys_keyword != Y_ENUM && yi->ys_keyword != Y_BIT)
continue;
if (i)
cprintf(cb0, "|");
cprintf(cb0, "%s", yi->ys_argument);
i++;
}
}
if (options & YANG_OPTIONS_FRACTION_DIGITS)
cprintf(cb0, " fraction-digits:%u", fraction_digits);
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
cprintf(cb0, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
if (mincv){
if ((r = cv2str_dup(mincv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
cprintf(cb0, "%s:", r);
free(r);
}
if (maxcv != NULL){
if ((r = cv2str_dup(maxcv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
}
else{ /* Cligen does not have 'max' keyword in range so need to find actual
max value of type if yang range expression is 0..max */
if ((r = cvtype_max2str_dup(cvtype)) == NULL){
clicon_err(OE_UNIX, errno, "cvtype_max2str");
goto done;
}
}
cprintf(cb0, "%s]", r);
free(r);
}
if (options & YANG_OPTIONS_PATTERN)
cprintf(cb0, " regexp:\"%s\"", pattern);
cprintf(cb0, ">");
if (description)
cprintf(cb0, "(\"%s\")", description);
if (completion){
if (cli_expand_var_generate(h, ys, cvtype, cb0) < 0)
goto done;
if (description)
cprintf(cb0, "(\"%s\")", description);
cprintf(cb0, ")");
}
retval = 0;
done:
return retval;
}
/*! Translate a yang leaf to cligen variable
* Make a type lookup and complete a cligen variable expression such as <a:string>.
* One complication is yang union, that needs a recursion since it consists of sub-types.
* eg type union{ type int32; type string } --> (<x:int32>| <x:string>)
*/
static int
yang2cli_var(clicon_handle h,
yang_stmt *ys,
cbuf *cb0,
char *description)
{
int retval = -1;
char *type; /* orig type */
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
cg_var *mincv = NULL;
cg_var *maxcv = NULL;
char *pattern = NULL;
yang_stmt *yt = NULL;
yang_stmt *yrt;
uint8_t fraction_digits = 0;
enum cv_type cvtype;
int options = 0;
int i;
if (yang_type_get(ys, &type, &yrestype,
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
/* Note restype can be NULL here for example with unresolved hardcoded uuid */
if (restype && strcmp(restype, "union") == 0){
/* Union: loop over resolved type's sub-types */
cprintf(cb0, "(");
yt = NULL;
i = 0;
while ((yt = yn_each((yang_node*)yrestype, yt)) != NULL){
if (yt->ys_keyword != Y_TYPE)
continue;
if (i++)
cprintf(cb0, "|");
if (yang_type_resolve(ys, yt, &yrt,
&options, &mincv, &maxcv, &pattern, &fraction_digits) < 0)
goto done;
restype = yrt?yrt->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0)
goto done;
if ((retval = yang2cli_var_sub(h, ys, cb0, description, cvtype, yrt,
options, mincv, maxcv, pattern, fraction_digits)) < 0)
goto done;
}
cprintf(cb0, ")");
}
else
if ((retval = yang2cli_var_sub(h, ys, cb0, description, cvtype, yrestype,
options, mincv, maxcv, pattern, fraction_digits)) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*!
* @param[in] h Clicon handle
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not.
*/
static int
yang2cli_leaf(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level,
int callback)
{
yang_stmt *yd; /* description */
int retval = -1;
char *description = NULL;
/* description */
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
description = yd->ys_argument;
cprintf(cbuf, "%*s", level*3, "");
if (gt == GT_VARS|| gt == GT_ALL){
cprintf(cbuf, "%s", ys->ys_argument);
if (yd != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
cprintf(cbuf, " ");
yang2cli_var(h, ys, cbuf, description);
}
else
yang2cli_var(h, ys, cbuf, description);
if (callback){
if (cli_callback_generate(h, ys, cbuf) < 0)
goto done;
cprintf(cbuf, ";\n");
}
retval = 0;
done:
return retval;
}
static int
yang2cli_container(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
yang_stmt *yc;
yang_stmt *yd;
int i;
int retval = -1;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
if (cli_callback_generate(h, ys, cbuf) < 0)
goto done;
cprintf(cbuf, ";{\n");
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
cprintf(cbuf, "%*s}\n", level*3, "");
retval = 0;
done:
return retval;
}
static int
yang2cli_list(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
yang_stmt *yc;
yang_stmt *yd;
yang_stmt *ykey;
yang_stmt *yleaf;
int i;
cg_var *cvi;
char *keyname;
cvec *cvk = NULL; /* vector of index keys */
int retval = -1;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL)
cprintf(cbuf, "(\"%s\")", yd->ys_argument);
/* Loop over all key variables */
if ((ykey = yang_find((yang_node*)ys, Y_KEY, NULL)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key", ys->ys_argument);
goto done;
}
/* The value is a list of keys: <key>[ <key>]* */
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
goto done;
cvi = NULL;
/* Iterate over individual keys */
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if ((yleaf = yang_find((yang_node*)ys, Y_LEAF, keyname)) == NULL){
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
ys->ys_argument, keyname);
goto done;
}
/* Print key variable now, and skip it in loop below
Note, only print callback on last statement
*/
if (yang2cli_leaf(h, yleaf, cbuf, gt==GT_VARS?GT_NONE:gt, level+1,
cvec_next(cvk, cvi)?0:1) < 0)
goto done;
}
cprintf(cbuf, "{\n");
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL){
/* cvk is a cvec of strings containing variable names
yc is a leaf that may match one of the values of cvk.
*/
cvi = NULL;
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
keyname = cv_string_get(cvi);
if (strcmp(keyname, yc->ys_argument) == 0)
break;
}
if (cvi != NULL)
continue;
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
}
cprintf(cbuf, "%*s}\n", level*3, "");
retval = 0;
done:
if (cvk)
cvec_free(cvk);
return retval;
}
/*! Generate cli code for yang choice statement
Example:
choice interface-type {
container ethernet { ... }
container fddi { ... }
}
@Note Removes 'meta-syntax' from cli syntax. They are not shown when xml is
translated to cli. and therefore input-syntax != output syntax. Which is bad
*/
static int
yang2cli_choice(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level)
{
int retval = -1;
yang_stmt *yc;
int i;
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL){
switch (yc->ys_keyword){
case Y_CASE:
if (yang2cli_stmt(h, yc, cbuf, gt, level+2) < 0)
goto done;
break;
case Y_CONTAINER:
case Y_LEAF:
case Y_LEAF_LIST:
case Y_LIST:
default:
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
break;
}
}
retval = 0;
done:
return retval;
}
/*! Translate yang-stmt to CLIgen syntax.
*/
static int
yang2cli_stmt(clicon_handle h,
yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt,
int level /* indentation level for pretty-print */
)
{
yang_stmt *yc;
int retval = -1;
int i;
if (yang_config(ys)){
switch (ys->ys_keyword){
case Y_GROUPING:
case Y_RPC:
case Y_AUGMENT:
return 0;
break;
case Y_CONTAINER:
if (yang2cli_container(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_LIST:
if (yang2cli_list(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_CHOICE:
if (yang2cli_choice(h, ys, cbuf, gt, level) < 0)
goto done;
break;
case Y_LEAF_LIST:
case Y_LEAF:
if (yang2cli_leaf(h, ys, cbuf, gt, level, 1) < 0)
goto done;
break;
default:
for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0)
goto done;
break;
}
}
retval = 0;
done:
return retval;
}
/*! Translate from a yang specification into a CLIgen syntax.
*
* Print a CLIgen syntax to cbuf string, then parse it.
* @param gt - how to generate CLI:
* VARS: generate keywords for regular vars only not index
* ALL: generate keywords for all variables including index
*/
int
yang2cli(clicon_handle h,
yang_spec *yspec,
parse_tree *ptnew,
enum genmodel_type gt)
{
cbuf *cbuf;
int i;
int retval = -1;
yang_stmt *ymod = NULL;
cvec *globals; /* global variables from syntax */
if ((cbuf = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "%s: cbuf_new", __FUNCTION__);
goto done;
}
/* Traverse YANG specification: loop through statements */
for (i=0; i<yspec->yp_len; i++)
if ((ymod = yspec->yp_stmt[i]) != NULL){
if (yang2cli_stmt(h, ymod, cbuf, gt, 0) < 0)
goto done;
}
clicon_debug(1, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cbuf));
/* Parse the buffer using cligen parser. XXX why this?*/
if ((globals = cvec_new(0)) == NULL)
goto done;
/* load cli syntax */
if (cligen_parse_str(cli_cligen(h), cbuf_get(cbuf),
"yang2cli", ptnew, globals) < 0)
goto done;
cvec_free(globals);
/* handle=NULL for global namespace, this means expand callbacks must be in
CLICON namespace, not in a cli frontend plugin. */
if (cligen_expand_str2fn(*ptnew, expand_str2fn, NULL) < 0)
goto done;
retval = 0;
done:
cbuf_free(cbuf);
return retval;
}

32
apps/cli/cli_generate.h Normal file
View file

@ -0,0 +1,32 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLI_GENERATE_H_
#define _CLI_GENERATE_H_
/*
* Prototypes
*/
int yang2cli(clicon_handle h, yang_spec *yspec, parse_tree *ptnew,
enum genmodel_type gt);
#endif /* _CLI_GENERATE_H_ */

295
apps/cli/cli_handle.c Normal file
View file

@ -0,0 +1,295 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include <dlfcn.h>
#include <dirent.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_handle.h"
#define CLICON_MAGIC 0x99aafabe
#define handle(h) (assert(clicon_handle_check(h)==0),(struct cli_handle *)(h))
#define cligen(h) (handle(h)->cl_cligen)
/*
* cli_handle
* first part of this is header, same for clicon_handle and config_handle.
* Access functions for common fields are found in clicon lib: clicon_options.[ch]
* This file should only contain access functions for the _specific_
* entries in the struct below.
*/
struct cli_handle {
int cl_magic; /* magic (HDR)*/
clicon_hash_t *cl_copt; /* clicon option list (HDR) */
clicon_hash_t *cl_data; /* internal clicon data (HDR) */
/* ------ end of common handle ------ */
cligen_handle cl_cligen; /* cligen handle */
int cl_send2backend; /* Send changes to configuration daemon */
enum candidate_db_type cl_candidate_type;
cli_syntax_t *cl_stx; /* syntax structure */
};
/*
* cli_handle_init
* returns a clicon handle for other CLICON API calls
*/
clicon_handle
cli_handle_init(void)
{
struct cli_handle *cl;
cligen_handle clih = NULL;
clicon_handle h = NULL;
if ((cl = (struct cli_handle *)clicon_handle_init0(sizeof(struct cli_handle))) == NULL)
return NULL;
if ((clih = cligen_init()) == NULL){
clicon_handle_exit((clicon_handle)cl);
goto done;
}
cligen_userhandle_set(clih, cl);
cl->cl_cligen = clih;
cl->cl_candidate_type = CANDIDATE_DB_SHARED;
h = (clicon_handle)cl;
done:
return h;
}
/*
* cli_handle_exit
* frees clicon handle
*/
int
cli_handle_exit(clicon_handle h)
{
cligen_handle ch = cligen(h);
clicon_handle_exit(h); /* frees h and options */
cligen_exit(ch);
return 0;
}
/*----------------------------------------------------------
* cli-specific handle access functions
*----------------------------------------------------------*/
/*! Send changes to configuration daemon or let client handle it itself. Default is 1 */
int
cli_set_send2backend(clicon_handle h, int send2backend)
{
struct cli_handle *cl = handle(h);
cl->cl_send2backend = send2backend;
return 0;
}
/*! Get status of whether to send changes to configuration daemon. */
int
cli_send2backend(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_send2backend;
}
enum candidate_db_type
cli_candidate_type(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_candidate_type;
}
int
cli_set_candidate_type(clicon_handle h, enum candidate_db_type type)
{
struct cli_handle *cl = handle(h);
cl->cl_candidate_type = type;
return 0;
}
/* Current syntax-group */
cli_syntax_t *
cli_syntax(clicon_handle h)
{
struct cli_handle *cl = handle(h);
return cl->cl_stx;
}
int
cli_syntax_set(clicon_handle h, cli_syntax_t *stx)
{
struct cli_handle *cl = handle(h);
cl->cl_stx = stx;
return 0;
}
/*----------------------------------------------------------
* cligen access functions
*----------------------------------------------------------*/
cligen_handle
cli_cligen(clicon_handle h)
{
return cligen(h);
}
/*
* cli_interactive and clicon_eval
*/
int
cli_exiting(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_exiting(ch);
}
/*
* cli_common.c: cli_quit
* cli_interactive()
*/
int
cli_set_exiting(clicon_handle h, int exiting)
{
cligen_handle ch = cligen(h);
return cligen_exiting_set(ch, exiting);
}
char
cli_comment(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_comment(ch);
}
char
cli_set_comment(clicon_handle h, char c)
{
cligen_handle ch = cligen(h);
return cligen_comment_set(ch, c);
}
char
cli_tree_add(clicon_handle h, char *tree, parse_tree pt)
{
cligen_handle ch = cligen(h);
return cligen_tree_add(ch, tree, pt);
}
char *
cli_tree_active(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_tree_active(ch);
}
int
cli_tree_active_set(clicon_handle h, char *treename)
{
cligen_handle ch = cligen(h);
return cligen_tree_active_set(ch, treename);
}
parse_tree *
cli_tree(clicon_handle h, char *name)
{
cligen_handle ch = cligen(h);
return cligen_tree(ch, name);
}
int
cli_parse_file(clicon_handle h,
FILE *f,
char *name, /* just for errs */
parse_tree *pt,
cvec *globals)
{
cligen_handle ch = cligen(h);
return cligen_parse_file(ch, f, name, pt, globals);
}
int
cli_susp_hook(clicon_handle h, cli_susphook_t *fn)
{
cligen_handle ch = cligen(h);
/* This assume first arg of fn can be treated as void* */
return cligen_susp_hook(ch, (cligen_susp_cb_t*)fn);
}
char *
cli_nomatch(clicon_handle h)
{
cligen_handle ch = cligen(h);
return cligen_nomatch(ch);
}
int
cli_prompt_set(clicon_handle h, char *prompt)
{
cligen_handle ch = cligen(h);
return cligen_prompt_set(ch, prompt);
}
int
cli_logsyntax_set(clicon_handle h, int status)
{
cligen_handle ch = cligen(h);
return cligen_logsyntax_set(ch, status);
}

58
apps/cli/cli_handle.h Normal file
View file

@ -0,0 +1,58 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifndef _CLI_HANDLE_H_
#define _CLI_HANDLE_H_
/*
* Prototypes
* Internal prototypes. For exported functions see clicon_cli_api.h
*/
char cli_tree_add(clicon_handle h, char *tree, parse_tree pt);
int cli_parse_file(clicon_handle h,
FILE *f,
char *name, /* just for errs */
parse_tree *pt,
cvec *globals);
char *cli_tree_active(clicon_handle h);
int cli_tree_active_set(clicon_handle h, char *treename);
parse_tree *cli_tree(clicon_handle h, char *name);
int cli_susp_hook(clicon_handle h, cli_susphook_t *fn);
char *cli_nomatch(clicon_handle h);
int cli_prompt_set(clicon_handle h, char *prompt);
int cli_logsyntax_set(clicon_handle h, int status);
/* Internal functions for handling cli groups */
cli_syntax_t *cli_syntax(clicon_handle h);
int cli_syntax_set(clicon_handle h, cli_syntax_t *stx);
#endif /* _CLI_HANDLE_H_ */

407
apps/cli/cli_main.c Normal file
View file

@ -0,0 +1,407 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "clicon_config.h" /* generated by config & autoconf */
#endif
#include <stdio.h>
#define __USE_GNU /* strverscmp */
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <assert.h>
/* cligen */
#include <cligen/cligen.h>
/* clicon */
#include <clicon/clicon.h>
#include "clicon_cli_api.h"
#include "cli_plugin.h"
#include "cli_generate.h"
#include "cli_common.h"
#include "cli_handle.h"
/* Command line options to be passed to getopt(3) */
#define CLI_OPTS "hD:f:F:1u:d:m:cP:qpGLl:"
static int
cli_terminate(clicon_handle h)
{
yang_spec *yspec;
if ((yspec = clicon_dbspec_yang(h)) != NULL)
yspec_free(yspec);
cli_plugin_finish(h);
exit_candidate_db(h);
cli_handle_exit(h);
return 0;
}
/*
* cli_sig_term
* Unlink pidfile and quit
*/
static void
cli_sig_term(int arg)
{
clicon_log(LOG_NOTICE, "%s: %u Terminated (killed by sig %d)",
__PROGRAM__, getpid(), arg);
exit(1);
}
/*
* Setup signal handlers
*/
static void
cli_signal_init (clicon_handle h)
{
cli_signal_block(h);
set_signal(SIGTERM, cli_sig_term, NULL);
}
static void
cli_interactive(clicon_handle h)
{
int res;
char *cmd;
char *new_mode;
int result;
/* Loop through all commands */
while(!cli_exiting(h)) {
// save_mode =
new_mode = cli_syntax_mode(h);
if ((cmd = clicon_cliread(h)) == NULL) {
cli_set_exiting(h, 1); /* EOF */
break;
}
if ((res = clicon_parse(h, cmd, &new_mode, &result)) < 0)
break;
}
}
static void
usage(char *argv0, clicon_handle h)
{
char *confsock = clicon_sock(h);
char *plgdir = clicon_cli_dir(h);
fprintf(stderr, "usage:%s [options] [commands]\n"
"where commands is a CLI command or options passed to the main plugin\n"
"where options are\n"
"\t-h \t\tHelp\n"
"\t-D <level> \tDebug\n"
"\t-f <file> \tConfig-file (mandatory)\n"
"\t-F <file> \tRead commands from file (default stdin)\n"
"\t-1\t\tDo not enter interactive mode\n"
"\t-u <sockpath>\tconfig UNIX domain path (default: %s)\n"
"\t-d <dir>\tSpecify plugin directory (default: %s)\n"
"\t-m <mode>\tSpecify plugin syntax mode\n"
"\t-c \t\tWrite to candidate db directly, not via config backend\n"
"\t-P <dbname> \tWrite to private database\n"
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
"\t-p \t\tPrint database yang specification\n"
"\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n"
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
"\t-l <s|e|o> \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n",
argv0,
confsock ? confsock : "none",
plgdir ? plgdir : "none"
);
exit(1);
}
/*
*/
int
main(int argc, char **argv)
{
char c;
enum candidate_db_type dbtype;
char private_db[MAXPATHLEN];
int once;
char *tmp;
char *argv0 = argv[0];
clicon_handle h;
int printspec = 0;
int printgen = 0;
int logclisyntax = 0;
int help = 0;
char *treename;
char *running_db;
int logdst = CLICON_LOG_STDERR;
/* Defaults */
/* In the startup, logs to stderr & debug flag set later */
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
/* Initiate CLICON handle */
if ((h = cli_handle_init()) == NULL)
goto done;
if (cli_plugin_init(h) != 0)
goto done;
dbtype = CANDIDATE_DB_SHARED;
once = 0;
private_db[0] = '\0';
cli_set_send2backend(h, 1); /* send changes to config daemon */
cli_set_comment(h, '#'); /* Default to handle #! clicon_cli scripts */
/*
* First-step command-line options for help, debug, config-file and log,
*/
optind = 1;
opterr = 0;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1)
switch (c) {
case '?':
case 'h':
/* Defer the call to usage() to later. Reason is that for helpful
text messages, default dirs, etc, are not set until later.
But this means that we need to check if 'help' is set before
exiting, and then call usage() before exit.
*/
help = 1;
break;
case 'D' : /* debug */
if (sscanf(optarg, "%d", &debug) != 1)
usage(argv[0], h);
break;
case 'f': /* config file */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
break;
case 'l': /* Log destination: s|e|o */
switch (optarg[0]){
case 's':
logdst = CLICON_LOG_SYSLOG;
break;
case 'e':
logdst = CLICON_LOG_STDERR;
break;
case 'o':
logdst = CLICON_LOG_STDOUT;
break;
default:
usage(argv[0], h);
}
break;
}
/*
* Logs, error and debug to stderr or syslog, set debug level
*/
clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst);
clicon_debug_init(debug, NULL);
/* Find and read configfile */
if (clicon_options_main(h) < 0){
if (help)
usage(argv[0], h);
return -1;
}
/* Now rest of options */
opterr = 0;
optind = 1;
while ((c = getopt(argc, argv, CLI_OPTS)) != -1){
switch (c) {
case 'D' : /* debug */
case 'f': /* config file */
case 'l': /* Log destination */
break; /* see above */
case 'F': /* read commands from file */
if (freopen(optarg, "r", stdin) == NULL){
cli_output(stderr, "freopen: %s\n", strerror(errno));
return -1;
}
break;
case '1' : /* Quit after reading database once - dont wait for events */
once = 1;
break;
case 'u': /* config unix domain path/ ip host */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_SOCK", optarg);
break;
case 'd': /* Plugin directory: overrides configfile */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CLI_DIR", optarg);
break;
case 'm': /* CLI syntax mode */
if (!strlen(optarg))
usage(argv[0], h);
clicon_option_str_set(h, "CLICON_CLI_MODE", optarg);
break;
case 'c' : /* No config daemon (used in bootstrapping and file load) */
cli_set_send2backend(h, 0);
break;
case 'P' : /* load to private database with given name */
dbtype = CANDIDATE_DB_PRIVATE;
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", optarg); /* override default */
break;
case 'q' : /* Quiet mode */
clicon_option_str_set(h, "CLICON_QUIET", "on");
break;
case 'p' : /* Print spec */
printspec++;
break;
case 'G' : /* Print generated CLI syntax */
printgen++;
break;
case 'L' : /* Debug print dynamic CLI syntax */
logclisyntax++;
break;
default:
usage(argv[0], h);
break;
}
}
argc -= optind;
argv += optind;
/* Defer: Wait to the last minute to print help message */
if (help)
usage(argv[0], h);
/* Setup signal handlers */
cli_signal_init(h);
/* Backward compatible mode, do not include keys in cgv-arrays in callbacks.
Should be 0 but default is 1 since all legacy apps use 1
Test legacy before shifting default to 0
*/
cv_exclude_keys(clicon_cli_varonly(h));
/* Parse db specification as cli*/
if (yang_spec_main(h, stdout, printspec) < 0)
goto done;
/* Check plugin directory */
if (clicon_cli_dir(h) == NULL){
clicon_err(OE_PLUGIN, 0, "clicon_cli_dir not defined");
goto done;
}
/* Create tree generated from dataspec */
if (clicon_cli_genmodel(h)){
yang_spec *yspec; /* yang spec */
parse_tree pt = {0,}; /* cli parse tree */
if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No YANG DB_SPEC");
goto done;
}
/* Create cli command tree from dbspec */
if (yang2cli(h, yspec, &pt, clicon_cli_genmodel_type(h)) < 0)
goto done;
treename = chunk_sprintf(__FUNCTION__, "datamodel:%s", clicon_dbspec_name(h));
cli_tree_add(h, treename, pt);
if (printgen)
cligen_print(stdout, pt, 1);
}
/* Initialize cli syntax */
if (cli_syntax_load(h) < 0)
goto done;
/* Set syntax mode if specified from command-line or config-file. */
if (clicon_option_exists(h, "CLICON_CLI_MODE"))
if ((tmp = clicon_cli_mode(h)) != NULL)
if (cli_set_syntax_mode(h, tmp) == 0) {
fprintf(stderr, "FATAL: Failed to set syntax mode '%s'\n", tmp);
goto done;
}
if (!cli_syntax_mode(h)){
fprintf (stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
goto done;
}
if (cli_tree(h, cli_syntax_mode(h)) == NULL){
fprintf (stderr, "FATAL: No such cli mode: %s\n", cli_syntax_mode(h));
goto done;
}
/* Initialize databases */
if ((running_db = clicon_running_db(h)) == NULL)
goto done;
if (strlen(private_db))
clicon_option_str_set(h, "CLICON_CANDIDATE_DB", private_db);
if (!cli_send2backend(h))
if (db_init(running_db) < 0){
fprintf (stderr, "FATAL: Could not init running_db. (Run as root?)\n");
goto done;
}
/* A client does not have access to the candidate (and running)
databases if both these conditions are true:
1. clicon_sock_family(h) == AF_INET[6]
2. cli_send2backend(h) == 1
*/
if (clicon_sock_family(h) == AF_UNIX || cli_send2backend(h)==0)
if (init_candidate_db(h, dbtype) < 0)
return -1;
if (logclisyntax)
cli_logsyntax_set(h, logclisyntax);
if (debug)
clicon_option_dump(h, debug);
/* Call start function in all plugins before we go interactive
Pass all args after the standard options to plugin_start
*/
tmp = *(argv-1);
*(argv-1) = argv0;
cli_plugin_start(h, argc+1, argv-1);
*(argv-1) = tmp;
/* Launch interfactive event loop, unless -1 */
if (once == 0)
cli_interactive(h);
done:
// Gets in your face if we log on stderr
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
clicon_log(LOG_NOTICE, "%s: %u Terminated\n", __PROGRAM__, getpid());
cli_terminate(h);
return 0;
}

1153
apps/cli/cli_plugin.c Normal file

File diff suppressed because it is too large Load diff

90
apps/cli/cli_plugin.h Normal file
View file

@ -0,0 +1,90 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLI_PLUGIN_H_
#define _CLI_PLUGIN_H_
#include <stdio.h>
#include <inttypes.h>
#include <netinet/in.h>
/* clicon generic callback pointer */
typedef void (clicon_callback_t)(clicon_handle h);
/* clicon_set value callback */
typedef int (cli_valcb_t)(cvec *vars, cg_var *cgv, cg_var *arg);
/* specific to cli. For common see clicon_plugin.h */
/* Hook to get prompt format before each getline */
typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
/* Ctrl-Z hook from getline() */
typedef int (cli_susphook_t)(clicon_handle, char *, int, int *);
/* CLIgen parse failure hook. Retry other mode? */
typedef char *(cli_parsehook_t)(clicon_handle, char *, char *);
typedef struct {
qelem_t csm_qelem; /* List header */
char csm_name[256]; /* Syntax mode name */
char csm_prompt[CLI_PROMPT_LEN]; /* Prompt for mode */
int csm_nsyntax; /* Num syntax specs registered by plugin */
parse_tree csm_pt; /* CLIgen parse tree */
} cli_syntaxmode_t;
/* A plugin list object */
struct cli_plugin {
qelem_t cp_qelem; /* List header */
char cp_name[256]; /* Plugin name */
void *cp_handle; /* Dynamic object handle */
};
/* Plugin group object */
typedef struct {
char stx_cnklbl[128]; /* Plugin group name */
int stx_nplugins; /* Number of plugins */
struct cli_plugin *stx_plugins; /* List of plugins */
int stx_nmodes; /* Number of syntax modes */
cli_syntaxmode_t *stx_active_mode; /* Current active syntax mode */
cli_syntaxmode_t *stx_modes; /* List of syntax modes */
cli_prompthook_t *stx_prompt_hook; /* Prompt hook */
cli_parsehook_t *stx_parse_hook; /* Parse mode hook */
cli_susphook_t *stx_susp_hook; /* Ctrl-Z hook from getline() */
} cli_syntax_t;
expand_cb *expand_str2fn(char *name, void *handle, char **error);
int cli_plugin_start(clicon_handle, int argc, char **argv);
int cli_plugin_init(clicon_handle h);
int clicon_eval(clicon_handle h, char *cmd, cg_obj *match_obj, cvec *vr);
int clicon_parse(clicon_handle h, char *cmd, char **mode, int *result);
char *clicon_cliread(clicon_handle h);
int cli_plugin_finish(clicon_handle h);
#endif /* _CLI_PLUGIN_H_ */

59
apps/cli/clicon_cli.h Normal file
View file

@ -0,0 +1,59 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CLICON_CLI_H_
#define _CLICON_CLI_H_
#include <sys/types.h>
#/* Common code (API and clicon_cli) */
include <clicon/clicon_cli_api.h>
/*! Clicon Cli plugin callbacks: use these in your cli plugin code
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
int plugin_init(clicon_handle h);
/* Called when backend started with cmd-line arguments from daemon call.
* @see plgstart_t
*/
int plugin_start(clicon_handle h, int argc, char **argv);
/* Called just before plugin unloaded.
* @see plgexit_t
*/
int plugin_exit(clicon_handle h);
/* Called before prompt is printed, return a customized prompt. */
char *plugin_prompt_hook(clicon_handle h, char *mode);
/* Called if a command is not matched w current mode. Return name of next syntax mode to check until NULL */
char *plugin_parse_hook(clicon_handle h, char *cmd, char *name);
/* Called if ^Z entered. Can modify cli command buffer and position */
int plugin_susp_hook(clicon_handle h, char *buf, int prompt_width, int *cursor_loc);
#endif /* _CLICON_CLI_H_ */

113
apps/cli/clicon_cli_api.h Normal file
View file

@ -0,0 +1,113 @@
/*
*
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
This file is part of CLICON.
CLICON 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.
CLICON 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 CLICON; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>.
* Note, this is a CLICON API file, only exprorted function prototypes should appear here
*/
#ifndef _CLICON_CLI_API_H_
#define _CLICON_CLI_API_H_
/*
* Constants
*/
/* Max prompt length */
#define CLI_PROMPT_LEN 64
#define CLI_DEFAULT_PROMPT ">"
/*
* Types
*/
//typedef void *cli_handle; /* clicon cli handle, see struct cli_handle */
enum candidate_db_type{
CANDIDATE_DB_NONE, /* No candidate */
CANDIDATE_DB_PRIVATE, /* Create a private candidate_db */
CANDIDATE_DB_SHARED, /* Share the candidate with everyone else */
CANDIDATE_DB_CURRENT /* Dont create candidate, use current directly */
};
/*
* Function Declarations
*/
/* cli_plugin.c */
int cli_set_syntax_mode(clicon_handle h, const char *mode);
char *cli_syntax_mode(clicon_handle h);
int cli_syntax_load(clicon_handle h);
int cli_handler_err(FILE *fd);
int cli_set_prompt(clicon_handle h, const char *mode, const char *prompt);
char *cli_prompt(char *fmt);
int cli_exec(clicon_handle h, char *cmd, char **mode, int *result);
int cli_ptpush(clicon_handle h, char *mode, char *string, char *op);
int cli_ptpop(clicon_handle h, char *mode, char *op);
/* cli_handle.c */
char cli_set_comment(clicon_handle h, char c);
char cli_comment(clicon_handle h);
int cli_set_exiting(clicon_handle h, int exiting);
int cli_exiting(clicon_handle h);
int cli_set_send2backend(clicon_handle h, int send2backend);
int cli_send2backend(clicon_handle h);
clicon_handle cli_handle_init(void);
int cli_handle_exit(clicon_handle h);
cligen_handle cli_cligen(clicon_handle h);
enum candidate_db_type cli_candidate_type(clicon_handle h);
int cli_set_candidate_type(clicon_handle h, enum candidate_db_type type);
/* cli_common.c */
int init_candidate_db(clicon_handle h, enum candidate_db_type type);
int exit_candidate_db(clicon_handle h);
#define cli_output cligen_output
int cli_set (clicon_handle h, cvec *vars, cg_var *arg);
int cli_merge (clicon_handle h, cvec *vars, cg_var *arg);
int cli_del(clicon_handle h, cvec *vars, cg_var *argv);
int cli_debug(clicon_handle h, cvec *vars, cg_var *argv);
int cli_record(clicon_handle h, cvec *vars, cg_var *argv);
int isrecording(void);
int record_command(char *str);
int cli_set_mode(clicon_handle h, cvec *vars, cg_var *argv);
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_dbvar(void *h, char *name, cvec *vars, cg_var *arg,
int *nr, char ***commands, char ***helptexts);
int expand_dbvar_auto(void *h, char *name, cvec *vars, cg_var *arg,
int *nr, char ***commands, char ***helptexts);
int expand_db_variable(clicon_handle h, char *dbname, char *basekey, char *variable, int *nr, char ***commands);
int expand_db_symbol(clicon_handle h, char *symbol, int element, int *nr, char ***commands);
int expand_dir(char *dir, int *nr, char ***commands, mode_t flags, int detail);
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 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);
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 /* _CLICON_CLI_API_H_ */