2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2009 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 2, 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_common.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_plugin_lib.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
36 * Linked list of active plugins.
41 * This is a linked list.
43 struct PluginList *next;
46 * Name of the library.
58 * Have we been initialized?
60 static int initialized;
64 * Libtool search path before we started.
66 static char *old_dlsearchpath;
70 * List of plugins we have loaded.
72 static struct PluginList *plugins;
76 * Setup libtool paths.
89 fprintf (stderr, _("Initialization of plugin mechanism failed: %s!\n"),
93 opath = lt_dlgetsearchpath ();
95 old_dlsearchpath = GNUNET_strdup (opath);
96 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
101 GNUNET_asprintf (&cpath, "%s:%s", opath, path);
102 lt_dlsetsearchpath (cpath);
108 lt_dlsetsearchpath (path);
121 lt_dlsetsearchpath (old_dlsearchpath);
122 if (old_dlsearchpath != NULL)
124 GNUNET_free (old_dlsearchpath);
125 old_dlsearchpath = NULL;
132 * Lookup a function in the plugin.
134 static GNUNET_PLUGIN_Callback
135 resolve_function (struct PluginList *plug, const char *name)
140 GNUNET_asprintf (&initName, "_%s_%s", plug->name, name);
141 mptr = lt_dlsym (plug->handle, &initName[1]);
143 mptr = lt_dlsym (plug->handle, initName);
145 LOG (GNUNET_ERROR_TYPE_ERROR,
146 _("`%s' failed to resolve method '%s' with error: %s\n"),
147 "lt_dlsym", &initName[1], lt_dlerror ());
148 GNUNET_free (initName);
153 * Test if a plugin exists.
155 * Note that the library must export a symbol called
156 * "library_name_init" for the test to succeed.
158 * @param library_name name of the plugin to test if it is installed
159 * @return GNUNET_YES if the plugin exists, GNUNET_NO if not
162 GNUNET_PLUGIN_test (const char *library_name)
165 GNUNET_PLUGIN_Callback init;
166 struct PluginList plug;
170 initialized = GNUNET_YES;
173 libhandle = lt_dlopenext (library_name);
174 if (libhandle == NULL)
176 plug.handle = libhandle;
177 plug.name = (char *) library_name;
178 init = resolve_function (&plug, "init");
182 lt_dlclose (libhandle);
185 lt_dlclose (libhandle);
191 * Setup plugin (runs the "init" callback and returns whatever "init"
192 * returned). If "init" returns NULL, the plugin is unloaded.
194 * Note that the library must export symbols called
195 * "library_name_init" and "library_name_done". These will be called
196 * when the library is loaded and unloaded respectively.
198 * @param library_name name of the plugin to load
199 * @param arg argument to the plugin initialization function
200 * @return whatever the initialization function returned
203 GNUNET_PLUGIN_load (const char *library_name, void *arg)
206 struct PluginList *plug;
207 GNUNET_PLUGIN_Callback init;
212 initialized = GNUNET_YES;
215 libhandle = lt_dlopenext (library_name);
216 if (libhandle == NULL)
218 LOG (GNUNET_ERROR_TYPE_ERROR,
219 _("`%s' failed for library `%s' with error: %s\n"),
220 "lt_dlopenext", library_name, lt_dlerror ());
223 plug = GNUNET_malloc (sizeof (struct PluginList));
224 plug->handle = libhandle;
225 plug->name = GNUNET_strdup (library_name);
226 plug->next = plugins;
228 init = resolve_function (plug, "init");
229 if ((init == NULL) || (NULL == (ret = init (arg))))
231 lt_dlclose (libhandle);
232 GNUNET_free (plug->name);
233 plugins = plug->next;
242 * Unload plugin (runs the "done" callback and returns whatever "done"
243 * returned). The plugin is then unloaded.
245 * @param library_name name of the plugin to unload
246 * @param arg argument to the plugin shutdown function
247 * @return whatever the shutdown function returned
250 GNUNET_PLUGIN_unload (const char *library_name, void *arg)
252 struct PluginList *pos;
253 struct PluginList *prev;
254 GNUNET_PLUGIN_Callback done;
259 while ((pos != NULL) && (0 != strcmp (pos->name, library_name)))
267 done = resolve_function (pos, "done");
274 prev->next = pos->next;
275 lt_dlclose (pos->handle);
276 GNUNET_free (pos->name);
281 initialized = GNUNET_NO;
287 struct LoadAllContext
289 const char *basename;
291 GNUNET_PLUGIN_LoaderCallback cb;
297 find_libraries (void *cls,
298 const char *filename)
300 struct LoadAllContext *lac = cls;
301 const char *slashpos;
309 while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR)))
310 libname = slashpos + 1;
311 n = strlen (libname);
312 if (0 != strncmp (lac->basename,
314 strlen (lac->basename)))
315 return GNUNET_OK; /* wrong name */
317 (0 == strcmp (&libname[n-3],
319 return GNUNET_OK; /* .la file */
320 basename = GNUNET_strdup (libname);
321 if (NULL != (dot = strstr (basename, ".")))
323 lib_ret = GNUNET_PLUGIN_load (basename, lac->arg);
325 lac->cb (lac->cb_cls, basename, lib_ret);
326 GNUNET_free (basename);
332 * Load all compatible plugins with the given base name.
334 * Note that the library must export symbols called
335 * "basename_ANYTHING_init" and "basename_ANYTHING__done". These will
336 * be called when the library is loaded and unloaded respectively.
338 * @param basename basename of the plugins to load
339 * @param arg argument to the plugin initialization function
340 * @param cb function to call for each plugin found
341 * @param cb_cls closure for 'cb'
344 GNUNET_PLUGIN_load_all (const char *basename,
346 GNUNET_PLUGIN_LoaderCallback cb,
349 struct LoadAllContext lac;
352 path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
355 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356 _("Could not determine plugin installation path.\n"));
359 lac.basename = basename;
363 GNUNET_DISK_directory_scan (path,
370 /* end of plugin.c */