2 This file is part of GNUnet
3 Copyright (C) 2002-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * @brief Methods to access plugins
22 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
29 #define LOG(kind,...) GNUNET_log_from (kind, "util-plugin", __VA_ARGS__)
32 * Linked list of active plugins.
37 * This is a linked list.
39 struct PluginList *next;
42 * Name of the library.
54 * Have we been initialized?
56 static int initialized;
59 * Libtool search path before we started.
61 static char *old_dlsearchpath;
64 * List of plugins we have loaded.
66 static struct PluginList *plugins;
70 * Setup libtool paths.
84 _("Initialization of plugin mechanism failed: %s!\n"),
88 opath = lt_dlgetsearchpath ();
90 old_dlsearchpath = GNUNET_strdup (opath);
91 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
96 GNUNET_asprintf (&cpath, "%s:%s", opath, path);
97 lt_dlsetsearchpath (cpath);
103 lt_dlsetsearchpath (path);
116 lt_dlsetsearchpath (old_dlsearchpath);
117 if (NULL != old_dlsearchpath)
119 GNUNET_free (old_dlsearchpath);
120 old_dlsearchpath = NULL;
127 * Lookup a function in the plugin.
129 * @param plug the plugin to check
130 * @param name name of the symbol to look for
131 * @return NULL if the symbol was not found
133 static GNUNET_PLUGIN_Callback
134 resolve_function (struct PluginList *plug,
140 GNUNET_asprintf (&initName,
144 mptr = lt_dlsym (plug->handle, &initName[1]);
146 mptr = lt_dlsym (plug->handle, initName);
148 LOG (GNUNET_ERROR_TYPE_ERROR,
149 _("`%s' failed to resolve method '%s' with error: %s\n"),
151 &initName[1], lt_dlerror ());
152 GNUNET_free (initName);
158 * Test if a plugin exists.
160 * Note that the library must export a symbol called
161 * `library_name_init` for the test to succeed.
163 * @param library_name name of the plugin to test if it is installed
164 * @return #GNUNET_YES if the plugin exists, #GNUNET_NO if not
167 GNUNET_PLUGIN_test (const char *library_name)
170 GNUNET_PLUGIN_Callback init;
171 struct PluginList plug;
175 initialized = GNUNET_YES;
178 libhandle = lt_dlopenext (library_name);
179 if (NULL == libhandle)
181 plug.handle = libhandle;
182 plug.name = (char *) library_name;
183 init = resolve_function (&plug, "init");
187 lt_dlclose (libhandle);
190 lt_dlclose (libhandle);
196 * Setup plugin (runs the `init` callback and returns whatever `init`
197 * returned). If `init` returns NULL, the plugin is unloaded.
199 * Note that the library must export symbols called
200 * `library_name_init` and `library_name_done`. These will be called
201 * when the library is loaded and unloaded respectively.
203 * @param library_name name of the plugin to load
204 * @param arg argument to the plugin initialization function
205 * @return whatever the initialization function returned
208 GNUNET_PLUGIN_load (const char *library_name, void *arg)
211 struct PluginList *plug;
212 GNUNET_PLUGIN_Callback init;
217 initialized = GNUNET_YES;
220 libhandle = lt_dlopenext (library_name);
221 if (libhandle == NULL)
223 LOG (GNUNET_ERROR_TYPE_ERROR,
224 _("`%s' failed for library `%s' with error: %s\n"),
226 library_name, lt_dlerror ());
229 plug = GNUNET_new (struct PluginList);
230 plug->handle = libhandle;
231 plug->name = GNUNET_strdup (library_name);
232 plug->next = plugins;
234 init = resolve_function (plug, "init");
235 if ((init == NULL) || (NULL == (ret = init (arg))))
237 lt_dlclose (libhandle);
238 GNUNET_free (plug->name);
239 plugins = plug->next;
248 * Unload plugin (runs the `done` callback and returns whatever `done`
249 * returned). The plugin is then unloaded.
251 * @param library_name name of the plugin to unload
252 * @param arg argument to the plugin shutdown function
253 * @return whatever the shutdown function returned
256 GNUNET_PLUGIN_unload (const char *library_name,
259 struct PluginList *pos;
260 struct PluginList *prev;
261 GNUNET_PLUGIN_Callback done;
266 while ((NULL != pos) && (0 != strcmp (pos->name, library_name)))
274 done = resolve_function (pos, "done");
281 prev->next = pos->next;
282 lt_dlclose (pos->handle);
283 GNUNET_free (pos->name);
288 initialized = GNUNET_NO;
295 * Closure for #find_libraries().
297 struct LoadAllContext
300 * Prefix the plugin names we find have to match.
302 const char *basename;
305 * Argument to give to 'init' when loading the plugin.
310 * Function to call for each plugin.
312 GNUNET_PLUGIN_LoaderCallback cb;
322 * Function called on each plugin in the directory. Loads
323 * the plugins that match the given basename.
325 * @param cls the `struct LoadAllContext` describing which
326 * plugins to load and what to do with them
327 * @param filename name of a plugin library to check
328 * @return #GNUNET_OK (continue loading)
331 find_libraries (void *cls, const char *filename)
333 struct LoadAllContext *lac = cls;
334 const char *slashpos;
342 while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR)))
343 libname = slashpos + 1;
344 n = strlen (libname);
345 if (0 != strncmp (lac->basename, libname, strlen (lac->basename)))
346 return GNUNET_OK; /* wrong name */
347 if ((n > 3) && (0 == strcmp (&libname[n - 3], ".la")))
348 return GNUNET_OK; /* .la file */
349 basename = GNUNET_strdup (libname);
350 if (NULL != (dot = strstr (basename, ".")))
352 lib_ret = GNUNET_PLUGIN_load (basename, lac->arg);
354 lac->cb (lac->cb_cls, basename, lib_ret);
355 GNUNET_free (basename);
361 * Load all compatible plugins with the given base name.
363 * Note that the library must export symbols called
364 * `basename_ANYTHING_init` and `basename_ANYTHING__done`. These will
365 * be called when the library is loaded and unloaded respectively.
367 * @param basename basename of the plugins to load
368 * @param arg argument to the plugin initialization function
369 * @param cb function to call for each plugin found
370 * @param cb_cls closure for @a cb
373 GNUNET_PLUGIN_load_all (const char *basename, void *arg,
374 GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
376 struct LoadAllContext lac;
379 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
382 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
383 _("Could not determine plugin installation path.\n"));
386 lac.basename = basename;
390 GNUNET_DISK_directory_scan (path, &find_libraries, &lac);
395 /* end of plugin.c */