Merge "Modules: Additional improvements to CLI completion."
This commit is contained in:
commit
306e7912db
3 changed files with 131 additions and 52 deletions
|
@ -94,6 +94,20 @@ enum ast_module_support_level {
|
|||
AST_MODULE_SUPPORT_DEPRECATED,
|
||||
};
|
||||
|
||||
/*! Used to specify which modules should be returned by ast_module_helper. */
|
||||
enum ast_module_helper_type {
|
||||
/*! Modules that are loaded by dlopen. */
|
||||
AST_MODULE_HELPER_LOADED = 0,
|
||||
/*! Running modules that include a reload callback. */
|
||||
AST_MODULE_HELPER_RELOAD = 1,
|
||||
/*! Modules that can be loaded or started. */
|
||||
AST_MODULE_HELPER_LOAD,
|
||||
/*! Modules that can be unloaded. */
|
||||
AST_MODULE_HELPER_UNLOAD,
|
||||
/*! Running modules */
|
||||
AST_MODULE_HELPER_RUNNING,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Load a module.
|
||||
* \param resource_name The name of the module to load.
|
||||
|
@ -237,14 +251,12 @@ int ast_loader_unregister(int (*updater)(void));
|
|||
* \param state The possible match to return.
|
||||
* \param rpos The position we should be matching. This should be the same as
|
||||
* pos.
|
||||
* \param needsreload This should be 1 if we need to reload this module and 0
|
||||
* otherwise. This function will only return modules that are reloadble
|
||||
* if this is 1.
|
||||
* \param type The type of action that will be performed by CLI.
|
||||
*
|
||||
* \retval A possible completion of the partial match.
|
||||
* \retval NULL if no matches were found.
|
||||
*/
|
||||
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload);
|
||||
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type);
|
||||
|
||||
/* Opaque type for module handles generated by the loader */
|
||||
|
||||
|
|
44
main/cli.c
44
main/cli.c
|
@ -45,7 +45,6 @@
|
|||
#include <regex.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <editline/readline.h>
|
||||
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
|
@ -224,28 +223,6 @@ static int cli_has_permissions(int uid, int gid, const char *command)
|
|||
|
||||
static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
|
||||
|
||||
static char *complete_fn(const char *word, int state)
|
||||
{
|
||||
char *c, *d;
|
||||
char filename[PATH_MAX];
|
||||
|
||||
if (word[0] == '/')
|
||||
ast_copy_string(filename, word, sizeof(filename));
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
|
||||
|
||||
c = d = filename_completion_function(filename, state);
|
||||
|
||||
if (c && word[0] != '/')
|
||||
c += (strlen(ast_config_AST_MODULE_DIR) + 1);
|
||||
if (c)
|
||||
c = ast_strdup(c);
|
||||
|
||||
ast_std_free(d);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
/* "module load <mod>" */
|
||||
|
@ -258,12 +235,14 @@ static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *
|
|||
return NULL;
|
||||
|
||||
case CLI_GENERATE:
|
||||
if (a->pos != e->args)
|
||||
if (a->pos != e->args) {
|
||||
return NULL;
|
||||
return complete_fn(a->word, a->n);
|
||||
}
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOAD);
|
||||
}
|
||||
if (a->argc != e->args + 1)
|
||||
if (a->argc != e->args + 1) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
if (ast_load_resource(a->argv[e->args])) {
|
||||
ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
|
||||
return CLI_FAILURE;
|
||||
|
@ -286,7 +265,7 @@ static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
|
|||
return NULL;
|
||||
|
||||
case CLI_GENERATE:
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1);
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RELOAD);
|
||||
}
|
||||
if (a->argc == e->args) {
|
||||
ast_module_reload(NULL);
|
||||
|
@ -482,7 +461,7 @@ static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args
|
|||
}
|
||||
} else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel"))
|
||||
|| (a->pos == 5 && atleast)) {
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RUNNING);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -733,7 +712,7 @@ static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args
|
|||
return NULL;
|
||||
|
||||
case CLI_GENERATE:
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD);
|
||||
}
|
||||
if (a->argc < e->args + 1)
|
||||
return CLI_SHOWUSAGE;
|
||||
|
@ -889,10 +868,11 @@ static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
|
|||
return NULL;
|
||||
|
||||
case CLI_GENERATE:
|
||||
if (a->pos == e->args)
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
|
||||
else
|
||||
if (a->pos == e->args) {
|
||||
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOADED);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* all the above return, so we proceed with the handler.
|
||||
* we are guaranteed to have argc >= e->args
|
||||
|
|
119
main/loader.c
119
main/loader.c
|
@ -36,6 +36,7 @@
|
|||
#include "asterisk/_private.h"
|
||||
#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
|
||||
#include <dirent.h>
|
||||
#include <editline/readline.h>
|
||||
|
||||
#include "asterisk/dlinkedlists.h"
|
||||
#include "asterisk/module.h"
|
||||
|
@ -702,35 +703,121 @@ int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode f
|
|||
return res;
|
||||
}
|
||||
|
||||
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
|
||||
static int module_matches_helper_type(struct ast_module *mod, enum ast_module_helper_type type)
|
||||
{
|
||||
struct ast_module *cur;
|
||||
int i, which=0, l = strlen(word);
|
||||
switch (type) {
|
||||
case AST_MODULE_HELPER_UNLOAD:
|
||||
return !mod->usecount && mod->flags.running && !mod->flags.declined;
|
||||
|
||||
case AST_MODULE_HELPER_RELOAD:
|
||||
return mod->flags.running && mod->info->reload;
|
||||
|
||||
case AST_MODULE_HELPER_RUNNING:
|
||||
return mod->flags.running;
|
||||
|
||||
case AST_MODULE_HELPER_LOADED:
|
||||
/* if we have a 'struct ast_module' then we're loaded. */
|
||||
return 1;
|
||||
default:
|
||||
/* This function is not called for AST_MODULE_HELPER_LOAD. */
|
||||
/* Unknown ast_module_helper_type. Assume it doesn't match. */
|
||||
ast_assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *module_load_helper(const char *word, int state)
|
||||
{
|
||||
struct ast_module *mod;
|
||||
int which = 0;
|
||||
char *name;
|
||||
char *ret = NULL;
|
||||
char *editline_ret;
|
||||
char fullpath[PATH_MAX];
|
||||
int idx = 0;
|
||||
/* This is needed to avoid listing modules that are already running. */
|
||||
AST_VECTOR(, char *) running_modules;
|
||||
|
||||
AST_VECTOR_INIT(&running_modules, 200);
|
||||
|
||||
AST_DLLIST_LOCK(&module_list);
|
||||
AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
|
||||
if (mod->flags.running) {
|
||||
AST_VECTOR_APPEND(&running_modules, mod->resource);
|
||||
}
|
||||
}
|
||||
|
||||
if (word[0] == '/') {
|
||||
/* BUGBUG: we should not support this. */
|
||||
ast_copy_string(fullpath, word, sizeof(fullpath));
|
||||
} else {
|
||||
snprintf(fullpath, sizeof(fullpath), "%s/%s", ast_config_AST_MODULE_DIR, word);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is ugly that we keep calling filename_completion_function.
|
||||
* The only way to avoid this would be to make a copy of the function
|
||||
* that skips matches found in the running_modules vector.
|
||||
*/
|
||||
while (!ret && (name = editline_ret = filename_completion_function(fullpath, idx++))) {
|
||||
if (word[0] != '/') {
|
||||
name += (strlen(ast_config_AST_MODULE_DIR) + 1);
|
||||
}
|
||||
|
||||
/* Don't list files that are already loaded! */
|
||||
if (!AST_VECTOR_GET_CMP(&running_modules, name, !strcasecmp) && ++which > state) {
|
||||
ret = ast_strdup(name);
|
||||
}
|
||||
|
||||
ast_std_free(editline_ret);
|
||||
}
|
||||
|
||||
/* Do not clean-up the elements, they belong to module_list. */
|
||||
AST_VECTOR_FREE(&running_modules);
|
||||
AST_DLLIST_UNLOCK(&module_list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
|
||||
{
|
||||
struct ast_module *mod;
|
||||
int which = 0;
|
||||
int wordlen = strlen(word);
|
||||
char *ret = NULL;
|
||||
|
||||
if (pos != rpos) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type == AST_MODULE_HELPER_LOAD) {
|
||||
return module_load_helper(word, state);
|
||||
}
|
||||
|
||||
if (type == AST_MODULE_HELPER_RELOAD) {
|
||||
int idx;
|
||||
|
||||
for (idx = 0; reload_classes[idx].name; idx++) {
|
||||
if (!strncasecmp(word, reload_classes[idx].name, wordlen) && ++which > state) {
|
||||
return ast_strdup(reload_classes[idx].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AST_DLLIST_LOCK(&module_list);
|
||||
AST_DLLIST_TRAVERSE(&module_list, cur, entry) {
|
||||
if (!strncasecmp(word, cur->resource, l) &&
|
||||
(cur->info->reload || !needsreload) &&
|
||||
++which > state) {
|
||||
ret = ast_strdup(cur->resource);
|
||||
AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
|
||||
if (!module_matches_helper_type(mod, type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncasecmp(word, mod->resource, wordlen) && ++which > state) {
|
||||
ret = ast_strdup(mod->resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_DLLIST_UNLOCK(&module_list);
|
||||
|
||||
if (!ret && needsreload) {
|
||||
for (i=0; !ret && reload_classes[i].name; i++) {
|
||||
if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state) {
|
||||
ret = ast_strdup(reload_classes[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue