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