From d2d3454177837cc747d5fabd3e788edbe09795fe Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 13 Oct 2021 21:03:59 +0200 Subject: [PATCH 01/10] Dispatcher: modified key handling and added print function also added dispatcher utility and test functions --- lib/clixon/clixon_dispatcher.h | 42 ++++++++++++++++++++++--- test/test_dispatcher.sh | 54 +++++++++++++++++++++++++++++++++ util/clixon_util_dispatcher | Bin 0 -> 18608 bytes 3 files changed, 91 insertions(+), 5 deletions(-) create mode 100755 test/test_dispatcher.sh create mode 100755 util/clixon_util_dispatcher diff --git a/lib/clixon/clixon_dispatcher.h b/lib/clixon/clixon_dispatcher.h index 88bde49d..ff8bb0fd 100644 --- a/lib/clixon/clixon_dispatcher.h +++ b/lib/clixon/clixon_dispatcher.h @@ -1,12 +1,43 @@ /* - * Copyright 2021 Rubicon Communications LLC (Netgate) + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2021 Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + * @see https://github.com/dcornejo/dispatcher */ -#ifndef DISPATCH_DISPATCHER_H -#define DISPATCH_DISPATCHER_H +#ifndef _CLIXON_DISPATCH_DISPATCHER_H +#define _CLIXON_DISPATCH_DISPATCHER_H -/*! prototype for a function to handle a path +/*! Prototype for a function to handle a path * minimally needs the path it's working on, but probably * we want to hand down cached data somehow * @param[in] h Generic handler @@ -74,5 +105,6 @@ struct _dispatcher_entry { int dispatcher_register_handler(dispatcher_entry_t **root, dispatcher_definition *x); int dispatcher_call_handlers(dispatcher_entry_t *root, void *handle, char *path, void *user_args); int dispatcher_free(dispatcher_entry_t *root); +int dispatcher_print(FILE *f, dispatcher_entry_t *root); -#endif /* DISPATCH_DISPATCHER_H */ +#endif /* _CLIXON_DISPATCH_DISPATCHER_H */ diff --git a/test/test_dispatcher.sh b/test/test_dispatcher.sh new file mode 100755 index 00000000..2735a9ad --- /dev/null +++ b/test/test_dispatcher.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# Test of path dispatcher + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +: ${clixon_util_dispatcher:="clixon_util_dispatcher"} + +new "null test" +expectpart "$($clixon_util_dispatcher)" 0 "^$" + +new "path /, nothing regged. Expect fail" +expectpart "$($clixon_util_dispatcher -c /)" 255 "^$" + +new "reg /, path / arg foo" +expectpart "$($clixon_util_dispatcher -a foo -p / -r -c /)" 0 "cb1 foo" + +new "reg /foo and /bar same cb1, call /" +expectpart "$($clixon_util_dispatcher -a foo -p /foo -r -a bar -p /bar -r -c /)" 0 "cb1 foo" "cb1 bar" + +new "reg /foo and /bar different cb, call /" +expectpart "$($clixon_util_dispatcher -i 1 -a foo -p /foo -r -a bar -p /bar -i 2 -r -c /)" 0 "cb1 foo" "cb2 bar" + +new "reg /foo and /bar call /foo" +expectpart "$($clixon_util_dispatcher -i 1 -a foo -p /foo -r -a bar -p /bar -i 2 -r -c /foo)" 0 "cb1 foo" + +new "reg /foo and /bar call /bar" +expectpart "$($clixon_util_dispatcher -i 1 -a foo -p /foo -r -a bar -p /bar -i 2 -r -c /bar)" 0 "cb2 bar" + +new "reg /route-table ipv4 and ipv6 call /route-table" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table -i 2 -r -c /route-table)" 0 "cb1 ipv4" "cb2 ipv6" + +new "reg /route-table/ ipv4,ipv6 call /route-table/ipv4" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table/ipv6 -i 2 -r -c /route-table/ipv4)" 0 "cb1 ipv4" --not-- cb2 + +new "reg /route-table/ ipv4,ipv6 call /route-table/ipv6" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table/ipv6 -i 2 -r -c /route-table/ipv6)" 0 "cb2 ipv6" --not-- cb1 + +new "reg /route-table/ ipv4,ipv6 call /route-table[proto='ipv4']/ipv4" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table/ipv6 -i 2 -r -c /route-table[proto='ipv4']/ipv4)" 0 "cb1 ipv4" --not-- "cb2 ipv6" + +new "reg /route-table/ ipv4,ipv6 call /route-table[proto='ipv6']/ipv6" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table/ipv6 -i 2 -r -c /route-table[proto='ipv6']/ipv6)" 0 "cb2 ipv6" --not-- "cb1 ipv4" + +new "reg /route-table/ ipv4,ipv6 call /route-table=/ipv4" +expectpart "$($clixon_util_dispatcher -i 1 -a ipv4 -p /route-table/ipv4 -r -a ipv6 -p /route-table/ipv6 -i 2 -r -c /route-table=/ipv4)" 0 "cb1 ipv4" --not-- "cb2 ipv6" + +# unset conditional parameters +unset clixon_util_dispatcher + +rm -rf $dir + +new "endtest" +endtest diff --git a/util/clixon_util_dispatcher b/util/clixon_util_dispatcher new file mode 100755 index 0000000000000000000000000000000000000000..4601c6a9c4dfb0e5784807463783c5fcae70dac2 GIT binary patch literal 18608 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 Date: Thu, 14 Oct 2021 08:58:35 +0200 Subject: [PATCH 02/10] Dispatcher test additions --- lib/clixon/clixon_dispatcher.h | 2 +- lib/clixon/clixon_plugin.h | 5 +-- lib/src/clixon_dispatcher.c | 67 +++++++++++++++++++++++++++++---- lib/src/clixon_yang.c | 2 +- util/Makefile.in | 8 +++- util/clixon_util_dispatcher | Bin 18608 -> 0 bytes util/clixon_util_xpath.c | 4 +- 7 files changed, 72 insertions(+), 16 deletions(-) delete mode 100755 util/clixon_util_dispatcher diff --git a/lib/clixon/clixon_dispatcher.h b/lib/clixon/clixon_dispatcher.h index ff8bb0fd..c27e1881 100644 --- a/lib/clixon/clixon_dispatcher.h +++ b/lib/clixon/clixon_dispatcher.h @@ -105,6 +105,6 @@ struct _dispatcher_entry { int dispatcher_register_handler(dispatcher_entry_t **root, dispatcher_definition *x); int dispatcher_call_handlers(dispatcher_entry_t *root, void *handle, char *path, void *user_args); int dispatcher_free(dispatcher_entry_t *root); -int dispatcher_print(FILE *f, dispatcher_entry_t *root); +int dispatcher_print(FILE *f, int level, dispatcher_entry_t *root); #endif /* _CLIXON_DISPATCH_DISPATCHER_H */ diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index 62168e2d..ffebc982 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -50,7 +50,6 @@ /* * Types */ - /*! Registered RPC callback function * @param[in] h Clicon handle @@ -201,8 +200,8 @@ typedef int (plgreset_t)(clicon_handle h, const char *db); * A complete valid XML tree is created by the plugin and sent back via xtop, which is merged * into a complete state tree by the system. * The plugin should ensure that xpath is matched (using namspace context nsc) - * This callback may be replaced with a "dispatcher" type API in the future where the - * XPath binding is stricter, similar to the pagination API. + * XXX: This callback may be replaced with a "dispatcher" type API in the future where the + * XPath binding is stricter, similar to the pagination API. * * @param[in] h Clicon handle * @param[in] xpath Part of state requested diff --git a/lib/src/clixon_dispatcher.c b/lib/src/clixon_dispatcher.c index b38e78f9..05b3f911 100644 --- a/lib/src/clixon_dispatcher.c +++ b/lib/src/clixon_dispatcher.c @@ -1,5 +1,36 @@ /* - * Copyright 2021 Rubicon Communications LLC (Netgate) + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2021 Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + * @see https://github.com/dcornejo/dispatcher */ @@ -285,11 +316,8 @@ get_entry(dispatcher_entry_t *root, /* some elements may have keys defined, strip them off */ for (int i = 0; i < split_path_len; i++) { - char *kptr = strchr(split_path_list[i], '='); - - if ((kptr != NULL) && (*kptr == '=')) { - *(kptr + 1) = 0; - } + char *kptr = split_path_list[i]; + strsep(&kptr, "=[]"); } /* search down the tree */ @@ -423,8 +451,12 @@ dispatcher_call_handlers(dispatcher_entry_t *root, void *user_args) { int ret = 0; - dispatcher_entry_t *best = get_entry(root, path); + dispatcher_entry_t *best; + if ((best = get_entry(root, path)) == NULL){ + errno = ENOENT; + return -1; + } if (best->children != NULL) { call_handler_helper(best->children, handle, path, user_args); } @@ -450,3 +482,24 @@ dispatcher_free(dispatcher_entry_t *root) free(root); return 0; } + +/*! Pretty-print dispatcher tree + */ +#define INDENT 3 +int +dispatcher_print(FILE *f, + int level, + dispatcher_entry_t *de) +{ + fprintf(f, "%*s%s", level*INDENT, "", de->node_name); + if (de->handler) + fprintf(f, " %p", de->handler); + if (de->arg) + fprintf(f, " (%p)", de->arg); + fprintf(f, "\n"); + if (de->children) + dispatcher_print(f, level+1, de->children); + if (de->peer) + dispatcher_print(f, level, de->peer); + return 0; +} diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 7a588f26..6f3b45ab 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -3585,7 +3585,7 @@ yang_extension_value(yang_stmt *ys, clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } - yext = NULL; /* This loop gets complicated in trhe case the extension is augmented */ + yext = NULL; /* This loop gets complicated in the case the extension is augmented */ while ((yext = yn_each(ys, yext)) != NULL) { if (yang_keyword_get(yext) != Y_UNKNOWN) continue; diff --git a/util/Makefile.in b/util/Makefile.in index ed34e1ef..7e4d21ed 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -91,7 +91,8 @@ APPSRC += clixon_util_path.c APPSRC += clixon_util_datastore.c APPSRC += clixon_util_regexp.c APPSRC += clixon_util_socket.c -APPSRC += clixon_util_validate.c +APPSRC += clixon_util_validate.c +APPSRC += clixon_util_dispatcher.c APPSRC += clixon_netconf_ssh_callhome.c APPSRC += clixon_netconf_ssh_callhome_client.c ifdef with_restconf @@ -149,6 +150,9 @@ clixon_util_socket: clixon_util_socket.c $(LIBDEPS) clixon_util_validate: clixon_util_validate.c $(LIBDEPS) $(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ -l clixon_backend -o $@ $(LIBS) +clixon_util_dispatcher: clixon_util_dispatcher.c $(LIBDEPS) + $(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ -l clixon_backend -o $@ $(LIBS) + ifdef with_restconf clixon_util_stream: clixon_util_stream.c $(LIBDEPS) $(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $(LDFLAGS) $^ $(LIBS) -lcurl -o $@ @@ -163,7 +167,7 @@ endif distclean: clean rm -f Makefile *~ .depend -install: +install: $(APPS) install -d -m 0755 $(DESTDIR)$(bindir) install -m 0755 $(INSTALLFLAGS) $(APPS) $(DESTDIR)$(bindir) diff --git a/util/clixon_util_dispatcher b/util/clixon_util_dispatcher deleted file mode 100755 index 4601c6a9c4dfb0e5784807463783c5fcae70dac2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18608 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 Date: Thu, 14 Oct 2021 09:14:12 +0200 Subject: [PATCH 03/10] Typo: forgot clixon_util_dispatcher.c --- util/clixon_util_dispatcher.c | 190 ++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 util/clixon_util_dispatcher.c diff --git a/util/clixon_util_dispatcher.c b/util/clixon_util_dispatcher.c new file mode 100644 index 00000000..45571daa --- /dev/null +++ b/util/clixon_util_dispatcher.c @@ -0,0 +1,190 @@ +/* + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2021 Olof Hagsand and Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + +* Utility for testing path dispatcher +* Everything is run by options and order is significant which makes it a little special. +* For example: +* clixon_util_dispatcher -r -c / : +* Register cb1 with default path "/" and arg NULL, call with path / +* clixon_util_dispatcher -i 2 -p /foo -a bar -r -c /bar -c /fie +* Register cb2 with path "/foo" and arg bar, call with path /bar then /fie +*/ + +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clixon */ +#include "clixon/clixon.h" +#include "clixon/clixon_backend.h" + +/* Command line options to be passed to getopt(3) */ +#define DISPATCHER_OPTS "hD:a:i:p:rc:" + +static int +usage(char *argv0) +{ + fprintf(stderr, "usage:%s [options]\n" + "where options are\n" + "\t-h \t\tHelp\n" + "\t-D \t Debug - print dispatch tree\n" + "\t-a \t Argument to callback (default: NULL)\n" + "\t-i \t Function index: 1..3 (default: 1)\n" + "\t-p \t Registered path (default: /)\n" + "\t-r \t Register callback (based on -a/-i/-p setting)\n" + "\t-c \t Call dispatcher with path\n", + argv0 + ); + exit(0); +} + +/*! Function to handle a path + * + * @param[in] h Generic handler + * @param[in] xpath Registered XPath using canonical prefixes + * @param[in] userargs Per-call user arguments + * @param[in] arg Per-path user argument + *( +/ * Make a CB() macro to generate simple callbacks that just prints the path and arg + */ +#define CB(i) static int cb##i(void *h0, char *xpath, void *userargs, void *arg) { fprintf(stdout, "%s %s\n", __FUNCTION__, (char*)arg); return 0; } + +CB(1) +CB(2) + +int +main(int argc, + char **argv) +{ + int retval = -1; + char *argv0 = argv[0]; + int logdst = CLICON_LOG_STDERR; + int dbg = 0; + int c; + char *arg = NULL; + handler_function fn = cb1; + dispatcher_entry_t *htable = NULL; + int ret; + char *regpath = "/"; /* Register path */ + + /* In the startup, logs to stderr & debug flag set later */ + clicon_log_init("dispatcher", LOG_DEBUG, logdst); + + optind = 1; + opterr = 0; + while ((c = getopt(argc, argv, DISPATCHER_OPTS)) != -1) + switch (c) { + case 'h': + usage(argv0); + break; + case 'D': + if (sscanf(optarg, "%d", &dbg) != 1) + usage(argv0); + break; + + case 'a' : + case 'i' : + case 'p' : + case 'r' : + case 'c' : + break; + default: + usage(argv[0]); + break; + } + /* + * Logs, error and debug to stderr or syslog, set debug level + */ + clicon_log_init("xpath", dbg?LOG_DEBUG:LOG_INFO, logdst); + + clicon_debug_init(dbg, NULL); + + /* Now rest of options */ + opterr = 0; + optind = 1; + while ((c = getopt(argc, argv, DISPATCHER_OPTS)) != -1){ + switch (c) { + case 'D' : /* debug */ + break; /* see above */ + case 'a' : /* arg string */ + arg = optarg; + break; + case 'i' : /* dispatcher function: 1..3 */ + switch (atoi(optarg)){ + case 1: fn = cb1; break; + case 2: fn = cb2; break; + // case 3: fn = cb3; break; + } + break; + case 'p' : /* register path */ + regpath = optarg; + break; + case 'r' :{ /* register callback based on -a/-i/-p*/ + dispatcher_definition x = {regpath, fn, arg}; + if (dispatcher_register_handler(&htable, &x) < 0) + goto done; + break; + } + case 'c':{ /* Execute a call using path */ + char *path = optarg; + if ((ret = dispatcher_call_handlers(htable, NULL, path, NULL)) < 0) + goto done; + fprintf(stderr, "path:%s ret:%d\n", path, ret); + break; + } + default: + usage(argv[0]); + break; + } + } + if (dbg) + dispatcher_print(stderr, 0, htable); + dispatcher_free(htable); + retval = 0; + done: + return retval; +} From a242cf47bdb741025907edd7003205fb597a9f7e Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 14 Oct 2021 13:14:10 +0200 Subject: [PATCH 04/10] Pagination callback modifications: ensure xml is bound to yang, removed code not used (eg remaining) and avoiding an extra xpath_vec call. Moved debug prints from plugin-callback-one to plugin-callback-all Fixed memory error in data-cvec access function --- apps/backend/backend_get.c | 101 ++++++++++++++++++++++----------- apps/backend/backend_plugin.c | 8 ++- apps/cli/cli_show.c | 6 +- example/main/example_backend.c | 17 +++++- lib/src/clixon_data.c | 18 +++++- lib/src/clixon_dispatcher.c | 12 ++-- test/test_pagination_state.sh | 18 ++++-- 7 files changed, 125 insertions(+), 55 deletions(-) diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index 586dc364..1d814516 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -284,9 +284,10 @@ get_client_statedata(clicon_handle h, * @param[in] h Clicon handle * @param[in] yspec Yang spec * @param[in] xret Result XML tree + * @param[in] xvec xpath lookup result on xret + * @param[in] xlen length of xvec * @param[in] xpath XPath point to object to get * @param[in] nsc Namespace context of xpath - * @param[out] x1p Pointer to first matching object if any * @retval 0 OK * @retval -1 Error */ @@ -294,17 +295,14 @@ static int filter_xpath_again(clicon_handle h, yang_stmt *yspec, cxobj *xret, + cxobj **xvec, + size_t xlen, char *xpath, - cvec *nsc, - cxobj **x1p) + cvec *nsc) { int retval = -1; - cxobj **xvec = NULL; - size_t xlen; int i; - if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) - goto done; /* If vectors are specified then mark the nodes found and * then filter out everything else, * otherwise return complete tree. @@ -326,12 +324,8 @@ filter_xpath_again(clicon_handle h, /* Add default recursive values */ if (xml_default_recurse(xret, 0) < 0) goto done; - if (xlen && x1p) - *x1p = xvec[0]; retval = 0; done: - if (xvec) - free(xvec); return retval; } @@ -339,6 +333,8 @@ filter_xpath_again(clicon_handle h, * * @param[in] h Clicon handle * @param[in] xret Result XML tree + * @param[in] xvec xpath lookup result on xret + * @param[in] xlen length of xvec * @param[in] xpath XPath point to object to get * @param[in] nsc Namespace context of xpath * @param[in] username User name for NACM access @@ -350,6 +346,8 @@ filter_xpath_again(clicon_handle h, static int get_nacm_and_reply(clicon_handle h, cxobj *xret, + cxobj **xvec, + size_t xlen, char *xpath, cvec *nsc, char *username, @@ -357,15 +355,11 @@ get_nacm_and_reply(clicon_handle h, cbuf *cbret) { int retval = -1; - cxobj **xvec = NULL; - size_t xlen; cxobj *xnacm = NULL; /* Pre-NACM access step */ xnacm = clicon_nacm_cache(h); if (xnacm != NULL){ /* Do NACM validation */ - if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) - goto done; /* NACM datanode/module read validation */ if (nacm_datanode_read(h, xret, xvec, xlen, username, xnacm) < 0) goto done; @@ -383,8 +377,6 @@ get_nacm_and_reply(clicon_handle h, cprintf(cbret, ""); retval = 0; done: - if (xvec) - free(xvec); return retval; } @@ -454,11 +446,7 @@ get_list_pagination(clicon_handle h, int retval = -1; uint32_t offset = 0; uint32_t limit = 0; - char *direction = NULL; - char *sort = NULL; - char *where = NULL; cbuf *cbpath = NULL; - cxobj *x; int list_config; yang_stmt *ylist; cxobj *xerr = NULL; @@ -468,7 +456,15 @@ get_list_pagination(clicon_handle h, int ret; uint32_t iddb; /* DBs lock, if any */ int locked; - cxobj *x1 = NULL; + cbuf *cberr = NULL; + cxobj **xvec = NULL; + size_t xlen; +#ifdef NOTYET + cxobj *x; + char *direction = NULL; + char *sort = NULL; + char *where = NULL; +#endif /* Check if list/leaf-list */ if (yang_path_arg(yspec, xpath, &ylist) < 0) @@ -504,11 +500,6 @@ get_list_pagination(clicon_handle h, goto done; goto ok; } -#if 0 /* XXX For now state lists are not implemenetd */ - if (netconf_operation_not_supported(cbret, "protocol", "List pagination for state lists is not yet implemented") < 0) - goto done; - goto ok; -#endif } /* offset */ if ((ret = element2value(h, xe, "offset", "none", cbret, &offset)) < 0) @@ -516,6 +507,7 @@ get_list_pagination(clicon_handle h, /* limit */ if (ret && (ret = element2value(h, xe, "limit", "unbounded", cbret, &limit)) < 0) goto done; +#ifdef NOTYET /* direction */ if (ret && (x = xml_find_type(xe, NULL, "direction", CX_ELMNT)) != NULL){ direction = xml_body(x); @@ -535,7 +527,7 @@ get_list_pagination(clicon_handle h, /* where */ if (ret && (x = xml_find_type(xe, NULL, "where", CX_ELMNT)) != NULL) where = xml_body(x); - +#endif /* Read config */ switch (content){ case CONTENT_CONFIG: /* config data only */ @@ -553,8 +545,10 @@ get_list_pagination(clicon_handle h, cprintf(cbpath, "%s", xpath); else cprintf(cbpath, "/"); +#ifdef NOTYET if (where) cprintf(cbpath, "[%s]", where); +#endif if (offset){ cprintf(cbpath, "[%u <= position()", offset); if (limit) @@ -607,11 +601,40 @@ get_list_pagination(clicon_handle h, offset, limit, xret)) < 0) goto done; - if (ret == 0) + if (ret == 0){ + if ((cberr = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "cbuf_new"); + goto done; + } + /* error reason should be in clicon_err_reason */ + cprintf(cberr, "Internal error, pagination state callback invalid return : %s", + clicon_err_reason); + if (netconf_operation_failed_xml(&xerr, "application", cbuf_get(cberr)) < 0) + goto done; + if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) + goto done; goto ok; + } + + /* System makes the binding */ + if ((ret = xml_bind_yang(xret, YB_MODULE, yspec, &xerr)) < 0) + goto done; + if (ret == 0){ + if (clicon_debug_get() && xret) + clicon_log_xml(LOG_DEBUG, xret, "Yang bind pagination state"); + if (clixon_netconf_internal_error(xerr, + ". Internal error, state callback returned invalid XML", + NULL) < 0) + goto done; + if (clicon_xml2cbuf(cbret, xerr, 0, 0, -1) < 0) + goto done; + goto ok; + } } + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) + goto done; /* Help function to filter out anything that is outside of xpath */ - if (filter_xpath_again(h, yspec, xret, xpath, nsc, &x1) < 0) + if (filter_xpath_again(h, yspec, xret, xvec, xlen, xpath, nsc) < 0) goto done; #ifdef LIST_PAGINATION_REMAINING /* Add remaining attribute Sec 3.1.5: @@ -639,17 +662,21 @@ get_list_pagination(clicon_handle h, cbuf_free(cba); } #endif /* LIST_PAGINATION_REMAINING */ - if (get_nacm_and_reply(h, xret, xpath, nsc, username, depth, cbret) < 0) + if (get_nacm_and_reply(h, xret, xvec, xlen, xpath, nsc, username, depth, cbret) < 0) goto done; ok: retval = 0; done: + if (xvec) + free(xvec); if (cbmsg) cbuf_free(cbmsg); if (cbpath) cbuf_free(cbpath); if (xerr) xml_free(xerr); + if (cberr) + cbuf_free(cberr); if (xret) xml_free(xret); return retval; @@ -696,6 +723,10 @@ get_common(clicon_handle h, int list_pagination = 0; char *valstr; cxobj *x; +#if 1 + cxobj **xvec = NULL; + size_t xlen; +#endif clicon_debug(1, "%s", __FUNCTION__); username = clicon_username_get(h); @@ -852,14 +883,18 @@ get_common(clicon_handle h, if (xml_apply(xret, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) goto done; } - if (filter_xpath_again(h, yspec, xret, xpath, nsc, NULL) < 0) + if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath?xpath:"/") < 0) goto done; - if (get_nacm_and_reply(h, xret, xpath, nsc, username, depth, cbret) < 0) + if (filter_xpath_again(h, yspec, xret, xvec, xlen, xpath, nsc) < 0) + goto done; + if (get_nacm_and_reply(h, xret, xvec, xlen, xpath, nsc, username, depth, cbret) < 0) goto done; ok: retval = 0; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + if (xvec) + free(xvec); if (xret) xml_free(xret); if (cbreason) diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index a3602170..c8bff188 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -108,6 +108,7 @@ clixon_plugin_reset_all(clicon_handle h, int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_reset_one(cp, h, db) < 0) @@ -160,6 +161,7 @@ clixon_plugin_pre_daemon_all(clicon_handle h) int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_pre_daemon_one(cp, h) < 0) @@ -213,6 +215,7 @@ clixon_plugin_daemon_all(clicon_handle h) int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); /* Loop through all plugins, call callbacks in each */ while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (clixon_plugin_daemon_one(cp, h) < 0) @@ -259,7 +262,6 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, plgstatedata_t *fn; /* Plugin statedata fn */ cxobj *x = NULL; - clicon_debug(1, "%s %s", __FUNCTION__, clixon_plugin_name_get(cp)); if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){ if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; @@ -407,7 +409,6 @@ clixon_plugin_lockdb_one(clixon_plugin_t *cp, int retval = -1; plglockdb_t *fn; /* Plugin statedata fn */ - clicon_debug(1, "%s %s", __FUNCTION__, clixon_plugin_name_get(cp)); if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){ if (fn(h, db, lock, id) < 0) goto done; @@ -605,6 +606,7 @@ plugin_transaction_begin_all(clicon_handle h, int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_begin_one(cp, h, td) < 0) goto done; @@ -899,6 +901,7 @@ plugin_transaction_end_all(clicon_handle h, int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_end_one(cp, h, td) < 0) goto done; @@ -942,6 +945,7 @@ plugin_transaction_abort_all(clicon_handle h, int retval = -1; clixon_plugin_t *cp = NULL; + clicon_debug(1, "%s", __FUNCTION__); while ((cp = clixon_plugin_each(h, cp)) != NULL) { if (plugin_transaction_abort_one(cp, h, td) < 0) ; /* dont abort on error */ diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index 76c2166d..07ba04ec 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -919,6 +919,7 @@ cli_pagination(clicon_handle h, uint32_t limit = 0; cxobj **xvec = NULL; size_t xlen; + int locked = 0; if (cvec_len(argv) != 5){ clicon_err(OE_PLUGIN, 0, "Expected usage: "); @@ -950,6 +951,7 @@ cli_pagination(clicon_handle h, goto done; if (clicon_rpc_lock(h, "running") < 0) goto done; + locked++; for (i = 0;; i++){ if (clicon_rpc_get_pageable_list(h, "running", xpath, nsc, CONTENT_ALL, @@ -1000,10 +1002,10 @@ cli_pagination(clicon_handle h, xvec = NULL; } } /* for i */ - if (clicon_rpc_unlock(h, "running") < 0) - goto done; retval = 0; done: + if (locked) + clicon_rpc_unlock(h, "running"); if (xvec) free(xvec); if (xret) diff --git a/example/main/example_backend.c b/example/main/example_backend.c index ae2fe8a1..947d9d70 100644 --- a/example/main/example_backend.c +++ b/example/main/example_backend.c @@ -514,7 +514,10 @@ example_statefile(clicon_handle h, xml_flag_set(x1, XML_FLAG_MARK); xml_apply_ancestor(x1, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE); } - if (xml_copy_marked(xt, xstate) < 0) /* Copy the marked elements */ + /* Copy the marked elements: + * note is yang-aware for copying of keys which means XML must be bound + */ + if (xml_copy_marked(xt, xstate) < 0) goto done; /* Unmark original tree */ if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)(XML_FLAG_MARK|XML_FLAG_CHANGE)) < 0) @@ -614,6 +617,9 @@ example_pagination(void *h0, xml_flag_set(x1, XML_FLAG_MARK); xml_apply_ancestor(x1, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE); } + /* Copy the marked elements: + * note is yang-aware for copying of keys which means XML must be bound + */ if (xml_copy_marked(xt, xstate) < 0) /* Copy the marked elements */ goto done; /* Unmark original tree */ @@ -1160,6 +1166,7 @@ example_daemon(clicon_handle h) int ret; FILE *fp = NULL; yang_stmt *yspec; + cxobj *xerr = NULL; /* Read state file (or should this be in init/start?) */ if (_state && _state_file && _state_file_cached){ @@ -1168,8 +1175,14 @@ example_daemon(clicon_handle h) clicon_err(OE_UNIX, errno, "open(%s)", _state_file); goto done; } - if ((ret = clixon_xml_parse_file(fp, YB_MODULE, yspec, &_state_xml_cache, NULL)) < 1) + /* Need to be yang bound for eg xml_copy_marked() in example_pagination + */ + if ((ret = clixon_xml_parse_file(fp, YB_MODULE, yspec, &_state_xml_cache, &xerr)) < 0) goto done; + if (ret == 0){ + xml_print(stderr, xerr); + goto done; + } } retval = 0; done: diff --git a/lib/src/clixon_data.c b/lib/src/clixon_data.c index 1c0970e3..7f21ec6e 100644 --- a/lib/src/clixon_data.c +++ b/lib/src/clixon_data.c @@ -227,6 +227,11 @@ clicon_data_cvec_set(clicon_handle h, const char *name, cvec *cvv) { + cvec *cvv0 = NULL; + + clicon_ptr_get(h, name, (void**)&cvv0); + if (cvv0) + cvec_free(cvv0); return clicon_ptr_set(h, name, cvv); } @@ -238,6 +243,11 @@ int clicon_data_cvec_del(clicon_handle h, const char *name) { + cvec *cvv = NULL; + + clicon_ptr_get(h, name, (void**)&cvv); + if (cvv) + cvec_free(cvv); return clicon_ptr_del(h, name); } @@ -377,9 +387,13 @@ clicon_nacm_ext(clicon_handle h) */ int clicon_nacm_ext_set(clicon_handle h, - cxobj *xn) + cxobj *x) { - return clicon_ptr_set(h, "nacm_xml", xn); + cxobj *x0 = NULL; + + if ((x0 = clicon_nacm_ext(h)) != NULL) + xml_free(x0); + return clicon_ptr_set(h, "nacm_xml", x); } /*! Get NACM (rfc 8341) XML parse tree cache diff --git a/lib/src/clixon_dispatcher.c b/lib/src/clixon_dispatcher.c index 05b3f911..b3793fb5 100644 --- a/lib/src/clixon_dispatcher.c +++ b/lib/src/clixon_dispatcher.c @@ -68,10 +68,6 @@ * [b=] * [b] * - * NOTE 1: there is not a mechanism to free the created structures since - * it is intended that this tree is created only at startup. if use case - * changes, this function is trivial. - * * NOTE 2: there is no attempt to optimize list searching here, sorry. I * do not think that the known use cases will get big enough to make the * tree get too large. I do not recommend that you encode every possible @@ -439,10 +435,10 @@ dispatcher_register_handler(dispatcher_entry_t **root, * * @param[in] handle * @param[in] root - * @param[in] path - * @retval 1 OK - * @retval 0 Invalid - * @retval -1 Error + * @param[in] path Note must be on the form: /a/b (no keys) + * @retval 1 OK + * @retval 0 Invalid + * @retval -1 Error */ int dispatcher_call_handlers(dispatcher_entry_t *root, diff --git a/test/test_pagination_state.sh b/test/test_pagination_state.sh index e9ef8490..5ba12df0 100755 --- a/test/test_pagination_state.sh +++ b/test/test_pagination_state.sh @@ -17,8 +17,6 @@ cfg=$dir/conf.xml fexample=$dir/example-social.yang fstate=$dir/mystate.xml -xpath=/es:audit-logs/es:audit-log - # For 1M test,m use an external file since the generation takes considerable time #fstate=~/tmp/mystate.xml @@ -110,7 +108,7 @@ function testrun_start() fi sudo pkill -f clixon_backend # to be sure - new "start backend -s init -f $cfg -- -siS $fstate -X $xpath" + new "start backend -s init -f $cfg -- -siS $fstate -x $xpath" start_backend -s init -f $cfg -- -siS $fstate -x $xpath fi @@ -132,19 +130,26 @@ function testrun_stop() fi } -testrun_start "/es:members/es:member[es:member-id='alice']/es:stats/es:numbers" +xpath0="/es:members/es:member[es:member-id='alice']/es:stats" +xpath="$xpath0/es:numbers" +testrun_start $xpath new "NETCONF get leaf-list member/numbers 0-10 alice" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOtrue010]]>]]>" "^alicepublic345678]]>]]>$" # negative new "NETCONF get container, expect fail" -expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOtrue010]]>]]>" "^applicationinvalid-valueerrorlist-pagination is enabled but target is not list or leaf-list]]>]]>$" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOtrue010]]>]]>" "^applicationinvalid-valueerrorlist-pagination is enabled but target is not list or leaf-list]]>]]>$" + +xpath="/es:members/es:member[es:member-id='bob']/es:stats/es:numbers" +new "NETCONF get leaf-list member/numbers 0-10 bob" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOtrue010]]>]]>" "^bobpublic131415161718]]>]]>$" testrun_stop #---------------------------- -testrun_start "/es:members/es:member/es:stats/es:numbers" +xpath="/es:members/es:member/es:stats/es:numbers" +testrun_start $xpath new "NETCONF get leaf-list member/numbers all" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOtrue010]]>]]>" "^alicepublic345678bobpublic13141516]]>]]>$" @@ -169,6 +174,7 @@ fi # interactive unset validatexml unset perfnr unset xpath +unset xpath0 rm -rf $dir From 764e9c628cb9c19bf109abfa89c08a4230be1746 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 19 Oct 2021 16:42:34 +0200 Subject: [PATCH 05/10] Added checks of changed handlers or blocked signal after plugin function calls --- CHANGELOG.md | 1 + apps/backend/backend_commit.c | 6 ++ apps/backend/backend_plugin.c | 72 +++++++++++++++++++ apps/cli/cli_plugin.c | 44 +++++++++++- lib/clixon/clixon_plugin.h | 14 ++++ lib/src/clixon_plugin.c | 127 ++++++++++++++++++++++++++++++++++ 6 files changed, 263 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 560857f1..5b2022be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Developers may need to change their code ### Minor features +* Added checks of changed handlers or blocked signal after plugin function calls * Added set/get pointer API to clixon_data: * clicon_ptr_get(), clicon_ptr_set(), * Restconf YANG PATCH according to RFC 8072 diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index 8abcbcbc..e5a141c7 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -937,10 +937,16 @@ from_client_restart_one(clicon_handle h, goto done; /* Application may define extra xml in its reset function*/ if ((resetfn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if ((retval = resetfn(h, db)) < 0) { clicon_debug(1, "plugin_start() failed"); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } /* 1. Start transaction */ if ((td = transaction_new()) == NULL) diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index c8bff188..0d4565b7 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -82,12 +82,18 @@ clixon_plugin_reset_one(clixon_plugin_t *cp, plgreset_t *fn; /* callback */ if ((fn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, db) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Reset callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -133,6 +139,10 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp, plgdaemon_t *fn; /* Daemonize plugin callback function */ if ((fn = clixon_plugin_api_get(cp)->ca_pre_daemon) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Pre-daemon callback in plugin:\ @@ -140,6 +150,8 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -186,12 +198,18 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp, plgdaemon_t *fn; /* Daemonize plugin callback function */ if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Daemon callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -265,12 +283,18 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){ if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, nsc, xpath, x) < 0){ if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: State callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, clixon_plugin_name_get(cp)); goto fail; /* Dont quit here on user callbacks */ } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } if (xp && x) *xp = x; @@ -410,8 +434,14 @@ clixon_plugin_lockdb_one(clixon_plugin_t *cp, plglockdb_t *fn; /* Plugin statedata fn */ if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, db, lock, id) < 0) goto done; + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -579,12 +609,18 @@ plugin_transaction_begin_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -632,12 +668,18 @@ plugin_transaction_validate_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -683,12 +725,18 @@ plugin_transaction_complete_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -766,12 +814,18 @@ plugin_transaction_commit_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -825,12 +879,18 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -876,12 +936,18 @@ plugin_transaction_end_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -920,12 +986,18 @@ plugin_transaction_abort_one(clixon_plugin_t *cp, trans_cb_t *fn; if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ clicon_log(LOG_NOTICE, "%s: Plugin '%s' callback does not make clicon_err call on error", __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } + if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + goto done; } retval = 0; done: diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 89f9294f..34c1888b 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -522,6 +522,47 @@ cli_handler_err(FILE *f) return 0; } +/*! Variant of eval for context checking + * @see cligen_eval + */ +int +cligen_clixon_eval(cligen_handle h, + cg_obj *co, + cvec *cvv) +{ + struct cg_callback *cc; + int retval = 0; + cvec *argv; + + if (h) + cligen_co_match_set(h, co); + for (cc = co->co_callbacks; cc; cc=cc->cc_next){ + /* Vector cvec argument to callback */ + if (cc->cc_fn_vec){ + plugin_context_t pc = {0,}; + argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL; + cligen_fn_str_set(h, cc->cc_fn_str); + if (plugin_context_get(&pc) < 0) + break; + if ((retval = (*cc->cc_fn_vec)( + cligen_userhandle(h)?cligen_userhandle(h):h, + cvv, + argv)) < 0){ + if (argv != NULL) + cvec_free(argv); + cligen_fn_str_set(h, NULL); + break; + } + if (plugin_context_check(&pc, "CLIgen", cc->cc_fn_str) < 0) + break; + if (argv != NULL) + cvec_free(argv); + cligen_fn_str_set(h, NULL); + } + } + return retval; +} + /*! Evaluate a matched command * @param[in] h Clicon handle * @param[in] cmd The command string @@ -541,7 +582,8 @@ clicon_eval(clicon_handle h, cli_output_reset(); if (!cligen_exiting(cli_cligen(h))) { clicon_err_reset(); - if ((retval = cligen_eval(cli_cligen(h), match_obj, cvv)) < 0) { + + if ((retval = cligen_clixon_eval(cli_cligen(h), match_obj, cvv)) < 0) { #if 0 /* This is removed since we get two error messages on failure. But maybe only sometime? Both a real log when clicon_err is called, and the here again. diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index ffebc982..e487b035 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -337,6 +337,17 @@ struct clixon_plugin_api{ #define ca_trans_abort u.cau_backend.cb_trans_abort #define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade +/*! Structure for checking status before and after a plugin call + * Currently signal settings: blocked and handlers, could be extended to more + * @see plugin_context_check + */ +struct plugin_context { + sigset_t pc_sigset; /* See sigprocmask(2) */ + struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ + int pc_status; /* 0: OK, -1: fail */ +}; +typedef struct plugin_context plugin_context_t; + /* * Macros */ @@ -375,6 +386,9 @@ int clixon_plugins_load(clicon_handle h, const char *function, const char *dir, int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin_t **cpp); +int plugin_context_get(plugin_context_t *pc); +int plugin_context_check(plugin_context_t *pc, const char *name, const char *fn); + int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h); int clixon_plugin_start_all(clicon_handle h); diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 20ea2a99..9a804cdd 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -330,6 +331,7 @@ plugin_load_one(clicon_handle h, clixon_plugin_t *cp = NULL; char *name; char *p; + plugin_context_t pc = {0,}; clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function); dlerror(); /* Clear any existing error */ @@ -348,6 +350,11 @@ plugin_load_one(clicon_handle h, goto done; } clicon_err_reset(); + + + if (plugin_context_get(&pc) < 0) + goto done; + if ((api = initfn(h)) == NULL) { if (!clicon_errno){ /* if clicon_err() is not called then log and continue */ clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file); @@ -359,6 +366,9 @@ plugin_load_one(clicon_handle h, goto done; } } + if (plugin_context_check(&pc, file, __FUNCTION__) < 0) + goto done; + /* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */ if ((cp = (clixon_plugin_t *)malloc(sizeof(struct clixon_plugin))) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); @@ -483,6 +493,93 @@ done: return retval; } +/*! Get system context, eg signal procmask (for blocking) and sigactions + * Call this before a plugin + * @see plugin_context_check + */ +int +plugin_context_get(plugin_context_t *pc) +{ + int retval = -1; + int i; + + if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){ + clicon_err(OE_UNIX, errno, "sigprocmask"); + goto done; + } + for (i=1; i<32; i++){ + if (sigaction(i, NULL, &pc->pc_sigaction_vec[i]) < 0){ + clicon_err(OE_UNIX, errno, "sigaction"); + goto done; + } + /* Mask SA_RESTORER: Not intended for application use. + * Note that it may not be included in user space so may be hardcoded below + */ +#ifdef SA_RESTORER + pc->pc_sigaction_vec[i].sa_flags &= ~SA_RESTORER; +#else + pc->pc_sigaction_vec[i].sa_flags &= ~0x04000000; +#endif + } + retval = 0; + done: + return retval; +} + +/*! Given an existing, old plugin context, check if anytjing has changed + * @param[in,out] oldpc Old plugin context, status will be returned inside oldpc + * @param[in] name Name of plugin for logging + * @param[in] fn Name of callback + * @retval -1 Error + * @retval 0 OK + * @see plugin_context_get + */ +int +plugin_context_check(plugin_context_t *oldpc, + const char *name, + const char *fn) +{ + int retval = -1; + int failed; + int i; + plugin_context_t newpc = {0, }; + + if (plugin_context_get(&newpc) < 0) + goto done; + for (i=1; i<32; i++){ + failed = 0; + if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc.pc_sigset, i)){ + clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, + name, fn, strsignal(i), i, + sigismember(&oldpc->pc_sigset, i), + sigismember(&newpc.pc_sigset, i) + ); + failed++; + } + if (oldpc->pc_sigaction_vec[i].sa_flags != newpc.pc_sigaction_vec[i].sa_flags){ + clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed flags of signal %s(%d) from 0x%x to 0x%x", __FUNCTION__, + name, fn, strsignal(i), i, + oldpc->pc_sigaction_vec[i].sa_flags, + newpc.pc_sigaction_vec[i].sa_flags);; + failed++; + } + if (oldpc->pc_sigaction_vec[i].sa_sigaction != newpc.pc_sigaction_vec[i].sa_sigaction){ + clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed action of signal %s(%d) from %p to %p", __FUNCTION__, + name, fn, strsignal(i), i, + oldpc->pc_sigaction_vec[i].sa_sigaction, + newpc.pc_sigaction_vec[i].sa_sigaction); + failed++; + } + if (failed){ + oldpc->pc_status = -1; + } + /* assert(oldpc->pc_status == 0); */ + } + retval = 0; + done: + return retval; +} + /*! Call single plugin start callback * @param[in] cp Plugin handle * @param[in] h Clixon handle @@ -497,12 +594,18 @@ clixon_plugin_start_one(clixon_plugin_t *cp, plgstart_t *fn; /* Plugin start */ if ((fn = cp->cp_api.ca_start) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Start callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); goto done; } + if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -545,12 +648,18 @@ clixon_plugin_exit_one(clixon_plugin_t *cp, plgexit_t *fn; if ((fn = cp->cp_api.ca_exit) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Exit callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); goto done; } + if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + goto done; if (dlclose(cp->cp_handle) != 0) { error = (char*)dlerror(); clicon_err(OE_PLUGIN, errno, "dlclose: %s", error ? error : "Unknown error"); @@ -611,12 +720,18 @@ clixon_plugin_auth_one(clixon_plugin_t *cp, clicon_debug(1, "%s", __FUNCTION__); if ((fn = cp->cp_api.ca_auth) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if ((retval = fn(h, req, auth_type, authp)) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Auth callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); goto done; } + if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + goto done; } else retval = 0; /* Ignored / no callback */ @@ -688,12 +803,18 @@ clixon_plugin_extension_one(clixon_plugin_t *cp, plgextension_t *fn; /* Plugin extension fn */ if ((fn = cp->cp_api.ca_extension) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, yext, ys) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Extension callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); goto done; } + if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + goto done; } retval = 0; done: @@ -752,12 +873,18 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, datastore_upgrade_t *fn; if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){ + plugin_context_t pc = {0,}; + + if (plugin_context_get(&pc) < 0) + goto done; if (fn(h, db, xt, msd) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Datastore upgrade callback in plugin: %s returned -1 but did not make a clicon_err call", __FUNCTION__, cp->cp_name); goto done; } + if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + goto done; } retval = 0; done: From c93348d8d592d250cfc5526c64145ed2ee1639a0 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Tue, 19 Oct 2021 17:28:13 +0200 Subject: [PATCH 06/10] Hide plugin check handler struct with a handler --- apps/backend/backend_commit.c | 9 ++- apps/backend/backend_plugin.c | 115 ++++++++++++++++------------- apps/cli/cli_plugin.c | 12 ++- lib/clixon/clixon_plugin.h | 17 ++--- lib/src/clixon_plugin.c | 135 ++++++++++++++++++++-------------- 5 files changed, 163 insertions(+), 125 deletions(-) diff --git a/apps/backend/backend_commit.c b/apps/backend/backend_commit.c index e5a141c7..0f71b19e 100644 --- a/apps/backend/backend_commit.c +++ b/apps/backend/backend_commit.c @@ -931,21 +931,20 @@ from_client_restart_one(clicon_handle h, yang_stmt *yspec; int i; cxobj *xn; + plugin_context_t *pc = NULL; yspec = clicon_dbspec_yang(h); if (xmldb_db_reset(h, db) < 0) goto done; /* Application may define extra xml in its reset function*/ if ((resetfn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if ((retval = resetfn(h, db)) < 0) { clicon_debug(1, "plugin_start() failed"); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } /* 1. Start transaction */ @@ -1027,6 +1026,8 @@ from_client_restart_one(clicon_handle h, goto fail; retval = 1; done: + if (pc) + free(pc); if (td){ xmldb_get0_free(h, &td->td_target); transaction_free(td); diff --git a/apps/backend/backend_plugin.c b/apps/backend/backend_plugin.c index 0d4565b7..6d1c1daf 100644 --- a/apps/backend/backend_plugin.c +++ b/apps/backend/backend_plugin.c @@ -78,13 +78,12 @@ clixon_plugin_reset_one(clixon_plugin_t *cp, clicon_handle h, char *db) { - int retval = -1; - plgreset_t *fn; /* callback */ + int retval = -1; + plgreset_t *fn; /* callback */ + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_reset) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, db) < 0) { if (clicon_errno < 0) @@ -92,11 +91,13 @@ clixon_plugin_reset_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -137,12 +138,12 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp, { int retval = -1; plgdaemon_t *fn; /* Daemonize plugin callback function */ + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_pre_daemon) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; + if (fn(h) < 0) { if (clicon_errno < 0) clicon_log(LOG_WARNING, "%s: Internal error: Pre-daemon callback in plugin:\ @@ -150,11 +151,13 @@ clixon_plugin_pre_daemon_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -196,11 +199,10 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp, { int retval = -1; plgdaemon_t *fn; /* Daemonize plugin callback function */ + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_daemon) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h) < 0) { if (clicon_errno < 0) @@ -208,11 +210,13 @@ clixon_plugin_daemon_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -279,13 +283,12 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, int retval = -1; plgstatedata_t *fn; /* Plugin statedata fn */ cxobj *x = NULL; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_statedata) != NULL){ if ((x = xml_new(DATASTORE_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL) goto done; - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, nsc, xpath, x) < 0){ if (clicon_errno < 0) @@ -293,13 +296,15 @@ clixon_plugin_statedata_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto fail; /* Dont quit here on user callbacks */ } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } if (xp && x) *xp = x; retval = 1; done: + if (pc) + free(pc); return retval; fail: retval = 0; @@ -432,19 +437,20 @@ clixon_plugin_lockdb_one(clixon_plugin_t *cp, { int retval = -1; plglockdb_t *fn; /* Plugin statedata fn */ + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_lockdb) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, db, lock, id) < 0) goto done; - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -607,11 +613,10 @@ plugin_transaction_begin_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_begin) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -619,11 +624,13 @@ plugin_transaction_begin_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -666,11 +673,10 @@ plugin_transaction_validate_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; - - if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){ - plugin_context_t pc = {0,}; + plugin_context_t *pc = NULL; - if (plugin_context_get(&pc) < 0) + if ((fn = clixon_plugin_api_get(cp)->ca_trans_validate) != NULL){ + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -678,11 +684,13 @@ plugin_transaction_validate_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -723,11 +731,10 @@ plugin_transaction_complete_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_complete) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -735,11 +742,13 @@ plugin_transaction_complete_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -812,11 +821,10 @@ plugin_transaction_commit_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -824,11 +832,13 @@ plugin_transaction_commit_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -877,11 +887,10 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_commit_done) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -889,11 +898,13 @@ plugin_transaction_commit_done_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -934,11 +945,10 @@ plugin_transaction_end_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_end) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -946,11 +956,13 @@ plugin_transaction_end_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -984,11 +996,10 @@ plugin_transaction_abort_one(clixon_plugin_t *cp, { int retval = -1; trans_cb_t *fn; + plugin_context_t *pc = NULL; if ((fn = clixon_plugin_api_get(cp)->ca_trans_abort) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, (transaction_data)td) < 0){ if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */ @@ -996,11 +1007,13 @@ plugin_transaction_abort_one(clixon_plugin_t *cp, __FUNCTION__, clixon_plugin_name_get(cp)); goto done; } - if (plugin_context_check(&pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) + if (plugin_context_check(pc, clixon_plugin_name_get(cp), __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index 34c1888b..cf52bd7b 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -533,16 +533,16 @@ cligen_clixon_eval(cligen_handle h, struct cg_callback *cc; int retval = 0; cvec *argv; + plugin_context_t *pc = NULL; if (h) cligen_co_match_set(h, co); for (cc = co->co_callbacks; cc; cc=cc->cc_next){ /* Vector cvec argument to callback */ if (cc->cc_fn_vec){ - plugin_context_t pc = {0,}; argv = cc->cc_cvec ? cvec_dup(cc->cc_cvec) : NULL; cligen_fn_str_set(h, cc->cc_fn_str); - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) break; if ((retval = (*cc->cc_fn_vec)( cligen_userhandle(h)?cligen_userhandle(h):h, @@ -553,13 +553,19 @@ cligen_clixon_eval(cligen_handle h, cligen_fn_str_set(h, NULL); break; } - if (plugin_context_check(&pc, "CLIgen", cc->cc_fn_str) < 0) + if (plugin_context_check(pc, "CLIgen", cc->cc_fn_str) < 0) break; + if (pc){ + free(pc); + pc = NULL; + } if (argv != NULL) cvec_free(argv); cligen_fn_str_set(h, NULL); } } + if (pc) + free(pc); return retval; } diff --git a/lib/clixon/clixon_plugin.h b/lib/clixon/clixon_plugin.h index e487b035..c7294881 100644 --- a/lib/clixon/clixon_plugin.h +++ b/lib/clixon/clixon_plugin.h @@ -337,16 +337,6 @@ struct clixon_plugin_api{ #define ca_trans_abort u.cau_backend.cb_trans_abort #define ca_datastore_upgrade u.cau_backend.cb_datastore_upgrade -/*! Structure for checking status before and after a plugin call - * Currently signal settings: blocked and handlers, could be extended to more - * @see plugin_context_check - */ -struct plugin_context { - sigset_t pc_sigset; /* See sigprocmask(2) */ - struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ - int pc_status; /* 0: OK, -1: fail */ -}; -typedef struct plugin_context plugin_context_t; /* * Macros @@ -359,6 +349,10 @@ typedef struct clixon_plugin_api clixon_plugin_api; * The internal struct is defined in clixon_plugin.c */ typedef struct clixon_plugin clixon_plugin_t; +/*! Structure for checking status before and after a plugin call + * The internal struct is defined in clixon_plugin.c */ +typedef struct plugin_context plugin_context_t; + /* * Prototypes */ @@ -371,7 +365,6 @@ typedef struct clixon_plugin clixon_plugin_t; */ clixon_plugin_api *clixon_plugin_init(clicon_handle h); - clixon_plugin_api *clixon_plugin_api_get(clixon_plugin_t *cp); char *clixon_plugin_name_get(clixon_plugin_t *cp); plghndl_t clixon_plugin_handle_get(clixon_plugin_t *cp); @@ -386,7 +379,7 @@ int clixon_plugins_load(clicon_handle h, const char *function, const char *dir, int clixon_pseudo_plugin(clicon_handle h, const char *name, clixon_plugin_t **cpp); -int plugin_context_get(plugin_context_t *pc); +plugin_context_t * plugin_context_get(void); int plugin_context_check(plugin_context_t *pc, const char *name, const char *fn); int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h); diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 9a804cdd..d55c8cb8 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -70,6 +70,15 @@ /* * Private types */ +/*! Structure for checking status before and after a plugin call + * Currently signal settings: blocked and handlers, could be extended to more + * @see plugin_context_check + */ +struct plugin_context { + sigset_t pc_sigset; /* See sigprocmask(2) */ + struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ + int pc_status; /* 0: OK, -1: fail */ +}; /* Internal plugin structure with dlopen() handle and plugin_api * This is an internal type, not exposed in the API @@ -328,10 +337,10 @@ plugin_load_one(clicon_handle h, void *handle = NULL; plginit2_t *initfn; clixon_plugin_api *api = NULL; - clixon_plugin_t *cp = NULL; + clixon_plugin_t *cp = NULL; char *name; char *p; - plugin_context_t pc = {0,}; + plugin_context_t *pc = NULL; clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function); dlerror(); /* Clear any existing error */ @@ -350,9 +359,7 @@ plugin_load_one(clicon_handle h, goto done; } clicon_err_reset(); - - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) < 0) goto done; if ((api = initfn(h)) == NULL) { @@ -366,7 +373,7 @@ plugin_load_one(clicon_handle h, goto done; } } - if (plugin_context_check(&pc, file, __FUNCTION__) < 0) + if (plugin_context_check(pc, file, __FUNCTION__) < 0) goto done; /* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */ @@ -392,6 +399,8 @@ plugin_load_one(clicon_handle h, retval = 1; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + if (pc) + free(pc); if (retval != 1 && handle) dlclose(handle); if (cp) @@ -495,14 +504,20 @@ done: /*! Get system context, eg signal procmask (for blocking) and sigactions * Call this before a plugin + * @retval pc Plugin context structure, use free() to deallocate + * @retval NULL Error * @see plugin_context_check - */ -int -plugin_context_get(plugin_context_t *pc) + * */ +plugin_context_t * +plugin_context_get(void) { - int retval = -1; - int i; + int i; + struct plugin_context *pc = NULL; + if ((pc = malloc(sizeof *pc)) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){ clicon_err(OE_UNIX, errno, "sigprocmask"); goto done; @@ -521,9 +536,11 @@ plugin_context_get(plugin_context_t *pc) pc->pc_sigaction_vec[i].sa_flags &= ~0x04000000; #endif } - retval = 0; + return pc; done: - return retval; + if (pc) + free(pc); + return NULL; } /*! Given an existing, old plugin context, check if anytjing has changed @@ -535,39 +552,40 @@ plugin_context_get(plugin_context_t *pc) * @see plugin_context_get */ int -plugin_context_check(plugin_context_t *oldpc, +plugin_context_check(plugin_context_t *oldpc0, const char *name, const char *fn) { - int retval = -1; - int failed; - int i; - plugin_context_t newpc = {0, }; + int retval = -1; + int failed; + int i; + struct plugin_context *oldpc = oldpc0; + struct plugin_context *newpc = NULL; - if (plugin_context_get(&newpc) < 0) + if ((newpc = plugin_context_get()) == NULL) goto done; for (i=1; i<32; i++){ failed = 0; - if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc.pc_sigset, i)){ + if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc->pc_sigset, i)){ clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, name, fn, strsignal(i), i, sigismember(&oldpc->pc_sigset, i), - sigismember(&newpc.pc_sigset, i) + sigismember(&newpc->pc_sigset, i) ); failed++; } - if (oldpc->pc_sigaction_vec[i].sa_flags != newpc.pc_sigaction_vec[i].sa_flags){ + if (oldpc->pc_sigaction_vec[i].sa_flags != newpc->pc_sigaction_vec[i].sa_flags){ clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed flags of signal %s(%d) from 0x%x to 0x%x", __FUNCTION__, name, fn, strsignal(i), i, oldpc->pc_sigaction_vec[i].sa_flags, - newpc.pc_sigaction_vec[i].sa_flags);; + newpc->pc_sigaction_vec[i].sa_flags);; failed++; } - if (oldpc->pc_sigaction_vec[i].sa_sigaction != newpc.pc_sigaction_vec[i].sa_sigaction){ + if (oldpc->pc_sigaction_vec[i].sa_sigaction != newpc->pc_sigaction_vec[i].sa_sigaction){ clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed action of signal %s(%d) from %p to %p", __FUNCTION__, name, fn, strsignal(i), i, oldpc->pc_sigaction_vec[i].sa_sigaction, - newpc.pc_sigaction_vec[i].sa_sigaction); + newpc->pc_sigaction_vec[i].sa_sigaction); failed++; } if (failed){ @@ -577,6 +595,8 @@ plugin_context_check(plugin_context_t *oldpc, } retval = 0; done: + if (newpc) + free(newpc); return retval; } @@ -590,13 +610,12 @@ int clixon_plugin_start_one(clixon_plugin_t *cp, clicon_handle h) { - int retval = -1; - plgstart_t *fn; /* Plugin start */ + int retval = -1; + plgstart_t *fn; /* Plugin start */ + plugin_context_t *pc = NULL; if ((fn = cp->cp_api.ca_start) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h) < 0) { if (clicon_errno < 0) @@ -604,11 +623,13 @@ clixon_plugin_start_one(clixon_plugin_t *cp, __FUNCTION__, cp->cp_name); goto done; } - if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -643,14 +664,13 @@ static int clixon_plugin_exit_one(clixon_plugin_t *cp, clicon_handle h) { - int retval = -1; - char *error; - plgexit_t *fn; - + int retval = -1; + char *error; + plgexit_t *fn; + plugin_context_t *pc = NULL; + if ((fn = cp->cp_api.ca_exit) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h) < 0) { if (clicon_errno < 0) @@ -658,7 +678,7 @@ clixon_plugin_exit_one(clixon_plugin_t *cp, __FUNCTION__, cp->cp_name); goto done; } - if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0) goto done; if (dlclose(cp->cp_handle) != 0) { error = (char*)dlerror(); @@ -667,6 +687,8 @@ clixon_plugin_exit_one(clixon_plugin_t *cp, } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -715,14 +737,13 @@ clixon_plugin_auth_one(clixon_plugin_t *cp, clixon_auth_type_t auth_type, char **authp) { - int retval = -1; - plgauth_t *fn; /* Plugin auth */ + int retval = -1; + plgauth_t *fn; /* Plugin auth */ + plugin_context_t *pc = NULL; clicon_debug(1, "%s", __FUNCTION__); if ((fn = cp->cp_api.ca_auth) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if ((retval = fn(h, req, auth_type, authp)) < 0) { if (clicon_errno < 0) @@ -730,12 +751,14 @@ clixon_plugin_auth_one(clixon_plugin_t *cp, __FUNCTION__, cp->cp_name); goto done; } - if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0) goto done; } else retval = 0; /* Ignored / no callback */ done: + if (pc) + free(pc); clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp); return retval; } @@ -799,13 +822,12 @@ clixon_plugin_extension_one(clixon_plugin_t *cp, yang_stmt *yext, yang_stmt *ys) { - int retval = 1; - plgextension_t *fn; /* Plugin extension fn */ + int retval = 1; + plgextension_t *fn; /* Plugin extension fn */ + plugin_context_t *pc = NULL; if ((fn = cp->cp_api.ca_extension) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, yext, ys) < 0) { if (clicon_errno < 0) @@ -813,11 +835,13 @@ clixon_plugin_extension_one(clixon_plugin_t *cp, __FUNCTION__, cp->cp_name); goto done; } - if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } @@ -871,11 +895,10 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, { int retval = -1; datastore_upgrade_t *fn; + plugin_context_t *pc = NULL; if ((fn = cp->cp_api.ca_datastore_upgrade) != NULL){ - plugin_context_t pc = {0,}; - - if (plugin_context_get(&pc) < 0) + if ((pc = plugin_context_get()) == NULL) goto done; if (fn(h, db, xt, msd) < 0) { if (clicon_errno < 0) @@ -883,11 +906,13 @@ clixon_plugin_datastore_upgrade_one(clixon_plugin_t *cp, __FUNCTION__, cp->cp_name); goto done; } - if (plugin_context_check(&pc, cp->cp_name, __FUNCTION__) < 0) + if (plugin_context_check(pc, cp->cp_name, __FUNCTION__) < 0) goto done; } retval = 0; done: + if (pc) + free(pc); return retval; } From 7d7024d11475d1ef75eeb4ffbe17333b4d62896f Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 20 Oct 2021 11:17:14 +0200 Subject: [PATCH 07/10] Plugin-context: moved status field from struct to function retval --- CHANGELOG.md | 4 ++- lib/src/clixon_plugin.c | 65 ++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b2022be..89d8a4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,7 +68,9 @@ Developers may need to change their code ### Minor features -* Added checks of changed handlers or blocked signal after plugin function calls +* Plugin context check before and after all callbacks. + * Check blocked signals and signal handlers + * Any changes to context are logged at loglevel WARNING * Added set/get pointer API to clixon_data: * clicon_ptr_get(), clicon_ptr_set(), * Restconf YANG PATCH according to RFC 8072 diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index d55c8cb8..18f15efd 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -77,7 +77,6 @@ struct plugin_context { sigset_t pc_sigset; /* See sigprocmask(2) */ struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ - int pc_status; /* 0: OK, -1: fail */ }; /* Internal plugin structure with dlopen() handle and plugin_api @@ -514,10 +513,11 @@ plugin_context_get(void) int i; struct plugin_context *pc = NULL; - if ((pc = malloc(sizeof *pc)) == NULL){ + if ((pc = malloc(sizeof(*pc))) == NULL){ clicon_err(OE_UNIX, errno, "malloc"); goto done; } + memset(pc, 0, sizeof(*pc)); if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){ clicon_err(OE_UNIX, errno, "sigprocmask"); goto done; @@ -543,12 +543,19 @@ plugin_context_get(void) return NULL; } -/*! Given an existing, old plugin context, check if anytjing has changed - * @param[in,out] oldpc Old plugin context, status will be returned inside oldpc - * @param[in] name Name of plugin for logging - * @param[in] fn Name of callback +/*! Given an existing, old plugin context, check if anything has changed + * + * Make a new check and compare with the old (procided as in-parameter). + * Log if there is a difference at loglevel WARNING. + * You can modify the code to also fail with assert if you want early fail. + * + * @param[in,out] oldpc Old plugin context + * @param[in] name Name of plugin for logging. Can be other name, context dependent + * @param[in] fn Typically name of callback, or caller function * @retval -1 Error - * @retval 0 OK + * @retval 0 Fail, log on syslog using LOG_WARNING + * @retval 1 OK + * @note name and fn are context dependent, since the env of callback calls are very different * @see plugin_context_get */ int @@ -567,7 +574,7 @@ plugin_context_check(plugin_context_t *oldpc0, for (i=1; i<32; i++){ failed = 0; if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc->pc_sigset, i)){ - clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, name, fn, strsignal(i), i, sigismember(&oldpc->pc_sigset, i), sigismember(&newpc->pc_sigset, i) @@ -575,29 +582,36 @@ plugin_context_check(plugin_context_t *oldpc0, failed++; } if (oldpc->pc_sigaction_vec[i].sa_flags != newpc->pc_sigaction_vec[i].sa_flags){ - clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed flags of signal %s(%d) from 0x%x to 0x%x", __FUNCTION__, + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed flags of signal %s(%d) from 0x%x to 0x%x", __FUNCTION__, name, fn, strsignal(i), i, oldpc->pc_sigaction_vec[i].sa_flags, newpc->pc_sigaction_vec[i].sa_flags);; failed++; } if (oldpc->pc_sigaction_vec[i].sa_sigaction != newpc->pc_sigaction_vec[i].sa_sigaction){ - clicon_log(LOG_WARNING, "%s Plugin %s %s: Changed action of signal %s(%d) from %p to %p", __FUNCTION__, + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed action of signal %s(%d) from %p to %p", __FUNCTION__, name, fn, strsignal(i), i, oldpc->pc_sigaction_vec[i].sa_sigaction, newpc->pc_sigaction_vec[i].sa_sigaction); failed++; } - if (failed){ - oldpc->pc_status = -1; - } - /* assert(oldpc->pc_status == 0); */ +#if 0 + /* In case you want early detection and crash. But otherwise it is recommended that + * the caller looks for retval == 0 */ + assert(failed == 0); +#endif + if (failed) + goto fail; + } - retval = 0; + retval = 1; /* OK */ done: if (newpc) free(newpc); return retval; + fail: + retval = 0; + goto done; } /*! Call single plugin start callback @@ -1058,12 +1072,13 @@ rpc_callback_call(clicon_handle h, void *arg) { int retval = -1; - rpc_callback_t *rc; - char *name; - char *prefix; - char *ns; - int nr = 0; /* How many callbacks */ + rpc_callback_t *rc; + char *name; + char *prefix; + char *ns; + int nr = 0; /* How many callbacks */ plugin_module_struct *ms = plugin_module_struct_get(h); + plugin_context_t *pc = NULL; if (ms == NULL){ clicon_err(OE_PLUGIN, EINVAL, "plugin module not initialized"); @@ -1077,17 +1092,27 @@ rpc_callback_call(clicon_handle h, if (strcmp(rc->rc_name, name) == 0 && ns && rc->rc_namespace && strcmp(rc->rc_namespace, ns) == 0){ + if ((pc = plugin_context_get()) == NULL) + goto done; if (rc->rc_callback(h, xe, cbret, arg, rc->rc_arg) < 0){ clicon_debug(1, "%s Error in: %s", __FUNCTION__, rc->rc_name); goto done; } nr++; + if (plugin_context_check(pc, rc->rc_name, __FUNCTION__) < 0) + goto done; + if (pc){ + free(pc); + pc = NULL; + } } rc = NEXTQ(rpc_callback_t *, rc); } while (rc != ms->ms_rpc_callbacks); retval = nr; /* 0: none found, >0 nr of handlers called */ done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + if (pc) + free(pc); return retval; } From 5d29d8aff07ccee70986d2d00bf834a32411bae1 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 21 Oct 2021 15:44:04 +0200 Subject: [PATCH 08/10] Plugin context check: check termios settings --- CHANGELOG.md | 1 + apps/cli/cli_common.c | 26 ++++++++++++-------- lib/clixon/clixon_sig.h | 2 ++ lib/src/clixon_event.c | 1 + lib/src/clixon_plugin.c | 54 +++++++++++++++++++++++++++++++++++------ lib/src/clixon_sig.c | 52 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89d8a4fe..81dc1a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ Developers may need to change their code * Plugin context check before and after all callbacks. * Check blocked signals and signal handlers + * Check termios settings * Any changes to context are logged at loglevel WARNING * Added set/get pointer API to clixon_data: * clicon_ptr_get(), clicon_ptr_set(), diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index d65a150a..e32509f2 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -165,17 +165,17 @@ cli_signal_flush(clicon_handle h) sigfn_t h1, h2, h3, h4; - set_signal (SIGTSTP, SIG_IGN, &h1); - set_signal (SIGQUIT, SIG_IGN, &h2); - set_signal (SIGCHLD, SIG_IGN, &h3); - set_signal (SIGINT, SIG_IGN, &h4); + set_signal(SIGTSTP, SIG_IGN, &h1); + set_signal(SIGQUIT, SIG_IGN, &h2); + set_signal(SIGCHLD, SIG_IGN, &h3); + set_signal(SIGINT, SIG_IGN, &h4); cli_signal_unblock (h); - set_signal (SIGTSTP, h1, NULL); - set_signal (SIGQUIT, h2, NULL); - set_signal (SIGCHLD, h3, NULL); - set_signal (SIGINT, h4, NULL); + set_signal(SIGTSTP, h1, NULL); + set_signal(SIGQUIT, h2, NULL); + set_signal(SIGCHLD, h3, NULL); + set_signal(SIGINT, h4, NULL); cli_signal_block (h); } @@ -562,9 +562,10 @@ cli_start_shell(clicon_handle h, int retval = -1; char bcmd[128]; cg_var *cv1 = cvec_i(vars, 1); - + sigset_t oldsigset; + struct sigaction oldsigaction[32] = {0,}; + cmd = (cvec_len(vars)>1 ? cv_string_get(cv1) : NULL); - if ((pw = getpwuid(getuid())) == NULL){ clicon_err(OE_UNIX, errno, "getpwuid"); goto done; @@ -575,6 +576,9 @@ cli_start_shell(clicon_handle h, goto done; } endpwent(); + + if (clixon_signal_save(&oldsigset, oldsigaction) < 0) + goto done; cli_signal_flush(h); cli_signal_unblock(h); if (cmd){ @@ -598,6 +602,8 @@ cli_start_shell(clicon_handle h, goto done; } #endif + if (clixon_signal_restore(&oldsigset, oldsigaction) < 0) + goto done; retval = 0; done: return retval; diff --git a/lib/clixon/clixon_sig.h b/lib/clixon/clixon_sig.h index 317c7079..07249374 100644 --- a/lib/clixon/clixon_sig.h +++ b/lib/clixon/clixon_sig.h @@ -47,6 +47,8 @@ typedef void (*sigfn_t)(int); * Prototypes */ int set_signal(int signo, void (*handler)(int), void (**oldhandler)(int)); +int clixon_signal_save(sigset_t *sigset, struct sigaction sigaction_vec[32]); +int clixon_signal_restore(sigset_t *sigset, struct sigaction sigaction_vec[32]); void clicon_signal_block(int); void clicon_signal_unblock(int); diff --git a/lib/src/clixon_event.c b/lib/src/clixon_event.c index 736c7541..9dad4dfe 100644 --- a/lib/src/clixon_event.c +++ b/lib/src/clixon_event.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/lib/src/clixon_plugin.c b/lib/src/clixon_plugin.c index 18f15efd..2bebbcf3 100644 --- a/lib/src/clixon_plugin.c +++ b/lib/src/clixon_plugin.c @@ -47,7 +47,8 @@ #include #include #include - +#include +#include #include #include @@ -71,12 +72,13 @@ * Private types */ /*! Structure for checking status before and after a plugin call - * Currently signal settings: blocked and handlers, could be extended to more + * Currently signal settings: blocked and handlers, and termios * @see plugin_context_check */ struct plugin_context { sigset_t pc_sigset; /* See sigprocmask(2) */ struct sigaction pc_sigaction_vec[32]; /* See sigaction(2) */ + struct termios pc_termios; /* See termios(3) */ }; /* Internal plugin structure with dlopen() handle and plugin_api @@ -518,6 +520,7 @@ plugin_context_get(void) goto done; } memset(pc, 0, sizeof(*pc)); + if (sigprocmask(0, NULL, &pc->pc_sigset) < 0){ clicon_err(OE_UNIX, errno, "sigprocmask"); goto done; @@ -536,6 +539,10 @@ plugin_context_get(void) pc->pc_sigaction_vec[i].sa_flags &= ~0x04000000; #endif } + if (isatty(0) && tcgetattr(0, &pc->pc_termios) < 0){ + clicon_err(OE_UNIX, errno, "tcgetattr %d", errno); + goto done; + } return pc; done: if (pc) @@ -564,15 +571,48 @@ plugin_context_check(plugin_context_t *oldpc0, const char *fn) { int retval = -1; - int failed; + int failed = 0; int i; struct plugin_context *oldpc = oldpc0; struct plugin_context *newpc = NULL; if ((newpc = plugin_context_get()) == NULL) goto done; + if (oldpc->pc_termios.c_iflag != newpc->pc_termios.c_iflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios input modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_iflag, + newpc->pc_termios.c_iflag); + failed++; + } + if (oldpc->pc_termios.c_oflag != newpc->pc_termios.c_oflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios output modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_oflag, + newpc->pc_termios.c_oflag); + failed++; + } + if (oldpc->pc_termios.c_cflag != newpc->pc_termios.c_cflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios control modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_cflag, + newpc->pc_termios.c_cflag); + failed++; + } + if (oldpc->pc_termios.c_lflag != newpc->pc_termios.c_lflag){ + clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed termios local modes from 0x%x to 0x%x", __FUNCTION__, + name, fn, + oldpc->pc_termios.c_lflag, + newpc->pc_termios.c_lflag); + failed++; + } + /* XXX pc_termios.cc_t c_cc[NCCS] not checked */ +#if 0 + /* In case you want early detection and crash. But otherwise it is recommended that + * the caller looks for retval == 0 */ + assert(failed == 0); +#endif for (i=1; i<32; i++){ - failed = 0; if (sigismember(&oldpc->pc_sigset, i) != sigismember(&newpc->pc_sigset, i)){ clicon_log(LOG_WARNING, "%s Plugin context %s %s: Changed blocking of signal %s(%d) from %d to %d", __FUNCTION__, name, fn, strsignal(i), i, @@ -600,10 +640,10 @@ plugin_context_check(plugin_context_t *oldpc0, * the caller looks for retval == 0 */ assert(failed == 0); #endif - if (failed) - goto fail; - } + if (failed) + goto fail; + retval = 1; /* OK */ done: if (newpc) diff --git a/lib/src/clixon_sig.c b/lib/src/clixon_sig.c index 16cb3176..611a27a8 100644 --- a/lib/src/clixon_sig.c +++ b/lib/src/clixon_sig.c @@ -121,6 +121,58 @@ clicon_signal_unblock(int sig) sigprocmask(SIG_UNBLOCK, &set, NULL); } +/*! Save complete signal context + */ +int +clixon_signal_save(sigset_t *sigset, + struct sigaction sigaction_vec[32]) +{ + int retval = -1; + int i; + + if (sigprocmask(0, NULL, sigset) < 0){ + clicon_err(OE_UNIX, errno, "sigprocmask"); + goto done; + } + for (i=1; i<32; i++){ + if (sigaction(i, NULL, &sigaction_vec[i]) < 0){ + clicon_err(OE_UNIX, errno, "sigaction"); + goto done; + } + } + retval = 0; + done: + return retval; +} + +/*! Restore complete signal context + * + * Note: sigaction may not restore SIGKILL or SIGSTOP, which cannot be caught or ignored. + */ +int +clixon_signal_restore(sigset_t *sigset, + struct sigaction sigaction_vec[32]) +{ + int retval = -1; + int i; + + if (sigprocmask(0, sigset, NULL) < 0){ + clicon_err(OE_UNIX, errno, "sigprocmask"); + goto done; + } + for (i=1; i<32; i++){ + if (i == SIGKILL || i == SIGSTOP) + continue; + if (sigaction(i, &sigaction_vec[i], NULL) < 0){ + clicon_err(OE_UNIX, errno, "sigaction"); + goto done; + } + } + retval = 0; + done: + return retval; +} + /*! Read pidfile and return pid using file descriptor * * @param[in] pidfile Name of pidfile From 448aa4c9941296f31c075b901be4ff30b88713f4 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 21 Oct 2021 16:04:05 +0200 Subject: [PATCH 09/10] include signal.h --- apps/backend/backend_plugin_restconf.c | 1 + apps/backend/clixon_backend_handle.c | 1 + apps/backend/clixon_backend_transaction.c | 1 + apps/cli/cli_generate.c | 1 + apps/cli/cli_handle.c | 1 + apps/cli/cli_plugin.c | 2 +- apps/restconf/restconf_api_native.c | 1 + apps/restconf/restconf_handle.c | 1 + example/main/example_netconf.c | 1 + util/Makefile.in | 1 - util/clixon_util_datastore.c | 1 + util/clixon_util_dispatcher.c | 1 + util/clixon_util_json.c | 1 + util/clixon_util_path.c | 1 + util/clixon_util_regexp.c | 1 + util/clixon_util_socket.c | 1 + util/clixon_util_ssl.c | 1 + util/clixon_util_stream.c | 1 + util/clixon_util_validate.c | 1 + util/clixon_util_xml.c | 1 + util/clixon_util_xml_mod.c | 1 + util/clixon_util_xpath.c | 1 + util/clixon_util_yang.c | 2 +- 23 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/backend/backend_plugin_restconf.c b/apps/backend/backend_plugin_restconf.c index c7db8249..3d04d2fa 100644 --- a/apps/backend/backend_plugin_restconf.c +++ b/apps/backend/backend_plugin_restconf.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include diff --git a/apps/backend/clixon_backend_handle.c b/apps/backend/clixon_backend_handle.c index dd9714de..f4eb77ac 100644 --- a/apps/backend/clixon_backend_handle.c +++ b/apps/backend/clixon_backend_handle.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include diff --git a/apps/backend/clixon_backend_transaction.c b/apps/backend/clixon_backend_transaction.c index e7af1c7c..0a7889ce 100644 --- a/apps/backend/clixon_backend_transaction.c +++ b/apps/backend/clixon_backend_transaction.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index a2cd6cfb..fe365836 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -78,6 +78,7 @@ You can see which CLISPEC it generates via clixon_cli -D 2: #include #include #include +#include #include /* cligen */ diff --git a/apps/cli/cli_handle.c b/apps/cli/cli_handle.c index e4fddeb1..5e992a08 100644 --- a/apps/cli/cli_handle.c +++ b/apps/cli/cli_handle.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/apps/cli/cli_plugin.c b/apps/cli/cli_plugin.c index cf52bd7b..77b60cbe 100644 --- a/apps/cli/cli_plugin.c +++ b/apps/cli/cli_plugin.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,6 @@ #include "cli_handle.h" #include "cli_generate.h" - /* * Constants */ diff --git a/apps/restconf/restconf_api_native.c b/apps/restconf/restconf_api_native.c index 956f33bd..981a4e98 100644 --- a/apps/restconf/restconf_api_native.c +++ b/apps/restconf/restconf_api_native.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/apps/restconf/restconf_handle.c b/apps/restconf/restconf_handle.c index ef413d08..2573e237 100644 --- a/apps/restconf/restconf_handle.c +++ b/apps/restconf/restconf_handle.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/example/main/example_netconf.c b/example/main/example_netconf.c index 2a35c939..00a21913 100644 --- a/example/main/example_netconf.c +++ b/example/main/example_netconf.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/util/Makefile.in b/util/Makefile.in index 7e4d21ed..fe6936f8 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -103,7 +103,6 @@ APPSRC += clixon_util_ssl.c # requires http/2 #APPSRC += clixon_util_grpc.c # work in progress endif - APPS = $(APPSRC:.c=) all: $(APPS) diff --git a/util/clixon_util_datastore.c b/util/clixon_util_datastore.c index 65e611f2..92d6401d 100644 --- a/util/clixon_util_datastore.c +++ b/util/clixon_util_datastore.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/util/clixon_util_dispatcher.c b/util/clixon_util_dispatcher.c index 45571daa..2cd00ddb 100644 --- a/util/clixon_util_dispatcher.c +++ b/util/clixon_util_dispatcher.c @@ -53,6 +53,7 @@ #include #include #include +#include #include /* cligen */ diff --git a/util/clixon_util_json.c b/util/clixon_util_json.c index 389b27ca..43a4ff5a 100644 --- a/util/clixon_util_json.c +++ b/util/clixon_util_json.c @@ -50,6 +50,7 @@ #include #include #include +#include /* cligen */ #include diff --git a/util/clixon_util_path.c b/util/clixon_util_path.c index f75a36da..7f7a034e 100644 --- a/util/clixon_util_path.c +++ b/util/clixon_util_path.c @@ -49,6 +49,7 @@ #include #include #include +#include #include /* cligen */ diff --git a/util/clixon_util_regexp.c b/util/clixon_util_regexp.c index edf5255c..0d02c55b 100644 --- a/util/clixon_util_regexp.c +++ b/util/clixon_util_regexp.c @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef HAVE_LIBXML2 /* Actually it should check for a header file */ #include diff --git a/util/clixon_util_socket.c b/util/clixon_util_socket.c index 28ce05b0..409e30f1 100644 --- a/util/clixon_util_socket.c +++ b/util/clixon_util_socket.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include diff --git a/util/clixon_util_ssl.c b/util/clixon_util_ssl.c index 68a17aa1..7e4b17ef 100644 --- a/util/clixon_util_ssl.c +++ b/util/clixon_util_ssl.c @@ -49,6 +49,7 @@ #include #include #include +#include #include /* gethostbyname */ #include /* inet_pton */ #include /* TCP_NODELAY */ diff --git a/util/clixon_util_stream.c b/util/clixon_util_stream.c index ebf3df83..41fd7d07 100644 --- a/util/clixon_util_stream.c +++ b/util/clixon_util_stream.c @@ -50,6 +50,7 @@ #include #include #include +#include #include /* cligen */ diff --git a/util/clixon_util_validate.c b/util/clixon_util_validate.c index a64465fe..415c2dda 100644 --- a/util/clixon_util_validate.c +++ b/util/clixon_util_validate.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c index 87a35d9c..b59ae889 100644 --- a/util/clixon_util_xml.c +++ b/util/clixon_util_xml.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include diff --git a/util/clixon_util_xml_mod.c b/util/clixon_util_xml_mod.c index 7347842c..49db916e 100644 --- a/util/clixon_util_xml_mod.c +++ b/util/clixon_util_xml_mod.c @@ -58,6 +58,7 @@ #include #include #include +#include /* cligen */ #include diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c index 878dcb39..9726ae1c 100644 --- a/util/clixon_util_xpath.c +++ b/util/clixon_util_xpath.c @@ -50,6 +50,7 @@ See https://www.w3.org/TR/xpath/ #include #include #include +#include #include /* cligen */ diff --git a/util/clixon_util_yang.c b/util/clixon_util_yang.c index 7f7ea051..f85a811c 100644 --- a/util/clixon_util_yang.c +++ b/util/clixon_util_yang.c @@ -51,11 +51,11 @@ #include #include #include +#include #include #include #include - /* cligen */ #include From 063e6d6faa334466223e42881b449fd6c5caaa29 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 21 Oct 2021 21:45:14 +0200 Subject: [PATCH 10/10] Added "exist" parameter to yang_extension_value() --- apps/cli/cli_auto.c | 18 +++++++++--------- apps/cli/cli_generate.c | 26 +++++++++++++------------- lib/clixon/clixon_yang.h | 2 +- lib/src/clixon_yang.c | 18 +++++++++++++----- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index 7b0cce6b..c51b6f79 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -171,7 +171,7 @@ cli_xml2file(cxobj *xn, if (xn == NULL) goto ok; /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) { + if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) { goto ok; } if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){ @@ -273,13 +273,13 @@ cli_xml2txt(cxobj *xn, clicon_err(OE_XML, EINVAL, "xn or fn is NULL"); goto done; } - /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) { - goto ok; - } - if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){ - goto ok; - } + /* Look for autocli-op defined in clixon-lib.yang */ + if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) { + goto ok; + } + if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){ + goto ok; + } xc = NULL; /* count children (elements and bodies, not attributes) */ while ((xc = xml_child_each(xn, xc, -1)) != NULL) if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY) @@ -342,7 +342,7 @@ cli_xml2cli(cxobj *xn, if ((ys = xml_spec(xn)) == NULL) goto ok; /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) { + if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) { goto ok; } if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){ diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index fe365836..ac6527df 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -121,7 +121,7 @@ cli_expand_var_generate(clicon_handle h, int retval = -1; char *api_path_fmt = NULL, *opext = NULL; - if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0) + if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) goto done; if (opext && strcmp(opext, "hide-database") == 0) { retval = 1; @@ -762,7 +762,7 @@ yang2cli_leaf(clicon_handle h, } cprintf(cb, "%*s", level*3, ""); /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0) + if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) goto done; if (gt == GT_VARS|| gt == GT_ALL || gt == GT_HIDE){ cprintf(cb, "%s", yang_argument_get(ys)); @@ -839,7 +839,7 @@ yang2cli_container(clicon_handle h, * a list, then skip container keyword * See also xml2cli */ - if ((hide = yang_container_cli_hide(ys, gt)) == 0){ + if ((hide = yang_container_cli_hide(ys, gt)) == 0){ cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys)); if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){ if ((helptext = strdup(yang_argument_get(yd))) == NULL){ @@ -853,14 +853,14 @@ yang2cli_container(clicon_handle h, if (cli_callback_generate(h, ys, cb) < 0) goto done; - /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0) - goto done; - if (opext != NULL && strcmp(opext, "hide") == 0){ - cprintf(cb, ",hide"); - } + /* Look for autocli-op defined in clixon-lib.yang */ + if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) + goto done; + if (opext != NULL && strcmp(opext, "hide") == 0){ + cprintf(cb, ",hide"); + } if (opext != NULL && strcmp(opext, "hide-database-auto-completion") == 0){ - cprintf(cb, ",hide-database-auto-completion"); + cprintf(cb, ",hide-database-auto-completion"); } cprintf(cb, ";{\n"); } @@ -868,11 +868,11 @@ yang2cli_container(clicon_handle h, yc = NULL; while ((yc = yn_each(ys, yc)) != NULL) if (yang2cli_stmt(h, yc, gt, level+1, state, show_tree, cb) < 0) - goto done; + goto done; if (hide == 0) cprintf(cb, "%*s}\n", level*3, ""); retval = 0; - done: + done: if (helptext) free(helptext); return retval; @@ -920,7 +920,7 @@ yang2cli_list(clicon_handle h, yang2cli_helptext(cb, helptext); } /* Look for autocli-op defined in clixon-lib.yang */ - if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0) + if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0) goto done; if (opext != NULL && strcmp(opext, "hide") == 0){ cprintf(cb, ",hide"); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 879e6b8c..96084036 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -270,6 +270,6 @@ int yang_type_cache_get(yang_stmt *ytype, yang_stmt **resolved, int *opti int yang_type_cache_set(yang_stmt *ys, yang_stmt *resolved, int options, cvec *cvv, cvec *patterns, uint8_t fraction); yang_stmt *yang_anydata_add(yang_stmt *yp, char *name); -int yang_extension_value(yang_stmt *ys, char *name, char *ns, char **value); +int yang_extension_value(yang_stmt *ys, char *name, char *ns, int *exist, char **value); #endif /* _CLIXON_YANG_H_ */ diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 6f3b45ab..d4e70dea 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -3553,15 +3553,20 @@ yang_anydata_add(yang_stmt *yp, return ys; } -/*! Find extension argument and return extension argument value +/*! Find extension argument and return if extension exists and its argument value + * * @param[in] ys Yang statement * @param[in] name Name of the extension * @param[in] ns The namespace + * @param[out] exist The extension exists. * @param[out] value clispec operator (hide/none) - direct pointer into yang, dont free + * @retval 0 OK: Look in exist and value for return value + * @retval -1 Error * This is for extensions with an argument * @code * char *value = NULL; - * if (yang_extension_value(ys, "mymode", "urn:example:lib", &value) < 0) + * int exist = 0; + * if (yang_extension_value(ys, "mymode", "urn:example:lib", &exist, &value) < 0) * err; * if (value != NULL){ * // use extension value @@ -3572,6 +3577,7 @@ int yang_extension_value(yang_stmt *ys, char *name, char *ns, + int *exist, char **value) { int retval = -1; @@ -3593,15 +3599,17 @@ yang_extension_value(yang_stmt *ys, continue; if (yang_find_prefix_by_namespace(ymod, ns, &prefix) < 0) goto ok; + cbuf_reset(cb); cprintf(cb, "%s:%s", prefix, name); if (strcmp(yang_argument_get(yext), cbuf_get(cb)) != 0) continue; break; } if (yext != NULL){ /* Found */ - if ((cv = yang_cv_get(yext)) == NULL) - goto ok; - if (value) + if (exist) + *exist = 1; + if (value && + (cv = yang_cv_get(yext)) != NULL) *value = cv_string_get(cv); } ok: