2 This file is part of GNUnet
3 (C) 2002-2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief Methods to access plugins
24 * @author Christian Grothoff
29 #include "gnunet_util_lib.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
34 * Linked list of active plugins.
39 * This is a linked list.
41 struct PluginList *next;
44 * Name of the library.
56 * Have we been initialized?
58 static int initialized;
62 * Libtool search path before we started.
64 static char *old_dlsearchpath;
67 * List of plugins we have loaded.
69 static struct PluginList *plugins;
73 * Setup libtool paths.
87 _("Initialization of plugin mechanism failed: %s!\n"),
91 opath = lt_dlgetsearchpath ();
93 old_dlsearchpath = GNUNET_strdup (opath);
94 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
99 GNUNET_asprintf (&cpath, "%s:%s", opath, path);
100 lt_dlsetsearchpath (cpath);
106 lt_dlsetsearchpath (path);
119 lt_dlsetsearchpath (old_dlsearchpath);
120 if (old_dlsearchpath != NULL)
122 GNUNET_free (old_dlsearchpath);
123 old_dlsearchpath = NULL;
130 * Lookup a function in the plugin.
132 * @param plug the plugin to check
133 * @param name name of the symbol to look for
134 * @return NULL if the symbol was not found
136 static GNUNET_PLUGIN_Callback
137 resolve_function (struct PluginList *plug, const char *name)
142 GNUNET_asprintf (&initName, "_%s_%s", plug->name, name);
143 mptr = lt_dlsym (plug->handle, &initName[1]);
145 mptr = lt_dlsym (plug->handle, initName);
147 LOG (GNUNET_ERROR_TYPE_ERROR,
148 _("`%s' failed to resolve method '%s' with error: %s\n"),
150 &initName[1], lt_dlerror ());
151 GNUNET_free (initName);
157 * Test if a plugin exists.
159 * Note that the library must export a symbol called
160 * `library_name_init` for the test to succeed.
162 * @param library_name name of the plugin to test if it is installed
163 * @return #GNUNET_YES if the plugin exists, #GNUNET_NO if not
166 GNUNET_PLUGIN_test (const char *library_name)
169 GNUNET_PLUGIN_Callback init;
170 struct PluginList plug;
174 initialized = GNUNET_YES;
177 libhandle = lt_dlopenext (library_name);
178 if (NULL == libhandle)
180 plug.handle = libhandle;
181 plug.name = (char *) library_name;
182 init = resolve_function (&plug, "init");
186 lt_dlclose (libhandle);
189 lt_dlclose (libhandle);
195 * Setup plugin (runs the `init` callback and returns whatever `init`
196 * returned). If `init` returns NULL, the plugin is unloaded.
198 * Note that the library must export symbols called
199 * `library_name_init` and `library_name_done`. These will be called
200 * when the library is loaded and unloaded respectively.
202 * @param library_name name of the plugin to load
203 * @param arg argument to the plugin initialization function
204 * @return whatever the initialization function returned
207 GNUNET_PLUGIN_load (const char *library_name, void *arg)
210 struct PluginList *plug;
211 GNUNET_PLUGIN_Callback init;
216 initialized = GNUNET_YES;
219 libhandle = lt_dlopenext (library_name);
220 if (libhandle == NULL)
222 LOG (GNUNET_ERROR_TYPE_ERROR,
223 _("`%s' failed for library `%s' with error: %s\n"),
225 library_name, lt_dlerror ());
228 plug = GNUNET_new (struct PluginList);
229 plug->handle = libhandle;
230 plug->name = GNUNET_strdup (library_name);
231 plug->next = plugins;
233 init = resolve_function (plug, "init");
234 if ((init == NULL) || (NULL == (ret = init (arg))))
236 lt_dlclose (libhandle);
237 GNUNET_free (plug->name);
238 plugins = plug->next;
247 * Unload plugin (runs the `done` callback and returns whatever `done`
248 * returned). The plugin is then unloaded.
250 * @param library_name name of the plugin to unload
251 * @param arg argument to the plugin shutdown function
252 * @return whatever the shutdown function returned
255 GNUNET_PLUGIN_unload (const char *library_name,
258 struct PluginList *pos;
259 struct PluginList *prev;
260 GNUNET_PLUGIN_Callback done;
265 while ((NULL != pos) && (0 != strcmp (pos->name, library_name)))
273 done = resolve_function (pos, "done");
280 prev->next = pos->next;
281 lt_dlclose (pos->handle);
282 GNUNET_free (pos->name);
287 initialized = GNUNET_NO;
294 * Closure for #find_libraries().
296 struct LoadAllContext
299 * Prefix the plugin names we find have to match.
301 const char *basename;
304 * Argument to give to 'init' when loading the plugin.
309 * Function to call for each plugin.
311 GNUNET_PLUGIN_LoaderCallback cb;
321 * Function called on each plugin in the directory. Loads
322 * the plugins that match the given basename.
324 * @param cls the `struct LoadAllContext` describing which
325 * plugins to load and what to do with them
326 * @param filename name of a plugin library to check
327 * @return #GNUNET_OK (continue loading)
330 find_libraries (void *cls, const char *filename)
332 struct LoadAllContext *lac = cls;
333 const char *slashpos;
341 while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR)))
342 libname = slashpos + 1;
343 n = strlen (libname);
344 if (0 != strncmp (lac->basename, libname, strlen (lac->basename)))
345 return GNUNET_OK; /* wrong name */
346 if ((n > 3) && (0 == strcmp (&libname[n - 3], ".la")))
347 return GNUNET_OK; /* .la file */
348 basename = GNUNET_strdup (libname);
349 if (NULL != (dot = strstr (basename, ".")))
351 lib_ret = GNUNET_PLUGIN_load (basename, lac->arg);
353 lac->cb (lac->cb_cls, basename, lib_ret);
354 GNUNET_free (basename);
360 * Load all compatible plugins with the given base name.
362 * Note that the library must export symbols called
363 * `basename_ANYTHING_init` and `basename_ANYTHING__done`. These will
364 * be called when the library is loaded and unloaded respectively.
366 * @param basename basename of the plugins to load
367 * @param arg argument to the plugin initialization function
368 * @param cb function to call for each plugin found
369 * @param cb_cls closure for @a cb
372 GNUNET_PLUGIN_load_all (const char *basename, void *arg,
373 GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
375 struct LoadAllContext lac;
378 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 _("Could not determine plugin installation path.\n"));
385 lac.basename = basename;
389 GNUNET_DISK_directory_scan (path, &find_libraries, &lac);
394 /* end of plugin.c */