libextractor  1.11
About: GNU libextractor is a library used to extract meta-data from files of arbitrary type.
  Fossies Dox: libextractor-1.11.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

extractor_plugpath.c
Go to the documentation of this file.
1 /*
2  This file is part of libextractor.
3  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009, 2012 Vidyut Samanta and Christian Grothoff
4 
5  libextractor 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 3, or (at your
8  option) any later version.
9 
10  libextractor 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.
14 
15  You should have received a copy of the GNU General Public License
16  along with libextractor; see the file COPYING. If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file main/extractor_plugpath.c
22  * @brief determine path where plugins are installed
23  * @author Christian Grothoff
24  */
25 
26 #include "platform.h"
27 #include "extractor.h"
28 #include <dirent.h>
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <ltdl.h>
32 
33 #include "extractor_plugpath.h"
34 #include "extractor_logging.h"
35 
36 /**
37  * Function to call on paths.
38  *
39  * @param cls closure
40  * @param path a directory path
41  */
42 typedef void (*EXTRACTOR_PathProcessor) (void *cls,
43  const char *path);
44 
45 
46 /**
47  * Remove a trailing '/bin/' from 'in' (if present).
48  *
49  * @param in input string, modified
50  * @return NULL if 'in' is NULL, otherwise 'in' with '/bin/' removed
51  */
52 static char *
53 cut_bin (char *in)
54 {
55  size_t p;
56 
57  if (NULL == in)
58  return NULL;
59  p = strlen (in);
60  if (p < 4)
61  return in;
62  if ( ('/' == in[p - 1]) ||
63  ('\\' == in[p - 1]) )
64  in[--p] = '\0';
65  if (0 == strcmp (&in[p - 4],
66  "/bin"))
67  {
68  in[p - 4] = '\0';
69  p -= 4;
70  }
71  else if (0 == strcmp (&in[p - 4],
72  "\\bin"))
73  {
74  in[p - 4] = '\0';
75  p -= 4;
76  }
77  return in;
78 }
79 
80 
81 #if GNU_LINUX
82 /**
83  * Try to determine path by reading /proc/PID/exe or
84  * /proc/PID/maps.
85  *
86  * Note that this may fail if LE is installed in one directory
87  * and the binary linking against it sits elsewhere.
88  */
89 static char *
90 get_path_from_proc_exe ()
91 {
92  char fn[64];
93  char line[1024];
94  char dir[1024];
95  char *lnk;
96  char *ret;
97  char *lestr;
98  ssize_t size;
99  FILE *f;
100 
101  snprintf (fn,
102  sizeof (fn),
103  "/proc/%u/maps",
104  getpid ());
105  if (NULL != (f = fopen (fn, "r")))
106  {
107  while (NULL != fgets (line, 1024, f))
108  {
109  if ( (1 == sscanf (line,
110  "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%s",
111  dir)) &&
112  (NULL != (lestr = strstr (dir,
113  "libextractor")) ) )
114  {
115  lestr[0] = '\0';
116  fclose (f);
117  return strdup (dir);
118  }
119  }
120  fclose (f);
121  }
122  snprintf (fn,
123  sizeof (fn),
124  "/proc/%u/exe",
125  getpid ());
126  if (NULL == (lnk = malloc (1029))) /* 1024 + 6 for "/lib/" catenation */
127  return NULL;
128  size = readlink (fn, lnk, 1023);
129  if ( (size <= 0) || (size >= 1024) )
130  {
131  free (lnk);
132  return NULL;
133  }
134  lnk[size] = '\0';
135  while ( ('/' != lnk[size]) &&
136  (size > 0) )
137  size--;
138  if ( (size < 4) ||
139  ('/' != lnk[size - 4]) )
140  {
141  /* not installed in "/bin/" -- binary path probably useless */
142  free (lnk);
143  return NULL;
144  }
145  lnk[size] = '\0';
146  lnk = cut_bin (lnk);
147  if (NULL == (ret = realloc (lnk, strlen (lnk) + 6)))
148  {
149  LOG_STRERROR ("realloc");
150  free (lnk);
151  return NULL;
152  }
153  strcat (ret, "/lib/"); /* guess "lib/" as the library dir */
154  return ret;
155 }
156 
157 
158 #endif
159 
160 
161 #if WINDOWS
162 static HMODULE le_dll = NULL;
163 
164 BOOL WINAPI
165 DllMain (HINSTANCE hinstDLL,
166  DWORD fdwReason,
167  LPVOID lpvReserved)
168 {
169  switch (fdwReason)
170  {
171  case DLL_PROCESS_ATTACH:
172  le_dll = (HMODULE) hinstDLL;
173  break;
174  }
175 
176  return TRUE;
177 }
178 
179 
180 /**
181  * Try to determine path with win32-specific function
182  */
183 static char *
184 get_path_from_module_filename ()
185 {
186  char *path;
187  char *ret;
188  char *idx;
189 
190  if (NULL == (path = malloc (4103))) /* 4096+nil+6 for "/lib/" catenation */
191  return NULL;
192  GetModuleFileName (le_dll, path, 4096);
193  idx = path + strlen (path);
194  while ( (idx > path) &&
195  ('\\' != *idx) &&
196  ('/' != *idx) )
197  idx--;
198  *idx = '\0';
199  path = cut_bin (path);
200  if (NULL == (ret = realloc (path, strlen (path) + 6)))
201  {
202  LOG_STRERROR ("realloc");
203  free (path);
204  return NULL;
205  }
206  strcat (ret, "/lib/"); /* guess "lib/" as the library dir */
207  return ret;
208 }
209 
210 
211 #endif
212 
213 
214 #if DARWIN
215 #include <dlfcn.h>
216 #include <mach-o/dyld.h>
217 
218 /**
219  * Signature of the '_NSGetExecutablePath" function.
220  *
221  * @param buf where to write the path
222  * @param number of bytes available in 'buf'
223  * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
224  */
225 typedef int
226 (*MyNSGetExecutablePathProto) (char *buf,
227  size_t *bufsize);
228 
229 
230 /**
231  * Try to obtain the path of our executable using '_NSGetExecutablePath'.
232  *
233  * @return NULL on error
234  */
235 static char *
236 get_path_from_NSGetExecutablePath ()
237 {
238  static char zero;
239  char *path;
240  char *ret;
241  size_t len;
242  MyNSGetExecutablePathProto func;
243 
244  path = NULL;
245  if (NULL == (func =
246  (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT,
247  "_NSGetExecutablePath")))
248  return NULL;
249  path = &zero;
250  len = 0;
251  /* get the path len, including the trailing \0 */
252  (void) func (path, &len);
253  if (0 == len)
254  return NULL;
255  if (NULL == (path = malloc (len)))
256  {
257  LOG_STRERROR ("malloc");
258  return NULL;
259  }
260  if (0 != func (path, &len))
261  {
262  free (path);
263  return NULL;
264  }
265  len = strlen (path);
266  while ((path[len] != '/') && (len > 0))
267  len--;
268  path[len] = '\0';
269  if (NULL != strstr (path, "/lib"))
270  return path;
271  path = cut_bin (path);
272  if (NULL == (ret = realloc (path, strlen (path) + 5)))
273  {
274  LOG_STRERROR ("realloc");
275  free (path);
276  return NULL;
277  }
278  strcat (ret, "/lib/");
279  return ret;
280 }
281 
282 
283 /**
284  * Try to obtain the path of our executable using '_dyld_image' API.
285  *
286  * @return NULL on error
287  */
288 static char *
289 get_path_from_dyld_image ()
290 {
291  const char *path;
292  char *s;
293  char *p;
294  unsigned int i;
295  int c;
296 
297  c = _dyld_image_count ();
298  for (i = 0; i < c; i++)
299  {
300  if (((void *) _dyld_get_image_header (i)) != (void *) &_mh_dylib_header)
301  continue;
302  path = _dyld_get_image_name (i);
303  if ( (NULL == path) || (0 == strlen (path)) )
304  continue;
305  if (NULL == (p = strdup (path)))
306  {
307  LOG_STRERROR ("strdup");
308  return NULL;
309  }
310  s = p + strlen (p);
311  while ( (s > p) && ('/' != *s) )
312  s--;
313  s++;
314  *s = '\0';
315  return p;
316  }
317  return NULL;
318 }
319 
320 
321 #endif
322 
323 
324 /**
325  * Return the actual path to a file found in the current
326  * PATH environment variable.
327  *
328  * @return path to binary, NULL if not found
329  */
330 static char *
332 {
333  struct stat sbuf;
334  char *path;
335  char *pos;
336  char *end;
337  char *buf;
338  char *ret;
339  const char *p;
340 
341  if (NULL == (p = getenv ("PATH")))
342  return NULL;
343  if (NULL == (path = strdup (p))) /* because we write on it */
344  {
345  LOG_STRERROR ("strdup");
346  return NULL;
347  }
348  if (NULL == (buf = malloc (strlen (path) + 20)))
349  {
350  LOG_STRERROR ("malloc");
351  free (path);
352  return NULL;
353  }
354  pos = path;
355  while (NULL != (end = strchr (pos, ':')))
356  {
357  *end = '\0';
358  sprintf (buf, "%s/%s", pos, "extract");
359  if (0 == stat (buf, &sbuf))
360  {
361  free (buf);
362  if (NULL == (pos = strdup (pos)))
363  {
364  LOG_STRERROR ("strdup");
365  free (path);
366  return NULL;
367  }
368  free (path);
369  pos = cut_bin (pos);
370  if (NULL == (ret = realloc (pos, strlen (pos) + 6)))
371  {
372  LOG_STRERROR ("realloc");
373  free (pos);
374  return NULL;
375  }
376  strcat (ret, "/lib/");
377  return ret;
378  }
379  pos = end + 1;
380  }
381  sprintf (buf, "%s/%s", pos, "extract");
382  if (0 == stat (buf, &sbuf))
383  {
384  pos = strdup (pos);
385  free (buf);
386  free (path);
387  if (NULL == pos)
388  return NULL;
389  pos = cut_bin (pos);
390  if (NULL == (ret = realloc (pos, strlen (pos) + 6)))
391  {
392  LOG_STRERROR ("realloc");
393  free (pos);
394  return NULL;
395  }
396  strcat (ret, "/lib/");
397  return ret;
398  }
399  free (buf);
400  free (path);
401  return NULL;
402 }
403 
404 
405 /**
406  * Create a filename by appending 'fname' to 'path'.
407  *
408  * @param path the base path
409  * @param fname the filename to append
410  * @return '$path/$fname', NULL on error
411  */
412 static char *
413 append_to_dir (const char *path,
414  const char *fname)
415 {
416  char *ret;
417  size_t slen;
418 
419  if (0 == (slen = strlen (path)))
420  return NULL;
421  if ('/' == fname[0])
422  fname++;
423  ret = malloc (slen + strlen (fname) + 2);
424  if (NULL == ret)
425  return NULL;
426 #ifdef MINGW
427  if ('\\' == path[slen - 1])
428  sprintf (ret,
429  "%s%s",
430  path,
431  fname);
432  else
433  sprintf (ret,
434  "%s\\%s",
435  path,
436  fname);
437 #else
438  if ('/' == path[slen - 1])
439  sprintf (ret,
440  "%s%s",
441  path,
442  fname);
443  else
444  sprintf (ret,
445  "%s/%s",
446  path,
447  fname);
448 #endif
449  return ret;
450 }
451 
452 
453 /**
454  * Iterate over all paths where we expect to find GNU libextractor
455  * plugins.
456  *
457  * @param pp function to call for each path
458  * @param pp_cls cls argument for pp.
459  */
460 static void
462  void *pp_cls)
463 {
464  const char *p;
465  char *path;
466  char *prefix;
467  char *d;
468  char *saveptr;
469 
470  prefix = NULL;
471  if (NULL != (p = getenv ("LIBEXTRACTOR_PREFIX")))
472  {
473  if (NULL == (d = strdup (p)))
474  {
475  LOG_STRERROR ("strdup");
476  return;
477  }
478  for (prefix = strtok_r (d, ":", &saveptr);
479  NULL != prefix;
480  prefix = strtok_r (NULL, ":", &saveptr))
481  pp (pp_cls, prefix);
482  free (d);
483  return;
484  }
485 #if GNU_LINUX
486  if (NULL == prefix)
487  prefix = get_path_from_proc_exe ();
488 #endif
489 #if WINDOWS
490  if (NULL == prefix)
491  prefix = get_path_from_module_filename ();
492 #endif
493 #if DARWIN
494  if (NULL == prefix)
495  prefix = get_path_from_NSGetExecutablePath ();
496  if (NULL == prefix)
497  prefix = get_path_from_dyld_image ();
498 #endif
499  if (NULL == prefix)
500  prefix = get_path_from_PATH ();
501  pp (pp_cls, PLUGININSTDIR);
502  if (NULL == prefix)
503  return;
504  path = append_to_dir (prefix, PLUGINDIR);
505  if (NULL != path)
506  {
507  if (0 != strcmp (path,
508  PLUGININSTDIR))
509  pp (pp_cls, path);
510  free (path);
511  }
512  free (prefix);
513 }
514 
515 
516 /**
517  * Closure for #find_plugin_in_path().
518  */
520 {
521  /**
522  * Name of the plugin we are looking for.
523  */
524  const char *short_name;
525 
526  /**
527  * Location for storing the path to the plugin upon success.
528  */
529  char *path;
530 };
531 
532 
533 /**
534  * Load all plugins from the given directory.
535  *
536  * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
537  * @param path path to a directory with plugins
538  */
539 static void
541  const char *path)
542 {
543  struct SearchContext *sc = cls;
544  DIR *dir;
545  struct dirent *ent;
546  const char *sym_name;
547  char *sym;
548  char *dot;
549  size_t dlen;
550 
551  if (NULL != sc->path)
552  return;
553  if (NULL == (dir = opendir (path)))
554  return;
555  while (NULL != (ent = readdir (dir)))
556  {
557  if ('.' == ent->d_name[0])
558  continue;
559  dlen = strlen (ent->d_name);
560  if ( (dlen < 4) ||
561  ( (0 != strcmp (&ent->d_name[dlen - 3], ".so")) &&
562  (0 != strcasecmp (&ent->d_name[dlen - 4], ".dll")) ) )
563  continue; /* only load '.so' and '.dll' */
564  if (NULL == (sym_name = strrchr (ent->d_name, '_')))
565  continue;
566  sym_name++;
567  if (NULL == (sym = strdup (sym_name)))
568  {
569  LOG_STRERROR ("strdup");
570  closedir (dir);
571  return;
572  }
573  dot = strchr (sym, '.');
574  if (NULL != dot)
575  *dot = '\0';
576  if (0 == strcmp (sym, sc->short_name))
577  {
578  sc->path = append_to_dir (path, ent->d_name);
579  free (sym);
580  break;
581  }
582  free (sym);
583  }
584  closedir (dir);
585 }
586 
587 
588 /**
589  * Given a short name of a library (i.e. "mime"), find
590  * the full path of the respective plugin.
591  */
592 char *
593 EXTRACTOR_find_plugin_ (const char *short_name)
594 {
595  struct SearchContext sc;
596 
597  sc.path = NULL;
598  sc.short_name = short_name;
600  &sc);
601  return sc.path;
602 }
603 
604 
605 /**
606  * Closure for #load_plugins_from_dir().
607  */
609 {
610  /**
611  * Accumulated result list.
612  */
614 
615  /**
616  * Flags to use for all plugins.
617  */
619 };
620 
621 
622 /**
623  * Load all plugins from the given directory.
624  *
625  * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
626  * @param path path to a directory with plugins
627  */
628 static void
630  const char *path)
631 {
632  struct DefaultLoaderContext *dlc = cls;
633  DIR *dir;
634  struct dirent *ent;
635  const char *sym_name;
636  char *sym;
637  char *dot;
638  size_t dlen;
639 
640  if (NULL == (dir = opendir (path)))
641  return;
642  while (NULL != (ent = readdir (dir)))
643  {
644  if (ent->d_name[0] == '.')
645  continue;
646  dlen = strlen (ent->d_name);
647  if ( (dlen < 4) ||
648  ( (0 != strcmp (&ent->d_name[dlen - 3], ".so")) &&
649  (0 != strcasecmp (&ent->d_name[dlen - 4], ".dll")) ) )
650  continue; /* only load '.so' and '.dll' */
651  if (NULL == (sym_name = strrchr (ent->d_name, '_')))
652  continue;
653  sym_name++;
654  if (NULL == (sym = strdup (sym_name)))
655  {
656  LOG_STRERROR ("strdup");
657  closedir (dir);
658  return;
659  }
660  if (NULL != (dot = strchr (sym, '.')))
661  *dot = '\0';
662  dlc->res = EXTRACTOR_plugin_add (dlc->res,
663  sym,
664  NULL,
665  dlc->flags);
666  free (sym);
667  }
668  closedir (dir);
669 }
670 
671 
672 /**
673  * Load the default set of plugins. The default can be changed
674  * by setting the LIBEXTRACTOR_LIBRARIES environment variable.
675  * If it is set to "env", then this function will return
676  * #EXTRACTOR_plugin_add_config(NULL, env, flags). Otherwise,
677  * it will load all of the installed plugins and return them.
678  *
679  * @param flags options for all of the plugins loaded
680  * @return the default set of plugins, NULL if no plugins were found
681  */
682 struct EXTRACTOR_PluginList *
684 {
685  struct DefaultLoaderContext dlc;
686  char *env;
687 
688  env = getenv ("LIBEXTRACTOR_LIBRARIES");
689  if (NULL != env)
690  return EXTRACTOR_plugin_add_config (NULL, env, flags);
691  dlc.res = NULL;
692  dlc.flags = flags;
694  &dlc);
695  return dlc.res;
696 }
697 
698 
699 /* end of extractor_plugpath.c */
EXTRACTOR_Options
Definition: extractor.h:57
struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_config(struct EXTRACTOR_PluginList *prev, const char *config, enum EXTRACTOR_Options flags)
struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add(struct EXTRACTOR_PluginList *prev, const char *library, const char *options, enum EXTRACTOR_Options flags)
logging API for GNU libextractor
#define LOG_STRERROR(syscall)
struct EXTRACTOR_PluginList * EXTRACTOR_plugin_add_defaults(enum EXTRACTOR_Options flags)
void(* EXTRACTOR_PathProcessor)(void *cls, const char *path)
static void get_installation_paths(EXTRACTOR_PathProcessor pp, void *pp_cls)
static char * append_to_dir(const char *path, const char *fname)
char * EXTRACTOR_find_plugin_(const char *short_name)
static char * cut_bin(char *in)
static char * get_path_from_PATH()
static void find_plugin_in_path(void *cls, const char *path)
static void load_plugins_from_dir(void *cls, const char *path)
determine path where plugins are installed
#define NULL
Definition: getopt1.c:60
char * getenv()
plaform specifics
enum EXTRACTOR_Options flags
struct EXTRACTOR_PluginList * res
enum EXTRACTOR_Options flags
const char * short_name