libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

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 */