diff options
Diffstat (limited to 'storage/mroonga/vendor/groonga/lib/plugin.c')
-rw-r--r-- | storage/mroonga/vendor/groonga/lib/plugin.c | 1396 |
1 files changed, 1396 insertions, 0 deletions
diff --git a/storage/mroonga/vendor/groonga/lib/plugin.c b/storage/mroonga/vendor/groonga/lib/plugin.c new file mode 100644 index 00000000..ce4e3347 --- /dev/null +++ b/storage/mroonga/vendor/groonga/lib/plugin.c @@ -0,0 +1,1396 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2012-2017 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA +*/ +#include "grn.h" +#include "grn_ctx_impl_mrb.h" +#include "grn_proc.h" +#include <groonga/plugin.h> + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include <sys/stat.h> +#ifdef HAVE_DIRENT_H +# include <dirent.h> +#endif /* HAVE_DIRENT_H */ + +#ifndef S_ISREG +# ifdef _S_IFREG +# define S_ISREG(mode) (mode & _S_IFREG) +# endif /* _S_IFREG */ +#endif /* !S_ISREG */ + +#include "grn_db.h" +#include "grn_plugin.h" +#include "grn_ctx_impl.h" +#include "grn_util.h" + +#ifdef GRN_WITH_MRUBY +# include <mruby.h> +#endif /* GRN_WITH_MRUBY */ + +static grn_hash *grn_plugins = NULL; +static grn_critical_section grn_plugins_lock; +static grn_ctx grn_plugins_ctx; + +#ifdef HAVE_DLFCN_H +# include <dlfcn.h> +# define grn_dl_open(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL) +# define grn_dl_open_error_label() dlerror() +# define grn_dl_close(dl) (dlclose(dl) == 0) +# define grn_dl_close_error_label() dlerror() +# define grn_dl_sym(dl, symbol) dlsym(dl, symbol) +# define grn_dl_sym_error_label() dlerror() +# define grn_dl_clear_error() dlerror() +#else +# define grn_dl_open(filename) LoadLibrary(filename) +# define grn_dl_open_error_label() "LoadLibrary" +# define grn_dl_close(dl) (FreeLibrary(dl) != 0) +# define grn_dl_close_error_label() "FreeLibrary" +# define grn_dl_sym(dl, symbol) ((void *)GetProcAddress(dl, symbol)) +# define grn_dl_sym_error_label() "GetProcAddress" +# define grn_dl_clear_error() +#endif + +#define GRN_PLUGIN_KEY_SIZE(filename) (strlen((filename)) + 1) + +static char grn_plugins_dir[GRN_ENV_BUFFER_SIZE]; + +void +grn_plugin_init_from_env(void) +{ + grn_getenv("GRN_PLUGINS_DIR", + grn_plugins_dir, + GRN_ENV_BUFFER_SIZE); +} + +static int +compute_name_size(const char *name, int name_size) +{ + if (name_size < 0) { + if (name) { + name_size = strlen(name); + } else { + name_size = 0; + } + } + return name_size; +} + +grn_id +grn_plugin_reference(grn_ctx *ctx, const char *filename) +{ + grn_id id; + grn_plugin **plugin = NULL; + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + id = grn_hash_get(&grn_plugins_ctx, grn_plugins, + filename, GRN_PLUGIN_KEY_SIZE(filename), + (void **)&plugin); + if (plugin) { + (*plugin)->refcount++; + } + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + return id; +} + +const char * +grn_plugin_path(grn_ctx *ctx, grn_id id) +{ + const char *path; + grn_plugin *plugin; + int value_size; + const char *system_plugins_dir; + size_t system_plugins_dir_size; + + if (id == GRN_ID_NIL) { + return NULL; + } + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + value_size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + if (!plugin) { + return NULL; + } + + path = plugin->path; + system_plugins_dir = grn_plugin_get_system_plugins_dir(); + system_plugins_dir_size = strlen(system_plugins_dir); + if (strncmp(system_plugins_dir, path, system_plugins_dir_size) == 0) { + const char *plugin_name = path + system_plugins_dir_size; + while (plugin_name[0] == '/') { + plugin_name++; + } + /* TODO: remove suffix too? */ + return plugin_name; + } else { + return path; + } +} + +#define GRN_PLUGIN_FUNC_PREFIX "grn_plugin_impl_" + +static grn_rc +grn_plugin_call_init(grn_ctx *ctx, grn_id id) +{ + grn_plugin *plugin; + int size; + + size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); + if (size == 0) { + return GRN_INVALID_ARGUMENT; + } + + if (plugin->init_func) { + return plugin->init_func(ctx); + } + + return GRN_SUCCESS; +} + +#ifdef GRN_WITH_MRUBY +static grn_rc +grn_plugin_call_register_mrb(grn_ctx *ctx, grn_id id, grn_plugin *plugin) +{ + grn_mrb_data *data; + mrb_state *mrb; + struct RClass *module; + struct RClass *plugin_loader_class; + int arena_index; + + grn_ctx_impl_mrb_ensure_init(ctx); + if (ctx->rc != GRN_SUCCESS) { + return ctx->rc; + } + + data = &(ctx->impl->mrb); + mrb = data->state; + module = data->module; + + { + int added; + grn_hash_add(ctx, ctx->impl->mrb.registered_plugins, + &id, sizeof(grn_id), NULL, &added); + if (!added) { + return ctx->rc; + } + } + + arena_index = mrb_gc_arena_save(mrb); + plugin_loader_class = mrb_class_get_under(mrb, module, "PluginLoader"); + mrb_funcall(mrb, mrb_obj_value(plugin_loader_class), + "load_file", 1, mrb_str_new_cstr(mrb, ctx->impl->plugin_path)); + mrb_gc_arena_restore(mrb, arena_index); + return ctx->rc; +} +#endif /*GRN_WITH_MRUBY */ + +static grn_rc +grn_plugin_call_register(grn_ctx *ctx, grn_id id) +{ + grn_plugin *plugin; + int size; + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + if (size == 0) { + return GRN_INVALID_ARGUMENT; + } + +#ifdef GRN_WITH_MRUBY + if (!plugin->dl) { + return grn_plugin_call_register_mrb(ctx, id, plugin); + } +#endif /* GRN_WITH_MRUBY */ + + if (plugin->register_func) { + return plugin->register_func(ctx); + } + + return GRN_SUCCESS; +} + +static grn_rc +grn_plugin_call_fin(grn_ctx *ctx, grn_id id) +{ + grn_plugin *plugin; + int size; + + size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); + if (size == 0) { + return GRN_INVALID_ARGUMENT; + } + + if (plugin->fin_func) { + return plugin->fin_func(ctx); + } + + return GRN_SUCCESS; +} + +static grn_rc +grn_plugin_initialize(grn_ctx *ctx, grn_plugin *plugin, + grn_dl dl, grn_id id, const char *path) +{ + plugin->dl = dl; + +#define GET_SYMBOL(type) do { \ + grn_dl_clear_error(); \ + plugin->type ## _func = grn_dl_sym(dl, GRN_PLUGIN_FUNC_PREFIX #type); \ + if (!plugin->type ## _func) { \ + const char *label; \ + label = grn_dl_sym_error_label(); \ + SERR("%s", label); \ + } \ +} while (0) + + GET_SYMBOL(init); + GET_SYMBOL(register); + GET_SYMBOL(fin); + +#undef GET_SYMBOL + + if (!plugin->init_func || !plugin->register_func || !plugin->fin_func) { + ERR(GRN_INVALID_FORMAT, + "init func (%s) %sfound, " + "register func (%s) %sfound and " + "fin func (%s) %sfound", + GRN_PLUGIN_FUNC_PREFIX "init", plugin->init_func ? "" : "not ", + GRN_PLUGIN_FUNC_PREFIX "register", plugin->register_func ? "" : "not ", + GRN_PLUGIN_FUNC_PREFIX "fin", plugin->fin_func ? "" : "not "); + } + + if (!ctx->rc) { + ctx->impl->plugin_path = path; + grn_plugin_call_init(ctx, id); + ctx->impl->plugin_path = NULL; + } + + return ctx->rc; +} + +#ifdef GRN_WITH_MRUBY +static grn_id +grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size) +{ + grn_ctx *plugins_ctx = &grn_plugins_ctx; + grn_id id = GRN_ID_NIL; + grn_plugin **plugin = NULL; + + grn_ctx_impl_mrb_ensure_init(ctx); + if (ctx->rc != GRN_SUCCESS) { + return GRN_ID_NIL; + } + + if (!ctx->impl->mrb.state) { + ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "mruby support isn't enabled"); + return GRN_ID_NIL; + } + + id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size, + (void **)&plugin, NULL); + if (!id) { + return id; + } + + { + grn_ctx *ctx = plugins_ctx; + *plugin = GRN_MALLOCN(grn_plugin, 1); + } + if (!*plugin) { + grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); + return GRN_ID_NIL; + } + + grn_memcpy((*plugin)->path, filename, filename_size); + (*plugin)->dl = NULL; + (*plugin)->init_func = NULL; + (*plugin)->register_func = NULL; + (*plugin)->fin_func = NULL; + (*plugin)->refcount = 1; + + return id; +} +#endif /* GRN_WITH_MRUBY */ + +grn_id +grn_plugin_open(grn_ctx *ctx, const char *filename) +{ + grn_ctx *plugins_ctx = &grn_plugins_ctx; + grn_id id = GRN_ID_NIL; + grn_dl dl; + grn_plugin **plugin = NULL; + size_t filename_size; + + filename_size = GRN_PLUGIN_KEY_SIZE(filename); + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + if ((id = grn_hash_get(plugins_ctx, grn_plugins, filename, filename_size, + (void **)&plugin))) { + (*plugin)->refcount++; + goto exit; + } + +#ifdef GRN_WITH_MRUBY + { + const char *mrb_suffix; + mrb_suffix = grn_plugin_get_ruby_suffix(); + if (filename_size > strlen(mrb_suffix) && + strcmp(filename + (strlen(filename) - strlen(mrb_suffix)), + mrb_suffix) == 0) { + id = grn_plugin_open_mrb(ctx, filename, filename_size); + goto exit; + } + } +#endif /* GRN_WITH_MRUBY */ + + if ((dl = grn_dl_open(filename))) { + if ((id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size, + (void **)&plugin, NULL))) { + { + grn_ctx *ctx = plugins_ctx; + *plugin = GRN_MALLOCN(grn_plugin, 1); + } + if (*plugin) { + grn_memcpy((*plugin)->path, filename, filename_size); + if (grn_plugin_initialize(ctx, *plugin, dl, id, filename)) { + { + grn_ctx *ctx = plugins_ctx; + GRN_FREE(*plugin); + } + *plugin = NULL; + } + } + if (!*plugin) { + grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); + if (grn_dl_close(dl)) { + /* Now, __FILE__ set in plugin is invalid. */ + ctx->errline = 0; + ctx->errfile = NULL; + } else { + const char *label; + label = grn_dl_close_error_label(); + SERR("%s", label); + } + id = GRN_ID_NIL; + } else { + (*plugin)->refcount = 1; + } + } else { + if (!grn_dl_close(dl)) { + const char *label; + label = grn_dl_close_error_label(); + SERR("%s", label); + } + } + } else { + const char *label; + label = grn_dl_open_error_label(); + SERR("%s", label); + } + +exit: + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + return id; +} + +grn_rc +grn_plugin_close(grn_ctx *ctx, grn_id id) +{ + grn_ctx *plugins_ctx = &grn_plugins_ctx; + grn_rc rc; + grn_plugin *plugin; + + if (id == GRN_ID_NIL) { + return GRN_INVALID_ARGUMENT; + } + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + if (!grn_hash_get_value(plugins_ctx, grn_plugins, id, &plugin)) { + rc = GRN_INVALID_ARGUMENT; + goto exit; + } + if (--plugin->refcount) { + rc = GRN_SUCCESS; + goto exit; + } + if (plugin->dl) { + grn_plugin_call_fin(ctx, id); + if (!grn_dl_close(plugin->dl)) { + const char *label; + label = grn_dl_close_error_label(); + SERR("%s", label); + } + } + { + grn_ctx *ctx = plugins_ctx; + GRN_FREE(plugin); + } + rc = grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); + +exit: + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + return rc; +} + +void * +grn_plugin_sym(grn_ctx *ctx, grn_id id, const char *symbol) +{ + grn_plugin *plugin; + grn_dl_symbol func; + + if (id == GRN_ID_NIL) { + return NULL; + } + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + if (!grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin)) { + func = NULL; + goto exit; + } + grn_dl_clear_error(); + if (!(func = grn_dl_sym(plugin->dl, symbol))) { + const char *label; + label = grn_dl_sym_error_label(); + SERR("%s", label); + } + +exit: + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + return func; +} + +grn_rc +grn_plugins_init(void) +{ + CRITICAL_SECTION_INIT(grn_plugins_lock); + grn_ctx_init(&grn_plugins_ctx, 0); + grn_plugins = grn_hash_create(&grn_plugins_ctx, NULL, + PATH_MAX, sizeof(grn_plugin *), + GRN_OBJ_KEY_VAR_SIZE); + if (!grn_plugins) { + grn_ctx_fin(&grn_plugins_ctx); + return GRN_NO_MEMORY_AVAILABLE; + } + return GRN_SUCCESS; +} + +grn_rc +grn_plugins_fin(void) +{ + grn_rc rc; + if (!grn_plugins) { return GRN_INVALID_ARGUMENT; } + GRN_HASH_EACH(&grn_plugins_ctx, grn_plugins, id, NULL, NULL, NULL, { + grn_plugin_close(&grn_plugins_ctx, id); + }); + rc = grn_hash_close(&grn_plugins_ctx, grn_plugins); + grn_ctx_fin(&grn_plugins_ctx); + CRITICAL_SECTION_FIN(grn_plugins_lock); + return rc; +} + +const char * +grn_plugin_get_suffix(void) +{ + return GRN_PLUGIN_SUFFIX; +} + +const char * +grn_plugin_get_ruby_suffix(void) +{ + return ".rb"; +} + +grn_rc +grn_plugin_register_by_path(grn_ctx *ctx, const char *path) +{ + grn_obj *db; + if (!ctx || !ctx->impl || !(db = ctx->impl->db)) { + ERR(GRN_INVALID_ARGUMENT, "db not initialized"); + return ctx->rc; + } + GRN_API_ENTER; + if (GRN_DB_P(db)) { + grn_id id; + id = grn_plugin_open(ctx, path); + if (id) { + ctx->impl->plugin_path = path; + ctx->rc = grn_plugin_call_register(ctx, id); + ctx->impl->plugin_path = NULL; + grn_plugin_close(ctx, id); + } + } else { + ERR(GRN_INVALID_ARGUMENT, "invalid db assigned"); + } + GRN_API_RETURN(ctx->rc); +} + +#ifdef WIN32 +static char *windows_plugins_dir = NULL; +static char windows_plugins_dir_buffer[PATH_MAX]; +static const char * +grn_plugin_get_default_system_plugins_dir(void) +{ + if (!windows_plugins_dir) { + const char *base_dir; + const char *relative_path = GRN_RELATIVE_PLUGINS_DIR; + size_t base_dir_length; + + base_dir = grn_windows_base_dir(); + base_dir_length = strlen(base_dir); + grn_strcpy(windows_plugins_dir_buffer, PATH_MAX, base_dir); + grn_strcat(windows_plugins_dir_buffer, PATH_MAX, "/"); + grn_strcat(windows_plugins_dir_buffer, PATH_MAX, relative_path); + windows_plugins_dir = windows_plugins_dir_buffer; + } + return windows_plugins_dir; +} + +#else /* WIN32 */ +static const char * +grn_plugin_get_default_system_plugins_dir(void) +{ + return GRN_PLUGINS_DIR; +} +#endif /* WIN32 */ + +const char * +grn_plugin_get_system_plugins_dir(void) +{ + if (grn_plugins_dir[0]) { + return grn_plugins_dir; + } else { + return grn_plugin_get_default_system_plugins_dir(); + } +} + +static char * +grn_plugin_find_path_raw(grn_ctx *ctx, const char *path) +{ + struct stat path_stat; + + if (stat(path, &path_stat) != 0) { + return NULL; + } + + if (!S_ISREG(path_stat.st_mode)) { + return NULL; + } + + return GRN_STRDUP(path); +} + +#ifdef GRN_WITH_MRUBY +static char * +grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) +{ + char mrb_path[PATH_MAX]; + const char *mrb_suffix; + size_t mrb_path_len; + + grn_ctx_impl_mrb_ensure_init(ctx); + if (ctx->rc != GRN_SUCCESS) { + return NULL; + } + + if (!ctx->impl->mrb.state) { + return NULL; + } + + mrb_suffix = grn_plugin_get_ruby_suffix(); + mrb_path_len = path_len + strlen(mrb_suffix); + if (mrb_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%s%s>", + path, mrb_suffix); + return NULL; + } + + grn_strcpy(mrb_path, PATH_MAX, path); + grn_strcat(mrb_path, PATH_MAX, mrb_suffix); + return grn_plugin_find_path_raw(ctx, mrb_path); +} +#else /* GRN_WITH_MRUBY */ +static char * +grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) +{ + return NULL; +} +#endif /* GRN_WITH_MRUBY */ + +static char * +grn_plugin_find_path_so(grn_ctx *ctx, const char *path, size_t path_len) +{ + char so_path[PATH_MAX]; + const char *so_suffix; + size_t so_path_len; + + so_suffix = grn_plugin_get_suffix(); + so_path_len = path_len + strlen(so_suffix); + if (so_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%s%s>", + path, so_suffix); + return NULL; + } + + grn_strcpy(so_path, PATH_MAX, path); + grn_strcat(so_path, PATH_MAX, so_suffix); + return grn_plugin_find_path_raw(ctx, so_path); +} + +static char * +grn_plugin_find_path_libs_so(grn_ctx *ctx, const char *path, size_t path_len) +{ + char libs_so_path[PATH_MAX]; + const char *base_name; + const char *so_suffix; + const char *libs_path = "/.libs"; + size_t libs_so_path_len; + + base_name = strrchr(path, '/'); + if (!base_name) { + return NULL; + } + + so_suffix = grn_plugin_get_suffix(); + libs_so_path_len = + base_name - path + + strlen(libs_path) + + strlen(base_name) + + strlen(so_suffix); + if (libs_so_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%.*s/.libs%s%s>", + (int)(base_name - path), path, base_name, so_suffix); + return NULL; + } + + libs_so_path[0] = '\0'; + grn_strncat(libs_so_path, PATH_MAX, path, base_name - path); + grn_strcat(libs_so_path, PATH_MAX, libs_path); + grn_strcat(libs_so_path, PATH_MAX, base_name); + grn_strcat(libs_so_path, PATH_MAX, so_suffix); + return grn_plugin_find_path_raw(ctx, libs_so_path); +} + +char * +grn_plugin_find_path(grn_ctx *ctx, const char *name) +{ + const char *plugins_dir; + char dir_last_char; + char path[PATH_MAX]; + int name_length, max_name_length; + char *found_path = NULL; + size_t path_len; + + GRN_API_ENTER; + if (name[0] == '/') { + path[0] = '\0'; + } else { + plugins_dir = grn_plugin_get_system_plugins_dir(); + grn_strcpy(path, PATH_MAX, plugins_dir); + + dir_last_char = plugins_dir[strlen(path) - 1]; + if (dir_last_char != '/') { + grn_strcat(path, PATH_MAX, "/"); + } + } + + name_length = strlen(name); + max_name_length = PATH_MAX - strlen(path) - 1; + if (name_length > max_name_length) { + ERR(GRN_INVALID_ARGUMENT, + "plugin name is too long: %d (max: %d) <%s%s>", + name_length, max_name_length, + path, name); + goto exit; + } + grn_strcat(path, PATH_MAX, name); + + found_path = grn_plugin_find_path_raw(ctx, path); + if (found_path) { + goto exit; + } + + path_len = strlen(path); + + found_path = grn_plugin_find_path_so(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; + } + + found_path = grn_plugin_find_path_libs_so(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; + } + + found_path = grn_plugin_find_path_mrb(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; + } + +exit : + GRN_API_RETURN(found_path); +} + +static void +grn_plugin_set_name_resolve_error(grn_ctx *ctx, const char *name, + const char *tag) +{ + const char *prefix, *prefix_separator, *suffix; + + if (name[0] == '/') { + prefix = ""; + prefix_separator = ""; + suffix = ""; + } else { + prefix = grn_plugin_get_system_plugins_dir(); + if (prefix[strlen(prefix) - 1] != '/') { + prefix_separator = "/"; + } else { + prefix_separator = ""; + } + suffix = grn_plugin_get_suffix(); + } + ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, + "%s cannot find plugin file: <%s%s%s%s>", + tag, prefix, prefix_separator, name, suffix); +} + +grn_rc +grn_plugin_register(grn_ctx *ctx, const char *name) +{ + grn_rc rc; + char *path; + + GRN_API_ENTER; + path = grn_plugin_find_path(ctx, name); + if (path) { + rc = grn_plugin_register_by_path(ctx, path); + GRN_FREE(path); + } else { + if (ctx->rc == GRN_SUCCESS) { + grn_plugin_set_name_resolve_error(ctx, name, "[plugin][register]"); + } + rc = ctx->rc; + } + GRN_API_RETURN(rc); +} + +grn_rc +grn_plugin_unregister_by_path(grn_ctx *ctx, const char *path) +{ + grn_obj *db; + grn_id plugin_id; + + if (!ctx || !ctx->impl) { + ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] ctx isn't initialized"); + return ctx->rc; + } + + db = ctx->impl->db; + if (!db) { + ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] DB isn't initialized"); + return ctx->rc; + } + + GRN_API_ENTER; + + CRITICAL_SECTION_ENTER(grn_plugins_lock); + plugin_id = grn_hash_get(&grn_plugins_ctx, grn_plugins, + path, GRN_PLUGIN_KEY_SIZE(path), + NULL); + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + if (plugin_id == GRN_ID_NIL) { + GRN_API_RETURN(ctx->rc); + } + + { + grn_table_cursor *cursor; + grn_id id; + + cursor = grn_table_cursor_open(ctx, db, + NULL, 0, + NULL, 0, + 0, -1, GRN_CURSOR_BY_ID); + if (!cursor) { + GRN_API_RETURN(ctx->rc); + } + + while ((id = grn_table_cursor_next(ctx, cursor))) { + grn_obj *obj; + obj = grn_ctx_at(ctx, id); + if (!obj) { + continue; + } + if (obj->header.type == GRN_PROC && DB_OBJ(obj)->range == plugin_id) { + grn_obj_remove(ctx, obj); + } else { + grn_obj_unlink(ctx, obj); + } + } + grn_table_cursor_close(ctx, cursor); + } + + GRN_API_RETURN(ctx->rc); +} + +grn_rc +grn_plugin_unregister(grn_ctx *ctx, const char *name) +{ + grn_rc rc; + char *path; + + GRN_API_ENTER; + path = grn_plugin_find_path(ctx, name); + if (path) { + rc = grn_plugin_unregister_by_path(ctx, path); + GRN_FREE(path); + } else { + if (ctx->rc == GRN_SUCCESS) { + grn_plugin_set_name_resolve_error(ctx, name, "[plugin][unregister]"); + } + rc = ctx->rc; + } + GRN_API_RETURN(rc); +} + +void +grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc) +{ +#ifdef GRN_WITH_MRUBY + grn_id plugin_id; + grn_plugin *plugin = NULL; + + if (!(proc->header.flags & GRN_OBJ_CUSTOM_NAME)) { + return; + } + + plugin_id = DB_OBJ(proc)->range; + CRITICAL_SECTION_ENTER(grn_plugins_lock); + { + const char *value; + value = grn_hash_get_value_(&grn_plugins_ctx, grn_plugins, plugin_id, NULL); + if (value) { + plugin = *((grn_plugin **)value); + } + } + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + if (!plugin) { + return; + } + + if (plugin->dl) { + return; + } + + grn_ctx_impl_mrb_ensure_init(ctx); + if (ctx->rc != GRN_SUCCESS) { + return; + } + + if (!ctx->impl->mrb.state) { + return; + } + + { + grn_id id; + int added; + id = DB_OBJ(proc)->id; + grn_hash_add(ctx, ctx->impl->mrb.checked_procs, + &id, sizeof(grn_id), NULL, &added); + if (!added) { + return; + } + } + + ctx->impl->plugin_path = plugin->path; + grn_plugin_call_register_mrb(ctx, plugin_id, plugin); + ctx->impl->plugin_path = NULL; +#endif /* GRN_WITH_MRUBY */ +} + +grn_rc +grn_plugin_get_names(grn_ctx *ctx, grn_obj *names) +{ + grn_hash *processed_paths; + const char *system_plugins_dir; + const char *native_plugin_suffix; + const char *ruby_plugin_suffix; + grn_bool is_close_opened_object_mode = GRN_FALSE; + + GRN_API_ENTER; + + if (ctx->rc) { + GRN_API_RETURN(ctx->rc); + } + + if (grn_thread_get_limit() == 1) { + is_close_opened_object_mode = GRN_TRUE; + } + + processed_paths = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, 0, + GRN_OBJ_TABLE_HASH_KEY | + GRN_OBJ_KEY_VAR_SIZE); + if (!processed_paths) { + GRN_API_RETURN(ctx->rc); + } + + system_plugins_dir = grn_plugin_get_system_plugins_dir(); + native_plugin_suffix = grn_plugin_get_suffix(); + ruby_plugin_suffix = grn_plugin_get_ruby_suffix(); + + GRN_TABLE_EACH_BEGIN_FLAGS(ctx, grn_ctx_db(ctx), cursor, id, + GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) { + void *name; + int name_size; + grn_obj *object; + const char *path; + grn_id processed_path_id; + + if (grn_id_is_builtin(ctx, id)) { + continue; + } + + name_size = grn_table_cursor_get_key(ctx, cursor, &name); + if (grn_obj_name_is_column(ctx, name, name_size)) { + continue; + } + + if (is_close_opened_object_mode) { + grn_ctx_push_temporary_open_space(ctx); + } + + object = grn_ctx_at(ctx, id); + if (!object) { + ERRCLR(ctx); + goto next_loop; + } + + if (!grn_obj_is_proc(ctx, object)) { + goto next_loop; + } + + path = grn_obj_path(ctx, object); + if (!path) { + goto next_loop; + } + + processed_path_id = grn_hash_get(ctx, processed_paths, + path, strlen(path), + NULL); + if (processed_path_id != GRN_ID_NIL) { + goto next_loop; + } + + grn_hash_add(ctx, processed_paths, + path, strlen(path), + NULL, NULL); + + { + const char *relative_path; + const char *libs_path = "/.libs/"; + const char *start_libs; + char name[PATH_MAX]; + + name[0] = '\0'; + if (strncmp(path, system_plugins_dir, strlen(system_plugins_dir)) == 0) { + relative_path = path + strlen(system_plugins_dir); + } else { + relative_path = path; + } + start_libs = strstr(relative_path, libs_path); + if (start_libs) { + grn_strncat(name, PATH_MAX, relative_path, start_libs - relative_path); + grn_strcat(name, PATH_MAX, "/"); + grn_strcat(name, PATH_MAX, start_libs + strlen(libs_path)); + } else { + grn_strcat(name, PATH_MAX, relative_path); + } + if (strlen(name) > strlen(native_plugin_suffix) && + strcmp(name + strlen(name) - strlen(native_plugin_suffix), + native_plugin_suffix) == 0) { + name[strlen(name) - strlen(native_plugin_suffix)] = '\0'; + } else if (strlen(name) > strlen(ruby_plugin_suffix) && + strcmp(name + strlen(name) - strlen(ruby_plugin_suffix), + ruby_plugin_suffix) == 0) { + name[strlen(name) - strlen(ruby_plugin_suffix)] = '\0'; + } + grn_vector_add_element(ctx, names, + name, strlen(name), + 0, GRN_DB_TEXT); + } + + next_loop : + if (is_close_opened_object_mode) { + grn_ctx_pop_temporary_open_space(ctx); + } + } GRN_TABLE_EACH_END(ctx, cursor); + + grn_hash_close(ctx, processed_paths); + + GRN_API_RETURN(ctx->rc); +} + +void * +grn_plugin_malloc(grn_ctx *ctx, size_t size, const char *file, int line, + const char *func) +{ + return grn_malloc(ctx, size, file, line, func); +} + +void * +grn_plugin_calloc(grn_ctx *ctx, size_t size, const char *file, int line, + const char *func) +{ + return grn_calloc(ctx, size, file, line, func); +} + +void * +grn_plugin_realloc(grn_ctx *ctx, void *ptr, size_t size, + const char *file, int line, const char *func) +{ + return grn_realloc(ctx, ptr, size, file, line, func); +} + +void +grn_plugin_free(grn_ctx *ctx, void *ptr, const char *file, int line, + const char *func) +{ + grn_free(ctx, ptr, file, line, func); +} + +void +grn_plugin_set_error(grn_ctx *ctx, grn_log_level level, grn_rc error_code, + const char *file, int line, const char *func, + const char *format, ...) +{ + char old_error_message[GRN_CTX_MSGSIZE]; + + ctx->errlvl = level; + ctx->rc = error_code; + ctx->errfile = file; + ctx->errline = line; + ctx->errfunc = func; + + grn_strcpy(old_error_message, GRN_CTX_MSGSIZE, ctx->errbuf); + + { + va_list ap; + va_start(ap, format); + grn_ctx_logv(ctx, format, ap); + va_end(ap); + } + + if (grn_ctx_impl_should_log(ctx)) { + grn_ctx_impl_set_current_error_message(ctx); + if (grn_logger_pass(ctx, level)) { + char new_error_message[GRN_CTX_MSGSIZE]; + grn_strcpy(new_error_message, GRN_CTX_MSGSIZE, ctx->errbuf); + grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, old_error_message); + { + va_list ap; + va_start(ap, format); + grn_logger_putv(ctx, level, file, line, func, format, ap); + va_end(ap); + } + grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, new_error_message); + } + if (level <= GRN_LOG_ERROR) { + grn_plugin_logtrace(ctx, level); + } + } +} + +void +grn_plugin_clear_error(grn_ctx *ctx) +{ + ERRCLR(ctx); +} + +void +grn_plugin_backtrace(grn_ctx *ctx) +{ + BACKTRACE(ctx); +} + +void +grn_plugin_logtrace(grn_ctx *ctx, grn_log_level level) +{ + if (level <= GRN_LOG_ERROR) { + grn_plugin_backtrace(ctx); + LOGTRACE(ctx, level); + } +} + +struct _grn_plugin_mutex { + grn_critical_section critical_section; +}; + +grn_plugin_mutex * +grn_plugin_mutex_open(grn_ctx *ctx) +{ + grn_plugin_mutex * const mutex = + GRN_PLUGIN_MALLOC(ctx, sizeof(grn_plugin_mutex)); + if (mutex != NULL) { + CRITICAL_SECTION_INIT(mutex->critical_section); + } + return mutex; +} + +grn_plugin_mutex * +grn_plugin_mutex_create(grn_ctx *ctx) +{ + return grn_plugin_mutex_open(ctx); +} + +void +grn_plugin_mutex_close(grn_ctx *ctx, grn_plugin_mutex *mutex) +{ + if (mutex != NULL) { + CRITICAL_SECTION_FIN(mutex->critical_section); + GRN_PLUGIN_FREE(ctx, mutex); + } +} + +void +grn_plugin_mutex_destroy(grn_ctx *ctx, grn_plugin_mutex *mutex) +{ + grn_plugin_mutex_close(ctx, mutex); +} + +void +grn_plugin_mutex_lock(grn_ctx *ctx, grn_plugin_mutex *mutex) +{ + if (mutex != NULL) { + CRITICAL_SECTION_ENTER(mutex->critical_section); + } +} + +void +grn_plugin_mutex_unlock(grn_ctx *ctx, grn_plugin_mutex *mutex) +{ + if (mutex != NULL) { + CRITICAL_SECTION_LEAVE(mutex->critical_section); + } +} + +grn_obj * +grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data, + grn_id domain, unsigned char flags) +{ + return grn_proc_alloc(ctx, user_data, domain, flags); +} + +grn_obj * +grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data) +{ + return grn_proc_get_vars(ctx, user_data); +} + +grn_obj * +grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data, + const char *name, int name_size) +{ + name_size = compute_name_size(name, name_size); + return grn_proc_get_var(ctx, user_data, name, name_size); +} + +grn_bool +grn_plugin_proc_get_var_bool(grn_ctx *ctx, + grn_user_data *user_data, + const char *name, + int name_size, + grn_bool default_value) +{ + grn_obj *var; + + var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); + return grn_proc_option_value_bool(ctx, var, default_value); +} + +int32_t +grn_plugin_proc_get_var_int32(grn_ctx *ctx, + grn_user_data *user_data, + const char *name, + int name_size, + int32_t default_value) +{ + grn_obj *var; + + var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); + return grn_proc_option_value_int32(ctx, var, default_value); +} + +const char * +grn_plugin_proc_get_var_string(grn_ctx *ctx, + grn_user_data *user_data, + const char *name, + int name_size, + size_t *size) +{ + grn_obj *var; + + var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); + return grn_proc_option_value_string(ctx, var, size); +} + +grn_content_type +grn_plugin_proc_get_var_content_type(grn_ctx *ctx, + grn_user_data *user_data, + const char *name, + int name_size, + grn_content_type default_value) +{ + grn_obj *var; + + var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); + return grn_proc_option_value_content_type(ctx, var, default_value); +} + +grn_obj * +grn_plugin_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data, + unsigned int offset) +{ + return grn_proc_get_var_by_offset(ctx, user_data, offset); +} + +grn_obj * +grn_plugin_proc_get_caller(grn_ctx *ctx, grn_user_data *user_data) +{ + grn_obj *caller = NULL; + GRN_API_ENTER; + grn_proc_get_info(ctx, user_data, NULL, NULL, &caller); + GRN_API_RETURN(caller); +} + +const char * +grn_plugin_win32_base_dir(void) +{ + return grn_plugin_windows_base_dir(); +} + +const char * +grn_plugin_windows_base_dir(void) +{ +#ifdef WIN32 + return grn_windows_base_dir(); +#else /* WIN32 */ + return NULL; +#endif /* WIN32 */ +} + +/* + grn_plugin_charlen() takes the length of a string, unlike grn_charlen_(). + */ +int +grn_plugin_charlen(grn_ctx *ctx, const char *str_ptr, + unsigned int str_length, grn_encoding encoding) +{ + return grn_charlen_(ctx, str_ptr, str_ptr + str_length, encoding); +} + +/* + grn_plugin_isspace() takes the length of a string, unlike grn_isspace(). + */ +int +grn_plugin_isspace(grn_ctx *ctx, const char *str_ptr, + unsigned int str_length, grn_encoding encoding) +{ + if ((str_ptr == NULL) || (str_length == 0)) { + return 0; + } + switch ((unsigned char)str_ptr[0]) { + case ' ' : + case '\f' : + case '\n' : + case '\r' : + case '\t' : + case '\v' : + return 1; + case 0x81 : + if ((encoding == GRN_ENC_SJIS) && (str_length >= 2) && + ((unsigned char)str_ptr[1] == 0x40)) { + return 2; + } + break; + case 0xA1 : + if ((encoding == GRN_ENC_EUC_JP) && (str_length >= 2) && + ((unsigned char)str_ptr[1] == 0xA1)) { + return 2; + } + break; + case 0xE3 : + if ((encoding == GRN_ENC_UTF8) && (str_length >= 3) && + ((unsigned char)str_ptr[1] == 0x80) && + ((unsigned char)str_ptr[2] == 0x80)) { + return 3; + } + break; + default : + break; + } + return 0; +} + +grn_rc +grn_plugin_expr_var_init(grn_ctx *ctx, + grn_expr_var *var, + const char *name, + int name_size) +{ + var->name = name; + var->name_size = compute_name_size(name, name_size); + GRN_TEXT_INIT(&var->value, 0); + return GRN_SUCCESS; +} + +grn_obj * +grn_plugin_command_create(grn_ctx *ctx, + const char *name, + int name_size, + grn_proc_func func, + unsigned int n_vars, + grn_expr_var *vars) +{ + grn_obj *proc; + name_size = compute_name_size(name, name_size); + proc = grn_proc_create(ctx, name, name_size, GRN_PROC_COMMAND, + func, NULL, NULL, n_vars, vars); + return proc; +} |