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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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-plugin", __VA_ARGS__)
34 * Linked list of active plugins.
38 * This is a linked list.
40 struct PluginList *next;
43 * Name of the library.
55 * Have we been initialized?
57 static int initialized;
60 * Libtool search path before we started.
62 static char *old_dlsearchpath;
65 * List of plugins we have loaded.
67 static struct PluginList *plugins;
71 * Setup libtool paths.
85 _("Initialization of plugin mechanism failed: %s!\n"),
89 opath = lt_dlgetsearchpath();
91 old_dlsearchpath = GNUNET_strdup(opath);
92 path = GNUNET_OS_installation_get_path(GNUNET_OS_IPK_LIBDIR);
97 GNUNET_asprintf(&cpath, "%s:%s", opath, path);
98 lt_dlsetsearchpath(cpath);
104 lt_dlsetsearchpath(path);
117 lt_dlsetsearchpath(old_dlsearchpath);
118 if (NULL != old_dlsearchpath)
120 GNUNET_free(old_dlsearchpath);
121 old_dlsearchpath = NULL;
128 * Lookup a function in the plugin.
130 * @param plug the plugin to check
131 * @param name name of the symbol to look for
132 * @return NULL if the symbol was not found
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"),
150 GNUNET_free(initName);
156 * Test if a plugin exists.
158 * Note that the library must export a symbol called
159 * `library_name_init` for the test to succeed.
161 * @param library_name name of the plugin to test if it is installed
162 * @return #GNUNET_YES if the plugin exists, #GNUNET_NO if not
165 GNUNET_PLUGIN_test(const char *library_name)
168 GNUNET_PLUGIN_Callback init;
169 struct PluginList plug;
173 initialized = GNUNET_YES;
176 libhandle = lt_dlopenext(library_name);
177 if (NULL == libhandle)
179 plug.handle = libhandle;
180 plug.name = (char *)library_name;
181 init = resolve_function(&plug, "init");
185 lt_dlclose(libhandle);
188 lt_dlclose(libhandle);
194 * Setup plugin (runs the `init` callback and returns whatever `init`
195 * returned). If `init` returns NULL, the plugin is unloaded.
197 * Note that the library must export symbols called
198 * `library_name_init` and `library_name_done`. These will be called
199 * when the library is loaded and unloaded respectively.
201 * @param library_name name of the plugin to load
202 * @param arg argument to the plugin initialization function
203 * @return whatever the initialization function returned
206 GNUNET_PLUGIN_load(const char *library_name, void *arg)
209 struct PluginList *plug;
210 GNUNET_PLUGIN_Callback init;
215 initialized = GNUNET_YES;
218 libhandle = lt_dlopenext(library_name);
219 if (libhandle == NULL)
221 LOG(GNUNET_ERROR_TYPE_ERROR,
222 _("`%s' failed for library `%s' with error: %s\n"),
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, void *arg)
257 struct PluginList *pos;
258 struct PluginList *prev;
259 GNUNET_PLUGIN_Callback done;
264 while ((NULL != pos) && (0 != strcmp(pos->name, library_name)))
272 done = resolve_function(pos, "done");
279 prev->next = pos->next;
280 lt_dlclose(pos->handle);
281 GNUNET_free(pos->name);
286 initialized = GNUNET_NO;
293 * Closure for #find_libraries().
295 struct LoadAllContext {
297 * Prefix the plugin names we find have to match.
299 const char *basename;
302 * Argument to give to 'init' when loading the plugin.
307 * Function to call for each plugin.
309 GNUNET_PLUGIN_LoaderCallback cb;
319 * Function called on each plugin in the directory. Loads
320 * the plugins that match the given basename.
322 * @param cls the `struct LoadAllContext` describing which
323 * plugins to load and what to do with them
324 * @param filename name of a plugin library to check
325 * @return #GNUNET_OK (continue loading)
328 find_libraries(void *cls, const char *filename)
330 struct LoadAllContext *lac = cls;
331 const char *slashpos;
339 while (NULL != (slashpos = strstr(libname, DIR_SEPARATOR_STR)))
340 libname = slashpos + 1;
342 if (0 != strncmp(lac->basename, libname, strlen(lac->basename)))
343 return GNUNET_OK; /* wrong name */
344 if ((n > 3) && (0 == strcmp(&libname[n - 3], ".la")))
345 return GNUNET_OK; /* .la file */
346 basename = GNUNET_strdup(libname);
347 if (NULL != (dot = strstr(basename, ".")))
349 lib_ret = GNUNET_PLUGIN_load(basename, lac->arg);
351 lac->cb(lac->cb_cls, basename, lib_ret);
352 GNUNET_free(basename);
358 * Load all compatible plugins with the given base name.
360 * Note that the library must export symbols called
361 * `basename_ANYTHING_init` and `basename_ANYTHING__done`. These will
362 * be called when the library is loaded and unloaded respectively.
364 * @param basename basename of the plugins to load
365 * @param arg argument to the plugin initialization function
366 * @param cb function to call for each plugin found
367 * @param cb_cls closure for @a cb
370 GNUNET_PLUGIN_load_all(const char *basename,
372 GNUNET_PLUGIN_LoaderCallback cb,
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 */