CLI plugin API restructuring completed. Now all plugin APIs have the generic form

documented in README and FAQ.
This commit is contained in:
Olof hagsand 2018-04-08 11:32:43 +02:00
parent afb6aa31db
commit 2e00411621
19 changed files with 317 additions and 551 deletions

View file

@ -43,8 +43,6 @@
*/
/* default group membership to access config unix socket */
#define CLICON_SOCK_GROUP "clicon"
/* Default name of master plugin */
#define CLICON_MASTER_PLUGIN "master"
/*
* Types
@ -137,9 +135,6 @@ static inline char *clicon_sock_group(clicon_handle h){
static inline char *clicon_backend_pidfile(clicon_handle h){
return clicon_option_str(h, "CLICON_BACKEND_PIDFILE");
}
static inline char *clicon_master_plugin(clicon_handle h){
return clicon_option_str(h, "CLICON_MASTER_PLUGIN");
}
static inline char *clicon_xmldb_dir(clicon_handle h){
return clicon_option_str(h, "CLICON_XMLDB_DIR");
}

View file

@ -38,10 +38,16 @@
#ifndef _CLIXON_PLUGIN_H_
#define _CLIXON_PLUGIN_H_
/*
* Constants
*/
/* Hardcoded plugin symbol. Must exist in all plugins to kickstart */
#define CLIXON_PLUGIN_INIT "clixon_plugin_init"
/*
* Types
*/
/* The dynamicically loadable plugin object handle */
/* Dynamicically loadable plugin object handle. @see return value of dlopen(3) */
typedef void *plghndl_t;
/* Registered RPC callback function */
@ -62,22 +68,13 @@ typedef int (*clicon_rpc_cb)(
* Backend see config_plugin.c
*/
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
#define PLUGIN_INIT "plugin_init"
typedef void * (plginit_t)(clicon_handle); /* Clixon plugin Init */
/* Called when backend started with cmd-line arguments from daemon call.
* @see plgstart_t
*/
#define PLUGIN_START "plugin_start"
typedef int (plgstart_t)(clicon_handle, int, char **); /* Plugin start */
/* Called just before plugin unloaded.
*/
#define PLUGIN_EXIT "plugin_exit"
typedef int (plgexit_t)(clicon_handle); /* Plugin exit */
/*! Called by restconf to check credentials and return username
@ -99,6 +96,14 @@ typedef void *transaction_data;
/* Transaction callbacks */
typedef int (trans_cb_t)(clicon_handle h, transaction_data td);
/* Hook to override default prompt with explicit function
* Format prompt before each getline
* @param[in] h Clicon handle
* @param[in] mode Cligen syntax mode
* @retval prompt Prompt to prepend all CLigen command lines
*/
typedef char *(cli_prompthook_t)(clicon_handle, char *mode);
/* plugin init struct for the api
* Note: Implicit init function
*/
@ -106,14 +111,20 @@ struct clixon_plugin_api;
typedef struct clixon_plugin_api* (plginit2_t)(clicon_handle); /* Clixon plugin Init */
struct clixon_plugin_api{
/*--- Common fields. ---*/
char ca_name[PATH_MAX]; /* Name of plugin (given by plugin) */
plginit2_t *ca_init; /* Clixon plugin Init (implicit) */
plgstart_t *ca_start; /* Plugin start */
plgexit_t *ca_exit; /* Plugin exit */
plgauth_t *ca_auth; /* Auth credentials */
/*--Above here common fields w clixon_backend_api ----------*/
plgreset_t *ca_reset; /* Reset system status (backend only) */
/*--- CLI plugin-only ---*/
cli_prompthook_t *ca_prompt; /* Prompt hook */
cligen_susp_cb_t *ca_suspend; /* Ctrl-Z hook, see cligen getline */
cligen_interrupt_cb_t *ca_interrupt; /* Ctrl-C, see cligen getline */
/*--- Backend plugin only ---*/
plgreset_t *ca_reset; /* Reset system status (backend only) */
plgstatedata_t *ca_statedata; /* Get state data from plugin (backend only) */
trans_cb_t *ca_trans_begin; /* Transaction start */
trans_cb_t *ca_trans_validate; /* Transaction validation */
@ -124,46 +135,34 @@ struct clixon_plugin_api{
};
typedef struct clixon_plugin_api clixon_plugin_api;
/*! Called when plugin loaded. Only mandadory callback. All others optional
* @see plginit_t
*/
/* Internal plugin structure with dlopen() handle and plugin_api
*/
struct clixon_plugin{
char cp_name[PATH_MAX]; /* Plugin filename. Note api ca_name is given by plugin itself */
plghndl_t cp_handle; /* Handle to plugin using dlopen(3) */
struct clixon_plugin_api cp_api;
char cp_name[PATH_MAX]; /* Plugin filename. Note api ca_name is given by plugin itself */
plghndl_t cp_handle; /* Handle to plugin using dlopen(3) */
clixon_plugin_api cp_api;
};
typedef struct clixon_plugin clixon_plugin;
/*
* Pseudo-Prototypes
* User-defineed plugins, not in library code
*/
#define CLIXON_PLUGIN_INIT "clixon_plugin_init" /* Nextgen */
/*! Plugin initialization
* @param[in] h Clixon handle
* @retval NULL Error with clicon_err set
* @retval api Pointer to API struct
*/
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
/*
* Prototypes
*/
clixon_plugin *plugin_each(clixon_plugin *cpprev);
clixon_plugin *plugin_each_revert(clixon_plugin *cpprev, int nr);
/*! Plugin initialization function. Must appear in all plugins
* @param[in] h Clixon handle
* @retval api Pointer to API struct
* @see CLIXON_PLUGIN_INIT default symbol
*/
clixon_plugin_api *clixon_plugin_init(clicon_handle h);
clixon_plugin *plugin_each(clicon_handle h, clixon_plugin *cpprev);
clixon_plugin *plugin_each_revert(clicon_handle h, clixon_plugin *cpprev, int nr);
clixon_plugin *plugin_find(clicon_handle h, char *name);
int clixon_plugins_load(clicon_handle h, char *function, char *dir);
/* obsolete */
plghndl_t plugin_load (clicon_handle h, char *file, int dlflags);
/* obsolete */
int plugin_unload(clicon_handle h, plghndl_t *handle);
int clixon_plugin_start(clicon_handle h, int argc, char **argv);
int clixon_plugin_exit(clicon_handle h);

View file

@ -60,7 +60,10 @@
#include "clixon_xml.h"
#include "clixon_plugin.h"
/* XXX The below should be placed in clixon handle when done */
/* List of plugins XXX
* 1. Place in clixon handle not global variables
* 2. Use qelem circular lists
*/
static clixon_plugin *_clixon_plugins = NULL; /* List of plugins (of client) */
static int _clixon_nplugins = 0; /* Number of plugins */
@ -69,17 +72,19 @@ static int _clixon_nplugins = 0; /* Number of plugins */
* @note Never manipulate the plugin during operation or using the
* same object recursively
*
* @param[in] h Clicon handle
* @param[in] plugin previous plugin, or NULL on init
* @code
* clicon_plugin *cp = NULL;
* while ((cp = plugin_each(cp)) != NULL) {
* while ((cp = plugin_each(h, cp)) != NULL) {
* ...
* }
* @endcode
* @note Not optimized, alwasy iterates from the start of the list
*/
clixon_plugin *
plugin_each(clixon_plugin *cpprev)
plugin_each(clicon_handle h,
clixon_plugin *cpprev)
{
int i;
clixon_plugin *cp;
@ -105,17 +110,19 @@ plugin_each(clixon_plugin *cpprev)
* @note Never manipulate the plugin during operation or using the
* same object recursively
*
* @param[in] h Clicon handle
* @param[in] plugin previous plugin, or NULL on init
* @code
* clicon_plugin *cp = NULL;
* while ((cp = plugin_each_revert(cp, nr)) != NULL) {
* while ((cp = plugin_each_revert(h, cp, nr)) != NULL) {
* ...
* }
* @endcode
* @note Not optimized, alwasy iterates from the start of the list
*/
clixon_plugin *
plugin_each_revert(clixon_plugin *cpprev,
plugin_each_revert(clicon_handle h,
clixon_plugin *cpprev,
int nr)
{
int i;
@ -137,6 +144,27 @@ plugin_each_revert(clixon_plugin *cpprev,
return cpnext;
}
/*! Find plugin by name
* @param[in] h Clicon handle
* @param[in] name Plugin name
* @retval p Plugin if found
* @retval NULL Not found
*/
clixon_plugin *
plugin_find(clicon_handle h,
char *name)
{
int i;
clixon_plugin *cp = NULL;
for (i = 0; i < _clixon_nplugins; i++) {
cp = &_clixon_plugins[i];
if (strcmp(cp->cp_name, name) == 0)
return cp;
}
return NULL;
}
/*! Load a dynamic plugin object and call its init-function
* @param[in] h Clicon handle
* @param[in] file Which plugin to load
@ -158,6 +186,7 @@ plugin_load_one(clicon_handle h,
clixon_plugin_api *api = NULL;
clixon_plugin *cp = NULL;
char *name;
char *p;
clicon_debug(1, "%s", __FUNCTION__);
dlerror(); /* Clear any existing error */
@ -187,10 +216,18 @@ plugin_load_one(clicon_handle h,
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(cp, 0, sizeof(struct clixon_plugin));
cp->cp_handle = handle;
/* Extract string after last '/' in filename, if any */
name = strrchr(file, '/') ? strrchr(file, '/')+1 : file;
/* strip extension, eg .so from name */
if ((p=strrchr(name, '.')) != NULL)
*p = '\0';
/* Copy name to struct */
memcpy(cp->cp_name, name, strlen(name)+1);
snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s",
(int)strlen(name)-2, name);
(int)strlen(name), name);
cp->cp_api = *api;
clicon_debug(1, "%s", __FUNCTION__);
done:
@ -246,80 +283,6 @@ done:
return retval;
}
/*! Load a dynamic plugin object and call its init-function
* Note 'file' may be destructively modified
* @param[in] h Clicon handle
* @param[in] file Which plugin to load
* @param[in] dlflags See man(3) dlopen
* @note OBSOLETE
*/
plghndl_t
plugin_load(clicon_handle h,
char *file,
int dlflags)
{
char *error;
void *handle = NULL;
plginit_t *initfn;
clicon_debug(1, "%s", __FUNCTION__);
dlerror(); /* Clear any existing error */
if ((handle = dlopen(file, dlflags)) == NULL) {
error = (char*)dlerror();
clicon_err(OE_PLUGIN, errno, "dlopen: %s\n", error ? error : "Unknown error");
goto done;
}
/* call plugin_init() if defined */
if ((initfn = dlsym(handle, PLUGIN_INIT)) == NULL){
clicon_err(OE_PLUGIN, errno, "Failed to find plugin_init when loading clixon plugin %s", file);
goto err;
}
if ((error = (char*)dlerror()) != NULL) {
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
goto done;
}
if (initfn(h) != 0) {
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
if (!clicon_errno) /* sanity: log if clicon_err() is not called ! */
clicon_err(OE_DB, 0, "Unknown error: %s: plugin_init does not make clicon_err call on error",
file);
goto err;
}
done:
return handle;
err:
if (handle)
dlclose(handle);
return NULL;
}
/*! Unload a plugin
* @param[in] h Clicon handle
* @param[in] handle Clicon handle
* @note OBSOLETE
*/
int
plugin_unload(clicon_handle h,
plghndl_t *handle)
{
int retval = 0;
char *error;
plgexit_t *exitfn;
/* Call exit function is it exists */
exitfn = dlsym(handle, PLUGIN_EXIT);
if (dlerror() == NULL)
exitfn(h);
dlerror(); /* Clear any existing error */
if (dlclose(handle) != 0) {
error = (char*)dlerror();
clicon_err(OE_PLUGIN, errno, "dlclose: %s\n", error ? error : "Unknown error");
/* Just report */
}
return retval;
}
/*! Call plugin_start in all plugins
* @param[in] h Clicon handle
*/
@ -425,7 +388,7 @@ clixon_plugin_auth(clicon_handle h,
*/
typedef struct {
qelem_t rc_qelem; /* List header */
clicon_rpc_cb rc_callback; /* RPC Callback */
clicon_rpc_cb rc_callback; /* RPC Callback */
void *rc_arg; /* Application specific argument to cb */
char *rc_tag; /* Xml/json tag when matched, callback called */
} rpc_callback_t;