diff --git a/include/asterisk/file.h b/include/asterisk/file.h index 453dc0746a1abb490b25b99d51096d47a5d4242d..c17cb327b3a6468848f96daa40184a010a2e7983 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -143,6 +143,11 @@ int ast_filecopy(const char *oldname, const char *newname, const char *fmt); * \param filename the name of the file * \param obj user data object * \return non-zero to stop reading, otherwise zero to continue + * + * \note dir_name is not processed by realpath or other functions, + * symbolic links are not resolved. This ensures dir_name + * always starts with the exact string originally passed to + * \ref ast_file_read_dir or \ref ast_file_read_dirs. */ typedef int (*ast_file_on_file)(const char *dir_name, const char *filename, void *obj); diff --git a/main/Makefile b/main/Makefile index b148b6f81e1128a5001c69d11203eafb7c69c015..7e9624ee1819330481fbfd39c16e5216c7ddd8c4 100644 --- a/main/Makefile +++ b/main/Makefile @@ -154,7 +154,6 @@ endif db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE) asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE) -loader.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE) json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE) bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE) crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE) diff --git a/main/loader.c b/main/loader.c index 159014e7215b8f02905a0fa3ac6b5bb5956a1805..6b29f0e969b6f8476635576e8107defde697daec 100644 --- a/main/loader.c +++ b/main/loader.c @@ -36,7 +36,6 @@ #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" @@ -56,6 +55,7 @@ #include "asterisk/app.h" #include "asterisk/test.h" #include "asterisk/sounds_index.h" +#include "asterisk/cli.h" #include <dlfcn.h> @@ -1036,57 +1036,55 @@ static int module_matches_helper_type(struct ast_module *mod, enum ast_module_he } } -static char *module_load_helper(const char *word, int state) +struct module_load_word { + const char *word; + size_t len; + size_t moddir_len; +}; + +static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj) { + struct module_load_word *word = obj; 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; + char *filename_merged = NULL; - AST_VECTOR_INIT(&running_modules, 200); + /* dir_name will never be shorter than word->moddir_len. */ + dir_name += word->moddir_len; + if (!ast_strlen_zero(dir_name)) { + ast_assert(dir_name[0] == '/'); - AST_DLLIST_LOCK(&module_list); - AST_DLLIST_TRAVERSE(&module_list, mod, entry) { - if (mod->flags.running) { - AST_VECTOR_APPEND(&running_modules, mod->resource); + dir_name += 1; + if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) { + /* If we can't allocate the string just give up! */ + return -1; } + filename = filename_merged; } - 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); + if (!strncasecmp(filename, word->word, word->len)) { + /* Don't list files that are already loaded! */ + mod = find_resource(filename, 0); + if (!mod || !mod->flags.running) { + ast_cli_completion_add(ast_strdup(filename)); + } } - /* - * 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); - } + ast_free(filename_merged); - /* Don't list files that are already loaded! */ - if (!AST_VECTOR_GET_CMP(&running_modules, name, !strcasecmp) && ++which > state) { - ret = ast_strdup(name); - } + return 0; +} - ast_std_free(editline_ret); - } +static void module_load_helper(const char *word) +{ + struct module_load_word word_l = { + .word = word, + .len = strlen(word), + .moddir_len = strlen(ast_config_AST_MODULE_DIR), + }; - /* Do not clean-up the elements, they belong to module_list. */ - AST_VECTOR_FREE(&running_modules); + AST_DLLIST_LOCK(&module_list); + ast_file_read_dirs(ast_config_AST_MODULE_DIR, module_load_helper_on_file, &word_l, -1); 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) @@ -1101,7 +1099,9 @@ char *ast_module_helper(const char *line, const char *word, int pos, int state, } if (type == AST_MODULE_HELPER_LOAD) { - return module_load_helper(word, state); + module_load_helper(word); + + return NULL; } if (type == AST_MODULE_HELPER_RELOAD) {