GNUnet  0.10.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 {
40  struct PluginList *next;
41 
45  char *name;
46 
50  void *handle;
51 };
52 
53 
57 static int initialized;
58 
62 static char *old_dlsearchpath;
63 
67 static struct PluginList *plugins;
68 
69 
73 static void
75 {
76  int err;
77  const char *opath;
78  char *path;
79  char *cpath;
80 
81  err = lt_dlinit();
82  if (err > 0)
83  {
84  fprintf(stderr,
85  _("Initialization of plugin mechanism failed: %s!\n"),
86  lt_dlerror());
87  return;
88  }
89  opath = lt_dlgetsearchpath();
90  if (NULL != opath)
93  if (NULL != path)
94  {
95  if (NULL != opath)
96  {
97  GNUNET_asprintf(&cpath, "%s:%s", opath, path);
98  lt_dlsetsearchpath(cpath);
99  GNUNET_free(path);
100  GNUNET_free(cpath);
101  }
102  else
103  {
104  lt_dlsetsearchpath(path);
105  GNUNET_free(path);
106  }
107  }
108 }
109 
110 
114 static void
116 {
117  lt_dlsetsearchpath(old_dlsearchpath);
118  if (NULL != old_dlsearchpath)
119  {
121  old_dlsearchpath = NULL;
122  }
123  lt_dlexit();
124 }
125 
126 
135 resolve_function(struct PluginList *plug, const char *name)
136 {
137  char *initName;
138  void *mptr;
139 
140  GNUNET_asprintf(&initName, "_%s_%s", plug->name, name);
141  mptr = lt_dlsym(plug->handle, &initName[1]);
142  if (NULL == mptr)
143  mptr = lt_dlsym(plug->handle, initName);
144  if (NULL == mptr)
146  _("`%s' failed to resolve method '%s' with error: %s\n"),
147  "lt_dlsym",
148  &initName[1],
149  lt_dlerror());
150  GNUNET_free(initName);
151  return mptr;
152 }
153 
154 
164 int
165 GNUNET_PLUGIN_test(const char *library_name)
166 {
167  void *libhandle;
169  struct PluginList plug;
170 
171  if (!initialized)
172  {
174  plugin_init();
175  }
176  libhandle = lt_dlopenext(library_name);
177  if (NULL == libhandle)
178  return GNUNET_NO;
179  plug.handle = libhandle;
180  plug.name = (char *)library_name;
181  init = resolve_function(&plug, "init");
182  if (NULL == init)
183  {
184  GNUNET_break(0);
185  lt_dlclose(libhandle);
186  return GNUNET_NO;
187  }
188  lt_dlclose(libhandle);
189  return GNUNET_YES;
190 }
191 
192 
205 void *
206 GNUNET_PLUGIN_load(const char *library_name, void *arg)
207 {
208  void *libhandle;
209  struct PluginList *plug;
211  void *ret;
212 
213  if (!initialized)
214  {
216  plugin_init();
217  }
218  libhandle = lt_dlopenext(library_name);
219  if (libhandle == NULL)
220  {
222  _("`%s' failed for library `%s' with error: %s\n"),
223  "lt_dlopenext",
224  library_name,
225  lt_dlerror());
226  return NULL;
227  }
228  plug = GNUNET_new(struct PluginList);
229  plug->handle = libhandle;
230  plug->name = GNUNET_strdup(library_name);
231  plug->next = plugins;
232  plugins = plug;
233  init = resolve_function(plug, "init");
234  if ((init == NULL) || (NULL == (ret = init(arg))))
235  {
236  lt_dlclose(libhandle);
237  GNUNET_free(plug->name);
238  plugins = plug->next;
239  GNUNET_free(plug);
240  return NULL;
241  }
242  return ret;
243 }
244 
245 
254 void *
255 GNUNET_PLUGIN_unload(const char *library_name, void *arg)
256 {
257  struct PluginList *pos;
258  struct PluginList *prev;
260  void *ret;
261 
262  prev = NULL;
263  pos = plugins;
264  while ((NULL != pos) && (0 != strcmp(pos->name, library_name)))
265  {
266  prev = pos;
267  pos = pos->next;
268  }
269  if (NULL == pos)
270  return NULL;
271 
272  done = resolve_function(pos, "done");
273  ret = NULL;
274  if (NULL != done)
275  ret = done(arg);
276  if (NULL == prev)
277  plugins = pos->next;
278  else
279  prev->next = pos->next;
280  lt_dlclose(pos->handle);
281  GNUNET_free(pos->name);
282  GNUNET_free(pos);
283  if (NULL == plugins)
284  {
285  plugin_fini();
287  }
288  return ret;
289 }
290 
291 
299  const char *basename;
300 
304  void *arg;
305 
310 
314  void *cb_cls;
315 };
316 
317 
327 static int
328 find_libraries(void *cls, const char *filename)
329 {
330  struct LoadAllContext *lac = cls;
331  const char *slashpos;
332  const char *libname;
333  char *basename;
334  char *dot;
335  void *lib_ret;
336  size_t n;
337 
338  libname = filename;
339  while (NULL != (slashpos = strstr(libname, DIR_SEPARATOR_STR)))
340  libname = slashpos + 1;
341  n = strlen(libname);
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, ".")))
348  *dot = '\0';
349  lib_ret = GNUNET_PLUGIN_load(basename, lac->arg);
350  if (NULL != lib_ret)
351  lac->cb(lac->cb_cls, basename, lib_ret);
352  GNUNET_free(basename);
353  return GNUNET_OK;
354 }
355 
356 
369 void
371  void *arg,
373  void *cb_cls)
374 {
375  struct LoadAllContext lac;
376  char *path;
377 
379  if (NULL == path)
380  {
382  _("Could not determine plugin installation path.\n"));
383  return;
384  }
385  lac.basename = basename;
386  lac.arg = arg;
387  lac.cb = cb;
388  lac.cb_cls = cb_cls;
390  GNUNET_free(path);
391 }
392 
393 
394 /* end of plugin.c */
static void done()
char * name
Name of the library.
Definition: plugin.c:45
void * arg
Argument to give to &#39;init&#39; when loading the plugin.
Definition: plugin.c:304
Return the directory where libraries are installed.
#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:40
int GNUNET_DISK_directory_scan(const char *dir_name, GNUNET_FileNameCallback callback, void *callback_cls)
Scan a directory for files.
Definition: disk.c:909
Linked list of active plugins.
Definition: plugin.c:36
void * handle
System handle.
Definition: plugin.c:50
static int ret
Final status code.
Definition: gnunet-arm.c:89
#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:74
static int initialized
Have we been initialized?
Definition: plugin.c:57
#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:255
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:314
#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:115
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:370
static int find_libraries(void *cls, const char *filename)
Function called on each plugin in the directory.
Definition: plugin.c:328
static char * init
Set to the name of a service to start.
Definition: gnunet-arm.c:69
static struct PluginList * plugins
List of plugins we have loaded.
Definition: plugin.c:67
#define GNUNET_log(kind,...)
GNUNET_PLUGIN_LoaderCallback cb
Function to call for each plugin.
Definition: plugin.c:309
Closure for find_libraries().
Definition: plugin.c:295
#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:206
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:165
#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:135
const char * basename
Prefix the plugin names we find have to match.
Definition: plugin.c:299
static char * old_dlsearchpath
Libtool search path before we started.
Definition: plugin.c:62