extractor_plugins.c (11386B)
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_plugins.c 22 * @brief code to load plugins 23 * @author Christian Grothoff 24 */ 25 #include "extractor_plugins.h" 26 #include "extractor_plugpath.h" 27 #include "extractor_ipc.h" 28 #include "extractor_logging.h" 29 30 31 /** 32 * Try to resolve a plugin function. 33 * 34 * @param lib_handle library to search for the symbol 35 * @param prefix prefix to add 36 * @param sym_name base name for the symbol 37 * @param options set to special options requested by the plugin 38 * @return NULL on error, otherwise pointer to the symbol 39 */ 40 static void * 41 get_symbol_with_prefix (void *lib_handle, 42 const char *template, 43 const char *prefix, 44 const char **options) 45 { 46 char *name; 47 void *symbol; 48 const char *sym_name; 49 char *sym; 50 char *dot; 51 const char *(*opt_fun)(void); 52 53 if (NULL != options) 54 *options = NULL; 55 if (NULL == (sym_name = strrchr (prefix, '_'))) 56 return NULL; 57 sym_name++; 58 if (NULL == (sym = strdup (sym_name))) 59 { 60 LOG_STRERROR ("strdup"); 61 return NULL; 62 } 63 if (NULL != (dot = strchr (sym, '.'))) 64 *dot = '\0'; 65 if (NULL == (name = malloc (strlen (sym) + strlen (template) + 1))) 66 { 67 free (sym); 68 return NULL; 69 } 70 sprintf (name, 71 template, 72 sym); 73 /* try without '_' first */ 74 symbol = lt_dlsym (lib_handle, 75 name + 1); 76 if (NULL == symbol) 77 { 78 /* now try with the '_' */ 79 const char *dlerr = lt_dlerror (); 80 char *first_error = (NULL == dlerr) ? NULL : strdup (dlerr); 81 82 symbol = lt_dlsym (lib_handle, 83 name); 84 if (NULL == symbol) 85 { 86 LOG ("Resolving symbol `%s' failed, " 87 "so I tried `%s', but that failed also. Errors are: " 88 "`%s' and `%s'.\n", 89 name + 1, 90 name, 91 (NULL == first_error) 92 ? ( (NULL == dlerr) 93 ? "no error from ltdl!?" 94 : "out of memory") 95 : first_error, 96 lt_dlerror ()); 97 } 98 if (NULL != first_error) 99 free (first_error); 100 } 101 102 if ( (NULL != symbol) && 103 (NULL != options) ) 104 { 105 /* get special options */ 106 sprintf (name, 107 "_EXTRACTOR_%s_options", 108 sym); 109 /* try without '_' first */ 110 opt_fun = lt_dlsym (lib_handle, name + 1); 111 if (NULL == opt_fun) 112 opt_fun = lt_dlsym (lib_handle, name); 113 if (NULL != opt_fun) 114 *options = opt_fun (); 115 } 116 free (sym); 117 free (name); 118 return symbol; 119 } 120 121 122 /** 123 * Load a plugin. 124 * 125 * @param plugin plugin to load 126 * @return 0 on success, -1 on error 127 */ 128 int 129 EXTRACTOR_plugin_load_ (struct EXTRACTOR_PluginList *plugin) 130 { 131 #if WINDOWS 132 wchar_t wlibname[4097]; 133 char llibname[4097]; 134 #endif 135 lt_dladvise advise; 136 137 if (EXTRACTOR_OPTION_DISABLED == plugin->flags) 138 return -1; 139 if (NULL == plugin->libname) 140 plugin->libname = EXTRACTOR_find_plugin_ (plugin->short_libname); 141 if (NULL == plugin->libname) 142 { 143 LOG ("Failed to find plugin `%s'\n", 144 plugin->short_libname); 145 plugin->flags = EXTRACTOR_OPTION_DISABLED; 146 return -1; 147 } 148 lt_dladvise_init (&advise); 149 lt_dladvise_ext (&advise); 150 lt_dladvise_local (&advise); 151 #if WINDOWS 152 wlibname[0] = L'\0'; 153 llibname[0] = '\0'; 154 if ( (MultiByteToWideChar (CP_UTF8, 0, plugin->libname, -1, 155 wlibname, sizeof (wlibname)) <= 0) || 156 (WideCharToMultiByte (CP_ACP, 0, wlibname, -1, 157 llibname, sizeof (llibname), NULL, NULL) < 0) ) 158 { 159 LOG ("Loading `%s' plugin failed: %s\n", 160 plugin->short_libname, 161 "can't convert plugin name to local encoding"); 162 free (plugin->libname); 163 plugin->libname = NULL; 164 plugin->flags = EXTRACTOR_OPTION_DISABLED; 165 return -1; 166 } 167 plugin->libraryHandle = lt_dlopenadvise (llibname, 168 advise); 169 #else 170 plugin->libraryHandle = lt_dlopenadvise (plugin->libname, 171 advise); 172 #endif 173 lt_dladvise_destroy (&advise); 174 if (NULL == plugin->libraryHandle) 175 { 176 LOG ("Loading `%s' plugin failed (using name `%s'): %s\n", 177 plugin->short_libname, 178 plugin->libname, 179 lt_dlerror ()); 180 free (plugin->libname); 181 plugin->libname = NULL; 182 plugin->flags = EXTRACTOR_OPTION_DISABLED; 183 return -1; 184 } 185 plugin->extract_method = get_symbol_with_prefix (plugin->libraryHandle, 186 "_EXTRACTOR_%s_extract_method", 187 plugin->libname, 188 &plugin->specials); 189 if (NULL == plugin->extract_method) 190 { 191 LOG ("Resolving `extract' method of plugin `%s' failed: %s\n", 192 plugin->short_libname, 193 lt_dlerror ()); 194 lt_dlclose (plugin->libraryHandle); 195 free (plugin->libname); 196 plugin->libname = NULL; 197 plugin->flags = EXTRACTOR_OPTION_DISABLED; 198 return -1; 199 } 200 return 0; 201 } 202 203 204 /** 205 * Add a library for keyword extraction. 206 * 207 * @param prev the previous list of libraries, may be NULL 208 * @param library the name of the library 209 * @param options options to pass to the plugin 210 * @param flags options to use 211 * @return the new list of libraries, equal to prev iff an error occurred 212 */ 213 struct EXTRACTOR_PluginList * 214 EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList *prev, 215 const char *library, 216 const char *options, 217 enum EXTRACTOR_Options flags) 218 { 219 struct EXTRACTOR_PluginList *plugin; 220 struct EXTRACTOR_PluginList *pos; 221 char *libname; 222 223 for (pos = prev; NULL != pos; pos = pos->next) 224 if (0 == strcmp (pos->short_libname, library)) 225 return prev; 226 /* no change, library already loaded */ 227 if (NULL == (libname = EXTRACTOR_find_plugin_ (library))) 228 { 229 LOG ("Could not load plugin `%s'\n", 230 library); 231 return prev; 232 } 233 if (NULL == (plugin = malloc (sizeof (struct EXTRACTOR_PluginList)))) 234 return prev; 235 memset (plugin, 0, sizeof (struct EXTRACTOR_PluginList)); 236 plugin->next = prev; 237 if (NULL == (plugin->short_libname = strdup (library))) 238 { 239 free (libname); 240 free (plugin); 241 return prev; 242 } 243 plugin->libname = libname; 244 plugin->flags = flags; 245 if (NULL != options) 246 plugin->plugin_options = strdup (options); 247 else 248 plugin->plugin_options = NULL; 249 plugin->seek_request = -1; 250 return plugin; 251 } 252 253 254 /** 255 * Load multiple libraries as specified by the user. 256 * 257 * @param config a string given by the user that defines which 258 * libraries should be loaded. Has the format 259 * "[[-]LIBRARYNAME[(options)][:[-]LIBRARYNAME[(options)]]]*". 260 * For example, 'mp3:ogg.so' loads the 261 * mp3 and the ogg library. The '-' before the LIBRARYNAME 262 * indicates that the library should be removed from 263 * the library list. 264 * @param prev the previous list of libraries, may be NULL 265 * @param flags options to use 266 * @return the new list of libraries, equal to prev iff an error occurred 267 * or if config was empty (or NULL). 268 */ 269 struct EXTRACTOR_PluginList * 270 EXTRACTOR_plugin_add_config (struct EXTRACTOR_PluginList *prev, 271 const char *config, 272 enum EXTRACTOR_Options flags) 273 { 274 char *cpy; 275 size_t pos; 276 size_t last; 277 ssize_t lastconf; 278 size_t len; 279 280 if (NULL == config) 281 return prev; 282 if (NULL == (cpy = strdup (config))) 283 return prev; 284 len = strlen (config); 285 pos = 0; 286 last = 0; 287 lastconf = 0; 288 while (pos < len) 289 { 290 while ( (':' != cpy[pos]) && 291 ('\0' != cpy[pos]) && 292 ('(' != cpy[pos]) ) 293 pos++; 294 switch (cpy[pos]) 295 { 296 case '(': 297 cpy[pos++] = '\0'; /* replace '(' by termination */ 298 lastconf = pos; /* start config from here, after (. */ 299 while ( ('\0' != cpy[pos]) && 300 (')' != cpy[pos])) 301 pos++; /* config until ) or EOS. */ 302 if (')' == cpy[pos]) 303 { 304 cpy[pos++] = '\0'; /* write end of config here. */ 305 while ( (':' != cpy[pos]) && 306 ('\0' != cpy[pos]) ) 307 pos++; /* forward until real end of string found. */ 308 cpy[pos++] = '\0'; 309 } 310 else 311 { 312 cpy[pos++] = '\0'; /* end of string. */ 313 } 314 break; 315 case ':': 316 case '\0': 317 lastconf = -1; /* NULL config when no (). */ 318 cpy[pos++] = '\0'; /* replace ':' by termination */ 319 break; 320 default: 321 ABORT (); 322 } 323 if ('-' == cpy[last]) 324 { 325 last++; 326 prev = EXTRACTOR_plugin_remove (prev, 327 &cpy[last]); 328 } 329 else 330 { 331 prev = EXTRACTOR_plugin_add (prev, 332 &cpy[last], 333 (-1 != lastconf) ? &cpy[lastconf] : NULL, 334 flags); 335 } 336 last = pos; 337 } 338 free (cpy); 339 return prev; 340 } 341 342 343 /** 344 * Remove a plugin from a list. 345 * 346 * @param prev the current list of plugins 347 * @param library the name of the plugin to remove 348 * @return the reduced list, unchanged if the plugin was not loaded 349 */ 350 struct EXTRACTOR_PluginList * 351 EXTRACTOR_plugin_remove (struct EXTRACTOR_PluginList *prev, 352 const char *library) 353 { 354 struct EXTRACTOR_PluginList *pos; 355 struct EXTRACTOR_PluginList *first; 356 357 pos = prev; 358 first = prev; 359 while ( (NULL != pos) && 360 (0 != strcmp (pos->short_libname, library)) ) 361 { 362 prev = pos; 363 pos = pos->next; 364 } 365 if (NULL == pos) 366 { 367 LOG ("Unloading plugin `%s' failed!\n", 368 library); 369 return first; 370 } 371 /* found, close library */ 372 if (first == pos) 373 first = pos->next; 374 else 375 prev->next = pos->next; 376 if (NULL != pos->channel) 377 EXTRACTOR_IPC_channel_destroy_ (pos->channel); 378 if ( (NULL != pos->shm) && 379 (0 == EXTRACTOR_IPC_shared_memory_change_rc_ (pos->shm, -1)) ) 380 EXTRACTOR_IPC_shared_memory_destroy_ (pos->shm); 381 if (NULL != pos->short_libname) 382 free (pos->short_libname); 383 if (NULL != pos->libname) 384 free (pos->libname); 385 free (pos->plugin_options); 386 if (NULL != pos->libraryHandle) 387 lt_dlclose (pos->libraryHandle); 388 free (pos); 389 return first; 390 } 391 392 393 /** 394 * Remove all plugins from the given list (destroys the list). 395 * 396 * @param plugin the list of plugins 397 */ 398 void 399 EXTRACTOR_plugin_remove_all (struct EXTRACTOR_PluginList *plugins) 400 { 401 while (NULL != plugins) 402 plugins = EXTRACTOR_plugin_remove (plugins, plugins->short_libname); 403 } 404 405 406 /* end of extractor_plugins.c */