1/*
2 * xmlmodule.c : basic API for dynamic module loading added 2.6.17
3 *
4 * See Copyright for the status of this software.
5 *
6 * joelwreed@comcast.net
7 *
8 * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
9 */
10
11#define IN_LIBXML
12#include "libxml.h"
13
14#include <string.h>
15#include <libxml/xmlmemory.h>
16#include <libxml/xmlerror.h>
17#include <libxml/xmlmodule.h>
18#include <libxml/globals.h>
19
20#ifdef LIBXML_MODULES_ENABLED
21
22struct _xmlModule {
23    unsigned char *name;
24    void *handle;
25};
26
27static void *xmlModulePlatformOpen(const char *name);
28static int xmlModulePlatformClose(void *handle);
29static int xmlModulePlatformSymbol(void *handle, const char *name, void **result);
30
31/************************************************************************
32 *									*
33 *		module memory error handler				*
34 *									*
35 ************************************************************************/
36
37/**
38 * xmlModuleErrMemory:
39 * @extra:  extra information
40 *
41 * Handle an out of memory condition
42 */
43static void
44xmlModuleErrMemory(xmlModulePtr module, const char *extra)
45{
46    const char *name = NULL;
47
48    if (module != NULL) {
49        name = (const char *) module->name;
50    }
51
52    __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
53                    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
54                    name, NULL, 0, 0,
55                    "Memory allocation failed : %s\n", extra);
56}
57
58/**
59 * xmlModuleOpen:
60 * @name: the module name
61 * @options: a set of xmlModuleOption
62 *
63 * Opens a module/shared library given its name or path
64 * NOTE: that due to portability issues, behaviour can only be
65 * guaranteed with @name using ASCII. We canot guarantee that
66 * an UTF-8 string would work, which is why name is a const char *
67 * and not a const xmlChar * .
68 * TODO: options are not yet implemented.
69 *
70 * Returns a handle for the module or NULL in case of error
71 */
72xmlModulePtr
73xmlModuleOpen(const char *name, int options ATTRIBUTE_UNUSED)
74{
75    xmlModulePtr module;
76
77    module = (xmlModulePtr) xmlMalloc(sizeof(xmlModule));
78    if (module == NULL) {
79        xmlModuleErrMemory(NULL, "creating module");
80        return (NULL);
81    }
82
83    memset(module, 0, sizeof(xmlModule));
84
85    module->handle = xmlModulePlatformOpen(name);
86
87    if (module->handle == NULL) {
88        xmlFree(module);
89        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
90                        XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0,
91                        name, NULL, 0, 0, "failed to open %s\n", name);
92        return(NULL);
93    }
94
95    module->name = xmlStrdup((const xmlChar *) name);
96    return (module);
97}
98
99/**
100 * xmlModuleSymbol:
101 * @module: the module
102 * @name: the name of the symbol
103 * @symbol: the resulting symbol address
104 *
105 * Lookup for a symbol address in the given module
106 * NOTE: that due to portability issues, behaviour can only be
107 * guaranteed with @name using ASCII. We canot guarantee that
108 * an UTF-8 string would work, which is why name is a const char *
109 * and not a const xmlChar * .
110 *
111 * Returns 0 if the symbol was found, or -1 in case of error
112 */
113int
114xmlModuleSymbol(xmlModulePtr module, const char *name, void **symbol)
115{
116    int rc = -1;
117
118    if ((NULL == module) || (symbol == NULL)) {
119        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
120                        XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0,
121                        NULL, NULL, 0, 0, "null parameter\n");
122        return rc;
123    }
124
125    rc = xmlModulePlatformSymbol(module->handle, name, symbol);
126
127    if (rc == -1) {
128        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
129                        XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0,
130                        name, NULL, 0, 0,
131                        "failed to find symbol: %s\n",
132			(name == NULL ? "NULL" : name));
133        return rc;
134    }
135
136    return rc;
137}
138
139/**
140 * xmlModuleClose:
141 * @module: the module handle
142 *
143 * The close operations unload the associated module and free the
144 * data associated to the module.
145 *
146 * Returns 0 in case of success, -1 in case of argument error and -2
147 *         if the module could not be closed/unloaded.
148 */
149int
150xmlModuleClose(xmlModulePtr module)
151{
152    int rc;
153
154    if (NULL == module) {
155        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
156                        XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, 0,
157                        NULL, NULL, 0, 0, "null module pointer\n");
158        return -1;
159    }
160
161    rc = xmlModulePlatformClose(module->handle);
162
163    if (rc != 0) {
164        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
165                        XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, 0,
166                        (const char *) module->name, NULL, 0, 0,
167                        "failed to close: %s\n", module->name);
168        return -2;
169    }
170
171    rc = xmlModuleFree(module);
172    return (rc);
173}
174
175/**
176 * xmlModuleFree:
177 * @module: the module handle
178 *
179 * The free operations free the data associated to the module
180 * but does not unload the associated shared library which may still
181 * be in use.
182 *
183 * Returns 0 in case of success, -1 in case of argument error
184 */
185int
186xmlModuleFree(xmlModulePtr module)
187{
188    if (NULL == module) {
189        __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE,
190                        XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, NULL,
191                        NULL, NULL, 0, 0, "null module pointer\n");
192        return -1;
193    }
194
195    xmlFree(module->name);
196    xmlFree(module);
197
198    return (0);
199}
200
201#if defined(HAVE_DLOPEN) && !defined(_WIN32)
202#ifdef HAVE_DLFCN_H
203#include <dlfcn.h>
204#endif
205
206#ifndef RTLD_GLOBAL            /* For Tru64 UNIX 4.0 */
207#define RTLD_GLOBAL 0
208#endif
209
210/**
211 * xmlModulePlatformOpen:
212 * @name: path to the module
213 *
214 * returns a handle on success, and zero on error.
215 */
216
217static void *
218xmlModulePlatformOpen(const char *name)
219{
220    return dlopen(name, RTLD_GLOBAL | RTLD_NOW);
221}
222
223/*
224 * xmlModulePlatformClose:
225 * @handle: handle to the module
226 *
227 * returns 0 on success, and non-zero on error.
228 */
229
230static int
231xmlModulePlatformClose(void *handle)
232{
233    return dlclose(handle);
234}
235
236/*
237 * xmlModulePlatformSymbol:
238 * http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html
239 * returns 0 on success and the loaded symbol in result, and -1 on error.
240 */
241
242static int
243xmlModulePlatformSymbol(void *handle, const char *name, void **symbol)
244{
245    *symbol = dlsym(handle, name);
246    if (dlerror() != NULL) {
247	return -1;
248    }
249    return 0;
250}
251
252#else /* ! HAVE_DLOPEN */
253
254#ifdef HAVE_SHLLOAD             /* HAVE_SHLLOAD */
255#ifdef HAVE_DL_H
256#include <dl.h>
257#endif
258/*
259 * xmlModulePlatformOpen:
260 * returns a handle on success, and zero on error.
261 */
262
263static void *
264xmlModulePlatformOpen(const char *name)
265{
266    return shl_load(name, BIND_IMMEDIATE, 0L);
267}
268
269/*
270 * xmlModulePlatformClose:
271 * returns 0 on success, and non-zero on error.
272 */
273
274static int
275xmlModulePlatformClose(void *handle)
276{
277    return shl_unload(handle);
278}
279
280/*
281 * xmlModulePlatformSymbol:
282 * http://docs.hp.com/en/B2355-90683/shl_load.3X.html
283 * returns 0 on success and the loaded symbol in result, and -1 on error.
284 */
285
286static int
287xmlModulePlatformSymbol(void *handle, const char *name, void **symbol)
288{
289    int rc;
290
291    errno = 0;
292    rc = shl_findsym(&handle, name, TYPE_UNDEFINED, symbol);
293    return rc;
294}
295
296#endif /* HAVE_SHLLOAD */
297#endif /* ! HAVE_DLOPEN */
298
299#ifdef _WIN32
300
301#include <windows.h>
302
303/*
304 * xmlModulePlatformOpen:
305 * returns a handle on success, and zero on error.
306 */
307
308static void *
309xmlModulePlatformOpen(const char *name)
310{
311    return LoadLibraryA(name);
312}
313
314/*
315 * xmlModulePlatformClose:
316 * returns 0 on success, and non-zero on error.
317 */
318
319static int
320xmlModulePlatformClose(void *handle)
321{
322    int rc;
323
324    rc = FreeLibrary(handle);
325    return (0 == rc);
326}
327
328/*
329 * xmlModulePlatformSymbol:
330 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp
331 * returns 0 on success and the loaded symbol in result, and -1 on error.
332 */
333
334static int
335xmlModulePlatformSymbol(void *handle, const char *name, void **symbol)
336{
337#ifdef _WIN32_WCE
338    /*
339     * GetProcAddressA seems only available on WinCE
340     */
341    *symbol = GetProcAddressA(handle, name);
342#else
343    *symbol = GetProcAddress(handle, name);
344#endif
345    return (NULL == *symbol) ? -1 : 0;
346}
347
348#endif /* _WIN32 */
349
350#ifdef HAVE_BEOS
351
352#include <kernel/image.h>
353
354/*
355 * xmlModulePlatformOpen:
356 * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html
357 * returns a handle on success, and zero on error.
358 */
359
360static void *
361xmlModulePlatformOpen(const char *name)
362{
363    return (void *) load_add_on(name);
364}
365
366/*
367 * xmlModulePlatformClose:
368 * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html
369 * returns 0 on success, and non-zero on error.
370 */
371
372static int
373xmlModulePlatformClose(void *handle)
374{
375    status_t rc;
376
377    rc = unload_add_on((image_id) handle);
378
379    if (rc == B_OK)
380        return 0;
381    else
382        return -1;
383}
384
385/*
386 * xmlModulePlatformSymbol:
387 * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html
388 * returns 0 on success and the loaded symbol in result, and -1 on error.
389 */
390
391static int
392xmlModulePlatformSymbol(void *handle, const char *name, void **symbol)
393{
394    status_t rc;
395
396    rc = get_image_symbol((image_id) handle, name, B_SYMBOL_TYPE_ANY, symbol);
397
398    return (rc == B_OK) ? 0 : -1;
399}
400
401#endif /* HAVE_BEOS */
402
403#ifdef HAVE_OS2
404
405#include <os2.h>
406
407/*
408 * xmlModulePlatformOpen:
409 * os2 api info: http://www.edm2.com/os2api/Dos/DosLoadModule.html
410 * returns a handle on success, and zero on error.
411 */
412
413static void *
414xmlModulePlatformOpen(const char *name)
415{
416    char errbuf[256];
417    void *handle;
418    int rc;
419
420    rc = DosLoadModule(errbuf, sizeof(errbuf) - 1, name, &handle);
421
422    if (rc)
423        return 0;
424    else
425        return (handle);
426}
427
428/*
429 * xmlModulePlatformClose:
430 * os2 api info: http://www.edm2.com/os2api/Dos/DosFreeModule.html
431 * returns 0 on success, and non-zero on error.
432 */
433
434static int
435xmlModulePlatformClose(void *handle)
436{
437    return DosFreeModule(handle);
438}
439
440/*
441 * xmlModulePlatformSymbol:
442 * os2 api info: http://www.edm2.com/os2api/Dos/DosQueryProcAddr.html
443 * returns 0 on success and the loaded symbol in result, and -1 on error.
444 */
445
446static int
447xmlModulePlatformSymbol(void *handle, const char *name, void **symbol)
448{
449    int rc;
450
451    rc = DosQueryProcAddr(handle, 0, name, symbol);
452
453    return (rc == NO_ERROR) ? 0 : -1;
454}
455
456#endif /* HAVE_OS2 */
457
458#define bottom_xmlmodule
459#include "elfgcchack.h"
460#endif /* LIBXML_MODULES_ENABLED */
461