From 84a70da19fdf98b028b98e23a228e32f591535fe Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 3 Nov 2011 15:24:08 +0000 Subject: implementing plugin directory scanner for #1746 --- src/include/gnunet_plugin_lib.h | 35 ++++++++++++++++++ src/util/plugin.c | 82 +++++++++++++++++++++++++++++++++++++++++ src/util/test_plugin.c | 13 +++++++ 3 files changed, 130 insertions(+) (limited to 'src') diff --git a/src/include/gnunet_plugin_lib.h b/src/include/gnunet_plugin_lib.h index d143a6ccf..ff795d975 100644 --- a/src/include/gnunet_plugin_lib.h +++ b/src/include/gnunet_plugin_lib.h @@ -62,6 +62,7 @@ typedef void *(*GNUNET_PLUGIN_Callback) (void *arg); int GNUNET_PLUGIN_test (const char *library_name); + /** * Setup plugin (runs the "init" callback and returns whatever "init" * returned). If "init" returns NULL, the plugin is unloaded. @@ -78,6 +79,40 @@ void * GNUNET_PLUGIN_load (const char *library_name, void *arg); +/** + * Signature of a function called by 'GNUNET_PLUGIN_load_all'. + * + * @param cls closure + * @param library_name full name of the library (to be used with + * 'GNUNET_PLUGIN_unload') + * @param lib_ret return value from the initialization function + * of the library (same as what 'GNUNET_PLUGIN_load' would + * have returned for the given library name) + */ +typedef void (*GNUNET_PLUGIN_LoaderCallback)(void *cls, + const char *library_name, + void *lib_ret); + + +/** + * Load all compatible plugins with the given base name. + * + * Note that the library must export symbols called + * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will + * be called when the library is loaded and unloaded respectively. + * + * @param basename basename of the plugins to load + * @param arg argument to the plugin initialization function + * @param cb function to call for each plugin found + * @param cb_cls closure for 'cb' + */ +void +GNUNET_PLUGIN_load_all (const char *basename, + void *arg, + GNUNET_PLUGIN_LoaderCallback cb, + void *cb_cls); + + /** * Unload plugin (runs the "done" callback and returns whatever "done" * returned). The plugin is then unloaded. diff --git a/src/util/plugin.c b/src/util/plugin.c index 77631410c..dffc8ecd6 100644 --- a/src/util/plugin.c +++ b/src/util/plugin.c @@ -284,5 +284,87 @@ GNUNET_PLUGIN_unload (const char *library_name, void *arg) } +struct LoadAllContext +{ + const char *basename; + void *arg; + GNUNET_PLUGIN_LoaderCallback cb; + void *cb_cls; +}; + + +static int +find_libraries (void *cls, + const char *filename) +{ + struct LoadAllContext *lac = cls; + const char *slashpos; + const char *libname; + char *basename; + char *dot; + void *lib_ret; + size_t n; + + libname = filename; + while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR))) + libname = slashpos + 1; + n = strlen (libname); + if (0 != strncmp (lac->basename, + libname, + strlen (lac->basename))) + return GNUNET_OK; /* wrong name */ + if ( (n > 3) && + (0 == strcmp (&libname[n-3], + ".la")) ) + return GNUNET_OK; /* .la file */ + basename = GNUNET_strdup (libname); + if (NULL != (dot = strstr (basename, "."))) + *dot = '\0'; + lib_ret = GNUNET_PLUGIN_load (basename, lac->arg); + if (NULL != lib_ret) + lac->cb (lac->cb_cls, basename, lib_ret); + GNUNET_free (basename); + return GNUNET_OK; +} + + +/** + * Load all compatible plugins with the given base name. + * + * Note that the library must export symbols called + * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will + * be called when the library is loaded and unloaded respectively. + * + * @param basename basename of the plugins to load + * @param arg argument to the plugin initialization function + * @param cb function to call for each plugin found + * @param cb_cls closure for 'cb' + */ +void +GNUNET_PLUGIN_load_all (const char *basename, + void *arg, + GNUNET_PLUGIN_LoaderCallback cb, + void *cb_cls) +{ + struct LoadAllContext lac; + char *path; + + path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR); + if (path == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not determine plugin installation path.\n")); + return; + } + lac.basename = basename; + lac.arg = arg; + lac.cb = cb; + lac.cb_cls = cb_cls; + GNUNET_DISK_directory_scan (path, + &find_libraries, + &lac); + GNUNET_free (path); +} + /* end of plugin.c */ diff --git a/src/util/test_plugin.c b/src/util/test_plugin.c index 479edb3cb..dc34841f5 100644 --- a/src/util/test_plugin.c +++ b/src/util/test_plugin.c @@ -26,6 +26,17 @@ #define VERBOSE GNUNET_EXTRA_LOGGING +static void +test_cb (void *cls, + const char *libname, + void *lib_ret) +{ + GNUNET_assert (0 == strcmp (cls, "test")); + GNUNET_assert (0 == strcmp (lib_ret, "Hello")); + GNUNET_assert (0 == strcmp (GNUNET_PLUGIN_unload (libname, "out"), "World")); +} + + static int check () { @@ -47,6 +58,8 @@ check () if (0 != strcmp (ret, "World")) return 4; free (ret); + + GNUNET_PLUGIN_load_all ("libgnunet_plugin_tes", "in", &test_cb, "test"); return 0; } -- cgit v1.2.3