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