* Auto-cli changed singature of yang2cli()
* Auto-cli: create generated CLI for sub-parts of a YANG spec
This commit is contained in:
parent
f69daf773e
commit
dda3244252
9 changed files with 282 additions and 126 deletions
|
|
@ -55,6 +55,7 @@ Users may have to change how they access the system
|
||||||
|
|
||||||
Developers may need to change their code
|
Developers may need to change their code
|
||||||
|
|
||||||
|
* Auto-cli changed singature of `yang2cli()`.
|
||||||
* Added by-ref parameter to `ys_cv_validate()` returning which sub-yang spec was validated in a union.
|
* Added by-ref parameter to `ys_cv_validate()` returning which sub-yang spec was validated in a union.
|
||||||
* Changed first parameter from `int fd` to `FILE *f` in the following functions:
|
* Changed first parameter from `int fd` to `FILE *f` in the following functions:
|
||||||
* clixon_xml_parse_file(), clixon_json_parse_file(), yang_parse_file()
|
* clixon_xml_parse_file(), clixon_json_parse_file(), yang_parse_file()
|
||||||
|
|
@ -62,6 +63,8 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|
||||||
|
* Auto-cli: create generated CLI for sub-parts of a YANG spec
|
||||||
|
* Experimental, see `yang2cli_sub()`
|
||||||
* Improved performance of parsing files as described in [Bytewise read() of files is slow #146](https://github.com/clicon/clixon/issues/146), thanks: @hjelmeland
|
* Improved performance of parsing files as described in [Bytewise read() of files is slow #146](https://github.com/clicon/clixon/issues/146), thanks: @hjelmeland
|
||||||
* Added new backend plugin: ca_pre-demon called if backend is daemonized just prior to forking.
|
* Added new backend plugin: ca_pre-demon called if backend is daemonized just prior to forking.
|
||||||
* Added XPATH functions `position`
|
* Added XPATH functions `position`
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ APPL = clixon_cli
|
||||||
|
|
||||||
# Not accessible from plugin
|
# Not accessible from plugin
|
||||||
APPSRC = cli_main.c
|
APPSRC = cli_main.c
|
||||||
APPSRC += cli_generate.c
|
|
||||||
APPOBJ = $(APPSRC:.c=.o)
|
APPOBJ = $(APPSRC:.c=.o)
|
||||||
|
|
||||||
# Accessible from plugin
|
# Accessible from plugin
|
||||||
|
|
@ -83,6 +82,7 @@ LIBSRC += cli_show.c
|
||||||
LIBSRC += cli_handle.c
|
LIBSRC += cli_handle.c
|
||||||
LIBSRC += cli_plugin.c
|
LIBSRC += cli_plugin.c
|
||||||
LIBSRC += cli_auto.c
|
LIBSRC += cli_auto.c
|
||||||
|
LIBSRC += cli_generate.c
|
||||||
LIBOBJ = $(LIBSRC:.c=.o)
|
LIBOBJ = $(LIBSRC:.c=.o)
|
||||||
|
|
||||||
# Name of lib
|
# Name of lib
|
||||||
|
|
@ -118,7 +118,7 @@ install-lib: $(MYLIB)
|
||||||
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon_cli.so
|
ln -sf $(MYLIBSO) $(DESTDIR)$(libdir)/$(MYLIBLINK) # -l:libclixon_cli.so
|
||||||
install -d -m 0755 $(DESTDIR)$(libdir)/clixon/plugins/cli
|
install -d -m 0755 $(DESTDIR)$(libdir)/clixon/plugins/cli
|
||||||
|
|
||||||
install-include: clixon_cli.h clixon_cli_api.h
|
install-include: clixon_cli.h clixon_cli_api.h cli_generate.h
|
||||||
install -d -m 0755 $(DESTDIR)$(includedir)/clixon
|
install -d -m 0755 $(DESTDIR)$(includedir)/clixon
|
||||||
install -m 0644 $^ $(DESTDIR)$(includedir)/clixon
|
install -m 0644 $^ $(DESTDIR)$(includedir)/clixon
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,8 @@ You can see which CLISPEC it generates via clixon_cli -D 2:
|
||||||
* @param[in] cvtype Type of the cligen variable
|
* @param[in] cvtype Type of the cligen variable
|
||||||
* @param[in] options
|
* @param[in] options
|
||||||
* @param[in] fraction_digits
|
* @param[in] fraction_digits
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb The string where the result format string is inserted.
|
* @param[out] cb The string where the result format string is inserted.
|
||||||
|
|
||||||
* @see expand_dbvar This is where the expand string is used
|
* @see expand_dbvar This is where the expand string is used
|
||||||
|
|
@ -116,12 +118,14 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
enum cv_type cvtype,
|
enum cv_type cvtype,
|
||||||
int options,
|
int options,
|
||||||
uint8_t fraction_digits,
|
uint8_t fraction_digits,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *api_path_fmt = NULL;
|
char *api_path_fmt = NULL;
|
||||||
|
|
||||||
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
|
if (yang2api_path_fmt(ys, 1, yp0, yp0_path, &api_path_fmt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "|<%s:%s", yang_argument_get(ys),
|
cprintf(cb, "|<%s:%s", yang_argument_get(ys),
|
||||||
cv_type2str(cvtype));
|
cv_type2str(cvtype));
|
||||||
|
|
@ -140,6 +144,8 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
/*! Create callback with api_path format string as argument
|
/*! Create callback with api_path format string as argument
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] ys yang_stmt of the node at hand
|
* @param[in] ys yang_stmt of the node at hand
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb The string where the result format string is inserted.
|
* @param[out] cb The string where the result format string is inserted.
|
||||||
* @see cli_dbxml This is where the xmlkeyfmt string is used
|
* @see cli_dbxml This is where the xmlkeyfmt string is used
|
||||||
* @see pt_callback_reference in CLIgen where the actual callback overwrites the template
|
* @see pt_callback_reference in CLIgen where the actual callback overwrites the template
|
||||||
|
|
@ -147,12 +153,14 @@ cli_expand_var_generate(clicon_handle h,
|
||||||
static int
|
static int
|
||||||
cli_callback_generate(clicon_handle h,
|
cli_callback_generate(clicon_handle h,
|
||||||
yang_stmt *ys,
|
yang_stmt *ys,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *api_path_fmt = NULL;
|
char *api_path_fmt = NULL;
|
||||||
|
|
||||||
if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0)
|
if (yang2api_path_fmt(ys, 0, yp0, yp0_path, &api_path_fmt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, ",%s(\"%s\")", GENERATE_CALLBACK,
|
cprintf(cb, ",%s(\"%s\")", GENERATE_CALLBACK,
|
||||||
api_path_fmt);
|
api_path_fmt);
|
||||||
|
|
@ -163,6 +171,19 @@ cli_callback_generate(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Print cligen help string as ("<helpstring>")
|
||||||
|
* @param[in] cb CLIgen buf holding generated CLIspec
|
||||||
|
* @param[in] helptext Help text
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
yang2cli_helptext(cbuf *cb,
|
||||||
|
char *helptext)
|
||||||
|
{
|
||||||
|
if (helptext)
|
||||||
|
cprintf(cb, "(\"%s\")", helptext);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Generate identityref statements for CLI variables
|
/*! Generate identityref statements for CLI variables
|
||||||
* @param[in] ys Yang statement
|
* @param[in] ys Yang statement
|
||||||
* @param[in] ytype Yang union type being resolved
|
* @param[in] ytype Yang union type being resolved
|
||||||
|
|
@ -195,8 +216,7 @@ yang2cli_var_identityref(yang_stmt *ys,
|
||||||
if (cvec_len(idrefvec) > 0){
|
if (cvec_len(idrefvec) > 0){
|
||||||
/* Add a wildchar string first -let validate take it for default prefix */
|
/* Add a wildchar string first -let validate take it for default prefix */
|
||||||
cprintf(cb, ">");
|
cprintf(cb, ">");
|
||||||
if (helptext)
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
|
||||||
cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr);
|
cprintf(cb, "|<%s:%s choice:", yang_argument_get(ys), cvtypestr);
|
||||||
yspec = ys_spec(ys);
|
yspec = ys_spec(ys);
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
@ -342,12 +362,13 @@ yang2cli_var_pattern(clicon_handle h,
|
||||||
|
|
||||||
/* Forward */
|
/* Forward */
|
||||||
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, enum genmodel_type gt,
|
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, enum genmodel_type gt,
|
||||||
int level, int state, int show_tree, cbuf *cb);
|
int level, int state, int show_tree,
|
||||||
|
yang_stmt *yp0, char *yp0_path, cbuf *cb);
|
||||||
|
|
||||||
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
|
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
|
||||||
yang_stmt *ytype, char *helptext, cbuf *cb);
|
yang_stmt *ytype, char *helptext, cbuf *cb);
|
||||||
|
|
||||||
/*! Generate CLI code for Yang leaf statement to CLIgen variable of specific type
|
/*! Generate CLI code for Yang leaf state ment to CLIgen variable of specific type
|
||||||
* Check for completion (of already existent values), ranges (eg range[min:max]) and
|
* Check for completion (of already existent values), ranges (eg range[min:max]) and
|
||||||
* patterns, (eg regexp:"[0.9]*").
|
* patterns, (eg regexp:"[0.9]*").
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
|
|
@ -431,8 +452,7 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, ">");
|
cprintf(cb, ">");
|
||||||
if (helptext)
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
|
||||||
if (type && strcmp(type, "identityref") == 0)
|
if (type && strcmp(type, "identityref") == 0)
|
||||||
cprintf(cb, ")");
|
cprintf(cb, ")");
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -538,6 +558,8 @@ yang2cli_var_union(clicon_handle h,
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] ys Yang statement
|
* @param[in] ys Yang statement
|
||||||
* @param[in] helptext CLI help text
|
* @param[in] helptext CLI help text
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
|
|
||||||
*
|
*
|
||||||
|
|
@ -551,6 +573,8 @@ static int
|
||||||
yang2cli_var(clicon_handle h,
|
yang2cli_var(clicon_handle h,
|
||||||
yang_stmt *ys,
|
yang_stmt *ys,
|
||||||
char *helptext,
|
char *helptext,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -588,10 +612,11 @@ yang2cli_var(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (clicon_cli_genmodel_completion(h)){
|
if (clicon_cli_genmodel_completion(h)){
|
||||||
if (cli_expand_var_generate(h, ys, cvtype,
|
if (cli_expand_var_generate(h, ys, cvtype,
|
||||||
options, fraction_digits, cb) < 0)
|
options, fraction_digits,
|
||||||
|
yp0, yp0_path,
|
||||||
|
cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (helptext)
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
|
||||||
}
|
}
|
||||||
cprintf(cb, ")");
|
cprintf(cb, ")");
|
||||||
}
|
}
|
||||||
|
|
@ -611,10 +636,11 @@ yang2cli_var(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (completionp){
|
if (completionp){
|
||||||
if (cli_expand_var_generate(h, ys, cvtype,
|
if (cli_expand_var_generate(h, ys, cvtype,
|
||||||
options, fraction_digits, cb) < 0)
|
options, fraction_digits,
|
||||||
|
yp0, yp0_path,
|
||||||
|
cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (helptext)
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
|
||||||
cprintf(cb, ")");
|
cprintf(cb, ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,6 +661,8 @@ yang2cli_var(clicon_handle h,
|
||||||
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not
|
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
* @param[in] key_leaf Is leaf in a key in a list module
|
* @param[in] key_leaf Is leaf in a key in a list module
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -645,6 +673,8 @@ yang2cli_leaf(clicon_handle h,
|
||||||
int callback,
|
int callback,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
int key_leaf,
|
int key_leaf,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
yang_stmt *yd; /* description */
|
yang_stmt *yd; /* description */
|
||||||
|
|
@ -664,22 +694,21 @@ yang2cli_leaf(clicon_handle h,
|
||||||
cprintf(cb, "%*s", level*3, "");
|
cprintf(cb, "%*s", level*3, "");
|
||||||
if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){
|
if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){
|
||||||
cprintf(cb, "%s", yang_argument_get(ys));
|
cprintf(cb, "%s", yang_argument_get(ys));
|
||||||
if (helptext)
|
yang2cli_helptext(cb, helptext);
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
|
||||||
cprintf(cb, " ");
|
cprintf(cb, " ");
|
||||||
if ((show_tree == 0) || (key_leaf == 1)) {
|
if ((show_tree == 0) || (key_leaf == 1)) {
|
||||||
if (yang2cli_var(h, ys, helptext, cb) < 0)
|
if (yang2cli_var(h, ys, helptext, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ((show_tree == 0) || (key_leaf == 1)) {
|
if ((show_tree == 0) || (key_leaf == 1)) {
|
||||||
if (yang2cli_var(h, ys, helptext, cb) < 0)
|
if (yang2cli_var(h, ys, helptext, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback){
|
if (callback){
|
||||||
if (cli_callback_generate(h, ys, cb) < 0)
|
if (cli_callback_generate(h, ys, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, ";\n");
|
cprintf(cb, ";\n");
|
||||||
}
|
}
|
||||||
|
|
@ -698,6 +727,8 @@ yang2cli_leaf(clicon_handle h,
|
||||||
* @param[in] level Indentation level
|
* @param[in] level Indentation level
|
||||||
* @param[in] state Include syntax for state not only config
|
* @param[in] state Include syntax for state not only config
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -707,6 +738,8 @@ yang2cli_container(clicon_handle h,
|
||||||
int level,
|
int level,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
|
|
@ -729,16 +762,16 @@ yang2cli_container(clicon_handle h,
|
||||||
}
|
}
|
||||||
if ((s = strstr(helptext, "\n\n")) != NULL)
|
if ((s = strstr(helptext, "\n\n")) != NULL)
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
}
|
}
|
||||||
if (cli_callback_generate(h, ys, cb) < 0)
|
if (cli_callback_generate(h, ys, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, ";{\n");
|
cprintf(cb, ";{\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each(ys, yc)) != NULL)
|
while ((yc = yn_each(ys, yc)) != NULL)
|
||||||
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (hide == 0)
|
if (hide == 0)
|
||||||
cprintf(cb, "%*s}\n", level*3, "");
|
cprintf(cb, "%*s}\n", level*3, "");
|
||||||
|
|
@ -756,6 +789,8 @@ yang2cli_container(clicon_handle h,
|
||||||
* @param[in] level Indentation level
|
* @param[in] level Indentation level
|
||||||
* @param[in] state Include syntax for state not only config
|
* @param[in] state Include syntax for state not only config
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -765,6 +800,8 @@ yang2cli_list(clicon_handle h,
|
||||||
int level,
|
int level,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
|
|
@ -786,7 +823,7 @@ yang2cli_list(clicon_handle h,
|
||||||
}
|
}
|
||||||
if ((s = strstr(helptext, "\n\n")) != NULL)
|
if ((s = strstr(helptext, "\n\n")) != NULL)
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
cprintf(cb, "(\"%s\")", helptext);
|
yang2cli_helptext(cb, helptext);
|
||||||
}
|
}
|
||||||
/* Loop over all key variables */
|
/* Loop over all key variables */
|
||||||
cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */
|
cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */
|
||||||
|
|
@ -805,7 +842,7 @@ yang2cli_list(clicon_handle h,
|
||||||
list_has_callback = cvec_next(cvk, cvi)?0:1;
|
list_has_callback = cvec_next(cvk, cvi)?0:1;
|
||||||
if (show_tree == 1) {
|
if (show_tree == 1) {
|
||||||
if (list_has_callback) {
|
if (list_has_callback) {
|
||||||
if (cli_callback_generate(h, ys, cb) < 0)
|
if (cli_callback_generate(h, ys, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, ";\n");
|
cprintf(cb, ";\n");
|
||||||
cprintf(cb, "{\n");
|
cprintf(cb, "{\n");
|
||||||
|
|
@ -814,7 +851,9 @@ yang2cli_list(clicon_handle h,
|
||||||
|
|
||||||
if (yang2cli_leaf(h, yleaf,
|
if (yang2cli_leaf(h, yleaf,
|
||||||
(gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1,
|
(gt==GT_VARS||gt==GT_HIDE)?GT_NONE:gt, level+1,
|
||||||
list_has_callback, show_tree, 1, cb) < 0)
|
list_has_callback, show_tree, 1,
|
||||||
|
yp0, yp0_path,
|
||||||
|
cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -832,7 +871,7 @@ yang2cli_list(clicon_handle h,
|
||||||
}
|
}
|
||||||
if (cvi != NULL)
|
if (cvi != NULL)
|
||||||
continue;
|
continue;
|
||||||
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, "%*s}\n", level*3, "");
|
cprintf(cb, "%*s}\n", level*3, "");
|
||||||
|
|
@ -854,6 +893,8 @@ yang2cli_list(clicon_handle h,
|
||||||
* @param[in] level Indentation level
|
* @param[in] level Indentation level
|
||||||
* @param[in] state Include syntax for state not only config
|
* @param[in] state Include syntax for state not only config
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
@example
|
@example
|
||||||
choice interface-type {
|
choice interface-type {
|
||||||
|
|
@ -871,6 +912,8 @@ yang2cli_choice(clicon_handle h,
|
||||||
int level,
|
int level,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -880,7 +923,7 @@ yang2cli_choice(clicon_handle h,
|
||||||
while ((yc = yn_each(ys, yc)) != NULL) {
|
while ((yc = yn_each(ys, yc)) != NULL) {
|
||||||
switch (yang_keyword_get(yc)){
|
switch (yang_keyword_get(yc)){
|
||||||
case Y_CASE:
|
case Y_CASE:
|
||||||
if (yang2cli_stmt(h, yc, gt, level+2, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+2, state, show_tree, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case Y_CONTAINER:
|
case Y_CONTAINER:
|
||||||
|
|
@ -888,7 +931,7 @@ yang2cli_choice(clicon_handle h,
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
case Y_LIST:
|
case Y_LIST:
|
||||||
default:
|
default:
|
||||||
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -905,6 +948,8 @@ yang2cli_choice(clicon_handle h,
|
||||||
* @param[in] level Indentation level
|
* @param[in] level Indentation level
|
||||||
* @param[in] state Include syntax for state not only config
|
* @param[in] state Include syntax for state not only config
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb Buffer where cligen code is written
|
* @param[out] cb Buffer where cligen code is written
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -914,6 +959,8 @@ yang2cli_stmt(clicon_handle h,
|
||||||
int level,
|
int level,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
yang_stmt *yc;
|
yang_stmt *yc;
|
||||||
|
|
@ -922,20 +969,24 @@ yang2cli_stmt(clicon_handle h,
|
||||||
if (state || yang_config(ys)){
|
if (state || yang_config(ys)){
|
||||||
switch (yang_keyword_get(ys)){
|
switch (yang_keyword_get(ys)){
|
||||||
case Y_CONTAINER:
|
case Y_CONTAINER:
|
||||||
if (yang2cli_container(h, ys, gt, level, state, show_tree, cb) < 0)
|
if (yang2cli_container(h, ys, gt, level, state, show_tree,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case Y_LIST:
|
case Y_LIST:
|
||||||
if (yang2cli_list(h, ys, gt, level, state, show_tree, cb) < 0)
|
if (yang2cli_list(h, ys, gt, level, state, show_tree,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case Y_CHOICE:
|
case Y_CHOICE:
|
||||||
if (yang2cli_choice(h, ys, gt, level, state, show_tree, cb) < 0)
|
if (yang2cli_choice(h, ys, gt, level, state, show_tree,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
case Y_LEAF:
|
case Y_LEAF:
|
||||||
if (yang2cli_leaf(h, ys, gt, level, 1, show_tree, 0, cb) < 0)
|
if (yang2cli_leaf(h, ys, gt, level, 1, show_tree, 0,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case Y_CASE:
|
case Y_CASE:
|
||||||
|
|
@ -943,7 +994,8 @@ yang2cli_stmt(clicon_handle h,
|
||||||
case Y_MODULE:
|
case Y_MODULE:
|
||||||
yc = NULL;
|
yc = NULL;
|
||||||
while ((yc = yn_each(ys, yc)) != NULL)
|
while ((yc = yn_each(ys, yc)) != NULL)
|
||||||
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
default: /* skip */
|
default: /* skip */
|
||||||
|
|
@ -957,39 +1009,46 @@ yang2cli_stmt(clicon_handle h,
|
||||||
|
|
||||||
/*! Generate CLI code for Yang specification
|
/*! Generate CLI code for Yang specification
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
* @param[in] yspec Yang specification
|
* @param[in] yn Create parse-tree from this yang node
|
||||||
* @param[in] gt CLI Generate style
|
|
||||||
* @param[in] printgen Log generated CLIgen syntax
|
* @param[in] printgen Log generated CLIgen syntax
|
||||||
* @param[in] state Also include state syntax
|
* @param[in] state Set to include state syntax
|
||||||
* @param[in] show_tree Is tree for show cli command
|
* @param[in] show_tree Is tree for show cli command
|
||||||
* @param[out] ptnew CLIgen parse-tree
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
*
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* Code generation styles:
|
* @param[out] pt CLIgen parse-tree (must be created on input)
|
||||||
* VARS: generate keywords for regular vars only not index
|
* @retval 0 OK
|
||||||
* ALL: generate keywords for all variables including index
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
yang2cli(clicon_handle h,
|
yang2cli(clicon_handle h,
|
||||||
yang_stmt *yspec,
|
yang_stmt *yn,
|
||||||
enum genmodel_type gt,
|
|
||||||
int printgen,
|
int printgen,
|
||||||
int state,
|
int state,
|
||||||
int show_tree,
|
int show_tree,
|
||||||
parse_tree *ptnew)
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
|
parse_tree *pt)
|
||||||
{
|
{
|
||||||
cbuf *cb = NULL;
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ymod = NULL;
|
cbuf *cb = NULL;
|
||||||
|
yang_stmt *yc;
|
||||||
cvec *globals; /* global variables from syntax */
|
cvec *globals; /* global variables from syntax */
|
||||||
|
enum genmodel_type gt;
|
||||||
|
|
||||||
|
if (pt == NULL){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "pt is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
gt = clicon_cli_genmodel_type(h);
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Traverse YANG, loop through all modules and generate CLI */
|
/* Traverse YANG, loop through all modules and generate CLI */
|
||||||
ymod = NULL;
|
yc = NULL;
|
||||||
while ((ymod = yn_each(yspec, ymod)) != NULL)
|
while ((yc = yn_each(yn, yc)) != NULL)
|
||||||
if (yang2cli_stmt(h, ymod, gt, 0, state, show_tree, cb) < 0)
|
if (yang2cli_stmt(h, yc, gt, 0, state, show_tree,
|
||||||
|
yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (printgen)
|
if (printgen)
|
||||||
clicon_log(LOG_NOTICE, "%s: Generated CLI spec:\n%s", __FUNCTION__, cbuf_get(cb));
|
clicon_log(LOG_NOTICE, "%s: Generated CLI spec:\n%s", __FUNCTION__, cbuf_get(cb));
|
||||||
|
|
@ -1000,7 +1059,7 @@ yang2cli(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
/* load cli syntax */
|
/* load cli syntax */
|
||||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb),
|
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb),
|
||||||
"yang2cli", ptnew, globals) < 0)
|
"yang2cli", pt, globals) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cvec_free(globals);
|
cvec_free(globals);
|
||||||
/* Resolve the expand callback functions in the generated syntax.
|
/* Resolve the expand callback functions in the generated syntax.
|
||||||
|
|
@ -1008,7 +1067,7 @@ yang2cli(clicon_handle h,
|
||||||
* handle=NULL for global namespace, this means expand callbacks must be in
|
* handle=NULL for global namespace, this means expand callbacks must be in
|
||||||
* CLICON namespace, not in a cli frontend plugin.
|
* CLICON namespace, not in a cli frontend plugin.
|
||||||
*/
|
*/
|
||||||
if (cligen_expandv_str2fn(ptnew, (expandv_str2fn_t*)clixon_str2fn, NULL) < 0)
|
if (cligen_expandv_str2fn(pt, (expandv_str2fn_t*)clixon_str2fn, NULL) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1017,3 +1076,51 @@ yang2cli(clicon_handle h,
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Generate CLI code for Yang specification
|
||||||
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] api_path API-path of sub-xml/yang
|
||||||
|
* @param[in] name Name of tree: use @<name> in clispec
|
||||||
|
* @param[in] printgen Log generated CLIgen syntax
|
||||||
|
* @param[in] state Also include state syntax
|
||||||
|
* @retval -1 Error, with clicon_err called
|
||||||
|
* @retval 0 OK , with result in yres
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang2cli_sub(clicon_handle h,
|
||||||
|
char *api_path,
|
||||||
|
char *name,
|
||||||
|
int printgen,
|
||||||
|
int state)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
yang_stmt *yspec;
|
||||||
|
yang_stmt *yn = NULL;
|
||||||
|
pt_head *ph;
|
||||||
|
parse_tree *pt = NULL; /* cli parse tree */
|
||||||
|
|
||||||
|
/* Get yspec */
|
||||||
|
yspec = clicon_dbspec_yang(h);
|
||||||
|
if (api_path2xml(api_path, yspec, NULL, YC_DATANODE, 1, NULL, &yn, NULL) < 0)
|
||||||
|
goto done;
|
||||||
|
if (yn == NULL)
|
||||||
|
goto ok; /* not found */
|
||||||
|
/* Create empty parse-tree */
|
||||||
|
if ((pt = pt_new()) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "pt_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
/* Generate tree from yangnode yn */
|
||||||
|
if (yang2cli(h, yn, printgen, state, 0, yn, api_path, pt) < 0)
|
||||||
|
goto done;
|
||||||
|
/* Add a new parse-tree header */
|
||||||
|
if ((ph = cligen_ph_add(cli_cligen(h), name)) == NULL)
|
||||||
|
goto done;
|
||||||
|
/* Add generated parse-tree to header */
|
||||||
|
if (cligen_ph_parsetree_set(ph, pt) < 0)
|
||||||
|
goto done;
|
||||||
|
ok:
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int yang2cli(clicon_handle h, yang_stmt *yspec, enum genmodel_type gt,
|
int yang2cli(clicon_handle h, yang_stmt *yspec,
|
||||||
int printgen, int state, int show_tree, parse_tree *ptnew);
|
int printgen, int state, int show_tree,
|
||||||
|
yang_stmt *yp0, char *yp0_path, parse_tree *ptnew);
|
||||||
|
int yang2cli_sub(clicon_handle h, char *api_path, char *name, int printgen, int state);
|
||||||
|
|
||||||
#endif /* _CLI_GENERATE_H_ */
|
#endif /* _CLI_GENERATE_H_ */
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,9 @@ cli_interactive(clicon_handle h)
|
||||||
* This tree is referenced from the main CLI spec (CLICON_CLISPEC_DIR) using the "tree reference"
|
* This tree is referenced from the main CLI spec (CLICON_CLISPEC_DIR) using the "tree reference"
|
||||||
* syntax, ie @datamodel
|
* syntax, ie @datamodel
|
||||||
* @param[in] h Clixon handle
|
* @param[in] h Clixon handle
|
||||||
|
* @param[in] state Set to include state syntax
|
||||||
* @param[in] printgen Print CLI syntax generated from dbspec
|
* @param[in] printgen Print CLI syntax generated from dbspec
|
||||||
|
* @param[in] show_tree Is tree for show cli command
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*
|
*
|
||||||
|
|
@ -259,7 +261,6 @@ cli_interactive(clicon_handle h)
|
||||||
static int
|
static int
|
||||||
autocli_tree(clicon_handle h,
|
autocli_tree(clicon_handle h,
|
||||||
char *name,
|
char *name,
|
||||||
enum genmodel_type gt,
|
|
||||||
int state,
|
int state,
|
||||||
int printgen,
|
int printgen,
|
||||||
int show_tree)
|
int show_tree)
|
||||||
|
|
@ -275,7 +276,7 @@ autocli_tree(clicon_handle h,
|
||||||
}
|
}
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
/* Generate tree (this is where the action is) */
|
/* Generate tree (this is where the action is) */
|
||||||
if (yang2cli(h, yspec, gt, printgen, state, show_tree, pt) < 0)
|
if (yang2cli(h, yspec, printgen, state, show_tree, NULL, NULL, pt) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
/* Append cligen tree and name it */
|
/* Append cligen tree and name it */
|
||||||
if ((ph = cligen_ph_add(cli_cligen(h), name)) == NULL)
|
if ((ph = cligen_ph_add(cli_cligen(h), name)) == NULL)
|
||||||
|
|
@ -307,13 +308,11 @@ autocli_start(clicon_handle h,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int autocli_model = 0;
|
int autocli_model = 0;
|
||||||
cbuf *show_treename = NULL, *treename = NULL;
|
cbuf *show_treename = NULL, *treename = NULL;
|
||||||
enum genmodel_type gt;
|
|
||||||
|
|
||||||
/* If autocli disabled quit */
|
/* If autocli disabled quit */
|
||||||
if ((autocli_model = clicon_cli_genmodel(h)) == 0)
|
if ((autocli_model = clicon_cli_genmodel(h)) == 0)
|
||||||
goto ok;
|
goto ok;
|
||||||
/* Get the autocli type, ie HOW the cli is generated (could be much more here) */
|
/* Get the autocli type, ie HOW the cli is generated (could be much more here) */
|
||||||
gt = clicon_cli_genmodel_type(h);
|
|
||||||
/* Create show_treename cbuf */
|
/* Create show_treename cbuf */
|
||||||
if ((show_treename = cbuf_new()) == NULL){
|
if ((show_treename = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
|
@ -326,20 +325,20 @@ autocli_start(clicon_handle h,
|
||||||
}
|
}
|
||||||
/* The tree name is by default @datamodel but can be changed by option (why would one do that?) */
|
/* The tree name is by default @datamodel but can be changed by option (why would one do that?) */
|
||||||
cprintf(treename, "%s", clicon_cli_model_treename(h));
|
cprintf(treename, "%s", clicon_cli_model_treename(h));
|
||||||
if (autocli_tree(h, cbuf_get(treename), gt, 0, printgen, 0) < 0)
|
if (autocli_tree(h, cbuf_get(treename), 0, printgen, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* The tree name is by default @datamodelshow but can be changed by option (why would one do that?) */
|
/* The tree name is by default @datamodelshow but can be changed by option (why would one do that?) */
|
||||||
cprintf(show_treename, "%s", clicon_cli_model_treename(h));
|
cprintf(show_treename, "%s", clicon_cli_model_treename(h));
|
||||||
cprintf(show_treename, "show");
|
cprintf(show_treename, "show");
|
||||||
if (autocli_tree(h, cbuf_get(show_treename), gt, 0, printgen, 1) < 0)
|
if (autocli_tree(h, cbuf_get(show_treename), 0, printgen, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Create a tree for config+state. This tree's name has appended "state" to @datamodel (XXX)
|
/* Create a tree for config+state. This tree's name has appended "state" to @datamodel
|
||||||
*/
|
*/
|
||||||
if (autocli_model > 1){
|
if (autocli_model > 1){
|
||||||
cprintf(treename, "state");
|
cprintf(treename, "state");
|
||||||
if (autocli_tree(h, cbuf_get(treename), gt, 1, printgen, 1) < 0)
|
if (autocli_tree(h, cbuf_get(treename), 1, printgen, 1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -654,6 +653,7 @@ main(int argc,
|
||||||
if (yang_spec_load_dir(h, str, yspec) < 0)
|
if (yang_spec_load_dir(h, str, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load clixon lib yang module */
|
/* Load clixon lib yang module */
|
||||||
if (yang_spec_parse_module(h, "clixon-lib", NULL, yspec) < 0)
|
if (yang_spec_parse_module(h, "clixon-lib", NULL, yspec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
#include <clixon/clixon.h>
|
#include <clixon/clixon.h>
|
||||||
#include <clixon/clixon_cli.h>
|
#include <clixon/clixon_cli.h>
|
||||||
|
#include <clixon/cli_generate.h>
|
||||||
|
|
||||||
/*! Example cli function */
|
/*! Example cli function */
|
||||||
int
|
int
|
||||||
|
|
@ -132,10 +132,24 @@ example_client_rpc(clicon_handle h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Plugin start
|
||||||
|
* Example on creating a generated tree from a sub-part of a yang spec.
|
||||||
|
* which can then be used in a clispec as: @datamodelexample.
|
||||||
|
* @see test_cli_gen_sub.sh
|
||||||
|
* @note still experimental
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
example_start(clicon_handle h)
|
||||||
|
{
|
||||||
|
if (yang2cli_sub(h, "/example2:table/parameter=abc", "datamodelexample", 1, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static clixon_plugin_api api = {
|
static clixon_plugin_api api = {
|
||||||
"example", /* name */
|
"example", /* name */
|
||||||
clixon_plugin_init, /* init */
|
clixon_plugin_init, /* init */
|
||||||
NULL, /* start */
|
example_start, /* start */
|
||||||
NULL, /* exit */
|
NULL, /* exit */
|
||||||
.ca_prompt=NULL, /* cli_prompthook_t */
|
.ca_prompt=NULL, /* cli_prompthook_t */
|
||||||
.ca_suspend=NULL, /* cligen_susp_cb_t */
|
.ca_suspend=NULL, /* cligen_susp_cb_t */
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,8 @@ typedef struct {
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int xml_yang_root(cxobj *x, cxobj **xr);
|
int xml_yang_root(cxobj *x, cxobj **xr);
|
||||||
int yang2api_path_fmt(yang_stmt *ys, int inclkey, char **api_path_fmt);
|
int yang2api_path_fmt(yang_stmt *ys, int inclkey, yang_stmt *yp0, char *yp0_path,
|
||||||
|
char **api_path_fmt);
|
||||||
int api_path_fmt2api_path(char *api_path_fmt, cvec *cvv, char **api_path);
|
int api_path_fmt2api_path(char *api_path_fmt, cvec *cvv, char **api_path);
|
||||||
int api_path_fmt2xpath(char *api_path_fmt, cvec *cvv, char **xpath);
|
int api_path_fmt2xpath(char *api_path_fmt, cvec *cvv, char **xpath);
|
||||||
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc, cxobj **xerr);
|
int api_path2xpath(char *api_path, yang_stmt *yspec, char **xpath, cvec **nsc, cxobj **xerr);
|
||||||
|
|
|
||||||
|
|
@ -280,13 +280,15 @@ xml_yang_root(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Construct an xml key format from yang statement using wildcards for keys
|
/*! Construct an api-path key format from yang statement using wildcards for keys
|
||||||
* Recursively construct it to the top.
|
* Recursively construct it to the top.
|
||||||
* Example:
|
* Example:
|
||||||
* yang: container a -> list b -> key c -> leaf d
|
* yang: container a -> list b -> key c -> leaf d
|
||||||
* xpath: /modname:a/b/%s/d
|
* path: /modname:a/b/%s/d
|
||||||
* @param[in] ys Yang statement
|
* @param[in] ys Yang statement
|
||||||
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
||||||
|
* @param[in] yp0 Build the path of ys only to this level not root (optional)
|
||||||
|
* @param[in] yp0path Use this path if stop at yp0 (not root)
|
||||||
* @param[out] cb api_path_fmt,
|
* @param[out] cb api_path_fmt,
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
|
|
@ -295,6 +297,8 @@ xml_yang_root(cxobj *x,
|
||||||
static int
|
static int
|
||||||
yang2api_path_fmt_1(yang_stmt *ys,
|
yang2api_path_fmt_1(yang_stmt *ys,
|
||||||
int inclkey,
|
int inclkey,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
cbuf *cb)
|
cbuf *cb)
|
||||||
{
|
{
|
||||||
yang_stmt *yp; /* parent */
|
yang_stmt *yp; /* parent */
|
||||||
|
|
@ -308,11 +312,14 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
||||||
clicon_err(OE_YANG, EINVAL, "yang expected parent %s", yang_argument_get(ys));
|
clicon_err(OE_YANG, EINVAL, "yang expected parent %s", yang_argument_get(ys));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yp != NULL && /* XXX rm */
|
if (yp == yp0){ /* Skip building path to root if match, use given path */
|
||||||
|
cprintf(cb, "%s/", yp0_path);
|
||||||
|
}
|
||||||
|
else if (yp != NULL && /* XXX rm */
|
||||||
yang_keyword_get(yp) != Y_MODULE &&
|
yang_keyword_get(yp) != Y_MODULE &&
|
||||||
yang_keyword_get(yp) != Y_SUBMODULE){
|
yang_keyword_get(yp) != Y_SUBMODULE){
|
||||||
|
|
||||||
if (yang2api_path_fmt_1((yang_stmt *)yp, 1, cb) < 0) /* recursive call */
|
if (yang2api_path_fmt_1((yang_stmt *)yp, 1, yp0, yp0_path, cb) < 0) /* recursive call */
|
||||||
goto done;
|
goto done;
|
||||||
if (yang_keyword_get(yp) != Y_CHOICE && yang_keyword_get(yp) != Y_CASE){
|
if (yang_keyword_get(yp) != Y_CHOICE && yang_keyword_get(yp) != Y_CASE){
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -391,6 +398,8 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
||||||
int
|
int
|
||||||
yang2api_path_fmt(yang_stmt *ys,
|
yang2api_path_fmt(yang_stmt *ys,
|
||||||
int inclkey,
|
int inclkey,
|
||||||
|
yang_stmt *yp0,
|
||||||
|
char *yp0_path,
|
||||||
char **api_path_fmt)
|
char **api_path_fmt)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
@ -400,7 +409,7 @@ yang2api_path_fmt(yang_stmt *ys,
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yang2api_path_fmt_1(ys, inclkey, cb) < 0)
|
if (yang2api_path_fmt_1(ys, inclkey, yp0, yp0_path, cb) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if ((*api_path_fmt = strdup(cbuf_get(cb))) == NULL){
|
if ((*api_path_fmt = strdup(cbuf_get(cb))) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "strdup");
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
|
@ -917,7 +926,6 @@ api_path2xml_vec(char **vec,
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restval is RFC 3896 encoded */
|
/* restval is RFC 3896 encoded */
|
||||||
if ((restval_enc = index(nodeid, '=')) != NULL){
|
if ((restval_enc = index(nodeid, '=')) != NULL){
|
||||||
*restval_enc = '\0';
|
*restval_enc = '\0';
|
||||||
|
|
@ -931,13 +939,15 @@ api_path2xml_vec(char **vec,
|
||||||
if (yang_keyword_get(y0) == Y_SPEC){ /* top-node */
|
if (yang_keyword_get(y0) == Y_SPEC){ /* top-node */
|
||||||
if (prefix == NULL){
|
if (prefix == NULL){
|
||||||
cprintf(cberr, "api-path element '%s', expected prefix:name", nodeid);
|
cprintf(cberr, "api-path element '%s', expected prefix:name", nodeid);
|
||||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((ymod = yang_find_module_by_name(y0, prefix)) == NULL){
|
if ((ymod = yang_find_module_by_name(y0, prefix)) == NULL){
|
||||||
cprintf(cberr, "No such yang module prefix");
|
cprintf(cberr, "No such yang module prefix");
|
||||||
if (netconf_unknown_element_xml(xerr, "application", prefix, cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_unknown_element_xml(xerr, "application", prefix, cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -948,14 +958,16 @@ api_path2xml_vec(char **vec,
|
||||||
yang_find_schemanode(y0, name):
|
yang_find_schemanode(y0, name):
|
||||||
yang_find_datanode(y0, name);
|
yang_find_datanode(y0, name);
|
||||||
if (y == NULL){
|
if (y == NULL){
|
||||||
if (netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
|
if (xerr &&
|
||||||
|
netconf_unknown_element_xml(xerr, "application", name, "Unknown element") < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (prefix && namespace == NULL){
|
if (prefix && namespace == NULL){
|
||||||
if ((ymod = yang_find_module_by_name(ys_spec(y0), prefix)) == NULL){
|
if ((ymod = yang_find_module_by_name(ys_spec(y0), prefix)) == NULL){
|
||||||
cprintf(cberr, "api-path element prefix: '%s', no such yang module", prefix);
|
cprintf(cberr, "api-path element prefix: '%s', no such yang module", prefix);
|
||||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -963,14 +975,17 @@ api_path2xml_vec(char **vec,
|
||||||
}
|
}
|
||||||
switch (yang_keyword_get(y)){
|
switch (yang_keyword_get(y)){
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
if (0 && restval==NULL){
|
#if 0
|
||||||
|
if (restval==NULL){
|
||||||
clicon_err(OE_XML, 0, "malformed key, expected '=restval'");
|
clicon_err(OE_XML, 0, "malformed key, expected '=restval'");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
if (x0 == NULL)
|
||||||
|
break;
|
||||||
if ((x = xml_new(yang_argument_get(y), x0, CX_ELMNT)) == NULL)
|
if ((x = xml_new(yang_argument_get(y), x0, CX_ELMNT)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_spec_set(x, y);
|
xml_spec_set(x, y);
|
||||||
|
|
||||||
if ((xb = xml_new("body", x, CX_BODY)) == NULL)
|
if ((xb = xml_new("body", x, CX_BODY)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (restval && xml_value_set(xb, restval) < 0)
|
if (restval && xml_value_set(xb, restval) < 0)
|
||||||
|
|
@ -985,7 +1000,8 @@ api_path2xml_vec(char **vec,
|
||||||
if (restval==NULL){
|
if (restval==NULL){
|
||||||
if (strict){
|
if (strict){
|
||||||
cprintf(cberr, "malformed key =%s, expected '=restval'", nodeid);
|
cprintf(cberr, "malformed key =%s, expected '=restval'", nodeid);
|
||||||
if (netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -998,17 +1014,19 @@ api_path2xml_vec(char **vec,
|
||||||
goto done;
|
goto done;
|
||||||
if ((nvalvec != cvec_len(cvk)) && strict){
|
if ((nvalvec != cvec_len(cvk)) && strict){
|
||||||
cprintf(cberr, "List key %s length mismatch", name);
|
cprintf(cberr, "List key %s length mismatch", name);
|
||||||
if (netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cvi = NULL;
|
cvi = NULL;
|
||||||
/* create list object */
|
/* create list object */
|
||||||
|
if (x0){
|
||||||
if ((x = xml_new(name, x0, CX_ELMNT)) == NULL)
|
if ((x = xml_new(name, x0, CX_ELMNT)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_spec_set(x, y);
|
xml_spec_set(x, y);
|
||||||
|
}
|
||||||
vi = 0;
|
vi = 0;
|
||||||
/* Create keys */
|
/* Create keys */
|
||||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||||
|
|
@ -1016,14 +1034,15 @@ api_path2xml_vec(char **vec,
|
||||||
if ((ykey = yang_find(y, Y_LEAF, keyname)) == NULL){
|
if ((ykey = yang_find(y, Y_LEAF, keyname)) == NULL){
|
||||||
cprintf(cberr, "List statement \"%s\" has no key leaf \"%s\"",
|
cprintf(cberr, "List statement \"%s\" has no key leaf \"%s\"",
|
||||||
yang_argument_get(y), keyname);
|
yang_argument_get(y), keyname);
|
||||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
if (xerr &&
|
||||||
|
netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (x != NULL){
|
||||||
if ((xn = xml_new(keyname, x, CX_ELMNT)) == NULL)
|
if ((xn = xml_new(keyname, x, CX_ELMNT)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_spec_set(xn, ykey);
|
xml_spec_set(xn, ykey);
|
||||||
|
|
||||||
if ((xb = xml_new("body", xn, CX_BODY)) == NULL)
|
if ((xb = xml_new("body", xn, CX_BODY)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
if (vi++ < nvalvec){
|
if (vi++ < nvalvec){
|
||||||
|
|
@ -1031,9 +1050,11 @@ api_path2xml_vec(char **vec,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default: /* eg Y_CONTAINER, Y_LEAF */
|
default: /* eg Y_CONTAINER, Y_LEAF */
|
||||||
if ((x = xml_find_type(x0, NULL, name, CX_ELMNT)) == NULL){ /* eg key of list */
|
if (x0 &&
|
||||||
|
(x = xml_find_type(x0, NULL, name, CX_ELMNT)) == NULL){ /* eg key of list */
|
||||||
if ((x = xml_new(name, x0, CX_ELMNT)) == NULL)
|
if ((x = xml_new(name, x0, CX_ELMNT)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
xml_spec_set(x, y);
|
xml_spec_set(x, y);
|
||||||
|
|
@ -1089,6 +1110,10 @@ api_path2xml_vec(char **vec,
|
||||||
* </subif-entry></config>
|
* </subif-entry></config>
|
||||||
* xbotp: <subid/>
|
* xbotp: <subid/>
|
||||||
* ybotp: Y_LEAF subid
|
* ybotp: Y_LEAF subid
|
||||||
|
* @code
|
||||||
|
* if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y, &xerr)) < 0)
|
||||||
|
* err;
|
||||||
|
* @endcode
|
||||||
* @note "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
* @note "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
||||||
* @see api_path2xpath For api-path to xpath translation (maybe could be combined?)
|
* @see api_path2xpath For api-path to xpath translation (maybe could be combined?)
|
||||||
*/
|
*/
|
||||||
|
|
@ -1109,17 +1134,13 @@ api_path2xml(char *api_path,
|
||||||
cbuf *cberr = NULL;
|
cbuf *cberr = NULL;
|
||||||
|
|
||||||
clicon_debug(2, "%s api_path:%s", __FUNCTION__, api_path);
|
clicon_debug(2, "%s api_path:%s", __FUNCTION__, api_path);
|
||||||
if (xtop == NULL){
|
|
||||||
clicon_err(OE_XML, EINVAL, "xtop is NULL");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if ((cberr = cbuf_new()) == NULL){
|
if ((cberr = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (*api_path != '/'){
|
if (*api_path != '/'){
|
||||||
cprintf(cberr, "Invalid api-path: %s (must start with '/')", api_path);
|
cprintf(cberr, "Invalid api-path: %s (must start with '/')", api_path);
|
||||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
if (xerr && netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -1130,7 +1151,7 @@ api_path2xml(char *api_path,
|
||||||
nvec--;
|
nvec--;
|
||||||
if (nvec < 1){
|
if (nvec < 1){
|
||||||
cprintf(cberr, "Malformed api-path: %s: too short)", api_path);
|
cprintf(cberr, "Malformed api-path: %s: too short)", api_path);
|
||||||
if (netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
if (xerr && netconf_invalid_value_xml(xerr, "application", cbuf_get(cberr)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
@ -1139,9 +1160,12 @@ api_path2xml(char *api_path,
|
||||||
xtop, yspec, nodeclass, strict,
|
xtop, yspec, nodeclass, strict,
|
||||||
xbotp, ybotp, xerr)) < 1)
|
xbotp, ybotp, xerr)) < 1)
|
||||||
goto done;
|
goto done;
|
||||||
|
/* Fix namespace */
|
||||||
|
if (xbotp){
|
||||||
xml_yang_root(*xbotp, &xroot);
|
xml_yang_root(*xbotp, &xroot);
|
||||||
if (xmlns_assign(xroot) < 0)
|
if (xmlns_assign(xroot) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
// ok:
|
// ok:
|
||||||
retval = 1;
|
retval = 1;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -149,30 +149,35 @@ pidfile_get(char *pidfile,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given a pid, kill that process
|
/*! Given a pid, kill that process
|
||||||
|
|
||||||
*
|
*
|
||||||
* @param[in] pid Process id
|
* @param[in] pid Process id
|
||||||
* @retval 0 Killed OK
|
* @retval 0 Killed OK
|
||||||
* @retval -1 Could not kill.
|
* @retval -1 Could not kill.
|
||||||
* Maybe shouldk not belong to pidfile code,..
|
* Maybe should not belong to pidfile code,..
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pidfile_zapold(pid_t pid)
|
pidfile_zapold(pid_t pid)
|
||||||
{
|
{
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
clicon_log(LOG_NOTICE, "Killing old daemon with pid: %d", pid);
|
clicon_log(LOG_NOTICE, "Killing old daemon with pid: %d", pid);
|
||||||
killpg(pid, SIGTERM);
|
killpg(pid, SIGTERM);
|
||||||
kill(pid, SIGTERM);
|
kill(pid, SIGTERM);
|
||||||
/* Need to sleep process properly and then check again */
|
/* Need to sleep process properly and then check again */
|
||||||
if (usleep(100000) < 0){
|
if (usleep(100000) < 0){
|
||||||
clicon_err(OE_UNIX, errno, "usleep");
|
clicon_err(OE_UNIX, errno, "usleep");
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((kill (pid, 0)) != 0 && errno == ESRCH) /* Nothing there */
|
if ((kill (pid, 0)) < 0){
|
||||||
;
|
if (errno != ESRCH){
|
||||||
else{ /* problem: couldnt kill it */
|
|
||||||
clicon_err(OE_DAEMON, errno, "Killing old demon");
|
clicon_err(OE_DAEMON, errno, "Killing old demon");
|
||||||
return -1;
|
goto done;
|
||||||
}
|
}
|
||||||
return 0;
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Write a pid-file
|
/*! Write a pid-file
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue