From 728fe9c6acd7eb50a3957fd5912b16e735c7958f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 3 Nov 2019 13:05:50 +0100 Subject: [PATCH 01/23] * Bumped version to 4.3.0.PRE * Added wildcard `*` as a mode to `CLICON_MODE` in clispec files * [Add missing includes](https://github.com/clicon/clixon/pulls) --- CHANGELOG.md | 11 +- apps/backend/clixon_backend_handle.c | 1 - apps/cli/cli_handle.c | 16 +-- apps/cli/cli_plugin.c | 86 ++++++++++----- configure | 4 +- configure.ac | 4 +- doc/DEVELOP.md | 8 +- example/main/example_cli.c | 1 - lib/clixon/clixon.h.in | 10 +- lib/clixon/clixon_string.h | 4 + lib/src/clixon_datastore_read.c | 1 - lib/src/clixon_datastore_write.c | 1 - lib/src/clixon_json.c | 1 - lib/src/clixon_nacm.c | 1 - lib/src/clixon_netconf_lib.c | 1 - lib/src/clixon_xml.c | 1 - lib/src/clixon_xml_changelog.c | 1 - lib/src/clixon_xml_nsctx.c | 1 - lib/src/clixon_xml_sort.c | 1 - lib/src/clixon_xpath.c | 1 - lib/src/clixon_xpath_ctx.c | 1 - lib/src/clixon_xpath_eval.c | 1 - lib/src/clixon_xpath_parse.y | 1 - test/test_cli_submodes.sh | 125 ++++++++++++++++++++++ util/clixon_util_insert.c | 1 - util/clixon_util_json.c | 1 - util/clixon_util_stream.c | 1 - util/clixon_util_xpath.c | 1 - yang/clixon/clixon-config@2019-09-11.yang | 15 +-- 29 files changed, 227 insertions(+), 75 deletions(-) create mode 100755 test/test_cli_submodes.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index e82e5dfe..6353a40e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Clixon Changelog +## 4.3.0 (Expected: ~December 2019) + +### Minor changes +* Added wildcard `*` as a mode to `CLICON_MODE` in clispec files + * If you set "CLICON_MODE="*";" in a clispec file it means that syntax will appear in all CLI spec modes. + +### Corrected Bugs +* [Add missing includes](https://github.com/clicon/clixon/pulls) + ## 4.2.0 (October 27 2019) ### Summary @@ -12,7 +21,7 @@ The main improvement in thus release concerns security in terms of priveleges an * use `-U ` clixon_backend command-line option to drop to `user` * Generic options are the following: * `CLICON_BACKEND_USER` sets the user to drop priveleges to - * CLICON_BACKEND_PRIVELEGES can have the following values: + * `CLICON_BACKEND_PRIVELEGES` can have the following values: * `none` Make no drop/change in privileges. This is currently the default. * `drop_perm` After initialization, drop privileges permanently * `drop_perm` After initialization, drop privileges temporarily (to a euid) diff --git a/apps/backend/clixon_backend_handle.c b/apps/backend/clixon_backend_handle.c index cd320bd2..6f5ca55e 100644 --- a/apps/backend/clixon_backend_handle.c +++ b/apps/backend/clixon_backend_handle.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/apps/cli/cli_handle.c b/apps/cli/cli_handle.c index 01fd3e32..7b0ebc79 100644 --- a/apps/cli/cli_handle.c +++ b/apps/cli/cli_handle.c @@ -162,10 +162,10 @@ cli_cligen(clicon_handle h) int cli_parse_file(clicon_handle h, - FILE *f, - char *name, /* just for errs */ - parse_tree *pt, - cvec *globals) + FILE *f, + char *name, /* just for errs */ + parse_tree *pt, + cvec *globals) { cligen_handle ch = cligen(h); @@ -182,7 +182,7 @@ cli_susp_hook(clicon_handle h, return cligen_susp_hook(ch, fn); } int -cli_interrupt_hook(clicon_handle h, +cli_interrupt_hook(clicon_handle h, cligen_interrupt_cb_t *fn) { cligen_handle ch = cligen(h); @@ -200,14 +200,16 @@ cli_nomatch(clicon_handle h) } int -cli_prompt_set(clicon_handle h, char *prompt) +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) +cli_logsyntax_set(clicon_handle h, + int status) { cligen_handle ch = cligen(h); return cligen_logsyntax_set(ch, status); diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 31331f21..964c4497 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -209,27 +208,29 @@ clixon_str2fn(char *name, return NULL; } -/*! Append to syntax mode from file - * @param[in] h Clixon handle - * @param[in] filename Name of file where syntax is specified (in syntax-group dir) - * @param[in] dir Name of dir, or NULL +/*! Load a file containing syntax and append to specified modes, also load C plugin + * @param[in] h Clixon handle + * @param[in] filename Name of file where syntax is specified (in syntax-group dir) + * @param[in] dir Name of dir, or NULL + * @param[out] allpt Universal CLIgen parse tree: apply to all modes */ static int -cli_load_syntax(clicon_handle h, - const char *filename, - const char *dir) +cli_load_syntax_file(clicon_handle h, + const char *filename, + const char *dir, + parse_tree *ptall) { - void *handle = NULL; /* Handle to plugin .so module */ - char *mode = NULL; /* Name of syntax mode to append new syntax */ - parse_tree pt = {0,}; - int retval = -1; - FILE *f; - char filepath[MAXPATHLEN]; - cvec *cvv = NULL; - char *prompt = NULL; - char **vec = NULL; - int i, nvec; - char *plgnam; + void *handle = NULL; /* Handle to plugin .so module */ + char *mode = NULL; /* Name of syntax mode to append new syntax */ + parse_tree pt = {0,}; + int retval = -1; + FILE *f; + char filepath[MAXPATHLEN]; + cvec *cvv = NULL; + char *prompt = NULL; + char **vec = NULL; + int i, nvec; + char *plgnam; clixon_plugin *cp; if (dir) @@ -253,10 +254,18 @@ cli_load_syntax(clicon_handle h, goto done; } fclose(f); - /* Get CLICON specific global variables */ + /* Get CLICON specific global variables: + * CLICON_MODE: which mode(s) this syntax applies to + * CLICON_PROMPT: Cli prompt in this mode + * CLICON_PLUGIN: Name of C API plugin + * Note: the base case is that it is: + * (1) a single mode or + * (2) "*" all modes or "m1:m2" - a list of modes + * but for (2), prompt and plgnam may have unclear semantics + */ + mode = cvec_find_str(cvv, "CLICON_MODE"); prompt = cvec_find_str(cvv, "CLICON_PROMPT"); plgnam = cvec_find_str(cvv, "CLICON_PLUGIN"); - mode = cvec_find_str(cvv, "CLICON_MODE"); if (plgnam != NULL) { /* Find plugin for callback resolving */ if ((cp = clixon_plugin_find(h, plgnam)) != NULL) @@ -288,8 +297,19 @@ cli_load_syntax(clicon_handle h, goto done; } } + /* Find all modes in CLICON_MODE string: where to append the pt syntax tree */ if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL) goto done; + + if (nvec == 1 && strcmp(vec[0], "*") == 0){ + /* Special case: Add this to all modes. Add to special "universal" syntax + * and add to all syntaxes after all files have been loaded. At this point + * all modes may not be known (not yet loaded) + */ + if (cligen_parsetree_merge(ptall, NULL, pt) < 0) + return -1; + } + else { for (i = 0; i < nvec; i++) { if (syntax_append(h, cli_syntax(h), @@ -300,6 +320,7 @@ cli_load_syntax(clicon_handle h, if (prompt) cli_set_prompt(h, vec[i], prompt); } + } cligen_parsetree_free(pt, 1); retval = 0; @@ -329,6 +350,7 @@ cli_syntax_load(clicon_handle h) cligen_susp_cb_t *fns = NULL; cligen_interrupt_cb_t *fni = NULL; clixon_plugin *cp; + parse_tree ptall = {0,}; /* Universal CLIgen parse tree all modes */ /* Syntax already loaded. XXX should we re-load?? */ if ((stx = cli_syntax(h)) != NULL) @@ -347,30 +369,38 @@ cli_syntax_load(clicon_handle h) cli_syntax_set(h, stx); + /* Load single specific clispec file */ if (clispec_file){ - if (cli_load_syntax(h, clispec_file, NULL) < 0) + if (cli_load_syntax_file(h, clispec_file, NULL, &ptall) < 0) goto done; } + /* Load all clispec .cli files in directory */ if (clispec_dir){ - /* load syntaxfiles */ + /* Get directory list of files */ if ((ndp = clicon_file_dirent(clispec_dir, &dp, "(.cli)$", S_IFREG)) < 0) goto done; - /* Load the rest */ + /* Load the syntax parse trees into cli_syntax stx structure */ for (i = 0; i < ndp; i++) { clicon_debug(1, "DEBUG: Loading syntax '%.*s'", (int)strlen(dp[i].d_name)-4, dp[i].d_name); - if (cli_load_syntax(h, dp[i].d_name, clispec_dir) < 0) + if (cli_load_syntax_file(h, dp[i].d_name, clispec_dir, &ptall) < 0) goto done; } } - /* Did we successfully load any syntax modes? */ + /* Were any syntax modes successfully loaded? If not, leave */ if (stx->stx_nmodes <= 0) { retval = 0; goto done; } - /* Parse syntax tree for all modes */ + + /* Go thorugh all modes and : + * 1) Add the universal syntax + * 2) add syntax tree (of those modes - "activate" syntax from stx to CLIgen) + */ m = stx->stx_modes; do { + if (cligen_parsetree_merge(&m->csm_pt, NULL, ptall) < 0) + return -1; if (gen_parse_tree(h, m) != 0) goto done; m = NEXTQ(cli_syntaxmode_t *, m); @@ -389,13 +419,13 @@ cli_syntax_load(clicon_handle h) /* All good. We can now proudly return a new group */ retval = 0; - done: if (retval != 0) { clixon_plugin_exit(h); cli_syntax_unload(h); cli_syntax_set(h, NULL); } + cligen_parsetree_free(ptall, 1); if (dp) free(dp); return retval; diff --git a/configure b/configure index 2bf8b1a8..124aadbc 100755 --- a/configure +++ b/configure @@ -2172,9 +2172,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu : ${INSTALLFLAGS="-s"} CLIXON_VERSION_MAJOR="4" -CLIXON_VERSION_MINOR="2" +CLIXON_VERSION_MINOR="3" CLIXON_VERSION_PATCH="0" -CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\"" +CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}.PRE\"" # Check CLIgen if test "$prefix" = "NONE"; then diff --git a/configure.ac b/configure.ac index fa281d81..c3cd8d3e 100644 --- a/configure.ac +++ b/configure.ac @@ -43,9 +43,9 @@ AC_INIT(lib/clixon/clixon.h.in) : ${INSTALLFLAGS="-s"} CLIXON_VERSION_MAJOR="4" -CLIXON_VERSION_MINOR="2" +CLIXON_VERSION_MINOR="3" CLIXON_VERSION_PATCH="0" -CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}\"" +CLIXON_VERSION="\"${CLIXON_VERSION_MAJOR}.${CLIXON_VERSION_MINOR}.${CLIXON_VERSION_PATCH}.PRE\"" # Check CLIgen if test "$prefix" = "NONE"; then diff --git a/doc/DEVELOP.md b/doc/DEVELOP.md index 46b69d74..834c1e58 100644 --- a/doc/DEVELOP.md +++ b/doc/DEVELOP.md @@ -122,6 +122,12 @@ After release: ``` * Run autoconf +Create release branch: +``` + git checkout -b release-4.2 4.2.0 + git push origin release-4.2 +``` + ## Use of constants etc -Use MAXPATHLEN (not PATH_MAX) \ No newline at end of file +Use MAXPATHLEN (not PATH_MAX) diff --git a/example/main/example_cli.c b/example/main/example_cli.c index 8cc88abf..04658d2e 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -43,7 +43,6 @@ #include #include #include -#include /* matching strings */ #include /* matching strings */ /* clicon */ diff --git a/lib/clixon/clixon.h.in b/lib/clixon/clixon.h.in index c810acd9..7de4a0d0 100644 --- a/lib/clixon/clixon.h.in +++ b/lib/clixon/clixon.h.in @@ -51,20 +51,14 @@ #include /* MAXPATHLEN */ /* - * CLIXON version macros + * CLIXON version macros, set in configure and resolved when expanding to + * clixon.h */ - #undef CLIXON_VERSION_STRING #undef CLIXON_VERSION_MAJOR #undef CLIXON_VERSION_MINOR #undef CLIXON_VERSION_PATCH -/* - * Use this constant to disable some prototypes that should not be visible outside the lib. - * This is an alternative to use separate internal include files. - */ -#define LIBCLIXON_API 1 - #include #include #include diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index 90717b74..10ff73a3 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -58,6 +58,10 @@ typedef struct map_str2int map_str2int; /*! A malloc version that aligns on 4 bytes. To avoid warning from valgrind */ #define align4(s) (((s)/4)*4 + 4) +/* Required for the inline to compile */ +#include +#include + /*! A strdup version that aligns on 4 bytes. To avoid warning from valgrind */ static inline char * strdup4(char *str) { diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 2150502c..62921c6b 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index 8ddc69fb..b6f294da 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_json.c b/lib/src/clixon_json.c index 6d989e42..d4fb484c 100644 --- a/lib/src/clixon_json.c +++ b/lib/src/clixon_json.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_nacm.c b/lib/src/clixon_nacm.c index 3e2848e1..b0da26e6 100644 --- a/lib/src/clixon_nacm.c +++ b/lib/src/clixon_nacm.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 3e7e3c8a..e8601af4 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 38723f7b..947647e7 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include diff --git a/lib/src/clixon_xml_changelog.c b/lib/src/clixon_xml_changelog.c index f74ab713..80cbb0fc 100644 --- a/lib/src/clixon_xml_changelog.c +++ b/lib/src/clixon_xml_changelog.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_xml_nsctx.c b/lib/src/clixon_xml_nsctx.c index c65cab5b..e588c204 100644 --- a/lib/src/clixon_xml_nsctx.c +++ b/lib/src/clixon_xml_nsctx.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include diff --git a/lib/src/clixon_xml_sort.c b/lib/src/clixon_xml_sort.c index 83b19a61..74e33291 100644 --- a/lib/src/clixon_xml_sort.c +++ b/lib/src/clixon_xml_sort.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 3e7a7056..33b094f9 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -65,7 +65,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_xpath_ctx.c b/lib/src/clixon_xpath_ctx.c index 30f44af6..cf8d6a0b 100644 --- a/lib/src/clixon_xpath_ctx.c +++ b/lib/src/clixon_xpath_ctx.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index d6b0eb7b..077c4fb2 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index f014b6a4..0fdeac5e 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -105,7 +105,6 @@ #include #include #include -#include #include #include #include diff --git a/test/test_cli_submodes.sh b/test/test_cli_submodes.sh new file mode 100755 index 00000000..af77d92e --- /dev/null +++ b/test/test_cli_submodes.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# CLIgen mode tests +# Have two modes: AAA and BBB +# Have the following clispec files with syntax for: +# 1) * 2) AAA, 3) BBB, 4) CCC, 5) AAA:BBB, 6) BBB:CCC +# Verify then that modes AAA and BBB have right syntax (also negative) +# AAA should have syntax from 1,2,5 (and not 3,4,6) +# BBB should have syntax from 1,3,5,6 (and not 2,4) + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +# include err() and new() functions and creates $dir + +cfg=$dir/conf_yang.xml +clidir=$dir/clidir + +if [ ! -d $clidir ]; then + mkdir $clidir +fi + +# Use yang in example + +cat < $cfg + + $cfg + /usr/local/share/clixon + $IETFRFC + clixon-example + /usr/local/lib/$APPNAME/backend + $clidir + /usr/local/lib/$APPNAME/cli + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + /usr/local/var/$APPNAME + +EOF + +# clispec files 1..6 for submodes AAA and BBB as described in top comment + +cat < $clidir/cli1.cli + CLICON_MODE="*"; + cmd1; +EOF + +cat < $clidir/cli2.cli + CLICON_MODE="AAA"; + cmd2; +EOF + +cat < $clidir/cli3.cli + CLICON_MODE="BBB"; + cmd3; +EOF + +cat < $clidir/cli4.cli + CLICON_MODE="CCC"; + cmd4; +EOF + +cat < $clidir/cli5.cli + CLICON_MODE="AAA:BBB"; + cmd5; +EOF + +cat < $clidir/cli6.cli + CLICON_MODE="BBB:CCC"; + cmd6; +EOF + +new "test params: -f $cfg" +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -z -f $cfg + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg + + new "waiting" + wait_backend +fi + + +m=AAA +# Tests using mode AAA that should pass +for c in 1 2 5; do + new "cli mode $m 1 cmd$c OK" + expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 0 "^$" +done +# Tests using mode AAA that should fail +for c in 3 4 6; do + new "cli mode $m 1 cmd$c Not OK" + expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 255 "^$" +done + +m=BBB +# Tests using mode BBB that should pass +for c in 1 3 5 6; do + new "cli mode $m 1 cmd$c OK" + expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 0 "^$" +done +# Tests using mode BBB that should fail +for c in 2 4; do + new "cli mode $m 1 cmd$c Not OK" + expectfn "$clixon_cli -1 -m $m -f $cfg cmd$c" 255 "^$" +done + +if [ $BE -eq 0 ]; then + exit # BE +fi + +new "Kill backend" +# Check if premature kill +pid=$(pgrep -u root -f clixon_backend) +if [ -z "$pid" ]; then + err "backend already dead" +fi +# kill backend +stop_backend -f $cfg + +rm -rf $dir diff --git a/util/clixon_util_insert.c b/util/clixon_util_insert.c index f4e86e83..d2a6a444 100644 --- a/util/clixon_util_insert.c +++ b/util/clixon_util_insert.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/util/clixon_util_json.c b/util/clixon_util_json.c index c1083690..4c333c96 100644 --- a/util/clixon_util_json.c +++ b/util/clixon_util_json.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/util/clixon_util_stream.c b/util/clixon_util_stream.c index 6b52fb3e..511c62ea 100644 --- a/util/clixon_util_stream.c +++ b/util/clixon_util_stream.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c index 57d5cac6..de760508 100644 --- a/util/clixon_util_xpath.c +++ b/util/clixon_util_xpath.c @@ -46,7 +46,6 @@ See https://www.w3.org/TR/xpath/ #include #include #include -#include #include #include #include diff --git a/yang/clixon/clixon-config@2019-09-11.yang b/yang/clixon/clixon-config@2019-09-11.yang index 7eb343cd..7dedec8f 100644 --- a/yang/clixon/clixon-config@2019-09-11.yang +++ b/yang/clixon/clixon-config@2019-09-11.yang @@ -338,20 +338,21 @@ module clixon-config { leaf CLICON_CLI_DIR { type string; description - "Location of cli frontend .so plugins. Load all .so - plugins in this dir as CLI object plugins"; + "Directory containing frontend cli loadable plugins. Load all .so + plugins in this directory as CLI object plugins"; } leaf CLICON_CLISPEC_DIR { type string; description - "Location of frontend .cli cligen spec files. Load all .cli - files in this dir as CLI specification files"; + "Directory containing frontend cligen spec files. Load all .cli + files in this directory as CLI specification files. + See also CLICON_CLISPEC_FILE."; } leaf CLICON_CLISPEC_FILE { type string; - description "Specific frontend .cli cligen spec file as simple - alternative to CLICON_CLISPEC_DIR. Also available as - -c in clixon_cli."; + description + "Specific frontend cligen spec file as aletrnative or complement + to CLICON_CLISPEC_DIR. Also available as -c in clixon_cli."; } leaf CLICON_CLI_MODE { type string; From 835f9030d2fedd3b850764bfea017b5a62843f13 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 11 Nov 2019 21:03:11 +0100 Subject: [PATCH 02/23] * State callbacks provided by user are validated. If they are invalid an internal error is returned. * Fixed multi-namespace for augmented state which was not covered in 4.2.0. * The multi-namespace augment state may rearrange the XML namespace attributes. * Mandatory variables can no longer be deleted. --- CHANGELOG.md | 9 + apps/backend/backend_client.c | 4 +- apps/backend/backend_commit.c | 12 +- apps/backend/backend_plugin.c | 28 +++ example/hello/README.md | 2 +- example/main/Makefile.in | 2 +- example/main/README.md | 2 +- ...23.yang => clixon-example@2019-11-05.yang} | 15 ++ example/main/example_backend.c | 67 ++---- lib/clixon/clixon_proto_client.h | 2 +- lib/clixon/clixon_xml_map.h | 1 + lib/src/clixon_datastore_write.c | 132 ----------- lib/src/clixon_netconf_lib.c | 2 +- lib/src/clixon_proto_client.c | 6 +- lib/src/clixon_xml_map.c | 205 ++++++++++++++++-- test/test_augment.sh | 11 +- test/test_netconf.sh | 6 +- test/test_perf_state.sh | 4 +- test/test_restconf.sh | 16 +- test/test_restconf_jukebox.sh | 2 +- 20 files changed, 299 insertions(+), 229 deletions(-) rename example/main/{clixon-example@2019-07-23.yang => clixon-example@2019-11-05.yang} (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6353a40e..9d7dc3ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,17 @@ ### Minor changes * Added wildcard `*` as a mode to `CLICON_MODE` in clispec files * If you set "CLICON_MODE="*";" in a clispec file it means that syntax will appear in all CLI spec modes. +* State callbacks provided by user are validated. If they are invalid an internal error is returned. +* Fixed multi-namespace for augmented state which was not covered in 4.2.0. + + +### API changes on existing features (you may need to change your code) +* The multi-namespace augment state may rearrange the XML namespace attributes. +* Main example yang changed to incorporate augmented state, new revision is 2019-11-15. ### Corrected Bugs + +* Mandatory variables can no longer be deleted. * [Add missing includes](https://github.com/clicon/clixon/pulls) ## 4.2.0 (October 27 2019) diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 8a379c0d..2aee6dca 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -170,7 +170,7 @@ client_get_capabilities(clicon_handle h, int retval = -1; cxobj *xrstate = NULL; /* xml restconf-state node */ cxobj *xcap = NULL; /* xml capabilities node */ - + if ((xrstate = xpath_first(*xret, "restconf-state")) == NULL){ clicon_err(OE_YANG, ENOENT, "restconf-state not found in config node"); goto done; @@ -321,7 +321,7 @@ client_statedata(clicon_handle h, if (ret == 0) goto fail; /* Code complex to filter out anything that is outside of xpath - * Actually this is a safety catch, should realy be done in plugins + * Actually this is a safety catch, should really be done in plugins * and modules_state functions. */ if (xpath_vec_nsc(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 7c45145c..a22e8360 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -118,10 +118,14 @@ generic_validate(clicon_handle h, for (i=0; itd_dlen; i++){ x1 = td->td_dvec[i]; ys = xml_spec(x1); - if (ys && yang_mandatory(ys) && yang_config(ys)==0){ - if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "Missing mandatory variable") < 0) - goto done; - goto fail; + if (ys && yang_mandatory(ys) && yang_config(ys)==1){ + yang_stmt *yp =yang_parent_get(ys); + if (yp== NULL || + (yang_keyword_get(yp)!=Y_MODULE && yang_keyword_get(yp)!=Y_SUBMODULE)){ + if (netconf_missing_element_xml(xret, "protocol", xml_name(x1), "May not remove mandatory variable") < 0) + goto done; + goto fail; + } } } /* added entries */ diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index a0dc92d3..450fd720 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -111,6 +111,7 @@ clixon_plugin_statedata(clicon_handle h, { int retval = -1; int ret; + cxobj *xerr = NULL; cxobj *x = NULL; clixon_plugin *cp = NULL; plgstatedata_t *fn; /* Plugin statedata fn */ @@ -124,6 +125,31 @@ clixon_plugin_statedata(clicon_handle h, goto fail; /* Dont quit here on user callbacks */ if (xml_apply(x, CX_ELMNT, xml_spec_populate, yspec) < 0) goto done; + /* Check XML from state callback by validating it. return internal + * error with error cause + */ + if ((ret = xml_yang_validate_all_top(h, x, &xerr)) < 0) + goto done; + if (ret > 0 && (ret = xml_yang_validate_add(h, x, &xerr)) < 0) + goto done; + if (ret == 0){ + cbuf *cberr = NULL; /* XXX Cumbersome, try to fold into one cb */ + cbuf *cberr2 = NULL; + if (netconf_err2cb(xpath_first(xerr, "rpc-error"), &cberr) < 0) + goto done; + if ((cberr2 = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + cprintf(cberr2, "Internal error: state callback returned invalid XML: %s", cbuf_get(cberr)); + if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr2))< 0) + goto done; + if (cberr) + cbuf_free(cberr); + if (cberr2) + cbuf_free(cberr2); + goto fail; + } if ((ret = netconf_trymerge(x, yspec, xret)) < 0) goto done; if (ret == 0) @@ -137,6 +163,8 @@ clixon_plugin_statedata(clicon_handle h, done: if (x) xml_free(x); + if (xerr) + xml_free(xerr); return retval; fail: retval = 0; diff --git a/example/hello/README.md b/example/hello/README.md index 0c7c3a0b..3f851677 100644 --- a/example/hello/README.md +++ b/example/hello/README.md @@ -82,7 +82,7 @@ Start restconf daemon Start sending restconf commands (using Curl): ``` - olof@vandal> curl -X POST http://localhost/restconf/data -d '{"clixon-hello:hello":{"world":null}}' + olof@vandal> curl -X POST http://localhost/restconf/data -H "Content-Type: application/yang-data+json" -d '{"clixon-hello:hello":{"world":null}}' olof@vandal> curl -X GET http://localhost/restconf/data { "data": { diff --git a/example/main/Makefile.in b/example/main/Makefile.in index 98596fd8..cc8cbbfb 100644 --- a/example/main/Makefile.in +++ b/example/main/Makefile.in @@ -79,7 +79,7 @@ all: $(PLUGINS) CLISPECS = $(APPNAME)_cli.cli -YANGSPECS = clixon-example@2019-07-23.yang +YANGSPECS = clixon-example@2019-11-05.yang # Backend plugin BE_SRC = $(APPNAME)_backend.c diff --git a/example/main/README.md b/example/main/README.md index 8abd26ee..b5101aca 100644 --- a/example/main/README.md +++ b/example/main/README.md @@ -206,7 +206,7 @@ clixon_netconf -qf /usr/local/etc/example.xml Restconf (assuming nginx started): ``` sudo su -c "/www-data/clixon_restconf -f /usr/local/etc/example.xml " -s /bin/sh www-data& -curl -X POST http://localhost/restconf/operations/clixon-example:example -d '{"clixon-example:input":{"x":"ipv4"}}' +curl -X POST http://localhost/restconf/operations/clixon-example:example -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"ipv4"}}' { "clixon-example:output": { "x": "ipv4", diff --git a/example/main/clixon-example@2019-07-23.yang b/example/main/clixon-example@2019-11-05.yang similarity index 92% rename from example/main/clixon-example@2019-07-23.yang rename to example/main/clixon-example@2019-11-05.yang index da93468f..b0c8e492 100644 --- a/example/main/clixon-example@2019-07-23.yang +++ b/example/main/clixon-example@2019-11-05.yang @@ -2,6 +2,9 @@ module clixon-example { yang-version 1.1; namespace "urn:example:clixon"; prefix ex; + revision 2019-11-05 { + description "Augment interface. Released in Clixon 4.3.0"; + } revision 2019-07-23 { description "Extension e4. Released in Clixon 4.1.0"; } @@ -42,6 +45,18 @@ module clixon-example { type string; } } + augment "/if:interfaces/if:interface" { + container my-status { + config false; + description "For testing augment+state"; + leaf int { + type int32; + } + leaf str { + type string; + } + } + } /* yang extension implemented by the example backend code. */ extension e4 { description diff --git a/example/main/example_backend.c b/example/main/example_backend.c index 25a38514..928c07d2 100644 --- a/example/main/example_backend.c +++ b/example/main/example_backend.c @@ -317,30 +317,23 @@ example_statedata(clicon_handle h, * state information. In this case adding dummy interface operation state * to configured interfaces. * Get config according to xpath */ - if (xmldb_get0(h, "running", nsc, xpath, 1, &xt, NULL) < 0) + if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) goto done; - - if (yang_find_module_by_namespace(yspec, "urn:ietf:params:xml:ns:yang:ietf-interfaces") != NULL){ - /* Here a separate namespace context nsc1 is created. The original nsc - * created by the system cannot be used trivially, since we dont know - * the prefixes, although we could by a complex mechanism find the prefix - * (if it exists) and use that when creating our xpath. - * But it is easier creating a new namespace context nsc1. - */ - if ((nsc1 = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-interfaces")) == NULL) - goto done; - if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) - goto done; - if (xlen){ - cprintf(cb, ""); - for (i=0; i%sup", name); - } - cprintf(cb, ""); - if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0) - goto done; + if (xmldb_get0(h, "running", nsc1, "/interfaces/interface/name", 1, &xt, NULL) < 0) + goto done; + if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) + goto done; + if (xlen){ + cprintf(cb, ""); + for (i=0; i%sex:ethup", name); + cprintf(cb, "42foo"); + cprintf(cb, ""); } + cprintf(cb, ""); + if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0) + goto done; } /* State in test_yang.sh , test_restconf.sh and test_order.sh */ if (yang_find_module_by_namespace(yspec, "urn:example:clixon") != NULL){ @@ -356,32 +349,14 @@ example_statedata(clicon_handle h, * (2) event-count is XOR on name, so is not 42 and 4 */ if (yang_find_module_by_namespace(yspec, "urn:example:events") != NULL){ - if ((nsc2 = xml_nsctx_init(NULL, "urn:example:events")) == NULL) + cbuf_reset(cb); + cprintf(cb, ""); + cprintf(cb, "interface-down90"); + cprintf(cb, "interface-up77"); + cprintf(cb, ""); + if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0) goto done; - if (xvec){ - free(xvec); - xvec = NULL; - } - if (xpath_vec_nsc(xt, nsc2, "/events/event/name", &xvec, &xlen) < 0) - goto done; - if (xlen){ - int j = 0; - int c; - cprintf(cb, ""); - - for (i=0; i%s%d", name, c); - } - cprintf(cb, ""); - if (xml_parse_string(cbuf_get(cb), NULL, &xstate) < 0) - goto done; - } } - ok: retval = 0; done: diff --git a/lib/clixon/clixon_proto_client.h b/lib/clixon/clixon_proto_client.h index 56bcf9ef..bf1ffc0a 100644 --- a/lib/clixon/clixon_proto_client.h +++ b/lib/clixon/clixon_proto_client.h @@ -44,7 +44,7 @@ int clicon_rpc_msg(clicon_handle h, struct clicon_msg *msg, cxobj **xret0, int *sock0); int clicon_rpc_netconf(clicon_handle h, char *xmlst, cxobj **xret, int *sp); int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp); -int clicon_rpc_generate_error(char *format, cxobj *xerr); +int clicon_rpc_generate_error(const char *format, cxobj *xerr); int clicon_rpc_get_config(clicon_handle h, char *username, char *db, char *xpath, cvec *nsc, cxobj **xret); int clicon_rpc_edit_config(clicon_handle h, char *db, enum operation_type op, char *xml); diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index 8a908f03..250acfe5 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -78,6 +78,7 @@ int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop, int xml2xpath(cxobj *x, char **xpath); int xml2api_path_1(cxobj *x, cbuf *cb); +int check_namespaces(cxobj *x0, cxobj *x1, cxobj *x1p); int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason); int yang_enum_int_value(cxobj *node, int32_t *val); diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index b6f294da..9daf9b93 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -132,138 +132,6 @@ attr_ns_value(cxobj *x, goto done; } -/*! Given a src node x0 and a target node x1, assign (optional) prefix and namespace - * @param[in] x0 Source XML tree - * @param[in] x1 Target XML tree - * 1. Find N=namespace(x0) - * 2. Detect if N is declared in x1 parent - * 3. If yes, assign prefix to x1 - * 4. If no, create new prefix/namespace binding and assign that to x1p (x1 if x1p is root) - * 5. Add prefix to x1, if any - * 6. Ensure x1 cache is updated - * @note switch use of x0 and x1 compared to datastore text_modify - * @see xml2ns - * XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0) - goto done; - */ -static int -check_namespaces(cxobj *x0, - cxobj *x1, - cxobj *x1p) -{ - int retval = -1; - char *namespace = NULL; - char *prefix0 = NULL;; - char *prefix10 = NULL; /* extra just for malloc problem */ - char *prefix1 = NULL;; - char *prefixb = NULL; /* identityref body prefix */ - cvec *nsc0 = NULL; - cvec *nsc = NULL; - cxobj *xa = NULL; - cxobj *x; - int isroot; - - /* XXX: need to identify root better than hiereustics and strcmp,... */ - isroot = xml_parent(x1p)==NULL && - strcmp(xml_name(x1p), "config") == 0 && - xml_prefix(x1p)==NULL; - - /* 1. Find N=namespace(x0) */ - prefix0 = xml_prefix(x0); - if (xml2ns(x0, prefix0, &namespace) < 0) - goto done; - if (namespace == NULL){ - clicon_err(OE_XML, ENOENT, "No namespace found for prefix:%s", - prefix0?prefix0:"NULL"); - goto done; - } - /* 2. Detect if namespace is declared in x1:s parent */ - if (xml2prefix(x1p, namespace, &prefix10) == 1){ - if (prefix10){ - if ((prefix1 = strdup(prefix10)) == NULL){ - clicon_err(OE_UNIX, errno, "strdup"); - goto done; - } - } - else - prefix1 = NULL; - /* 3. If yes, assign prefix to x1 */ - if (prefix1 && xml_prefix_set(x1, prefix1) < 0) - goto done; - /* And copy namespace context from parent to child */ - if ((nsc0 = nscache_get_all(x1p)) != NULL){ - if ((nsc = cvec_dup(nsc0)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_dup"); - goto done; - } - nscache_replace(x1, nsc); - } - /* Just in case */ - if (nscache_set(x1, prefix1, namespace) < 0) - goto done; - } - else{ - /* 4. If no, create new prefix/namespace binding and assign that to x1p - * use modules own default prefix (some chance for clash) - */ - if (prefix0 == NULL && !isroot){ - assert(xml_spec(x1) != NULL); - prefix0 = yang_find_myprefix(xml_spec(x1)); - } - if (prefix0) - if ((prefix1 = strdup(prefix0)) == NULL){ - clicon_err(OE_UNIX, errno, "strdup"); - goto done; - } - - /* Add binding to x1p. We add to parent due to heurestics, so we dont - * end up in adding it to large number of siblings - */ - if (isroot) - x = x1; - else - x = x1p; - if (nscache_set(x, prefix1, namespace) < 0) - goto done; - if (x == x1p){ - if ((nsc0 = nscache_get_all(x1p)) != NULL) - if ((nsc = cvec_dup(nsc0)) == NULL){ - clicon_err(OE_UNIX, errno, "cvec_dup"); - goto done; - } - /* Copy x1p cache to x1 */ - nscache_replace(x1, nsc); - } - /* Create xmlns attribute to x1p/x1 XXX same code v */ - if (prefix1){ - if ((xa = xml_new(prefix1, x, NULL)) == NULL) - goto done; - if (xml_prefix_set(xa, "xmlns") < 0) - goto done; - } - else{ - if ((xa = xml_new("xmlns", x, NULL)) == NULL) - goto done; - } - xml_type_set(xa, CX_ATTR); - if (xml_value_set(xa, namespace) < 0) - goto done; - xml_sort(x, NULL); /* Ensure attr is first / XXX xml_insert? */ - - /* 5. Add prefix to x1, if any */ - if (prefix1 && xml_prefix_set(x1, prefix1) < 0) - goto done; - } - /* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */ - retval = 0; - done: - if (prefixb) - free(prefixb); - if (prefix1) - free(prefix1); - return retval; -} - static int check_identityref(cxobj *x0, cxobj *x1, diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index e8601af4..2f9efaec 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1338,7 +1338,7 @@ netconf_db_find(cxobj *xn, } /*! Generate netconf error msg to cbuf to use in string printout or logs - * @param[in] xerr Netconf error message on the level: + * @param[in] xerr Netconf error message on the level: * @param[out] cberr Translation from netconf err to cbuf. Free with cbuf_free. * @retval 0 OK, with cberr set * @retval -1 Error diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 785b1eb0..146cc52a 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -227,11 +227,11 @@ clicon_rpc_netconf_xml(clicon_handle h, /*! Generate and log clicon error function call from Netconf error message * @param[in] prefix Print this string (if given) before: ": " - * @param[in] xerr Netconf error message on the level: + * @param[in] xerr Netconf error message on the level: */ int -clicon_rpc_generate_error(char *prefix, - cxobj *xerr) +clicon_rpc_generate_error(const char *prefix, + cxobj *xerr) { int retval = -1; cbuf *cb = NULL; diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index a1dc2730..e6217e37 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2153,6 +2153,46 @@ xml_tree_prune_flagged(cxobj *xt, return retval; } +/*! Add prefix:namespace pair to xml node, set cache, prefix, etc + */ +static int +add_namespace(cxobj *x1, /* target */ + cxobj *x1p, + char *prefix1, + char *namespace) +{ + int retval = -1; + cxobj *xa = NULL; + + /* Add binding to x1p. We add to parent due to heurestics, so we dont + * end up in adding it to large number of siblings + */ + if (nscache_set(x1, prefix1, namespace) < 0) + goto done; + /* Create xmlns attribute to x1p/x1 XXX same code v */ + if (prefix1){ + if ((xa = xml_new(prefix1, x1, NULL)) == NULL) + goto done; + if (xml_prefix_set(xa, "xmlns") < 0) + goto done; + } + else{ + if ((xa = xml_new("xmlns", x1, NULL)) == NULL) + goto done; + } + xml_type_set(xa, CX_ATTR); + if (xml_value_set(xa, namespace) < 0) + goto done; + xml_sort(x1, NULL); /* Ensure attr is first / XXX xml_insert? */ + + /* 5. Add prefix to x1, if any */ + if (prefix1 && xml_prefix_set(x1, prefix1) < 0) + goto done; + retval = 0; + done: + return retval; +} + /*! Add default values (if not set) * @param[in] xt XML tree with some node marked * @param[in] arg Ignored @@ -2175,6 +2215,7 @@ xml_default(cxobj *xt, int added=0; char *namespace; char *prefix; + int ret; if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){ retval = 0; @@ -2195,9 +2236,22 @@ xml_default(cxobj *xt, /* assign right prefix */ if ((namespace = yang_find_mynamespace(y)) != NULL){ prefix = NULL; - if (xml2prefix(xt, namespace, &prefix)) + if ((ret = xml2prefix(xt, namespace, &prefix)) < 0) + goto done; + if (ret){ if (xml_prefix_set(xc, prefix) < 0) goto done; + } + else{ /* namespace does not exist in target, use source prefix */ + char *prefix1 = NULL; + if ((prefix1 = strdup(yang_find_myprefix(y))) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + + if (add_namespace(xc, xt, prefix1, namespace) < 0) + goto done; + } } xml_flag_set(xc, XML_FLAG_DEFAULT); @@ -3190,6 +3244,124 @@ xmlns_assign(cxobj *x) return retval; } +/*! Given a src node x0 and a target node x1, assign (optional) prefix and namespace + * @param[in] x0 Source XML tree + * @param[in] x1 Target XML tree + * 1. Find N=namespace(x0) + * 2. Detect if N is declared in x1 parent + * 3. If yes, assign prefix to x1 + * 4. If no, create new prefix/namespace binding and assign that to x1p (x1 if x1p is root) + * 5. Add prefix to x1, if any + * 6. Ensure x1 cache is updated + * @note switch use of x0 and x1 compared to datastore text_modify + * @see xml2ns + * XXX: fail handling: if (netconf_data_missing(cbret, NULL, "Data does not exist; cannot delete resource") < 0) + goto done; + */ +int +check_namespaces(cxobj *x0, /* source */ + cxobj *x1, /* target */ + cxobj *x1p) +{ + int retval = -1; + char *namespace = NULL; + char *prefix0 = NULL;; + char *prefix1 = NULL; + char *prefixb = NULL; /* identityref body prefix */ + cvec *nsc0 = NULL; + cvec *nsc = NULL; + int isroot; + char *pexist = NULL; + yang_stmt *y; + + /* XXX: need to identify root better than hiereustics and strcmp,... */ + isroot = xml_parent(x1p)==NULL && + (strcmp(xml_name(x1p), "config") == 0 || strcmp(xml_name(x1p), "top") == 0)&& + xml_prefix(x1p)==NULL; + + /* 1. Find N=namespace(x0) */ + prefix0 = xml_prefix(x0); + if (xml2ns(x0, prefix0, &namespace) < 0) + goto done; + if (namespace == NULL){ + clicon_err(OE_XML, ENOENT, "No namespace found for prefix:%s", + prefix0?prefix0:"NULL"); + goto done; + } + /* 2a. Detect if namespace is declared in x1 target parent */ + if (xml2prefix(x1p, namespace, &pexist) == 1){ + /* Yes, and it has prefix pexist */ + if (pexist){ + if ((prefix1 = strdup(pexist)) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + } + else + prefix1 = NULL; + /* 3. If yes, assign prefix to x1 */ + if (prefix1 && xml_prefix_set(x1, prefix1) < 0) + goto done; + /* And copy namespace context from parent to child */ + if ((nsc0 = nscache_get_all(x1p)) != NULL){ + if ((nsc = cvec_dup(nsc0)) == NULL){ + clicon_err(OE_UNIX, errno, "cvec_dup"); + goto done; + } + nscache_replace(x1, nsc); + } + /* Just in case */ + if (nscache_set(x1, prefix1, namespace) < 0) + goto done; + } + else{ /* No, namespace does not exist in x1 _parent_ + * Check if it is exists in x1 itself */ + if (nscache_get_prefix(x1, namespace, &pexist) == 1){ + /* Yes it exists, but is it equal? */ + if ((pexist == NULL && prefix0 == NULL) || + (pexist && prefix0 && + strcmp(pexist, prefix0)==0)){ /* Equal, reuse */ + ; + } + else{ /* namespace exist, but not equal, use existing */ + /* Add prefix to x1, if any */ + if (pexist && xml_prefix_set(x1, pexist) < 0) + goto done; + } + goto ok; /* skip */ + } + else + { /* namespace does not exist in target x1, use source prefix + * use the prefix defined in the module + */ + if (isroot){ + if (prefix0 && (prefix1 = strdup(prefix0)) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + } + else{ + y = xml_spec(x0); + if ((prefix1 = strdup(yang_find_myprefix(y))) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + } + } + if (add_namespace(x1, x1p, prefix1, namespace) < 0) + goto done; + } + ok: + /* 6. Ensure x1 cache is updated (I think it is done w xmlns_set above) */ + retval = 0; + done: + if (prefixb) + free(prefixb); + if (prefix1) + free(prefix1); + return retval; +} + /*! Merge a base tree x0 with x1 with yang spec y * @param[in] x0 Base xml tree (can be NULL in add scenarios) * @param[in] y0 Yang spec corresponding to xml-node x0. NULL if x0 is NULL @@ -3201,20 +3373,18 @@ xmlns_assign(cxobj *x) * Assume x0 and x1 are same on entry and that y is the spec */ static int -xml_merge1(cxobj *x0, +xml_merge1(cxobj *x0, /* the target */ yang_stmt *y0, cxobj *x0p, - cxobj *x1, + cxobj *x1, /* the source */ char **reason) { int retval = -1; - char *x1name; char *x1cname; /* child name */ cxobj *x0c; /* base child */ cxobj *x0b; /* base body */ cxobj *x1c; /* mod child */ - cxobj *x0a; /* x0 xmlns attribute */ - cxobj *x1a; /* x1 xmlns attribute */ + char *x1name; char *x1bstr; /* mod body string */ yang_stmt *yc; /* yang child */ cbuf *cbr = NULL; /* Reason buffer */ @@ -3243,13 +3413,16 @@ xml_merge1(cxobj *x0, if (xml_value_set(x0b, x1bstr) < 0) goto done; } - + if (check_namespaces(x1, x0, x0p) < 0) + goto done; } /* if LEAF|LEAF_LIST */ else { /* eg Y_CONTAINER, Y_LIST */ if (x0==NULL){ - if ((x0 = xml_new(x1name, x0p, (yang_stmt*)y0)) == NULL) + if ((x0 = xml_new(x1name, NULL, (yang_stmt*)y0)) == NULL) goto done; } + if (check_namespaces(x1, x0, x0p) < 0) + goto done; /* Loop through children of the modification tree */ x1c = NULL; while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) { @@ -3277,19 +3450,11 @@ xml_merge1(cxobj *x0, goto done; if (*reason != NULL) goto ok; - } + } /* while */ + if (xml_parent(x0) == NULL && + xml_insert(x0p, x0, INS_LAST, NULL, NULL) < 0) + goto done; } /* else Y_CONTAINER */ - assert(x0); - /* Copy xmlns attributes (if it does not already exist) */ - if ((x1a = xml_find_type(x1, NULL, "xmlns", CX_ATTR)) != NULL) - if (xml_find_type(x0, NULL, "xmlns", CX_ATTR)==NULL){ - if ((x0a = xml_dup(x1a)) == NULL) - goto done; - if (xml_addsub(x0, x0a) < 0) - goto done; - } - - ok: retval = 0; done: diff --git a/test/test_augment.sh b/test/test_augment.sh index fcbc9251..2cc1db1b 100755 --- a/test/test_augment.sh +++ b/test/test_augment.sh @@ -12,6 +12,8 @@ # 2. example-augment - urn:example:augment - mymod # (augmented): mandatory-leaf, me, other, # (uses/grouping): ip, port, lid, lport +# Note augment+state not tested here (need plugin), simple test in test_restconf.sh +# # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -217,13 +219,12 @@ new "restconf get augment json" expectpart "$(curl -s -i -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}} ' new "restconf get augment xml" -expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' 'e1mymod:some-new-iftypetrue808080e2fdditrueif:fddi808080e3fdditruemymod:you808080' - +expectpart "$(curl -s -i -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK ' 'e1mymod:some-new-iftypetrue808080e2fdditrueif:fddi808080e3fdditruemymod:you808080' #e123' XML=$(cat <e123' +e1mymod:some-new-iftypetrue23' EOF ) @@ -240,10 +241,10 @@ new "restconf POST augment multi-namespace path e2 (middle path)" expectpart "$(curl -s -X POST -H 'Content-Type: application/yang-data+xml' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e2 -d "$XML" )" 0 '' new "restconf GET augment multi-namespace top" -expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","example-augment:ospf":{"reference-bandwidth":23},"example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}' +expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interfaces":{"interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080},{"name":"e2","type":"fddi","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:other":"ietf-interfaces:fddi","example-augment:port":80,"example-augment:lport":8080},{"name":"e3","type":"fddi","example-augment:mandatory-leaf":"true","example-augment:me":"you","example-augment:port":80,"example-augment:lport":8080}\]}}' new "restconf GET augment multi-namespace level 1" -expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"e1","example-augment:ospf":{"reference-bandwidth":23},"example-augment:port":80,"example-augment:lport":8080}\]}' +expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 'HTTP/1.1 200 OK' '{"ietf-interfaces:interface":\[{"name":"e1","type":"example-augment:some-new-iftype","example-augment:ospf":{"reference-bandwidth":23},"example-augment:mandatory-leaf":"true","example-augment:port":80,"example-augment:lport":8080}\]}' new "restconf GET augment multi-namespace cross" expectpart "$(curl -si -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1/example-augment:ospf)" 0 'HTTP/1.1 200 OK' '{"example-augment:ospf":{"reference-bandwidth":23}}' diff --git a/test/test_netconf.sh b/test/test_netconf.sh index b08d3af9..e0476c1e 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -102,7 +102,7 @@ cat < $tmp # new EOF new "netconf get config xpath" -expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^eth1true]]>]]>$' +expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^eth1true]]>]]>$' # Too many quotes cat < $tmp # new @@ -110,7 +110,7 @@ cat < $tmp # new EOF new "netconf get config xpath parent" -expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^eth/0/0trueeth1truetruefalse9.2.3.424]]>]]>$' +expecteof "$clixon_netconf -qf $cfg" 0 "$(cat $tmp)" '^eth/0/0trueeth1truetruefalse9.2.3.424]]>]]>$' new "netconf validate missing type" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^" @@ -163,7 +163,7 @@ new "netconf edit state operation should fail" expecteof "$clixon_netconf -qf $cfg" 0 'e0up]]>]]>' "^protocolinvalid-valueerrorState data not allowed]]>]]>" new "netconf get state operation" -expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^eth1ex:ethtrueup]]>]]>$' +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^eth1ex:ethtrueup42foo]]>]]>$' new "netconf lock/unlock" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>]]>]]>" "^]]>]]>]]>]]>$" diff --git a/test/test_perf_state.sh b/test/test_perf_state.sh index 61a2359a..402cfd3f 100755 --- a/test/test_perf_state.sh +++ b/test/test_perf_state.sh @@ -90,7 +90,7 @@ expecteof "time $clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>" -expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^e1ex:ethtrueup]]>]]>$' +expecteof "$clixon_netconf -qf $cfg" 0 "$msg" '^e1ex:ethtrueup42foo]]>]]>$' new "netconf get $perfreq single reqs" { time -p for (( i=0; i<$perfreq; i++ )); do @@ -101,7 +101,7 @@ done | $clixon_netconf -qf $cfg > /dev/null; } 2>&1 | awk '/real/ {print $2}' # RESTCONF get new "restconf get test single req" -expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface":[{"name":"e1","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]} +expecteq "$(curl -s -X GET http://localhost/restconf/data/ietf-interfaces:interfaces/interface=e1)" 0 '{"ietf-interfaces:interface":[{"name":"e1","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]} ' new "restconf get $perfreq single reqs" diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 80997b19..433f8d6b 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -194,12 +194,16 @@ new "restconf Add interfaces subtree eth/0/0 using POST" expectpart "$(curl -s -X POST http://localhost/restconf/data/ietf-interfaces:interfaces -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}')" 0 "" new "restconf Check eth/0/0 added config" -expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}\]}} - ' +expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}}' + +new "restconf Check eth/0/0 GET augmented state level 1" +expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 '{"ietf-interfaces:interface":\[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}\]}' + +new "restconf Check eth/0/0 GET augmented state level 2" +expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0/clixon-example:my-status)" 0 '{"clixon-example:my-status":{"int":42,"str":"foo"}}' new "restconf Check eth/0/0 added state" -expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":\["42","41","43"\]}} - ' +expectpart "$(curl -s -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/clixon-example:state)" 0 '{"clixon-example:state":{"op":\["42","41","43"\]}}' new "restconf Re-post eth/0/0 which should generate error" expectpart "$(curl -s -X POST -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"data-exists","error-severity":"error","error-message":"Data already exists; cannot create new resource"}}} ' @@ -211,7 +215,7 @@ new "Add nothing using POST (expect fail)" expectpart "$(curl -is -X POST -H "Content-Type: application/yang-data+json" http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"rpc","error-tag":"malformed-message","error-severity":"error","error-message":"The message-body MUST contain exactly one instance of the expected data resource"}}}' new "restconf Check description added" -expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}} +expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","description":"The-first-interface","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]}} ' new "restconf delete eth/0/0" @@ -227,7 +231,7 @@ new "restconf Add subtree eth/0/0 using PUT" expecteq "$(curl -s -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-interfaces:interface":{"name":"eth/0/0","type":"clixon-example:eth","enabled":true}}' http://localhost/restconf/data/ietf-interfaces:interfaces/interface=eth%2f0%2f0)" 0 "" new "restconf get subtree" -expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up"}]}} +expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces)" 0 '{"ietf-interfaces:interfaces":{"interface":[{"name":"eth/0/0","type":"clixon-example:eth","enabled":true,"oper-status":"up","clixon-example:my-status":{"int":42,"str":"foo"}}]}} ' new "restconf rpc using POST json" diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index ccb1de91..e5631a9c 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -99,7 +99,7 @@ expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://loca # This just catches the header and the jukebox module, the RFC has foo and bar which # seems wrong to recreate new "B.1.2. Retrieve the Server Module Information" -expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":' '"module":\[{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"}' +expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+json' http://localhost/restconf/data/ietf-yang-library:modules-state)" 0 "HTTP/1.1 200 OK" 'Cache-Control: no-cache' "Content-Type: application/yang-data+json" '{"ietf-yang-library:modules-state":{"module-set-id":"0","module":\[{"name":"clixon-lib","revision":"2019-08-13","namespace":"http://clicon.org/lib","conformance-type":"implement"},{"name":"clixon-rfc5277","revision":"2008-07-01","namespace":"urn:ietf:params:xml:ns:netmod:notification","conformance-type":"implement"},{"name":"example-events","revision":\[null\],"namespace":"urn:example:events","conformance-type":"implement"},{"name":"example-jukebox","revision":"2016-08-15","namespace":"http://example.com/ns/example-jukebox","conformance-type":"implement"' new "B.1.3. Retrieve the Server Capability Information" expectpart "$(curl -si -X GET -H 'Accept: application/yang-data+xml' http://localhost/restconf/data/ietf-restconf-monitoring:restconf-state/capabilities)" 0 "HTTP/1.1 200 OK" "Content-Type: application/yang-data+xml" 'Cache-Control: no-cache' 'urn:ietf:params:restconf:capability:defaults:1.0?basic-mode=expliciturn:ietf:params:restconf:capability:depth From 1defd2afc74adb30eaae33cfce48d6b4aeac3d94 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 11 Nov 2019 21:47:03 +0100 Subject: [PATCH 03/23] memleak --- CHANGELOG.md | 2 -- lib/src/clixon_xml_map.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d7dc3ac..3b98429f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,11 @@ * State callbacks provided by user are validated. If they are invalid an internal error is returned. * Fixed multi-namespace for augmented state which was not covered in 4.2.0. - ### API changes on existing features (you may need to change your code) * The multi-namespace augment state may rearrange the XML namespace attributes. * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. ### Corrected Bugs - * Mandatory variables can no longer be deleted. * [Add missing includes](https://github.com/clicon/clixon/pulls) diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index e6217e37..a5f03729 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2243,12 +2243,10 @@ xml_default(cxobj *xt, goto done; } else{ /* namespace does not exist in target, use source prefix */ - char *prefix1 = NULL; - if ((prefix1 = strdup(yang_find_myprefix(y))) == NULL){ + if ((prefix = yang_find_myprefix(y)) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); goto done; } - if (add_namespace(xc, xt, prefix1, namespace) < 0) goto done; } From 58f3d7b59a769f45ce0f00f89aa1ba11f88bc63c Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 11 Nov 2019 21:52:21 +0100 Subject: [PATCH 04/23] compile error --- lib/src/clixon_xml_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index a5f03729..3709e124 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -2247,7 +2247,7 @@ xml_default(cxobj *xt, clicon_err(OE_UNIX, errno, "strdup"); goto done; } - if (add_namespace(xc, xt, prefix1, namespace) < 0) + if (add_namespace(xc, xt, prefix, namespace) < 0) goto done; } } From 70caeaa783ab6506916827ef50a6d127db316954 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 12 Nov 2019 20:17:43 +0100 Subject: [PATCH 05/23] mandatory test --- test/test_type.sh | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/test/test_type.sh b/test/test_type.sh index 1538fbbd..2ef9a177 100755 --- a/test/test_type.sh +++ b/test/test_type.sh @@ -196,6 +196,14 @@ module example{ description "For testing different truth values in CLI"; type boolean; } + container manc{ + presence true; + description "mandatory test"; + leaf man{ + type string; + mandatory true; + } + } } EOF @@ -247,7 +255,6 @@ EOF new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" - new "netconf set transitive string error" expecteof "$clixon_netconf -qf $cfg" 0 '9xx]]>]]>' "^]]>]]>" @@ -593,6 +600,32 @@ EOF new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" + #------ Mandatory + + new "netconf set container w/o mandatory leaf" + expecteof "$clixon_netconf -qf $cfg" 0 ']]>]]>' "^]]>]]>" + + new "netconf validate should fail" + expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" 'applicationmissing-elementmanerrorMandatory variable]]>]]>' + + new "netconf set container with mandatory leaf" + expecteof "$clixon_netconf -qf $cfg" 0 'foo]]>]]>' "^]]>]]>" + + new "netconf commit" + expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" + + new "netconf delete mandatory variable" + expecteof "$clixon_netconf -qf $cfg" 0 'foonone]]>]]>' '^]]>]]>$' + + new "get mandatory" + expecteof "$clixon_netconf -qf $cfg" 0 ']]>]]>' '^]]>]]>$' + + new "netconf validate should fail" + expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^protocolmissing-elementmanerrorMay not remove mandatory variable]]>]]>$' + + new "netconf discard-changes" + expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" + #------ minus new "type with minus" From 6b9a9d46f944857b97323a49aee516361a503898 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 12 Nov 2019 20:47:09 +0100 Subject: [PATCH 06/23] changed netconf_err2cb --- apps/backend/backend_plugin.c | 19 ++++++------------- lib/clixon/clixon_netconf_lib.h | 2 +- lib/src/clixon_netconf_lib.c | 27 ++++++++++++--------------- lib/src/clixon_proto_client.c | 6 +++++- util/clixon_util_xml.c | 6 +++++- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 450fd720..29038b63 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -115,6 +115,7 @@ clixon_plugin_statedata(clicon_handle h, cxobj *x = NULL; clixon_plugin *cp = NULL; plgstatedata_t *fn; /* Plugin statedata fn */ + cbuf *cberr = NULL; while ((cp = clixon_plugin_each(h, cp)) != NULL) { if ((fn = cp->cp_api.ca_statedata) == NULL) @@ -133,21 +134,11 @@ clixon_plugin_statedata(clicon_handle h, if (ret > 0 && (ret = xml_yang_validate_add(h, x, &xerr)) < 0) goto done; if (ret == 0){ - cbuf *cberr = NULL; /* XXX Cumbersome, try to fold into one cb */ - cbuf *cberr2 = NULL; - if (netconf_err2cb(xpath_first(xerr, "rpc-error"), &cberr) < 0) + cprintf(cberr, "Internal error: state callback returned invalid XML: "); + if (netconf_err2cb(xpath_first(xerr, "rpc-error"), cberr) < 0) goto done; - if ((cberr2 = cbuf_new()) == NULL){ - clicon_err(OE_UNIX, errno, "cbuf_new"); + if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr))< 0) goto done; - } - cprintf(cberr2, "Internal error: state callback returned invalid XML: %s", cbuf_get(cberr)); - if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr2))< 0) - goto done; - if (cberr) - cbuf_free(cberr); - if (cberr2) - cbuf_free(cberr2); goto fail; } if ((ret = netconf_trymerge(x, yspec, xret)) < 0) @@ -161,6 +152,8 @@ clixon_plugin_statedata(clicon_handle h, } retval = 1; done: + if (cberr) + cbuf_free(cberr); if (x) xml_free(x); if (xerr) diff --git a/lib/clixon/clixon_netconf_lib.h b/lib/clixon/clixon_netconf_lib.h index 463671c2..06e5c83b 100644 --- a/lib/clixon/clixon_netconf_lib.h +++ b/lib/clixon/clixon_netconf_lib.h @@ -90,7 +90,7 @@ int netconf_trymerge(cxobj *x, yang_stmt *yspec, cxobj **xret); int netconf_module_features(clicon_handle h); int netconf_module_load(clicon_handle h); char *netconf_db_find(cxobj *xn, char *name); -int netconf_err2cb(cxobj *xerr, cbuf **cberr); +int netconf_err2cb(cxobj *xerr, cbuf *cberr); const netconf_content netconf_content_str2int(char *str); const char *netconf_content_int2str(netconf_content nr); int netconf_hello_server(clicon_handle h, cbuf *cb, uint32_t session_id); diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 2f9efaec..78d18692 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1338,39 +1338,36 @@ netconf_db_find(cxobj *xn, } /*! Generate netconf error msg to cbuf to use in string printout or logs - * @param[in] xerr Netconf error message on the level: - * @param[out] cberr Translation from netconf err to cbuf. Free with cbuf_free. + * @param[in] xerr Netconf error message on the level: + * @param[in,out] cberr Translation from netconf err to cbuf. * @retval 0 OK, with cberr set * @retval -1 Error * @code - * cbuf *cb = NULL; - * if (netconf_err2cb(xerr, &cb) < 0) + * cbuf *cb = NULL; + * if ((cb = cbuf_new()) ==NULL){ + * err; + * if (netconf_err2cb(xerr, cb) < 0) * err; * printf("%s", cbuf_get(cb)); + * cbuf_free(cb); * @endcode * @see clicon_rpc_generate_error */ int netconf_err2cb(cxobj *xerr, - cbuf **cberr) + cbuf *cberr) { int retval = -1; - cbuf *cb = NULL; cxobj *x; - if ((cb = cbuf_new()) ==NULL){ - clicon_err(OE_XML, errno, "cbuf_new"); - goto done; - } if ((x=xpath_first(xerr, "error-type"))!=NULL) - cprintf(cb, "%s ", xml_body(x)); + cprintf(cberr, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-tag"))!=NULL) - cprintf(cb, "%s ", xml_body(x)); + cprintf(cberr, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-message"))!=NULL) - cprintf(cb, "%s ", xml_body(x)); + cprintf(cberr, "%s ", xml_body(x)); if ((x=xpath_first(xerr, "error-info"))!=NULL) - clicon_xml2cbuf(cb, xml_child_i(x,0), 0, 0, -1); - *cberr = cb; + clicon_xml2cbuf(cberr, xml_child_i(x,0), 0, 0, -1); retval = 0; done: return retval; diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 146cc52a..a1de8f4e 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -236,7 +236,11 @@ clicon_rpc_generate_error(const char *prefix, int retval = -1; cbuf *cb = NULL; - if (netconf_err2cb(xerr, &cb) < 0) + if ((cb = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if (netconf_err2cb(xerr, cb) < 0) goto done; if (prefix) clicon_log(LOG_ERR, "%s: %s", prefix, cbuf_get(cb)); diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c index 45a1b0e7..30b4d9e2 100644 --- a/util/clixon_util_xml.c +++ b/util/clixon_util_xml.c @@ -234,7 +234,11 @@ main(int argc, if (ret > 0 && (ret = xml_yang_validate_add(h, xc, &xerr)) < 0) goto done; if (ret == 0){ - if (netconf_err2cb(xerr, &cbret) < 0) + if ((cbret = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if (netconf_err2cb(xerr, cbret) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret)); goto done; From 039e08f86a1a9c3522bf595100b0f68a84ad3ce9 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 14 Nov 2019 20:57:20 +0100 Subject: [PATCH 07/23] [xml_parse_string() is slow for a long XML string #96](https://github.com/clicon/clixon/issues/96) --- CHANGELOG.md | 1 + lib/src/clixon_netconf_lib.c | 1 - lib/src/clixon_options.c | 6 ++- lib/src/clixon_xml.c | 89 +++++++++++++++++++++++----------- lib/src/clixon_xml_changelog.c | 6 ++- lib/src/clixon_xml_parse.l | 9 +++- util/clixon_util_xpath.c | 6 ++- 7 files changed, 83 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b98429f..64a5c564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. ### Corrected Bugs +* [xml_parse_string() is slow for a long XML string #96](https://github.com/clicon/clixon/issues/96) * Mandatory variables can no longer be deleted. * [Add missing includes](https://github.com/clicon/clixon/pulls) diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 78d18692..69ffb640 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1369,7 +1369,6 @@ netconf_err2cb(cxobj *xerr, if ((x=xpath_first(xerr, "error-info"))!=NULL) clicon_xml2cbuf(cberr, xml_child_i(x,0), 0, 0, -1); retval = 0; - done: return retval; } diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 42b8326f..72feb443 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -256,7 +256,11 @@ parse_configfile(clicon_handle h, if ((ret = xml_yang_validate_add(h, xc, &xret)) < 0) goto done; if (ret == 0){ - if (netconf_err2cb(xret, &cbret) < 0) + if ((cbret = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if (netconf_err2cb(xret, cbret) < 0) goto done; clicon_err(OE_CFG, 0, "Config file validation: %s", cbuf_get(cbret)); goto done; diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index 947647e7..be8a36b8 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -78,6 +78,8 @@ #define XML_TOP_SYMBOL "top" /* How many XML children to start with if any (and then add exponentialy) */ #define XML_CHILDVEC_MAX_DEFAULT 4 +/* Initial length of x_value malloced string */ +#define XML_VALUE_MAX_DEFAULT 32 /* * Types @@ -125,6 +127,8 @@ struct xml{ int x_childvec_max;/* Length of allocated vector */ enum cxobj_type x_type; /* type of node: element, attribute, body */ char *x_value; /* attribute and body nodes have values */ + uint32_t x_value_len; /* Length of x_value string (excluding null) */ + uint32_t x_value_max; /* allocated size for x_value */ int x_flags; /* Flags according to XML_FLAG_* */ yang_stmt *x_spec; /* Pointer to specification, eg yang, by reference, dont free */ @@ -623,6 +627,42 @@ xml_value(cxobj *xn) return xn->x_value; } +/*! xml value string reallocator + */ +static int +xml_value_realloc(cxobj *xn, + int len0, + char *val) +{ + int retval = -1; + int len; + int diff; + + if (val==NULL) + goto ok; + len = len0 + strlen(val); + diff = xn->x_value_max - (len + 1); + if (diff <= 0){ + while (diff <= 0){ + if (xn->x_value_max == 0) + xn->x_value_max = XML_VALUE_MAX_DEFAULT; + else + xn->x_value_max *= 2; + diff = xn->x_value_max - (len + 1); + } + if ((xn->x_value = realloc(xn->x_value, xn->x_value_max)) == NULL){ + clicon_err(OE_XML, errno, "realloc"); + goto done; + } + } + strncpy(xn->x_value + len0, val, len-len0+1); + xn->x_value_len = len; + ok: + retval = 0; + done: + return retval; +} + /*! Set value of xml node, value is copied * @param[in] xn xml node * @param[in] val new value, null-terminated string, copied by function @@ -633,17 +673,17 @@ int xml_value_set(cxobj *xn, char *val) { - if (xn->x_value){ - free(xn->x_value); - xn->x_value = NULL; + int retval = -1; + + if (xn->x_value && strlen(xn->x_value)){ + xn->x_value[0] = '\0'; + xn->x_value_len = 0; } - if (val){ - if ((xn->x_value = strdup(val)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - return -1; - } - } - return 0; + if (xml_value_realloc(xn, 0, val) < 0) + goto done; + retval = 0; + done: + return retval; } /*! Append value of xnode, value is copied @@ -656,18 +696,8 @@ char * xml_value_append(cxobj *xn, char *val) { - int len0; - int len; - - len0 = xn->x_value?strlen(xn->x_value):0; - if (val){ - len = len0 + strlen(val); - if ((xn->x_value = realloc(xn->x_value, len+1)) == NULL){ - clicon_err(OE_XML, errno, "realloc"); - return NULL; - } - strncpy(xn->x_value + len0, val, len-len0+1); - } + if (xml_value_realloc(xn, xn->x_value_len, val) < 0) + return NULL; return xn->x_value; } @@ -2141,22 +2171,23 @@ int xml_copy_one(cxobj *x0, cxobj *x1) { + int retval = -1; char *s; xml_type_set(x1, xml_type(x0)); if ((s = xml_value(x0))){ /* malloced string */ - if ((x1->x_value = strdup(s)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - return -1; - } + if (xml_value_set(x1, s) < 0) + goto done; } if ((s = xml_name(x0))) /* malloced string */ if ((xml_name_set(x1, s)) < 0) - return -1; + goto done; if ((s = xml_prefix(x0))) /* malloced string */ if ((xml_prefix_set(x1, s)) < 0) - return -1; - return 0; + goto done; + retval = 0; + done: + return retval; } /*! Copy xml tree x0 to other existing tree x1 diff --git a/lib/src/clixon_xml_changelog.c b/lib/src/clixon_xml_changelog.c index 80cbb0fc..3335beb2 100644 --- a/lib/src/clixon_xml_changelog.c +++ b/lib/src/clixon_xml_changelog.c @@ -451,7 +451,11 @@ clixon_xml_changelog_init(clicon_handle h) if (ret==1 && (ret = xml_yang_validate_add(h, xt, &xret)) < 0) goto done; if (ret == 0){ /* validation failed */ - if (netconf_err2cb(xret, &cbret) < 0) + if ((cbret = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if (netconf_err2cb(xret, cbret) < 0) goto done; clicon_err(OE_YANG, 0, "validation failed: %s", cbuf_get(cbret)); goto done; diff --git a/lib/src/clixon_xml_parse.l b/lib/src/clixon_xml_parse.l index 8d1826c2..f57fb896 100644 --- a/lib/src/clixon_xml_parse.l +++ b/lib/src/clixon_xml_parse.l @@ -94,6 +94,7 @@ ncname {namestart}{namechar}* %s STATEA %s AMPERSAND %s CDATA +%s CDATAEND %s CMNT %s STR %s TEXTDECL @@ -145,9 +146,13 @@ ncname {namestart}{namechar}* "apos;" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;} "quot;" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;} -. { clixon_xml_parselval.string = yytext; return CHARDATA;} \n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);} -"]]>" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;} +\] { BEGIN(CDATAEND);clixon_xml_parselval.string = yytext;return (CHARDATA);} +[^]\n]+ { clixon_xml_parselval.string = yytext; return CHARDATA;} + +\n { clixon_xml_parselval.string = yytext;_YA->ya_linenum++; return (CHARDATA);} +"]>" { BEGIN(_YA->ya_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;} +. { BEGIN(CDATA); clixon_xml_parselval.string = yytext;return (CHARDATA);} "-->" { BEGIN(START); return ECOMMENT; } . diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c index de760508..8ca280d5 100644 --- a/util/clixon_util_xpath.c +++ b/util/clixon_util_xpath.c @@ -296,7 +296,11 @@ main(int argc, if (ret > 0 && (ret = xml_yang_validate_add(h, x1, &xerr)) < 0) goto done; if (ret == 0){ - if (netconf_err2cb(xerr, &cbret) < 0) + if ((cbret = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + if (netconf_err2cb(xerr, cbret) < 0) goto done; fprintf(stderr, "xml validation error: %s\n", cbuf_get(cbret)); goto done; From 43eb9fe9d2d0bf0a57f2e6078fa33d5380f6f5bc Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 14 Nov 2019 22:16:45 +0100 Subject: [PATCH 08/23] state callback xml error --- apps/backend/backend_plugin.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 29038b63..866f4755 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -134,9 +134,17 @@ clixon_plugin_statedata(clicon_handle h, if (ret > 0 && (ret = xml_yang_validate_add(h, x, &xerr)) < 0) goto done; if (ret == 0){ + if ((cberr = cbuf_new()) ==NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } cprintf(cberr, "Internal error: state callback returned invalid XML: "); if (netconf_err2cb(xpath_first(xerr, "rpc-error"), cberr) < 0) goto done; + if (*xret){ + xml_free(*xret); + *xret = NULL; + } if (netconf_operation_failed_xml(xret, "application", cbuf_get(cberr))< 0) goto done; goto fail; From 06c2793e7922e29c92a8ef87aee23abd04e9423f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 14 Nov 2019 22:26:07 +0100 Subject: [PATCH 09/23] added perf xml test --- test/test_perf_xml.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 test/test_perf_xml.sh diff --git a/test/test_perf_xml.sh b/test/test_perf_xml.sh new file mode 100755 index 00000000..9c7ed164 --- /dev/null +++ b/test/test_perf_xml.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Test: XML performance test +# See https://github.com/clicon/clixon/issues/96 +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +: ${clixon_util_xml:="clixon_util_xml"} + +# Number of list/leaf-list entries in file +: ${perfnr:=30000} + +fxml=$dir/long.xml + +new "generate long file $fxml" +echo -n " $fxml +for (( i=0; i<$perfnr; i++ )); do + echo "*>i10.0.0.$i/32 10.255.0.20 0 100 0 i" >> $fxml +done +echo "]]>" >> $fxml + +new "xml parse long CDATA" +expecteof_file "time $clixon_util_xml" 0 "$fxml" + +rm -rf $dir + From 52629d7b35270a5bee33fdbba18c90b498957034 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Fri, 15 Nov 2019 17:04:13 +0100 Subject: [PATCH 10/23] Added "canonical" global namespace context: `nsctx_global` --- CHANGELOG.md | 3 +++ apps/backend/backend_main.c | 32 ++++++++++++++++-------- apps/cli/cli_main.c | 12 +++++++++ apps/netconf/netconf_main.c | 12 +++++++++ apps/restconf/restconf_lib.c | 3 +++ apps/restconf/restconf_main.c | 9 +++++++ lib/clixon/clixon_data.h | 3 +++ lib/clixon/clixon_xml_nsctx.h | 1 + lib/src/clixon_data.c | 40 ++++++++++++++++++++++++++++++ lib/src/clixon_xml_nsctx.c | 46 ++++++++++++++++++++++++++++++++--- lib/src/clixon_yang.c | 2 +- 11 files changed, 149 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64a5c564..d5dbae38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## 4.3.0 (Expected: ~December 2019) ### Minor changes +* Added "canonical" global namespace context: `nsctx_global` + * This is a normalized XML prefix:namespace pair vector computed from all loaded Yang modules. Useful when writing XML and XPATH expressions in callbacks. + * Get it with `clicon_nsctx_global_get(h)` * Added wildcard `*` as a mode to `CLICON_MODE` in clispec files * If you set "CLICON_MODE="*";" in a clispec file it means that syntax will appear in all CLI spec modes. * State callbacks provided by user are validated. If they are invalid an internal error is returned. diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 3fe9603c..c6263576 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -92,6 +92,7 @@ backend_terminate(clicon_handle h) cxobj *x; struct stat st; int ss; + cvec *nsctx; clicon_debug(1, "%s", __FUNCTION__); if ((ss = clicon_socket_get(h)) != -1) @@ -108,6 +109,8 @@ backend_terminate(clicon_handle h) xml_free(x); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); + if ((nsctx = clicon_nsctx_global_get(h)) != NULL) + cvec_free(nsctx); if ((yspec = clicon_config_yang(h)) != NULL) yspec_free(yspec); if ((x = clicon_nacm_ext(h)) != NULL) @@ -451,6 +454,7 @@ main(int argc, int ret; char *dir; gid_t gid = -1; + cvec *nsctx_global = NULL; /* Global namespace context */ /* In the startup, logs to stderr & syslog and debug flag set later */ clicon_log_init(__PROGRAM__, LOG_INFO, logdst); @@ -722,10 +726,10 @@ main(int argc, if ((str = clicon_yang_main_dir(h)) != NULL) if (yang_spec_load_dir(h, str, yspec) < 0) goto done; - /* Load clixon lib yang module */ + /* Load clixon lib yang module */ if (yang_spec_parse_module(h, "clixon-lib", NULL, yspec) < 0) goto done; - /* Load yang module library, RFC7895 */ + /* Load yang module library, RFC7895 */ if (yang_modules_init(h) < 0) goto done; /* Add netconf yang spec, used by netconf client and as internal protocol @@ -736,13 +740,21 @@ main(int argc, if (yang_spec_parse_module(h, "ietf-restconf", NULL, yspec)< 0) goto done; /* Load yang Restconf stream discovery */ - if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && - yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0) - goto done; - /* Load yang Netconf stream discovery */ - if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && - yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0) - goto done; + if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC8040") && + yang_spec_parse_module(h, "ietf-restconf-monitoring", NULL, yspec)< 0) + goto done; + /* Load yang Netconf stream discovery */ + if (clicon_option_bool(h, "CLICON_STREAM_DISCOVERY_RFC5277") && + yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0) + goto done; + /* Here all modules are loaded + * Compute and set canonical namespace context + */ + if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0) + goto done; + if (clicon_nsctx_global_set(h, nsctx_global) < 0) + goto done; + /* Initialize server socket and save it to handle */ if (backend_rpc_init(h) < 0) goto done; @@ -895,7 +907,7 @@ main(int argc, goto done; ok: retval = 0; - done: + done: if (cbret) cbuf_free(cbret); clicon_log(LOG_NOTICE, "%s: %u Terminated retval:%d", __PROGRAM__, getpid(), retval); diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index a9e2f7bf..c0981710 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -163,6 +163,7 @@ static int cli_terminate(clicon_handle h) { yang_stmt *yspec; + cvec *nsctx; cxobj *x; clicon_rpc_close_session(h); @@ -170,6 +171,8 @@ cli_terminate(clicon_handle h) yspec_free(yspec); if ((yspec = clicon_config_yang(h)) != NULL) yspec_free(yspec); + if ((nsctx = clicon_nsctx_global_get(h)) != NULL) + cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) xml_free(x); cli_plugin_finish(h); @@ -286,6 +289,7 @@ main(int argc, char **argv) int tabmode; char *dir; uint32_t id = 0; + cvec *nsctx_global = NULL; /* Global namespace context */ /* Defaults */ once = 0; @@ -513,6 +517,14 @@ main(int argc, char **argv) if (netconf_module_load(h) < 0) goto done; + /* Here all modules are loaded + * Compute and set canonical namespace context + */ + if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0) + goto done; + if (clicon_nsctx_global_set(h, nsctx_global) < 0) + goto done; + /* Create tree generated from dataspec. If no other trees exists, this is * the only one. * The following code creates the tree @datamodel diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 02e8d94e..ec527cb8 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -323,6 +323,7 @@ static int netconf_terminate(clicon_handle h) { yang_stmt *yspec; + cvec *nsctx; cxobj *x; clixon_plugin_exit(h); @@ -332,6 +333,8 @@ netconf_terminate(clicon_handle h) yspec_free(yspec); if ((yspec = clicon_config_yang(h)) != NULL) yspec_free(yspec); + if ((nsctx = clicon_nsctx_global_get(h)) != NULL) + cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) xml_free(x); event_exit(); @@ -395,6 +398,7 @@ main(int argc, yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */ char *str; uint32_t id; + cvec *nsctx_global = NULL; /* Global namespace context */ /* Create handle */ if ((h = clicon_handle_init()) == NULL) @@ -554,6 +558,14 @@ main(int argc, /* Add netconf yang spec, used by netconf client and as internal protocol */ if (netconf_module_load(h) < 0) goto done; + /* Here all modules are loaded + * Compute and set canonical namespace context + */ + if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0) + goto done; + if (clicon_nsctx_global_set(h, nsctx_global) < 0) + goto done; + /* Call start function is all plugins before we go interactive */ if (clixon_plugin_start(h) < 0) goto done; diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index fe8a2544..22d474cb 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -593,6 +593,7 @@ int restconf_terminate(clicon_handle h) { yang_stmt *yspec; + cvec *nsctx; cxobj *x; int fs; /* fgcx socket */ @@ -606,6 +607,8 @@ restconf_terminate(clicon_handle h) yspec_free(yspec); if ((yspec = clicon_config_yang(h)) != NULL) yspec_free(yspec); + if ((nsctx = clicon_nsctx_global_get(h)) != NULL) + cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) xml_free(x); clicon_handle_exit(h); diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 1bcadbfd..d7c6dc48 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -589,6 +589,7 @@ main(int argc, char *str; clixon_plugin *cp = NULL; uint32_t id = 0; + cvec *nsctx_global = NULL; /* Global namespace context */ /* In the startup, logs to stderr & debug flag set later */ clicon_log_init(__PROGRAM__, LOG_INFO, logdst); @@ -760,6 +761,14 @@ main(int argc, yang_spec_parse_module(h, "clixon-rfc5277", NULL, yspec)< 0) goto done; + /* Here all modules are loaded + * Compute and set canonical namespace context + */ + if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0) + goto done; + if (clicon_nsctx_global_set(h, nsctx_global) < 0) + goto done; + /* Dump configuration options on debug */ if (debug) clicon_option_dump(h, debug); diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 7dfd556a..b1b61926 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -61,6 +61,9 @@ typedef struct { yang_stmt * clicon_dbspec_yang(clicon_handle h); int clicon_dbspec_yang_set(clicon_handle h, yang_stmt *ys); +cvec *clicon_nsctx_global_get(clicon_handle h); +int clicon_nsctx_global_set(clicon_handle h, cvec *nsctx); + cxobj * clicon_nacm_ext(clicon_handle h); int clicon_nacm_ext_set(clicon_handle h, cxobj *xn); diff --git a/lib/clixon/clixon_xml_nsctx.h b/lib/clixon/clixon_xml_nsctx.h index 3c383a85..5d6987ee 100644 --- a/lib/clixon/clixon_xml_nsctx.h +++ b/lib/clixon/clixon_xml_nsctx.h @@ -55,5 +55,6 @@ int xml_nsctx_get_prefix(cvec *cvv, char *namespace, char **prefix); int xml_nsctx_add(cvec *nsc, char *prefix, char *namespace); int xml_nsctx_node(cxobj *x, cvec **ncp); int xml_nsctx_yang(yang_stmt *yn, cvec **ncp); +int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp); #endif /* _CLIXON_XML_NSCTX_H */ diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 4f23a4f2..3e6a6298 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -75,6 +75,8 @@ /*! Get YANG specification for application * Must use hash functions directly since they are not strings. + * @param[in] h Clicon handle + * @retval yspec Yang spec */ yang_stmt * clicon_dbspec_yang(clicon_handle h) @@ -90,6 +92,8 @@ clicon_dbspec_yang(clicon_handle h) /*! Set yang specification for application * ys must be a malloced pointer + * @param[in] h Clicon handle + * @param[in] yspec Yang spec */ int clicon_dbspec_yang_set(clicon_handle h, @@ -105,6 +109,42 @@ clicon_dbspec_yang_set(clicon_handle h, return 0; } +/*! Get Global "canonical" namespace context + * Canonical: use prefix and namespace specified in the yang modules. + * @param[in] h Clicon handle + * @retval nsctx Namespace context (malloced) + */ +cvec * +clicon_nsctx_global_get(clicon_handle h) +{ + clicon_hash_t *cdat = clicon_data(h); + size_t len; + void *p; + + if ((p = clicon_hash_value(cdat, "nsctx_global", &len)) != NULL) + return *(cvec **)p; + return NULL; +} + +/*! Set global "canonical" namespace context + * Canonical: use prefix and namespace specified in the yang modules. + * @param[in] h Clicon handle + * @param[in] nsctx Namespace context (malloced) + */ +int +clicon_nsctx_global_set(clicon_handle h, + cvec *nsctx) +{ + clicon_hash_t *cdat = clicon_data(h); + + /* It is the pointer to cvec that should be copied by hash, + so we send a ptr to the ptr to indicate what to copy. + */ + if (clicon_hash_add(cdat, "nsctx_global", &nsctx, sizeof(nsctx)) == NULL) + return -1; + return 0; +} + /*! Get NACM (rfc 8341) XML parse tree if external not in std xml config * @param[in] h Clicon handle * @retval xn XML NACM tree, or NULL diff --git a/lib/src/clixon_xml_nsctx.c b/lib/src/clixon_xml_nsctx.c index e588c204..1134d000 100644 --- a/lib/src/clixon_xml_nsctx.c +++ b/lib/src/clixon_xml_nsctx.c @@ -182,7 +182,6 @@ xml_nsctx_add(cvec *cvv, return retval; } - static int xml_nsctx_node1(cxobj *xn, cvec *nsc) @@ -268,10 +267,10 @@ xml_nsctx_node(cxobj *xn, return retval; } -/*! Create and initialize XML namespace from Yang node +/*! Create and initialize XML namespace context from Yang node * Primary use is Yang path statements, eg leafrefs and others * Fully explore all prefix:namespace pairs from context of one node - * @param[in] xn XML node + * @param[in] yn Yang statement in module tree (or module itself) * @param[out] ncp XML namespace context * @retval 0 OK * @retval -1 Error @@ -354,3 +353,44 @@ xml_nsctx_yang(yang_stmt *yn, return retval; } +/*! Create and initialize XML namespace context from Yang spec + * + * That is, create a "canonical" XML namespace mapping from all loaded yang + * modules which are children of the yang specification. + * ALso add netconf base namespace: nc , urn:ietf:params:xml:ns:netconf:base:1.0 + * Fully explore all prefix:namespace pairs of all yang modules + * @param[in] yspec Yang spec + * @param[out] ncp XML namespace context + */ +int +xml_nsctx_yangspec(yang_stmt *yspec, + cvec **ncp) +{ + int retval = -1; + cvec *nc = NULL; + yang_stmt *ymod = NULL; + yang_stmt *yprefix; + yang_stmt *ynamespace; + + if ((nc = cvec_new(0)) == NULL){ + clicon_err(OE_XML, errno, "cvec_new"); + goto done; + } + ymod = NULL; + while ((ymod = yn_each(yspec, ymod)) != NULL){ + if (yang_keyword_get(ymod) != Y_MODULE) + continue; + if ((yprefix = yang_find(ymod, Y_PREFIX, NULL)) == NULL) + continue; + if ((ynamespace = yang_find(ymod, Y_NAMESPACE, NULL)) == NULL) + continue; + if (xml_nsctx_add(nc, yang_argument_get(yprefix), yang_argument_get(ynamespace)) < 0) + goto done; + } + if (xml_nsctx_add(nc, NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE) < 0) + goto done; + *ncp = nc; + retval = 0; + done: + return retval; +} diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 051627d7..6168f791 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -766,7 +766,7 @@ yang_find_myprefix(yang_stmt *ys) } if ((yprefix = yang_find(ymod, Y_PREFIX, NULL)) == NULL) goto done; - prefix = yprefix->ys_argument; + prefix = yang_argument_get(yprefix); done: return prefix; } From d0e97ee33818873eb46fd6ce71c1aa37e038e8e1 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 16 Nov 2019 16:49:40 +0100 Subject: [PATCH 11/23] Removed obsolete config yang handler Added base netconf as default namespace in canonical nsctx --- apps/backend/backend_main.c | 3 --- apps/cli/cli_main.c | 3 --- apps/netconf/netconf_main.c | 3 --- apps/restconf/restconf_lib.c | 2 -- apps/restconf/restconf_main.c | 1 - lib/clixon/clixon_data.h | 3 --- lib/src/clixon_data.c | 39 ++++------------------------------- lib/src/clixon_xml_nsctx.c | 3 +++ 8 files changed, 7 insertions(+), 50 deletions(-) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index c6263576..eb915210 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -111,8 +111,6 @@ backend_terminate(clicon_handle h) yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); - if ((yspec = clicon_config_yang(h)) != NULL) - yspec_free(yspec); if ((x = clicon_nacm_ext(h)) != NULL) xml_free(x); if ((x = clicon_conf_xml(h)) != NULL) @@ -519,7 +517,6 @@ main(int argc, usage(h, argv[0]); return -1; } - clicon_config_yang_set(h, yspecfg); /* External NACM file? */ nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); if (nacm_mode && strcmp(nacm_mode, "external") == 0) diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index c0981710..83c38625 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -169,8 +169,6 @@ cli_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) @@ -361,7 +359,6 @@ main(int argc, char **argv) usage(h, argv[0]); return -1; } - clicon_config_yang_set(h, yspecfg); /* Now rest of options */ opterr = 0; optind = 1; diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index ec527cb8..153ec13f 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -331,8 +331,6 @@ netconf_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) @@ -449,7 +447,6 @@ main(int argc, /* Find and read configfile */ if (clicon_options_main(h, yspecfg) < 0) return -1; - clicon_config_yang_set(h, yspecfg); /* Now rest of options */ optind = 1; opterr = 0; diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 22d474cb..b79de44f 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -605,8 +605,6 @@ restconf_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); - if ((yspec = clicon_config_yang(h)) != NULL) - yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index d7c6dc48..f188f7da 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -648,7 +648,6 @@ main(int argc, /* Find and read configfile */ if (clicon_options_main(h, yspecfg) < 0) goto done; - clicon_config_yang_set(h, yspecfg); stream_path = clicon_option_str(h, "CLICON_STREAM_PATH"); /* Now rest of options, some overwrite option file */ optind = 1; diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index b1b61926..3f173e04 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -67,9 +67,6 @@ int clicon_nsctx_global_set(clicon_handle h, cvec *nsctx); cxobj * clicon_nacm_ext(clicon_handle h); int clicon_nacm_ext_set(clicon_handle h, cxobj *xn); -yang_stmt * clicon_config_yang(clicon_handle h); -int clicon_config_yang_set(clicon_handle h, yang_stmt *ys); - cxobj *clicon_conf_xml(clicon_handle h); int clicon_conf_xml_set(clicon_handle h, cxobj *x); diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 3e6a6298..595e5db3 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -113,6 +113,10 @@ clicon_dbspec_yang_set(clicon_handle h, * Canonical: use prefix and namespace specified in the yang modules. * @param[in] h Clicon handle * @retval nsctx Namespace context (malloced) + * @code + * cvec *nsctx; + * nsctx = clicon_nsctx_global_get(h); + * @endcode */ cvec * clicon_nsctx_global_get(clicon_handle h) @@ -186,41 +190,6 @@ clicon_nacm_ext_set(clicon_handle h, return 0; } - -#if 1 /* Temporary function until "Top-level Yang symbol cannot be called "config"" is fixed */ -/*! Get YANG specification for clixon config - * Must use hash functions directly since they are not strings. - */ -yang_stmt * -clicon_config_yang(clicon_handle h) -{ - clicon_hash_t *cdat = clicon_data(h); - size_t len; - void *p; - - if ((p = clicon_hash_value(cdat, "control_yang", &len)) != NULL) - return *(yang_stmt **)p; - return NULL; -} - -/*! Set yang specification for control - * ys must be a malloced pointer - */ -int -clicon_config_yang_set(clicon_handle h, - yang_stmt *ys) -{ - clicon_hash_t *cdat = clicon_data(h); - - /* It is the pointer to ys that should be copied by hash, - so we send a ptr to the ptr to indicate what to copy. - */ - if (clicon_hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL) - return -1; - return 0; -} -#endif - /*! Get YANG specification for Clixon system options and features * Must use hash functions directly since they are not strings. * Example: features are typically accessed directly in the config tree. diff --git a/lib/src/clixon_xml_nsctx.c b/lib/src/clixon_xml_nsctx.c index 1134d000..6cabf39a 100644 --- a/lib/src/clixon_xml_nsctx.c +++ b/lib/src/clixon_xml_nsctx.c @@ -387,6 +387,9 @@ xml_nsctx_yangspec(yang_stmt *yspec, if (xml_nsctx_add(nc, yang_argument_get(yprefix), yang_argument_get(ynamespace)) < 0) goto done; } + /* Add base netconf namespace as default and "nc" prefix */ + if (xml_nsctx_add(nc, NULL, NETCONF_BASE_NAMESPACE) < 0) + goto done; if (xml_nsctx_add(nc, NETCONF_BASE_PREFIX, NETCONF_BASE_NAMESPACE) < 0) goto done; *ncp = nc; From f2cad01fc66af2bcf7569d9fbfb56316c96c074b Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 16 Nov 2019 17:34:18 +0100 Subject: [PATCH 12/23] Updated openconfig and yangmodels repos lead to some changed in testscript and a minor parsing lapsus --- lib/src/clixon_yang_parse.y | 1 + test/test_openconfig.sh | 1 + test/test_yang_models.sh | 28 +++++++++++++++++++++++----- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/src/clixon_yang_parse.y b/lib/src/clixon_yang_parse.y index 81189eb8..e363ff69 100644 --- a/lib/src/clixon_yang_parse.y +++ b/lib/src/clixon_yang_parse.y @@ -1490,6 +1490,7 @@ notification_substmt : if_feature_stmt { clicon_debug(2,"notification-substmt - | typedef_stmt { clicon_debug(2,"notification-substmt -> typedef-stmt"); } | grouping_stmt { clicon_debug(2,"notification-substmt -> grouping-stmt"); } | data_def_stmt { clicon_debug(2,"notification-substmt -> data-def-stmt"); } + | unknown_stmt { clicon_debug(2,"notification-substmt -> unknown-stmt");} | { clicon_debug(2,"notification-substmt -> "); } ; diff --git a/test/test_openconfig.sh b/test/test_openconfig.sh index b11db787..1f1158ae 100755 --- a/test/test_openconfig.sh +++ b/test/test_openconfig.sh @@ -37,6 +37,7 @@ cat < $cfg $OCDIR/lacp $OCDIR/lldp $OCDIR/local-routing + $OCDIR/macsec $OCDIR/mpls $OCDIR/multicast $OCDIR/network-instance diff --git a/test/test_yang_models.sh b/test/test_yang_models.sh index 0da1e5fd..0e3fec47 100755 --- a/test/test_yang_models.sh +++ b/test/test_yang_models.sh @@ -35,8 +35,10 @@ cat < $cfg $cfg $YANGMODELS/standard/ietf/RFC - $YANGMODELS/standard/ieee/draft/802.1 + $YANGMODELS/standard/ieee/draft/802.1/Qcr $YANGMODELS/standard/ieee/draft/802 + $YANGMODELS/standard/ieee/draft/802 + $YANGMODELS/standard/ieee/published/802.1 /usr/local/share/clixon /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli @@ -59,11 +61,27 @@ new "yangmodel Experimental IEEE 1588: $YANGMODELS/experimental/ieee/1588" expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/experimental/ieee/1588 show version" 0 "$version." # Standard IEEE -new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1" -expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1 show version" 0 "$version." +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1/ABcu" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1/ABcu show version" 0 "$version." -new "yangmodel Standard IEEE 802.3: $YANGMODELS/standard/ieee/draft/802.3" -expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.3 show version" 0 "$version." +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1/Qcr" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1/Qcr show version" 0 "$version." + +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1/Qcw" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1/Qcw show version" 0 "$version." + +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1/Qcx" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1/Qcx -p $YANGMODELS/standard/ieee/draft/802.1/ABcu show version" 0 "$version." + +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/draft/802.1/x" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/draft/802.1/x show version" 0 "$version." + +# Published +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/published/802.1" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/published/802.1 show version" 0 "$version." + +new "yangmodel Standard IEEE 802.1: $YANGMODELS/standard/ieee/published/802.3" +expectfn "$clixon_cli -D $DBG -1f $cfg -o CLICON_YANG_MAIN_DIR=$YANGMODELS/standard/ieee/published/802.3 show version" 0 "$version." # Standard IETF new "yangmodel Standard IETF: $YANGMODELS/standard/ietf/RFC" From 9575d10887e35079c4a9b227dde6ab0f6f09fa03 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 18 Nov 2019 21:16:12 +0100 Subject: [PATCH 13/23] use cbuf for xml value code --- lib/clixon/clixon_xml.h | 2 +- lib/src/clixon_json_parse.y | 2 +- lib/src/clixon_xml.c | 83 ++++++++++++++----------------------- lib/src/clixon_xml_parse.y | 5 +-- test/test_perf_xml.sh | 5 ++- 5 files changed, 39 insertions(+), 58 deletions(-) diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index 73d06f96..429fb191 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -129,7 +129,7 @@ int xml_flag_reset(cxobj *xn, uint16_t flag); char *xml_value(cxobj *xn); int xml_value_set(cxobj *xn, char *val); -char *xml_value_append(cxobj *xn, char *val); +int xml_value_append(cxobj *xn, char *val); enum cxobj_type xml_type(cxobj *xn); int xml_type_set(cxobj *xn, enum cxobj_type type); diff --git a/lib/src/clixon_json_parse.y b/lib/src/clixon_json_parse.y index 8bbc6396..5a5503da 100644 --- a/lib/src/clixon_json_parse.y +++ b/lib/src/clixon_json_parse.y @@ -228,7 +228,7 @@ json_current_body(struct clicon_json_yacc_arg *jy, if ((xn = xml_new("body", jy->jy_current, NULL)) == NULL) goto done; xml_type_set(xn, CX_BODY); - if (value && xml_value_append(xn, value)==NULL) + if (value && xml_value_append(xn, value) < 0) goto done; retval = 0; done: diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index be8a36b8..e948abde 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -126,9 +126,7 @@ struct xml{ int x_childvec_len;/* Number of children */ int x_childvec_max;/* Length of allocated vector */ enum cxobj_type x_type; /* type of node: element, attribute, body */ - char *x_value; /* attribute and body nodes have values */ - uint32_t x_value_len; /* Length of x_value string (excluding null) */ - uint32_t x_value_max; /* allocated size for x_value */ + cbuf *x_value_cb; /* attribute and body nodes have values */ int x_flags; /* Flags according to XML_FLAG_* */ yang_stmt *x_spec; /* Pointer to specification, eg yang, by reference, dont free */ @@ -624,43 +622,7 @@ xml_flag_reset(cxobj *xn, char* xml_value(cxobj *xn) { - return xn->x_value; -} - -/*! xml value string reallocator - */ -static int -xml_value_realloc(cxobj *xn, - int len0, - char *val) -{ - int retval = -1; - int len; - int diff; - - if (val==NULL) - goto ok; - len = len0 + strlen(val); - diff = xn->x_value_max - (len + 1); - if (diff <= 0){ - while (diff <= 0){ - if (xn->x_value_max == 0) - xn->x_value_max = XML_VALUE_MAX_DEFAULT; - else - xn->x_value_max *= 2; - diff = xn->x_value_max - (len + 1); - } - if ((xn->x_value = realloc(xn->x_value, xn->x_value_max)) == NULL){ - clicon_err(OE_XML, errno, "realloc"); - goto done; - } - } - strncpy(xn->x_value + len0, val, len-len0+1); - xn->x_value_len = len; - ok: - retval = 0; - done: - return retval; + return xn->x_value_cb?cbuf_get(xn->x_value_cb):NULL; } /*! Set value of xml node, value is copied @@ -675,12 +637,15 @@ xml_value_set(cxobj *xn, { int retval = -1; - if (xn->x_value && strlen(xn->x_value)){ - xn->x_value[0] = '\0'; - xn->x_value_len = 0; + if (xn->x_value_cb == NULL){ + if ((xn->x_value_cb = cbuf_new()) == NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } } - if (xml_value_realloc(xn, 0, val) < 0) - goto done; + else + cbuf_reset(xn->x_value_cb); + cprintf(xn->x_value_cb, "%s", val); retval = 0; done: return retval; @@ -692,13 +657,25 @@ xml_value_set(cxobj *xn, * @retval NULL on error with clicon-err set, or if value is set to NULL * @retval new value */ -char * +int xml_value_append(cxobj *xn, char *val) { - if (xml_value_realloc(xn, xn->x_value_len, val) < 0) - return NULL; - return xn->x_value; + int retval = -1; + + if (xn->x_value_cb == NULL){ + if ((xn->x_value_cb = cbuf_new()) == NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); + goto done; + } + } + if (cprintf(xn->x_value_cb, "%s", val) < 0){ + clicon_err(OE_XML, errno, "cprintf"); + goto done; + } + retval = 0; + done: + return retval; } /*! Get type of xnode @@ -1623,8 +1600,8 @@ xml_free(cxobj *x) if (x->x_name) free(x->x_name); - if (x->x_value) - free(x->x_value); + if (x->x_value_cb) + cbuf_free(x->x_value_cb); if (x->x_prefix) free(x->x_prefix); for (i=0; ix_childvec_len; i++){ @@ -2648,8 +2625,10 @@ clicon_log_xml(int level, int retval = -1; /* Print xml as cbuf */ - if ((cb = cbuf_new()) == NULL) + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_XML, errno, "cbuf_new"); goto done; + } if (clicon_xml2cbuf(cb, x, 0, 0, -1) < 0) goto done; diff --git a/lib/src/clixon_xml_parse.y b/lib/src/clixon_xml_parse.y index 6d735d62..3a1e9419 100644 --- a/lib/src/clixon_xml_parse.y +++ b/lib/src/clixon_xml_parse.y @@ -104,7 +104,7 @@ xml_parse_content(struct xml_parse_yacc_arg *ya, goto done; xml_type_set(xn, CX_BODY); } - if (xml_value_append(xn, str)==NULL) + if (xml_value_append(xn, str) < 0) goto done; ya->ya_xelement = xn; retval = 0; @@ -140,7 +140,7 @@ xml_parse_whitespace(struct xml_parse_yacc_arg *ya, goto done; xml_type_set(xn, CX_BODY); } - if (xml_value_append(xn, str)==NULL) + if (xml_value_append(xn, str) < 0) goto done; ya->ya_xelement = xn; ok: @@ -148,7 +148,6 @@ xml_parse_whitespace(struct xml_parse_yacc_arg *ya, done: return retval; } - static int xml_parse_version(struct xml_parse_yacc_arg *ya, diff --git a/test/test_perf_xml.sh b/test/test_perf_xml.sh index 9c7ed164..17d7d6ce 100755 --- a/test/test_perf_xml.sh +++ b/test/test_perf_xml.sh @@ -18,8 +18,11 @@ for (( i=0; i<$perfnr; i++ )); do done echo "]]>" >> $fxml +# 32-bit i386: +#0.37user 1.94system 0:02.47elapsed 93%CPU (0avgtext+0avgdata 9336maxresident)k +#256inputs+0outputs (2major+2049minor)pagefaults 0swa new "xml parse long CDATA" expecteof_file "time $clixon_util_xml" 0 "$fxml" - + rm -rf $dir From ba472bf15f9aac73cb7a1ad213320f6c6b1115a3 Mon Sep 17 00:00:00 2001 From: Anthony Hinsinger Date: Tue, 19 Nov 2019 14:40:48 +0100 Subject: [PATCH 14/23] Update xml root element --- docker/main/start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/main/start.sh b/docker/main/start.sh index 909f72fd..88995157 100755 --- a/docker/main/start.sh +++ b/docker/main/start.sh @@ -23,7 +23,7 @@ PORT=${PORT:-80} STORE=${STORE:-} CONFIG0=$(cat < + /usr/local/etc/example.xml *:* /usr/local/share/clixon @@ -42,7 +42,7 @@ CONFIG0=$(cat <0 init disabled - + EOF ) From 0d22a8b6d0687e6db7cc542745a5d1a14ee6ac58 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 26 Nov 2019 21:51:28 +0100 Subject: [PATCH 15/23] Yang files reorganized into three classes: clixon, mandatory, optional --- .travis.yml | 1 - CHANGELOG.md | 6 +- apps/backend/backend_plugin.c | 9 + configure | 55 +-- configure.ac | 35 +- doc/FAQ.md | 6 +- docker/main/Dockerfile | 2 +- example/main/README.md | 3 +- lib/src/clixon_xml.c | 1 - lib/src/clixon_xml_sort.c | 4 +- yang/Makefile.in | 7 +- yang/README.md | 14 + yang/clixon/Makefile.in | 2 +- yang/clixon/clixon-config@2019-09-11.yang | 2 +- yang/{standard => mandatory}/Makefile.in | 19 +- .../ietf-inet-types@2013-07-15.yang | 0 .../ietf-netconf-acm@2018-02-14.yang | 0 .../ietf-netconf@2011-06-01.yang | 0 .../ietf-restconf-monitoring@2017-01-26.yang | 0 .../ietf-restconf@2017-01-26.yang | 0 .../ietf-yang-library@2016-06-21.yang | 0 .../ietf-yang-types@2013-07-15.yang | 0 yang/optional/Makefile.in | 70 ++++ .../iana-if-type@2014-05-08.yang | 0 .../ietf-interfaces@2018-02-20.yang | 0 .../ietf-ip@2014-06-16.yang | 0 .../ietf-netconf-monitoring@2010-10-04.yang | 0 .../ietf-routing@2018-03-13.yang | 0 .../ietf-module-revision@2018-08-08.yang | 392 ------------------ 29 files changed, 166 insertions(+), 462 deletions(-) create mode 100644 yang/README.md rename yang/{standard => mandatory}/Makefile.in (81%) rename yang/{standard => mandatory}/ietf-inet-types@2013-07-15.yang (100%) rename yang/{standard => mandatory}/ietf-netconf-acm@2018-02-14.yang (100%) rename yang/{standard => mandatory}/ietf-netconf@2011-06-01.yang (100%) rename yang/{standard => mandatory}/ietf-restconf-monitoring@2017-01-26.yang (100%) rename yang/{standard => mandatory}/ietf-restconf@2017-01-26.yang (100%) rename yang/{standard => mandatory}/ietf-yang-library@2016-06-21.yang (100%) rename yang/{standard => mandatory}/ietf-yang-types@2013-07-15.yang (100%) create mode 100644 yang/optional/Makefile.in rename yang/{standard => optional}/iana-if-type@2014-05-08.yang (100%) rename yang/{standard => optional}/ietf-interfaces@2018-02-20.yang (100%) rename yang/{standard => optional}/ietf-ip@2014-06-16.yang (100%) rename yang/{standard => optional}/ietf-netconf-monitoring@2010-10-04.yang (100%) rename yang/{standard => optional}/ietf-routing@2018-03-13.yang (100%) delete mode 100644 yang/standard/ietf-module-revision@2018-08-08.yang diff --git a/.travis.yml b/.travis.yml index b8c1a54e..23573a00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ language: c branches: only: - master - - develop before_script: - sudo apt-get install -y libfcgi-dev - ./test/travis/before_script.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index d5dbae38..bd58463e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Clixon Changelog -## 4.3.0 (Expected: ~December 2019) +## 4.3.0 (Expected: December 2019) ### Minor changes * Added "canonical" global namespace context: `nsctx_global` @@ -12,6 +12,10 @@ * Fixed multi-namespace for augmented state which was not covered in 4.2.0. ### API changes on existing features (you may need to change your code) +* Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional). + * Clixon and mandatory yang spec are always installed + * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped lofgic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. + * Optional yang files can be installed in a separate dir with `--with-opt-yang-installdir=DIR` (renamed from `with-std-yang-installdir`) * The multi-namespace augment state may rearrange the XML namespace attributes. * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 866f4755..3f0925a3 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -149,6 +149,15 @@ clixon_plugin_statedata(clicon_handle h, goto done; goto fail; } +#if 1 + if (debug){ + cbuf *ccc=cbuf_new(); + if (clicon_xml2cbuf(ccc, x, 0, 0, -1) < 0) + goto done; + clicon_debug(1, "%s MERGE: %s", __FUNCTION__, cbuf_get(ccc)); + cbuf_free(ccc); + } +#endif if ((ret = netconf_trymerge(x, yspec, xret)) < 0) goto done; if (ret == 0) diff --git a/configure b/configure index 124aadbc..e0146b78 100755 --- a/configure +++ b/configure @@ -621,7 +621,7 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS LIBOBJS -STD_YANG_INSTALLDIR +OPT_YANG_INSTALLDIR YANG_INSTALLDIR EGREP GREP @@ -633,7 +633,7 @@ YACC CPP wwwuser wwwdir -enable_stdyangs +enable_optyangs with_restconf SH_SUFFIX CLIXON_DEFAULT_CONFIG @@ -711,14 +711,14 @@ ac_user_opts=' enable_option_checking enable_debug with_cligen -enable_stdyangs +enable_optyangs enable_publish with_restconf with_wwwuser with_configfile with_libxml2 with_yang_installdir -with_std_yang_installdir +with_opt_yang_installdir ' ac_precious_vars='build_alias host_alias @@ -1355,8 +1355,8 @@ Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug Build with debug symbols, default: no - --disable-stdyangs Include standard yang files in clixon install, - default: yes + --enable-optyangs Include standard yang files in clixon install, + default: no --enable-publish Enable publish of notification streams using SSE and curl @@ -1369,7 +1369,7 @@ Optional Packages: --with-configfile=FILE set default path to config file --with-libxml2 use gnome/libxml2 regex engine --with-yang-installdir=DIR Install Clixon yang files here (default: ${prefix}/share/clixon) - --with-std-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon) + --with-opt-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon) Some influential environment variables: CC C compiler command @@ -4247,22 +4247,22 @@ fi # Disable/enable standard Yang files. # If enable - include yang/standard/*.yang in clixon yang files (default) # If disable - get standard yang files from elsewhere -# Check whether --enable-stdyangs was given. -if test "${enable_stdyangs+set}" = set; then : - enableval=$enable_stdyangs; +# Check whether --enable-optyangs was given. +if test "${enable_optyangs+set}" = set; then : + enableval=$enable_optyangs; if test "$enableval" = no; then - enable_stdyangs=no + enable_optyangs=no else - enable_stdyangs=yes + enable_optyangs=yes fi else - enable_stdyangs=yes + enable_optyangs=no fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: stdyangs is $enable_stdyangs" >&5 -$as_echo "stdyangs is $enable_stdyangs" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: optyangs is $enable_optyangs" >&5 +$as_echo "optyangs is $enable_optyangs" >&6; } # Experimental: Curl publish notification stream to eg Nginx nchan. # Check whether --enable-publish was given. @@ -4933,8 +4933,8 @@ $as_echo "Have getsockopt SO_PEERCRED" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# YANG_INSTALLDIR is where clixon installs the Clixon yang files -# (the files in in yang/clixon) +# YANG_INSTALLDIR is where clixon installs the Clixon yang files and mandatory +# standard yang files: the files in in yang/clixon and yang/mandatory # Each application designer may need to place YANG_INSTALLDIR in their config: # $YANG_INSTALLDIR @@ -4950,22 +4950,22 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: Clixon yang files are installed in ${YANG_INSTALLDIR}" >&5 $as_echo "Clixon yang files are installed in ${YANG_INSTALLDIR}" >&6; } -# STD_YANG_INSTALLDIR is where clixon installs standard yang files -# (the files in in yang/standard) +# OPT_YANG_INSTALLDIR is where clixon installs standard yang files +# ( the files in in yang/standard) # that Clixon needs to run (or examples rely on). These may be retreived from # elsewhere (eg yangmodels repo) -# Check whether --with-std-yang-installdir was given. -if test "${with_std_yang_installdir+set}" = set; then : - withval=$with_std_yang_installdir; STD_YANG_INSTALLDIR="$withval" +# Check whether --with-opt-yang-installdir was given. +if test "${with_opt_yang_installdir+set}" = set; then : + withval=$with_opt_yang_installdir; OPT_YANG_INSTALLDIR="$withval" else - STD_YANG_INSTALLDIR="${prefix}/share/clixon" + OPT_YANG_INSTALLDIR="${prefix}/share/clixon" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Standard yang files are installed in ${STD_YANG_INSTALLDIR}" >&5 -$as_echo "Standard yang files are installed in ${STD_YANG_INSTALLDIR}" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled)" >&5 +$as_echo "Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled)" >&6; } # Default location for config file @@ -4976,7 +4976,7 @@ _ACEOF -ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/hello/Makefile extras/rpm/Makefile docker/Makefile docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/standard/Makefile doc/Makefile test/Makefile" +ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/hello/Makefile extras/rpm/Makefile docker/Makefile docker/main/Makefile docker/base/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/mandatory/Makefile yang/optional/Makefile doc/Makefile test/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -5692,7 +5692,8 @@ do "util/Makefile") CONFIG_FILES="$CONFIG_FILES util/Makefile" ;; "yang/Makefile") CONFIG_FILES="$CONFIG_FILES yang/Makefile" ;; "yang/clixon/Makefile") CONFIG_FILES="$CONFIG_FILES yang/clixon/Makefile" ;; - "yang/standard/Makefile") CONFIG_FILES="$CONFIG_FILES yang/standard/Makefile" ;; + "yang/mandatory/Makefile") CONFIG_FILES="$CONFIG_FILES yang/mandatory/Makefile" ;; + "yang/optional/Makefile") CONFIG_FILES="$CONFIG_FILES yang/optional/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; diff --git a/configure.ac b/configure.ac index c3cd8d3e..e82bf576 100644 --- a/configure.ac +++ b/configure.ac @@ -89,7 +89,7 @@ AC_SUBST(CLIXON_DEFAULT_CONFIG) AC_SUBST(LIBS) AC_SUBST(SH_SUFFIX) AC_SUBST(with_restconf) # If yes, compile apps/restconf -AC_SUBST(enable_stdyangs) +AC_SUBST(enable_optyangs) AC_SUBST(wwwdir,/www-data) AC_SUBST(wwwuser,www-data) @@ -151,16 +151,16 @@ fi # Disable/enable standard Yang files. # If enable - include yang/standard/*.yang in clixon yang files (default) # If disable - get standard yang files from elsewhere -AC_ARG_ENABLE(stdyangs, AS_HELP_STRING([--disable-stdyangs],[Include standard yang files in clixon install, default: yes]),[ +AC_ARG_ENABLE(optyangs, AS_HELP_STRING([--enable-optyangs],[Include optional yang files for examples and testing in clixon install, default: no]),[ if test "$enableval" = no; then - enable_stdyangs=no + enable_optyangs=no else - enable_stdyangs=yes + enable_optyangs=yes fi ], - [ enable_stdyangs=yes]) + [ enable_optyangs=no]) -AC_MSG_RESULT(stdyangs is $enable_stdyangs) +AC_MSG_RESULT(optyangs is $enable_optyangs) # Experimental: Curl publish notification stream to eg Nginx nchan. AC_ARG_ENABLE(publish, AS_HELP_STRING([--enable-publish],[Enable publish of notification streams using SSE and curl]),[ @@ -229,8 +229,8 @@ AC_CHECK_FUNCS(inet_aton sigaction sigvec strlcpy strsep strndup alphasort versi AC_TRY_COMPILE([#include ], [getsockopt(1, SOL_SOCKET, SO_PEERCRED, 0, 0);], [AC_DEFINE(HAVE_SO_PEERCRED, 1, [Have getsockopt SO_PEERCRED]) AC_MSG_RESULT(Have getsockopt SO_PEERCRED)]) -# YANG_INSTALLDIR is where clixon installs the Clixon yang files -# (the files in in yang/clixon) +# YANG_INSTALLDIR is where clixon installs the Clixon yang files and mandatory +# standard yang files: the files in in yang/clixon and yang/mandatory # Each application designer may need to place YANG_INSTALLDIR in their config: # $YANG_INSTALLDIR AC_ARG_WITH(yang-installdir, @@ -241,17 +241,17 @@ AC_ARG_WITH(yang-installdir, AC_SUBST(YANG_INSTALLDIR) AC_MSG_RESULT(Clixon yang files are installed in ${YANG_INSTALLDIR}) -# STD_YANG_INSTALLDIR is where clixon installs standard yang files -# (the files in in yang/standard) +# OPT_YANG_INSTALLDIR is where clixon installs standard yang files +# ( the files in in yang/standard) # that Clixon needs to run (or examples rely on). These may be retreived from # elsewhere (eg yangmodels repo) -AC_ARG_WITH(std-yang-installdir, - [ --with-std-yang-installdir=DIR Install standard yang files here (default: ${prefix}/share/clixon) ], - [STD_YANG_INSTALLDIR="$withval"], - [STD_YANG_INSTALLDIR="${prefix}/share/clixon"] +AC_ARG_WITH(opt-yang-installdir, + [ --with-opt-yang-installdir=DIR Install optional yang files here (default: ${prefix}/share/clixon) ], + [OPT_YANG_INSTALLDIR="$withval"], + [OPT_YANG_INSTALLDIR="${prefix}/share/clixon"] ) -AC_SUBST(STD_YANG_INSTALLDIR) -AC_MSG_RESULT(Standard yang files are installed in ${STD_YANG_INSTALLDIR}) +AC_SUBST(OPT_YANG_INSTALLDIR) +AC_MSG_RESULT(Optional yang files are installed in ${OPT_YANG_INSTALLDIR} (if enabled)) # Default location for config file AC_DEFINE_UNQUOTED(CLIXON_DEFAULT_CONFIG,"${CLIXON_DEFAULT_CONFIG}",[Location for apps to find default config file]) @@ -280,7 +280,8 @@ AC_OUTPUT(Makefile util/Makefile yang/Makefile yang/clixon/Makefile - yang/standard/Makefile + yang/mandatory/Makefile + yang/optional/Makefile doc/Makefile test/Makefile ) diff --git a/doc/FAQ.md b/doc/FAQ.md index 6c0cccc1..ae97a24a 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -77,12 +77,14 @@ One of the examples is [a hello world example](../example/hello). Please start w ## How do you build and install Clixon? Clixon: ``` - ./configure; + ./configure --enable-optyang; make; sudo make install; sudo make install-include ``` -The main example: +(note: optyang enable only if you need to run the main example, otherwise it is not necessary). + +The main example: ``` cd example; make; diff --git a/docker/main/Dockerfile b/docker/main/Dockerfile index dfa05546..630dc43b 100644 --- a/docker/main/Dockerfile +++ b/docker/main/Dockerfile @@ -62,7 +62,7 @@ RUN adduser -D -H www-data RUN apk add --update nginx # Configure, build and install clixon -RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data +RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-wwwuser=www-data --enable-optyangs RUN make RUN make install RUN make install-include diff --git a/example/main/README.md b/example/main/README.md index b5101aca..d5e98d50 100644 --- a/example/main/README.md +++ b/example/main/README.md @@ -30,13 +30,14 @@ This directory contains a Clixon example used primarily for testing. It can be u * `example_netconf.c` Netconf callback plugin * `Makefile.in` Example makefile where plugins are built and installed - ## Compile and run Before you start, +* You must configure with: `--enable-optyangs` to run the main example. * Make [group setup](../../doc/FAQ.md#do-i-need-to-setup-anything-important) * Setup [restconf](../../doc/FAQ.md#how-do-i-use-restconf) + ``` cd example make && sudo make install diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index e948abde..f7dcf0d3 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -151,7 +151,6 @@ static const map_str2int xsmap[] = { {NULL, -1} }; - /*! Translate from xml type in enum form to string keyword * @param[in] type Xml type * @retval str String keyword diff --git a/lib/src/clixon_xml_sort.c b/lib/src/clixon_xml_sort.c index 74e33291..1ee212f0 100644 --- a/lib/src/clixon_xml_sort.c +++ b/lib/src/clixon_xml_sort.c @@ -617,8 +617,8 @@ xml_insert2(cxobj *xp, xc = xml_child_i(xp, mid); if ((yc = xml_spec(xc)) == NULL){ if (xml_type(xc) != CX_ELMNT) - clicon_err(OE_XML, 0, "No spec found %s (wrong xml type:%d)", - xml_name(xc), xml_type(xc)); + clicon_err(OE_XML, 0, "No spec found %s (wrong xml type:%s)", + xml_name(xc), xml_type2str(xml_type(xc))); else clicon_err(OE_XML, 0, "No spec found %s", xml_name(xc)); goto done; diff --git a/yang/Makefile.in b/yang/Makefile.in index d9ee3301..f816c8c9 100644 --- a/yang/Makefile.in +++ b/yang/Makefile.in @@ -37,12 +37,13 @@ prefix = @prefix@ bindir = @bindir@ includedir = @includedir@ datarootdir = @datarootdir@ -enable_stdyangs = @enable_stdyangs@ +enable_optyangs = @enable_optyangs@ SUBDIRS = clixon +SUBDIRS += mandatory # See configure.ac -ifeq ($(enable_stdyangs),yes) -SUBDIRS += standard +ifeq ($(enable_optyangs),yes) +SUBDIRS += optional endif .PHONY: all clean depend install $(SUBDIRS) diff --git a/yang/README.md b/yang/README.md new file mode 100644 index 00000000..89accf31 --- /dev/null +++ b/yang/README.md @@ -0,0 +1,14 @@ +# Yang files + +There are three classes of Yang files + * Clixon yang files. + * Mandatory: "Standard" yang files necessary for clixon lib/client/backend to run + * Optional: "Standard" yang files for examples and tests + +The first two (clixon and mandatory) are always installed. If you want +to change where the are installed, configure with: `--with-yang-installdir=DIR` + +The third (optional) is only installed if configure flag +`--enable-optyang` is set. Further, the optional yang files are +installed in `--with-opt-yang-installdir=DIR` if given, otherwise in +the same dir as the mandatory. \ No newline at end of file diff --git a/yang/clixon/Makefile.in b/yang/clixon/Makefile.in index d924bf37..b199ba2d 100644 --- a/yang/clixon/Makefile.in +++ b/yang/clixon/Makefile.in @@ -38,7 +38,7 @@ bindir = @bindir@ includedir = @includedir@ datarootdir = @datarootdir@ -# See also STD_YANG_INSTALLDIR for the standard yang files +# See also OPT_YANG_INSTALLDIR for the standard yang files YANG_INSTALLDIR = @YANG_INSTALLDIR@ YANGSPECS = clixon-config@2019-09-11.yang diff --git a/yang/clixon/clixon-config@2019-09-11.yang b/yang/clixon/clixon-config@2019-09-11.yang index 7dedec8f..6cfd354f 100644 --- a/yang/clixon/clixon-config@2019-09-11.yang +++ b/yang/clixon/clixon-config@2019-09-11.yang @@ -358,7 +358,7 @@ module clixon-config { type string; default "base"; description - "Startup CLI mode. This should match a CLICON_MODE set in + "Startup CLI mode. This should match a CLICON_MODE variable set in one of the clispec files"; } leaf CLICON_CLI_GENMODEL { diff --git a/yang/standard/Makefile.in b/yang/mandatory/Makefile.in similarity index 81% rename from yang/standard/Makefile.in rename to yang/mandatory/Makefile.in index 44909ddb..eb7f016c 100644 --- a/yang/standard/Makefile.in +++ b/yang/mandatory/Makefile.in @@ -39,20 +39,15 @@ includedir = @includedir@ datarootdir = @datarootdir@ # See also YANG_INSTALLDIR for the clixon-specific yang files -STD_YANG_INSTALLDIR = @STD_YANG_INSTALLDIR@ +YANG_INSTALLDIR = @YANG_INSTALLDIR@ -YANGSPECS = iana-if-type@2014-05-08.yang -YANGSPECS += ietf-interfaces@2018-02-20.yang -YANGSPECS += ietf-yang-types@2013-07-15.yang -YANGSPECS += ietf-ip@2014-06-16.yang -YANGSPECS += ietf-inet-types@2013-07-15.yang -YANGSPECS += ietf-routing@2018-03-13.yang -YANGSPECS += ietf-yang-library@2016-06-21.yang +YANGSPECS = ietf-inet-types@2013-07-15.yang YANGSPECS += ietf-netconf@2011-06-01.yang YANGSPECS += ietf-netconf-acm@2018-02-14.yang YANGSPECS += ietf-restconf@2017-01-26.yang YANGSPECS += ietf-restconf-monitoring@2017-01-26.yang -YANGSPECS += ietf-netconf-monitoring@2010-10-04.yang +YANGSPECS += ietf-yang-library@2016-06-21.yang +YANGSPECS += ietf-yang-types@2013-07-15.yang all: @@ -62,11 +57,11 @@ distclean: clean rm -f Makefile *~ .depend install: $(YANGSPECS) - install -d -m 0755 $(DESTDIR)$(STD_YANG_INSTALLDIR) - install -m 0644 $(YANGSPECS) $(DESTDIR)$(STD_YANG_INSTALLDIR) + install -d -m 0755 $(DESTDIR)$(YANG_INSTALLDIR) + install -m 0644 $(YANGSPECS) $(DESTDIR)$(YANG_INSTALLDIR) uninstall: - (cd $(DESTDIR)$(STD_YANG_INSTALLDIR); rm -rf *.yang) + (cd $(DESTDIR)$(YANG_INSTALLDIR); rm -rf *.yang) install-include: diff --git a/yang/standard/ietf-inet-types@2013-07-15.yang b/yang/mandatory/ietf-inet-types@2013-07-15.yang similarity index 100% rename from yang/standard/ietf-inet-types@2013-07-15.yang rename to yang/mandatory/ietf-inet-types@2013-07-15.yang diff --git a/yang/standard/ietf-netconf-acm@2018-02-14.yang b/yang/mandatory/ietf-netconf-acm@2018-02-14.yang similarity index 100% rename from yang/standard/ietf-netconf-acm@2018-02-14.yang rename to yang/mandatory/ietf-netconf-acm@2018-02-14.yang diff --git a/yang/standard/ietf-netconf@2011-06-01.yang b/yang/mandatory/ietf-netconf@2011-06-01.yang similarity index 100% rename from yang/standard/ietf-netconf@2011-06-01.yang rename to yang/mandatory/ietf-netconf@2011-06-01.yang diff --git a/yang/standard/ietf-restconf-monitoring@2017-01-26.yang b/yang/mandatory/ietf-restconf-monitoring@2017-01-26.yang similarity index 100% rename from yang/standard/ietf-restconf-monitoring@2017-01-26.yang rename to yang/mandatory/ietf-restconf-monitoring@2017-01-26.yang diff --git a/yang/standard/ietf-restconf@2017-01-26.yang b/yang/mandatory/ietf-restconf@2017-01-26.yang similarity index 100% rename from yang/standard/ietf-restconf@2017-01-26.yang rename to yang/mandatory/ietf-restconf@2017-01-26.yang diff --git a/yang/standard/ietf-yang-library@2016-06-21.yang b/yang/mandatory/ietf-yang-library@2016-06-21.yang similarity index 100% rename from yang/standard/ietf-yang-library@2016-06-21.yang rename to yang/mandatory/ietf-yang-library@2016-06-21.yang diff --git a/yang/standard/ietf-yang-types@2013-07-15.yang b/yang/mandatory/ietf-yang-types@2013-07-15.yang similarity index 100% rename from yang/standard/ietf-yang-types@2013-07-15.yang rename to yang/mandatory/ietf-yang-types@2013-07-15.yang diff --git a/yang/optional/Makefile.in b/yang/optional/Makefile.in new file mode 100644 index 00000000..c95bb922 --- /dev/null +++ b/yang/optional/Makefile.in @@ -0,0 +1,70 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# +# Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren +# +# 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 ***** +# +VPATH = @srcdir@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +prefix = @prefix@ +bindir = @bindir@ +includedir = @includedir@ +datarootdir = @datarootdir@ + +# See also OPT_YANG_INSTALLDIR for optionali yang files +OPT_YANG_INSTALLDIR = @OPT_YANG_INSTALLDIR@ + +YANGSPECS = iana-if-type@2014-05-08.yang +YANGSPECS += ietf-interfaces@2018-02-20.yang +YANGSPECS += ietf-ip@2014-06-16.yang +YANGSPECS += ietf-netconf-monitoring@2010-10-04.yang +YANGSPECS += ietf-routing@2018-03-13.yang + +all: + +clean: + +distclean: clean + rm -f Makefile *~ .depend + +install: $(YANGSPECS) + install -d -m 0755 $(DESTDIR)$(OPT_YANG_INSTALLDIR) + install -m 0644 $(YANGSPECS) $(DESTDIR)$(OPT_YANG_INSTALLDIR) + +uninstall: + (cd $(DESTDIR)$(OPT_YANG_INSTALLDIR); rm -rf *.yang) + +install-include: + +depend: + + +#include .depend + diff --git a/yang/standard/iana-if-type@2014-05-08.yang b/yang/optional/iana-if-type@2014-05-08.yang similarity index 100% rename from yang/standard/iana-if-type@2014-05-08.yang rename to yang/optional/iana-if-type@2014-05-08.yang diff --git a/yang/standard/ietf-interfaces@2018-02-20.yang b/yang/optional/ietf-interfaces@2018-02-20.yang similarity index 100% rename from yang/standard/ietf-interfaces@2018-02-20.yang rename to yang/optional/ietf-interfaces@2018-02-20.yang diff --git a/yang/standard/ietf-ip@2014-06-16.yang b/yang/optional/ietf-ip@2014-06-16.yang similarity index 100% rename from yang/standard/ietf-ip@2014-06-16.yang rename to yang/optional/ietf-ip@2014-06-16.yang diff --git a/yang/standard/ietf-netconf-monitoring@2010-10-04.yang b/yang/optional/ietf-netconf-monitoring@2010-10-04.yang similarity index 100% rename from yang/standard/ietf-netconf-monitoring@2010-10-04.yang rename to yang/optional/ietf-netconf-monitoring@2010-10-04.yang diff --git a/yang/standard/ietf-routing@2018-03-13.yang b/yang/optional/ietf-routing@2018-03-13.yang similarity index 100% rename from yang/standard/ietf-routing@2018-03-13.yang rename to yang/optional/ietf-routing@2018-03-13.yang diff --git a/yang/standard/ietf-module-revision@2018-08-08.yang b/yang/standard/ietf-module-revision@2018-08-08.yang deleted file mode 100644 index b7b6b7a1..00000000 --- a/yang/standard/ietf-module-revision@2018-08-08.yang +++ /dev/null @@ -1,392 +0,0 @@ -module ietf-module-revision { - yang-version 1.1; - namespace "urn:ietf:params:xml:ns:yang:ietf-module-revision"; - prefix ml; - - import ietf-yang-library { - prefix yanglib; - } - import ietf-yang-types { - prefix yang; - } - - organization - "IETF Network Modeling (NETMOD) Working Group"; - contact - "WG Web: - - WG List: - - Author: Qin Wu - - Zitao Wang - "; - description - "This YANG module defines an module log."; - - revision 2018-08-08 { - description - "Initial revision."; - reference "RFC XXXX: Using Metadata with YANG for Module revisions"; - } - - identity operation-type { - description - "Abstract base identity for the operation type "; - } - - identity create { - base operation-type; - description - "Denotes create new data nodes"; - } - - identity delete { - base operation-type; - description - "Denotes delete the target node"; - } - - identity move { - base operation-type; - description - "Denote move the target node."; - } - - identity modify { - base operation-type; - description - "Denote modify the target data node."; - } - - identity statement-type { - description - "Base identity for statement type"; - } - - identity feature-statement { - base statement-type; - description - "feature statement, if this type be chose, it means that the - feature or if-feature statement been modified"; - } - identity identity-statement { - base statement-type; - description - "identity statement, if this type be chose, it means that the - identity statement been modified, for example, add new identity, etc."; - } - - identity grouping-statement { - base statement-type; - description - "grouping statement, if this type be chose, it means that the grouping - statement been modified."; - } - - identity typedef-statement { - base statement-type; - description - "typedef statement, if this type be chose, it means that the typedef - statement been modified."; - } - - identity augment-statement { - base statement-type; - description - "augment statement, if this type be chose, it means that the augment - statement been modified."; - } - - identity rpc-statement { - base statement-type; - description - "rpc statement, if this type be chose, it means that the rpc - statement been modified."; - } - - identity notification-statement { - base statement-type; - description - "notification statement, if this type be chose, it means that the notification - statement been modified."; - } - - extension purpose { - argument name; - description - "The purpose can be used to mark the data nodes change purpose. - The name argument can be specified in the following recommended mode - - bug-fix, which can help user to understand the data nodes' changes present bug fix, - - new-function, which can help user to understand the data nodes' changes present new function, - - nmda-conform, which can help user to understand the data nodes' changes conform to NMDA, - - and note that the user can argument the purpose name according to their sepcific requirements."; - } - - grouping data-definition { - container data-definition { - leaf target-node { - type yang:xpath1.0; - mandatory true; - description - "Identifies the target data node for update. - Notice that, if the update-type equal to move or delete, - this target-node must point to the data node of old version. - \t - For example, suppose the target node is a YANG leaf named a, - and the previous version is: - \t - container foo { - leaf a { type string; } - leaf b { type int32; } - } - \t - the new version is: - container foo { - leaf b {type int32;} - } - \t - Therefore, the targe-node should be /foo/a."; - } - leaf location-point { - type yang:xpath1.0; - description - "Identifies the location point where the updates happened."; - } - leaf where { - when "derived-from-or-self(../../change-operation, 'move')" { - description - "This leaf only applies for 'move' - updates."; - } - type enumeration { - enum "before" { - description - "Insert or move a data node before the data resource - identified by the 'point' parameter."; - } - enum "after" { - description - "Insert or move a data node after the data resource - identified by the 'point' parameter."; - } - enum "first" { - description - "Insert or move a data node so it becomes ordered - as the first entry."; - } - enum "last" { - description - "Insert or move a data node so it becomes ordered - as the last entry."; - } - } - default "last"; - description - "Identifies where a data resource will be inserted - or moved."; - } - anydata data-definition { - when "derived-from-or-self(../../change-operation, 'modify')" { - description - "This nodes only be present when - the 'change-operation' equal to 'modify'."; - } - description - "This nodes used for present the definitions before updated. - And this nodes only be present when - the 'change-operation' equal to 'modify'."; - } - description - "Container for data statement"; - } - description - "Grouping for data definition"; - } - - grouping other-statement { - container other-statement { - leaf statement-name { - type identityref { - base statement-type; - } - description - "Statement name, for example, identity, feature, typedef, etc."; - } - anydata statement-definition { - description - "This nodes used for present new the definitions."; - } - list substatements { - key "statement-name"; - leaf statement-name { - type identityref { - base statement-type; - } - description - "Statement name, for example, identity, feature, typedef, etc."; - } - anydata substatement-definition { - description - "This nodes used for present new the definitions."; - } - description - "List for substatements updates"; - } - description - "Container for header statement updates"; - } - description - "Grouping for header statement"; - } - - grouping change-log { - list revision-change-log { - key "index"; - leaf index { - type uint32; - description - "Index for module change log"; - } - leaf change-operation { - type identityref { - base operation-type; - } - mandatory true; - description - "This leaf indicate the change operation, such as create, move, delete, modify, etc."; - } - choice yang-statements { - description - "Choice for various YANG statements that have been impacted."; - case data-definition-statement { - uses data-definition; - } - case other-statement { - uses other-statement; - } - } - description - "List for module revision change log"; - } - description - "Grouping for module revision change log"; - } - - container yang-modules { - config false; - list module { - key "name revision"; - leaf name { - type yang:yang-identifier; - description - "The YANG module or submodule name."; - } - leaf revision { - type yanglib:revision-identifier; - description - "The YANG module or submodule revision date. If no revision - statement is present in the YANG module or submodule, this - leaf is not instantiated."; - } - leaf backward-compatible { - type boolean; - description - "Indicates whether it is a backward compatible version. - If this parameter is set to true, it means that this version is - a backwards compatible version"; - } - uses change-log; - description - "List for module updated log"; - } - description - "This container present the modules updated log."; - } - augment "/yanglib:yang-library/yanglib:module-set/yanglib:module" { - description - "Augment the yang library with backward compatibility indication."; - leaf backward-compatible { - type boolean; - description - "backward compatibility indication."; - } - } - augment "/yanglib:yang-library/yanglib:module-set/yanglib:module/yanglib:submodule" { - description - "Augment the yang library with backward compatibility indication."; - leaf backward-compatible { - type boolean; - description - "backward compatibility indication."; - } - } - rpc module-revision-change { - description - "Module Node change query operation."; - input { - leaf source-module-name { - type yang:yang-identifier; - mandatory true; - description - "The Source YANG module or submodule name."; - } - leaf source-revision { - type yanglib:revision-identifier; - description - "The Source YANG module revision date. If no revision - statement is present in the YANG module or submodule, this - leaf is not instantiated."; - } - leaf target-module-name { - type yang:yang-identifier; - mandatory true; - description - "The Target YANG module or submodule name."; - } - leaf target-revision { - type yanglib:revision-identifier; - description - "The target YANG module revision date. If no revision - statement is present in the YANG module or submodule, this - leaf is not instantiated."; - } - } - output { - choice status-response{ - leaf wrong-match{ - type empty; - description - "This leaf indicates that two modules have nothing in common."; - } - list data-nodes { - key "data-node-name"; - description - "Each entry represents a data node of a given module that - have been changed from source revision of - a module to target revision of the module."; - leaf data-node-name { - type string; - description - "a data node name of a given module that - has been changed."; - } - leaf is-new-node { - type boolean; - description - "indicate the data node is newly introduced node in the target revision."; - } - leaf change-operation { - type identityref { - base operation-type; - } - description - "This leaf indicate the change operation, - such as create, move, delete, modify, etc."; - } - } - } - } - } -} From 6fc8a69dff014fd78cc0473857dd4db364db9e7f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 27 Nov 2019 22:02:39 +0100 Subject: [PATCH 16/23] Fixed: [xpath_tree2cbuf() changes integers into floating point representations #99](https://github.com/clicon/clixon/issues/99) --- CHANGELOG.md | 3 +- lib/clixon/clixon_xpath.h | 1 + lib/src/clixon_xpath | Bin 25708 -> 0 bytes lib/src/clixon_xpath.c | 8 +-- lib/src/clixon_xpath_parse.l | 2 +- lib/src/clixon_xpath_parse.y | 98 +++++++++++++++++++---------------- 6 files changed, 61 insertions(+), 51 deletions(-) delete mode 100644 lib/src/clixon_xpath diff --git a/CHANGELOG.md b/CHANGELOG.md index bd58463e..d92916e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,12 +14,13 @@ ### API changes on existing features (you may need to change your code) * Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional). * Clixon and mandatory yang spec are always installed - * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped lofgic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. + * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped logic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. * Optional yang files can be installed in a separate dir with `--with-opt-yang-installdir=DIR` (renamed from `with-std-yang-installdir`) * The multi-namespace augment state may rearrange the XML namespace attributes. * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. ### Corrected Bugs +* [xpath_tree2cbuf() changes integers into floating point representations #99](https://github.com/clicon/clixon/issues/99) * [xml_parse_string() is slow for a long XML string #96](https://github.com/clicon/clixon/issues/96) * Mandatory variables can no longer be deleted. * [Add missing includes](https://github.com/clicon/clixon/pulls) diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 0998da16..338dc002 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -106,6 +106,7 @@ struct xpath_tree{ enum xp_type xs_type; int xs_int; /* step-> axis-type */ double xs_double; + char *xs_strnr; /* original string xs_double: numeric value */ char *xs_s0; char *xs_s1; struct xpath_tree *xs_c0; /* child 0 */ diff --git a/lib/src/clixon_xpath b/lib/src/clixon_xpath deleted file mode 100644 index 472df3d5d30e5620c9625a568090f163f158d92c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25708 zcmb<-^>JfjWMqH=CI&kO5O0B?16T+`GB7B3fw^G9fx&`-lfi*OnL&Ypje&uIm4Sf) zrp^J%g3&)fhA}WOz-SJz2@DL(3=9k`3=9kwOb`JJCWr|zS_UG_0HdMCfZYbN4=Rmf zGf1pP3q&$7z-R^r1+V}}Kgg{QbirJP2f7Jh28^x%If#LQVFi?i=>s_rr0)k*-w&uh z82tfcFarYvjE4CSV6mv^)7>cPG*vsiGEIsZcb)i zX@zcug_*9IiC%HOo)I`+LFR+hy8DHKZ2}nsa-Re=-bEN7X#gZ2cgMlwcYeodOGd_f zc^ic}lvh7Y1Vw`m0|Pj|LHbTSP+)9e30eyhGh|?3FkxU|aB{u+X2V3?ek=+mre8J{OGIXGsV+&RPM+ssMv^rsM zgsMlk*A(nuUWOSe5cLI6^Iw4d%grFb4-tnthv5uZoR6VJ4OLtLT+T=`G(g=0tDhKh zGLw>XGL!T3AZ2#EXNYfnN@`JRdS-D+YEg)JR%LH>F z%JPc99Ed|Q^D;|d#)6D2NGvK&jV~@K%FIiLiKiA7#i!*lR1_qZWW=Xs78RE;#KT-t z7N1`bpPU3X5n_BMRAE_aGDy@YxvY#KB{iuu9V!lYWl3d0Dm0waQ^DbEtY-=q0EM|3 zLuy542}4?5ZemGt219&&W^sP9rDc3^adKiFD2$6s5|gvzlQXj8(-Jdt7>ZI8b8_;N z8H!7aQc4RzR8DFhLvCtracT*OS6osAqLPaX@)+XdQ;Ul7^5b*zlM_oa^YcKOQ$T8y z3o03MVdkWy78Nn1LF2Tzq^LL*Y;1Bam`W`w$}eJwj|U|bXjJDWX67-(r=}#9Br?Ru zClwb%#2MmK^HLbxeLS6<GBo1r)fg}u&#F5*_7D(bCJ3wkd*a1l#UM4UwFnAz|bAl8? zaR8Dy7gP*HMIecDg9M;B0ZE((Dh8r5ki>aG0#IClB+dsF15p)7;`|^1C~iO!2erwd z!VDcq;>hi*2}t6|_2vvDabcJt3=9klki%B z0FpSUO$?Jdfg~;o6J%guxPT-sg(Q9hNn9F9`~i|UtPcf}et{$|3lf0h4@ly2P%#ko z14&#SBml$E`UI4wklVu?Na9K`wG0dl0!ZS@Na7Mm;wnhu3P|E=Na7ku;?OPT&_~jiK{;Puc86dqcAN>FS|G(-f1qFr-P;LG40+@dY#0O>Jmj}T7 zT_8TF$a}c~%-;m!gR=6=1z`Rv5FeCX#nOIf%u>-`ceVR&jRs5S@Wd;n4bjV zgRf%u>-^fCd==K}FT zS?6T{n9l^_gR;y^2QdGayaGc8D670Q0P{bA_@FHEQUT0=1>%FU#!CS({}G4}$`UUb z!2DYvJ}4`^{O}j#|4Se~C=0xN0Op?p@f8^u7+zig^ACaepseun0GPiE#0O=8mm9$R zO&~rf>Aze6=C1MeW6nhxdXJqhby;Slg)}!+nME@hG{svn~ zc?AZBQo&G<&ZjTx{{R0UdyJJ$UV(w}^I=f_@MyN}kXB$|D3OCZK_qnl2i*h)kItw6 zFT}pA{{R0!zdXas;{X5ugUs+~ek0(~S^LAI+x17cgM`Nnk6w|ZAeVv!Ji0vuAT)zV z=Q)qg<1hC7{r?{%(j6cHqB;XOK-6&uP=a6pTY2&@)K~+L&e|Iu-L5x0x*0q=T|YpW z4gwyXt{~fPbUVm&y1wveuKmEkKji@bwga86Z<=f0FqCj~yT0gjeexPaGal%4ebVjv z1jSt+JUXv|98(W+49H}V8KpKa-v9ppznj6Qm-n791A|X5tGX})L+8O=pv<_h6ja&v z+8z;RfH?ETqQC$D?*Qenmuid*3}A~TK^7%n@aT5^un!yroyTAN{{8>|Yr}5W7u}&x zG!J!N@R-pZ`obgml1DGkRj``w&<`Gr7d<);LA9KJaRTHFG$;RnI{D0>|Np@O&|Le2 zq15t)4M;7>$=VPnmk1%8TnllsAl%9C|3IDmx(v;|KcJQ$f8kBoy+6?0EAbl~r#C!6 zUg-oyIEeYfqcZ@^?hbv@86blhw=X<8OCNNG-tp-4y>Q(13n(Z(j=TN<121vY?_2~A!&>ecmqr3D0MA7jV zj{l*?>3}7CL5c7MG+BrKLW&mtR*=%;u3tc2>301BNzuU`&2KV1I%`*Wbe1kS?g~yi z9^I}h__s0GIPkYxg6geq*A*Vk2N*p%T~~mlJUU$uc=Up>=?Vb`29TfDKrA}p(Oi3i zq14`^J9fnji=Uum>(MEr;?v8kD+o@yH3Eoq0ICW-dToUTVM+J-umAsFzGPxxIPSUy z?-|4!?qdRm(x9c8{86J!m__r~%9N=#SjV(eHhi>ucH7$c^0H@6t ziBR{)pjgtk4iYgq!Uj}85#fm&9-T}tQ@|$0u6WV@9VxWGBk06G#!VSOq z(cKaVn_1e!)=U2#Onz zZr2x3LrNj4DNhnE|G{O^0#G`O{rUg@aaVBUcDwHIXg-n=9Sf^m9Ke-JXX%CGu5XY_ z9+-1kzWx8-{DQI5^-H(w7Y}fmegl$>Y-0IaH!?6Vpokv>r@jzX5qD$3K#EyYX`v9tZAd<7?+?$8?^og$$8 z?!gOAK9_kA$%hA=P;B*hVaezFxBvfNvmbYT!vKj{P=@~D(J9dF`UX-qc{IOC@aU}F z;n7*T!J{*D#c|gIV5P@hFM#Q8*9{=Ao&N?-Zjd-EwRy4s3&=4(y}ajmz>Y{ka)b)R z5nFg*jwt#Dt$bcyU}j+O=nVzcld$+t`v*!bm0aLb@#T7u0&wDRJ>k&{!loiTkQBe> zE7%F3Y6|^Nr)K2f#-3y58{UHLd1`I86}Zv=87GNeMTo z6#y=EN>x3&T~B}tM7HMI0}Q2tV5>Wizu5cj|Noacj0_Af)4^6A0fqHT8BoB1Dgsbh zd<4BL{sA(Azx5<2B9FU10PC0x;&i({0QvdN7f|?sD$5VZm1XK@Q23VSfGSatvab+6 zsHj^3sXSLeDo-hx0gAYm110<*4|O|mv>xDZRf8x8#RY#0C}kgag@pMENC>U~ z*MHcymPx?s zjyr(5k&xyv_Hx7nnnd@5`dcq9d<2IBy!dGN04+Xdae#{t6AnZfHWic$dTkpxV8w^= zr~m)KMfuA(aKi;OfDWqn!3C2UB!nSZuhiy+8q8z|h{>nf5hjDukw>qs8rDcr-A~$*R+-$QWQLc_!Qbg z0tNI9Pz}-SdV?7pGteFk#GcR>9^K%^=42{HKvB>DDj1}8075SP*Q zOtliaY(0R+^(v6_I-yyt)cl3iduS+|u!BQ6hz$`IYe5$D+Dfs*Liy~6|Nmc3 zLf8Yc!Q?2YlmRCeP?2=TBl(m^cj$}mAP!LBqH?0Rsc)`5~a5MVDYYq>Xeo$==&Vb+^PCCQ^A5iQC zcaJYdk+>w2R-Pn>853?mYfN`R)Jz$5}o3K}i+V7y*~PFFblh zt-uPvo$pAn8(9@VBHgT#Agc91DeKF*pymv#Ain}b>jD0jc2M+#n)amv9^I^;`4kvH zLE7p1<8=kJPxD&Yqnq^>p8`X7=oe5LKy((YU2l{!z2lR)-?!VBCV1O*~Ia1_A94V|SQJUT&H z2ZVj0bqCm&#lQdmhbRvAXnbR#z`)SC_so4z(X;iy{r~?{Ji1v_K|_unovtqo4;*j3 zb05?I{QuvhxAnpO|NnP^R-nK$yUiPrL@!99yA@;#SlXlWT<7r@6W;v)-`RTQ{{R2Y zdqE^arT2?9uR*!3`A0@6&vCF60|NuYYvUJFz~Y_9U#tejb>~5kUeV2<21&1}FEazf ze$ey7*W|AT~Idv}A`9y9p2wXlMm z+H#9roZDF3z#9^I{=F!1O#eGDq=I*&svZF~Lye>2zΜYBu-j{vzkL4h|Nm}q z5P5XRzDV&fmH~%d3G0hbum1n{XgmT6UqrJyptE)lxDg3W=*L~pfCAS8+K_Cn-NRU7 z+FZMbsYKrc)TrzRB{2nVND}Kc4McWS;p_kZ_k$|g7w&KV{|9NU@I*xkhIqzB_*Pu!X2J; zK<)>nF>q~L%Jf>^qc;@PAbJ5;(GT(=*gdHrt3fS&aG~%4WF`|x2vn`K9smo1E&BWN z|Nm~+Gba!8%eR0uGB}1icK&w^^X&ZQ80y)1)iK1US9J%w0z;@ruP%rV_R)N5c-!OP zUuMuq`HQnJ{{Q!AeOn?2)9=&y%BS<2OXq*b{~~uhnh!I2SiUZO1sXt)j&+Q2jCG82 zj6a-~rUz61`7mgB{S6051!!D>5jw}GT5P2NoACs#)d2Bx6LZq?i*i#_6jCb+ic*V< zGxPJT6rvqei(?s7Q^3w=z@rYVtk_B+H?tT#<(itJ5FKl!pjr&p1f5oOV9*D1p_8Nv zH40#EQEFleL}@ZZXmMhCDu|;HZ3CV%wu|LrC`(O_hs>*jh2lXjgw6-&7#Mi|{{NrD#K6$<@BjZECI*Ht z|Nj5K!o;l*|NsAnqW>dE8te{GI39cR|9>~A zbcE@5ZDwX}WCp7NX#<%9Y6^lHWr8U7@WAZ>b$g{iEi%xo4a^*7XBLnlApM~JveVc9 z|IdQ_3zt8^1e4ccWMFvz{r`XPS`wH%Q!z*y>`xy?1_t*Z|Nn#6l)&VfCE)ghx_B-> z|NjTCA%V$ffVG4D*~7@d5cu=||9oWkdo(jMCxMLsc@u2U7Dfh!8NdGj2d^!GnZuk7 zRs@QRD~t>bAAbM;p9<39#3#_t;KV24#3$gy#{o`9GE58%5`X^x2L%Vns8Ku`0;3^7pAbk8f~*H~fYLBq zK}7?IjZSAm1)vmo%?wB#Xo46-!`7XFCWt|N*m^V2ge!;-TTcy|U=z0dIHiijM30VCFnpg*^15Gf4=mu_x{V;J0C?Do-50D}T z1_scCJBSIh|KERze_n7w^#6zQVd44#$}fY;gY*srhOJ{qx7!W6zAy|*r$Om5DBT97 zr$OmuPTF4N8YW=`<)^2Bq7e^fV~F3`%c< z(#N3mH7NZIN`HgWY|#A;Vo+KQN}EAxHz*wjrPH8v8I*2=($k+Ct$b3qg%$7?1A24*JqGDZdlW)}7$uprx8uplcN zGXnz)3u|Ux2?H|+>n8>V2BtY6ndVFovy+*Dfw=|5WaeN8H5^$v*f^#_4EVytz`$P3 z#K3TaRV>JTLGjDi35quk4O?ag2L4H)#LW*{^TWjN#lpbA%>N4He16bEFjoHSAWi(qAQSoP zSr`~N_(AUGJP;-vf~6Ib}0J z_Bb;$Fx2yd2J0F4rNDOPvVazOGTAXPFmNiAFf%X+ROIF`u&-odU{GKTI>gMtz+uG1 zz`z&`Vlr?{2C+jx;laTH+R4Ni3KAFK5C@5efy5;^rm!$DFouKJG7M}SCzwH@4YHjH zWGG`~B{Ktqpe3k>7YkAY%gW$B5J+?m2MYs(P;nUpV=RcpG%B$OcNtS&VfwG zf$%~^mVmsH3*p6xeq>}|SjNJ@z{%{P4k^GPsRkqlPBokiVj#N(L1D)@6Qu2c2t*;c zR|YbAjvgxmgHS~t1LI6kXfRET5bp+AG7FRrm?j2@3xJ$68>E+Mq7T^X;6PxS=pX{x z{=qm8qAf$@H^{j85QQlc?jYX!jiM0i7z9H=0lx(#yA3J^?)ZUJ%`swQU=T`WVB7+- zlX>EddayNHK!L?PaYDUtYJ4IC<2H!o4iLADfpI&8yP;kYyCFOeaOgR)fkH0`8hQ{%e=(PYI9gIn9KrxCLICAKkuS^) z42%~brmv}&{125^g|;JvOA^x=81I8z#xyZNxGXUT&WnKMXpoKIxZz?D1NmDp2xR6@ zkeQB9d%->{5ME5)5I8I&=PdUKM-CD zC|v$R*a^Y~sSJ$ZVw`DW2H4{ulR24Vp&pk4$Ce_43gmM=C-k6TsdFIi8a_1I7ErjIMGh-UsdWVeDcA<;z)68So$i z*!z1y!ysVqcY!^C@O~HACXn}KHiLZB#Rw{|nJ3Pumn$}4VC(@)Gfhm8D>h_c?1l0i zd5Ob)*BtkyoLP%#a6dzG1uub|llp7&%Z*ybjfx07-E78IM6X>@X-~Gcqu6$${)f z-^9Z>=L_8KUr+-gAa?(P+8rPh3rct}Sr3R){(zmr$(#XQT?}#2U$BcfnG2wzV2AyK znwtSiI{(2cm?ow`Tq(}<4Z2N;L7|j|fq_dNlp@f#4l&Mg=7NQgF%!riOcOI8t~6$X zWZnds8z5I2Gl9|r)5Hh{>1+_+g$a~PHI*Sz10E&iT(BR;1a_V zDsX0hJvg-}af4Dz6H01HWGaE~c9LoVrM`Hke^4hfuyM>{VqoC52kmm=W?)bRHAVi* zL+T!oQQ$Sf-8LM4X@ zRK|gFkz8^T17jW&$j?j@6CfVQ2b;${aZkNmMTr3eV*xb89poxX7#Itoya-6}6hXru znyZST+zjQ4G6u#HCQxiDS1>S^f^{ipGBB2bO_xsrdAl6UW||lPNepwCZmU8fN^%dB z0qfk#fwmqoPGC9(E}H`w7*zT|h5kxVGf(9OGXn$nDlpTLfq{WX8x-fNAR>l`fkEv8 z69a=9D3z#zbTg={F*7jm8W-|_q6M~DjE%z?)bD2$WK`u7=4R%T<`ZNTViyo+U|7BW3-pV;Ymesh_Ny-D8UtBTCR*Ro`FFHYB;y2u)QQG z1XV>DLCysQnHnqD0qt+gff=EnoRgWJ znukLsIX{m9w%@O!I7crTR4f#iq@<*#>1BYnnS*xg73*by=AUvhlQQ%5GC+qEK+FWq z&*)`Wmw|CNleX~nwUNfV*X~|)J-wxwNnM!9NO(ayM+=joFoaVE z;jG;~KayEgk0Yb3Ig&|Tm_zZiKF4(qVFQl&3`{JH%w>AaJWQ&LWwu5fViiw!H*=(y zGFgd4?S@EmoCGP_83iKQCa`f_XVT(@vYEL!(l{bH(m6hJD00ka(ida05{czFiK*EK zq=6$HOzQeDS21ZZg4k>m*qC`a6n2-{R(!5#=1}A){mh}*%whYP!&VC{@5Po|%48*M zShm*Ih{L|DgCm{ENO&Pf`hsST^tF+DJ}+2%eO+Yf+TCRkv)M}6)`Im-V9VIEa5u;N z`C$Kk=1}~+fa5wyhPi@6h?$Q`lab>obM8El2%8rhv-l?vi#ci+0}~4q+XN724I8t@ zlasqS=BIN!T?jXwLzuZ7=5{YOX5LSGCUT^gmF_7$`FZW0NM>F=4#zeQZ%{0hf}OhH zGe_jwNRIT<(x~QUj`@*K=R@Kprf7aKld;(DryP+W%a}9QFiWi|J^6X}(>wPJ0VNw#-FFn;#y4#0YT#v)PwRHE>`AoXPQP)eqOyt0xpGpPzMNWZc6CqFM;0Zf$U6=$aBrKTu=hN(bm%8N2f zQscp@ic3=ROTpF!`GH8t>*9;^@N= zpO%xDUd&KY7N46~0agRD8KfjWxwI%gIX|Z~HxJ1XAiIlFOF*41kbw{AYCfS5%tE-A`ms3H#e~;Il~rmc!z>+x`J+6fTy#9ZW?&+v2H<8eo1O_Nj^Aoo!#6S;^W;y z{hUKQ{r%$O89=*>v!Q`!#1NmGp90w`&QM$yUuFnu6(*<0mn9ZKqZT~(4U#f|C}2pg z$WO`wClYXwm8B*d#DjDp!W0w*6(Avh*Z2ruAF#i2@{_aUOTbJwPaju?g2d$P)Dnh* z#1hbaI@o9fke2xP{IsZJpON)wA86fciN)++Q8Q>k#WhJ0}^Kf&M z!Tapvb6{J^L6rq0Pz*o`#Wg6%KZqeMCqJwJ zUQq^#h|;{$;?xu)hT;gVU=r|B0LC4*|-!CnJElAtlp+Q=527PJ zv8X7qk^!s(#?DGE0y`ryH#3<*FFn5mOz44aftZ+7T+E=CoS&PUnpeW02R@k~KCvh< zFFmyw#?8!2%ZITOlafFQ4XQ9FGcOe;14>4qRuUx`G!F=B3_|8PK<7O{`ZA!=Qjoc@ zc|Z^wgh6USGz^0_N`mIzVESR_CxJ(`v79Xe9V~)rX8@fQgsi`W31WW<)IiYs6u4s0 zC_XZW0dhXmxBvh1p~@Lx^OG~60-zBakQUf{B?pLug#ADrGSCDHR17wM`2wn60ICr* zzX|d?Oh0TMF$^@wj-($pANm92DWv&NsPUkNEQ|@J<3M|sk=zfPZ!CjOpyq&8flfkz zFrdx?wSvI{*$fPzZLe_u!{#$zK=lWJRWX3i0Yi2_RG6U(8m2IFVe_Y;P98`NZ2lA) z3=HW02d(J=#VJgG19bki0XpFeo4*C=2lZ9a^@BRZAa{Yn7i1r7{#pREgPDPWK?)>@ zgh6&8aTz*6g9Z!`|AE8}p!1goQ2n6k5|B6ygIBOa*KmQvrl9GEovXG0v_qPKf#DHs z;u)kENgtHUFbhq83-o-K7SLP>(!4WFJ-YirQ(GYa!@_R@RR091e$e0yOfQIrg&&9w z!l20!Wc~1S$e^3=Vds#6)PgX&{oA1KhuJTo0m*+78X(mS44@GY2n#}@+Yj0{1KNBJ zou+4ituKI`SB9=0oex^e1&S(|e%Shh7oZ6>(4-{9S~!WW{|40kF#VvN%OJ%ch}3@< zns#9NVe{><^W>8nn1Io5Eg_)*AF^}3tbGP(gl)@7=FS679CpmnmKf*+&-iqY+d3S*_185kL0=S?Cj zU}j)~pVx>g&ddO7KcI@Uz}p3=;;am?`W{uBjR97Vql&XL!0KmIaSjGpy^AW&$pEWQ zQN_6!VD%)bIOe%wAbDm69tK#w2I9joGXpOJtiFPYfoNt1%yY&d;`|J-`US*?VP*ya z_&Js^F%ZqnAjkl#4?uhvW@ZqAm-8?&5Y5aW%m6FDL3|iyW)NY3mCGdKLc!HA6l$2h%$o4#(5dgXWBvM@-Z^-Gr;D< zVd{;b>d|MvA>}wf18f2rrXF;TD9AnN)5UR6_rT_3L2V#VIDjU?K=A^bp@h}fptI3H z;;=bNShdgrbr1SvA?O@Sko#dXc%X6`WIiaKvBk?`uzLgC&O{vNUQP#_gJdC; z30g;h&79LX)Pt5)2{K@wGx-sRdRAua=ezRZ5SPRuu82e20Ef6G4skym;t4p!>v4#8 zfYyv*sV}DDP!C!Xh%KB!YXBizFQE|vrOtv@elbZf1VG!-P+^8!ILv>mtpz( z4_G}f1NyQH(83uZ23`jAB@x1)1!WAp44`ADKz4%ngfK8LD1*g8BBWB&P1p=pyRHPT{;)69`l^lMPPAcl@Ru79O7GXh#$fs zewqdQ`NQ{dsDF(^{3i}^ZdL{cK_<-eY{glz+iM6~lLzr43h9bN+!u#%A^& zH$EA3s%=argq4@Ze{P^^o{G`O3_>_|TqT=|((h7#;{M>?^)RNQ`Ju^#lBL=LB zKm+la@!+A__|&|TqDltHfNn}@Zf+$*Jal*$%!>z&1EVN~&J93jq(NiXplLDCm^WlI zA@YQao|&P!G5YvFcyt}I+Yn8yr5SXn96XzVDrsbB0hI*L%AiRan?NPO1LdGSif9VV z48SuWdS*uE7GM@=x&XwpM9fp5YB4qhO*FU#Ir_TByZX6+W{<#;1Y@IwOA150OQfHp zuctHURNTDG5@?8l&l_flclYska`cJ!cXJDN4T%qNbn zOEKzs_;{qyDlREX&MiPy2|aHZRS@k!>G=4R;{5oG#JrT8ROqS2 z2=$)AY z(cFr5CNn~-IpoM=P~;YsfYLnZWM+gk$YkX6k--yL;G~0kN;b%LNSr{AtOlQVjqU7g zgvv}`-R2NqXIL%+C2Lq|hjOSlWWO`2&WhX|@M+e?B}L%VpD|?P!RKv5 X${f%P9Jo9K2VF@Ks$$5LA*vVvgsp2$ diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 33b094f9..3a9b48d0 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -180,8 +180,8 @@ xpath_tree_print0(cbuf *cb, cprintf(cb, "%d ", xs->xs_int); break; } - if (xs->xs_double) - cprintf(cb,"%lf ", xs->xs_double); + if (xs->xs_strnr) + cprintf(cb,"%s ", xs->xs_strnr); cprintf(cb, "\n"); if (xs->xs_c0) xpath_tree_print0(cb, xs->xs_c0,level+1); @@ -253,7 +253,7 @@ xpath_tree2cbuf(xpath_tree *xs, cprintf(xcb, "'%s'", xs->xs_s0); break; case XP_PRIME_NR: - cprintf(xcb, "%lf", xs->xs_double); + cprintf(xcb, "%s", xs->xs_strnr?xs->xs_strnr:"0"); break; case XP_STEP: switch (xs->xs_int){ @@ -313,6 +313,8 @@ xpath_tree2cbuf(xpath_tree *xs, int xpath_tree_free(xpath_tree *xs) { + if (xs->xs_strnr) + free(xs->xs_strnr); if (xs->xs_s0) free(xs->xs_s0); if (xs->xs_s1) diff --git a/lib/src/clixon_xpath_parse.l b/lib/src/clixon_xpath_parse.l index 31699443..8676b9d1 100644 --- a/lib/src/clixon_xpath_parse.l +++ b/lib/src/clixon_xpath_parse.l @@ -140,7 +140,7 @@ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+) \" { BEGIN(QLITERAL); return QUOTE; } \' { BEGIN(ALITERAL); return APOST; } -\-?({integer}|{real}) { sscanf(yytext,"%lf",&clixon_xpath_parselval.dval); return NUMBER;} +\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; } [0-9A-Za-z_\-]+ { clixon_xpath_parselval.string = strdup(yytext); return NAME; /* rather be catch-all */ } diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index 0fdeac5e..a5050aaa 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -44,7 +44,6 @@ %union { int intval; - double dval; char *string; void *stack; /* xpath_tree */ } @@ -54,8 +53,7 @@ %token ADDOP %token RELOP -%token NUMBER - +%token NUMBER %token X_EOF %token QUOTE %token APOST @@ -161,13 +159,13 @@ xpath_parse_exit(struct clicon_xpath_yacc_arg *xy) static xpath_tree * xp_new(enum xp_type type, int i0, - double d0, + char *numstr, char *s0, char *s1, xpath_tree *c0, xpath_tree *c1) { - xpath_tree *xs = NULL; + xpath_tree *xs = NULL; if ((xs = malloc(sizeof(xpath_tree))) == NULL){ clicon_err(OE_XML, errno, "malloc"); @@ -176,7 +174,15 @@ xp_new(enum xp_type type, memset(xs, 0, sizeof(*xs)); xs->xs_type = type; xs->xs_int = i0; - xs->xs_double = d0; + if (numstr){ + xs->xs_strnr = numstr; + if (sscanf(numstr, "%lf", &xs->xs_double) == EOF){ + clicon_err(OE_XML, errno, "sscanf"); + goto done; + } + } + else + xs->xs_double = 0.0; xs->xs_s0 = s0; xs->xs_s1 = s1; xs->xs_c0 = c0; @@ -196,50 +202,50 @@ start : expr X_EOF { _XY->xy_top=$1;clicon_debug(2,"start->expr"); | locationpath X_EOF { _XY->xy_top=$1;clicon_debug(2,"start->locationpath"); YYACCEPT; } ; -expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"expr->expr or andexpr"); } - | andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"expr-> andexpr"); } +expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"expr->expr or andexpr"); } + | andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"expr-> andexpr"); } ; -andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"andexpr-> andexpr and relexpr"); } - | relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"andexpr-> relexpr"); } +andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"andexpr-> andexpr and relexpr"); } + | relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"andexpr-> relexpr"); } ; -relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"relexpr-> relexpr relop addexpr"); } - | addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"relexpr-> addexpr"); } +relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"relexpr-> relexpr relop addexpr"); } + | addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"relexpr-> addexpr"); } ; -addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(2,"addexpr-> addexpr ADDOP unionexpr"); } - | unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"addexpr-> unionexpr"); } +addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);clicon_debug(2,"addexpr-> addexpr ADDOP unionexpr"); } + | unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"addexpr-> unionexpr"); } ; /* node-set */ -unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(2,"unionexpr-> unionexpr | pathexpr"); } - | pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"unionexpr-> pathexpr"); } +unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(2,"unionexpr-> unionexpr | pathexpr"); } + | pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"unionexpr-> pathexpr"); } ; -pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> locationpath"); } - | primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> primaryexpr"); } +pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> locationpath"); } + | primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(2,"pathexpr-> primaryexpr"); } ; /* location path returns a node-set */ -locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> rellocpath"); } - | abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> abslocpath"); } +locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> rellocpath"); } + | abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"locationpath-> abslocpath"); } ; -abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(2,"abslocpath-> /"); } - | '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(2,"abslocpath->/ rellocpath");} +abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,NULL, NULL);clicon_debug(2,"abslocpath-> /"); } + | '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,$2, NULL);clicon_debug(2,"abslocpath->/ rellocpath");} /* // is short for /descendant-or-self::node()/ */ - | DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$2, NULL); clicon_debug(2,"abslocpath-> // rellocpath"); } + | DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); clicon_debug(2,"abslocpath-> // rellocpath"); } ; -rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(2,"rellocpath-> step"); } - | rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(2,"rellocpath-> rellocpath / step"); } - | rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(2,"rellocpath-> rellocpath // step"); } +rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"rellocpath-> step"); } + | rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(2,"rellocpath-> rellocpath / step"); } + | rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); clicon_debug(2,"rellocpath-> rellocpath // step"); } ; -step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(2,"step->axisspec(%d) nodetest", $1); } - | '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(2,"step-> ."); } - | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, $2); clicon_debug(2,"step-> .."); } +step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);clicon_debug(2,"step->axisspec(%d) nodetest", $1); } + | '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); clicon_debug(2,"step-> ."); } + | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); clicon_debug(2,"step-> .."); } ; axisspec : AXISNAME { clicon_debug(2,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;} @@ -247,31 +253,31 @@ axisspec : AXISNAME { clicon_debug(2,"axisspec-> AXISNAME(%d) ::", $1); $$=$1 | { clicon_debug(2,"axisspec-> "); $$=A_CHILD;} ; -nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(2,"nodetest-> *"); } - | NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(2,"nodetest-> name(%s)",$1); } - | NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : name(%s)", $1, $3); } - | NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : *", $1); } - | NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype():%s", $1); } +nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(2,"nodetest-> *"); } + | NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); clicon_debug(2,"nodetest-> name(%s)",$1); } + | NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : name(%s)", $1, $3); } + | NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);clicon_debug(2,"nodetest-> name(%s) : *", $1); } + | NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,NULL, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype():%s", $1); } ; /* evaluates to boolean */ -predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(2,"predicates-> [ expr ]"); } - | { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(2,"predicates->"); } +predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); clicon_debug(2,"predicates-> [ expr ]"); } + | { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(2,"predicates->"); } ; -primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(2,"primaryexpr-> ( expr )"); } - | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> NUMBER(%lf)", $1); } - | QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" string \""); } - | QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" \""); } - | APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' string '"); } - | APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' '"); } - | FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); } - | FUNCTIONNAME '(' args ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, $3, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); } +primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); clicon_debug(2,"primaryexpr-> ( expr )"); } + | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> NUMBER(%s)", $1); /*XXX*/} + | QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" string \""); } + | QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> \" \""); } + | APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' string '"); } + | APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, NULL, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> ' '"); } + | FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,NULL, $1, NULL, NULL, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); } + | FUNCTIONNAME '(' args ')' { $$=xp_new(XP_PRIME_FN,A_NAN,NULL, $1, NULL, $3, NULL);clicon_debug(2,"primaryexpr-> functionname ( arguments )"); } ; -args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, $3); +args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3); clicon_debug(2,"args -> args expr");} - | expr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL); + | expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(2,"args -> expr "); } ; From 69b27f3280f1359d3d075715a399a7ec483b2142 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 30 Nov 2019 22:19:23 +0100 Subject: [PATCH 17/23] Added clicon_handle as parameter to all functions to get better error message --- CHANGELOG.md | 1 + lib/clixon/clixon_data.h | 6 ------ lib/clixon/clixon_options.h | 6 ------ lib/clixon/clixon_proto.h | 9 ++++++--- lib/src/clixon_proto.c | 31 +++++++++++++++++++------------ lib/src/clixon_proto_client.c | 4 ++-- util/clixon_util_socket.c | 10 +++++++--- 7 files changed, 35 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d92916e9..f8baf5c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Fixed multi-namespace for augmented state which was not covered in 4.2.0. ### API changes on existing features (you may need to change your code) +* C-API: Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message * Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional). * Clixon and mandatory yang spec are always installed * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped logic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 3f173e04..42981a3b 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -40,12 +40,6 @@ #ifndef _CLIXON_DATA_H_ #define _CLIXON_DATA_H_ -/* - * Constants - */ -/* default group membership to access config unix socket */ -#define CLICON_SOCK_GROUP "clicon" - /* * Types */ diff --git a/lib/clixon/clixon_options.h b/lib/clixon/clixon_options.h index fdca3460..6177ee71 100644 --- a/lib/clixon/clixon_options.h +++ b/lib/clixon/clixon_options.h @@ -38,12 +38,6 @@ #ifndef _CLIXON_OPTIONS_H_ #define _CLIXON_OPTIONS_H_ -/* - * Constants - */ -/* default group membership to access config unix socket */ -#define CLICON_SOCK_GROUP "clicon" - /* * Types */ diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index 5e77fcb2..97f005e4 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -69,14 +69,17 @@ struct clicon_msg *clicon_msg_encode(uint32_t id, char *format, ...); #endif int clicon_msg_decode(struct clicon_msg *msg, yang_stmt *yspec, uint32_t *id, cxobj **xml); -int clicon_connect_unix(char *sockpath); +int clicon_connect_unix(clicon_handle h, char *sockpath); -int clicon_rpc_connect_unix(struct clicon_msg *msg, + +int clicon_rpc_connect_unix(clicon_handle h, + struct clicon_msg *msg, char *sockpath, char **ret, int *sock0); -int clicon_rpc_connect_inet(struct clicon_msg *msg, +int clicon_rpc_connect_inet(clicon_handle h, + struct clicon_msg *msg, char *dst, uint16_t port, char **ret, diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index 5c7d98f7..6c1dbd04 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -71,6 +71,7 @@ #include "clixon_yang.h" #include "clixon_sig.h" #include "clixon_xml.h" +#include "clixon_options.h" #include "clixon_proto.h" static int _atomicio_sig = 0; @@ -191,12 +192,14 @@ clicon_msg_decode(struct clicon_msg *msg, } /*! Open local connection using unix domain sockets + * @param[in] h Clicon handle * @param[in] sockpath Unix domain file path - * @retval s socket - * @retval -1 error + * @retval s socket + * @retval -1 error */ int -clicon_connect_unix(char *sockpath) +clicon_connect_unix(clicon_handle h, + char *sockpath) { struct sockaddr_un addr; int retval = -1; @@ -213,9 +216,9 @@ clicon_connect_unix(char *sockpath) clicon_debug(2, "%s: connecting to %s", __FUNCTION__, addr.sun_path); if (connect(s, (struct sockaddr *)&addr, SUN_LEN(&addr)) < 0){ if (errno == EACCES) - clicon_err(OE_CFG, errno, "connecting unix socket: %s." - "Client should be member of group $CLICON_SOCK_GROUP: ", - sockpath); + clicon_err(OE_CFG, errno, "connecting unix socket: %s. " + "Is user not member of group: \"%s\"?", + sockpath, clicon_sock_group(h)); else clicon_err(OE_CFG, errno, "connecting unix socket: %s", sockpath); close(s); @@ -394,6 +397,7 @@ clicon_msg_rcv(int s, /*! Connect to server, send a clicon_msg message and wait for result using unix socket * + * @param[in] h Clicon handle * @param[in] msg CLICON msg data structure. It has fixed header and variable body. * @param[in] sockpath Unix domain file path * @param[out] retdata Returned data as string netconf xml tree. @@ -403,7 +407,8 @@ clicon_msg_rcv(int s, * @see clicon_rpc But this is one-shot rpc: open, send, get reply and close. */ int -clicon_rpc_connect_unix(struct clicon_msg *msg, +clicon_rpc_connect_unix(clicon_handle h, + struct clicon_msg *msg, char *sockpath, char **retdata, int *sock0) @@ -422,7 +427,7 @@ clicon_rpc_connect_unix(struct clicon_msg *msg, clicon_err(OE_PROTO, EIO, "%s: Not unix socket", sockpath); goto done; } - if ((s = clicon_connect_unix(sockpath)) < 0) + if ((s = clicon_connect_unix(h, sockpath)) < 0) goto done; if (clicon_rpc(s, msg, retdata) < 0) goto done; @@ -436,7 +441,8 @@ clicon_rpc_connect_unix(struct clicon_msg *msg, } /*! Connect to server, send a clicon_msg message and wait for result using an inet socket - * This uses unix domain socket communication + * + * @param[in] h Clicon handle * @param[in] msg CLICON msg data structure. It has fixed header and variable body. * @param[in] dst IPv4 address * @param[in] port TCP port @@ -447,7 +453,8 @@ clicon_rpc_connect_unix(struct clicon_msg *msg, * @see clicon_rpc But this is one-shot rpc: open, send, get reply and close. */ int -clicon_rpc_connect_inet(struct clicon_msg *msg, +clicon_rpc_connect_inet(clicon_handle h, + struct clicon_msg *msg, char *dst, uint16_t port, char **retdata, @@ -597,9 +604,9 @@ send_msg_notify(int s, /*! Send a clicon_msg NOTIFY message asynchronously to client * + * @param[in] h Clicon handle * @param[in] s Socket to communicate with client - * @param[in] level - * @param[in] xml Event as XML + * @param[in] xev Event as XML * @retval 0 OK * @retval -1 Error * @see send_msg_notify XXX beauty contest diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index a1de8f4e..5a3e7bd6 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -108,7 +108,7 @@ clicon_rpc_msg(clicon_handle h, /* What to do if inet socket? */ switch (clicon_sock_family(h)){ case AF_UNIX: - if (clicon_rpc_connect_unix(msg, sock, &retdata, sock0) < 0){ + if (clicon_rpc_connect_unix(h, msg, sock, &retdata, sock0) < 0){ #if 0 if (errno == ESHUTDOWN) /* Maybe could reconnect on a higher layer, but lets fail @@ -127,7 +127,7 @@ clicon_rpc_msg(clicon_handle h, clicon_err(OE_FATAL, 0, "CLICON_SOCK_PORT not set"); goto done; } - if (clicon_rpc_connect_inet(msg, sock, port, &retdata, sock0) < 0) + if (clicon_rpc_connect_inet(h, msg, sock, port, &retdata, sock0) < 0) goto done; break; } diff --git a/util/clixon_util_socket.c b/util/clixon_util_socket.c index 787b20ad..ed2c66c2 100644 --- a/util/clixon_util_socket.c +++ b/util/clixon_util_socket.c @@ -95,10 +95,14 @@ main(int argc, char *family = "UNIX"; int ret; cbuf *cb = cbuf_new(); - + clicon_handle h; + /* In the startup, logs to stderr & debug flag set later */ clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR); + if ((h = clicon_handle_init()) == NULL) + goto done; + optind = 1; opterr = 0; while ((c = getopt(argc, argv, "hD:s:f:Ja:")) != -1) @@ -161,11 +165,11 @@ main(int argc, if ((msg = clicon_msg_encode(getpid(), "%s", cbuf_get(cb))) < 0) goto done; if (strcmp(family, "UNIX")==0){ - if (clicon_rpc_connect_unix(msg, sockpath, &retdata, NULL) < 0) + if (clicon_rpc_connect_unix(h, msg, sockpath, &retdata, NULL) < 0) goto done; } else - if (clicon_rpc_connect_inet(msg, sockpath, 4535, &retdata, NULL) < 0) + if (clicon_rpc_connect_inet(h, msg, sockpath, 4535, &retdata, NULL) < 0) goto done; fprintf(stdout, "%s\n", retdata); retval = 0; From c4954f5c438cefb6ec13698baa2f2a5ec22c8a2e Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 1 Dec 2019 16:48:45 +0100 Subject: [PATCH 18/23] memerror in uid-get. reinsert save config yang spec (removed for wrong reasons previously causing memleaks) --- apps/backend/backend_main.c | 7 +++++- apps/backend/backend_socket.c | 6 ++++- apps/cli/cli_main.c | 7 +++++- apps/netconf/netconf_main.c | 7 +++++- apps/restconf/restconf_lib.c | 2 ++ apps/restconf/restconf_main.c | 5 +++- lib/clixon/clixon_data.h | 3 +++ lib/src/clixon_data.c | 45 +++++++++++++++++++++++++++++++---- lib/src/clixon_uid.c | 16 ++++++++----- 9 files changed, 83 insertions(+), 15 deletions(-) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index eb915210..da6c2f14 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -109,6 +109,8 @@ backend_terminate(clicon_handle h) xml_free(x); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); + if ((yspec = clicon_config_yang(h)) != NULL) + yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_nacm_ext(h)) != NULL) @@ -507,7 +509,7 @@ main(int argc, clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); - /* Create configure yang-spec */ + /* Create configure yang-spec (note different from dbspec holding application specs) */ if ((yspecfg = yspec_new()) == NULL) goto done; @@ -517,6 +519,9 @@ main(int argc, usage(h, argv[0]); return -1; } + if (clicon_config_yang_set(h, yspecfg) < 0) + goto done; + /* External NACM file? */ nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); if (nacm_mode && strcmp(nacm_mode, "external") == 0) diff --git a/apps/backend/backend_socket.c b/apps/backend/backend_socket.c index 018f6b6c..5d6bc82f 100644 --- a/apps/backend/backend_socket.c +++ b/apps/backend/backend_socket.c @@ -270,10 +270,12 @@ backend_accept_client(int fd, #error "Need getsockopt O_PEERCRED or getpeereid for unix socket peer cred" #endif if (name != NULL){ - if ((ce->ce_username = strdup(name)) == NULL){ + if ((ce->ce_username = name) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); + name = NULL; goto done; } + name = NULL; } break; case AF_INET: @@ -291,5 +293,7 @@ backend_accept_client(int fd, goto done; retval = 0; done: + if (name) + free(name); return retval; } diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 83c38625..172fc8d0 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -169,6 +169,8 @@ cli_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); + if ((yspec = clicon_config_yang(h)) != NULL) + yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) @@ -350,7 +352,7 @@ main(int argc, char **argv) clicon_debug_init(debug, NULL); - /* Create top-level yang spec and store as option */ + /* Create configure yang-spec (note different from dbspec holding application specs) */ if ((yspecfg = yspec_new()) == NULL) goto done; /* Find and read configfile */ @@ -359,6 +361,9 @@ main(int argc, char **argv) usage(h, argv[0]); return -1; } + if (clicon_config_yang_set(h, yspecfg) < 0) + goto done; + /* Now rest of options */ opterr = 0; optind = 1; diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 153ec13f..b3d8b215 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -331,6 +331,8 @@ netconf_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); + if ((yspec = clicon_config_yang(h)) != NULL) + yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) @@ -441,12 +443,15 @@ main(int argc, clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); - /* Create configure yang-spec */ + /* Create configure yang-spec (note different from dbspec holding application specs) */ if ((yspecfg = yspec_new()) == NULL) goto done; /* Find and read configfile */ if (clicon_options_main(h, yspecfg) < 0) return -1; + if (clicon_config_yang_set(h, yspecfg) < 0) + goto done; + /* Now rest of options */ optind = 1; opterr = 0; diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index b79de44f..22d474cb 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -605,6 +605,8 @@ restconf_terminate(clicon_handle h) clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); + if ((yspec = clicon_config_yang(h)) != NULL) + yspec_free(yspec); if ((nsctx = clicon_nsctx_global_get(h)) != NULL) cvec_free(nsctx); if ((x = clicon_conf_xml(h)) != NULL) diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index f188f7da..aaa639be 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -642,12 +642,15 @@ main(int argc, goto done; } - /* Create configure yang-spec */ + /* Create configure yang-spec note different from dbspec holding application specs) */ if ((yspecfg = yspec_new()) == NULL) goto done; /* Find and read configfile */ if (clicon_options_main(h, yspecfg) < 0) goto done; + if (clicon_config_yang_set(h, yspecfg) < 0) + goto done; + stream_path = clicon_option_str(h, "CLICON_STREAM_PATH"); /* Now rest of options, some overwrite option file */ optind = 1; diff --git a/lib/clixon/clixon_data.h b/lib/clixon/clixon_data.h index 42981a3b..961ac7aa 100644 --- a/lib/clixon/clixon_data.h +++ b/lib/clixon/clixon_data.h @@ -55,6 +55,9 @@ typedef struct { yang_stmt * clicon_dbspec_yang(clicon_handle h); int clicon_dbspec_yang_set(clicon_handle h, yang_stmt *ys); +yang_stmt * clicon_config_yang(clicon_handle h); +int clicon_config_yang_set(clicon_handle h, yang_stmt *ys); + cvec *clicon_nsctx_global_get(clicon_handle h); int clicon_nsctx_global_set(clicon_handle h, cvec *nsctx); diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 595e5db3..45e5bc46 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -73,10 +73,11 @@ #include "clixon_xpath.h" #include "clixon_data.h" -/*! Get YANG specification for application +/*! Get YANG specification for application specs * Must use hash functions directly since they are not strings. * @param[in] h Clicon handle * @retval yspec Yang spec + * @see clicon_config_yang for the configuration yang */ yang_stmt * clicon_dbspec_yang(clicon_handle h) @@ -90,10 +91,10 @@ clicon_dbspec_yang(clicon_handle h) return NULL; } -/*! Set yang specification for application - * ys must be a malloced pointer +/*! Set yang specification for application specifications * @param[in] h Clicon handle - * @param[in] yspec Yang spec + * @param[in] yspec Yang spec (malloced pointer) + * @see clicon_config_yang_set for the configuration yang */ int clicon_dbspec_yang_set(clicon_handle h, @@ -109,6 +110,42 @@ clicon_dbspec_yang_set(clicon_handle h, return 0; } +/*! Get YANG specification for clixon config (separate from application yangs) + * @param[in] h Clicon handle + * @retval yspec Yang spec + * @see clicon_dbspec_yang for the application specs + */ +yang_stmt * +clicon_config_yang(clicon_handle h) +{ + clicon_hash_t *cdat = clicon_data(h); + size_t len; + void *p; + + if ((p = clicon_hash_value(cdat, "control_yang", &len)) != NULL) + return *(yang_stmt **)p; + return NULL; +} + +/*! Set yang specification for configuration + * @param[in] h Clicon handle + * @param[in] yspec Yang spec (malloced pointer) + * @see clicon_dbspec_yang_set for the application specs + */ +int +clicon_config_yang_set(clicon_handle h, + yang_stmt *ys) +{ + clicon_hash_t *cdat = clicon_data(h); + + /* It is the pointer to ys that should be copied by hash, + so we send a ptr to the ptr to indicate what to copy. + */ + if (clicon_hash_add(cdat, "control_yang", &ys, sizeof(ys)) == NULL) + return -1; + return 0; +} + /*! Get Global "canonical" namespace context * Canonical: use prefix and namespace specified in the yang modules. * @param[in] h Clicon handle diff --git a/lib/src/clixon_uid.c b/lib/src/clixon_uid.c index b08cef5b..21160e4c 100644 --- a/lib/src/clixon_uid.c +++ b/lib/src/clixon_uid.c @@ -121,7 +121,7 @@ name2uid(const char *name, /*! Translate uid to user name * @param[in] uid User id - * @param[out] name User name + * @param[out] name User name (Malloced, need to be freed) * @retval 0 OK * @retval -1 Error. or not found */ @@ -131,7 +131,7 @@ uid2name(const uid_t uid, { int retval = -1; char buf[1024]; - struct passwd pwbuf; + struct passwd pwbuf = {0,}; struct passwd *pwbufp = NULL; if (getpwuid_r(uid, &pwbuf, buf, sizeof(buf), &pwbufp) != 0){ @@ -139,17 +139,21 @@ uid2name(const uid_t uid, goto done; } if (pwbufp == NULL){ - clicon_err(OE_UNIX, 0, "No such user: %u", uid); + clicon_err(OE_UNIX, ENOENT, "No such user: %u", uid); goto done; } - if (name) - *name = pwbufp->pw_name; + + if (name){ + if ((*name = strdup(pwbufp->pw_name)) == NULL){ + clicon_err(OE_UNIX, errno, "strdup"); + goto done; + } + } retval = 0; done: return retval; } - /* Privileges drop perm, temp and restore * @see https://www.usenix.org/legacy/events/sec02/full_papers/chen/chen.pdf */ From 08b128f4d7f79ae44380233f32ec06ed25cedc2d Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 1 Dec 2019 17:42:34 +0100 Subject: [PATCH 19/23] moved config yang spec from main functions to options_main function --- apps/backend/backend_main.c | 9 +-------- apps/cli/cli_main.c | 10 ++-------- apps/netconf/netconf_main.c | 12 +++--------- apps/restconf/restconf_main.c | 8 +------- lib/clixon/clixon_options.h | 2 +- lib/src/clixon_options.c | 13 ++++++++++--- 6 files changed, 18 insertions(+), 36 deletions(-) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index da6c2f14..b1091f3d 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -446,7 +446,6 @@ main(int argc, char *nacm_mode; int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR; yang_stmt *yspec = NULL; - yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */ char *str; int ss = -1; /* server socket */ cbuf *cbret = NULL; /* startup cbuf if invalid */ @@ -509,18 +508,12 @@ main(int argc, clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); - /* Create configure yang-spec (note different from dbspec holding application specs) */ - if ((yspecfg = yspec_new()) == NULL) - goto done; - /* Find and read configfile */ - if (clicon_options_main(h, yspecfg) < 0){ + if (clicon_options_main(h) < 0){ if (help) usage(h, argv[0]); return -1; } - if (clicon_config_yang_set(h, yspecfg) < 0) - goto done; /* External NACM file? */ nacm_mode = clicon_option_str(h, "CLICON_NACM_MODE"); diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 172fc8d0..cc5de600 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -283,7 +283,6 @@ main(int argc, char **argv) int logdst = CLICON_LOG_STDERR; char *restarg = NULL; /* what remains after options */ yang_stmt *yspec; - yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */ struct passwd *pw; char *str; int tabmode; @@ -352,17 +351,12 @@ main(int argc, char **argv) clicon_debug_init(debug, NULL); - /* Create configure yang-spec (note different from dbspec holding application specs) */ - if ((yspecfg = yspec_new()) == NULL) - goto done; - /* Find and read configfile */ - if (clicon_options_main(h, yspecfg) < 0){ + /* Find, read and parse configfile */ + if (clicon_options_main(h) < 0){ if (help) usage(h, argv[0]); return -1; } - if (clicon_config_yang_set(h, yspecfg) < 0) - goto done; /* Now rest of options */ opterr = 0; diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index b3d8b215..b98028a5 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -395,7 +395,6 @@ main(int argc, struct passwd *pw; struct timeval tv = {0,}; /* timeout */ yang_stmt *yspec = NULL; - yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */ char *str; uint32_t id; cvec *nsctx_global = NULL; /* Global namespace context */ @@ -443,15 +442,10 @@ main(int argc, clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); - /* Create configure yang-spec (note different from dbspec holding application specs) */ - if ((yspecfg = yspec_new()) == NULL) - goto done; - /* Find and read configfile */ - if (clicon_options_main(h, yspecfg) < 0) + /* Find, read and parse configfile */ + if (clicon_options_main(h) < 0) return -1; - if (clicon_config_yang_set(h, yspecfg) < 0) - goto done; - + /* Now rest of options */ optind = 1; opterr = 0; diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index aaa639be..e9354b18 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -582,7 +582,6 @@ main(int argc, char *dir; int logdst = CLICON_LOG_SYSLOG; yang_stmt *yspec = NULL; - yang_stmt *yspecfg = NULL; /* For config XXX clixon bug */ char *stream_path; int finish = 0; int start = 1; @@ -642,13 +641,8 @@ main(int argc, goto done; } - /* Create configure yang-spec note different from dbspec holding application specs) */ - if ((yspecfg = yspec_new()) == NULL) - goto done; /* Find and read configfile */ - if (clicon_options_main(h, yspecfg) < 0) - goto done; - if (clicon_config_yang_set(h, yspecfg) < 0) + if (clicon_options_main(h) < 0) goto done; stream_path = clicon_option_str(h, "CLICON_STREAM_PATH"); diff --git a/lib/clixon/clixon_options.h b/lib/clixon/clixon_options.h index 6177ee71..51eaedc7 100644 --- a/lib/clixon/clixon_options.h +++ b/lib/clixon/clixon_options.h @@ -109,7 +109,7 @@ int clicon_option_dump(clicon_handle h, int dblevel); int clicon_option_add(clicon_handle h, char *name, char *value); /* Initialize options: set defaults, read config-file, etc */ -int clicon_options_main(clicon_handle h, yang_stmt *yspec); +int clicon_options_main(clicon_handle h); /*! Check if a clicon option has a value */ int clicon_option_exists(clicon_handle h, const char *name); diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 72feb443..5b53cfc6 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -355,8 +355,7 @@ clicon_option_add(clicon_handle h, * other yang modules. */ int -clicon_options_main(clicon_handle h, - yang_stmt *yspec) +clicon_options_main(clicon_handle h) { int retval = -1; char *configfile; @@ -364,7 +363,11 @@ clicon_options_main(clicon_handle h, char *suffix; char xml = 0; /* Configfile is xml, otherwise legacy */ cxobj *xconfig = NULL; + yang_stmt *yspec = NULL; + /* Create configure yang-spec */ + if ((yspec = yspec_new()) == NULL) + goto done; /* * Set configure file if not set by command-line above */ @@ -413,8 +416,12 @@ clicon_options_main(clicon_handle h, clicon_err(OE_CFG, 0, "Config file %s: did not find corresponding Yang specification\nHint: File does not begin with: or clixon-config.yang not found?", configfile, CLIXON_CONF_NS); goto done; } + /* Set yang config spec (must store to free at exit, since conf_xml below uses it) */ + if (clicon_config_yang_set(h, yspec) < 0) + goto done; /* Set clixon_conf pointer to handle */ - clicon_conf_xml_set(h, xconfig); + if (clicon_conf_xml_set(h, xconfig) < 0) + goto done; retval = 0; done: From 46552066d1472cb15832246576a988b638f8b8e5 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 2 Dec 2019 20:55:28 +0100 Subject: [PATCH 20/23] Added nsc parameter to `xmldb_get()` --- CHANGELOG.md | 4 +++- apps/backend/backend_startup.c | 2 +- lib/clixon/clixon_datastore.h | 4 ++-- lib/src/clixon_datastore_read.c | 6 ++++-- util/clixon_util_datastore.c | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8baf5c7..d174d542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ * Fixed multi-namespace for augmented state which was not covered in 4.2.0. ### API changes on existing features (you may need to change your code) -* C-API: Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message +* C-API + * Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message + * Added nsc parameter to `xmldb_get()` * Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional). * Clixon and mandatory yang spec are always installed * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped logic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. diff --git a/apps/backend/backend_startup.c b/apps/backend/backend_startup.c index 96f35baa..9314968c 100644 --- a/apps/backend/backend_startup.c +++ b/apps/backend/backend_startup.c @@ -241,7 +241,7 @@ startup_extraxml(clicon_handle h, * It should be empty if extra-xml is null and reset plugins did nothing * then skip validation. */ - if (xmldb_get(h, tmp_db, NULL, &xt0) < 0) + if (xmldb_get(h, tmp_db, NULL, NULL, &xt0) < 0) goto done; if (xt0==NULL || xml_child_nr(xt0)==0) goto ok; diff --git a/lib/clixon/clixon_datastore.h b/lib/clixon/clixon_datastore.h index bb4e5e24..ba0cf9af 100644 --- a/lib/clixon/clixon_datastore.h +++ b/lib/clixon/clixon_datastore.h @@ -49,9 +49,9 @@ int xmldb_validate_db(const char *db); int xmldb_connect(clicon_handle h); int xmldb_disconnect(clicon_handle h); /* in clixon_datastore_read.[ch] */ -int xmldb_get(clicon_handle h, const char *db, char *xpath, cxobj **xtop); +int xmldb_get(clicon_handle h, const char *db, cvec *nsc, char *xpath, cxobj **xtop); int xmldb_get0(clicon_handle h, const char *db, - cvec *nc, char *xpath, + cvec *nsc, char *xpath, int copy, cxobj **xtop, modstate_diff_t *msd); int xmldb_get0_clear(clicon_handle h, cxobj *x); int xmldb_get0_free(clicon_handle h, cxobj **xp); diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 62921c6b..07fb53d4 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -647,12 +647,13 @@ xmldb_get_zerocopy(clicon_handle h, /*! Get content of datastore and return a copy of the XML tree * @param[in] h Clicon handle * @param[in] db Name of database to search in (filename including dir path + * @param[in] nsc XML namespace context for XPATH * @param[in] xpath String with XPATH syntax. or NULL for all * @param[out] xret Single return XML tree. Free with xml_free() * @retval 0 OK * @retval -1 Error * @code - * if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]", &xt) < 0) + * if (xmldb_get(xh, "running", NULL, "/interfaces/interface[name="eth"]", &xt) < 0) * err; * xml_free(xt); * @endcode @@ -661,10 +662,11 @@ xmldb_get_zerocopy(clicon_handle h, int xmldb_get(clicon_handle h, const char *db, + cvec *nsc, char *xpath, cxobj **xret) { - return xmldb_get0(h, db, NULL, xpath, 1, xret, NULL); + return xmldb_get0(h, db, nsc, xpath, 1, xret, NULL); } /*! Zero-copy variant of get content of database diff --git a/util/clixon_util_datastore.c b/util/clixon_util_datastore.c index 099e8446..ec069a34 100644 --- a/util/clixon_util_datastore.c +++ b/util/clixon_util_datastore.c @@ -198,7 +198,7 @@ main(int argc, char **argv) xpath = argv[1]; else xpath = "/"; - if (xmldb_get(h, db, xpath, &xt) < 0) + if (xmldb_get(h, db, NULL, xpath, &xt) < 0) goto done; clicon_xml2file(stdout, xt, 0, 0); fprintf(stdout, "\n"); @@ -217,7 +217,7 @@ main(int argc, char **argv) else xpath = "/"; for (i=0;i Date: Sat, 7 Dec 2019 18:10:19 +0100 Subject: [PATCH 21/23] [filter in netconf - one specific entry #100](https://github.com/clicon/clixon/issues/100) --- CHANGELOG.md | 1 + apps/netconf/netconf_filter.c | 1 - apps/netconf/netconf_rpc.c | 75 +++++++++++++-------------- lib/src/clixon_xml.c | 2 +- test/test_netconf.sh | 2 +- test/test_netconf_filter.sh | 96 +++++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 43 deletions(-) create mode 100755 test/test_netconf_filter.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index d174d542..57b656be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. ### Corrected Bugs +* [filter in netconf - one specific entry #100](https://github.com/clicon/clixon/issues/100) * [xpath_tree2cbuf() changes integers into floating point representations #99](https://github.com/clicon/clixon/issues/99) * [xml_parse_string() is slow for a long XML string #96](https://github.com/clicon/clixon/issues/96) * Mandatory variables can no longer be deleted. diff --git a/apps/netconf/netconf_filter.c b/apps/netconf/netconf_filter.c index 8451c33b..59540559 100644 --- a/apps/netconf/netconf_filter.c +++ b/apps/netconf/netconf_filter.c @@ -121,7 +121,6 @@ xml_filter_recursive(cxobj *xfilter, int remove_s; *remove_me = 0; - assert(xfilter && xparent && strcmp(xml_name(xfilter), xml_name(xparent))==0); /* 1. Check selection */ if (xml_child_nr(xfilter) == 0) goto match; diff --git a/apps/netconf/netconf_rpc.c b/apps/netconf/netconf_rpc.c index adb9329f..67e886f1 100644 --- a/apps/netconf/netconf_rpc.c +++ b/apps/netconf/netconf_rpc.c @@ -80,6 +80,31 @@ */ +static int +netconf_get_config_subtree(clicon_handle h, + cxobj *xfilter, + cxobj **xret) +{ + int retval = -1; + cxobj *xdata; + + /* a subtree filter is comprised of zero or more element subtrees*/ + if ((xdata = xpath_first(*xret, "/rpc-reply/data")) == NULL) + goto ok; + if (xml_filter(xfilter, xdata) < 0){ + xml_parse_va(xret, NULL, "" + "operation-failed" + "applicatio" + "error" + "filtering" + ""); + } +ok: + retval = 0; + // done: + return retval; +} + /*! Get configuration * @param[in] h Clicon handle * @param[in] xn Sub-tree (under xorig) at ... level. @@ -136,37 +161,22 @@ netconf_get_config(clicon_handle h, cxobj *xfilter; /* filter */ int retval = -1; char *ftype = NULL; - cxobj *xfilterconf; - cxobj *xconf; /* ie ... */ if ((xfilter = xpath_first(xn, "filter")) != NULL) ftype = xml_find_value(xfilter, "type"); - if (ftype == NULL || strcmp(ftype, "xpath")==0){ + if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) goto done; } else if (strcmp(ftype, "subtree")==0){ - /* Default rfc filter is subtree. I prefer xpath and use it internally. - Get whole subtree and then filter aftwerwards. This is suboptimal. - Therefore please use xpath. + /* Get whole config first, then filter. This is suboptimal */ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) goto done; - if (xfilter && - (xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL && - (xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){ - /* xml_filter removes parts of xml tree not matching */ - if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) || - xml_filter(xfilterconf, xconf) < 0){ - xml_parse_va(xret, NULL, "" - "operation-failed" - "applicatio" - "error" - "filtering" - ""); - } - } + /* Now filter on whole tree */ + if (netconf_get_config_subtree(h, xfilter, xret) < 0) + goto done; } else{ xml_parse_va(xret, NULL, "" @@ -348,37 +358,22 @@ netconf_get(clicon_handle h, cxobj *xfilter; /* filter */ int retval = -1; char *ftype = NULL; - cxobj *xfilterconf; - cxobj *xconf; /* ie ... */ if ((xfilter = xpath_first(xn, "filter")) != NULL) ftype = xml_find_value(xfilter, "type"); - if (ftype == NULL || strcmp(ftype, "xpath")==0){ + if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) goto done; } else if (strcmp(ftype, "subtree")==0){ - /* Default rfc filter is subtree. I prefer xpath and use it internally. - Get whole subtree and then filter aftwerwards. This is suboptimal. - Therefore please use xpath. + /* Get whole config + state first, then filter. This is suboptimal */ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) goto done; - if (xfilter && - (xfilterconf = xpath_first(xfilter, "//configuration"))!= NULL && - (xconf = xpath_first(*xret, "/rpc-reply/data")) != NULL){ - /* xml_filter removes parts of xml tree not matching */ - if ((strcmp(xml_name(xfilterconf), xml_name(xconf))!=0) || - xml_filter(xfilterconf, xconf) < 0){ - xml_parse_va(xret, NULL, "" - "operation-failed" - "applicatio" - "error" - "filtering" - ""); - } - } + /* Now filter on whole tree */ + if (netconf_get_config_subtree(h, xfilter, xret) < 0) + goto done; } else{ xml_parse_va(xret, NULL, "" diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index f7dcf0d3..add0961b 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -400,7 +400,7 @@ xml2ns(cxobj *x, /*! Add a namespace attribute to an XML node, either default or specific prefix * @param[in] x XML tree * @param[in] prefix prefix/ns localname. If NULL then set default xmlns - * @param[out] namespace URI namespace (or NULL). Will be copied + * @param[in] ns URI namespace (or NULL). Will be copied * @retval 0 OK * @retval -1 Error * @see xml2ns diff --git a/test/test_netconf.sh b/test/test_netconf.sh index e0476c1e..c451f061 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -136,7 +136,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" -new "netconf edit config merge" +new "netconf edit config merge eth2" expecteof "$clixon_netconf -qf $cfg" 0 'eth2ex:ethmerge]]>]]>' "^]]>]]>$" # Note, the type here is non-existant identityref, fails on validation diff --git a/test/test_netconf_filter.sh b/test/test_netconf_filter.sh new file mode 100755 index 00000000..8328c2ad --- /dev/null +++ b/test/test_netconf_filter.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# Test netconf filter, subtree and xpath +# Note subtree namespaces not implemented + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf_yang.xml +fyang=$dir/filter.yang + +cat < $cfg + + $cfg + /usr/local/share/clixon + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/lib/$APPNAME/backend + /usr/local/var/$APPNAME/$APPNAME.pidfile + /usr/local/var/$APPNAME + +EOF + +cat < $fyang +module filter{ + yang-version 1.1; + namespace "urn:example:filter"; + prefix fi; + container x{ + list y { + key a; + leaf a{ + type string; + } + leaf b{ + type string; + } + } + } +} +EOF + +new "test params: -f $cfg" + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg +fi + +new "waiting" +wait_backend + +new "Add two entries" +expecteof "$clixon_netconf -qf $cfg" 0 '1122]]>]]>' '^]]>]]>$' + +new "netconf commit" +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" + +new "wrong filter type" +expecteof "$clixon_netconf -qf $cfg" 0 "1]]>]]>" '^operation-failedapplicatioerrorfilter type not supportedtype]]>]]>$' + +new "get-config subtree one" +expecteof "$clixon_netconf -qf $cfg" 0 "1]]>]]>" '^11]]>]]>$' + +new "get subtree one" +expecteof "$clixon_netconf -qf $cfg" 0 "1]]>]]>" '^11]]>]]>$' + +new "get-config xpath one" +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^11]]>]]>$' + +new "get xpath one" +expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" '^11]]>]]>$' + +if [ $BE -eq 0 ]; then + exit # BE +fi + +new "Kill backend" +# Check if premature kill +pid=$(pgrep -u root -f clixon_backend) +if [ -z "$pid" ]; then + err "backend already dead" +fi +# kill backend +stop_backend -f $cfg + +rm -rf $dir From d68a829862f63855efffe5b899df0cbf311539f7 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sat, 7 Dec 2019 20:46:13 +0100 Subject: [PATCH 22/23] * Added namespace-context parameter `nsc` to `xpath_first` and `xpath_vec`, (`xpath_vec_nsc` and xpath_first_nsc` are removed). --- CHANGELOG.md | 7 +- apps/backend/backend_client.c | 24 ++--- apps/backend/backend_plugin.c | 2 +- apps/cli/cli_common.c | 12 +-- apps/cli/cli_show.c | 16 +-- apps/netconf/netconf_lib.c | 8 +- apps/netconf/netconf_main.c | 6 +- apps/netconf/netconf_rpc.c | 18 ++-- apps/restconf/restconf_lib.c | 2 +- apps/restconf/restconf_main.c | 2 +- apps/restconf/restconf_methods.c | 42 ++++---- apps/restconf/restconf_methods_get.c | 14 +-- apps/restconf/restconf_methods_post.c | 50 ++++----- apps/restconf/restconf_stream.c | 10 +- example/main/example_backend.c | 6 +- example/main/example_backend_nacm.c | 4 +- example/main/example_cli.c | 2 +- lib/clixon/clixon_xpath.h | 16 +-- lib/src/clixon_datastore_read.c | 8 +- lib/src/clixon_datastore_write.c | 2 +- lib/src/clixon_nacm.c | 30 +++--- lib/src/clixon_netconf_lib.c | 8 +- lib/src/clixon_options.c | 2 +- lib/src/clixon_proto_client.c | 42 ++++---- lib/src/clixon_stream.c | 2 +- lib/src/clixon_xml_changelog.c | 8 +- lib/src/clixon_xml_map.c | 2 +- lib/src/clixon_xml_sort.c | 4 +- lib/src/clixon_xpath.c | 145 ++------------------------ lib/src/clixon_yang_module.c | 4 +- util/clixon_util_insert.c | 4 +- util/clixon_util_xpath.c | 2 +- 32 files changed, 186 insertions(+), 318 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b656be..5a150706 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,14 @@ * Fixed multi-namespace for augmented state which was not covered in 4.2.0. ### API changes on existing features (you may need to change your code) -* C-API - * Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message - * Added nsc parameter to `xmldb_get()` * Yang files reorganized into three classes: clixon, mandatory, optional (previous "standard" split into mandatory and optional). * Clixon and mandatory yang spec are always installed * Optional yang files are loaded only if configured with `--enable-optyangs` (flipped logic and changed from `disable-stdyangs`). NOTE: you must do this to run examples and tests. * Optional yang files can be installed in a separate dir with `--with-opt-yang-installdir=DIR` (renamed from `with-std-yang-installdir`) +* C-API + * Added namespace-context parameter `nsc` to `xpath_first` and `xpath_vec`, (`xpath_vec_nsc` and xpath_first_nsc` are removed). + * Added clicon_handle as parameter to all `clicon_connect_` functions to get better error message + * Added nsc parameter to `xmldb_get()` * The multi-namespace augment state may rearrange the XML namespace attributes. * Main example yang changed to incorporate augmented state, new revision is 2019-11-15. diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 2aee6dca..943e9510 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -171,7 +171,7 @@ client_get_capabilities(clicon_handle h, cxobj *xrstate = NULL; /* xml restconf-state node */ cxobj *xcap = NULL; /* xml capabilities node */ - if ((xrstate = xpath_first(*xret, "restconf-state")) == NULL){ + if ((xrstate = xpath_first(*xret, NULL, "restconf-state")) == NULL){ clicon_err(OE_YANG, ENOENT, "restconf-state not found in config node"); goto done; } @@ -324,7 +324,7 @@ client_statedata(clicon_handle h, * Actually this is a safety catch, should really be done in plugins * and modules_state functions. */ - if (xpath_vec_nsc(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(*xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* If vectors are specified then mark the nodes found and * then filter out everything else, @@ -434,7 +434,7 @@ from_client_get_config(clicon_handle h, if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) goto done; if (ret == 0){ /* Do NACM validation */ - if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* NACM datanode/module read validation */ if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0) @@ -529,14 +529,14 @@ from_client_edit_config(clicon_handle h, goto done; goto ok; } - if ((x = xpath_first(xn, "default-operation")) != NULL){ + if ((x = xpath_first(xn, NULL, "default-operation")) != NULL){ if (xml_operation(xml_body(x), &operation) < 0){ if (netconf_invalid_value(cbret, "protocol", "Wrong operation")< 0) goto done; goto ok; } } - if ((xc = xpath_first(xn, "config")) == NULL){ + if ((xc = xpath_first(xn, NULL, "config")) == NULL){ if (netconf_missing_element(cbret, "protocol", "config", NULL) < 0) goto done; goto ok; @@ -967,7 +967,7 @@ from_client_get(clicon_handle h, if ((ret = nacm_access_pre(h, username, NACM_DATA, &xnacm)) < 0) goto done; if (ret == 0){ /* Do NACM validation */ - if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* NACM datanode/module read validation */ if (nacm_datanode_read(xret, xvec, xlen, username, xnacm) < 0) @@ -1122,9 +1122,9 @@ from_client_create_subscription(clicon_handle h, if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netmod:notification")) == NULL) goto done; - if ((x = xpath_first_nsc(xe, nsc, "//stream")) != NULL) + if ((x = xpath_first(xe, nsc, "//stream")) != NULL) stream = xml_find_value(x, "body"); - if ((x = xpath_first_nsc(xe, nsc, "//stopTime")) != NULL){ + if ((x = xpath_first(xe, nsc, "//stopTime")) != NULL){ if ((stoptime = xml_find_value(x, "body")) != NULL && str2time(stoptime, &stop) < 0){ if (netconf_bad_element(cbret, "application", "stopTime", "Expected timestamp") < 0) @@ -1132,7 +1132,7 @@ from_client_create_subscription(clicon_handle h, goto ok; } } - if ((x = xpath_first_nsc(xe, nsc, "//startTime")) != NULL){ + if ((x = xpath_first(xe, nsc, "//startTime")) != NULL){ if ((starttime = xml_find_value(x, "body")) != NULL && str2time(starttime, &start) < 0){ if (netconf_bad_element(cbret, "application", "startTime", "Expected timestamp") < 0) @@ -1140,7 +1140,7 @@ from_client_create_subscription(clicon_handle h, goto ok; } } - if ((xfilter = xpath_first_nsc(xe, nsc, "//filter")) != NULL){ + if ((xfilter = xpath_first(xe, nsc, "//filter")) != NULL){ if ((ftype = xml_find_value(xfilter, "type")) != NULL){ /* Only accept xpath as filter type */ if (strcmp(ftype, "xpath") != 0){ @@ -1367,8 +1367,8 @@ from_client_msg(clicon_handle h, goto reply; } - if ((x = xpath_first_nsc(xt, NULL, "/rpc")) == NULL){ - if ((x = xpath_first_nsc(xt, NULL, "/hello")) != NULL){ + if ((x = xpath_first(xt, NULL, "/rpc")) == NULL){ + if ((x = xpath_first(xt, NULL, "/hello")) != NULL){ if ((ret = from_client_hello(h, x, ce, cbret)) <0) goto done; goto reply; diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 3f0925a3..6ca91325 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -139,7 +139,7 @@ clixon_plugin_statedata(clicon_handle h, goto done; } cprintf(cberr, "Internal error: state callback returned invalid XML: "); - if (netconf_err2cb(xpath_first(xerr, "rpc-error"), cberr) < 0) + if (netconf_err2cb(xpath_first(xerr, NULL, "rpc-error"), cberr) < 0) goto done; if (*xret){ xml_free(*xret); diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 8a273cd4..7bc1f340 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -707,13 +707,13 @@ compare_dbs(clicon_handle h, astext = 0; if (clicon_rpc_get_config(h, NULL, "running", "/", NULL, &xc1) < 0) goto done; - if ((xerr = xpath_first(xc1, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(xc1, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } if (clicon_rpc_get_config(h, NULL, "candidate", "/", NULL, &xc2) < 0) goto done; - if ((xerr = xpath_first(xc2, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(xc2, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } @@ -877,7 +877,7 @@ save_config_file(clicon_handle h, clicon_err(OE_CFG, 0, "get config: empty tree"); /* Shouldnt happen */ goto done; } - if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } @@ -985,7 +985,7 @@ cli_notification_cb(int s, } if (clicon_msg_decode(reply, NULL, NULL, &xt) < 0) /* XXX pass yang_spec */ goto done; - if ((xe = xpath_first(xt, "//event")) != NULL){ + if ((xe = xpath_first(xt, NULL, "//event")) != NULL){ x = NULL; while ((x = xml_child_each(xe, x, -1)) != NULL) { switch (format){ @@ -1217,7 +1217,7 @@ cli_copy_config(clicon_handle h, /* Get from object configuration and store in x1 */ if (clicon_rpc_get_config(h, NULL, db, cbuf_get(cb), nsc, &x1) < 0) goto done; - if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(x1, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } @@ -1236,7 +1236,7 @@ cli_copy_config(clicon_handle h, xml_name_set(x2, "config"); cprintf(cb, "/%s", keyname); - if ((x = xpath_first_nsc(x2, nsc, "%s", cbuf_get(cb))) == NULL){ + if ((x = xpath_first(x2, nsc, "%s", cbuf_get(cb))) == NULL){ clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname); goto done; } diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 18af35cc..c0897b61 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -157,7 +157,7 @@ expand_dbvar(void *h, /* Get configuration */ if (clicon_rpc_get_config(h, NULL, dbstr, xpath, nsc, &xt) < 0) /* XXX */ goto done; - if ((xe = xpath_first(xt, "/rpc-error")) != NULL){ + if ((xe = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xe); goto ok; } @@ -204,12 +204,12 @@ expand_dbvar(void *h, fprintf(stderr, "%s\n", reason); goto done; } - if ((xcur = xpath_first_nsc(xt, nsc, "%s", xpath)) == NULL){ + if ((xcur = xpath_first(xt, nsc, "%s", xpath)) == NULL){ clicon_err(OE_DB, 0, "xpath %s should return merged content", xpath); goto done; } } - if (xpath_vec_nsc(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0) + if (xpath_vec(xcur, nsc, "%s", &xvec, &xlen, xpathcur) < 0) goto done; /* Loop for inserting into commands cvec. * Detect duplicates: for ordered-by system assume list is ordered, so you need @@ -486,7 +486,7 @@ cli_show_config1(clicon_handle h, if (clicon_rpc_get(h, cbuf_get(cbxpath), nsc, CONTENT_ALL, -1, &xt) < 0) goto done; } - if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } @@ -634,12 +634,12 @@ show_conf_xpath(clicon_handle h, goto done; if (clicon_rpc_get_config(h, NULL, str, xpath, nsc, &xt) < 0) goto done; - if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } - if (xpath_vec_nsc(xt, nsc, "%s", &xv, &xlen, xpath) < 0) + if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0) goto done; for (i=0; i" @@ -163,7 +163,7 @@ netconf_get_config(clicon_handle h, char *ftype = NULL; /* ie ... */ - if ((xfilter = xpath_first(xn, "filter")) != NULL) + if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL) ftype = xml_find_value(xfilter, "type"); if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) @@ -218,7 +218,7 @@ get_edit_opts(cxobj *xn, cxobj *x; char *optstr; - if ((x = xpath_first(xn, "test-option")) != NULL){ + if ((x = xpath_first(xn, NULL, "test-option")) != NULL){ if ((optstr = xml_body(x)) != NULL){ if (strcmp(optstr, "test-then-set") == 0) *testopt = TEST_THEN_SET; @@ -230,7 +230,7 @@ get_edit_opts(cxobj *xn, goto parerr; } } - if ((x = xpath_first(xn, "error-option")) != NULL){ + if ((x = xpath_first(xn, NULL, "error-option")) != NULL){ if ((optstr = xml_body(x)) != NULL){ if (strcmp(optstr, "stop-on-error") == 0) *erropt = STOP_ON_ERROR; @@ -360,7 +360,7 @@ netconf_get(clicon_handle h, char *ftype = NULL; /* ie ... */ - if ((xfilter = xpath_first(xn, "filter")) != NULL) + if ((xfilter = xpath_first(xn, NULL, "filter")) != NULL) ftype = xml_find_value(xfilter, "type"); if (xfilter == NULL || ftype == NULL || strcmp(ftype, "xpath")==0){ if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, NULL) < 0) @@ -443,7 +443,7 @@ netconf_notification_cb(int s, if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:netconf:notification:1.0")) == NULL) goto done; - if ((xn = xpath_first_nsc(xt, nsc, "notification")) == NULL) + if ((xn = xpath_first(xt, nsc, "notification")) == NULL) goto ok; /* create netconf message */ if ((cb = cbuf_new()) == NULL){ @@ -495,7 +495,7 @@ netconf_create_subscription(clicon_handle h, int s; char *ftype; - if ((xfilter = xpath_first(xn, "//filter")) != NULL){ + if ((xfilter = xpath_first(xn, NULL, "//filter")) != NULL){ if ((ftype = xml_find_value(xfilter, "type")) != NULL){ if (strcmp(ftype, "xpath") != 0){ xml_parse_va(xret, NULL, "" @@ -511,7 +511,7 @@ netconf_create_subscription(clicon_handle h, } if (clicon_rpc_netconf_xml(h, xml_parent(xn), xret, &s) < 0) goto done; - if (xpath_first(*xret, "rpc-reply/rpc-error") != NULL) + if (xpath_first(*xret, NULL, "rpc-reply/rpc-error") != NULL) goto ok; if (event_reg_fd(s, netconf_notification_cb, @@ -617,7 +617,7 @@ netconf_application_rpc(clicon_handle h, */ if (0) if ((youtput = yang_find(yrpc, Y_OUTPUT, NULL)) != NULL){ - xoutput=xpath_first(*xret, "/"); + xoutput=xpath_first(*xret, NULL, "/"); xml_spec_set(xoutput, youtput); /* needed for xml_spec_populate */ if (xml_apply(xoutput, CX_ELMNT, xml_spec_populate, yspec) < 0) goto done; diff --git a/apps/restconf/restconf_lib.c b/apps/restconf/restconf_lib.c index 22d474cb..a87ceec9 100644 --- a/apps/restconf/restconf_lib.c +++ b/apps/restconf/restconf_lib.c @@ -476,7 +476,7 @@ api_return_err(clicon_handle h, clicon_debug(1, "%s", __FUNCTION__); if ((cb = cbuf_new()) == NULL) goto done; - if ((xtag = xpath_first(xerr, "//error-tag")) == NULL){ + if ((xtag = xpath_first(xerr, NULL, "//error-tag")) == NULL){ restconf_notfound(r); goto ok; } diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index e9354b18..3ee07a19 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -418,7 +418,7 @@ api_restconf(clicon_handle h, else{ if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xerr, pretty, media_out, 0) < 0) goto done; goto ok; diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index 0ecf18f4..0545cb72 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -283,7 +283,7 @@ api_data_write(clicon_handle h, if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0) goto done; if (ret == 0){ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -296,7 +296,7 @@ api_data_write(clicon_handle h, "candidate", cbuf_get(cbpath), nsc, &xret) < 0){ if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -341,7 +341,7 @@ api_data_write(clicon_handle h, if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot, &xerr)) < 0) goto done; if (ret == 0){ /* validation failed */ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -358,7 +358,7 @@ api_data_write(clicon_handle h, if (data == NULL || strlen(data) == 0){ if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -373,7 +373,7 @@ api_data_write(clicon_handle h, if (xml_parse_string(data, yspec, &xdata0) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -392,7 +392,7 @@ api_data_write(clicon_handle h, if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -401,7 +401,7 @@ api_data_write(clicon_handle h, goto ok; } if (ret == 0){ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -422,7 +422,7 @@ api_data_write(clicon_handle h, if (xml_child_nr(xdata0) != 1){ if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -450,7 +450,7 @@ api_data_write(clicon_handle h, if (ymoddata != ymodapi){ if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -493,7 +493,7 @@ api_data_write(clicon_handle h, if (strcmp(dname, xml_name(xbot))){ if (netconf_operation_failed_xml(&xerr, "protocol", "Not same symbol in api-path as data") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -518,7 +518,7 @@ api_data_write(clicon_handle h, if (match_list_keys(ybot, xdata, xbot) < 0){ if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -542,7 +542,7 @@ api_data_write(clicon_handle h, if (parbod == NULL || strcmp(parbod, xml_body(xdata))){ if (netconf_operation_failed_xml(&xerr, "protocol", "api-path keys do not match data keys") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -603,7 +603,7 @@ api_data_write(clicon_handle h, clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) goto done; - if ((xe = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -616,14 +616,14 @@ api_data_write(clicon_handle h, cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ cbuf_reset(cbx); cprintf(cbx, "", username?username:""); cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) goto done; /* log errors from discard, but ignore */ - if ((xpath_first(xretdis, "//rpc-error")) != NULL) + if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; @@ -646,7 +646,7 @@ api_data_write(clicon_handle h, if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; /* If copy-config failed, log and ignore (already committed) */ - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); } @@ -840,7 +840,7 @@ api_data_delete(clicon_handle h, if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y, &xerr)) < 0) goto done; if (ret == 0){ /* validation failed */ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -871,7 +871,7 @@ api_data_delete(clicon_handle h, cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) goto done; - if ((xe = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -885,14 +885,14 @@ api_data_delete(clicon_handle h, cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ cbuf_reset(cbx); cprintf(cbx, "", clicon_nacm_recovery_user(h)); cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) goto done; /* log errors from discard, but ignore */ - if ((xpath_first(xretdis, "//rpc-error")) != NULL) + if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; @@ -915,7 +915,7 @@ api_data_delete(clicon_handle h, if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; /* If copy-config failed, log and ignore (already committed) */ - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); } diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c index b62da0da..124b35b1 100644 --- a/apps/restconf/restconf_methods_get.c +++ b/apps/restconf/restconf_methods_get.c @@ -130,7 +130,7 @@ api_data_get2(clicon_handle h, if (netconf_bad_attribute_xml(&xerr, "application", "content", "Unrecognized value of content attribute") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -152,7 +152,7 @@ api_data_get2(clicon_handle h, if (netconf_bad_attribute_xml(&xerr, "application", "depth", "Unrecognized value of depth attribute") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -172,7 +172,7 @@ api_data_get2(clicon_handle h, if ((ret = api_path2xpath_cvv(pcvec, pi, yspec, cbpath, &nsc, &xerr)) < 0) goto done; if (ret == 0){ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -196,7 +196,7 @@ api_data_get2(clicon_handle h, if (ret < 0){ if (netconf_operation_failed_xml(&xerr, "protocol", clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -218,7 +218,7 @@ api_data_get2(clicon_handle h, } #endif /* Check if error return */ - if ((xe = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -247,10 +247,10 @@ api_data_get2(clicon_handle h, } } else{ - if (xpath_vec_nsc(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){ + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0){ if (netconf_operation_failed_xml(&xerr, "application", clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } diff --git a/apps/restconf/restconf_methods_post.c b/apps/restconf/restconf_methods_post.c index c7700f41..40763d88 100644 --- a/apps/restconf/restconf_methods_post.c +++ b/apps/restconf/restconf_methods_post.c @@ -147,7 +147,7 @@ api_data_post(clicon_handle h, if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &ybot, &xerr)) < 0) goto done; if (ret == 0){ /* validation failed */ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -171,7 +171,7 @@ api_data_post(clicon_handle h, if (data == NULL || strlen(data) == 0){ if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -186,7 +186,7 @@ api_data_post(clicon_handle h, if (xml_parse_string(data, NULL, &xdata0) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -208,7 +208,7 @@ api_data_post(clicon_handle h, if ((ret = json_parse_str(data, yspec, &xdata0, &xerr)) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -217,7 +217,7 @@ api_data_post(clicon_handle h, goto ok; } if (ret == 0){ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -237,7 +237,7 @@ api_data_post(clicon_handle h, if (xml_child_nr(xdata0) != 1){ if (netconf_malformed_message_xml(&xerr, "The message-body MUST contain exactly one instance of the expected data resource") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -268,7 +268,7 @@ api_data_post(clicon_handle h, if (ys_real_module(ydata) != ymoddata){ if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -282,7 +282,7 @@ api_data_post(clicon_handle h, if (ybot && yang_parent_get(ydata) != ybot){ if (netconf_malformed_message_xml(&xerr, "Data is not prefixed with matching namespace") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -338,7 +338,7 @@ api_data_post(clicon_handle h, clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xret, NULL) < 0) goto done; - if ((xe = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -352,14 +352,14 @@ api_data_post(clicon_handle h, cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ cbuf_reset(cbx); cprintf(cbx, "", username?username:""); cprintf(cbx, ""); if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretdis, NULL) < 0) goto done; /* log errors from discard, but ignore */ - if ((xpath_first(xretdis, "//rpc-error")) != NULL) + if ((xpath_first(xretdis, NULL, "//rpc-error")) != NULL) clicon_log(LOG_WARNING, "%s: discard-changes failed which may lead candidate in an inconsistent state", __FUNCTION__); if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) /* Use original xe */ goto done; @@ -382,7 +382,7 @@ api_data_post(clicon_handle h, if (clicon_rpc_netconf(h, cbuf_get(cbx), &xretcom, NULL) < 0) goto done; /* If copy-config failed, log and ignore (already committed) */ - if ((xe = xpath_first(xretcom, "//rpc-error")) != NULL){ + if ((xe = xpath_first(xretcom, NULL, "//rpc-error")) != NULL){ clicon_log(LOG_WARNING, "%s: copy-config running->startup failed", __FUNCTION__); } @@ -466,7 +466,7 @@ api_operations_post_input(clicon_handle h, if (xml_parse_string(data, yspec, &xdata) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -479,7 +479,7 @@ api_operations_post_input(clicon_handle h, if ((ret = json_parse_str(data, yspec, &xdata, &xerr)) < 0){ if (netconf_malformed_message_xml(&xerr, clicon_err_reason) < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -488,7 +488,7 @@ api_operations_post_input(clicon_handle h, goto fail; } if (ret == 0){ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -527,7 +527,7 @@ api_operations_post_input(clicon_handle h, else if (netconf_malformed_message_xml(&xerr, "restconf RPC has malformed input statement (multiple or not called input)") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -601,7 +601,7 @@ api_operations_post_output(clicon_handle h, xml_child_nr_type(xret, CX_ELMNT) != 1){ if (netconf_malformed_message_xml(&xerr, "restconf RPC does not have single input") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -639,7 +639,7 @@ api_operations_post_output(clicon_handle h, (ret = xml_yang_validate_add(h, xoutput, &xerr)) < 0) goto done; if (ret == 0){ /* validation failed */ - if ((xe = xpath_first(xerr, "rpc-reply/rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-reply/rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -770,7 +770,7 @@ api_operations_post(clicon_handle h, if (oppath == NULL || strcmp(oppath,"/")==0){ if (netconf_operation_failed_xml(&xerr, "protocol", "Operation name expected") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -789,7 +789,7 @@ api_operations_post(clicon_handle h, if ((ys = yang_find(yspec, Y_MODULE, prefix)) == NULL){ if (netconf_operation_failed_xml(&xerr, "protocol", "yang module not found") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -800,7 +800,7 @@ api_operations_post(clicon_handle h, if ((yrpc = yang_find(ys, Y_RPC, id)) == NULL){ if (netconf_missing_element_xml(&xerr, "application", id, "RPC not defined") < 0) goto done; - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -826,7 +826,7 @@ api_operations_post(clicon_handle h, if ((ret = api_path2xml(oppath, yspec, xtop, YC_SCHEMANODE, 1, &xbot, &y, &xerr)) < 0) goto done; if (ret == 0){ /* validation failed */ - if ((xe = xpath_first(xerr, "rpc-error")) == NULL){ + if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto done; } @@ -867,7 +867,7 @@ api_operations_post(clicon_handle h, if ((ret = xml_yang_validate_rpc(h, xtop, &xret)) < 0) goto done; if (ret == 0){ - if ((xe = xpath_first(xret, "rpc-error")) == NULL){ + if ((xe = xpath_first(xret, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); goto ok; } @@ -900,7 +900,7 @@ api_operations_post(clicon_handle h, if (xml_parse_string(cbuf_get(cbret), NULL, &xret) < 0) goto done; /* Local error: return it and quit */ - if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -909,7 +909,7 @@ api_operations_post(clicon_handle h, else { /* Send to backend */ if (clicon_rpc_netconf_xml(h, xtop, &xret, NULL) < 0) goto done; - if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; diff --git a/apps/restconf/restconf_stream.c b/apps/restconf/restconf_stream.c index 47375a98..a6b6ecdb 100644 --- a/apps/restconf/restconf_stream.c +++ b/apps/restconf/restconf_stream.c @@ -187,11 +187,11 @@ restconf_stream_cb(int s, clicon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; } - if ((xn = xpath_first(xtop, "notification")) == NULL) + if ((xn = xpath_first(xtop, NULL, "notification")) == NULL) goto ok; #ifdef notused - xt = xpath_first(xn, "eventTime"); - if ((xe = xpath_first(xn, "event")) == NULL) /* event can depend on yang? */ + xt = xpath_first(xn, NULL, "eventTime"); + if ((xe = xpath_first(xn, NULL, "event")) == NULL) /* event can depend on yang? */ goto ok; if (xt) @@ -268,7 +268,7 @@ restconf_stream(clicon_handle h, cprintf(cb, "]]>]]>"); if (clicon_rpc_netconf(h, cbuf_get(cb), &xret, &s) < 0) goto done; - if ((xe = xpath_first(xret, "rpc-reply/rpc-error")) != NULL){ + if ((xe = xpath_first(xret, NULL, "rpc-reply/rpc-error")) != NULL){ if (api_return_err(h, r, xe, pretty, media_out, 0) < 0) goto done; goto ok; @@ -417,7 +417,7 @@ api_stream(clicon_handle h, else{ if (netconf_access_denied_xml(&xret, "protocol", "The requested URL was unauthorized") < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ if (api_return_err(h, r, xerr, pretty, media_out, 0) < 0) goto done; goto ok; diff --git a/example/main/example_backend.c b/example/main/example_backend.c index 928c07d2..95542477 100644 --- a/example/main/example_backend.c +++ b/example/main/example_backend.c @@ -321,7 +321,7 @@ example_statedata(clicon_handle h, goto done; if (xmldb_get0(h, "running", nsc1, "/interfaces/interface/name", 1, &xt, NULL) < 0) goto done; - if (xpath_vec_nsc(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) + if (xpath_vec(xt, nsc1, "/interfaces/interface/name", &xvec, &xlen) < 0) goto done; if (xlen){ cprintf(cb, ""); @@ -475,7 +475,7 @@ upgrade_2016(clicon_handle h, if ((name = xml_find_body(xi, "name")) == NULL) continue; /* shouldnt happen */ /* Get corresponding /interfaces/interface entry */ - xif = xpath_first(xt, "/interfaces/interface[name=\"%s\"]", name); + xif = xpath_first(xt, NULL, "/interfaces/interface[name=\"%s\"]", name); /* - Move /if:interfaces-state/if:interface/if:admin-status to * /if:interfaces/if:interface/ */ if ((x = xml_find(xi, "admin-status")) != NULL && xif){ @@ -578,7 +578,7 @@ upgrade_2018(clicon_handle h, /* Change type /interfaces/interface/statistics/in-octets to * decimal64 with fraction-digits 3 and divide values with 1000 */ - if ((x = xpath_first(xi, "statistics/in-octets")) != NULL){ + if ((x = xpath_first(xi, NULL, "statistics/in-octets")) != NULL){ if ((xb = xml_body_get(x)) != NULL){ uint64_t u64; cbuf *cb = cbuf_new(); diff --git a/example/main/example_backend_nacm.c b/example/main/example_backend_nacm.c index c0f49a40..a3c42657 100644 --- a/example/main/example_backend_nacm.c +++ b/example/main/example_backend_nacm.c @@ -87,7 +87,7 @@ nacm_validate(clicon_handle h, if (_transaction_log){ transaction_log(h, td, LOG_NOTICE, __FUNCTION__); if (_transaction_error_toggle==0 && - xpath_first(transaction_target(td), "%s", _transaction_xpath)){ + xpath_first(transaction_target(td), NULL, "%s", _transaction_xpath)){ _transaction_error_toggle=1; /* toggle if triggered */ clicon_err(OE_XML, 0, "User error"); return -1; /* induce fail */ @@ -116,7 +116,7 @@ nacm_commit(clicon_handle h, if (_transaction_log){ transaction_log(h, td, LOG_NOTICE, __FUNCTION__); if (_transaction_error_toggle==1 && - xpath_first(target, "%s", _transaction_xpath)){ + xpath_first(target, NULL, "%s", _transaction_xpath)){ _transaction_error_toggle=0; /* toggle if triggered */ clicon_err(OE_XML, 0, "User error"); return -1; /* induce fail */ diff --git a/example/main/example_cli.c b/example/main/example_cli.c index 04658d2e..330c38e4 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -109,7 +109,7 @@ example_client_rpc(clicon_handle h, /* Send to backend */ if (clicon_rpc_netconf_xml(h, xrpc, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 338dc002..1b2dfbb9 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -143,21 +143,13 @@ int xpath_vec_flag(cxobj *xcur, cvec *nsc, char *xpformat, uint16_t flags, * If you do not know what a namespace context is, see README.md#xml-and-xpath */ #if defined(__GNUC__) && __GNUC__ >= 3 -cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4))); -int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6))); +cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *xpformat, ...) __attribute__ ((format (printf, 3, 4))); +int xpath_vec(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 3, 6))); #else -cxobj *xpath_first_nsc(cxobj *xcur, cvec *nsc, char *xpformat, ...); -int xpath_vec_nsc(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...); +cxobj *xpath_first(cxobj *xcur, cvec *nsc, char *xpformat, ...); +int xpath_vec(cxobj *xcur, cvec *nsc, char *xpformat, cxobj ***vec, size_t *veclen, ...); #endif -/* Functions with nsc == NULL (implicit xpath context). */ -#if defined(__GNUC__) && __GNUC__ >= 3 -cxobj *xpath_first(cxobj *xcur, char *xpformat, ...) __attribute__ ((format (printf, 2, 3))); -int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); -#else -cxobj *xpath_first(cxobj *xcur, char *xpformat, ...); -int xpath_vec(cxobj *xcur, char *xpformat, cxobj ***vec, size_t *veclen, ...); -#endif int xpath2canonical(char *xpath0, cvec *nsc0, yang_stmt *yspec, char **xpath1, cvec **nsc1); #endif /* _CLIXON_XPATH_H */ diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 07fb53d4..29e096e5 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -263,7 +263,7 @@ text_read_modstate(clicon_handle h, if ((name = xml_find_body(xm, "name")) == NULL) continue; /* 3a) There is no such module in the system */ - if ((xs = xpath_first(xmcache, "module[name=\"%s\"]", name)) == NULL){ + if ((xs = xpath_first(xmcache, NULL, "module[name=\"%s\"]", name)) == NULL){ // fprintf(stderr, "%s: Module %s: not in system\n", __FUNCTION__, name); if ((xm2 = xml_dup(xm)) == NULL) goto done; @@ -425,7 +425,7 @@ xmldb_get_nocache(clicon_handle h, goto done; /* Here xt looks like: ... */ /* Given the xpath, return a vector of matches in xvec */ - if (xpath_vec_nsc(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(xt, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* If vectors are specified then mark the nodes found with all ancestors @@ -531,7 +531,7 @@ xmldb_get_cache(clicon_handle h, */ /* Here xt looks like: ... */ - if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* Make new tree by copying top-of-tree from x0t to x1t */ @@ -620,7 +620,7 @@ xmldb_get_zerocopy(clicon_handle h, else x0t = de->de_xml; /* Here xt looks like: ... */ - if (xpath_vec_nsc(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(x0t, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; /* Iterate through the match vector * For every node found in x0, mark the tree up to t1 diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index 9daf9b93..95eb5379 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -887,7 +887,7 @@ xmldb_put(clicon_handle h, if ((nsc = xml_nsctx_init(NULL, "urn:ietf:params:xml:ns:yang:ietf-netconf-acm")) == NULL) goto done; if (xnacm0 != NULL && - (xnacm = xpath_first_nsc(xnacm0, nsc, "nacm")) != NULL){ + (xnacm = xpath_first(xnacm0, nsc, "nacm")) != NULL){ /* Pre-NACM access step, if permit, then dont do any nacm checks in * text_modify_* below */ if ((permit = nacm_access(h, mode, xnacm, username)) < 0) diff --git a/lib/src/clixon_nacm.c b/lib/src/clixon_nacm.c index b0da26e6..51a83c51 100644 --- a/lib/src/clixon_nacm.c +++ b/lib/src/clixon_nacm.c @@ -213,7 +213,7 @@ nacm_rpc(char *rpc, goto step10; /* User's group */ - if (xpath_vec_nsc(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) + if (xpath_vec(xnacm, nsc, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) goto done; /* 5. If no groups are found, continue with step 10. */ if (glen == 0) @@ -222,14 +222,14 @@ nacm_rpc(char *rpc, configuration. If a rule-list's "group" leaf-list does not match any of the user's groups, proceed to the next rule-list entry. */ - if (xpath_vec_nsc(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0) + if (xpath_vec(xnacm, nsc, "rule-list", &rlistvec, &rlistlen) < 0) goto done; for (i=0; i= 3.10 */ if ((nsc = xml_nsctx_init(NULL, CLIXON_CONF_NS)) == NULL) goto done; - if ((xc = xpath_first_nsc(xt, nsc, "clixon-config")) == NULL){ + if ((xc = xpath_first(xt, nsc, "clixon-config")) == NULL){ clicon_err(OE_CFG, 0, "Config file %s: Lacks top-level \"clixon-config\" element\nClixon config files should begin with: ", filename, CLIXON_CONF_NS); goto done; diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 5a3e7bd6..5d4b8dba 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -272,7 +272,7 @@ clicon_rpc_generate_error(const char *prefix, * err; * if (clicon_rpc_get_config(h, NULL, "running", "/hello/world", nsc, &xt) < 0) * err; - * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + * if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ * clicon_rpc_generate_error("", xerr); * err; * } @@ -328,9 +328,9 @@ clicon_rpc_get_config(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; /* Send xml error back: first check error, then ok */ - if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL) + if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL) xd = xml_parent(xd); /* point to rpc-reply */ - else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL) + else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL) if ((xd = xml_new("data", NULL, NULL)) == NULL) goto done; if (xt){ @@ -394,7 +394,7 @@ clicon_rpc_edit_config(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Editing configuration", xerr); goto done; } @@ -441,7 +441,7 @@ clicon_rpc_copy_config(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Copying configuration", xerr); goto done; } @@ -481,7 +481,7 @@ clicon_rpc_delete_config(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Deleting configuration", xerr); goto done; } @@ -517,7 +517,7 @@ clicon_rpc_lock(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Locking configuration", xerr); goto done; } @@ -552,7 +552,7 @@ clicon_rpc_unlock(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Configuration unlock", xerr); goto done; } @@ -586,7 +586,7 @@ clicon_rpc_unlock(clicon_handle h, * err; * if (clicon_rpc_get(h, "/hello/world", nsc, CONTENT_ALL, -1, &xt) < 0) * err; - * if ((xerr = xpath_first(xt, "/rpc-error")) != NULL){ + * if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){ * clicon_rpc_generate_error(xerr); * err; * } @@ -650,9 +650,9 @@ clicon_rpc_get(clicon_handle h, if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; /* Send xml error back: first check error, then ok */ - if ((xd = xpath_first(xret, "/rpc-reply/rpc-error")) != NULL) + if ((xd = xpath_first(xret, NULL, "/rpc-reply/rpc-error")) != NULL) xd = xml_parent(xd); /* point to rpc-reply */ - else if ((xd = xpath_first(xret, "/rpc-reply/data")) == NULL) + else if ((xd = xpath_first(xret, NULL, "/rpc-reply/data")) == NULL) if ((xd = xml_new("data", NULL, NULL)) == NULL) goto done; if (xt){ @@ -693,7 +693,7 @@ clicon_rpc_close_session(clicon_handle h) goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Close session", xerr); goto done; } @@ -729,7 +729,7 @@ clicon_rpc_kill_session(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Kill session", xerr); goto done; } @@ -764,7 +764,7 @@ clicon_rpc_validate(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr); goto done; } @@ -797,7 +797,7 @@ clicon_rpc_commit(clicon_handle h) goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr); goto done; } @@ -830,7 +830,7 @@ clicon_rpc_discard_changes(clicon_handle h) goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Discard changes", xerr); goto done; } @@ -876,7 +876,7 @@ clicon_rpc_create_subscription(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, s0) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Create subscription", xerr); goto done; } @@ -911,11 +911,11 @@ clicon_rpc_debug(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Debug",xerr); goto done; } - if (xpath_first(xret, "//rpc-reply/ok") == NULL){ + if (xpath_first(xret, NULL, "//rpc-reply/ok") == NULL){ clicon_err(OE_XML, 0, "rpc error"); /* XXX extract info from rpc-error */ goto done; } @@ -954,11 +954,11 @@ clicon_hello_req(clicon_handle h, goto done; if (clicon_rpc_msg(h, msg, &xret, NULL) < 0) goto done; - if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){ + if ((xerr = xpath_first(xret, NULL, "//rpc-error")) != NULL){ clicon_rpc_generate_error("Hello", xerr); goto done; } - if ((x = xpath_first(xret, "hello/session-id")) == NULL){ + if ((x = xpath_first(xret, NULL, "hello/session-id")) == NULL){ clicon_err(OE_XML, 0, "hello session-id"); goto done; } diff --git a/lib/src/clixon_stream.c b/lib/src/clixon_stream.c index 397b91db..85e48edd 100644 --- a/lib/src/clixon_stream.c +++ b/lib/src/clixon_stream.c @@ -514,7 +514,7 @@ stream_notify1(clicon_handle h, else{ /* xpath match */ if (ss->ss_xpath == NULL || strlen(ss->ss_xpath)==0 || - xpath_first(xevent, "%s", ss->ss_xpath) != NULL) + xpath_first(xevent, NULL, "%s", ss->ss_xpath) != NULL) if ((*ss->ss_fn)(h, 0, xevent, ss->ss_arg) < 0) goto done; ss = NEXTQ(struct stream_subscription *, ss); diff --git a/lib/src/clixon_xml_changelog.c b/lib/src/clixon_xml_changelog.c index 3335beb2..833ee800 100644 --- a/lib/src/clixon_xml_changelog.c +++ b/lib/src/clixon_xml_changelog.c @@ -199,7 +199,7 @@ changelog_move(clicon_handle h, int retval = -1; cxobj *xp; /* destination parent node */ - if ((xp = xpath_first_nsc(xt, nsc, "%s", dst)) == NULL){ + if ((xp = xpath_first(xt, nsc, "%s", dst)) == NULL){ clicon_err(OE_XML, 0, "path required"); goto done; } @@ -252,7 +252,7 @@ changelog_op(clicon_handle h, if ((wxpath = xml_find_body(xi, "where")) == NULL) goto ok; /* Get vector of target nodes meeting the where requirement */ - if (xpath_vec_nsc(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0) + if (xpath_vec(xt, nsc, "%s", &wvec, &wlen, wxpath) < 0) goto done; for (i=0; ixc_type == XT_NODESET && xr->xc_size) - cx = xr->xc_nodeset[0]; - done: - if (xr) - ctx_free(xr); - if (xpath) - free(xpath); - return cx; -} - -/*! Xpath nodeset function where only the first matching entry is returned - * - * @param[in] xcur XML tree where to search - * @param[in] xpformat Format string for XPATH syntax - * @retval xml-tree XML tree of first match - * @retval NULL Error or not found - * - * @code - * cxobj *x; - * if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) { - * ... - * } - * @endcode - * @note the returned pointer points into the original tree so should not be freed after use. - * @note return value does not see difference between error and not found - * @see also xpath_vec. - * @see xpath_first_nsc which is more generic with namespace context - */ -cxobj * xpath_first(cxobj *xcur, + cvec *nsc, char *xpformat, ...) { @@ -532,7 +475,7 @@ xpath_first(cxobj *xcur, goto done; } va_end(ap); - if (xpath_vec_ctx(xcur, NULL, xpath, &xr) < 0) + if (xpath_vec_ctx(xcur, nsc, xpath, &xr) < 0) goto done; if (xr && xr->xc_type == XT_NODESET && xr->xc_size) cx = xr->xc_nodeset[0]; @@ -557,7 +500,7 @@ xpath_first(cxobj *xcur, * cvec *nsc; // namespace context * cxobj **vec; * size_t veclen; - * if (xpath_vec_nsc(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0) + * if (xpath_vec(xcur, nsc, "//symbol/foo", &vec, &veclen) < 0) * goto err; * for (i=0; ixc_type == XT_NODESET){ - *vec = xr->xc_nodeset; - xr->xc_nodeset = NULL; - *veclen = xr->xc_size; - } - retval = 0; - done: - if (xr) - ctx_free(xr); - if (xpath) - free(xpath); - return retval; -} - -/*! Given XML tree and xpath, returns nodeset as xml node vector - * If result is not nodeset, return empty nodeset - * @param[in] xcur xml-tree where to search - * @param[in] xpformat Format string for XPATH syntax - * @param[out] vec vector of xml-trees. Vector must be free():d after use - * @param[out] veclen returns length of vector in return value - * @retval 0 OK - * @retval -1 Error - * @code - * cxobj **vec; - * size_t veclen; - * if (xpath_vec(xcur, "//symbol/foo", &vec, &veclen) < 0) - * goto err; - * for (i=0; ixc_type == XT_NODESET){ *vec = xr->xc_nodeset; @@ -682,7 +557,7 @@ xpath_vec(cxobj *xcur, return retval; } -/* Xpath that returns a vector of matches (only nodes marked with flags) +/* XPath that returns a vector of matches (only nodes marked with flags) * @param[in] xcur xml-tree where to search * @param[in] xpformat Format string for XPATH syntax * @param[in] nsc External XML namespace context, or NULL diff --git a/lib/src/clixon_yang_module.c b/lib/src/clixon_yang_module.c index 0459da1b..cc1fe48a 100644 --- a/lib/src/clixon_yang_module.c +++ b/lib/src/clixon_yang_module.c @@ -306,7 +306,7 @@ yang_modules_state_get(clicon_handle h, /* xc is also original tree, need to copy it */ if ((xw = xml_wrap(xc, "top")) == NULL) goto done; - if (xpath_first(xw, "%s", xpath)){ + if (xpath_first(xw, NULL, "%s", xpath)){ if ((x = xml_dup(xc)) == NULL) /* Make copy and use below */ goto done; } @@ -338,7 +338,7 @@ yang_modules_state_get(clicon_handle h, if ((x = xml_wrap(x, "top")) < 0) goto done; /* extract xpath part of module-state tree */ - if (xpath_vec_nsc(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + if (xpath_vec(x, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; if (xvec != NULL){ for (i=0; i Date: Mon, 9 Dec 2019 21:12:39 +0100 Subject: [PATCH 23/23] test kill valgrind process after run --- apps/cli/cli_main.c | 2 +- test/lib.sh | 2 +- test/test_augment.sh | 2 +- test/test_choice.sh | 4 ++-- test/test_identity.sh | 2 +- test/test_nacm.sh | 2 +- test/test_nacm_default.sh | 2 +- test/test_nacm_ext.sh | 2 +- test/test_nacm_module_read.sh | 2 +- test/test_nacm_module_write.sh | 2 +- test/test_nacm_protocol.sh | 2 +- test/test_perf.sh | 2 +- test/test_perf_state.sh | 2 +- test/test_privileges.sh | 2 +- test/test_restconf.sh | 4 ++-- test/test_restconf2.sh | 4 ++-- test/test_restconf_err.sh | 4 ++-- test/test_restconf_jukebox.sh | 4 ++-- test/test_restconf_listkey.sh | 4 ++-- test/test_restconf_patch.sh | 4 ++-- test/test_restconf_startup.sh | 2 +- test/test_rpc.sh | 2 +- test/test_stream.sh | 2 +- test/test_submodule.sh | 2 +- test/test_upgrade_auto.sh | 2 +- test/test_upgrade_interfaces.sh | 2 +- test/test_upgrade_repair.sh | 2 +- test/test_yang_namespace.sh | 2 +- 28 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index cc5de600..2beb7867 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -541,7 +541,7 @@ main(int argc, char **argv) cligen_tree_add(cli_cligen(h), treeref, pt); if (printgen) - cligen_print(stdout, pt, 1); + cligen_print(stdout, pt, 1); /* pt_print */ } /* Initialize cli syntax */ diff --git a/test/lib.sh b/test/lib.sh index 4d43e4df..3e8e3c32 100755 --- a/test/lib.sh +++ b/test/lib.sh @@ -213,7 +213,7 @@ start_restconf(){ } stop_restconf(){ - sudo pkill -u $wwwuser -f "$clixon_restconf" + sudo pkill -u $wwwuser -f clixon_restconf # Dont use $clixon_restoconf doesnt work in valgrind if [ $valgrindtest -eq 3 ]; then sleep 1 checkvalgrind diff --git a/test/test_augment.sh b/test/test_augment.sh index 2cc1db1b..ccb7af20 100755 --- a/test/test_augment.sh +++ b/test/test_augment.sh @@ -169,7 +169,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_choice.sh b/test/test_choice.sh index 9bb5e8dc..129908db 100755 --- a/test/test_choice.sh +++ b/test/test_choice.sh @@ -111,7 +111,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg" start_backend -s init -f $cfg @@ -121,7 +121,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_identity.sh b/test/test_identity.sh index 4759723c..ce272ef6 100755 --- a/test/test_identity.sh +++ b/test/test_identity.sh @@ -155,7 +155,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_nacm.sh b/test/test_nacm.sh index dedf6799..2da70b4b 100755 --- a/test/test_nacm.sh +++ b/test/test_nacm.sh @@ -127,7 +127,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_nacm_default.sh b/test/test_nacm_default.sh index 97b3c90f..84ef39b2 100755 --- a/test/test_nacm_default.sh +++ b/test/test_nacm_default.sh @@ -103,7 +103,7 @@ EOF wait_backend new "kill old restconf daemon" - sudo pkill -u $wwwuser clixon_restconf + sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_nacm_ext.sh b/test/test_nacm_ext.sh index 9cfd720e..da066b30 100755 --- a/test/test_nacm_ext.sh +++ b/test/test_nacm_ext.sh @@ -147,7 +147,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable http basic auth)" start_restconf -f $cfg -- -a diff --git a/test/test_nacm_module_read.sh b/test/test_nacm_module_read.sh index 1f420f2f..4d2a3550 100755 --- a/test/test_nacm_module_read.sh +++ b/test/test_nacm_module_read.sh @@ -141,7 +141,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_nacm_module_write.sh b/test/test_nacm_module_write.sh index 25aa75ee..67082c42 100755 --- a/test/test_nacm_module_write.sh +++ b/test/test_nacm_module_write.sh @@ -149,7 +149,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_nacm_protocol.sh b/test/test_nacm_protocol.sh index 123d4f91..5f8d64d8 100755 --- a/test/test_nacm_protocol.sh +++ b/test/test_nacm_protocol.sh @@ -150,7 +150,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_perf.sh b/test/test_perf.sh index 385cc1a6..063e5d02 100755 --- a/test/test_perf.sh +++ b/test/test_perf.sh @@ -83,7 +83,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_perf_state.sh b/test/test_perf_state.sh index 402cfd3f..05935413 100755 --- a/test/test_perf_state.sh +++ b/test/test_perf_state.sh @@ -61,7 +61,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_privileges.sh b/test/test_privileges.sh index 27a37a44..0e927819 100755 --- a/test/test_privileges.sh +++ b/test/test_privileges.sh @@ -60,7 +60,7 @@ testrun(){ err fi # Kill all backends regardless of user or pid files (we mess with them in this test) - sudo pkill clixon_backend + sudo pkill -f clixon_backend # start backend as user diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 433f8d6b..e4e12451 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -43,7 +43,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg -- -s" start_backend -s init -f $cfg -- -s fi @@ -52,7 +52,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh index 162139a7..598baf11 100755 --- a/test/test_restconf2.sh +++ b/test/test_restconf2.sh @@ -74,7 +74,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg" start_backend -s init -f $cfg fi @@ -83,7 +83,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_restconf_err.sh b/test/test_restconf_err.sh index 192abc71..39ab119c 100755 --- a/test/test_restconf_err.sh +++ b/test/test_restconf_err.sh @@ -120,7 +120,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg" start_backend -s init -f $cfg fi @@ -129,7 +129,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_restconf_jukebox.sh b/test/test_restconf_jukebox.sh index e5631a9c..4a36fa97 100755 --- a/test/test_restconf_jukebox.sh +++ b/test/test_restconf_jukebox.sh @@ -69,7 +69,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg -- -s" start_backend -s init -f "$cfg" -- -s fi @@ -78,7 +78,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_restconf_listkey.sh b/test/test_restconf_listkey.sh index 24571e4d..ee778a4a 100755 --- a/test/test_restconf_listkey.sh +++ b/test/test_restconf_listkey.sh @@ -71,7 +71,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s init -f $cfg" start_backend -s init -f $cfg @@ -81,7 +81,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_restconf_patch.sh b/test/test_restconf_patch.sh index afb5510e..6facdc0c 100755 --- a/test/test_restconf_patch.sh +++ b/test/test_restconf_patch.sh @@ -100,7 +100,7 @@ if [ $BE -ne 0 ]; then if [ $? -ne 0 ]; then err fi - sudo pkill clixon_backend # to be sure + sudo pkill -f clixon_backend # to be sure new "start backend -s startup -f $cfg" start_backend -s startup -f $cfg fi @@ -109,7 +109,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon (-a is enable basic authentication)" start_restconf -f $cfg -- -a diff --git a/test/test_restconf_startup.sh b/test/test_restconf_startup.sh index e9fa9326..5aaeb4da 100755 --- a/test/test_restconf_startup.sh +++ b/test/test_restconf_startup.sh @@ -65,7 +65,7 @@ testrun(){ wait_backend new "kill old restconf daemon" - sudo pkill -u $wwwuser clixon_restconf + sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg -y $fyang $option diff --git a/test/test_rpc.sh b/test/test_rpc.sh index 1aaa5ee6..4174e37e 100755 --- a/test/test_rpc.sh +++ b/test/test_rpc.sh @@ -47,7 +47,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_stream.sh b/test/test_stream.sh index 27fafd1a..280f84fa 100755 --- a/test/test_stream.sh +++ b/test/test_stream.sh @@ -118,7 +118,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_submodule.sh b/test/test_submodule.sh index 7ee65882..823de222 100755 --- a/test/test_submodule.sh +++ b/test/test_submodule.sh @@ -163,7 +163,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_upgrade_auto.sh b/test/test_upgrade_auto.sh index 0dabb323..0169f29c 100755 --- a/test/test_upgrade_auto.sh +++ b/test/test_upgrade_auto.sh @@ -259,7 +259,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_upgrade_interfaces.sh b/test/test_upgrade_interfaces.sh index 20d071a7..169e5cab 100755 --- a/test/test_upgrade_interfaces.sh +++ b/test/test_upgrade_interfaces.sh @@ -270,7 +270,7 @@ testrun(){ wait_backend new "kill old restconf daemon" - sudo pkill -u $wwwuser clixon_restconf + sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_upgrade_repair.sh b/test/test_upgrade_repair.sh index 9f01b0fe..bb0a3301 100755 --- a/test/test_upgrade_repair.sh +++ b/test/test_upgrade_repair.sh @@ -117,7 +117,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg diff --git a/test/test_yang_namespace.sh b/test/test_yang_namespace.sh index 60d49b1b..6c700a74 100755 --- a/test/test_yang_namespace.sh +++ b/test/test_yang_namespace.sh @@ -80,7 +80,7 @@ new "waiting" wait_backend new "kill old restconf daemon" -sudo pkill -u $wwwuser clixon_restconf +sudo pkill -u $wwwuser -f clixon_restconf new "start restconf daemon" start_restconf -f $cfg