Home | History | Annotate | Download | only in gmodule
      1 /* GMODULE - GLIB wrapper code for dynamic module loading
      2  * Copyright (C) 1998, 2000 Tim Janik
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
     12  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public
     15  * License along with this library; if not, write to the
     16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     17  * Boston, MA 02111-1307, USA.
     18  */
     19 
     20 /*
     21  * MT safe
     22  */
     23 
     24 /* because we are compatible with archive format only since AIX 4.3 */
     25 
     26 #define __AR_BIG__
     27 
     28 #include "config.h"
     29 
     30 #include <ar.h>
     31 #include <stdlib.h>
     32 
     33 #include <dlfcn.h>
     34 
     35 /* --- functions --- */
     36 static gchar*
     37 fetch_dlerror (gboolean replace_null)
     38 {
     39   gchar *msg = dlerror ();
     40 
     41   /* make sure we always return an error message != NULL, if
     42    * expected to do so. */
     43 
     44   if (!msg && replace_null)
     45     return "unknown dl-error";
     46 
     47   return msg;
     48 }
     49 
     50 static gchar* _g_module_get_member(const gchar* file_name)
     51 {
     52   gchar* member = NULL;
     53   struct fl_hdr file_header;
     54   struct ar_hdr ar_header;
     55   long first_member;
     56   long name_len;
     57   int fd;
     58 
     59   fd = open(file_name, O_RDONLY);
     60   if (fd == -1)
     61     return NULL;
     62 
     63   if (read(fd, (void*)&file_header, FL_HSZ) != FL_HSZ)
     64     goto exit;
     65 
     66   if (strncmp(file_header.fl_magic, AIAMAGBIG, SAIAMAG) != 0)
     67     goto exit;
     68 
     69   /* read first archive file member header */
     70 
     71   first_member = atol(file_header.fl_fstmoff);
     72 
     73   if (lseek(fd, first_member, SEEK_SET) != first_member)
     74     goto exit;
     75 
     76   if (read(fd, (void*)&ar_header, AR_HSZ - 2) != AR_HSZ - 2)
     77     goto exit;
     78 
     79   /* read member name */
     80 
     81   name_len = atol(ar_header.ar_namlen);
     82 
     83   member = g_malloc(name_len+1);
     84   if (!member)
     85     goto exit;
     86 
     87   if (read(fd, (void*)member, name_len) != name_len)
     88     {
     89       g_free(member);
     90       member = NULL;
     91       goto exit;
     92     }
     93 
     94   member[name_len] = 0;
     95 
     96 exit:
     97   close(fd);
     98 
     99   return member;
    100 }
    101 
    102 static gpointer
    103 _g_module_open (const gchar *file_name,
    104 		gboolean     bind_lazy,
    105 		gboolean     bind_local)
    106 {
    107   gpointer handle;
    108   gchar* member;
    109   gchar* full_name;
    110 
    111   /* extract name of first member of archive */
    112 
    113   member = _g_module_get_member (file_name);
    114   if (member != NULL)
    115     {
    116       full_name = g_strconcat (file_name, "(", member, ")", NULL);
    117       g_free (member);
    118     }
    119   else
    120     full_name = g_strdup (file_name);
    121 
    122   handle = dlopen (full_name,
    123 		   (bind_local ? RTLD_LOCAL : RTLD_GLOBAL) | RTLD_MEMBER | (bind_lazy ? RTLD_LAZY : RTLD_NOW));
    124 
    125   g_free (full_name);
    126 
    127   if (!handle)
    128     g_module_set_error (fetch_dlerror (TRUE));
    129 
    130   return handle;
    131 }
    132 
    133 static gpointer
    134 _g_module_self (void)
    135 {
    136   gpointer handle;
    137 
    138   handle = dlopen (NULL, RTLD_GLOBAL | RTLD_LAZY);
    139   if (!handle)
    140     g_module_set_error (fetch_dlerror (TRUE));
    141 
    142   return handle;
    143 }
    144 
    145 static void
    146 _g_module_close (gpointer handle,
    147 		 gboolean is_unref)
    148 {
    149   /* are there any systems out there that have dlopen()/dlclose()
    150    * without a reference count implementation?
    151    */
    152   is_unref |= 1;
    153 
    154   if (is_unref)
    155     {
    156       if (dlclose (handle) != 0)
    157 	g_module_set_error (fetch_dlerror (TRUE));
    158     }
    159 }
    160 
    161 static gpointer
    162 _g_module_symbol (gpointer     handle,
    163 		  const gchar *symbol_name)
    164 {
    165   gpointer p;
    166 
    167   p = dlsym (handle, symbol_name);
    168   if (!p)
    169     g_module_set_error (fetch_dlerror (FALSE));
    170 
    171   return p;
    172 }
    173 
    174 static gchar*
    175 _g_module_build_path (const gchar *directory,
    176 		      const gchar *module_name)
    177 {
    178   if (directory && *directory) {
    179     if (strncmp (module_name, "lib", 3) == 0)
    180       return g_strconcat (directory, "/", module_name, NULL);
    181     else
    182       return g_strconcat (directory, "/lib", module_name, "." G_MODULE_SUFFIX, NULL);
    183   } else if (strncmp (module_name, "lib", 3) == 0)
    184     return g_strdup (module_name);
    185   else
    186     return g_strconcat ("lib", module_name, "." G_MODULE_SUFFIX, NULL);
    187 }
    188