diff options
Diffstat (limited to 'src/main/extractor_plugpath.c')
-rw-r--r-- | src/main/extractor_plugpath.c | 520 |
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 | */ | ||
38 | static char * | ||
39 | cut_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 | */ | ||
66 | static char * | ||
67 | get_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 | */ | ||
135 | static char * | ||
136 | get_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 | ||
164 | static 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 | */ | ||
196 | static char * | ||
197 | get_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 | */ | ||
270 | static char * | ||
271 | append_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 | */ | ||
319 | void | ||
320 | get_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 | |||
373 | struct 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 | */ | ||
386 | static void | ||
387 | find_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 | */ | ||
447 | char * | ||
448 | find_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 | */ | ||
469 | void | ||
470 | load_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 | |||