"Fossies" - the Fresh Open Source Software Archive

Member "libextractor-1.11/src/main/extractor_plugpath.c" (30 Jan 2021, 14967 Bytes) of package /linux/privat/libextractor-1.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "extractor_plugpath.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10_vs_1.11.

    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_plugpath.c
   22  * @brief determine path where plugins are installed
   23  * @author Christian Grothoff
   24  */
   25 
   26 #include "platform.h"
   27 #include "extractor.h"
   28 #include <dirent.h>
   29 #include <sys/types.h>
   30 #include <signal.h>
   31 #include <ltdl.h>
   32 
   33 #include "extractor_plugpath.h"
   34 #include "extractor_logging.h"
   35 
   36 /**
   37  * Function to call on paths.
   38  *
   39  * @param cls closure
   40  * @param path a directory path
   41  */
   42 typedef void (*EXTRACTOR_PathProcessor) (void *cls,
   43                                          const char *path);
   44 
   45 
   46 /**
   47  * Remove a trailing '/bin/' from 'in' (if present).
   48  *
   49  * @param in input string, modified
   50  * @return NULL if 'in' is NULL, otherwise 'in' with '/bin/' removed
   51  */
   52 static char *
   53 cut_bin (char *in)
   54 {
   55   size_t p;
   56 
   57   if (NULL == in)
   58     return NULL;
   59   p = strlen (in);
   60   if (p < 4)
   61     return in;
   62   if ( ('/' == in[p - 1]) ||
   63        ('\\' == in[p - 1]) )
   64     in[--p] = '\0';
   65   if (0 == strcmp (&in[p - 4],
   66                    "/bin"))
   67   {
   68     in[p - 4] = '\0';
   69     p -= 4;
   70   }
   71   else if (0 == strcmp (&in[p - 4],
   72                         "\\bin"))
   73   {
   74     in[p - 4] = '\0';
   75     p -= 4;
   76   }
   77   return in;
   78 }
   79 
   80 
   81 #if GNU_LINUX
   82 /**
   83  * Try to determine path by reading /proc/PID/exe or
   84  * /proc/PID/maps.
   85  *
   86  * Note that this may fail if LE is installed in one directory
   87  * and the binary linking against it sits elsewhere.
   88  */
   89 static char *
   90 get_path_from_proc_exe ()
   91 {
   92   char fn[64];
   93   char line[1024];
   94   char dir[1024];
   95   char *lnk;
   96   char *ret;
   97   char *lestr;
   98   ssize_t size;
   99   FILE *f;
  100 
  101   snprintf (fn,
  102             sizeof (fn),
  103             "/proc/%u/maps",
  104             getpid ());
  105   if (NULL != (f = fopen (fn, "r")))
  106   {
  107     while (NULL != fgets (line, 1024, f))
  108     {
  109       if ( (1 == sscanf (line,
  110                          "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%s",
  111                          dir)) &&
  112            (NULL != (lestr = strstr (dir,
  113                                      "libextractor")) ) )
  114       {
  115         lestr[0] = '\0';
  116         fclose (f);
  117         return strdup (dir);
  118       }
  119     }
  120     fclose (f);
  121   }
  122   snprintf (fn,
  123             sizeof (fn),
  124             "/proc/%u/exe",
  125             getpid ());
  126   if (NULL == (lnk = malloc (1029))) /* 1024 + 6 for "/lib/" catenation */
  127     return NULL;
  128   size = readlink (fn, lnk, 1023);
  129   if ( (size <= 0) || (size >= 1024) )
  130   {
  131     free (lnk);
  132     return NULL;
  133   }
  134   lnk[size] = '\0';
  135   while ( ('/' != lnk[size]) &&
  136           (size > 0) )
  137     size--;
  138   if ( (size < 4) ||
  139        ('/' != lnk[size - 4]) )
  140   {
  141     /* not installed in "/bin/" -- binary path probably useless */
  142     free (lnk);
  143     return NULL;
  144   }
  145   lnk[size] = '\0';
  146   lnk = cut_bin (lnk);
  147   if (NULL == (ret = realloc (lnk, strlen (lnk) + 6)))
  148   {
  149     LOG_STRERROR ("realloc");
  150     free (lnk);
  151     return NULL;
  152   }
  153   strcat (ret, "/lib/"); /* guess "lib/" as the library dir */
  154   return ret;
  155 }
  156 
  157 
  158 #endif
  159 
  160 
  161 #if WINDOWS
  162 static HMODULE le_dll = NULL;
  163 
  164 BOOL WINAPI
  165 DllMain (HINSTANCE hinstDLL,
  166          DWORD fdwReason,
  167          LPVOID lpvReserved)
  168 {
  169   switch (fdwReason)
  170   {
  171   case DLL_PROCESS_ATTACH:
  172     le_dll = (HMODULE) hinstDLL;
  173     break;
  174   }
  175 
  176   return TRUE;
  177 }
  178 
  179 
  180 /**
  181  * Try to determine path with win32-specific function
  182  */
  183 static char *
  184 get_path_from_module_filename ()
  185 {
  186   char *path;
  187   char *ret;
  188   char *idx;
  189 
  190   if (NULL == (path = malloc (4103))) /* 4096+nil+6 for "/lib/" catenation */
  191     return NULL;
  192   GetModuleFileName (le_dll, path, 4096);
  193   idx = path + strlen (path);
  194   while ( (idx > path) &&
  195           ('\\' != *idx) &&
  196           ('/' != *idx) )
  197     idx--;
  198   *idx = '\0';
  199   path = cut_bin (path);
  200   if (NULL == (ret = realloc (path, strlen (path) + 6)))
  201   {
  202     LOG_STRERROR ("realloc");
  203     free (path);
  204     return NULL;
  205   }
  206   strcat (ret, "/lib/"); /* guess "lib/" as the library dir */
  207   return ret;
  208 }
  209 
  210 
  211 #endif
  212 
  213 
  214 #if DARWIN
  215 #include <dlfcn.h>
  216 #include <mach-o/dyld.h>
  217 
  218 /**
  219  * Signature of the '_NSGetExecutablePath" function.
  220  *
  221  * @param buf where to write the path
  222  * @param number of bytes available in 'buf'
  223  * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
  224  */
  225 typedef int
  226 (*MyNSGetExecutablePathProto) (char *buf,
  227                                size_t *bufsize);
  228 
  229 
  230 /**
  231  * Try to obtain the path of our executable using '_NSGetExecutablePath'.
  232  *
  233  * @return NULL on error
  234  */
  235 static char *
  236 get_path_from_NSGetExecutablePath ()
  237 {
  238   static char zero;
  239   char *path;
  240   char *ret;
  241   size_t len;
  242   MyNSGetExecutablePathProto func;
  243 
  244   path = NULL;
  245   if (NULL == (func =
  246                  (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT,
  247                                                      "_NSGetExecutablePath")))
  248     return NULL;
  249   path = &zero;
  250   len = 0;
  251   /* get the path len, including the trailing \0 */
  252   (void) func (path, &len);
  253   if (0 == len)
  254     return NULL;
  255   if (NULL == (path = malloc (len)))
  256   {
  257     LOG_STRERROR ("malloc");
  258     return NULL;
  259   }
  260   if (0 != func (path, &len))
  261   {
  262     free (path);
  263     return NULL;
  264   }
  265   len = strlen (path);
  266   while ((path[len] != '/') && (len > 0))
  267     len--;
  268   path[len] = '\0';
  269   if (NULL != strstr (path, "/lib"))
  270     return path;
  271   path = cut_bin (path);
  272   if (NULL == (ret = realloc (path, strlen (path) + 5)))
  273   {
  274     LOG_STRERROR ("realloc");
  275     free (path);
  276     return NULL;
  277   }
  278   strcat (ret, "/lib/");
  279   return ret;
  280 }
  281 
  282 
  283 /**
  284  * Try to obtain the path of our executable using '_dyld_image' API.
  285  *
  286  * @return NULL on error
  287  */
  288 static char *
  289 get_path_from_dyld_image ()
  290 {
  291   const char *path;
  292   char *s;
  293   char *p;
  294   unsigned int i;
  295   int c;
  296 
  297   c = _dyld_image_count ();
  298   for (i = 0; i < c; i++)
  299   {
  300     if (((void *) _dyld_get_image_header (i)) != (void *) &_mh_dylib_header)
  301       continue;
  302     path = _dyld_get_image_name (i);
  303     if ( (NULL == path) || (0 == strlen (path)) )
  304       continue;
  305     if (NULL == (p = strdup (path)))
  306     {
  307       LOG_STRERROR ("strdup");
  308       return NULL;
  309     }
  310     s = p + strlen (p);
  311     while ( (s > p) && ('/' != *s) )
  312       s--;
  313     s++;
  314     *s = '\0';
  315     return p;
  316   }
  317   return NULL;
  318 }
  319 
  320 
  321 #endif
  322 
  323 
  324 /**
  325  * Return the actual path to a file found in the current
  326  * PATH environment variable.
  327  *
  328  * @return path to binary, NULL if not found
  329  */
  330 static char *
  331 get_path_from_PATH ()
  332 {
  333   struct stat sbuf;
  334   char *path;
  335   char *pos;
  336   char *end;
  337   char *buf;
  338   char *ret;
  339   const char *p;
  340 
  341   if (NULL == (p = getenv ("PATH")))
  342     return NULL;
  343   if (NULL == (path = strdup (p))) /* because we write on it */
  344   {
  345     LOG_STRERROR ("strdup");
  346     return NULL;
  347   }
  348   if (NULL == (buf = malloc (strlen (path) + 20)))
  349   {
  350     LOG_STRERROR ("malloc");
  351     free (path);
  352     return NULL;
  353   }
  354   pos = path;
  355   while (NULL != (end = strchr (pos, ':')))
  356   {
  357     *end = '\0';
  358     sprintf (buf, "%s/%s", pos, "extract");
  359     if (0 == stat (buf, &sbuf))
  360     {
  361       free (buf);
  362       if (NULL == (pos = strdup (pos)))
  363       {
  364         LOG_STRERROR ("strdup");
  365         free (path);
  366         return NULL;
  367       }
  368       free (path);
  369       pos = cut_bin (pos);
  370       if (NULL == (ret = realloc (pos, strlen (pos) + 6)))
  371       {
  372         LOG_STRERROR ("realloc");
  373         free (pos);
  374         return NULL;
  375       }
  376       strcat (ret, "/lib/");
  377       return ret;
  378     }
  379     pos = end + 1;
  380   }
  381   sprintf (buf, "%s/%s", pos, "extract");
  382   if (0 == stat (buf, &sbuf))
  383   {
  384     pos = strdup (pos);
  385     free (buf);
  386     free (path);
  387     if (NULL == pos)
  388       return NULL;
  389     pos = cut_bin (pos);
  390     if (NULL == (ret = realloc (pos, strlen (pos) + 6)))
  391     {
  392       LOG_STRERROR ("realloc");
  393       free (pos);
  394       return NULL;
  395     }
  396     strcat (ret, "/lib/");
  397     return ret;
  398   }
  399   free (buf);
  400   free (path);
  401   return NULL;
  402 }
  403 
  404 
  405 /**
  406  * Create a filename by appending 'fname' to 'path'.
  407  *
  408  * @param path the base path
  409  * @param fname the filename to append
  410  * @return '$path/$fname', NULL on error
  411  */
  412 static char *
  413 append_to_dir (const char *path,
  414                const char *fname)
  415 {
  416   char *ret;
  417   size_t slen;
  418 
  419   if (0 == (slen = strlen (path)))
  420     return NULL;
  421   if ('/' == fname[0])
  422     fname++;
  423   ret = malloc (slen + strlen (fname) + 2);
  424   if (NULL == ret)
  425     return NULL;
  426 #ifdef MINGW
  427   if ('\\' == path[slen - 1])
  428     sprintf (ret,
  429              "%s%s",
  430              path,
  431              fname);
  432   else
  433     sprintf (ret,
  434              "%s\\%s",
  435              path,
  436              fname);
  437 #else
  438   if ('/' == path[slen - 1])
  439     sprintf (ret,
  440              "%s%s",
  441              path,
  442              fname);
  443   else
  444     sprintf (ret,
  445              "%s/%s",
  446              path,
  447              fname);
  448 #endif
  449   return ret;
  450 }
  451 
  452 
  453 /**
  454  * Iterate over all paths where we expect to find GNU libextractor
  455  * plugins.
  456  *
  457  * @param pp function to call for each path
  458  * @param pp_cls cls argument for pp.
  459  */
  460 static void
  461 get_installation_paths (EXTRACTOR_PathProcessor pp,
  462                         void *pp_cls)
  463 {
  464   const char *p;
  465   char *path;
  466   char *prefix;
  467   char *d;
  468   char *saveptr;
  469 
  470   prefix = NULL;
  471   if (NULL != (p = getenv ("LIBEXTRACTOR_PREFIX")))
  472   {
  473     if (NULL == (d = strdup (p)))
  474     {
  475       LOG_STRERROR ("strdup");
  476       return;
  477     }
  478     for (prefix = strtok_r (d, ":", &saveptr);
  479          NULL != prefix;
  480          prefix = strtok_r (NULL, ":", &saveptr))
  481       pp (pp_cls, prefix);
  482     free (d);
  483     return;
  484   }
  485 #if GNU_LINUX
  486   if (NULL == prefix)
  487     prefix = get_path_from_proc_exe ();
  488 #endif
  489 #if WINDOWS
  490   if (NULL == prefix)
  491     prefix = get_path_from_module_filename ();
  492 #endif
  493 #if DARWIN
  494   if (NULL == prefix)
  495     prefix = get_path_from_NSGetExecutablePath ();
  496   if (NULL == prefix)
  497     prefix = get_path_from_dyld_image ();
  498 #endif
  499   if (NULL == prefix)
  500     prefix = get_path_from_PATH ();
  501   pp (pp_cls, PLUGININSTDIR);
  502   if (NULL == prefix)
  503     return;
  504   path = append_to_dir (prefix, PLUGINDIR);
  505   if (NULL != path)
  506   {
  507     if (0 != strcmp (path,
  508                      PLUGININSTDIR))
  509       pp (pp_cls, path);
  510     free (path);
  511   }
  512   free (prefix);
  513 }
  514 
  515 
  516 /**
  517  * Closure for #find_plugin_in_path().
  518  */
  519 struct SearchContext
  520 {
  521   /**
  522    * Name of the plugin we are looking for.
  523    */
  524   const char *short_name;
  525 
  526   /**
  527    * Location for storing the path to the plugin upon success.
  528    */
  529   char *path;
  530 };
  531 
  532 
  533 /**
  534  * Load all plugins from the given directory.
  535  *
  536  * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
  537  * @param path path to a directory with plugins
  538  */
  539 static void
  540 find_plugin_in_path (void *cls,
  541                      const char *path)
  542 {
  543   struct SearchContext *sc = cls;
  544   DIR *dir;
  545   struct dirent *ent;
  546   const char *sym_name;
  547   char *sym;
  548   char *dot;
  549   size_t dlen;
  550 
  551   if (NULL != sc->path)
  552     return;
  553   if (NULL == (dir = opendir (path)))
  554     return;
  555   while (NULL != (ent = readdir (dir)))
  556   {
  557     if ('.' == ent->d_name[0])
  558       continue;
  559     dlen = strlen (ent->d_name);
  560     if ( (dlen < 4) ||
  561          ( (0 != strcmp (&ent->d_name[dlen - 3], ".so")) &&
  562            (0 != strcasecmp (&ent->d_name[dlen - 4], ".dll")) ) )
  563       continue; /* only load '.so' and '.dll' */
  564     if (NULL == (sym_name = strrchr (ent->d_name, '_')))
  565       continue;
  566     sym_name++;
  567     if (NULL == (sym = strdup (sym_name)))
  568     {
  569       LOG_STRERROR ("strdup");
  570       closedir (dir);
  571       return;
  572     }
  573     dot = strchr (sym, '.');
  574     if (NULL != dot)
  575       *dot = '\0';
  576     if (0 == strcmp (sym, sc->short_name))
  577     {
  578       sc->path = append_to_dir (path, ent->d_name);
  579       free (sym);
  580       break;
  581     }
  582     free (sym);
  583   }
  584   closedir (dir);
  585 }
  586 
  587 
  588 /**
  589  * Given a short name of a library (i.e. "mime"), find
  590  * the full path of the respective plugin.
  591  */
  592 char *
  593 EXTRACTOR_find_plugin_ (const char *short_name)
  594 {
  595   struct SearchContext sc;
  596 
  597   sc.path = NULL;
  598   sc.short_name = short_name;
  599   get_installation_paths (&find_plugin_in_path,
  600                           &sc);
  601   return sc.path;
  602 }
  603 
  604 
  605 /**
  606  * Closure for #load_plugins_from_dir().
  607  */
  608 struct DefaultLoaderContext
  609 {
  610   /**
  611    * Accumulated result list.
  612    */
  613   struct EXTRACTOR_PluginList *res;
  614 
  615   /**
  616    * Flags to use for all plugins.
  617    */
  618   enum EXTRACTOR_Options flags;
  619 };
  620 
  621 
  622 /**
  623  * Load all plugins from the given directory.
  624  *
  625  * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend
  626  * @param path path to a directory with plugins
  627  */
  628 static void
  629 load_plugins_from_dir (void *cls,
  630                        const char *path)
  631 {
  632   struct DefaultLoaderContext *dlc = cls;
  633   DIR *dir;
  634   struct dirent *ent;
  635   const char *sym_name;
  636   char *sym;
  637   char *dot;
  638   size_t dlen;
  639 
  640   if (NULL == (dir = opendir (path)))
  641     return;
  642   while (NULL != (ent = readdir (dir)))
  643   {
  644     if (ent->d_name[0] == '.')
  645       continue;
  646     dlen = strlen (ent->d_name);
  647     if ( (dlen < 4) ||
  648          ( (0 != strcmp (&ent->d_name[dlen - 3], ".so")) &&
  649            (0 != strcasecmp (&ent->d_name[dlen - 4], ".dll")) ) )
  650       continue; /* only load '.so' and '.dll' */
  651     if (NULL == (sym_name = strrchr (ent->d_name, '_')))
  652       continue;
  653     sym_name++;
  654     if (NULL == (sym = strdup (sym_name)))
  655     {
  656       LOG_STRERROR ("strdup");
  657       closedir (dir);
  658       return;
  659     }
  660     if (NULL != (dot = strchr (sym, '.')))
  661       *dot = '\0';
  662     dlc->res = EXTRACTOR_plugin_add (dlc->res,
  663                                      sym,
  664                                      NULL,
  665                                      dlc->flags);
  666     free (sym);
  667   }
  668   closedir (dir);
  669 }
  670 
  671 
  672 /**
  673  * Load the default set of plugins. The default can be changed
  674  * by setting the LIBEXTRACTOR_LIBRARIES environment variable.
  675  * If it is set to "env", then this function will return
  676  * #EXTRACTOR_plugin_add_config(NULL, env, flags).  Otherwise,
  677  * it will load all of the installed plugins and return them.
  678  *
  679  * @param flags options for all of the plugins loaded
  680  * @return the default set of plugins, NULL if no plugins were found
  681  */
  682 struct EXTRACTOR_PluginList *
  683 EXTRACTOR_plugin_add_defaults (enum EXTRACTOR_Options flags)
  684 {
  685   struct DefaultLoaderContext dlc;
  686   char *env;
  687 
  688   env = getenv ("LIBEXTRACTOR_LIBRARIES");
  689   if (NULL != env)
  690     return EXTRACTOR_plugin_add_config (NULL, env, flags);
  691   dlc.res = NULL;
  692   dlc.flags = flags;
  693   get_installation_paths (&load_plugins_from_dir,
  694                           &dlc);
  695   return dlc.res;
  696 }
  697 
  698 
  699 /* end of extractor_plugpath.c */