CLI plugin API restructuring completed. Now all plugin APIs have the generic form
documented in README and FAQ.
This commit is contained in:
parent
afb6aa31db
commit
2e00411621
19 changed files with 317 additions and 551 deletions
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue