From 56e51f1a8d3fd9aa024a925038bdc8f6a59ce00f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 22 Jul 2018 21:29:21 +0200 Subject: [PATCH 01/71] 3.8.0.PRE preparations and * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 --- CHANGELOG.md | 18 + apps/backend/backend_client.c | 16 +- apps/cli/cli_common.c | 90 --- apps/cli/cli_show.c | 11 +- apps/cli/clixon_cli_api.h | 21 - configure | 4 +- configure.ac | 4 +- example/example_cli.c | 4 - include/clixon_custom.h | 15 - lib/clixon/clixon.h.in | 1 - lib/clixon/clixon_xsl.h | 50 -- lib/src/Makefile.in | 2 +- lib/src/clixon_options.c | 1 - lib/src/clixon_proto.c | 1 - lib/src/clixon_proto_client.c | 1 - lib/src/clixon_xml_map.c | 17 +- lib/src/clixon_xpath.c | 19 - lib/src/clixon_xsl.c | 1041 --------------------------------- test/lib.sh | 4 - test/test_netconf.sh | 19 +- test/test_order.sh | 18 - test/test_yang.sh | 5 - 22 files changed, 29 insertions(+), 1333 deletions(-) delete mode 100644 lib/clixon/clixon_xsl.h delete mode 100644 lib/src/clixon_xsl.c diff --git a/CHANGELOG.md b/CHANGELOG.md index ff9c8650..b9538186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Clixon Changelog +## 3.8.0 (Upcoming) + +### Major New features + +### API changes on existing features (you may need to change your code) + +### Minor changes +* Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 + +### Corrected Bugs + +### Known issues +* Namespace name relabeling is not supported. + * Eg: if "des" is defined as prefix for an imported module, then a relabeling using xmlfns is not supported, such as: +``` + x:des3 +``` + ## 3.7.0 (22 July 2018) ### Major New features diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 7ffdbf2b..224b371d 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -987,13 +987,7 @@ nacm_access(clicon_handle h, if (username == NULL) goto step10; /* User's group */ - if (xpath_vec(xacm, -#ifdef COMPAT_XSL - "groups/group[user-name=%s]", -#else - "groups/group[user-name='%s']", -#endif - &gvec, &glen, username) < 0) + if (xpath_vec(xacm, "groups/group[user-name='%s']", &gvec, &glen, username) < 0) goto done; /* 5. If no groups are found, continue with step 10. */ if (glen == 0) @@ -1010,13 +1004,7 @@ nacm_access(clicon_handle h, for (j=0; j #include #include -#include #include #include #include diff --git a/lib/clixon/clixon_xsl.h b/lib/clixon/clixon_xsl.h deleted file mode 100644 index 5d572528..00000000 --- a/lib/clixon/clixon_xsl.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * - ***** BEGIN LICENSE BLOCK ***** - - Copyright (C) 2009-2018 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 ***** - - * XML XPATH and XSLT functions. - */ -#ifndef _CLIXON_XSL_H -#define _CLIXON_XSL_H - -/* - * Prototypes - */ -int xpath_vec_xsl(cxobj *cxtop, char *xpath, cxobj ***vec, size_t *veclen); -int xpath_vec_flag_xsl(cxobj *cxtop, char *xpath, uint16_t flags, - cxobj ***vec, size_t *veclen); -cxobj *xpath_first_xsl(cxobj *cxtop, char *xpath); -#ifdef COMPAT_XSL -cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev); -#endif - -#endif /* _CLIXON_XSL_H */ diff --git a/lib/src/Makefile.in b/lib/src/Makefile.in index a37680c9..23126689 100644 --- a/lib/src/Makefile.in +++ b/lib/src/Makefile.in @@ -72,7 +72,7 @@ SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \ clixon_json.c clixon_yang.c clixon_yang_type.c \ clixon_hash.c clixon_options.c clixon_plugin.c \ clixon_proto.c clixon_proto_client.c \ - clixon_xsl.c clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \ + clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \ clixon_xml_db.c clixon_netconf_lib.c YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \ diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index cfd0d76c..7b97439f 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -67,7 +67,6 @@ #include "clixon_options.h" #include "clixon_xml.h" #include "clixon_plugin.h" -#include "clixon_xsl.h" #include "clixon_xpath_ctx.h" #include "clixon_xpath.h" #include "clixon_xml_map.h" diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index 2a71992e..6b41c6a5 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -71,7 +71,6 @@ #include "clixon_yang.h" #include "clixon_sig.h" #include "clixon_xml.h" -#include "clixon_xsl.h" #include "clixon_proto.h" static int _atomicio_sig = 0; diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 35c4b28c..63c4e4cf 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -64,7 +64,6 @@ #include "clixon_options.h" #include "clixon_xml.h" #include "clixon_plugin.h" -#include "clixon_xsl.h" #include "clixon_string.h" #include "clixon_xpath_ctx.h" #include "clixon_xpath.h" diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 301dfa0d..4576fc82 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -85,7 +85,6 @@ #include "clixon_plugin.h" #include "clixon_xpath_ctx.h" #include "clixon_xpath.h" -#include "clixon_xsl.h" #include "clixon_log.h" #include "clixon_err.h" #include "clixon_xml_sort.h" @@ -1088,13 +1087,7 @@ api_path_fmt2xpath(char *api_path_fmt, clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; } - cprintf(cb, -#ifdef COMPAT_XSL - "[%s=%s]", -#else - "[%s='%s']", -#endif - cv_name_get(cv), str); + cprintf(cb, "[%s='%s']", cv_name_get(cv), str); free(str); } } @@ -1511,13 +1504,7 @@ api_path2xpath_cvv(yang_spec *yspec, cprintf(xpath, "/%s", name); v = val; while ((cvi = cvec_each(cvk, cvi)) != NULL){ - cprintf(xpath, -#ifdef COMPAT_XSL - "[%s=%s]", -#else - "[%s='%s']", -#endif - cv_string_get(cvi), v); + cprintf(xpath, "[%s='%s']", cv_string_get(cvi), v); v += strlen(v)+1; } if (val) diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 173b30e5..e4c9513a 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -62,7 +62,6 @@ #include "clixon_handle.h" #include "clixon_yang.h" #include "clixon_xml.h" -#include "clixon_xsl.h" #include "clixon_xpath_parse.h" #include "clixon_xpath_ctx.h" #include "clixon_xpath.h" @@ -1142,16 +1141,11 @@ xpath_first(cxobj *xcur, goto done; } va_end(ap); -#ifdef COMPAT_XSL - if ((cx = xpath_first_xsl(xcur, xpath)) == NULL) - goto done; -#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; if (xr && xr->xc_type == XT_NODESET && xr->xc_size) cx = xr->xc_nodeset[0]; -#endif done: if (xr) ctx_free(xr); @@ -1211,10 +1205,6 @@ xpath_vec(cxobj *xcur, va_end(ap); *vec=NULL; *veclen = 0; -#ifdef COMPAT_XSL - if (xpath_vec_xsl(xcur, xpath, vec, veclen) < 0) - goto done; -#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; if (xr && xr->xc_type == XT_NODESET){ @@ -1222,7 +1212,6 @@ xpath_vec(cxobj *xcur, xr->xc_nodeset = NULL; *veclen = xr->xc_size; } -#endif retval = 0; done: if (xr) @@ -1268,10 +1257,8 @@ xpath_vec_flag(cxobj *xcur, size_t len; char *xpath = NULL; xp_ctx *xr = NULL; -#ifndef COMPAT_XSL int i; cxobj *x; -#endif va_start(ap, veclen); len = vsnprintf(NULL, 0, format, ap); @@ -1291,10 +1278,6 @@ xpath_vec_flag(cxobj *xcur, va_end(ap); *vec=NULL; *veclen = 0; -#ifdef COMPAT_XSL - if (xpath_vec_flag_xsl(xcur, xpath, flags, vec, veclen) < 0) - goto done; -#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; if (xr && xr->xc_type == XT_NODESET){ @@ -1305,8 +1288,6 @@ xpath_vec_flag(cxobj *xcur, goto done; } } -#endif - retval = 0; done: if (xr) diff --git a/lib/src/clixon_xsl.c b/lib/src/clixon_xsl.c deleted file mode 100644 index 86ab22e8..00000000 --- a/lib/src/clixon_xsl.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* - * - ***** BEGIN LICENSE BLOCK ***** - - Copyright (C) 2009-2018 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 ***** - - * Limited XML XPATH and XSLT functions. - * NOTE: there is a main function at the end of this file where you can test out - * different xpath expressions. - * Look at the end of the file for a test unit program - -The code is implemented according to XPATH 1.0: - https://www.w3.org/TR/xpath-10/ - -The primary syntactic construct in XPath is the expression. An expression matches -the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr) - */ -#ifdef HAVE_CONFIG_H -#include "clixon_config.h" /* generated by config & autoconf */ -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* cligen */ -#include - -/* clicon */ -#include "clixon_err.h" -#include "clixon_log.h" -#include "clixon_string.h" -#include "clixon_queue.h" -#include "clixon_hash.h" -#include "clixon_handle.h" -#include "clixon_yang.h" -#include "clixon_xml.h" -#include "clixon_xpath_ctx.h" -#include "clixon_xpath.h" -#include "clixon_xsl.h" - - -/* Constants */ -#define XPATH_VEC_START 128 - -/* - * Types - */ - -struct searchvec{ - cxobj **sv_v0; /* here is result */ - int sv_v0len; - cxobj **sv_v1; /* this is tmp storage */ - int sv_v1len; - int sv_max; -}; -typedef struct searchvec searchvec; - -/* Local types - */ - -struct xpath_predicate{ - struct xpath_predicate *xp_next; - char *xp_expr; -}; - -/* XPATH Axis according to https://www.w3.org/TR/xpath-10/#NT-Step - * Axis ::= AxisSpecifier NodeTest Predicate* - * Eg "child:: - */ -struct xpath_element{ - struct xpath_element *xe_next; - enum axis_type xe_type; - char *xe_prefix; /* eg for namespaces */ - char *xe_str; /* eg for child */ - struct xpath_predicate *xe_predicate; /* eg within [] */ -}; - -/* Mapping between axis type string <--> int */ -static const map_str2int axismap[] = { - {"self", A_SELF}, - {"child", A_CHILD}, - {"parent", A_PARENT}, - {"root", A_ROOT}, - {"ancestor", A_ANCESTOR}, - {"descendant-or-self", A_DESCENDANT_OR_SELF}, - {NULL, -1} -}; - -static int xpath_split(char *xpathstr, char **pathexpr); - -/*! Print xpath structure for debug */ -static int -xpath_print(FILE *f, - struct xpath_element *xplist) -{ - struct xpath_element *xe; - struct xpath_predicate *xp; - - for (xe=xplist; xe; xe=xe->xe_next){ - fprintf(f, "\t:%s %s ", clicon_int2str(axismap, xe->xe_type), - xe->xe_str?xe->xe_str:""); - for (xp=xe->xe_predicate; xp; xp=xp->xp_next) - fprintf(f, "[%s]", xp->xp_expr); - } - return 0; -} - -/*! Extract PredicateExpr (Expr) from a Predicate within [] - * @see xpath_expr For evaluation of predicate - */ -static int -xpath_parse_predicate(struct xpath_element *xe, - char *pred) -{ - int retval = -1; - struct xpath_predicate *xp; - char *s; - int i; - int len; - - len = strlen(pred); - for (i=len-1; i>=0; i--){ /* -1 since we search for ][ */ - s = &pred[i]; - if (i==0 || - (*(s)==']' && *(s+1)=='[')){ - if (i) { - *(s)= '\0'; - s += 2; - } - if ((xp = malloc(sizeof(*xp))) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - memset(xp, 0, sizeof(*xp)); - if ((xp->xp_expr = strdup(s)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - xp->xp_next = xe->xe_predicate; - xe->xe_predicate = xp; - } - } - retval = 0; - done: - return retval; -} - -/*! XPATH parse, create new child element - * @param[in] atype Axis type, see https://www.w3.org/TR/xpath-10/#axes - * @param[in] str - * @param[out] xpnext - */ -static int -xpath_element_new(enum axis_type atype, - char *str, - struct xpath_element ***xpnext) -{ - int retval = -1; - struct xpath_element *xe; - char *str1 = NULL; - char *pred; - char *local; - - if ((xe = malloc(sizeof(*xe))) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - memset(xe, 0, sizeof(*xe)); - xe->xe_type = atype; - if (str){ - if ((str1 = strdup(str)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - if (xpath_split(str1, &pred) < 0) /* Can be more predicates */ - goto done; - if (strlen(str1)){ - /* Split into prefix and localname */ - if ((local = index(str1, ':')) != NULL){ - *local = '\0'; - local++; - if ((xe->xe_prefix = strdup(str1)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - } - else - local = str1; - if ((xe->xe_str = strdup(local)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - } - else{ - if ((xe->xe_str = strdup("*")) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - } - if (pred && strlen(pred)){ - if (xpath_parse_predicate(xe, pred) < 0) - goto done; - } - } - (**xpnext) = xe; - *xpnext = &xe->xe_next; - retval = 0; - done: - if (str1) - free(str1); - return retval; -} - -static int -xpath_element_free(struct xpath_element *xe) -{ - struct xpath_predicate *xp; - - if (xe->xe_str) - free(xe->xe_str); - if (xe->xe_prefix) - free(xe->xe_prefix); - while ((xp = xe->xe_predicate) != NULL){ - xe->xe_predicate = xp->xp_next; - if (xp->xp_expr) - free(xp->xp_expr); - free(xp); - } - free(xe); - return 0; -} - -static int -xpath_free(struct xpath_element *xplist) -{ - struct xpath_element *xe, *xe_next; - - for (xe=xplist; xe; xe=xe_next){ - xe_next = xe->xe_next; - xpath_element_free(xe); - } - return 0; -} - -/*! Parse xpath to xpath_element structure - - * - * [1] LocationPath ::= RelativeLocationPath - * | AbsoluteLocationPath - * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? - * | AbbreviatedAbsoluteLocationPath - * [3] RelativeLocationPath ::= Step - | RelativeLocationPath '/' Step - | AbbreviatedRelativeLocationPath - * @see https://www.w3.org/TR/xpath-10/#NT-LocationPath - */ -static int -xpath_parse(char *xpath, - struct xpath_element **xplist0) -{ - int retval = -1; - int nvec = 0; - char *s; - char *s0; - int i; - struct xpath_element *xplist = NULL; - struct xpath_element **xpnext = &xplist; - int esc = 0; - - if ((s0 = strdup(xpath)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - s = s0; - if (strlen(s)) - nvec = 1; - /* Chop up LocationPath in Steps delimited by '/' (unless [] predicate) - * Eg, "/a/b[/c]/d" -> "a" "b[/c]" "d" - */ - esc = 0; - while (*s != '\0'){ - switch (*s){ - case '/': - if (esc) - break; - nvec++; - *s = '\0'; - break; - case '[': - esc++; - break; - case ']': - esc--; - break; - default: - break; - } - s++; - } - /* Iterate through steps (s), see https://www.w3.org/TR/xpath-10/#NT-Step */ - s = s0; - for (i=0; i= - * - - * - = # RelationalExpr '=' RelationalExpr - * - =current() XXX - * @see https://www.w3.org/TR/xpath/#predicates - */ -static int -xpath_expr(cxobj *xcur, - char *predicate_expression, - uint16_t flags, - cxobj ***vec0, - size_t *vec0len) -{ - char *e_a; - char *e_v; - int i; - int j; - int retval = -1; - cxobj *x; - cxobj *xv; - cxobj **vec = NULL; - size_t veclen = 0; - int oplen; - char *tag; - char *val; - char *e0; - char *e; - char *name; - - if ((e0 = strdup(predicate_expression)) == NULL){ - clicon_err(OE_UNIX, errno, "strdup"); - goto done; - } - e = e0; - if (*e == '@'){ /* @ attribute */ - e++; - e_v=e; - e_a = strsep(&e_v, "="); - if (e_a == NULL){ - clicon_err(OE_XML, errno, "malformed expression: [@%s]", e); - goto done; - } - for (i=0; i<*vec0len; i++){ - xv = (*vec0)[i]; - if ((x = xml_find(xv, e_a)) != NULL && - (xml_type(x) == CX_ATTR)){ - if (!e_v || strcmp(xml_value(x), e_v) == 0){ - clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags)); - if (flags==0x0 || xml_flag(xv, flags)){ - if (cxvec_append(xv, &vec, &veclen) < 0) - goto done; - break; /* xv added */ - } - } - } - } - } - else{ /* either or , where ='=' for now */ - oplen = strcspn(e, "="); - if (strlen(e+oplen)==0){ /* no operator */ - if (sscanf(e, "%d", &i) == 1){ /* number */ - if (i < *vec0len){ - xv = (*vec0)[i]; /* XXX: cant compress: gcc breaks */ - clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags)); - if (flags==0x0 || xml_flag(xv, flags)) - if (cxvec_append(xv, &vec, &veclen) < 0) - goto done; - } - } - else{ - clicon_err(OE_XML, errno, "malformed expression: [%s]", e); - goto done; - } - } - else{ /* name = expr */ - if ((tag = strsep(&e, "=")) == NULL){ - clicon_err(OE_XML, errno, "malformed expression: [%s]", e); - goto done; - } - /* Strip trailing spaces */ - while (tag[strlen(tag)-1] == ' ') - tag[strlen(tag)-1] = '\0'; - /* Strip heading spaces */ - while (e[0]==' ') - e++; - if (strncmp(e, "current()", strlen("current()")) == 0){ - /* name = current()xpath */ - cxobj **svec0 = NULL; - size_t svec0len = 0; - cxobj **svec1 = NULL; - size_t svec1len = 0; - char *ebody; - - e += strlen("current("); /* e is path expression */ - *e = '.'; - if ((svec0 = calloc(1, sizeof(cxobj *))) == NULL){ - clicon_err(OE_UNIX, errno, "calloc"); - goto done; - } - svec0[0] = xcur; - svec0len++; - /* Recursive invocation */ - if (xpath_exec(xcur, e, svec0, svec0len, - flags, &svec1, &svec1len) < 0) - goto done; - for (j=0; jxe_type), xe->xe_str?xe->xe_str:""); -#endif - switch (xe->xe_type){ - case A_SELF: - break; - case A_PARENT: - j = 0; - for (i=0; ixe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0) - goto done; - } - } - else{ - for (i=0; ixe_str, name, 0) == 0) { - clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(x, flags)); - if (flags==0x0 || xml_flag(x, flags)) - if (cxvec_append(x, &vec1, &vec1len) < 0) - goto done; - } - } - } - } - free(vec0); - vec0 = vec1; - vec0len = vec1len; - break; - case A_DESCENDANT_OR_SELF: - /* Instead of collecting all descendants (which we could) - just set a flag and treat that in the next operation */ - descendants++; - break; - default: - break; - } - /* remove duplicates - * This is cycle-heavy and I dont know when it is needed? - */ - if (0) - for (i=0; ixe_predicate; xp; xp = xp->xp_next){ - if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0) - goto done; - } - - if (xpath_find(xcur, xe->xe_next, descendants, - vec0, vec0len, flags, - vec2, vec2len) < 0) - goto done; - retval = 0; - done: - return retval; -} - -/*! Transform eg "a/b[kalle]" -> "a/b" e="kalle" - * @param[in,out] xpathstr Eg "a/b[kalle]" -> "a/b" - * @param[out] pathexpr Eg "kalle" - * Which also means: - * "a/b[foo][bar]" -> pathexpr: "foo][bar" - * @note destructively modify xpathstr, no new strings allocated - */ -static int -xpath_split(char *xpathstr, - char **pathexpr) -{ - int retval = -1; - int last; - char *pe = NULL; - - if (strlen(xpathstr)){ - last = strlen(xpathstr) - 1; /* XXX: this could be -1.. */ - if (xpathstr[last] == ']'){ - xpathstr[last] = '\0'; - if (strlen(xpathstr)){ - if ((pe = index(xpathstr,'[')) != NULL){ - *pe = '\0'; - pe++; - } - } - if (pe==NULL){ - clicon_err(OE_XML, errno, "mismatched []: %s", xpathstr); - goto done; - } - } - } - retval = 0; - done: - *pathexpr = pe; - return retval; -} - -/*! Process single xpath expression on xml tree - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with XPATH syntax - * @param[in] vec0 vector of XML trees - * @param[in] vec0len length of XML trees - * @param[in] flags if != 0, only match xml nodes matching flags - * @param[out] vec2 Result XML node vector - * @param[out] vec2len Length of result vector. - * @see https://www.w3.org/TR/xpath-10/#NT-LocationPath - */ -static int -xpath_exec(cxobj *xcur, - char *xpath, - cxobj **vec0, - size_t vec0len, - uint16_t flags, - cxobj ***vec2, - size_t *vec2len) -{ - struct xpath_element *xplist; - cxobj **vec1; - size_t vec1len; - - if (cxvec_dup(vec0, vec0len, &vec1, &vec1len) < 0) - goto done; - if (xpath_parse(xpath, &xplist) < 0) - goto done; - if (debug > 1) - xpath_print(stderr, xplist); - if (xpath_find(xcur, xplist, 0, vec1, vec1len, flags, vec2, vec2len) < 0) - goto done; - if (xpath_free(xplist) < 0) - goto done; - done: - return 0; -} /* xpath_exec */ - - -/*! Intermediate xpath function to handle 'conditional' cases. - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with XPATH syntax - * @param[in] flags if != 0, only match xml nodes matching flags - * @param[out] vec1 vector of XML trees - * @param[out] vec1len length of XML trees - * For example: xpath = //a | //b. - * xpath_first+ splits xpath up in several subcalls - * (eg xpath=//a and xpath=//b) and collects the results. - * Note: if a match is found in both, two (or more) same results will be - * returned. - * Note, this could be 'folded' into xpath1 but I judged it too complex. - * @see https://www.w3.org/TR/xpath-10/#NT-Expr - * An 'Expr' is composed of compositions of and, or, =, +, -, down to: - * PathExpr ::= LocationPath - * | FilterExpr - * | FilterExpr '/' RelativeLocationPath - * | FilterExpr '//' RelativeLocationPath - */ -static int -xpath_choice(cxobj *xcur, - char *xpath0, - uint16_t flags, - cxobj ***vec1, - size_t *vec1len) -{ - int retval = -1; - char *s0 = NULL; - char *s1; - char *s2; - char *xpath; - cxobj **vec0 = NULL; - size_t vec0len = 0; - - if ((s0 = strdup(xpath0)) == NULL){ - clicon_err(OE_XML, errno, "strdup"); - goto done; - } - s2 = s1 = s0; - if ((vec0 = calloc(1, sizeof(cxobj *))) == NULL){ - clicon_err(OE_UNIX, errno, "calloc"); - goto done; - } - vec0[0] = xcur; - vec0len++; - while (s1 != NULL){ - s2 = strstr(s1, " | "); - if (s2 != NULL){ - *s2 = '\0'; /* terminate xpath */ - s2 += 3; - } - xpath = s1; - s1 = s2; - if (xpath_exec(xcur, xpath, vec0, vec0len, flags, vec1, vec1len) < 0) - goto done; - } - retval = 0; - done: - if (s0) - free(s0); - if (vec0) - free(vec0); - return retval; -} - -/*! Xpath nodeset function where only the first matching entry is returned - * args: - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with XPATH syntax - * @retval 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 fter use. - * @note return value does not see difference between error and not found - * @see xpath_first. This is obsolete and only enabled with COMPAT_XSL - */ -cxobj * -xpath_first_xsl(cxobj *xcur, - char *xpath) -{ - cxobj **vec1 = NULL; - size_t vec1len = 0; - cxobj *xn = NULL; - - if (xpath_choice(xcur, xpath, 0, &vec1, &vec1len) < 0) - goto done; - if (vec1len) - xn = vec1[0]; - else - xn = NULL; - done: - if (vec1) - free(vec1); - return xn; -} - -#ifdef COMPAT_XSL -/*! A restricted xpath iterator that loops over all matching entries. Dont use. - * - * See xpath1() on details for subset. - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with XPATH syntax - * @param[in] xprev iterator/result should be initiated to NULL - * @retval xml-tree of n:th match, or NULL on error. - * - * @code - * cxobj *x = NULL; - * while ((x = xpath_each(xcur, "//symbol/foo", x)) != NULL) { - * ... - * } - * @endcode - * - * @note The returned pointer points into the original tree so should not be freed - * after use. - * @note obsolete. Dont use - */ -cxobj * -xpath_each(cxobj *xcur, - char *xpath, - cxobj *xprev) -{ - static cxobj **vec1 = NULL; /* XXX */ - static size_t vec1len = 0; - cxobj *xn = NULL; - int i; - - if (xprev == NULL){ - if (vec1) { - free(vec1); - vec1 = NULL; - } - vec1len = 0; - if (xpath_choice(xcur, xpath, 0, &vec1, &vec1len) < 0) - goto done; - } - if (vec1len){ - if (xprev==NULL) - xn = vec1[0]; - else{ - for (i=0; i=vec1len-1) - xn = NULL; - else - xn = vec1[i+1]; - } - } - else - xn = NULL; - done: - return xn; -} -#endif - -/*! A restricted xpath that returns a vector of matches - * - * See xpath1() on details for subset - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with 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 **xvec = NULL; - * size_t xlen; - * if (xpath_vec(xcur, "//symbol/foo", &xvec, &xlen) < 0) - * goto err; - * for (i=0; ieth/0/0ex:ethnone ]]>]]>' "^]]>]]>$" # Too many quotes, (single inside double inside single) need to fool bash -if [ -z "$COMPAT_XSL" ]; then cat < $tmp # new ]]>]]> EOF -else # old -cat < $tmp -]]>]]> -EOF -fi + new "Check eth/0/0 added using xpath" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth/0/0ex:ethtrue]]>]]>$" @@ -122,29 +117,17 @@ new "netconf edit config" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "eth/0/0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" # Too many quotes -if [ -z "$COMPAT_XSL" ]; then cat < $tmp # new ]]>]]> EOF -else -cat < $tmp # old -]]>]]> -EOF -fi new "netconf get config xpath" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth1true]]>]]>$" # Too many quotes -if [ -z "$COMPAT_XSL" ]; then cat < $tmp # new ]]>]]> EOF -else -cat < $tmp # old -]]>]]> -EOF -fi new "netconf get config xpath parent" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth/0/0trueeth1truetruefalse
9.2.3.424
]]>]]>$" diff --git a/test/test_order.sh b/test/test_order.sh index 848e839a..5d292c1f 100755 --- a/test/test_order.sh +++ b/test/test_order.sh @@ -121,8 +121,6 @@ fi new "verify running from start, should be: l,c,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if XML_SORT set to false" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhoppdbcaabcddbarabarcbarbbarabarbbarcbardbar]]>]]>$" -if [ -z "$COMPAT_XSL" ]; then #new - new "get each ordered-by user leaf-list" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" @@ -135,22 +133,6 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" -else # old - -new "get each ordered-by user leaf-list" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" - -new "get each ordered-by user leaf-list" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" - -new "get each ordered-by user leaf-list" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" - -new "get each ordered-by user leaf-list" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" - -fi - new "delete candidate" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" diff --git a/test/test_yang.sh b/test/test_yang.sh index 7ebbbf12..3b59cfa7 100755 --- a/test/test_yang.sh +++ b/test/test_yang.sh @@ -136,13 +136,8 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" -if [ -z "$COMPAT_XSL" ]; then # new new "netconf get leaf-list path" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" -else # old -new "netconf get leaf-list path" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" -fi new "netconf get (should be some)" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^125one]]>]]>$" From 666d74bf1be2ec2f9ffeb1c1ed67e14ea6464460 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Tue, 24 Jul 2018 17:59:17 +0200 Subject: [PATCH 02/71] Added -l option for clixon_backend for directing syslog to stderr or stdout i\ f running in foreground --- CHANGELOG.md | 1 + apps/backend/backend_main.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9538186..77adfd5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Minor changes * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 +* Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground ### Corrected Bugs diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index db331b7e..ccc26088 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -73,7 +73,7 @@ #include "backend_handle.h" /* Command line options to be passed to getopt(3) */ -#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:g:y:x:" /* substitute s: for IRCc:r */ +#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:g:l:y:x:" /* substitute s: for IRCc:r */ /*! Terminate. Cannot use h after this */ static int @@ -140,6 +140,7 @@ usage(clicon_handle h, " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" " -c \tLoad extra xml configuration, but don't commit.\n" " -g \tClient membership required to this group (default: %s)\n" + " -l \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" " -y \tOverride yang spec file (dont include .yang suffix)\n" " -x \tXMLDB plugin\n", argv0, @@ -553,6 +554,7 @@ main(int argc, int xml_pretty; char *xml_format; char *nacm_mode; + int logdst = CLICON_LOG_SYSLOG; /* In the startup, logs to stderr & syslog and debug flag set later */ clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG); @@ -589,6 +591,21 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg); break; + case 'l': /* Log destination: s|e|o */ + switch (optarg[0]){ + case 's': + logdst = CLICON_LOG_SYSLOG; + break; + case 'e': + logdst = CLICON_LOG_STDERR; + break; + case 'o': + logdst = CLICON_LOG_STDOUT; + break; + default: + usage(h, argv[0]); + } + break; } /* * Here we have the debug flag settings, use that. @@ -597,7 +614,7 @@ main(int argc, * XXX: if started in a start-daemon script, there will be irritating * double syslogs until fork below. */ - clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG); + clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); /* Find and read configfile */ @@ -668,6 +685,8 @@ main(int argc, clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg); break; } + case 'l' : + break; default: usage(h, argv[0]); break; @@ -676,6 +695,8 @@ main(int argc, argc -= optind; argv += optind; + clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); + /* Defer: Wait to the last minute to print help message */ if (help) usage(h, argv[0]); From b7eb89962d26437f0f3319aeed73e80eea9df5be Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Tue, 24 Jul 2018 18:57:10 +0000 Subject: [PATCH 03/71] clixon-sock not mandatory since family may be inet --- yang/clixon-config@2018-04-30.yang | 1 - 1 file changed, 1 deletion(-) diff --git a/yang/clixon-config@2018-04-30.yang b/yang/clixon-config@2018-04-30.yang index c629a3c7..164d108b 100644 --- a/yang/clixon-config@2018-04-30.yang +++ b/yang/clixon-config@2018-04-30.yang @@ -248,7 +248,6 @@ module clixon-config { } leaf CLICON_SOCK { type string; - mandatory true; description "If family above is AF_UNIX: Unix socket for communicating with clixon_backend. If family is AF_INET: IPv4 address"; From c6a62b96dee11e236a39c777a8ea2752485b0d84 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 24 Jul 2018 22:27:52 +0200 Subject: [PATCH 04/71] sock ipv4 --- apps/backend/backend_socket.c | 8 +++++--- lib/src/clixon_xml_db.c | 9 ++++----- yang/clixon-config@2018-04-30.yang | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/backend/backend_socket.c b/apps/backend/backend_socket.c index a2587044..ec32fb53 100644 --- a/apps/backend/backend_socket.c +++ b/apps/backend/backend_socket.c @@ -74,7 +74,8 @@ #include "backend_handle.h" static int -config_socket_init_ipv4(clicon_handle h, char *dst) +config_socket_init_ipv4(clicon_handle h, + char *dst) { int s; struct sockaddr_in addr; @@ -116,7 +117,8 @@ config_socket_init_ipv4(clicon_handle h, char *dst) * and group according to CLICON_SOCK_GROUP option. */ static int -config_socket_init_unix(clicon_handle h, char *sock) +config_socket_init_unix(clicon_handle h, + char *sock) { int s; struct sockaddr_un addr; @@ -197,7 +199,7 @@ backend_socket_init(clicon_handle h) */ int backend_accept_client(int fd, - void *arg) + void *arg) { int retval = -1; clicon_handle h = (clicon_handle)arg; diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index b909385b..e29c7c30 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -143,10 +143,8 @@ xmldb_plugin_unload(clicon_handle h) xmldb_handle xh; char *error; - if ((handle = clicon_xmldb_plugin_get(h)) == NULL){ - clicon_err(OE_PLUGIN, errno, "No plugin handle"); - goto done; - } + if ((handle = clicon_xmldb_plugin_get(h)) == NULL) + goto ok; /* OK, may not have been initialized */ /* If connected storage handle then disconnect */ if ((xh = clicon_xmldb_handle_get(h)) != NULL) xmldb_disconnect(h); /* sets xmldb handle to NULL */ @@ -165,8 +163,9 @@ xmldb_plugin_unload(clicon_handle h) clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error"); /* Just report no -1 return*/ } + ok: retval = 0; - done: + // done: return retval; } diff --git a/yang/clixon-config@2018-04-30.yang b/yang/clixon-config@2018-04-30.yang index 164d108b..c629a3c7 100644 --- a/yang/clixon-config@2018-04-30.yang +++ b/yang/clixon-config@2018-04-30.yang @@ -248,6 +248,7 @@ module clixon-config { } leaf CLICON_SOCK { type string; + mandatory true; description "If family above is AF_UNIX: Unix socket for communicating with clixon_backend. If family is AF_INET: IPv4 address"; From 539a60d613c25dfe89b40143a6cb1acc5607d1b1 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Wed, 25 Jul 2018 11:40:06 +0200 Subject: [PATCH 05/71] backend socket options -a -u --- apps/cli/cli_main.c | 12 +++++++----- apps/netconf/netconf_main.c | 12 +++++++++++- apps/restconf/restconf_main.c | 14 ++++++++++++-- doc/FAQ.md | 2 +- lib/src/clixon_plugin.c | 2 +- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index bd10b8f8..e9cdc424 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -71,7 +71,7 @@ #include "cli_handle.h" /* Command line options to be passed to getopt(3) */ -#define CLI_OPTS "hD:f:xl:F:1u:d:m:qpGLy:c:U:" +#define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qpGLy:c:U:" /*! terminate cli application */ static int @@ -197,7 +197,6 @@ static void usage(clicon_handle h, char *argv0) { - char *confsock = clicon_sock(h); char *plgdir = clicon_cli_dir(h); fprintf(stderr, "usage:%s [options] [commands]\n" @@ -209,7 +208,8 @@ usage(clicon_handle h, "\t-x\t\tDump configuration file as XML on stdout (migration utility)\n" "\t-F \tRead commands from file (default stdin)\n" "\t-1\t\tDo not enter interactive mode\n" - "\t-u \tconfig UNIX domain path (default: %s)\n" + "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" + "\t-u \tInternal socket domain path or IP addr (see -a)\n" "\t-d \tSpecify plugin directory (default: %s)\n" "\t-m \tSpecify plugin syntax mode\n" "\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n" @@ -221,7 +221,6 @@ usage(clicon_handle h, "\t-c \tSpecify cli spec file.\n" "\t-U \tOver-ride unix user with a pseudo user for NACM.\n", argv0, - confsock ? confsock : "none", plgdir ? plgdir : "none" ); exit(1); @@ -354,7 +353,10 @@ main(int argc, char **argv) case '1' : /* Quit after reading database once - dont wait for events */ once = 1; break; - case 'u': /* config unix domain path/ ip host */ + case 'a': /* internal backend socket address family */ + clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); + break; + case 'u': /* internal backend socket unix domain path or ip host */ if (!strlen(optarg)) usage(h, argv[0]); clicon_option_str_set(h, "CLICON_SOCK", optarg); diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 9811d959..1c203fff 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -71,7 +71,7 @@ #include "netconf_rpc.h" /* Command line options to be passed to getopt(3) */ -#define NETCONF_OPTS "hDqf:d:Sy:U:" +#define NETCONF_OPTS "hDqf:a:u:d:Sy:U:" /*! Process incoming packet * @param[in] h Clicon handle @@ -296,6 +296,8 @@ usage(clicon_handle h, "\t-D\t\tDebug\n" "\t-q\t\tQuiet: dont send hello prompt\n" "\t-f \tConfiguration file (mandatory)\n" + "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" + "\t-u \tInternal socket domain path or IP addr (see -a)\n" "\t-d \tSpecify netconf plugin directory dir (default: %s)\n" "\t-S\t\tLog on syslog\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n" @@ -374,6 +376,14 @@ main(int argc, case 'f': /* config file */ case 'S': /* Log on syslog */ break; /* see above */ + case 'a': /* internal backend socket address family */ + clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); + break; + case 'u': /* internal backend socket unix domain path or ip host */ + if (!strlen(optarg)) + usage(h, argv[0]); + clicon_option_str_set(h, "CLICON_SOCK", optarg); + break; case 'q': /* quiet: dont write hello */ quiet++; break; diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 7ffc9260..e43f6c96 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -74,7 +74,7 @@ #include "restconf_methods.h" /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hDf:p:y:" +#define RESTCONF_OPTS "hDf:p:y:a:u:" /* RESTCONF enables deployments to specify where the RESTCONF API is located. The client discovers this by getting the "/.well-known/host-meta" @@ -488,7 +488,9 @@ usage(clicon_handle h, "\t-D \t\tDebug. Log to syslog\n" "\t-f \tConfiguration file (mandatory)\n" "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" - "\t-y \tOverride yang spec file (dont include .yang suffix)\n", + "\t-y \tOverride yang spec file (dont include .yang suffix)\n" + "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" + "\t-u \tInternal socket domain path or IP addr (see -a)\n", argv0, clicon_restconf_dir(h) ); @@ -541,6 +543,14 @@ main(int argc, case 'y' : /* yang module */ yangspec = optarg; break; + case 'a': /* internal backend socket address family */ + clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); + break; + case 'u': /* internal backend socket unix domain path or ip host */ + if (!strlen(optarg)) + usage(h, argv[0]); + clicon_option_str_set(h, "CLICON_SOCK", optarg); + break; default: usage(h, argv[0]); break; diff --git a/doc/FAQ.md b/doc/FAQ.md index c1d130d0..64ba9f3c 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -43,7 +43,7 @@ The example: ## Do I need to setup anything? (IMPORTANT) -The config demon requires a valid group to create a server UNIX socket. +The config demon requires a valid group to create a server UNIX domain socket. Define a valid CLICON_SOCK_GROUP in the config file or via the -g option or create the group and add the user to it. The default group is 'clicon'. Add yourself and www-data, if you intend to use restconf. diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 2631938c..5e17cd1e 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -189,7 +189,7 @@ plugin_load_one(clicon_handle h, char *name; char *p; - clicon_debug(1, "%s", __FUNCTION__); + clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function); dlerror(); /* Clear any existing error */ if ((handle = dlopen(file, dlflags)) == NULL) { error = (char*)dlerror(); From 968435ec5eff509aec4bbc27e33977c2ed0d5227 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Wed, 25 Jul 2018 12:45:00 +0200 Subject: [PATCH 06/71] internal backend socket family --- apps/backend/backend_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index ccc26088..7a273294 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -73,7 +73,7 @@ #include "backend_handle.h" /* Command line options to be passed to getopt(3) */ -#define BACKEND_OPTS "hD:f:d:b:Fzu:P:1s:c:g:l:y:x:" /* substitute s: for IRCc:r */ +#define BACKEND_OPTS "hD:f:d:b:Fzu:a:P:1s:c:g:l:y:x:" /* substitute s: for IRCc:r */ /*! Terminate. Cannot use h after this */ static int @@ -135,7 +135,8 @@ usage(clicon_handle h, " -z\t\tKill other config daemon and exit\n" " -F\t\tRun in foreground, do not run as daemon\n" " -1\t\tRun once and then quit (dont wait for events)\n" - " -u \tConfig UNIX domain path / ip address (default: %s)\n" + " -a UNIX|IPv4|IPv6\tInternal backend socket family\n" + " -u \tInternal socket domain path or IP addr (see -a)(default: %s)\n" " -P \tPid filename (default: %s)\n" " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" " -c \tLoad extra xml configuration, but don't commit.\n" @@ -656,6 +657,9 @@ main(int argc, case 'z': /* Zap other process */ zap++; break; + case 'a': /* internal backend socket address family */ + clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); + break; case 'u': /* config unix domain path / ip address */ if (!strlen(optarg)) usage(h, argv[0]); From 156660419e8bb1e9d08b645332310e8e4a87b773 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Thu, 26 Jul 2018 12:54:14 +0200 Subject: [PATCH 07/71] * Set dir /www-data with www-data as owner, see https://github.com/clicon/clixo\ n/issues/37 --- CHANGELOG.md | 3 ++- apps/restconf/Makefile.in | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77adfd5a..23ad263a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground ### Corrected Bugs - +* Setting /www-data with www-data as owner, see https://github.com/clicon/clixon/issues/37 + ### Known issues * Namespace name relabeling is not supported. * Eg: if "des" is defined as prefix for an imported module, then a relabeling using xmlfns is not supported, such as: diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index d54f1255..431d64cb 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -45,12 +45,14 @@ bindir = @bindir@ libdir = @libdir@ mandir = @mandir@ libexecdir = @libexecdir@ -wwwdir = /www-data localstatedir = @localstatedir@ sysconfdir = @sysconfdir@ includedir = @includedir@ HOST_VENDOR = @host_vendor@ +wwwdir = /www-data +wwwuser = www-data + SH_SUFFIX = @SH_SUFFIX@ CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@ CLIXON_MINOR = @CLIXON_VERSION_MINOR@ @@ -97,8 +99,9 @@ distclean: clean # Put other executables in libexec/ # Also create a libexec/ directory for writeable/temporary files. # Put config file in etc/ +# Shouldnt www-dir be owned by www-data? install: install-lib $(APPL) - install -d -m 0755 $(DESTDIR)$(wwwdir) + install -d -m 0755 -o $(wwwuser) -g $(wwwuser) $(DESTDIR)$(wwwdir) install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(wwwdir) install-lib: $(MYLIB) From 5164db36033de71834ceee4e7f9eb1a74afd64df Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Thu, 26 Jul 2018 20:13:02 +0200 Subject: [PATCH 08/71] Added clicon_log_init(.., CLICON_LOG_FILE) option and clicon_log_file() for c\ ases where neither syslog or stderr is useful. --- CHANGELOG.md | 3 ++- apps/backend/backend_main.c | 1 + apps/cli/cli_main.c | 1 + apps/netconf/netconf_main.c | 1 + apps/restconf/Makefile.in | 4 ++-- apps/restconf/restconf_main.c | 29 ++++++++++++++++++++----- configure | 20 ++++++----------- configure.ac | 2 ++ lib/clixon/clixon_log.h | 4 +++- lib/src/clixon_log.c | 41 +++++++++++++++++++++++++++-------- 10 files changed, 75 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23ad263a..45ba4a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ ### API changes on existing features (you may need to change your code) ### Minor changes +* Added clicon_log_init(.., CLICON_LOG_FILE) option and clicon_log_file() for cases where neither syslog or stderr is useful. * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground ### Corrected Bugs -* Setting /www-data with www-data as owner, see https://github.com/clicon/clixon/issues/37 +* Set dir /www-data with www-data as owner, see https://github.com/clicon/clixon/issues/37 ### Known issues * Namespace name relabeling is not supported. diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 7a273294..0785adf5 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -98,6 +98,7 @@ backend_terminate(clicon_handle h) event_exit(); clicon_log_register_callback(NULL, NULL); clicon_debug(1, "%s done", __FUNCTION__); + clicon_log_exit(); return 0; } diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index e9cdc424..e2e2bb8f 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -84,6 +84,7 @@ cli_terminate(clicon_handle h) yspec_free(yspec); cli_plugin_finish(h); cli_handle_exit(h); + clicon_log_exit(); return 0; } diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 1c203fff..543f015e 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -278,6 +278,7 @@ netconf_terminate(clicon_handle h) yspec_free(yspec); event_exit(); clicon_handle_exit(h); + clicon_log_exit(); return 0; } diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index 431d64cb..79a47104 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -50,8 +50,8 @@ sysconfdir = @sysconfdir@ includedir = @includedir@ HOST_VENDOR = @host_vendor@ -wwwdir = /www-data -wwwuser = www-data +wwwdir = @wwwdir@ +wwwuser = @wwwuser@ SH_SUFFIX = @SH_SUFFIX@ CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@ diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index e43f6c96..b4390016 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -74,7 +74,7 @@ #include "restconf_methods.h" /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hDf:p:y:a:u:" +#define RESTCONF_OPTS "hDf:p:y:a:u:l:" /* RESTCONF enables deployments to specify where the RESTCONF API is located. The client discovers this by getting the "/.well-known/host-meta" @@ -85,6 +85,8 @@ #define RESTCONF_API "restconf" #define RESTCONF_API_ROOT "/restconf" +#define RESTCONF_LOGFILE "/www-data/clixon_restconf.log" + /*! Generic REST method, GET, PUT, DELETE, etc * @param[in] h CLIXON handle * @param[in] r Fastcgi request handle @@ -449,6 +451,7 @@ restconf_terminate(clicon_handle h) if ((yspec = clicon_dbspec_yang(h)) != NULL) yspec_free(yspec); clicon_handle_exit(h); + clicon_log_exit(); return 0; } @@ -490,7 +493,8 @@ usage(clicon_handle h, "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" - "\t-u \tInternal socket domain path or IP addr (see -a)\n", + "\t-u \tInternal socket domain path or IP addr (see -a)\n" + "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n", argv0, clicon_restconf_dir(h) ); @@ -515,9 +519,10 @@ main(int argc, char *yangspec=NULL; char *dir; char *tmp; + int logdst = CLICON_LOG_SYSLOG; /* In the startup, logs to stderr & debug flag set later */ - clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_SYSLOG); + clicon_log_init(__PROGRAM__, LOG_INFO, logdst); /* Create handle */ if ((h = clicon_handle_init()) == NULL) goto done; @@ -551,14 +556,28 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_SOCK", optarg); break; + case 'l': /* Log destination: s|e|o */ + switch (optarg[0]){ + case 's': + logdst = CLICON_LOG_SYSLOG; + break; + case 'f': + logdst = CLICON_LOG_FILE; + if (clicon_log_file(RESTCONF_LOGFILE) < 0) + goto done; + break; + default: + usage(h, argv[0]); + } + break; default: usage(h, argv[0]); break; - } + } /* switch getopt */ argc -= optind; argv += optind; - clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, CLICON_LOG_SYSLOG); + clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid()); if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){ diff --git a/configure b/configure index 3eaead6b..c7d2bd1c 100755 --- a/configure +++ b/configure @@ -633,6 +633,8 @@ CPP OBJEXT EXEEXT ac_ct_CC +wwwuser +wwwdir with_restconf RANLIB SH_SUFFIX @@ -683,7 +685,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -760,7 +761,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' @@ -1013,15 +1013,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1159,7 +1150,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1312,7 +1303,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -2449,6 +2439,10 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # If yes, compile apps/restconf +wwwdir=/www-data + +wwwuser=www-data + # ac_ext=c ac_cpp='$CPP $CPPFLAGS' diff --git a/configure.ac b/configure.ac index 03943911..7161ff62 100644 --- a/configure.ac +++ b/configure.ac @@ -89,6 +89,8 @@ AC_SUBST(LIBS) AC_SUBST(SH_SUFFIX) AC_SUBST(RANLIB) AC_SUBST(with_restconf) # If yes, compile apps/restconf +AC_SUBST(wwwdir,/www-data) +AC_SUBST(wwwuser,www-data) # AC_PROG_CC() AC_PROG_CPP diff --git a/lib/clixon/clixon_log.h b/lib/clixon/clixon_log.h index 7b833427..026d9ba4 100644 --- a/lib/clixon/clixon_log.h +++ b/lib/clixon/clixon_log.h @@ -44,6 +44,7 @@ #define CLICON_LOG_SYSLOG 1 /* print logs on syslog */ #define CLICON_LOG_STDERR 2 /* print logs on stderr */ #define CLICON_LOG_STDOUT 4 /* print logs on stdout */ +#define CLICON_LOG_FILE 8 /* print logs on clicon_log_filename */ /* * Types @@ -55,11 +56,12 @@ typedef int (clicon_log_notify_t)(int level, char *msg, void *arg); */ extern int debug; - /* * Prototypes */ int clicon_log_init(char *ident, int upto, int flags); +int clicon_log_exit(void); +int clicon_log_file(char *filename); int clicon_get_logflags(void); int clicon_log_str(int level, char *msg); #if defined(__GNUC__) && __GNUC__ >= 3 diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 21d24bcc..7b3d2b75 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -66,8 +66,8 @@ static int _logflags = 0x0; static clicon_log_notify_t *_log_notify_cb = NULL; static void *_log_notify_arg = NULL; -/* Set to open file to bypass logging and write debug messages directly to file */ -static FILE *_debugfile = NULL; +/* Set to open file to write debug messages directly to file */ +static FILE *_logfile = NULL; /*! Initialize system logger. * @@ -97,6 +97,31 @@ clicon_log_init(char *ident, return 0; } +int +clicon_log_exit(void) +{ + if (_logfile) + fclose(_logfile); + return 0; +} + +/* If log flags include CLICON_LOG_FILE, set the file + * @param[in] filename File to log to + * @retval 0 OK + * @retval -1 Error + */ +int +clicon_log_file(char *filename) +{ + if (_logfile) + fclose(_logfile); + if ((_logfile = fopen(filename, "a")) == NULL){ + fprintf(stderr, "fopen: %s\n", strerror(errno)); /* dont use clicon_err here due to recursion */ + return -1; + } + return 0; +} + int clicon_get_logflags(void) { @@ -183,6 +208,10 @@ clicon_log_str(int level, flogtime(stdout); fprintf(stdout, "%s\n", msg); } + if ((_logflags & CLICON_LOG_FILE) && _logfile){ + flogtime(_logfile); + fprintf(_logfile, "%s\n", msg); + } if (_log_notify_cb){ static int cb = 0; char *d, *msg2; @@ -326,13 +355,7 @@ clicon_debug(int dbglevel, goto done; } va_end(args); - if (_debugfile != NULL){ /* Bypass syslog altogether */ - /* XXX: Here use date sub-routine as found in err_print1 */ - flogtime(_debugfile); - fprintf(_debugfile, "%s\n", msg); - } - else - clicon_log_str(LOG_DEBUG, msg); + clicon_log_str(LOG_DEBUG, msg); retval = 0; done: if (msg) From e48f8dd00eb8e351f595850f4d4b1321d619ff75 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Sun, 29 Jul 2018 19:41:10 +0200 Subject: [PATCH 09/71] clixon_netconf -S is obsolete. Use clixon_netconf -l s instead. * Unified log handling for all clicon applications using -l e|o|s|f. * The options stand for e:stderr, o:stdout, s: syslog, f:file --- CHANGELOG.md | 5 ++- apps/backend/backend_main.c | 25 ++++------- apps/backend/backend_plugin.c | 2 +- apps/cli/cli_main.c | 23 ++++------ apps/netconf/netconf_main.c | 30 ++++++------- apps/restconf/restconf_main.c | 85 +++++++++++++++++++---------------- lib/clixon/clixon_log.h | 1 + lib/src/clixon_log.c | 31 ++++++++++++- lib/src/clixon_xpath.c | 4 +- 9 files changed, 116 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ba4a4f..58ff9e5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,12 @@ ### Major New features ### API changes on existing features (you may need to change your code) +* clixon_netconf -S is obsolete. Use clixon_netconf -l s instead. ### Minor changes -* Added clicon_log_init(.., CLICON_LOG_FILE) option and clicon_log_file() for cases where neither syslog or stderr is useful. +* Unified log handling for all clicon applications using -l e|o|s|f. + * The options stand for e:stderr, o:stdout, s: syslog, f:file + * Added file logging (-l f)for cases where neither syslog nor stderr is useful. * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 0785adf5..76391b10 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -75,6 +75,8 @@ /* Command line options to be passed to getopt(3) */ #define BACKEND_OPTS "hD:f:d:b:Fzu:a:P:1s:c:g:l:y:x:" /* substitute s: for IRCc:r */ +#define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log" + /*! Terminate. Cannot use h after this */ static int backend_terminate(clicon_handle h) @@ -556,10 +558,10 @@ main(int argc, int xml_pretty; char *xml_format; char *nacm_mode; - int logdst = CLICON_LOG_SYSLOG; + int logdst = CLICON_LOG_SYSLOG|CLICON_LOG_STDERR; /* In the startup, logs to stderr & syslog and debug flag set later */ - clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR|CLICON_LOG_SYSLOG); + clicon_log_init(__PROGRAM__, LOG_INFO, logdst); /* Initiate CLICON handle */ if ((h = backend_handle_init()) == NULL) return -1; @@ -594,20 +596,9 @@ main(int argc, clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg); break; case 'l': /* Log destination: s|e|o */ - switch (optarg[0]){ - case 's': - logdst = CLICON_LOG_SYSLOG; - break; - case 'e': - logdst = CLICON_LOG_STDERR; - break; - case 'o': - logdst = CLICON_LOG_STDOUT; - break; - default: - usage(h, argv[0]); - } - break; + if ((logdst = clicon_log_opt(optarg[0])) < 0) + usage(h, argv[0]); + break; } /* * Here we have the debug flag settings, use that. @@ -616,6 +607,8 @@ main(int argc, * XXX: if started in a start-daemon script, there will be irritating * double syslogs until fork below. */ + if ((logdst & CLICON_LOG_FILE) && clicon_log_file(BACKEND_LOGFILE) < 0) + goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 6dd23d4d..e193b876 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -259,7 +259,7 @@ plugin_transaction_begin(clicon_handle h, clicon_log(LOG_NOTICE, "%s: Plugin '%s' transaction_begin callback does not make clicon_err call on error", __FUNCTION__, cp->cp_name); - break; + break; } } return retval; diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index e2e2bb8f..7c8e4559 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -73,6 +73,8 @@ /* Command line options to be passed to getopt(3) */ #define CLI_OPTS "hD:f:xl:F:1a:u:d:m:qpGLy:c:U:" +#define CLI_LOGFILE "/tmp/clixon_cli.log" + /*! terminate cli application */ static int cli_terminate(clicon_handle h) @@ -297,25 +299,16 @@ main(int argc, char **argv) case 'x': /* dump config file as xml (migration from .conf file)*/ dump_configfile_xml++; break; - case 'l': /* Log destination: s|e|o */ - switch (optarg[0]){ - case 's': - logdst = CLICON_LOG_SYSLOG; - break; - case 'e': - logdst = CLICON_LOG_STDERR; - break; - case 'o': - logdst = CLICON_LOG_STDOUT; - break; - default: - usage(h, argv[0]); - } - break; + case 'l': /* Log destination: s|e|o */ + if ((logdst = clicon_log_opt(optarg[0])) < 0) + usage(h, argv[0]); + break; } /* * Logs, error and debug to stderr or syslog, set debug level */ + if ((logdst & CLICON_LOG_FILE) && clicon_log_file(CLI_LOGFILE) < 0) + goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 543f015e..0942986b 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -71,7 +71,9 @@ #include "netconf_rpc.h" /* Command line options to be passed to getopt(3) */ -#define NETCONF_OPTS "hDqf:a:u:d:Sy:U:" +#define NETCONF_OPTS "hDf:l:qa:u:d:y:U:" + +#define NETCONF_LOGFILE "/tmp/clixon_netconf.log" /*! Process incoming packet * @param[in] h Clicon handle @@ -297,10 +299,11 @@ usage(clicon_handle h, "\t-D\t\tDebug\n" "\t-q\t\tQuiet: dont send hello prompt\n" "\t-f \tConfiguration file (mandatory)\n" + "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" "\t-u \tInternal socket domain path or IP addr (see -a)\n" "\t-d \tSpecify netconf plugin directory dir (default: %s)\n" - "\t-S\t\tLog on syslog\n" + "\t-y \tOverride yang spec file (dont include .yang suffix)\n" "\t-U \tOver-ride unix user with a pseudo user for NACM.\n", argv0, @@ -318,15 +321,12 @@ main(int argc, char *argv0 = argv[0]; int quiet = 0; clicon_handle h; - int use_syslog; char *dir; + int logdst = CLICON_LOG_STDERR; struct passwd *pw; - /* Defaults */ - use_syslog = 0; - /* In the startup, logs to stderr & debug flag set later */ - clicon_log_init(__PROGRAM__, LOG_INFO, CLICON_LOG_STDERR); + clicon_log_init(__PROGRAM__, LOG_INFO, logdst); /* Create handle */ if ((h = clicon_handle_init()) == NULL) return -1; @@ -352,15 +352,17 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg); break; - case 'S': /* Log on syslog */ - use_syslog = 1; + case 'l': /* Log destination: s|e|o */ + if ((logdst = clicon_log_opt(optarg[0])) < 0) + usage(h, argv[0]); break; } /* * Logs, error and debug to stderr or syslog, set debug level */ - clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, - use_syslog?CLICON_LOG_SYSLOG:CLICON_LOG_STDERR); + if ((logdst & CLICON_LOG_FILE) && clicon_log_file(NETCONF_LOGFILE) < 0) + goto done; + clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); /* Find and read configfile */ @@ -374,8 +376,8 @@ main(int argc, switch (c) { case 'h' : /* help */ case 'D' : /* debug */ - case 'f': /* config file */ - case 'S': /* Log on syslog */ + case 'f': /* config file */ + case 'l': /* log */ break; /* see above */ case 'a': /* internal backend socket address family */ clicon_option_str_set(h, "CLICON_SOCK_FAMILY", optarg); @@ -410,8 +412,6 @@ main(int argc, argc -= optind; argv += optind; - - /* Parse yang database spec file */ if (yang_spec_main(h) == NULL) goto done; diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index b4390016..66350486 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -74,7 +74,7 @@ #include "restconf_methods.h" /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hDf:p:y:a:u:l:" +#define RESTCONF_OPTS "hDf:l:p:y:a:u:" /* RESTCONF enables deployments to specify where the RESTCONF API is located. The client discovers this by getting the "/.well-known/host-meta" @@ -490,11 +490,11 @@ usage(clicon_handle h, "\t-h \t\tHelp\n" "\t-D \t\tDebug. Log to syslog\n" "\t-f \tConfiguration file (mandatory)\n" + "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n" "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" - "\t-u \tInternal socket domain path or IP addr (see -a)\n" - "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n", + "\t-u \tInternal socket domain path or IP addr (see -a)\n", argv0, clicon_restconf_dir(h) ); @@ -540,6 +540,45 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg); break; + case 'l': /* Log destination: s|e|o */ + if ((logdst = clicon_log_opt(optarg[0])) < 0) + usage(h, argv[0]); + break; + } /* switch getopt */ + argc -= optind; + argv += optind; + + /* + * Logs, error and debug to stderr or syslog, set debug level + */ + if ((logdst & CLICON_LOG_FILE) && clicon_log_file(RESTCONF_LOGFILE) < 0) + goto done; + clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); + + clicon_debug_init(debug, NULL); + clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid()); + if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){ + clicon_err(OE_DEMON, errno, "Setting signal"); + goto done; + } + if (set_signal(SIGINT, restconf_sig_term, NULL) < 0){ + clicon_err(OE_DEMON, errno, "Setting signal"); + goto done; + } + /* Find and read configfile */ + if (clicon_options_main(h) < 0) + goto done; + + /* Now rest of options, some overwrite option file */ + optind = 1; + opterr = 0; + while ((c = getopt(argc, argv, RESTCONF_OPTS)) != -1) + switch (c) { + case 'h' : /* help */ + case 'D' : /* debug */ + case 'f': /* config file */ + case 'l': /* log */ + break; /* see above */ case 'd': /* Plugin directory */ if (!strlen(optarg)) usage(h, argv[0]); @@ -556,42 +595,10 @@ main(int argc, usage(h, argv[0]); clicon_option_str_set(h, "CLICON_SOCK", optarg); break; - case 'l': /* Log destination: s|e|o */ - switch (optarg[0]){ - case 's': - logdst = CLICON_LOG_SYSLOG; - break; - case 'f': - logdst = CLICON_LOG_FILE; - if (clicon_log_file(RESTCONF_LOGFILE) < 0) - goto done; - break; - default: - usage(h, argv[0]); - } - break; - default: - usage(h, argv[0]); - break; - } /* switch getopt */ - argc -= optind; - argv += optind; - - clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); - clicon_debug_init(debug, NULL); - clicon_log(LOG_NOTICE, "%s: %u Started", __PROGRAM__, getpid()); - if (set_signal(SIGTERM, restconf_sig_term, NULL) < 0){ - clicon_err(OE_DEMON, errno, "Setting signal"); - goto done; - } - if (set_signal(SIGINT, restconf_sig_term, NULL) < 0){ - clicon_err(OE_DEMON, errno, "Setting signal"); - goto done; - } - - /* Find and read configfile */ - if (clicon_options_main(h) < 0) - goto done; + default: + usage(h, argv[0]); + break; + } /* Overwrite yang module with -y option */ if (yangspec) diff --git a/lib/clixon/clixon_log.h b/lib/clixon/clixon_log.h index 026d9ba4..4524bcd7 100644 --- a/lib/clixon/clixon_log.h +++ b/lib/clixon/clixon_log.h @@ -61,6 +61,7 @@ extern int debug; */ int clicon_log_init(char *ident, int upto, int flags); int clicon_log_exit(void); +int clicon_log_opt(char c); int clicon_log_file(char *filename); int clicon_get_logflags(void); int clicon_log_str(int level, char *msg); diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 7b3d2b75..1815c121 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -105,7 +105,36 @@ clicon_log_exit(void) return 0; } -/* If log flags include CLICON_LOG_FILE, set the file +/*! Utility function to set log destination/flag using command-line option + * @param[in] c Log option,one of s,f,e,o + * @retval -1 No match + * @retval 0 One of CLICON_LOG_SYSLOG|STDERR|STDOUT|FILE + */ +int +clicon_log_opt(char c) +{ + int logdst = -1; + + switch (c){ + case 's': + logdst = CLICON_LOG_SYSLOG; + break; + case 'e': + logdst = CLICON_LOG_STDERR; + break; + case 'o': + logdst = CLICON_LOG_STDOUT; + break; + case 'f': + logdst = CLICON_LOG_FILE; + break; + default: + break; + } + return logdst; +} + +/*! If log flags include CLICON_LOG_FILE, set the file * @param[in] filename File to log to * @retval 0 OK * @retval -1 Error diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index e4c9513a..2900562e 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -1070,10 +1070,10 @@ xpath_vec_ctx(cxobj *xcur, clicon_err(OE_XML, 0, "XPATH parser error with no error code (should not happen)"); goto done; } - if (debug){ + if (debug > 1){ cbuf *cb = cbuf_new(); xpath_tree_print(cb, xy.xy_top); - clicon_debug(1, "xpath parse tree:\n%s", cbuf_get(cb)); + clicon_debug(2, "xpath parse tree:\n%s", cbuf_get(cb)); cbuf_free(cb); } xc.xc_type = XT_NODESET; From f9a97c57ca3d344650af4e7ce5776f42cd21afeb Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 29 Jul 2018 20:22:20 +0200 Subject: [PATCH 10/71] set /www-data access only if sudo --- apps/restconf/Makefile.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/restconf/Makefile.in b/apps/restconf/Makefile.in index 79a47104..89aa84e0 100644 --- a/apps/restconf/Makefile.in +++ b/apps/restconf/Makefile.in @@ -99,9 +99,13 @@ distclean: clean # Put other executables in libexec/ # Also create a libexec/ directory for writeable/temporary files. # Put config file in etc/ -# Shouldnt www-dir be owned by www-data? +# Also a rule for letting www-dir be owned by www-data, which only orks for sudo install: install-lib $(APPL) +ifeq ($(shell whoami),root) install -d -m 0755 -o $(wwwuser) -g $(wwwuser) $(DESTDIR)$(wwwdir) +else + install -d -m 0755 $(DESTDIR)$(wwwdir) +endif install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(wwwdir) install-lib: $(MYLIB) From e497238b8bd8648c233c88221a48eca273761467 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Sun, 29 Jul 2018 20:54:58 +0200 Subject: [PATCH 11/71] restconf dual getopt --- apps/restconf/restconf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 66350486..227badda 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -545,8 +545,6 @@ main(int argc, usage(h, argv[0]); break; } /* switch getopt */ - argc -= optind; - argv += optind; /* * Logs, error and debug to stderr or syslog, set debug level @@ -599,6 +597,8 @@ main(int argc, usage(h, argv[0]); break; } + argc -= optind; + argv += optind; /* Overwrite yang module with -y option */ if (yangspec) From 66e232bebaa2373152b29868cfdee1c287f70a3e Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 30 Jul 2018 11:56:48 +0000 Subject: [PATCH 12/71] moved xpath debug level from 1 to 2 --- lib/src/clixon_xpath.c | 6 +-- lib/src/clixon_xpath_parse.y | 92 ++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 2900562e..737a557a 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -856,14 +856,14 @@ xp_eval(xp_ctx *xc, xp_ctx *xr2 = NULL; int use_xr0 = 0; /* In 2nd child use transitively result of 1st child */ - if (debug){ + if (debug>1){ cbuf *cb; if ((cb = cbuf_new()) == NULL){ clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } ctx_print(cb, +2, xc, (char*)clicon_int2str(xpath_tree_map, xs->xs_type)); - clicon_debug(1, "%s", cbuf_get(cb)); + clicon_debug(2, "%s", cbuf_get(cb)); cbuf_free(cb); } /* Pre-actions before check first child c0 @@ -1027,7 +1027,7 @@ xp_eval(xp_ctx *xc, goto done; } ctx_print(cb, -2, *xrp, (char*)clicon_int2str(xpath_tree_map, xs->xs_type)); - clicon_debug(1, "%s", cbuf_get(cb)); + clicon_debug(2, "%s", cbuf_get(cb)); cbuf_free(cb); } retval = 0; diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index 0e601167..4e055ca7 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -193,85 +193,85 @@ xp_new(enum xp_type type, /* */ -start : expr X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->expr"); YYACCEPT; } - | locationpath X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->locationpath"); YYACCEPT; } +start : expr X_EOF { _XY->xy_top=$1;clicon_debug(2,"start->expr"); YYACCEPT; } + | 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(1,"expr->expr or andexpr"); } - | andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"expr-> andexpr"); } +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"); } ; -andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"andexpr-> andexpr and relexpr"); } - | relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"andexpr-> relexpr"); } +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"); } ; -relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"relexpr-> relexpr relop addexpr"); } - | addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"relexpr-> addexpr"); } +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"); } ; -addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"addexpr-> addexpr ADDOP unionexpr"); } - | unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"addexpr-> unionexpr"); } +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"); } ; /* node-set */ -unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"unionexpr-> unionexpr | pathexpr"); } - | pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"unionexpr-> pathexpr"); } +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"); } ; -pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> locationpath"); } - | primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> primaryexpr"); } +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"); } ; /* location path returns a node-set */ -locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> rellocpath"); } - | abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> abslocpath"); } +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"); } ; -abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(1,"abslocpath-> /"); } - | '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(1,"abslocpath->/ rellocpath");} +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");} /* // 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(1,"abslocpath-> // rellocpath"); } + | DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,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(1,"rellocpath-> step"); } - | rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"rellocpath-> rellocpath / step"); } - | rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(1,"rellocpath-> rellocpath // step"); } +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"); } ; -step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(1,"step->axisspec(%d) nodetest", $1); } - | '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> ."); } - | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"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-> .."); } ; -axisspec : AXISNAME DOUBLECOLON { clicon_debug(1,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;} - | '@' { $$=A_ATTRIBUTE; clicon_debug(1,"axisspec-> @"); } - | { clicon_debug(1,"axisspec-> "); $$=A_CHILD;} +axisspec : AXISNAME DOUBLECOLON { clicon_debug(2,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;} + | '@' { $$=A_ATTRIBUTE; clicon_debug(2,"axisspec-> @"); } + | { clicon_debug(2,"axisspec-> "); $$=A_CHILD;} ; -nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"nodetest-> *"); } - | NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(1,"nodetest-> name(%s)",$1); } - | NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : name(%s)", $1, $3); } - | NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : *", $1); } - | NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype()"); } +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(2,"nodetest-> nodetype()"); } ; /* evaluates to boolean */ -predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(1,"predicates-> [ expr ]"); } - | { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"predicates->"); } +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->"); } ; -primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(1,"primaryexpr-> ( expr )"); } - | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> NUMBER(%lf)", $1); } - | QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" string \""); } - | QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" \""); } - | APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' string '"); } - | APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' '"); } - | FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> functionname ( arguments )"); } +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 )"); } ; /* XXX Adding this between FUNCTIONNAME() breaks parser,.. -arguments : arguments expr { clicon_debug(1,"arguments-> arguments expr"); } - | { clicon_debug(1,"arguments-> "); } +arguments : arguments expr { clicon_debug(2,"arguments-> arguments expr"); } + | { clicon_debug(2,"arguments-> "); } ; */ string : string CHAR { @@ -279,9 +279,9 @@ string : string CHAR { $$ = realloc($1, len+strlen($2) + 1); sprintf($$+len, "%s", $2); free($2); - clicon_debug(1,"string-> string CHAR"); + clicon_debug(2,"string-> string CHAR"); } - | CHAR { clicon_debug(1,"string-> "); } + | CHAR { clicon_debug(2,"string-> "); } ; From ef9bb742d147b8116896b936ec6e711225e51a09 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 30 Jul 2018 13:32:45 +0000 Subject: [PATCH 13/71] axismap not used --- lib/src/clixon_xpath.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 737a557a..2fec113a 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -88,17 +88,6 @@ const map_str2int xpopmap[] = { {NULL, -1} }; -/* Mapping between axis type string <--> int */ -static const map_str2int axismap[] = { - {"self", A_SELF}, - {"child", A_CHILD}, - {"parent", A_PARENT}, - {"root", A_ROOT}, - {"ancestor", A_ANCESTOR}, - {"descendant-or-self", A_DESCENDANT_OR_SELF}, - {NULL, -1} -}; - static const map_str2int xpath_tree_map[] = { {"expr", XP_EXP}, {"andexpr", XP_AND}, From c53f3f2fe38b1f9eb5fad0f2268cbdc0d30b80ce Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 30 Jul 2018 17:35:45 +0000 Subject: [PATCH 14/71] Added file logging (`-l f` or `-l f`) for cases where neither syslog nor stderr is useful\ . --- CHANGELOG.md | 6 +++--- apps/backend/backend_main.c | 8 +++++--- apps/cli/cli_main.c | 10 ++++++---- apps/netconf/netconf_main.c | 8 +++++--- apps/restconf/restconf_main.c | 8 +++++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ff9e5a..86621a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,12 @@ ### Major New features ### API changes on existing features (you may need to change your code) -* clixon_netconf -S is obsolete. Use clixon_netconf -l s instead. +* Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead. ### Minor changes -* Unified log handling for all clicon applications using -l e|o|s|f. +* Unified log handling for all clicon applications using -l e|o|s|f. * The options stand for e:stderr, o:stdout, s: syslog, f:file - * Added file logging (-l f)for cases where neither syslog nor stderr is useful. + * Added file logging (`-l f` or `-l f`) for cases where neither syslog nor stderr is useful. * Obsoleted COMPAT_CLIV and COMPAT_XSL that were optional in 3.7 * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 76391b10..3b018dcc 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -144,7 +144,7 @@ usage(clicon_handle h, " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" " -c \tLoad extra xml configuration, but don't commit.\n" " -g \tClient membership required to this group (default: %s)\n" - " -l \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" + " -l > \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" " -y \tOverride yang spec file (dont include .yang suffix)\n" " -x \tXMLDB plugin\n", argv0, @@ -598,6 +598,10 @@ main(int argc, case 'l': /* Log destination: s|e|o */ if ((logdst = clicon_log_opt(optarg[0])) < 0) usage(h, argv[0]); + if (logdst == CLICON_LOG_FILE && + strlen(optarg)>1 && + clicon_log_file(optarg+1) < 0) + goto done; break; } /* @@ -607,8 +611,6 @@ main(int argc, * XXX: if started in a start-daemon script, there will be irritating * double syslogs until fork below. */ - if ((logdst & CLICON_LOG_FILE) && clicon_log_file(BACKEND_LOGFILE) < 0) - goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 7c8e4559..7ecf20f8 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -219,7 +219,7 @@ usage(clicon_handle h, "\t-p \t\tPrint database yang specification\n" "\t-G \t\tPrint CLI syntax generated from dbspec (if CLICON_CLI_GENMODEL enabled)\n" "\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n" - "\t-l \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default)\n" + "\t-l > \tLog on (s)yslog, std(e)rr, std(o)ut or (f)ile (stderr is default)\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n" "\t-c \tSpecify cli spec file.\n" "\t-U \tOver-ride unix user with a pseudo user for NACM.\n", @@ -299,16 +299,18 @@ main(int argc, char **argv) case 'x': /* dump config file as xml (migration from .conf file)*/ dump_configfile_xml++; break; - case 'l': /* Log destination: s|e|o */ + case 'l': /* Log destination: s|e|o|f */ if ((logdst = clicon_log_opt(optarg[0])) < 0) usage(h, argv[0]); + if (logdst == CLICON_LOG_FILE && + strlen(optarg)>1 && + clicon_log_file(optarg+1) < 0) + goto done; break; } /* * Logs, error and debug to stderr or syslog, set debug level */ - if ((logdst & CLICON_LOG_FILE) && clicon_log_file(CLI_LOGFILE) < 0) - goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 0942986b..817c2c82 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -299,7 +299,7 @@ usage(clicon_handle h, "\t-D\t\tDebug\n" "\t-q\t\tQuiet: dont send hello prompt\n" "\t-f \tConfiguration file (mandatory)\n" - "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n" + "\t-l > \tLog on std(e)rr, std(o)ut, (s)yslog, (f)ile (syslog is default)\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" "\t-u \tInternal socket domain path or IP addr (see -a)\n" "\t-d \tSpecify netconf plugin directory dir (default: %s)\n" @@ -355,13 +355,15 @@ main(int argc, case 'l': /* Log destination: s|e|o */ if ((logdst = clicon_log_opt(optarg[0])) < 0) usage(h, argv[0]); + if (logdst == CLICON_LOG_FILE && + strlen(optarg)>1 && + clicon_log_file(optarg+1) < 0) + goto done; break; } /* * Logs, error and debug to stderr or syslog, set debug level */ - if ((logdst & CLICON_LOG_FILE) && clicon_log_file(NETCONF_LOGFILE) < 0) - goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index 227badda..be5bfd67 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -490,7 +490,7 @@ usage(clicon_handle h, "\t-h \t\tHelp\n" "\t-D \t\tDebug. Log to syslog\n" "\t-f \tConfiguration file (mandatory)\n" - "\t-l \tLog on (s)yslog, (f)ile (syslog is default)\n" + "\t-l > \tLog on (s)yslog, (f)ile (syslog is default)\n" "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" "\t-y \tOverride yang spec file (dont include .yang suffix)\n" "\t-a UNIX|IPv4|IPv6\tInternal backend socket family\n" @@ -543,14 +543,16 @@ main(int argc, case 'l': /* Log destination: s|e|o */ if ((logdst = clicon_log_opt(optarg[0])) < 0) usage(h, argv[0]); + if (logdst == CLICON_LOG_FILE && + strlen(optarg)>1 && + clicon_log_file(optarg+1) < 0) + goto done; break; } /* switch getopt */ /* * Logs, error and debug to stderr or syslog, set debug level */ - if ((logdst & CLICON_LOG_FILE) && clicon_log_file(RESTCONF_LOGFILE) < 0) - goto done; clicon_log_init(__PROGRAM__, debug?LOG_DEBUG:LOG_INFO, logdst); clicon_debug_init(debug, NULL); From 03559427406878c47087bbc024c106a45fda1e3e Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 30 Jul 2018 18:08:34 +0000 Subject: [PATCH 15/71] flush log file --- lib/src/clixon_log.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 1815c121..589eb796 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -240,6 +240,7 @@ clicon_log_str(int level, if ((_logflags & CLICON_LOG_FILE) && _logfile){ flogtime(_logfile); fprintf(_logfile, "%s\n", msg); + fflush(_logfile); } if (_log_notify_cb){ static int cb = 0; From 656800cdd3b395c42b21e9de079332ba9bb4bc9a Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Wed, 1 Aug 2018 07:13:33 +0000 Subject: [PATCH 16/71] order backend cmd options; open syslog only if syslog is enabled --- apps/backend/backend_main.c | 22 +++++++++++----------- lib/src/clixon_log.c | 11 +++++++---- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/backend/backend_main.c b/apps/backend/backend_main.c index 3b018dcc..07617e93 100644 --- a/apps/backend/backend_main.c +++ b/apps/backend/backend_main.c @@ -73,7 +73,7 @@ #include "backend_handle.h" /* Command line options to be passed to getopt(3) */ -#define BACKEND_OPTS "hD:f:d:b:Fzu:a:P:1s:c:g:l:y:x:" /* substitute s: for IRCc:r */ +#define BACKEND_OPTS "hD:f:l:d:b:Fza:u:P:1s:c:g:y:x:" /* substitute s: for IRCc:r */ #define BACKEND_LOGFILE "/usr/local/var/clixon_backend.log" @@ -132,19 +132,20 @@ usage(clicon_handle h, "where options are\n" " -h\t\tHelp\n" " -D \tDebug level\n" - " -f \tCLICON config file (mandatory)\n" + " -f \tCLICON config file\n" + " -l > \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" " -d \tSpecify backend plugin directory (default: %s)\n" " -b \tSpecify XMLDB database directory\n" - " -z\t\tKill other config daemon and exit\n" " -F\t\tRun in foreground, do not run as daemon\n" - " -1\t\tRun once and then quit (dont wait for events)\n" + " -z\t\tKill other config daemon and exit\n" " -a UNIX|IPv4|IPv6\tInternal backend socket family\n" " -u \tInternal socket domain path or IP addr (see -a)(default: %s)\n" " -P \tPid filename (default: %s)\n" + " -1\t\tRun once and then quit (dont wait for events)\n" " -s \tSpecify backend startup mode: none|startup|running|init (replaces -IRCr\n" " -c \tLoad extra xml configuration, but don't commit.\n" " -g \tClient membership required to this group (default: %s)\n" - " -l > \tLog on (s)yslog, std(e)rr or std(o)ut (stderr is default) Only valid if -F, if background syslog is on syslog.\n" + " -y \tOverride yang spec file (dont include .yang suffix)\n" " -x \tXMLDB plugin\n", argv0, @@ -577,7 +578,6 @@ main(int argc, optind = 1; while ((c = getopt(argc, argv, BACKEND_OPTS)) != -1) switch (c) { - case '?': case 'h': /* Defer the call to usage() to later. Reason is that for helpful text messages, default dirs, etc, are not set until later. @@ -631,8 +631,10 @@ main(int argc, optind = 1; while ((c = getopt(argc, argv, BACKEND_OPTS)) != -1) switch (c) { + case 'h' : /* help */ case 'D' : /* debug */ case 'f': /* config file */ + case 'l' : break; /* see above */ case 'd': /* Plugin directory */ if (!strlen(optarg)) @@ -647,9 +649,6 @@ main(int argc, case 'F' : /* foreground */ foreground = 1; break; - case '1' : /* Quit after reading database once - dont wait for events */ - once = 1; - break; case 'z': /* Zap other process */ zap++; break; @@ -664,6 +663,9 @@ main(int argc, case 'P': /* pidfile */ clicon_option_str_set(h, "CLICON_BACKEND_PIDFILE", optarg); break; + case '1' : /* Quit after reading database once - dont wait for events */ + once = 1; + break; case 's' : /* startup mode */ clicon_option_str_set(h, "CLICON_STARTUP_MODE", optarg); if (clicon_startup_mode(h) < 0){ @@ -685,8 +687,6 @@ main(int argc, clicon_option_str_set(h, "CLICON_XMLDB_PLUGIN", optarg); break; } - case 'l' : - break; default: usage(h, argv[0]); break; diff --git a/lib/src/clixon_log.c b/lib/src/clixon_log.c index 589eb796..9e8e2f1a 100644 --- a/lib/src/clixon_log.c +++ b/lib/src/clixon_log.c @@ -89,11 +89,14 @@ clicon_log_init(char *ident, int upto, int flags) { - if (setlogmask(LOG_UPTO(upto)) < 0) - /* Cant syslog here */ - fprintf(stderr, "%s: setlogmask: %s\n", __FUNCTION__, strerror(errno)); + _logflags = flags; - openlog(ident, LOG_PID, LOG_USER); /* LOG_PUSER is achieved by direct stderr logs in clicon_log */ + if (flags & CLICON_LOG_SYSLOG){ + if (setlogmask(LOG_UPTO(upto)) < 0) + /* Cant syslog here */ + fprintf(stderr, "%s: setlogmask: %s\n", __FUNCTION__, strerror(errno)); + openlog(ident, LOG_PID, LOG_USER); /* LOG_PUSER is achieved by direct stderr logs in clicon_log */ + } return 0; } From 10ada483e528fc33ba94bd36036dcf3a7e708e18 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Wed, 1 Aug 2018 18:34:44 +0200 Subject: [PATCH 17/71] Memory error in backend transaction revert --- CHANGELOG.md | 1 + apps/backend/backend_plugin.c | 4 ++-- lib/src/clixon_plugin.c | 12 +++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86621a90..a80300f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * Added -l option for clixon_backend for directing syslog to stderr or stdout if running in foreground ### Corrected Bugs +* Memory error in backend transaction revert * Set dir /www-data with www-data as owner, see https://github.com/clicon/clixon/issues/37 ### Known issues diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index e193b876..b11e9b67 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -100,7 +100,7 @@ clixon_plugin_reset(clicon_handle h, if ((resetfn = cp->cp_api.ca_reset) == NULL) continue; if ((retval = resetfn(h, db)) < 0) { - clicon_debug(1, "plugin_start() failed\n"); + clicon_debug(1, "plugin_start() failed"); return -1; } break; @@ -357,7 +357,7 @@ plugin_transaction_revert(clicon_handle h, while ((cp = clixon_plugin_each_revert(h, cp, nr)) != NULL) { if ((fn = cp->cp_api.ca_trans_commit) == NULL) continue; - if ((retval = fn(h, (transaction_data)td)) < 0){ + if ((retval = fn(h, (transaction_data)&tr)) < 0){ clicon_log(LOG_NOTICE, "%s: Plugin '%s' trans_commit revert callback failed", __FUNCTION__, cp->cp_name); break; diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 5e17cd1e..7710ae80 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -130,8 +130,10 @@ clixon_plugin_each_revert(clicon_handle h, clixon_plugin *cp = NULL; clixon_plugin *cpnext = NULL; - if (cpprev == NULL) - cpnext = &_clixon_plugins[nr-1]; + if (cpprev == NULL){ + if (nr>0) + cpnext = &_clixon_plugins[nr-1]; + } else{ for (i = nr-1; i >= 0; i--) { cp = &_clixon_plugins[i]; @@ -320,7 +322,7 @@ clixon_plugin_start(clicon_handle h, continue; // optind = 0; if (startfn(h, argc, argv) < 0) { - clicon_debug(1, "plugin_start() failed\n"); + clicon_debug(1, "plugin_start() failed"); return -1; } } @@ -343,7 +345,7 @@ clixon_plugin_exit(clicon_handle h) if ((exitfn = cp->cp_api.ca_exit) == NULL) continue; if (exitfn(h) < 0) { - clicon_debug(1, "plugin_exit() failed\n"); + clicon_debug(1, "plugin_exit() failed"); return -1; } if (dlclose(cp->cp_handle) != 0) { @@ -385,7 +387,7 @@ clixon_plugin_auth(clicon_handle h, if ((authfn = cp->cp_api.ca_auth) == NULL) continue; if ((retval = authfn(h, arg)) < 0) { - clicon_debug(1, "plugin_auth() failed\n"); + clicon_debug(1, "plugin_auth() failed"); return -1; } break; From 7c94991fe9b0c8daba1e820029861c12abfb806e Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Fri, 3 Aug 2018 13:24:41 +0200 Subject: [PATCH 18/71] * clixon_restconf and clixon_netconf now take -D as command-line option\ instead of just -D * This aligns to clixon_cli and clixon_backend --- CHANGELOG.md | 2 ++ apps/cli/cli_main.c | 2 +- apps/netconf/netconf_main.c | 5 +++-- apps/restconf/README.md | 2 +- apps/restconf/restconf_main.c | 9 +++++---- apps/restconf/restconf_methods.c | 2 +- test/lib.sh | 4 ++-- test/test_perf.sh | 2 +- test/test_restconf.sh | 2 +- test/test_restconf2.sh | 2 +- 10 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a80300f9..0f780790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Major New features ### API changes on existing features (you may need to change your code) +* clixon_restconf and clixon_netconf now take -D as command-line option instead of just -D + * This aligns to clixon_cli and clixon_backend * Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead. ### Minor changes diff --git a/apps/cli/cli_main.c b/apps/cli/cli_main.c index 7ecf20f8..f2d2de3a 100644 --- a/apps/cli/cli_main.c +++ b/apps/cli/cli_main.c @@ -206,7 +206,7 @@ usage(clicon_handle h, "where commands is a CLI command or options passed to the main plugin\n" "where options are\n" "\t-h \t\tHelp\n" - "\t-D \tDebug\n" + "\t-D \tDebug level\n" "\t-f \tConfig-file (mandatory)\n" "\t-x\t\tDump configuration file as XML on stdout (migration utility)\n" "\t-F \tRead commands from file (default stdin)\n" diff --git a/apps/netconf/netconf_main.c b/apps/netconf/netconf_main.c index 817c2c82..77db0176 100644 --- a/apps/netconf/netconf_main.c +++ b/apps/netconf/netconf_main.c @@ -296,7 +296,7 @@ usage(clicon_handle h, fprintf(stderr, "usage:%s\n" "where options are\n" "\t-h\t\tHelp\n" - "\t-D\t\tDebug\n" + "\t-D \tDebug level\n" "\t-q\t\tQuiet: dont send hello prompt\n" "\t-f \tConfiguration file (mandatory)\n" "\t-l > \tLog on std(e)rr, std(o)ut, (s)yslog, (f)ile (syslog is default)\n" @@ -345,7 +345,8 @@ main(int argc, usage(h, argv[0]); break; case 'D' : /* debug */ - debug = 1; + if (sscanf(optarg, "%d", &debug) != 1) + usage(h, argv[0]); break; case 'f': /* override config file */ if (!strlen(optarg)) diff --git a/apps/restconf/README.md b/apps/restconf/README.md index ce077300..f3f0c71f 100644 --- a/apps/restconf/README.md +++ b/apps/restconf/README.md @@ -66,7 +66,7 @@ curl -sX POST -d '{"interfaces":{"interface":{"name":"eth1","type":"eth","enable Start the restconf fastcgi program with debug flag: ``` -sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/example.xml" -s /bin/sh www-data +sudo su -c "/www-data/clixon_restconf -D 1 f /usr/local/etc/example.xml" -s /bin/sh www-data ``` Look at syslog: ``` diff --git a/apps/restconf/restconf_main.c b/apps/restconf/restconf_main.c index be5bfd67..2a9d8ae5 100644 --- a/apps/restconf/restconf_main.c +++ b/apps/restconf/restconf_main.c @@ -39,7 +39,7 @@ * sudo apt-get install libfcgi-dev * gcc -o fastcgi fastcgi.c -lfcgi - * sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/example.xml " -s /bin/sh www-data + * sudo su -c "/www-data/clixon_restconf -D 1 -f /usr/local/etc/example.xml " -s /bin/sh www-data * This is the interface: * api/data/profile=/metric= PUT data:enable= @@ -74,7 +74,7 @@ #include "restconf_methods.h" /* Command line options to be passed to getopt(3) */ -#define RESTCONF_OPTS "hDf:l:p:y:a:u:" +#define RESTCONF_OPTS "hD:f:l:p:y:a:u:" /* RESTCONF enables deployments to specify where the RESTCONF API is located. The client discovers this by getting the "/.well-known/host-meta" @@ -488,7 +488,7 @@ usage(clicon_handle h, fprintf(stderr, "usage:%s [options]\n" "where options are\n" "\t-h \t\tHelp\n" - "\t-D \t\tDebug. Log to syslog\n" + "\t-D \tDebug level\n" "\t-f \tConfiguration file (mandatory)\n" "\t-l > \tLog on (s)yslog, (f)ile (syslog is default)\n" "\t-d \tSpecify restconf plugin directory dir (default: %s)\n" @@ -533,7 +533,8 @@ main(int argc, usage(h, argv[0]); break; case 'D' : /* debug */ - debug = 1; + if (sscanf(optarg, "%d", &debug) != 1) + usage(h, argv[0]); break; case 'f': /* override config file */ if (!strlen(optarg)) diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index d75dafd9..6a1712f6 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -39,7 +39,7 @@ * sudo apt-get install libfcgi-dev * gcc -o fastcgi fastcgi.c -lfcgi - * sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/example.xml " -s /bin/sh www-data + * sudo su -c "/www-data/clixon_restconf -D 1 f /usr/local/etc/example.xml " -s /bin/sh www-data * This is the interface: * api/data/profile=/metric= PUT data:enable= diff --git a/test/lib.sh b/test/lib.sh index 1b58a404..2e7d0549 100755 --- a/test/lib.sh +++ b/test/lib.sh @@ -15,8 +15,8 @@ clixon_cli=clixon_cli clixon_netconf=clixon_netconf # How to run restconf stand-alone and using valgrind -#sudo su -c "/www-data/clixon_restconf -f $cfg -D" -s /bin/sh www-data -#sudo su -c "valgrind --leak-check=full --show-leak-kinds=all /www-data/clixon_restconf -f $cfg -D" -s /bin/sh www-data +#sudo su -c "/www-data/clixon_restconf -f $cfg -D 1" -s /bin/sh www-data +#sudo su -c "valgrind --leak-check=full --show-leak-kinds=all /www-data/clixon_restconf -f $cfg -D 1" -s /bin/sh www-data #clixon_backend="valgrind --leak-check=full --show-leak-kinds=all clixon_backend" clixon_backend=clixon_backend diff --git a/test/test_perf.sh b/test/test_perf.sh index 7fe241a0..b5703683 100755 --- a/test/test_perf.sh +++ b/test/test_perf.sh @@ -72,7 +72,7 @@ new "kill old restconf daemon" sudo pkill -u www-data clixon_restconf new "start restconf daemon" -sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D +sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D 1 sleep 1 diff --git a/test/test_restconf.sh b/test/test_restconf.sh index 7201eb74..c2fc32b1 100755 --- a/test/test_restconf.sh +++ b/test/test_restconf.sh @@ -92,7 +92,7 @@ new "kill old restconf daemon" sudo pkill -u www-data clixon_restconf new "start restconf daemon" -sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang -D +sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg -y $fyang # -D 1 sleep 1 diff --git a/test/test_restconf2.sh b/test/test_restconf2.sh index dfd7a265..1065cbee 100755 --- a/test/test_restconf2.sh +++ b/test/test_restconf2.sh @@ -60,7 +60,7 @@ new "kill old restconf daemon" sudo pkill -u www-data clixon_restconf new "start restconf daemon" -sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg # -D +sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c www-data -- -f $cfg # -D 1 sleep 1 From 7564bcd9b2080fa8d9e3b4befdb3a4066e3571d8 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Sun, 5 Aug 2018 12:20:37 +0200 Subject: [PATCH 19/71] docker improvement --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2a2ce179..c8c488ec 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -40,7 +40,6 @@ RUN apt-get update && apt-get install -y \ libfcgi-dev \ libcurl4-openssl-dev - RUN groupadd clicon # Create a directory to hold source-code, dependencies etc @@ -49,7 +48,7 @@ WORKDIR /clixon # Clone cligen and clixon RUN git clone https://github.com/olofhagsand/cligen.git -RUN git clone https://github.com/clicon/clixon.git +RUN git clone -b develop https://github.com/clicon/clixon.git # Build cligen WORKDIR /clixon/cligen @@ -59,12 +58,13 @@ RUN make install # Build clixon WORKDIR /clixon/clixon -RUN git checkout -b develop origin/develop RUN ./configure RUN make RUN make install RUN make install-include +RUN rm -rf /clixon + RUN ldconfig From bb6d043d6cb5840b9ccc6cd47a7c13775ffd8834 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Sun, 5 Aug 2018 16:34:45 +0200 Subject: [PATCH 20/71] deprecated readdir_r with readdir --- doc/FAQ.md | 4 ++-- docker/Dockerfile | 2 -- docker/Makefile.in | 1 + example/Dockerfile | 10 +++++++--- example/README.md | 18 ++++++++---------- lib/src/clixon_file.c | 18 +++++------------- 6 files changed, 23 insertions(+), 30 deletions(-) diff --git a/doc/FAQ.md b/doc/FAQ.md index 64ba9f3c..50c68dac 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -103,10 +103,10 @@ You can change where CLixon looks for the configuration FILE as follows: ## Can I run Clixon as docker containers? Yes, the example works as docker containers as well. There should be a -prepared container in docker hib for the example where the backend and +prepared container in docker hub for the example where the backend and CLI is bundled. ``` -sudo docker run -ti --rm olofhagsand/clixon_example +sudo docker run -td olofhagsand/clixon_example ``` Look in the example documentation for more info. diff --git a/docker/Dockerfile b/docker/Dockerfile index c8c488ec..6bdadc9c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -40,8 +40,6 @@ RUN apt-get update && apt-get install -y \ libfcgi-dev \ libcurl4-openssl-dev -RUN groupadd clicon - # Create a directory to hold source-code, dependencies etc RUN mkdir /clixon WORKDIR /clixon diff --git a/docker/Makefile.in b/docker/Makefile.in index 58905f5b..7eaed4cc 100644 --- a/docker/Makefile.in +++ b/docker/Makefile.in @@ -56,6 +56,7 @@ distclean: clean docker: sudo docker build -t $(IMAGE) . + @echo "cd ../example; make docker to build example application" push: sudo docker push $(IMAGE) diff --git a/example/Dockerfile b/example/Dockerfile index 24403dc5..08314bf8 100644 --- a/example/Dockerfile +++ b/example/Dockerfile @@ -34,8 +34,11 @@ FROM olofhagsand/clixon MAINTAINER Olof Hagsand -RUN apt-get update && apt-get install -y \ - procps # ps for debugging +#RUN apt-get update && apt-get install -y procps # ps for debugging + +# The example uses "clicon" group +RUN groupadd clicon + # Create a directory to hold source-code, dependencies etc RUN mkdir /example WORKDIR /example @@ -53,7 +56,8 @@ RUN make RUN make install RUN install example.xml /usr/local/etc/clixon.xml -CMD /usr/local/sbin/clixon_backend && /usr/local/bin/clixon_cli +# Log to stderr. Add -D 1 for debug +CMD /usr/local/sbin/clixon_backend -F -a IPv4 -u 0.0.0.0 -s init -l e diff --git a/example/README.md b/example/README.md index 0c6d6356..11ed13cf 100644 --- a/example/README.md +++ b/example/README.md @@ -198,19 +198,13 @@ The example contains some stubs for authorization according to [RFC8341(NACM)](h Example systemd files for backend and restconf daemons are found under the systemd directory. Install them under /etc/systemd/system for example. -## Run as docker container - -(Note not updated) -``` -cd docker -# look in README -``` - ## Docker -Run the example as a docker container as follows: +Run the example as a docker container and access it from a host CLI as follows: ``` -sudo docker run -ti --rm olofhagsand/clixon_example +ID=$(sudo docker run -td olofhagsand/clixon_example) +IP=$(sudo docker inspect -f '{{.NetworkSettings.IPAddress }}' $ID) +clixon_cli -a IPv4 -u $IP -f ./example.xml ``` Build the container and push yourself: First change the IMAGE variable in Makefile (eg to "you/clixon_example). Then build and push: @@ -220,5 +214,9 @@ make push sudo docker run -ti --rm you/clixon_example ``` +Note that the configuration database is internal in the container, so +it is deleted if the container is restarted. To make the configuration +database persistent, you need to mount running_db using `-v` + diff --git a/lib/src/clixon_file.c b/lib/src/clixon_file.c index 160d3145..22998553 100644 --- a/lib/src/clixon_file.c +++ b/lib/src/clixon_file.c @@ -112,8 +112,7 @@ clicon_file_dirent(const char *dir, char errbuf[128]; char filename[MAXPATHLEN]; struct stat st; - struct dirent dent; - struct dirent *dresp; + struct dirent *dent; struct dirent *tmp; struct dirent *new = NULL; struct dirent *dvecp = NULL; @@ -132,22 +131,15 @@ clicon_file_dirent(const char *dir, clicon_err(OE_UNIX, errno, "opendir(%s)", dir); goto quit; } - for (res = readdir_r(dirp, &dent, &dresp); - dresp; - res = readdir_r(dirp, &dent, &dresp)) { - if (res != 0) { - clicon_err(OE_UNIX, 0, "readdir: %s", strerror(errno)); - goto quit; - } - + while((dent = readdir(dirp)) != NULL) { /* Filename matching */ if (regexp) { - if (regexec(&re, dent.d_name, (size_t) 0, NULL, 0) != 0) + if (regexec(&re, dent->d_name, (size_t) 0, NULL, 0) != 0) continue; } /* File type matching */ if (type) { - snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dent.d_name); + snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dent->d_name); res = lstat(filename, &st); if (res != 0) { clicon_err(OE_UNIX, 0, "lstat: %s", strerror(errno)); @@ -161,7 +153,7 @@ clicon_file_dirent(const char *dir, goto quit; } new = tmp; - memcpy(&new[nent], &dent, sizeof(dent)); + memcpy(&new[nent], dent, sizeof(*dent)); nent++; } /* while */ From de2d5be6ddda70baf4f3c5ecc328c5118c16b2f9 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 27 Aug 2018 19:07:52 +0000 Subject: [PATCH 21/71] export populate --- lib/clixon/clixon_err.h | 2 +- lib/clixon/clixon_yang.h | 1 + lib/src/clixon_yang.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/clixon/clixon_err.h b/lib/clixon/clixon_err.h index 8b8900ac..b5961453 100644 --- a/lib/clixon/clixon_err.h +++ b/lib/clixon/clixon_err.h @@ -55,7 +55,7 @@ enum clicon_err{ OE_DB = 1, /* database registries */ OE_DEMON, /* demons: pidfiles, etc */ OE_EVENTS, /* events, filedescriptors, timeouts */ - OE_CFG, /* config commit / quagga */ + OE_CFG, /* configuration */ OE_PROTO, /* config/client communication */ OE_REGEX, /* Regexp error */ OE_UNIX, /* unix/linux syscall error */ diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 18fbee6b..49b5c5da 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -258,6 +258,7 @@ char *yang_find_myprefix(yang_stmt *ys); int yang_order(yang_stmt *y); int yang_print(FILE *f, yang_node *yn); int yang_print_cbuf(cbuf *cb, yang_node *yn, int marginal); +int ys_populate(yang_stmt *ys, void *arg); yang_stmt *yang_parse_file(int fd, const char *name, yang_spec *ysp); int yang_parse(clicon_handle h, const char *yang_dir, const char *module, const char *revision, yang_spec *ysp); diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index afdedbc1..d6336da9 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1331,7 +1331,7 @@ ys_populate_identity(yang_stmt *ys, * See ys_parse_sub for first pass and what can be assumed * After this pass, cv:s are set for LEAFs and LEAF-LISTs */ -static int +int ys_populate(yang_stmt *ys, void *arg) { From 2cadfa167e3baffeac99b1759b84f2c0e8210c08 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 27 Aug 2018 20:14:27 +0000 Subject: [PATCH 22/71] EPEER --- lib/src/clixon_proto.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index 6b41c6a5..6c1db58b 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -245,9 +245,10 @@ atomicio(ssize_t (*fn) (int, void *, size_t), if (!_atomicio_sig) continue; } - else - if (errno == EAGAIN) - continue; + else if (errno == EAGAIN) + continue; + else if (errno == EPEER) + res = 0; case 0: /* fall thru */ return (res); default: From f37fdb954fc3438b9d118617680385ecaa17fd3b Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 27 Aug 2018 20:20:43 +0000 Subject: [PATCH 23/71] ECONNRESET --- lib/src/clixon_proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/clixon_proto.c b/lib/src/clixon_proto.c index 6c1db58b..1eaa4a66 100644 --- a/lib/src/clixon_proto.c +++ b/lib/src/clixon_proto.c @@ -247,7 +247,7 @@ atomicio(ssize_t (*fn) (int, void *, size_t), } else if (errno == EAGAIN) continue; - else if (errno == EPEER) + else if (errno == ECONNRESET)/* Connection reset by peer */ res = 0; case 0: /* fall thru */ return (res); From 0631be19cb7a8334f0e159fbe6bd1be9286f6595 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 18 Sep 2018 22:49:29 +0200 Subject: [PATCH 24/71] * Notification event streams enhancements * Yang 1.1 notification support * Event stream discovery support according to RFC 5277 Sec 3.2.5.1 (netconf) and RFC 8040 (restconf) --- CHANGELOG.md | 3 + apps/backend/backend_client.c | 107 +++++++++++-- apps/backend/backend_main.c | 10 +- apps/backend/clixon_backend_handle.c | 2 + apps/cli/cli_handle.c | 12 +- apps/restconf/README.md | 4 +- lib/clixon/clixon.h.in | 1 + lib/clixon/clixon_handle.h | 5 + lib/clixon/clixon_yang.h | 1 + lib/src/Makefile.in | 2 +- lib/src/clixon_handle.c | 33 +++- lib/src/clixon_yang.c | 52 +++++- lib/src/clixon_yang_parse.y | 37 ++++- test/test_event.sh | 117 ++++++++++++++ yang/Makefile.in | 1 + yang/ietf-restconf-monitoring@2017-01-26.yang | 149 ++++++++++++++++++ 16 files changed, 502 insertions(+), 34 deletions(-) create mode 100755 test/test_event.sh create mode 100644 yang/ietf-restconf-monitoring@2017-01-26.yang diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f780790..0a46eab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ### Major New features ### API changes on existing features (you may need to change your code) +* Notification event streams enhancements + * Yang 1.1 notification support + * Event stream discovery support according to RFC 5277 Sec 3.2.5.1 (netconf) and RFC 8040 (restconf) * clixon_restconf and clixon_netconf now take -D as command-line option instead of just -D * This aligns to clixon_cli and clixon_backend * Application command option -S to clixon_netconf is obsolete. Use `clixon_netconf -l s` instead. diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 224b371d..71714e68 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -99,20 +99,10 @@ client_subscription_add(struct client_entry *ce, return su; } -static struct client_entry * -ce_find_bypid(struct client_entry *ce_list, int pid) -{ - struct client_entry *ce; - - for (ce = ce_list; ce; ce = ce->ce_next) - if (ce->ce_pid == pid) - return ce; - return NULL; -} - +/*! Delete stream subscription from client subscription list */ static int client_subscription_delete(struct client_entry *ce, - struct client_subscription *su0) + struct client_subscription *su0) { struct client_subscription *su; struct client_subscription **su_prev; @@ -134,7 +124,8 @@ client_subscription_delete(struct client_entry *ce, #ifdef notused /* xxx */ static struct client_subscription * -client_subscription_find(struct client_entry *ce, char *stream) +client_subscription_find(struct client_entry *ce, + char *stream) { struct client_subscription *su = NULL; @@ -146,6 +137,18 @@ client_subscription_find(struct client_entry *ce, char *stream) } #endif +static struct client_entry * +ce_find_bypid(struct client_entry *ce_list, + int pid) +{ + struct client_entry *ce; + + for (ce = ce_list; ce; ce = ce->ce_next) + if (ce->ce_pid == pid) + return ce; + return NULL; +} + /*! Remove client entry state * Close down everything wrt clients (eg sockets, subscriptions) * Finally actually remove client struct in handle @@ -258,6 +261,79 @@ from_client_get_config(clicon_handle h, return retval; } +static int +client_get_streams(clicon_handle h, + char *xpath, + cxobj **xtop) +{ + int retval = -1; + cxobj *x = NULL; + cxobj *xc; + char *reason = NULL; + yang_spec *yspec; + cbuf *cb; + + if ((yspec = clicon_dbspec_yang(h)) == NULL){ + clicon_err(OE_YANG, ENOENT, "No yang spec"); + goto done; + } + if (*xtop==NULL){ + clicon_err(OE_CFG, ENOENT, "XML tree expected"); + goto done; + } + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, 0, "clicon buffer"); + goto done; + } + cprintf(cb,""); + if (stream_get_xml(h, cb) < 0) + goto done; + cprintf(cb,""); + /* XXX. yspec */ + if (xml_parse_string(cbuf_get(cb), NULL, &x) < 0) + goto done; + if (xml_merge(*xtop, x, yspec, &reason) < 0) + goto done; + if (reason){ + while ((xc = xml_child_i(*xtop, 0)) != NULL) + xml_purge(xc); + if (netconf_operation_failed_xml(xtop, "rpc", reason)< 0) + goto done; + goto ok; + } +#ifdef notyet + /* Code complex to filter out anything that is outside of xpath */ + if (xpath_vec(*xtop, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + goto done; + + /* If vectors are specified then mark the nodes found and + * then filter out everything else, + * otherwise return complete tree. + */ + if (xvec != NULL){ + for (i=0; i