1 /***************************************************************************
2 begin : Fri Nov 22 2002
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6
7 ***************************************************************************
8 * *
9 * This library is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU Lesser General Public *
11 * License as published by the Free Software Foundation; either *
12 * version 2.1 of the License, or (at your option) any later version. *
13 * *
14 * This library is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
17 * Lesser General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU Lesser General Public *
20 * License along with this library; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22 * MA 02111-1307 USA *
23 * *
24 ***************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include "libloader_p.h"
31 #include <gwenhywfar/misc.h>
32 #include <gwenhywfar/debug.h>
33 #include <gwenhywfar/buffer.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <assert.h>
38 #ifdef ENABLE_NLS
39 # include <locale.h>
40 #endif
41 #ifdef HAVE_DLFCN_H
42 # include <dlfcn.h>
43 #endif
44
45
46
GWEN_LibLoader_ModuleInit(void)47 int GWEN_LibLoader_ModuleInit(void)
48 {
49 return 0;
50 }
51
52
GWEN_LibLoader_ModuleFini(void)53 int GWEN_LibLoader_ModuleFini(void)
54 {
55 return 0;
56 }
57
58
59
GWEN_LibLoader_new(void)60 GWEN_LIBLOADER *GWEN_LibLoader_new(void)
61 {
62 GWEN_LIBLOADER *h;
63
64 GWEN_NEW_OBJECT(GWEN_LIBLOADER, h);
65 return h;
66 }
67
68
69
GWEN_LibLoader_free(GWEN_LIBLOADER * h)70 void GWEN_LibLoader_free(GWEN_LIBLOADER *h)
71 {
72 if (h) {
73 GWEN_FREE_OBJECT(h);
74 }
75 }
76
77
78
GWEN_LibLoader_LoadLibrary(GWEN_LIBLOADER * h,const char * name)79 int GWEN_LibLoader_LoadLibrary(GWEN_LIBLOADER *h,
80 const char *name)
81 {
82 const char *errorstring;
83
84 assert(h);
85
86 DBG_DEBUG(GWEN_LOGDOMAIN, "Loading library \"%s\"", name);
87
88 h->handle=dlopen(name, RTLD_LAZY);
89 if (!h->handle) {
90
91 #ifdef ENABLE_NLS
92 const char *orig_locale = setlocale(LC_MESSAGES, NULL);
93 char *currentLocale = strdup(orig_locale ? orig_locale : "C");
94 setlocale(LC_MESSAGES, "C");
95 #endif
96
97 /* The string is checked against the known "C" locale strings
98 below. We *have* to switch to the C locale temporarily because
99 otherwise the string might be any translated value. */
100 errorstring = dlerror();
101
102 #ifdef ENABLE_NLS
103 setlocale(LC_MESSAGES, currentLocale);
104 free(currentLocale);
105 #endif
106
107 DBG_INFO(GWEN_LOGDOMAIN, "dlopen(%s): %s", name, errorstring);
108 if (strstr(errorstring, "No such file")) {
109 if (strstr(errorstring, name)) {
110 return GWEN_ERROR_NOT_FOUND;
111 }
112 }
113 else if (strstr(errorstring, "undefined symbol:")) {
114 DBG_INFO(GWEN_LOGDOMAIN,
115 "GWEN: Error loading library: %s",
116 errorstring);
117 if (strstr(errorstring, name))
118 return GWEN_ERROR_COULD_NOT_RESOLVE;
119 else
120 return GWEN_ERROR_COULD_NOT_LOAD;
121 }
122 DBG_INFO(GWEN_LOGDOMAIN,
123 "GWEN: Error loading library: %s",
124 errorstring);
125 return GWEN_ERROR_COULD_NOT_LOAD;
126 }
127 DBG_INFO(GWEN_LOGDOMAIN, "Loaded library \"%s\"", name);
128 return 0;
129 }
130
131
132
GWEN_LibLoader_CloseLibrary(GWEN_LIBLOADER * h)133 int GWEN_LibLoader_CloseLibrary(GWEN_LIBLOADER *h)
134 {
135
136 assert(h);
137
138 if (!h->handle)
139 return GWEN_ERROR_NOT_OPEN;
140 if (dlclose(h->handle)!=0) {
141 DBG_ERROR(GWEN_LOGDOMAIN,
142 "GWEN: Error unloading library: %s",
143 dlerror());
144 return GWEN_ERROR_CLOSE;
145 }
146 h->handle=0;
147 return 0;
148 }
149
150
151
GWEN_LibLoader_Resolve(GWEN_LIBLOADER * h,const char * name,void ** p)152 int GWEN_LibLoader_Resolve(GWEN_LIBLOADER *h,
153 const char *name, void **p)
154 {
155 assert(h);
156 assert(name);
157 assert(p);
158
159 if (!h->handle)
160 return GWEN_ERROR_NOT_OPEN;
161 *p=dlsym(h->handle, name);
162 if (!*p) {
163 DBG_INFO(GWEN_LOGDOMAIN, "Error resolving symbol \"%s\": %s\n",
164 name, dlerror());
165 return GWEN_ERROR_COULD_NOT_RESOLVE;
166 }
167 DBG_VERBOUS(GWEN_LOGDOMAIN, "Resolved symbol \"%s\": %p\n",
168 name, *p);
169 return 0;
170 }
171
172
173
GWEN_LibLoader_OpenLibraryWithPath(GWEN_LIBLOADER * h,const char * path,const char * name)174 int GWEN_LibLoader_OpenLibraryWithPath(GWEN_LIBLOADER *h,
175 const char *path,
176 const char *name)
177 {
178 GWEN_BUFFER *buffer;
179 unsigned int pos;
180 unsigned int pos2;
181 unsigned int i;
182 int missingSoExt;
183 int missingLibPrefix;
184 int err;
185
186 assert(h);
187 assert(name);
188 missingSoExt=0;
189 missingLibPrefix=0;
190 buffer=GWEN_Buffer_new(0, 256, 0, 1);
191
192 if (path) {
193 GWEN_Buffer_AppendString(buffer, path);
194 GWEN_Buffer_AppendByte(buffer, '/');
195 }
196 /* remember current position */
197 pos=GWEN_Buffer_GetPos(buffer);
198 /* append name of the library to load */
199 GWEN_Buffer_AppendString(buffer, name);
200 i=strlen(name);
201
202 /* check whether we have the ".so" extension */
203 if ((i<=3) || (strcmp(name+i-3, ".so")!=0)) {
204 /* no SO-extension, add it myself */
205 missingSoExt=1;
206 }
207
208 /* check whether we have the "lib" prefix */
209 if ((i<=3) || (strncmp(name, "lib", 3)!=0)) {
210 /* no SO-extension, add it myself */
211 missingLibPrefix=1;
212 }
213
214 /* try to load the library */
215 err=GWEN_LibLoader_LoadLibrary(h, GWEN_Buffer_GetStart(buffer));
216 if (!err) {
217 DBG_INFO(GWEN_LOGDOMAIN, "Library \"%s\" loaded",
218 GWEN_Buffer_GetStart(buffer));
219 GWEN_Buffer_free(buffer);
220 return 0;
221 }
222
223 /* could not load, check why */
224 /*if (GWEN_Error_GetType(err)!=
225 GWEN_Error_FindType(GWEN_LIBLOADER_ERROR_TYPE) ||
226 GWEN_Error_GetCode(err)!=GWEN_LIBLOADER_ERROR_NOT_FOUND) {
227 DBG_ERROR_ERR(GWEN_LOGDOMAIN, err);
228 DBG_INFO(GWEN_LOGDOMAIN, "Could not load library \"%s\"",
229 GWEN_Buffer_GetStart(buffer));
230 GWEN_Buffer_free(buffer);
231 return err;
232 }
233 */
234
235 /* hmm, not found, try some variants */
236 if (missingSoExt) {
237 /* try again, this time with ".so" appended */
238 pos2=GWEN_Buffer_GetPos(buffer);
239 GWEN_Buffer_AppendString(buffer, ".so");
240 err=GWEN_LibLoader_LoadLibrary(h, GWEN_Buffer_GetStart(buffer));
241 if (!err) {
242 DBG_INFO(GWEN_LOGDOMAIN, "Library \"%s\" loaded",
243 GWEN_Buffer_GetStart(buffer));
244 GWEN_Buffer_free(buffer);
245 return 0;
246 }
247 GWEN_Buffer_Crop(buffer, 0, pos2);
248 GWEN_Buffer_SetPos(buffer, pos2);
249
250 /* could not load, check why */
251 if (err!=GWEN_ERROR_NOT_FOUND) {
252 DBG_INFO(GWEN_LOGDOMAIN, "Could not load library \"%s\"",
253 GWEN_Buffer_GetStart(buffer));
254 GWEN_Buffer_free(buffer);
255 return err;
256 }
257 }
258
259 if (missingLibPrefix) {
260 GWEN_Buffer_SetPos(buffer, pos);
261 /* insert "lib" */
262 GWEN_Buffer_InsertString(buffer, "lib");
263 /* try again */
264 err=GWEN_LibLoader_LoadLibrary(h, GWEN_Buffer_GetStart(buffer));
265 if (!err) {
266 DBG_INFO(GWEN_LOGDOMAIN, "Library \"%s\" loaded",
267 GWEN_Buffer_GetStart(buffer));
268 GWEN_Buffer_free(buffer);
269 return 0;
270 }
271
272 /* could not load, check why */
273 if (err!=GWEN_ERROR_NOT_FOUND) {
274 DBG_INFO(GWEN_LOGDOMAIN, "Could not load library \"%s\"",
275 GWEN_Buffer_GetStart(buffer));
276 GWEN_Buffer_free(buffer);
277 return err;
278 }
279
280 /* try again, this time with ".so" AND "lib" */
281 if (missingSoExt) {
282 GWEN_Buffer_AppendString(buffer, ".so");
283 err=GWEN_LibLoader_LoadLibrary(h, GWEN_Buffer_GetStart(buffer));
284 if (!err) {
285 DBG_INFO(GWEN_LOGDOMAIN, "Library \"%s\" loaded",
286 GWEN_Buffer_GetStart(buffer));
287 GWEN_Buffer_free(buffer);
288 return 0;
289 }
290 }
291 }
292
293 DBG_INFO(GWEN_LOGDOMAIN, "Library \"%s\" name (or variants) not found, giving up",
294 name);
295 GWEN_Buffer_free(buffer);
296 return err;
297 }
298
299
300
GWEN_LibLoader_OpenLibrary(GWEN_LIBLOADER * h,const char * name)301 int GWEN_LibLoader_OpenLibrary(GWEN_LIBLOADER *h,
302 const char *name)
303 {
304 return GWEN_LibLoader_OpenLibraryWithPath(h, 0, name);
305 }
306
307
308
309
310
311
312
313
314