diff --git a/apps/restconf/restconf_main_native.c b/apps/restconf/restconf_main_native.c index db55112b..888be1fe 100644 --- a/apps/restconf/restconf_main_native.c +++ b/apps/restconf/restconf_main_native.c @@ -951,6 +951,7 @@ restconf_native_terminate(clicon_handle h) /*! Query backend of config. * Loop to wait for backend starting, try again if not done + * @param[in] h Clixon handle * @param[out] xrestconf XML restconf config, malloced (if retval = 1) * @retval 1 OK (and xrestconf set) * @retval 0 Fail - no config diff --git a/example/main/example_backend.c b/example/main/example_backend.c index 4ad282d3..a78d97b1 100644 --- a/example/main/example_backend.c +++ b/example/main/example_backend.c @@ -42,7 +42,7 @@ * -i read state file on init not by request for optimization (requires -sS ) * -u enable upgrade function - auto-upgrade testing * -U general-purpose upgrade - * -t enable transaction logging (cal syslog for every transaction) + * -t enable transaction logging (call syslog for every transaction) * -v Failing validate and commit if is present (synthetic error) */ #include @@ -67,7 +67,7 @@ #include /* Command line options to be passed to getopt(3) */ -#define BACKEND_EXAMPLE_OPTS "a:rsS:x:iuUt:v:" +#define BACKEND_EXAMPLE_OPTS "a:rsS:x:iuUtv:" /*! Yang action * Start backend with -- -a @@ -132,13 +132,6 @@ static int _general_upgrade = 0; */ static int _transaction_log = 0; -/*! Variable to control transaction logging (for debug) - * If set, call syslog for every transaction callback - * Start backend with -- -v - */ -static char *_validate_fail_xpath = NULL; -static int _validate_fail_toggle = 0; /* fail at validate and commit */ - /* forward */ static int example_stream_timer_setup(clicon_handle h); @@ -158,14 +151,6 @@ main_validate(clicon_handle h, { if (_transaction_log) transaction_log(h, td, LOG_NOTICE, __FUNCTION__); - if (_validate_fail_xpath){ - if (_validate_fail_toggle==0 && - xpath_first(transaction_target(td), NULL, "%s", _validate_fail_xpath)){ - _validate_fail_toggle = 1; /* toggle if triggered */ - clicon_err(OE_XML, 0, "User error"); - return -1; /* induce fail */ - } - } return 0; } @@ -193,15 +178,6 @@ main_commit(clicon_handle h, if (_transaction_log) transaction_log(h, td, LOG_NOTICE, __FUNCTION__); - if (_validate_fail_xpath){ - if (_validate_fail_toggle==1 && - xpath_first(transaction_target(td), NULL, "%s", _validate_fail_xpath)){ - _validate_fail_toggle = 0; /* toggle if triggered */ - clicon_err(OE_XML, 0, "User error"); - return -1; /* induce fail */ - } - } - /* Create namespace context for xpath */ if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) goto done; @@ -1333,9 +1309,6 @@ clixon_plugin_init(clicon_handle h) case 't': /* transaction log */ _transaction_log = 1; break; - case 'v': /* validate fail */ - _validate_fail_xpath = optarg; - break; } if (_state_file){ diff --git a/example/main/example_backend_nacm.c b/example/main/example_backend_nacm.c index 9c3c71d1..b61c16d3 100644 --- a/example/main/example_backend_nacm.c +++ b/example/main/example_backend_nacm.c @@ -68,7 +68,7 @@ static int _transaction_log = 0; /*! Variable to control transaction logging (for debug) - * If set, call syslog for every transaction callback + * XPath to trigger validation error * Start backend with -- -v */ static char *_validate_fail_xpath = NULL; diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 78dae6ce..c51cd979 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -262,7 +262,6 @@ int yang_spec_dump(yang_stmt *yspec, int debuglevel); int if_feature(yang_stmt *yspec, char *module, char *feature); int ys_populate(yang_stmt *ys, void *arg); int ys_populate2(yang_stmt *ys, void *arg); -int yang_if_feature_parse(char *str, yang_stmt *ys, int linenum, int *enabled); int yang_apply(yang_stmt *yn, enum rfc_6020 key, yang_applyfn_t fn, int from, void *arg); int yang_datanode(yang_stmt *ys); int yang_abs_schema_nodeid(yang_stmt *ys, char *schema_nodeid, yang_stmt **yres); diff --git a/lib/src/Makefile.in b/lib/src/Makefile.in index 10d32f3a..f300cf7b 100644 --- a/lib/src/Makefile.in +++ b/lib/src/Makefile.in @@ -76,7 +76,8 @@ SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \ clixon_string.c clixon_regex.c clixon_handle.c clixon_file.c \ clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \ clixon_xml_bind.c clixon_json.c clixon_proc.c \ - clixon_yang.c clixon_yang_type.c clixon_yang_module.c clixon_yang_parse_lib.c \ + clixon_yang.c clixon_yang_type.c clixon_yang_module.c \ + clixon_yang_parse_lib.c clixon_yang_parse_sub.c \ clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \ clixon_path.c clixon_validate.c \ clixon_hash.c clixon_options.c clixon_data.c clixon_plugin.c \ diff --git a/lib/src/clixon_if_feature_parse.y b/lib/src/clixon_if_feature_parse.y index 3348b471..d04175a8 100644 --- a/lib/src/clixon_if_feature_parse.y +++ b/lib/src/clixon_if_feature_parse.y @@ -58,7 +58,7 @@ %token TOKEN %token SEP -%type iffactor ifexpr +%type if_feature_factor if_feature_expr %start top @@ -167,38 +167,40 @@ if_feature_check(char *str, %% -top : ifexpr MY_EOF +/* See RFC 7950 Sec 14 if-feature-expr-str */ +top : if_feature_expr MY_EOF { - _PARSE_DEBUG("top->expr"); + _PARSE_DEBUG("top->if-feature-expr"); _IF->if_enabled = $1; YYACCEPT; } ; -ifexpr : iffactor sep1 OR sep1 ifexpr +if_feature_expr : if_feature_factor sep1 OR sep1 if_feature_expr { - _PARSE_DEBUG("expr->factor sep OR sep expr"); + _PARSE_DEBUG("if-feature-expr->if-feature-factor sep OR sep expr"); $$ = $1 || $5; } - | iffactor sep1 AND sep1 ifexpr + | if_feature_factor sep1 AND sep1 if_feature_expr { - _PARSE_DEBUG("expr->factor sep AND sep expr"); + _PARSE_DEBUG("if-feature-expr->if-feature-factor sep AND sep if-feature-expr"); $$ = $1 && $5; } - | iffactor + | if_feature_factor { - _PARSE_DEBUG("expr->factor"); + _PARSE_DEBUG("if-feature-expr->if-feature-factor"); $$ = $1; } ; -iffactor : NOT sep1 iffactor { _PARSE_DEBUG("factor-> NOT sep factor"); - $$ = !$3; } - | '(' optsep ifexpr optsep ')' - { _PARSE_DEBUG("factor-> ( optsep expr optsep )"); +if_feature_factor : NOT sep1 if_feature_factor + { _PARSE_DEBUG("if-feature-factor-> NOT sep if-feature-factor"); + $$ = !$3; } + | '(' optsep if_feature_expr optsep ')' + { _PARSE_DEBUG("if-feature-factor-> ( optsep if-feature-expr optsep )"); $$ = $3; } | TOKEN { - _PARSE_DEBUG("factor->TOKEN"); + _PARSE_DEBUG("if-feature-factor-> TOKEN"); if (_IF->if_ys == NULL) $$ = 0; else if (($$ = if_feature_check($1, _IF->if_ys)) < 0) { free($1); diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 8c926fc1..27f42374 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -59,7 +59,6 @@ #include #include #include -#include /* cligen */ #include @@ -80,8 +79,8 @@ #include "clixon_plugin.h" #include "clixon_data.h" #include "clixon_options.h" -#include "clixon_if_feature_parse.h" #include "clixon_yang_parse.h" +#include "clixon_yang_parse_sub.h" #include "clixon_yang_parse_lib.h" #include "clixon_yang_cardinality.h" #include "clixon_yang_type.h" @@ -2783,44 +2782,6 @@ ys_populate2(yang_stmt *ys, return retval; } -/*! Invoke yang if-feature sub-parser on string - * - * @param[in] str If-feature-expr string - * @param[in] ys Yang if-feature statement - * @param[in] linenum Line number context - * @param[out] enabled 0: Disabled, 1: Enabled - * @retval 0 OK - * @retval -1 Error - */ -int -yang_if_feature_parse(char *str, - yang_stmt *ys, - int linenum, - int *enabled) -{ - int retval = -1; - clixon_if_feature_yacc ife = {0,}; - - clicon_debug(2, "%s %s", __FUNCTION__, str); - ife.if_parse_string = str; - ife.if_linenum = linenum; - ife.if_ys = ys; - if (clixon_if_feature_parsel_init(&ife) < 0) - goto done; - if (clixon_if_feature_parseparse(&ife) != 0) { /* yacc returns 1 on error */ - clicon_log(LOG_NOTICE, "If-feature error: line %d", ife.if_linenum); - if (clicon_errno == 0) - clicon_err(OE_JSON, 0, "If-feature parser error with no error code (should not happen)"); - goto done; - } - if (enabled) - *enabled = ife.if_enabled; - retval = 0; - done: - clixon_if_feature_parsel_exit(&ife); - return retval; -} - /*! Find feature and if-feature nodes, check features and remove disabled nodes * @param[in] h Clixon handle * @param[in] yt Yang statement @@ -2829,7 +2790,7 @@ yang_if_feature_parse(char *str, * @retval 1 OK * @note On return 1 the over-lying function need to remove yt from its parent * @note cannot use yang_apply here since child-list is modified (destructive) - * @note if-feature syntax is restricted to single, and, or, syntax, such as "a or b" + * @note if-features is parsed in full context here, previous restricted pass in ys_parse_sub */ int yang_features(clicon_handle h, @@ -2845,7 +2806,7 @@ yang_features(clicon_handle h, while (iys_len){ ys = yt->ys_stmt[i]; if (ys->ys_keyword == Y_IF_FEATURE){ - /* Parse the if-feature-expr string */ + /* Parse the if-feature-expr string using yang sub-parser */ ret = 0; if (yang_if_feature_parse(yang_argument_get(ys), ys, 1, &ret) < 0) goto done; diff --git a/lib/src/clixon_yang_parse.y b/lib/src/clixon_yang_parse.y index 3a387b07..e778479e 100644 --- a/lib/src/clixon_yang_parse.y +++ b/lib/src/clixon_yang_parse.y @@ -69,6 +69,7 @@ %type string %type integer_value_str %type identifier_ref +%type if_feature_expr_str %type abs_schema_nodeid %type desc_schema_nodeid_strs %type desc_schema_nodeid_str @@ -688,9 +689,18 @@ feature_substmt : if_feature_stmt { _PARSE_DEBUG("feature-substmt -> if-featu ; /* if-feature-stmt = if-feature-keyword sep if-feature-expr-str */ -if_feature_stmt : K_IF_FEATURE string stmtend +if_feature_stmt : K_IF_FEATURE if_feature_expr_str stmtend { if (ysp_add(_yy, Y_IF_FEATURE, $2, NULL) == NULL) _YYERROR("if_feature_stmt"); - _PARSE_DEBUG("if-feature-stmt -> IF-FEATURE identifier-ref-arg-str"); } + _PARSE_DEBUG("if-feature-stmt -> IF-FEATURE if-feature-expr-str"); } + ; + +/* a string that matches the rule if-feature-expr + * @see yang_if_feature_parse + */ +if_feature_expr_str : string + { $$=$1; + _PARSE_DEBUG("if-feature-expr-str -> string that matches the rule if-feature-expr"); + } ; /* Typedef */ diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index a456a930..255972f9 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -66,8 +66,6 @@ #include #include #include -#include -#include #include #include #include @@ -99,6 +97,7 @@ #include "clixon_yang_cardinality.h" #include "clixon_plugin.h" #include "clixon_yang_internal.h" +#include "clixon_yang_parse_sub.h" #include "clixon_yang_parse_lib.h" /* Size of json read buffer when reading from file*/ @@ -1961,6 +1960,7 @@ ys_parse_sub(yang_stmt *ys, case Y_IF_FEATURE: /* Invoke next level parser on if-feature-expr string. Note do not send ys since * pass 1 is not yet resolved, only check syntax, actual feature check made in next pass + * @see yang_features */ if (yang_if_feature_parse(yang_argument_get(ys), NULL, yang_linenum_get(ys), NULL) < 0) goto done; diff --git a/lib/src/clixon_yang_parse_sub.c b/lib/src/clixon_yang_parse_sub.c new file mode 100644 index 00000000..bf164930 --- /dev/null +++ b/lib/src/clixon_yang_parse_sub.c @@ -0,0 +1,95 @@ +/* + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2009-2019 Olof Hagsand + Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + + * Sub-parsers to upper-level YANG parser: everything that is "stringified" + */ + +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + +#include +#include +#include +#include + +/* cligen */ +#include + +/* clicon */ +#include "clixon_log.h" +#include "clixon_err.h" +#include "clixon_queue.h" +#include "clixon_hash.h" +#include "clixon_handle.h" +#include "clixon_yang.h" +#include "clixon_if_feature_parse.h" + +/*! Invoke yang if-feature sub-parser on string + * + * @param[in] str If-feature-expr string + * @param[in] ys Yang if-feature statement + * @param[in] linenum Line number context + * @param[out] enabled 0: Disabled, 1: Enabled + * @retval 0 OK + * @retval -1 Error + */ +int +yang_if_feature_parse(char *str, + yang_stmt *ys, + int linenum, + int *enabled) +{ + int retval = -1; + clixon_if_feature_yacc ife = {0,}; + + clicon_debug(2, "%s %s", __FUNCTION__, str); + ife.if_parse_string = str; + ife.if_linenum = linenum; + ife.if_ys = ys; + if (clixon_if_feature_parsel_init(&ife) < 0) + goto done; + if (clixon_if_feature_parseparse(&ife) != 0) { /* yacc returns 1 on error */ + clicon_log(LOG_NOTICE, "If-feature error: line %d str:%s", ife.if_linenum, str); + if (clicon_errno == 0) + clicon_err(OE_YANG, 0, "If-feature parser error with no error code (should not happen)"); + goto done; + } + if (enabled) + *enabled = ife.if_enabled; + retval = 0; + done: + clixon_if_feature_parsel_exit(&ife); + return retval; +} diff --git a/lib/src/clixon_yang_parse_sub.h b/lib/src/clixon_yang_parse_sub.h new file mode 100644 index 00000000..4e906635 --- /dev/null +++ b/lib/src/clixon_yang_parse_sub.h @@ -0,0 +1,44 @@ +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2009-2019 Olof Hagsand + Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + + * Sub-parsers to upper-level YANG parser: everything that is "stringified" + */ +#ifndef _CLIXON_YANG_PARSE_SUB_H_ +#define _CLIXON_YANG_PARSE_SUB_H_ + +/* + * Prototypes + */ +int yang_if_feature_parse(char *str, yang_stmt *ys, int linenum, int *enabled); + +#endif /* _CLIXON_YANG_PARSER_SUB_H_ */ diff --git a/test/test_autocli_spec.sh b/test/test_autocli_spec.sh index daedf830..63547c86 100755 --- a/test/test_autocli_spec.sh +++ b/test/test_autocli_spec.sh @@ -9,7 +9,7 @@ APPNAME=example # include err() and new() functions and creates $dir cfg=$dir/conf_yang.xml -fspec=$dir/automode.cli +clispec=$dir/automode.cli fin=$dir/in fstate=$dir/state.xml fyang=$dir/clixon-example.yang @@ -65,7 +65,7 @@ module clixon-example2 { } EOF -cat < $fspec +cat < $clispec CLICON_MODE="example"; CLICON_PROMPT="%U@%H %W> "; CLICON_PLUGIN="example_cli"; diff --git a/test/test_transaction.sh b/test/test_transaction.sh index e12dea40..69c19fa0 100755 --- a/test/test_transaction.sh +++ b/test/test_transaction.sh @@ -98,7 +98,7 @@ function checklog(){ if [ -z "$t" ]; then echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $# -gt 0 ]; then - echo "Not found in log" + echo "Not found \"$s\" on line $l0" echo fi echo -e "\e[0m" @@ -126,7 +126,7 @@ if [ $BE -ne 0 ]; then err fi new "start backend -s init -f $cfg -l f$flog -- -t -v /x/y[a=$errnr]" - start_backend -s init -f $cfg -l f$flog -- -t -v /x/y[a=$errnr] # -t means transaction logging + start_backend -s init -f $cfg -l f$flog -- -t -v "/x/y[a='$errnr']" # -t means transaction logging fi new "wait backend"