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
|
|
@ -66,13 +66,6 @@
|
|||
#include "cli_plugin.h"
|
||||
#include "cli_handle.h"
|
||||
|
||||
/*! Name of master plugin functions
|
||||
* More in clicon_plugin.h
|
||||
* @note not really used consider documenting or remove
|
||||
*/
|
||||
#define PLUGIN_PROMPT_HOOK "plugin_prompt_hook"
|
||||
#define PLUGIN_SUSP_HOOK "plugin_susp_hook"
|
||||
|
||||
/*
|
||||
*
|
||||
* CLI PLUGIN INTERFACE, INTERNAL SECTION
|
||||
|
|
@ -82,7 +75,9 @@
|
|||
/*! Find syntax mode named 'mode'. Create if specified
|
||||
*/
|
||||
static cli_syntaxmode_t *
|
||||
syntax_mode_find(cli_syntax_t *stx, const char *mode, int create)
|
||||
syntax_mode_find(cli_syntax_t *stx,
|
||||
const char *mode,
|
||||
int create)
|
||||
{
|
||||
cli_syntaxmode_t *m;
|
||||
|
||||
|
|
@ -111,40 +106,26 @@ syntax_mode_find(cli_syntax_t *stx, const char *mode, int create)
|
|||
return m;
|
||||
}
|
||||
|
||||
/*! Find plugin by name
|
||||
*/
|
||||
static struct cli_plugin *
|
||||
plugin_find_cli(cli_syntax_t *stx, char *plgnam)
|
||||
{
|
||||
struct cli_plugin *p;
|
||||
|
||||
if ((p = stx->stx_plugins) != NULL)
|
||||
do {
|
||||
if (strcmp (p->cp_name, plgnam) == 0)
|
||||
return p;
|
||||
p = NEXTQ(struct cli_plugin *, p);
|
||||
} while (p && p != stx->stx_plugins);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Generate parse tree for syntax mode
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] m Syntax mode struct
|
||||
*/
|
||||
static int
|
||||
gen_parse_tree(clicon_handle h, cli_syntaxmode_t *m)
|
||||
gen_parse_tree(clicon_handle h,
|
||||
cli_syntaxmode_t *m)
|
||||
{
|
||||
cligen_tree_add(cli_cligen(h), m->csm_name, m->csm_pt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! Append syntax
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
static int
|
||||
syntax_append(clicon_handle h,
|
||||
cli_syntax_t *stx,
|
||||
const char *name,
|
||||
parse_tree pt)
|
||||
const char *name,
|
||||
parse_tree pt)
|
||||
{
|
||||
cli_syntaxmode_t *m;
|
||||
|
||||
|
|
@ -157,27 +138,18 @@ syntax_append(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Unload all plugins in a group
|
||||
/*! Remove all cligen syntax modes
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
static int
|
||||
cli_syntax_unload(clicon_handle h)
|
||||
{
|
||||
cli_syntax_t *stx = cli_syntax(h);
|
||||
struct cli_plugin *p;
|
||||
cli_syntaxmode_t *m;
|
||||
|
||||
if (stx == NULL)
|
||||
return 0;
|
||||
|
||||
while (stx->stx_nplugins > 0) {
|
||||
p = stx->stx_plugins;
|
||||
plugin_unload(h, p->cp_handle);
|
||||
clicon_debug(1, "DEBUG: Plugin '%s' unloaded.", p->cp_name);
|
||||
DELQ(p, stx->stx_plugins, struct cli_plugin *);
|
||||
if (p)
|
||||
free(p);
|
||||
stx->stx_nplugins--;
|
||||
}
|
||||
while (stx->stx_nmodes > 0) {
|
||||
m = stx->stx_modes;
|
||||
DELQ(m, stx->stx_modes, cli_syntaxmode_t *);
|
||||
|
|
@ -237,34 +209,6 @@ clixon_str2fn(char *name,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*! Load a dynamic plugin object and call it's init-function
|
||||
* Note 'file' may be destructively modified
|
||||
* @retval plugin-handle should be freed after use
|
||||
*/
|
||||
static plghndl_t
|
||||
cli_plugin_load(clicon_handle h,
|
||||
char *file,
|
||||
int dlflags)
|
||||
{
|
||||
char *name;
|
||||
plghndl_t handle = NULL;
|
||||
struct cli_plugin *cp = NULL;
|
||||
|
||||
if ((handle = plugin_load(h, file, dlflags)) == NULL)
|
||||
goto quit;
|
||||
if ((cp = malloc(sizeof (struct cli_plugin))) == NULL) {
|
||||
perror("malloc");
|
||||
goto quit;
|
||||
}
|
||||
memset (cp, 0, sizeof(*cp));
|
||||
name = basename(file);
|
||||
snprintf(cp->cp_name, sizeof(cp->cp_name), "%.*s", (int)strlen(name)-3, name);
|
||||
cp->cp_handle = handle;
|
||||
|
||||
quit:
|
||||
return cp;
|
||||
}
|
||||
|
||||
/*! Append to syntax mode from file
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] filename Name of file where syntax is specified (in syntax-group dir)
|
||||
|
|
@ -286,7 +230,7 @@ cli_load_syntax(clicon_handle h,
|
|||
char **vec = NULL;
|
||||
int i, nvec;
|
||||
char *plgnam;
|
||||
struct cli_plugin *p;
|
||||
clixon_plugin *cp;
|
||||
|
||||
if (dir)
|
||||
snprintf(filepath, MAXPATHLEN-1, "%s/%s", dir, filename);
|
||||
|
|
@ -316,8 +260,8 @@ cli_load_syntax(clicon_handle h,
|
|||
mode = cvec_find_str(cvv, "CLICON_MODE");
|
||||
|
||||
if (plgnam != NULL) { /* Find plugin for callback resolving */
|
||||
if ((p = plugin_find_cli (cli_syntax(h), plgnam)) != NULL)
|
||||
handle = p->cp_handle;
|
||||
if ((cp = plugin_find(h, plgnam)) != NULL)
|
||||
handle = cp->cp_handle;
|
||||
if (handle == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "CLICON_PLUGIN set to '%s' in %s but plugin %s.so not found in %s\n",
|
||||
plgnam, filename, plgnam,
|
||||
|
|
@ -325,7 +269,6 @@ cli_load_syntax(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve callback names to function pointers. */
|
||||
if (cligen_callbackv_str2fn(pt, (cgv_str2fn_t*)clixon_str2fn, handle) < 0){
|
||||
clicon_err(OE_PLUGIN, 0, "Mismatch between CLIgen file '%s' and CLI plugin file '%s'. Some possible errors:\n\t1. A function given in the CLIgen file does not exist in the plugin (ie link error)\n\t2. The CLIgen spec does not point to the correct plugin .so file (CLICON_PLUGIN=\"%s\" is wrong)",
|
||||
|
|
@ -343,7 +286,10 @@ cli_load_syntax(clicon_handle h,
|
|||
if ((vec = clicon_strsep(mode, ":", &nvec)) == NULL)
|
||||
goto done;
|
||||
for (i = 0; i < nvec; i++) {
|
||||
if (syntax_append(h, cli_syntax(h), vec[i], pt) < 0) {
|
||||
if (syntax_append(h,
|
||||
cli_syntax(h),
|
||||
vec[i],
|
||||
pt) < 0) {
|
||||
goto done;
|
||||
}
|
||||
if (prompt)
|
||||
|
|
@ -361,74 +307,7 @@ done:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Load plugins within a directory
|
||||
*/
|
||||
static int
|
||||
cli_plugin_load_dir(clicon_handle h,
|
||||
char *dir,
|
||||
cli_syntax_t *stx)
|
||||
{
|
||||
int i;
|
||||
int ndp;
|
||||
struct dirent *dp = NULL;
|
||||
char *master_plugin;
|
||||
char master[MAXPATHLEN];
|
||||
char filename[MAXPATHLEN];
|
||||
struct cli_plugin *cp;
|
||||
struct stat st;
|
||||
int retval = -1;
|
||||
|
||||
/* Format master plugin path */
|
||||
if ((master_plugin = clicon_master_plugin(h)) == NULL){
|
||||
clicon_err(OE_PLUGIN, 0, "clicon_master_plugin option not set");
|
||||
goto quit;
|
||||
}
|
||||
snprintf(master, MAXPATHLEN-1, "%s.so", master_plugin);
|
||||
|
||||
/* Get plugin objects names from plugin directory */
|
||||
ndp = clicon_file_dirent(dir, &dp, "(.so)$", S_IFREG);
|
||||
if (ndp < 0)
|
||||
goto quit;
|
||||
|
||||
/* Load master plugin first */
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, master);
|
||||
if (stat(filename, &st) == 0) {
|
||||
clicon_debug(1, "DEBUG: Loading master plugin '%s'", master);
|
||||
cp = cli_plugin_load(h, filename, RTLD_NOW|RTLD_GLOBAL);
|
||||
if (cp == NULL)
|
||||
goto quit;
|
||||
/* Look up certain call-backs in master plugin */
|
||||
stx->stx_prompt_hook =
|
||||
dlsym(cp->cp_handle, PLUGIN_PROMPT_HOOK);
|
||||
stx->stx_susp_hook =
|
||||
dlsym(cp->cp_handle, PLUGIN_SUSP_HOOK);
|
||||
INSQ(cp, stx->stx_plugins);
|
||||
stx->stx_nplugins++;
|
||||
}
|
||||
|
||||
/* Load the rest */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
if (strcmp (dp[i].d_name, master) == 0)
|
||||
continue; /* Skip master now */
|
||||
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
|
||||
clicon_debug(1, "DEBUG: Loading plugin '%s'", dp[i].d_name);
|
||||
|
||||
if ((cp = cli_plugin_load (h, filename, RTLD_NOW)) == NULL)
|
||||
goto quit;
|
||||
INSQ(cp, stx->stx_plugins);
|
||||
stx->stx_nplugins++;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
||||
quit:
|
||||
if (dp)
|
||||
free(dp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Load a syntax group.
|
||||
/*! Load a syntax group. Includes both CLI plugin and CLIgen spec syntax files.
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
|
|
@ -443,6 +322,9 @@ cli_syntax_load (clicon_handle h)
|
|||
struct dirent *dp = NULL;
|
||||
cli_syntax_t *stx;
|
||||
cli_syntaxmode_t *m;
|
||||
cligen_susp_cb_t *fns = NULL;
|
||||
cligen_interrupt_cb_t *fni = NULL;
|
||||
clixon_plugin *cp;
|
||||
|
||||
/* Syntax already loaded. XXX should we re-load?? */
|
||||
if ((stx = cli_syntax(h)) != NULL)
|
||||
|
|
@ -456,59 +338,62 @@ cli_syntax_load (clicon_handle h)
|
|||
/* Allocate plugin group object */
|
||||
if ((stx = malloc(sizeof(*stx))) == NULL) {
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto quit;
|
||||
goto done;
|
||||
}
|
||||
memset (stx, 0, sizeof (*stx)); /* Zero out all */
|
||||
|
||||
cli_syntax_set(h, stx);
|
||||
|
||||
/* First load CLICON system plugins. CLIXON_CLI_SYSDIR is defined
|
||||
in Makefile*/
|
||||
if (cli_plugin_load_dir(h, CLIXON_CLI_SYSDIR, stx) < 0)
|
||||
goto quit;
|
||||
|
||||
/* Then load application plugins */
|
||||
if (plugin_dir && cli_plugin_load_dir(h, plugin_dir, stx) < 0)
|
||||
goto quit;
|
||||
|
||||
/* Load cli plugins */
|
||||
if (plugin_dir &&
|
||||
clixon_plugins_load(h, CLIXON_PLUGIN_INIT, plugin_dir)< 0)
|
||||
goto done;
|
||||
if (clispec_file){
|
||||
if (cli_load_syntax(h, clispec_file, NULL) < 0)
|
||||
goto quit;
|
||||
goto done;
|
||||
}
|
||||
if (clispec_dir){
|
||||
/* load syntaxfiles */
|
||||
if ((ndp = clicon_file_dirent(clispec_dir, &dp, "(.cli)$", S_IFREG)) < 0)
|
||||
goto quit;
|
||||
goto done;
|
||||
/* Load the rest */
|
||||
for (i = 0; i < ndp; i++) {
|
||||
clicon_debug(1, "DEBUG: Loading syntax '%.*s'",
|
||||
(int)strlen(dp[i].d_name)-4, dp[i].d_name);
|
||||
if (cli_load_syntax(h, dp[i].d_name, clispec_dir) < 0)
|
||||
goto quit;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* Did we successfully load any syntax modes? */
|
||||
if (stx->stx_nmodes <= 0) {
|
||||
retval = 0;
|
||||
goto quit;
|
||||
goto done;
|
||||
}
|
||||
/* Parse syntax tree for all modes */
|
||||
m = stx->stx_modes;
|
||||
do {
|
||||
if (gen_parse_tree(h, m) != 0)
|
||||
goto quit;
|
||||
goto done;
|
||||
m = NEXTQ(cli_syntaxmode_t *, m);
|
||||
} while (m && m != stx->stx_modes);
|
||||
|
||||
|
||||
/* Set callbacks into CLIgen */
|
||||
cli_susp_hook(h, cli_syntax(h)->stx_susp_hook);
|
||||
/* Set susp and interrupt callbacks into CLIgen */
|
||||
cp = NULL;
|
||||
while ((cp = plugin_each(h, cp)) != NULL) {
|
||||
if (fns==NULL && (fns = cp->cp_api.ca_suspend) != NULL)
|
||||
if (cli_susp_hook(h, fns) < 0)
|
||||
goto done;
|
||||
if (fni==NULL && (fni = cp->cp_api.ca_interrupt) != NULL)
|
||||
if (cli_susp_hook(h, fns) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* All good. We can now proudly return a new group */
|
||||
retval = 0;
|
||||
|
||||
quit:
|
||||
done:
|
||||
if (retval != 0) {
|
||||
clixon_plugin_exit(h);
|
||||
cli_syntax_unload(h);
|
||||
cli_syntax_set(h, NULL);
|
||||
}
|
||||
|
|
@ -517,34 +402,15 @@ quit:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Call plugin_start() in all plugins
|
||||
*/
|
||||
int
|
||||
cli_plugin_start(clicon_handle h, int argc, char **argv)
|
||||
{
|
||||
struct cli_plugin *p;
|
||||
cli_syntax_t *stx;
|
||||
plgstart_t *startfun;
|
||||
// XXX int (*startfun)(clicon_handle, int, char **);
|
||||
|
||||
stx = cli_syntax(h);
|
||||
|
||||
if ((p = stx->stx_plugins) != NULL)
|
||||
do {
|
||||
startfun = dlsym(p->cp_handle, PLUGIN_START);
|
||||
if (dlerror() == NULL)
|
||||
startfun(h, argc, argv);
|
||||
p = NEXTQ(struct cli_plugin *, p);
|
||||
} while (p && p != stx->stx_plugins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
/*! Remove syntax modes and remove syntax
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
cli_plugin_finish(clicon_handle h)
|
||||
{
|
||||
/* Remove all CLI plugins */
|
||||
clixon_plugin_exit(h);
|
||||
/* Remove all cligen syntax modes */
|
||||
cli_syntax_unload(h);
|
||||
cli_syntax_set(h, NULL);
|
||||
return 0;
|
||||
|
|
@ -553,6 +419,7 @@ cli_plugin_finish(clicon_handle h)
|
|||
/*! Help function to print a meaningful error string.
|
||||
* Sometimes the libraries specify an error string, if so print that.
|
||||
* Otherwise just print 'command error'.
|
||||
* @param[in] f File handler to write error to.
|
||||
*/
|
||||
int
|
||||
cli_handler_err(FILE *f)
|
||||
|
|
@ -704,22 +571,30 @@ done:
|
|||
}
|
||||
|
||||
/*! Read command from CLIgen's cliread() using current syntax mode.
|
||||
* @param[in] h Clicon handle
|
||||
* @retval string char* buffer containing CLIgen command
|
||||
* @retval NULL Fatal error
|
||||
*/
|
||||
char *
|
||||
clicon_cliread(clicon_handle h)
|
||||
{
|
||||
char *ret;
|
||||
char *pfmt = NULL;
|
||||
char *ret;
|
||||
char *pfmt = NULL;
|
||||
cli_syntaxmode_t *mode;
|
||||
cli_syntax_t *stx;
|
||||
|
||||
cli_syntax_t *stx;
|
||||
cli_prompthook_t *fn;
|
||||
clixon_plugin *cp;
|
||||
|
||||
stx = cli_syntax(h);
|
||||
mode = stx->stx_active_mode;
|
||||
|
||||
if (stx->stx_prompt_hook)
|
||||
pfmt = stx->stx_prompt_hook(h, mode->csm_name);
|
||||
/* Get prompt from plugin callback? */
|
||||
cp = NULL;
|
||||
while ((cp = plugin_each(h, cp)) != NULL) {
|
||||
if ((fn = cp->cp_api.ca_prompt) == NULL)
|
||||
continue;
|
||||
pfmt = fn(h, mode->csm_name);
|
||||
break;
|
||||
}
|
||||
if (clicon_quiet_mode(h))
|
||||
cli_prompt_set(h, "");
|
||||
else
|
||||
|
|
@ -732,6 +607,7 @@ clicon_cliread(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Initialize plugin code (not the plugins themselves)
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
cli_plugin_init(clicon_handle h)
|
||||
|
|
@ -746,11 +622,12 @@ cli_plugin_init(clicon_handle h)
|
|||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Set syntax mode mode for existing current plugin group.
|
||||
/*! Set syntax mode mode for existing current plugin group.
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
int
|
||||
cli_set_syntax_mode(clicon_handle h, const char *name)
|
||||
cli_set_syntax_mode(clicon_handle h,
|
||||
const char *name)
|
||||
{
|
||||
cli_syntaxmode_t *mode;
|
||||
|
||||
|
|
@ -761,8 +638,8 @@ cli_set_syntax_mode(clicon_handle h, const char *name)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get syntax mode name
|
||||
/*! Get syntax mode name
|
||||
* @param[in] h Clicon handle
|
||||
*/
|
||||
char *
|
||||
cli_syntax_mode(clicon_handle h)
|
||||
|
|
@ -774,14 +651,15 @@ cli_syntax_mode(clicon_handle h)
|
|||
return csm->csm_name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback from cli_set_prompt(). Set prompt format for syntax mode
|
||||
* Arguments:
|
||||
* name : Name of syntax mode
|
||||
* prompt : Prompt format
|
||||
/*! Callback from cli_set_prompt(). Set prompt format for syntax mode
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] name Name of syntax mode
|
||||
* @param[in] prompt Prompt format
|
||||
*/
|
||||
int
|
||||
cli_set_prompt(clicon_handle h, const char *name, const char *prompt)
|
||||
cli_set_prompt(clicon_handle h,
|
||||
const char *name,
|
||||
const char *prompt)
|
||||
{
|
||||
cli_syntaxmode_t *m;
|
||||
|
||||
|
|
@ -793,9 +671,14 @@ cli_set_prompt(clicon_handle h, const char *name, const char *prompt)
|
|||
}
|
||||
|
||||
/*! Format prompt
|
||||
* @param[out] prompt Prompt string to be written
|
||||
* @param[in] plen Length of prompt string
|
||||
* @param[in] fmt Stdarg fmt string
|
||||
*/
|
||||
static int
|
||||
prompt_fmt (char *prompt, size_t plen, char *fmt, ...)
|
||||
prompt_fmt (char *prompt,
|
||||
size_t plen,
|
||||
char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *s = fmt;
|
||||
|
|
@ -849,6 +732,7 @@ done:
|
|||
}
|
||||
|
||||
/*! Return a formatted prompt string
|
||||
* @param[in] fmt Format string
|
||||
*/
|
||||
char *
|
||||
cli_prompt(char *fmt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue