diff options
-rw-r--r-- | src/main/extractor_plugins.c | 350 | ||||
-rw-r--r-- | src/main/extractor_plugins.h | 118 | ||||
-rw-r--r-- | src/main/extractor_plugpath.c | 520 | ||||
-rw-r--r-- | src/main/extractor_plugpath.h | 47 |
4 files changed, 1035 insertions, 0 deletions
diff --git a/src/main/extractor_plugins.c b/src/main/extractor_plugins.c new file mode 100644 index 0000000..026e86b --- /dev/null +++ b/src/main/extractor_plugins.c | |||
@@ -0,0 +1,350 @@ | |||
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 "extractor_plugins.h" | ||
22 | #include "extractor_plugpath.h" | ||
23 | |||
24 | |||
25 | /** | ||
26 | * Load the default set of plugins. The default can be changed | ||
27 | * by setting the LIBEXTRACTOR_LIBRARIES environment variable. | ||
28 | * If it is set to "env", then this function will return | ||
29 | * EXTRACTOR_plugin_add_config (NULL, env, flags). Otherwise, | ||
30 | * it will load all of the installed plugins and return them. | ||
31 | * | ||
32 | * @param flags options for all of the plugins loaded | ||
33 | * @return the default set of plugins, NULL if no plugins were found | ||
34 | */ | ||
35 | struct EXTRACTOR_PluginList * | ||
36 | EXTRACTOR_plugin_add_defaults(enum EXTRACTOR_Options flags) | ||
37 | { | ||
38 | struct DefaultLoaderContext dlc; | ||
39 | char *env; | ||
40 | |||
41 | env = getenv ("LIBEXTRACTOR_LIBRARIES"); | ||
42 | if (env != NULL) | ||
43 | return EXTRACTOR_plugin_add_config (NULL, env, flags); | ||
44 | dlc.res = NULL; | ||
45 | dlc.flags = flags; | ||
46 | get_installation_paths (&load_plugins_from_dir, | ||
47 | &dlc); | ||
48 | return dlc.res; | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Try to resolve a plugin function. | ||
53 | * | ||
54 | * @param lib_handle library to search for the symbol | ||
55 | * @param prefix prefix to add | ||
56 | * @param sym_name base name for the symbol | ||
57 | * @param options set to special options requested by the plugin | ||
58 | * @return NULL on error, otherwise pointer to the symbol | ||
59 | */ | ||
60 | static void * | ||
61 | get_symbol_with_prefix(void *lib_handle, | ||
62 | const char *template, | ||
63 | const char *prefix, | ||
64 | const char **options) | ||
65 | { | ||
66 | char *name; | ||
67 | void *symbol; | ||
68 | const char *sym_name; | ||
69 | char *sym; | ||
70 | char *dot; | ||
71 | const char *(*opt_fun)(void); | ||
72 | |||
73 | if (NULL != options) *options = NULL; | ||
74 | sym_name = strstr (prefix, "_"); | ||
75 | if (sym_name == NULL) | ||
76 | return NULL; | ||
77 | sym_name++; | ||
78 | sym = strdup (sym_name); | ||
79 | if (sym == NULL) | ||
80 | return NULL; | ||
81 | dot = strstr (sym, "."); | ||
82 | if (dot != NULL) | ||
83 | *dot = '\0'; | ||
84 | name = malloc(strlen(sym) + strlen(template) + 1); | ||
85 | if (name == NULL) | ||
86 | { | ||
87 | free (sym); | ||
88 | return NULL; | ||
89 | } | ||
90 | sprintf(name, | ||
91 | template, | ||
92 | sym); | ||
93 | /* try without '_' first */ | ||
94 | symbol = lt_dlsym(lib_handle, name + 1); | ||
95 | if (symbol==NULL) | ||
96 | { | ||
97 | /* now try with the '_' */ | ||
98 | #if DEBUG | ||
99 | char *first_error = strdup (lt_dlerror()); | ||
100 | #endif | ||
101 | symbol = lt_dlsym(lib_handle, name); | ||
102 | #if DEBUG | ||
103 | if (NULL == symbol) | ||
104 | { | ||
105 | fprintf(stderr, | ||
106 | "Resolving symbol `%s' failed, " | ||
107 | "so I tried `%s', but that failed also. Errors are: " | ||
108 | "`%s' and `%s'.\n", | ||
109 | name+1, | ||
110 | name, | ||
111 | first_error == NULL ? "out of memory" : first_error, | ||
112 | lt_dlerror()); | ||
113 | } | ||
114 | if (first_error != NULL) | ||
115 | free(first_error); | ||
116 | #endif | ||
117 | } | ||
118 | |||
119 | if ( (symbol != NULL) && | ||
120 | (NULL != options) ) | ||
121 | { | ||
122 | /* get special options */ | ||
123 | sprintf(name, | ||
124 | "_EXTRACTOR_%s_options", | ||
125 | sym); | ||
126 | /* try without '_' first */ | ||
127 | opt_fun = lt_dlsym(lib_handle, name + 1); | ||
128 | if (opt_fun == NULL) | ||
129 | opt_fun = lt_dlsym(lib_handle, name); | ||
130 | if (opt_fun != NULL) | ||
131 | *options = opt_fun (); | ||
132 | } | ||
133 | free (sym); | ||
134 | free(name); | ||
135 | |||
136 | return symbol; | ||
137 | } | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Load a plugin. | ||
142 | * | ||
143 | * @param plugin plugin to load | ||
144 | * @return 0 on success, -1 on error | ||
145 | */ | ||
146 | int | ||
147 | plugin_load (struct EXTRACTOR_PluginList *plugin) | ||
148 | { | ||
149 | #if WINDOWS | ||
150 | wchar_t wlibname[4097]; | ||
151 | char llibname[4097]; | ||
152 | #endif | ||
153 | lt_dladvise advise; | ||
154 | |||
155 | if (plugin->libname == NULL) | ||
156 | plugin->libname = find_plugin (plugin->short_libname); | ||
157 | if (plugin->libname == NULL) | ||
158 | { | ||
159 | #if DEBUG | ||
160 | fprintf (stderr, | ||
161 | "Failed to find plugin `%s'\n", | ||
162 | plugin->short_libname); | ||
163 | #endif | ||
164 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
165 | return -1; | ||
166 | } | ||
167 | lt_dladvise_init (&advise); | ||
168 | lt_dladvise_ext (&advise); | ||
169 | lt_dladvise_local (&advise); | ||
170 | #if WINDOWS | ||
171 | wlibname[0] = L'\0'; | ||
172 | llibname[0] = '\0'; | ||
173 | if (MultiByteToWideChar (CP_UTF8, 0, plugin->libname, -1, wlibname, 4097) <= 0 | ||
174 | || WideCharToMultiByte (CP_ACP, 0, wlibname, -1, llibname, 4097, NULL, NULL) < 0) | ||
175 | { | ||
176 | #if DEBUG | ||
177 | fprintf (stderr, | ||
178 | "Loading `%s' plugin failed: %s\n", | ||
179 | plugin->short_libname, | ||
180 | "can't convert plugin name to local encoding"); | ||
181 | free (plugin->libname); | ||
182 | plugin->libname = NULL; | ||
183 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
184 | return -1; | ||
185 | #endif | ||
186 | } | ||
187 | plugin->libraryHandle = lt_dlopenadvise (llibname, | ||
188 | advise); | ||
189 | #else | ||
190 | plugin->libraryHandle = lt_dlopenadvise (plugin->libname, | ||
191 | advise); | ||
192 | #endif | ||
193 | lt_dladvise_destroy(&advise); | ||
194 | if (plugin->libraryHandle == NULL) | ||
195 | { | ||
196 | #if DEBUG | ||
197 | fprintf (stderr, | ||
198 | "Loading `%s' plugin failed: %s\n", | ||
199 | plugin->short_libname, | ||
200 | lt_dlerror ()); | ||
201 | #endif | ||
202 | free (plugin->libname); | ||
203 | plugin->libname = NULL; | ||
204 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
205 | return -1; | ||
206 | } | ||
207 | plugin->extractMethod = get_symbol_with_prefix (plugin->libraryHandle, | ||
208 | "_EXTRACTOR_%s_extract", | ||
209 | plugin->libname, | ||
210 | &plugin->specials); | ||
211 | if (plugin->extractMethod == NULL) | ||
212 | { | ||
213 | #if DEBUG | ||
214 | fprintf (stderr, | ||
215 | "Resolving `extract' method of plugin `%s' failed: %s\n", | ||
216 | plugin->short_libname, | ||
217 | lt_dlerror ()); | ||
218 | #endif | ||
219 | lt_dlclose (plugin->libraryHandle); | ||
220 | free (plugin->libname); | ||
221 | plugin->libname = NULL; | ||
222 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
223 | return -1; | ||
224 | } | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | |||
229 | |||
230 | |||
231 | /** | ||
232 | * Add a library for keyword extraction. | ||
233 | * | ||
234 | * @param prev the previous list of libraries, may be NULL | ||
235 | * @param library the name of the library | ||
236 | * @param flags options to use | ||
237 | * @return the new list of libraries, equal to prev iff an error occured | ||
238 | */ | ||
239 | struct EXTRACTOR_PluginList * | ||
240 | EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList * prev, | ||
241 | const char *library, | ||
242 | const char *options, | ||
243 | enum EXTRACTOR_Options flags) | ||
244 | { | ||
245 | struct EXTRACTOR_PluginList *result; | ||
246 | char *libname; | ||
247 | |||
248 | libname = find_plugin (library); | ||
249 | if (libname == NULL) | ||
250 | { | ||
251 | fprintf (stderr, | ||
252 | "Could not load `%s'\n", | ||
253 | library); | ||
254 | return prev; | ||
255 | } | ||
256 | result = calloc (1, sizeof (struct EXTRACTOR_PluginList)); | ||
257 | if (result == NULL) | ||
258 | return prev; | ||
259 | result->next = prev; | ||
260 | result->short_libname = strdup (library); | ||
261 | if (result->short_libname == NULL) | ||
262 | { | ||
263 | free (result); | ||
264 | return NULL; | ||
265 | } | ||
266 | result->libname = libname; | ||
267 | result->flags = flags; | ||
268 | if (NULL != options) | ||
269 | result->plugin_options = strdup (options); | ||
270 | else | ||
271 | result->plugin_options = NULL; | ||
272 | return result; | ||
273 | } | ||
274 | |||
275 | |||
276 | /** | ||
277 | * Load multiple libraries as specified by the user. | ||
278 | * | ||
279 | * @param config a string given by the user that defines which | ||
280 | * libraries should be loaded. Has the format | ||
281 | * "[[-]LIBRARYNAME[(options)][:[-]LIBRARYNAME[(options)]]]*". | ||
282 | * For example, 'mp3:ogg.so' loads the | ||
283 | * mp3 and the ogg library. The '-' before the LIBRARYNAME | ||
284 | * indicates that the library should be removed from | ||
285 | * the library list. | ||
286 | * @param prev the previous list of libraries, may be NULL | ||
287 | * @param flags options to use | ||
288 | * @return the new list of libraries, equal to prev iff an error occured | ||
289 | * or if config was empty (or NULL). | ||
290 | */ | ||
291 | struct EXTRACTOR_PluginList * | ||
292 | EXTRACTOR_plugin_add_config (struct EXTRACTOR_PluginList * prev, | ||
293 | const char *config, | ||
294 | enum EXTRACTOR_Options flags) | ||
295 | { | ||
296 | char *cpy; | ||
297 | size_t pos; | ||
298 | size_t last; | ||
299 | ssize_t lastconf; | ||
300 | size_t len; | ||
301 | |||
302 | if (config == NULL) | ||
303 | return prev; | ||
304 | len = strlen(config); | ||
305 | cpy = strdup(config); | ||
306 | if (cpy == NULL) | ||
307 | return prev; | ||
308 | pos = 0; | ||
309 | last = 0; | ||
310 | lastconf = 0; | ||
311 | while (pos < len) | ||
312 | { | ||
313 | while ((cpy[pos] != ':') && (cpy[pos] != '\0') && | ||
314 | (cpy[pos] != '(')) | ||
315 | pos++; | ||
316 | if( cpy[pos] == '(' ) { | ||
317 | cpy[pos++] = '\0'; /* replace '(' by termination */ | ||
318 | lastconf = pos; /* start config from here, after (. */ | ||
319 | while ((cpy[pos] != '\0') && (cpy[pos] != ')')) | ||
320 | pos++; /* config until ) or EOS. */ | ||
321 | if( cpy[pos] == ')' ) { | ||
322 | cpy[pos++] = '\0'; /* write end of config here. */ | ||
323 | while ((cpy[pos] != ':') && (cpy[pos] != '\0')) | ||
324 | pos++; /* forward until real end of string found. */ | ||
325 | cpy[pos++] = '\0'; | ||
326 | } else { | ||
327 | cpy[pos++] = '\0'; /* end of string. */ | ||
328 | } | ||
329 | } else { | ||
330 | lastconf = -1; /* NULL config when no (). */ | ||
331 | cpy[pos++] = '\0'; /* replace ':' by termination */ | ||
332 | } | ||
333 | if (cpy[last] == '-') | ||
334 | { | ||
335 | last++; | ||
336 | prev = EXTRACTOR_plugin_remove (prev, | ||
337 | &cpy[last]); | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | prev = EXTRACTOR_plugin_add (prev, | ||
342 | &cpy[last], | ||
343 | (lastconf != -1) ? &cpy[lastconf] : NULL, | ||
344 | flags); | ||
345 | } | ||
346 | last = pos; | ||
347 | } | ||
348 | free (cpy); | ||
349 | return prev; | ||
350 | } | ||
diff --git a/src/main/extractor_plugins.h b/src/main/extractor_plugins.h new file mode 100644 index 0000000..ea0eabb --- /dev/null +++ b/src/main/extractor_plugins.h | |||
@@ -0,0 +1,118 @@ | |||
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 | #if !defined (EXTRACTOR_PLUGINS_H) | ||
22 | #define EXTRACTOR_PLUGINS_H | ||
23 | |||
24 | #include "platform.h" | ||
25 | #include "plibc.h" | ||
26 | #include "extractor.h" | ||
27 | //#include <dirent.h> | ||
28 | //#include <sys/types.h> | ||
29 | #ifndef WINDOWS | ||
30 | #include <sys/wait.h> | ||
31 | #include <sys/shm.h> | ||
32 | #endif | ||
33 | #include <signal.h> | ||
34 | #include <ltdl.h> | ||
35 | |||
36 | /** | ||
37 | * Linked list of extractor plugins. An application builds this list | ||
38 | * by telling libextractor to load various keyword-extraction | ||
39 | * plugins. Libraries can also be unloaded (removed from this list, | ||
40 | * see EXTRACTOR_plugin_remove). | ||
41 | */ | ||
42 | struct EXTRACTOR_PluginList | ||
43 | { | ||
44 | /** | ||
45 | * This is a linked list. | ||
46 | */ | ||
47 | struct EXTRACTOR_PluginList *next; | ||
48 | |||
49 | /** | ||
50 | * Pointer to the plugin (as returned by lt_dlopen). | ||
51 | */ | ||
52 | void * libraryHandle; | ||
53 | |||
54 | /** | ||
55 | * Name of the library (i.e., 'libextractor_foo.so') | ||
56 | */ | ||
57 | char *libname; | ||
58 | |||
59 | /** | ||
60 | * Name of the library (i.e., 'libextractor_foo.so') | ||
61 | */ | ||
62 | char *short_libname; | ||
63 | |||
64 | /** | ||
65 | * Pointer to the function used for meta data extraction. | ||
66 | */ | ||
67 | EXTRACTOR_ExtractMethod extractMethod; | ||
68 | |||
69 | /** | ||
70 | * Options for the plugin. | ||
71 | */ | ||
72 | char * plugin_options; | ||
73 | |||
74 | /** | ||
75 | * Special options for the plugin | ||
76 | * (as returned by the plugin's "options" method; | ||
77 | * typically NULL). | ||
78 | */ | ||
79 | const char *specials; | ||
80 | |||
81 | /** | ||
82 | * Flags to control how the plugin is executed. | ||
83 | */ | ||
84 | enum EXTRACTOR_Options flags; | ||
85 | |||
86 | /** | ||
87 | * Process ID of the child process for this plugin. 0 for | ||
88 | * none. | ||
89 | */ | ||
90 | #ifndef WINDOWS | ||
91 | int cpid; | ||
92 | #else | ||
93 | HANDLE hProcess; | ||
94 | #endif | ||
95 | |||
96 | /** | ||
97 | * Pipe used to send information about shared memory segments to | ||
98 | * the child process. NULL if not initialized. | ||
99 | */ | ||
100 | FILE *cpipe_in; | ||
101 | |||
102 | /** | ||
103 | * Pipe used to read information about extracted meta data from | ||
104 | * the child process. -1 if not initialized. | ||
105 | */ | ||
106 | int cpipe_out; | ||
107 | }; | ||
108 | |||
109 | /** | ||
110 | * Load a plugin. | ||
111 | * | ||
112 | * @param plugin plugin to load | ||
113 | * @return 0 on success, -1 on error | ||
114 | */ | ||
115 | int | ||
116 | plugin_load (struct EXTRACTOR_PluginList *plugin); | ||
117 | |||
118 | #endif /* EXTRACTOR_PLUGINS_H */ | ||
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 | |||
diff --git a/src/main/extractor_plugpath.h b/src/main/extractor_plugpath.h new file mode 100644 index 0000000..33bc29f --- /dev/null +++ b/src/main/extractor_plugpath.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #if !defined(EXTRACTOR_PLUGPATH_H) | ||
2 | #define EXTRACTOR_PLUGPATH_H | ||
3 | |||
4 | struct DefaultLoaderContext | ||
5 | { | ||
6 | struct EXTRACTOR_PluginList *res; | ||
7 | enum EXTRACTOR_Options flags; | ||
8 | }; | ||
9 | |||
10 | /** | ||
11 | * Function to call on paths. | ||
12 | * | ||
13 | * @param cls closure | ||
14 | * @param path a directory path | ||
15 | */ | ||
16 | typedef void (*PathProcessor)(void *cls, | ||
17 | const char *path); | ||
18 | |||
19 | /** | ||
20 | * Iterate over all paths where we expect to find GNU libextractor | ||
21 | * plugins. | ||
22 | * | ||
23 | * @param pp function to call for each path | ||
24 | * @param pp_cls cls argument for pp. | ||
25 | */ | ||
26 | void | ||
27 | get_installation_paths (PathProcessor pp, | ||
28 | void *pp_cls); | ||
29 | |||
30 | /** | ||
31 | * Given a short name of a library (i.e. "mime"), find | ||
32 | * the full path of the respective plugin. | ||
33 | */ | ||
34 | char * | ||
35 | find_plugin (const char *short_name); | ||
36 | |||
37 | /** | ||
38 | * Load all plugins from the given directory. | ||
39 | * | ||
40 | * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend | ||
41 | * @param path path to a directory with plugins | ||
42 | */ | ||
43 | void | ||
44 | load_plugins_from_dir (void *cls, | ||
45 | const char *path); | ||
46 | |||
47 | #endif /* EXTRACTOR_PLUGPATH_H */ | ||