aboutsummaryrefslogtreecommitdiff
path: root/src/main/extractor_plugpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/extractor_plugpath.c')
-rw-r--r--src/main/extractor_plugpath.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/src/main/extractor_plugpath.c b/src/main/extractor_plugpath.c
new file mode 100644
index 0000000..1cc5858
--- /dev/null
+++ b/src/main/extractor_plugpath.c
@@ -0,0 +1,520 @@
1/*
2 This file is part of libextractor.
3 (C) 2002, 2003, 2004, 2005, 2006, 2009 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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21#include "platform.h"
22#include "plibc.h"
23#include "extractor.h"
24#include <dirent.h>
25#include <sys/types.h>
26#ifndef WINDOWS
27#include <sys/wait.h>
28#include <sys/shm.h>
29#endif
30#include <signal.h>
31#include <ltdl.h>
32
33#include "extractor_plugpath.h"
34
35/**
36 * Remove a trailing '/bin' from in (if present).
37 */
38static char *
39cut_bin(char * in) {
40 size_t p;
41
42 if (in == NULL)
43 return NULL;
44 p = strlen(in);
45 if (p > 4) {
46 if ( (in[p-1] == '/') ||
47 (in[p-1] == '\\') )
48 in[--p] = '\0';
49 if (0 == strcmp(&in[p-3],
50 "bin")) {
51 in[p-3] = '\0';
52 p -= 3;
53 }
54 }
55 return in;
56}
57
58#if LINUX
59/**
60 * Try to determine path by reading /proc/PID/exe or
61 * /proc/PID/maps.
62 *
63 * Note that this may fail if LE is installed in one directory
64 * and the binary linking against it sits elsewhere.
65 */
66static char *
67get_path_from_proc_exe() {
68 char fn[64];
69 char line[1024];
70 char dir[1024];
71 char * lnk;
72 char * ret;
73 char * lestr;
74 ssize_t size;
75 FILE * f;
76
77 snprintf(fn,
78 sizeof (fn),
79 "/proc/%u/maps",
80 getpid());
81 f = FOPEN(fn, "r");
82 if (f != NULL) {
83 while (NULL != fgets(line, 1024, f)) {
84 if ( (1 == sscanf(line,
85 "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%s",
86 dir)) &&
87 (NULL != (lestr = strstr(dir,
88 "libextractor")) ) ) {
89 lestr[0] = '\0';
90 fclose(f);
91 return strdup(dir);
92 }
93 }
94 fclose(f);
95 }
96 snprintf(fn,
97 sizeof (fn),
98 "/proc/%u/exe",
99 getpid());
100 lnk = malloc(1029); /* 1024 + 5 for "lib/" catenation */
101 if (lnk == NULL)
102 return NULL;
103 size = readlink(fn, lnk, 1023);
104 if ( (size <= 0) || (size >= 1024) ) {
105 free(lnk);
106 return NULL;
107 }
108 lnk[size] = '\0';
109 while ( (lnk[size] != '/') &&
110 (size > 0) )
111 size--;
112 if ( (size < 4) ||
113 (lnk[size-4] != '/') ) {
114 /* not installed in "/bin/" -- binary path probably useless */
115 free(lnk);
116 return NULL;
117 }
118 lnk[size] = '\0';
119 lnk = cut_bin(lnk);
120 ret = realloc(lnk, strlen(lnk) + 5);
121 if (ret == NULL)
122 {
123 free (lnk);
124 return NULL;
125 }
126 strcat(ret, "lib/"); /* guess "lib/" as the library dir */
127 return ret;
128}
129#endif
130
131#if WINDOWS
132/**
133 * Try to determine path with win32-specific function
134 */
135static char *
136get_path_from_module_filename() {
137 char * path;
138 char * ret;
139 char * idx;
140
141 path = malloc(4103); /* 4096+nil+6 for "/lib/" catenation */
142 if (path == NULL)
143 return NULL;
144 GetModuleFileName(NULL, path, 4096);
145 idx = path + strlen(path);
146 while ( (idx > path) &&
147 (*idx != '\\') &&
148 (*idx != '/') )
149 idx--;
150 *idx = '\0';
151 path = cut_bin(path);
152 ret = realloc(path, strlen(path) + 6);
153 if (ret == NULL)
154 {
155 free (path);
156 return NULL;
157 }
158 strcat(ret, "/lib/"); /* guess "lib/" as the library dir */
159 return ret;
160}
161#endif
162
163#if DARWIN
164static char * get_path_from_dyld_image() {
165 const char * path;
166 char * p, * s;
167 int i;
168 int c;
169
170 p = NULL;
171 c = _dyld_image_count();
172 for (i = 0; i < c; i++) {
173 if (_dyld_get_image_header(i) == &_mh_dylib_header) {
174 path = _dyld_get_image_name(i);
175 if (path != NULL && strlen(path) > 0) {
176 p = strdup(path);
177 if (p == NULL)
178 return NULL;
179 s = p + strlen(p);
180 while ( (s > p) && (*s != '/') )
181 s--;
182 s++;
183 *s = '\0';
184 }
185 break;
186 }
187 }
188 return p;
189}
190#endif
191
192/**
193 * This may also fail -- for example, if extract
194 * is not also installed.
195 */
196static char *
197get_path_from_PATH() {
198 struct stat sbuf;
199 char * path;
200 char * pos;
201 char * end;
202 char * buf;
203 char * ret;
204 const char * p;
205
206 p = getenv("PATH");
207 if (p == NULL)
208 return NULL;
209 path = strdup(p); /* because we write on it */
210 if (path == NULL)
211 return NULL;
212 buf = malloc(strlen(path) + 20);
213 if (buf == NULL)
214 {
215 free (path);
216 return NULL;
217 }
218 pos = path;
219
220 while (NULL != (end = strchr(pos, ':'))) {
221 *end = '\0';
222 sprintf(buf, "%s/%s", pos, "extract");
223 if (0 == stat(buf, &sbuf)) {
224 pos = strdup(pos);
225 free(buf);
226 free(path);
227 if (pos == NULL)
228 return NULL;
229 pos = cut_bin(pos);
230 ret = realloc(pos, strlen(pos) + 5);
231 if (ret == NULL)
232 {
233 free (pos);
234 return NULL;
235 }
236 strcat(ret, "lib/");
237 return ret;
238 }
239 pos = end + 1;
240 }
241 sprintf(buf, "%s/%s", pos, "extract");
242 if (0 == stat(buf, &sbuf)) {
243 pos = strdup(pos);
244 free(buf);
245 free(path);
246 if (pos == NULL)
247 return NULL;
248 pos = cut_bin(pos);
249 ret = realloc(pos, strlen(pos) + 5);
250 if (ret == NULL)
251 {
252 free (pos);
253 return NULL;
254 }
255 strcat(ret, "lib/");
256 return ret;
257 }
258 free(buf);
259 free(path);
260 return NULL;
261}
262
263/**
264 * Create a filename by appending 'fname' to 'path'.
265 *
266 * @param path the base path
267 * @param fname the filename to append
268 * @return '$path/$fname'
269 */
270static char *
271append_to_dir (const char *path,
272 const char *fname)
273{
274 char *ret;
275 size_t slen;
276
277 slen = strlen (path);
278 if (slen == 0)
279 return NULL;
280 if (fname[0] == DIR_SEPARATOR)
281 fname++;
282 ret = malloc (slen + strlen(fname) + 2);
283 if (ret == NULL)
284 return NULL;
285#ifdef MINGW
286 if (path[slen-1] == '\\')
287 sprintf (ret,
288 "%s%s",
289 path,
290 fname);
291 else
292 sprintf (ret,
293 "%s\\%s",
294 path,
295 fname);
296#else
297 if (path[slen-1] == '/')
298 sprintf (ret,
299 "%s%s",
300 path,
301 fname);
302 else
303 sprintf (ret,
304 "%s/%s",
305 path,
306 fname);
307#endif
308 return ret;
309}
310
311
312/**
313 * Iterate over all paths where we expect to find GNU libextractor
314 * plugins.
315 *
316 * @param pp function to call for each path
317 * @param pp_cls cls argument for pp.
318 */
319void
320get_installation_paths (PathProcessor pp,
321 void *pp_cls)
322{
323 const char *p;
324 char * path;
325 char * prefix;
326 char * d;
327
328 prefix = NULL;
329 p = getenv("LIBEXTRACTOR_PREFIX");
330 if (p != NULL)
331 {
332 d = strdup (p);
333 if (d == NULL)
334 return;
335 prefix = strtok (d, PATH_SEPARATOR_STR);
336 while (NULL != prefix)
337 {
338 pp (pp_cls, prefix);
339 prefix = strtok (NULL, PATH_SEPARATOR_STR);
340 }
341 free (d);
342 return;
343 }
344#if LINUX
345 if (prefix == NULL)
346 prefix = get_path_from_proc_exe();
347#endif
348#if WINDOWS
349 if (prefix == NULL)
350 prefix = get_path_from_module_filename();
351#endif
352#if DARWIN
353 if (prefix == NULL)
354 prefix = get_path_from_dyld_image();
355#endif
356 if (prefix == NULL)
357 prefix = get_path_from_PATH();
358 pp (pp_cls, PLUGININSTDIR);
359 if (prefix == NULL)
360 return;
361 path = append_to_dir (prefix, PLUGINDIR);
362 if (path != NULL)
363 {
364 if (0 != strcmp (path,
365 PLUGININSTDIR))
366 pp (pp_cls, path);
367 free (path);
368 }
369 free (prefix);
370}
371
372
373struct SearchContext
374{
375 const char *short_name;
376 char *path;
377};
378
379
380/**
381 * Load all plugins from the given directory.
382 *
383 * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
384 * @param path path to a directory with plugins
385 */
386static void
387find_plugin_in_path (void *cls,
388 const char *path)
389{
390 struct SearchContext *sc = cls;
391 DIR *dir;
392 struct dirent *ent;
393 const char *la;
394 const char *sym_name;
395 char *sym;
396 char *dot;
397
398 if (sc->path != NULL)
399 return;
400 dir = OPENDIR (path);
401 if (NULL == dir)
402 return;
403 while (NULL != (ent = READDIR (dir)))
404 {
405 if (ent->d_name[0] == '.')
406 continue;
407 if ( (NULL != (la = strstr (ent->d_name, ".la"))) &&
408 (la[3] == '\0') )
409 continue; /* only load '.so' and '.dll' */
410 sym_name = strstr (ent->d_name, "_");
411 if (sym_name == NULL)
412 continue;
413 sym_name++;
414 sym = strdup (sym_name);
415 if (sym == NULL)
416 {
417 CLOSEDIR (dir);
418 return;
419 }
420 dot = strstr (sym, ".");
421 if (dot != NULL)
422 *dot = '\0';
423 if (0 == strcmp (sym, sc->short_name))
424 {
425 sc->path = append_to_dir (path, ent->d_name);
426 free (sym);
427 break;
428 }
429 free (sym);
430 }
431#if DEBUG
432 if (sc->path == NULL)
433 fprintf (stderr,
434 "Failed to find plugin `%s' in `%s'\n",
435 sc->short_name,
436 path);
437#endif
438 CLOSEDIR (dir);
439}
440
441
442
443/**
444 * Given a short name of a library (i.e. "mime"), find
445 * the full path of the respective plugin.
446 */
447char *
448find_plugin (const char *short_name)
449{
450 struct SearchContext sc;
451
452 sc.path = NULL;
453 sc.short_name = short_name;
454 get_installation_paths (&find_plugin_in_path,
455 &sc);
456 return sc.path;
457}
458
459
460
461
462
463/**
464 * Load all plugins from the given directory.
465 *
466 * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
467 * @param path path to a directory with plugins
468 */
469void
470load_plugins_from_dir (void *cls,
471 const char *path)
472{
473 struct DefaultLoaderContext *dlc = cls;
474 DIR *dir;
475 struct dirent *ent;
476 const char *la;
477 const char *sym_name;
478 char *sym;
479 char *dot;
480
481 dir = opendir (path);
482 if (NULL == dir)
483 return;
484 while (NULL != (ent = readdir (dir)))
485 {
486 if (ent->d_name[0] == '.')
487 continue;
488 if ( ( (NULL != (la = strstr (ent->d_name, ".la"))) &&
489 (la[3] == '\0') ) ||
490 ( (NULL != (la = strstr (ent->d_name, ".a"))) &&
491 (la[2] == '\0')) )
492 continue; /* only load '.so' and '.dll' */
493
494 sym_name = strstr (ent->d_name, "_");
495 if (sym_name == NULL)
496 continue;
497 sym_name++;
498 sym = strdup (sym_name);
499 if (NULL == sym)
500 {
501 closedir (dir);
502 return;
503 }
504 dot = strstr (sym, ".");
505 if (dot != NULL)
506 *dot = '\0';
507#if DEBUG > 1
508 fprintf (stderr,
509 "Adding default plugin `%s'\n",
510 sym);
511#endif
512 dlc->res = EXTRACTOR_plugin_add (dlc->res,
513 sym,
514 NULL,
515 dlc->flags);
516 free (sym);
517 }
518 closedir (dir);
519}
520