GNUnet  0.11.x
plugin.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2002-2013 GNUnet e.V.
4 
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.
9 
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.
14 
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
27 #include "platform.h"
28 #include <ltdl.h>
29 #include "gnunet_util_lib.h"
30 
31 #define LOG(kind, ...) GNUNET_log_from (kind, "util-plugin", __VA_ARGS__)
32 
36 struct PluginList
37 {
41  struct PluginList *next;
42 
46  char *name;
47 
51  void *handle;
52 };
53 
54 
58 static int initialized;
59 
63 static char *old_dlsearchpath;
64 
68 static struct PluginList *plugins;
69 
70 
74 static void
76 {
77  int err;
78  const char *opath;
79  char *path;
80  char *cpath;
81 
82  err = lt_dlinit ();
83  if (err > 0)
84  {
85  fprintf (stderr,
86  _ ("Initialization of plugin mechanism failed: %s!\n"),
87  lt_dlerror ());
88  return;
89  }
90  opath = lt_dlgetsearchpath ();
91  if (NULL != opath)
94  if (NULL != path)
95  {
96  if (NULL != opath)
97  {
98  GNUNET_asprintf (&cpath, "%s:%s", opath, path);
99  lt_dlsetsearchpath (cpath);
100  GNUNET_free (path);
101  GNUNET_free (cpath);
102  }
103  else
104  {
105  lt_dlsetsearchpath (path);
106  GNUNET_free (path);
107  }
108  }
109 }
110 
111 
115 static void
117 {
118  lt_dlsetsearchpath (old_dlsearchpath);
119  if (NULL != old_dlsearchpath)
120  {
122  old_dlsearchpath = NULL;
123  }
124  lt_dlexit ();
125 }
126 
127 
136 resolve_function (struct PluginList *plug, const char *name)
137 {
138  char *initName;
139  void *mptr;
140 
141  GNUNET_asprintf (&initName, "_%s_%s", plug->name, name);
142  mptr = lt_dlsym (plug->handle, &initName[1]);
143  if (NULL == mptr)
144  mptr = lt_dlsym (plug->handle, initName);
145  if (NULL == mptr)
147  _ ("`%s' failed to resolve method '%s' with error: %s\n"),
148  "lt_dlsym",
149  &initName[1],
150  lt_dlerror ());
151  GNUNET_free (initName);
152  return mptr;
153 }
154 
155 
165 int
166 GNUNET_PLUGIN_test (const char *library_name)
167 {
168  void *libhandle;
170  struct PluginList plug;
171 
172  if (! initialized)
173  {
175  plugin_init ();
176  }
177  libhandle = lt_dlopenext (library_name);
178  if (NULL == libhandle)
179  return GNUNET_NO;
180  plug.handle = libhandle;
181  plug.name = (char *) library_name;
182  init = resolve_function (&plug, "init");
183  if (NULL == init)
184  {
185  GNUNET_break (0);
186  lt_dlclose (libhandle);
187  return GNUNET_NO;
188  }
189  lt_dlclose (libhandle);
190  return GNUNET_YES;
191 }
192 
193 
206 void *
207 GNUNET_PLUGIN_load (const char *library_name, void *arg)
208 {
209  void *libhandle;
210  struct PluginList *plug;
212  void *ret;
213 
214  if (! initialized)
215  {
217  plugin_init ();
218  }
219  libhandle = lt_dlopenext (library_name);
220  if (libhandle == NULL)
221  {
223  _ ("`%s' failed for library `%s' with error: %s\n"),
224  "lt_dlopenext",
225  library_name,
226  lt_dlerror ());
227  return NULL;
228  }
229  plug = GNUNET_new (struct PluginList);
230  plug->handle = libhandle;
231  plug->name = GNUNET_strdup (library_name);
232  plug->next = plugins;
233  plugins = plug;
234  init = resolve_function (plug, "init");
235  if ((init == NULL) || (NULL == (ret = init (arg))))
236  {
237  lt_dlclose (libhandle);
238  GNUNET_free (plug->name);
239  plugins = plug->next;
240  GNUNET_free (plug);
241  return NULL;
242  }
243  return ret;
244 }
245 
246 
255 void *
256 GNUNET_PLUGIN_unload (const char *library_name, void *arg)
257 {
258  struct PluginList *pos;
259  struct PluginList *prev;
261  void *ret;
262 
263  prev = NULL;
264  pos = plugins;
265  while ((NULL != pos) && (0 != strcmp (pos->name, library_name)))
266  {
267  prev = pos;
268  pos = pos->next;
269  }
270  if (NULL == pos)
271  return NULL;
272 
273  done = resolve_function (pos, "done");
274  ret = NULL;
275  if (NULL != done)
276  ret = done (arg);
277  if (NULL == prev)
278  plugins = pos->next;
279  else
280  prev->next = pos->next;
281  lt_dlclose (pos->handle);
282  GNUNET_free (pos->name);
283  GNUNET_free (pos);
284  if (NULL == plugins)
285  {
286  plugin_fini ();
288  }
289  return ret;
290 }
291 
292 
297 {
301  const char *basename;
302 
306  void *arg;
307 
312 
316  void *cb_cls;
317 };
318 
319 
329 static int
330 find_libraries (void *cls, const char *filename)
331 {
332  struct LoadAllContext *lac = cls;
333  const char *slashpos;
334  const char *libname;
335  char *basename;
336  char *dot;
337  void *lib_ret;
338  size_t n;
339 
340  libname = filename;
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, ".")))
350  *dot = '\0';
351  lib_ret = GNUNET_PLUGIN_load (basename, lac->arg);
352  if (NULL != lib_ret)
353  lac->cb (lac->cb_cls, basename, lib_ret);
354  GNUNET_free (basename);
355  return GNUNET_OK;
356 }
357 
358 
371 void
373  void *arg,
375  void *cb_cls)
376 {
377  struct LoadAllContext lac;
378  char *path;
379 
381  if (NULL == path)
382  {
384  _ ("Could not determine plugin installation path.\n"));
385  return;
386  }
387  lac.basename = basename;
388  lac.arg = arg;
389  lac.cb = cb;
390  lac.cb_cls = cb_cls;
392  GNUNET_free (path);
393 }
394 
395 
396 /* end of plugin.c */
static void done()
char * name
Name of the library.
Definition: plugin.c:46
void * arg
Argument to give to &#39;init&#39; when loading the plugin.
Definition: plugin.c:306
Return the directory where libraries are installed.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_NO
Definition: gnunet_common.h:78
void(* GNUNET_PLUGIN_LoaderCallback)(void *cls, const char *library_name, void *lib_ret)
Signature of a function called by GNUNET_PLUGIN_load_all().
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct PluginList * next
This is a linked list.
Definition: plugin.c:41
int GNUNET_DISK_directory_scan(const char *dir_name, GNUNET_FileNameCallback callback, void *callback_cls)
Scan a directory for files.
Definition: disk.c:912
Linked list of active plugins.
Definition: plugin.c:36
void * handle
System handle.
Definition: plugin.c:51
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static void plugin_init()
Setup libtool paths.
Definition: plugin.c:75
static int initialized
Have we been initialized?
Definition: plugin.c:58
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the done callback and returns whatever done returned).
Definition: plugin.c:256
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
#define LOG(kind,...)
Definition: plugin.c:31
void * cb_cls
Closure for cb.
Definition: plugin.c:316
#define DIR_SEPARATOR_STR
Definition: platform.h:168
char * GNUNET_OS_installation_get_path(enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation directory.
static char * filename
static void plugin_fini()
Shutdown libtool.
Definition: plugin.c:116
void GNUNET_PLUGIN_load_all(const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
Load all compatible plugins with the given base name.
Definition: plugin.c:372
static int find_libraries(void *cls, const char *filename)
Function called on each plugin in the directory.
Definition: plugin.c:330
static char * init
Set to the name of a service to start.
Definition: gnunet-arm.c:74
static struct PluginList * plugins
List of plugins we have loaded.
Definition: plugin.c:68
#define GNUNET_log(kind,...)
GNUNET_PLUGIN_LoaderCallback cb
Function to call for each plugin.
Definition: plugin.c:311
Closure for find_libraries().
Definition: plugin.c:296
#define GNUNET_YES
Definition: gnunet_common.h:77
void * GNUNET_PLUGIN_load(const char *library_name, void *arg)
Setup plugin (runs the init callback and returns whatever init returned).
Definition: plugin.c:207
void *(* GNUNET_PLUGIN_Callback)(void *arg)
Signature of any function exported by a plugin.
int GNUNET_PLUGIN_test(const char *library_name)
Test if a plugin exists.
Definition: plugin.c:166
#define GNUNET_free(ptr)
Wrapper around free.
static GNUNET_PLUGIN_Callback resolve_function(struct PluginList *plug, const char *name)
Lookup a function in the plugin.
Definition: plugin.c:136
const char * basename
Prefix the plugin names we find have to match.
Definition: plugin.c:301
static char * old_dlsearchpath
Libtool search path before we started.
Definition: plugin.c:63