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
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 
137  const char *name)
138 {
139  char *initName;
140  void *mptr;
141 
142  GNUNET_asprintf (&initName,
143  "_%s_%s",
144  plug->name,
145  name);
146  mptr = lt_dlsym (plug->handle, &initName[1]);
147  if (NULL == mptr)
148  mptr = lt_dlsym (plug->handle, initName);
149  if (NULL == mptr)
151  _("`%s' failed to resolve method '%s' with error: %s\n"),
152  "lt_dlsym",
153  &initName[1], lt_dlerror ());
154  GNUNET_free (initName);
155  return mptr;
156 }
157 
158 
168 int
169 GNUNET_PLUGIN_test (const char *library_name)
170 {
171  void *libhandle;
173  struct PluginList plug;
174 
175  if (! initialized)
176  {
178  plugin_init ();
179  }
180  libhandle = lt_dlopenext (library_name);
181  if (NULL == libhandle)
182  return GNUNET_NO;
183  plug.handle = libhandle;
184  plug.name = (char *) library_name;
185  init = resolve_function (&plug, "init");
186  if (NULL == init)
187  {
188  GNUNET_break (0);
189  lt_dlclose (libhandle);
190  return GNUNET_NO;
191  }
192  lt_dlclose (libhandle);
193  return GNUNET_YES;
194 }
195 
196 
209 void *
210 GNUNET_PLUGIN_load (const char *library_name, void *arg)
211 {
212  void *libhandle;
213  struct PluginList *plug;
215  void *ret;
216 
217  if (!initialized)
218  {
220  plugin_init ();
221  }
222  libhandle = lt_dlopenext (library_name);
223  if (libhandle == NULL)
224  {
226  _("`%s' failed for library `%s' with error: %s\n"),
227  "lt_dlopenext",
228  library_name, lt_dlerror ());
229  return NULL;
230  }
231  plug = GNUNET_new (struct PluginList);
232  plug->handle = libhandle;
233  plug->name = GNUNET_strdup (library_name);
234  plug->next = plugins;
235  plugins = plug;
236  init = resolve_function (plug, "init");
237  if ((init == NULL) || (NULL == (ret = init (arg))))
238  {
239  lt_dlclose (libhandle);
240  GNUNET_free (plug->name);
241  plugins = plug->next;
242  GNUNET_free (plug);
243  return NULL;
244  }
245  return ret;
246 }
247 
248 
257 void *
258 GNUNET_PLUGIN_unload (const char *library_name,
259  void *arg)
260 {
261  struct PluginList *pos;
262  struct PluginList *prev;
264  void *ret;
265 
266  prev = NULL;
267  pos = plugins;
268  while ((NULL != pos) && (0 != strcmp (pos->name, library_name)))
269  {
270  prev = pos;
271  pos = pos->next;
272  }
273  if (NULL == pos)
274  return NULL;
275 
276  done = resolve_function (pos, "done");
277  ret = NULL;
278  if (NULL != done)
279  ret = done (arg);
280  if (NULL == prev)
281  plugins = pos->next;
282  else
283  prev->next = pos->next;
284  lt_dlclose (pos->handle);
285  GNUNET_free (pos->name);
286  GNUNET_free (pos);
287  if (NULL == plugins)
288  {
289  plugin_fini ();
291  }
292  return ret;
293 }
294 
295 
300 {
304  const char *basename;
305 
309  void *arg;
310 
315 
319  void *cb_cls;
320 };
321 
322 
332 static int
333 find_libraries (void *cls, const char *filename)
334 {
335  struct LoadAllContext *lac = cls;
336  const char *slashpos;
337  const char *libname;
338  char *basename;
339  char *dot;
340  void *lib_ret;
341  size_t n;
342 
343  libname = filename;
344  while (NULL != (slashpos = strstr (libname, DIR_SEPARATOR_STR)))
345  libname = slashpos + 1;
346  n = strlen (libname);
347  if (0 != strncmp (lac->basename, libname, strlen (lac->basename)))
348  return GNUNET_OK; /* wrong name */
349  if ((n > 3) && (0 == strcmp (&libname[n - 3], ".la")))
350  return GNUNET_OK; /* .la file */
351  basename = GNUNET_strdup (libname);
352  if (NULL != (dot = strstr (basename, ".")))
353  *dot = '\0';
354  lib_ret = GNUNET_PLUGIN_load (basename, lac->arg);
355  if (NULL != lib_ret)
356  lac->cb (lac->cb_cls, basename, lib_ret);
357  GNUNET_free (basename);
358  return GNUNET_OK;
359 }
360 
361 
374 void
375 GNUNET_PLUGIN_load_all (const char *basename, void *arg,
377 {
378  struct LoadAllContext lac;
379  char *path;
380 
382  if (NULL == path)
383  {
385  _("Could not determine plugin installation path.\n"));
386  return;
387  }
388  lac.basename = basename;
389  lac.arg = arg;
390  lac.cb = cb;
391  lac.cb_cls = cb_cls;
393  GNUNET_free (path);
394 }
395 
396 
397 /* 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:309
#define FPRINTF
Definition: plibc.h:683
Return the directory where libraries are installed.
#define GNUNET_NO
Definition: gnunet_common.h:81
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:78
#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:1233
Linked list of active plugins.
Definition: plugin.c:36
void * handle
System handle.
Definition: plugin.c:51
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:75
static int initialized
Have we been initialized?
Definition: plugin.c:58
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the done callback and returns whatever done returned).
Definition: plugin.c:258
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:319
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:375
static int find_libraries(void *cls, const char *filename)
Function called on each plugin in the directory.
Definition: plugin.c:333
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:68
#define GNUNET_log(kind,...)
GNUNET_PLUGIN_LoaderCallback cb
Function to call for each plugin.
Definition: plugin.c:314
Closure for find_libraries().
Definition: plugin.c:299
#define GNUNET_YES
Definition: gnunet_common.h:80
void * GNUNET_PLUGIN_load(const char *library_name, void *arg)
Setup plugin (runs the init callback and returns whatever init returned).
Definition: plugin.c:210
#define DIR_SEPARATOR_STR
Definition: plibc.h:632
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:169
#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:304
static char * old_dlsearchpath
Libtool search path before we started.
Definition: plugin.c:63