Merge branch 'master' into feature_openconfig_compress
This commit is contained in:
commit
9d8d9ac042
43 changed files with 997 additions and 139 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
||||
|
|
@ -37,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
|
||||
|
|
@ -285,11 +312,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 */
|
||||
|
|
@ -411,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,
|
||||
|
|
@ -423,8 +447,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 +478,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
|
|
|||
|
|
@ -43,10 +43,12 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
|
|
@ -69,6 +71,15 @@
|
|||
/*
|
||||
* Private types
|
||||
*/
|
||||
/*! Structure for checking status before and after a plugin call
|
||||
* 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
|
||||
* This is an internal type, not exposed in the API
|
||||
|
|
@ -327,9 +338,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 = NULL;
|
||||
|
||||
clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function);
|
||||
dlerror(); /* Clear any existing error */
|
||||
|
|
@ -348,6 +360,9 @@ plugin_load_one(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
clicon_err_reset();
|
||||
if ((pc = plugin_context_get()) < 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 +374,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");
|
||||
|
|
@ -382,6 +400,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)
|
||||
|
|
@ -483,6 +503,157 @@ done:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! 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
|
||||
* */
|
||||
plugin_context_t *
|
||||
plugin_context_get(void)
|
||||
{
|
||||
int i;
|
||||
struct plugin_context *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;
|
||||
}
|
||||
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
|
||||
}
|
||||
if (isatty(0) && tcgetattr(0, &pc->pc_termios) < 0){
|
||||
clicon_err(OE_UNIX, errno, "tcgetattr %d", errno);
|
||||
goto done;
|
||||
}
|
||||
return pc;
|
||||
done:
|
||||
if (pc)
|
||||
free(pc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! 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 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
|
||||
plugin_context_check(plugin_context_t *oldpc0,
|
||||
const char *name,
|
||||
const char *fn)
|
||||
{
|
||||
int retval = -1;
|
||||
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++){
|
||||
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,
|
||||
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 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 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 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 = 1; /* OK */
|
||||
done:
|
||||
if (newpc)
|
||||
free(newpc);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Call single plugin start callback
|
||||
* @param[in] cp Plugin handle
|
||||
* @param[in] h Clixon handle
|
||||
|
|
@ -493,19 +664,26 @@ 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){
|
||||
if ((pc = plugin_context_get()) == NULL)
|
||||
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:
|
||||
if (pc)
|
||||
free(pc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -540,17 +718,22 @@ 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){
|
||||
if ((pc = plugin_context_get()) == NULL)
|
||||
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");
|
||||
|
|
@ -558,6 +741,8 @@ clixon_plugin_exit_one(clixon_plugin_t *cp,
|
|||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (pc)
|
||||
free(pc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -606,21 +791,28 @@ 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){
|
||||
if ((pc = plugin_context_get()) == NULL)
|
||||
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 */
|
||||
done:
|
||||
if (pc)
|
||||
free(pc);
|
||||
clicon_debug(1, "%s retval:%d auth:%s", __FUNCTION__, retval, *authp);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -684,19 +876,26 @@ 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){
|
||||
if ((pc = plugin_context_get()) == NULL)
|
||||
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:
|
||||
if (pc)
|
||||
free(pc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -750,17 +949,24 @@ 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){
|
||||
if ((pc = plugin_context_get()) == NULL)
|
||||
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:
|
||||
if (pc)
|
||||
free(pc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -906,12 +1112,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");
|
||||
|
|
@ -925,17 +1132,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -3585,7 +3591,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;
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue