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