Imported Debian patch 0.63.0-6
[hcoop/debian/courier-authlib.git] / libltdl / loaders / preopen.c
diff --git a/libltdl/loaders/preopen.c b/libltdl/loaders/preopen.c
new file mode 100644 (file)
index 0000000..7149287
--- /dev/null
@@ -0,0 +1,375 @@
+/* loader-preopen.c -- emulate dynamic linking using preloaded_symbols
+
+   Copyright (C) 1998, 1999, 2000, 2004, 2006,
+                 2007, 2008 Free Software Foundation, Inc.
+   Written by Thomas Tanner, 1998
+
+   NOTE: The canonical source of this file is maintained with the
+   GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
+
+GNU Libltdl is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+As a special exception to the GNU Lesser General Public License,
+if you distribute this file as part of a program or library that
+is built using GNU Libtool, you may include this file under the
+same distribution terms that you use for the rest of that program.
+
+GNU Libltdl is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
+copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
+or obtained by writing to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "lt__private.h"
+#include "lt_dlloader.h"
+
+/* Use the preprocessor to rename non-static symbols to avoid namespace
+   collisions when the loader code is statically linked into libltdl.
+   Use the "<module_name>_LTX_" prefix so that the symbol addresses can
+   be fetched from the preloaded symbol list by lt_dlsym():  */
+#define get_vtable     preopen_LTX_get_vtable
+
+LT_BEGIN_C_DECLS
+LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
+LT_END_C_DECLS
+
+
+/* Boilerplate code to set up the vtable for hooking this loader into
+   libltdl's loader list:  */
+static int      vl_init  (lt_user_data loader_data);
+static int      vl_exit  (lt_user_data loader_data);
+static lt_module vm_open  (lt_user_data loader_data, const char *filename,
+                           lt_dladvise advise);
+static int      vm_close (lt_user_data loader_data, lt_module module);
+static void *   vm_sym   (lt_user_data loader_data, lt_module module,
+                         const char *symbolname);
+
+static lt_dlvtable *vtable = 0;
+
+/* Return the vtable for this loader, only the name and sym_prefix
+   attributes (plus the virtual function implementations, obviously)
+   change between loaders.  */
+lt_dlvtable *
+get_vtable (lt_user_data loader_data)
+{
+  if (!vtable)
+    {
+      vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable);
+    }
+
+  if (vtable && !vtable->name)
+    {
+      vtable->name             = "lt_preopen";
+      vtable->sym_prefix       = 0;
+      vtable->module_open      = vm_open;
+      vtable->module_close     = vm_close;
+      vtable->find_sym         = vm_sym;
+      vtable->dlloader_init    = vl_init;
+      vtable->dlloader_exit    = vl_exit;
+      vtable->dlloader_data    = loader_data;
+      vtable->priority         = LT_DLLOADER_PREPEND;
+    }
+
+  if (vtable && (vtable->dlloader_data != loader_data))
+    {
+      LT__SETERROR (INIT_LOADER);
+      return 0;
+    }
+
+  return vtable;
+}
+
+
+
+/* --- IMPLEMENTATION --- */
+
+
+/* Wrapper type to chain together symbol lists of various origins.  */
+typedef struct symlist_chain
+{
+  struct symlist_chain *next;
+  const lt_dlsymlist   *symlist;
+} symlist_chain;
+
+
+static int add_symlist   (const lt_dlsymlist *symlist);
+static int free_symlists (void);
+
+/* The start of the symbol lists chain.  */
+static symlist_chain          *preloaded_symlists              = 0;
+
+/* A symbol list preloaded before lt_init() was called.  */
+static const   lt_dlsymlist   *default_preloaded_symbols       = 0;
+
+
+/* A function called through the vtable to initialise this loader.  */
+static int
+vl_init (lt_user_data LT__UNUSED loader_data)
+{
+  int errors = 0;
+
+  preloaded_symlists = 0;
+  if (default_preloaded_symbols)
+    {
+      errors = lt_dlpreload (default_preloaded_symbols);
+    }
+
+  return errors;
+}
+
+
+/* A function called through the vtable when this loader is no
+   longer needed by the application.  */
+static int
+vl_exit (lt_user_data LT__UNUSED loader_data)
+{
+  vtable = NULL;
+  free_symlists ();
+  return 0;
+}
+
+
+/* A function called through the vtable to open a module with this
+   loader.  Returns an opaque representation of the newly opened
+   module for processing with this loader's other vtable functions.  */
+static lt_module
+vm_open (lt_user_data LT__UNUSED loader_data, const char *filename,
+         lt_dladvise LT__UNUSED advise)
+{
+  symlist_chain *lists;
+  lt_module     module = 0;
+
+  if (!preloaded_symlists)
+    {
+      LT__SETERROR (NO_SYMBOLS);
+      goto done;
+    }
+
+  /* Can't use NULL as the reflective symbol header, as NULL is
+     used to mark the end of the entire symbol list.  Self-dlpreopened
+     symbols follow this magic number, chosen to be an unlikely
+     clash with a real module name.  */
+  if (!filename)
+    {
+      filename = "@PROGRAM@";
+    }
+
+  for (lists = preloaded_symlists; lists; lists = lists->next)
+    {
+      const lt_dlsymlist *symbol;
+      for (symbol= lists->symlist; symbol->name; ++symbol)
+       {
+         if (!symbol->address && streq (symbol->name, filename))
+           {
+             /* If the next symbol's name and address is 0, it means
+                the module just contains the originator and no symbols.
+                In this case we pretend that we never saw the module and
+                hope that some other loader will be able to load the module
+                and have access to its symbols */
+             const lt_dlsymlist *next_symbol = symbol +1;
+             if (next_symbol->address && next_symbol->name)
+               {
+                 module = (lt_module) lists->symlist;
+                 goto done;
+               }
+           }
+       }
+    }
+
+  LT__SETERROR (FILE_NOT_FOUND);
+
+ done:
+  return module;
+}
+
+
+/* A function called through the vtable when a particular module
+   should be unloaded.  */
+static int
+vm_close (lt_user_data LT__UNUSED loader_data, lt_module LT__UNUSED module)
+{
+  /* Just to silence gcc -Wall */
+  module = 0;
+  return 0;
+}
+
+
+/* A function called through the vtable to get the address of
+   a symbol loaded from a particular module.  */
+static void *
+vm_sym (lt_user_data LT__UNUSED loader_data, lt_module module, const char *name)
+{
+  lt_dlsymlist        *symbol = (lt_dlsymlist*) module;
+
+  symbol +=2;                  /* Skip header (originator then libname). */
+
+  while (symbol->name)
+    {
+      if (streq (symbol->name, name))
+       {
+         return symbol->address;
+       }
+
+    ++symbol;
+  }
+
+  LT__SETERROR (SYMBOL_NOT_FOUND);
+
+  return 0;
+}
+
+
+
+/* --- HELPER FUNCTIONS --- */
+
+
+/* The symbol lists themselves are not allocated from the heap, but
+   we can unhook them and free up the chain of links between them.  */
+static int
+free_symlists (void)
+{
+  symlist_chain *lists;
+
+  lists = preloaded_symlists;
+  while (lists)
+    {
+      symlist_chain *next = lists->next;
+      FREE (lists);
+      lists = next;
+    }
+  preloaded_symlists = 0;
+
+  return 0;
+}
+
+/* Add a new symbol list to the global chain.  */
+static int
+add_symlist (const lt_dlsymlist *symlist)
+{
+  symlist_chain *lists;
+  int           errors   = 0;
+
+  /* Search for duplicate entries:  */
+  for (lists = preloaded_symlists;
+       lists && lists->symlist != symlist; lists = lists->next)
+    /*NOWORK*/;
+
+  /* Don't add the same list twice:  */
+  if (!lists)
+    {
+      symlist_chain *tmp = (symlist_chain *) lt__zalloc (sizeof *tmp);
+
+      if (tmp)
+       {
+         tmp->symlist = symlist;
+         tmp->next = preloaded_symlists;
+         preloaded_symlists = tmp;
+       }
+      else
+       {
+         ++errors;
+       }
+    }
+
+  return errors;
+}
+
+
+
+/* --- PRELOADING API CALL IMPLEMENTATIONS --- */
+
+
+/* Save a default symbol list for later.  */
+int
+lt_dlpreload_default (const lt_dlsymlist *preloaded)
+{
+  default_preloaded_symbols = preloaded;
+  return 0;
+}
+
+
+/* Add a symbol list to the global chain, or with a NULL argument,
+   revert to just the default list.  */
+int
+lt_dlpreload (const lt_dlsymlist *preloaded)
+{
+  int errors = 0;
+
+  if (preloaded)
+    {
+      errors = add_symlist (preloaded);
+    }
+  else
+    {
+      free_symlists();
+
+      if (default_preloaded_symbols)
+       {
+         errors = lt_dlpreload (default_preloaded_symbols);
+       }
+    }
+
+  return errors;
+}
+
+
+/* Open all the preloaded modules from the named originator, executing
+   a callback for each one.  If ORIGINATOR is NULL, then call FUNC for
+   each preloaded module from the program itself.  */
+int
+lt_dlpreload_open (const char *originator, lt_dlpreload_callback_func *func)
+{
+  symlist_chain *list;
+  int           errors = 0;
+  int           found  = 0;
+
+  /* For each symlist in the chain...  */
+  for (list = preloaded_symlists; list; list = list->next)
+    {
+      /* ...that was preloaded by the requesting ORIGINATOR... */
+      if ((originator && streq (list->symlist->name, originator))
+          || (!originator && streq (list->symlist->name, "@PROGRAM@")))
+       {
+         const lt_dlsymlist *symbol;
+         unsigned int idx = 0;
+
+         ++found;
+
+         /* ...load the symbols per source compilation unit:
+            (we preincrement the index to skip over the originator entry)  */
+         while ((symbol = &list->symlist[++idx])->name != 0)
+           {
+             if ((symbol->address == 0)
+                 && (strneq (symbol->name, "@PROGRAM@")))
+               {
+                 lt_dlhandle handle = lt_dlopen (symbol->name);
+                 if (handle == 0)
+                   {
+                     ++errors;
+                   }
+                 else
+                   {
+                     errors += (*func) (handle);
+                   }
+               }
+           }
+       }
+    }
+
+  if (!found)
+    {
+      LT__SETERROR(CANNOT_OPEN);
+      ++errors;
+    }
+
+  return errors;
+}