libextractor

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

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