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