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