]> git.saurik.com Git - wxWidgets.git/blame - src/iodbc/dlf.c
Fix for probably rare but potential refcount leak.
[wxWidgets.git] / src / iodbc / dlf.c
CommitLineData
cd5bf2a6
RR
1/*
2 * dlf.c
3 *
4 * $Id$
5 *
6 * Dynamic Library Loader (mapping to SVR4)
7 *
8 * The iODBC driver manager.
9 *
10 * Copyright (C) 1995 by Ke Jin <kejin@empress.com>
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the Free
24 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
1a6944fd 26
88ac883a 27#include "dlf.h"
1a6944fd
RR
28#include <errno.h>
29
cd5bf2a6
RR
30#ifdef DLDAPI_DEFINED
31#undef DLDAPI_DEFINED
1a6944fd
RR
32#endif
33
cd5bf2a6
RR
34#ifdef DLDAPI_SVR4_DLFCN
35#define DLDAPI_DEFINED
36static char sccsid[] = "@(#)dynamic load interface -- SVR4 dlfcn";
1a6944fd
RR
37#endif
38
cd5bf2a6 39/*********************************
1a6944fd 40 *
cd5bf2a6 41 * HP/UX
1a6944fd
RR
42 *
43 *********************************/
1a6944fd 44
cd5bf2a6
RR
45#ifdef DLDAPI_HP_SHL
46#define DLDAPI_DEFINED
47#include <dl.h>
1a6944fd 48
cd5bf2a6
RR
49static char sccsid[] = "@(#)dynamic load interface -- HP/UX dl(shl)";
50
51void *
52dlopen (char *path, int mode)
1a6944fd 53{
cd5bf2a6 54 return (void *) shl_load ((char *) (path), BIND_DEFERRED, 0L);
1a6944fd
RR
55}
56
cd5bf2a6
RR
57
58void *
59dlsym (void *hdll, char *sym)
1a6944fd 60{
cd5bf2a6
RR
61 void *symaddr = 0;
62 int ret;
1a6944fd 63
cd5bf2a6
RR
64 if (!hdll)
65 hdll = (void *) PROG_HANDLE;
1a6944fd 66
cd5bf2a6
RR
67 /* Remember, a driver may export calls as function pointers
68 * (i.e. with type TYPE_DATA) rather than as functions
69 * (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we
70 * uses TYPE_UNDEFINED to cover all of them.
71 */
72 ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr);
1a6944fd 73
cd5bf2a6
RR
74 if (ret == -1)
75 return 0;
1a6944fd 76
cd5bf2a6 77 return symaddr;
1a6944fd
RR
78}
79
cd5bf2a6
RR
80
81char *
82dlerror ()
1a6944fd 83{
cd5bf2a6 84 extern char *strerror ();
1a6944fd 85
cd5bf2a6 86 return strerror (errno);
1a6944fd
RR
87}
88
cd5bf2a6
RR
89
90int
91dlclose (void *hdll)
1a6944fd 92{
cd5bf2a6 93 return shl_unload ((shl_t) hdll);
1a6944fd 94}
cd5bf2a6 95#endif /* end of HP/UX Seection */
1a6944fd 96
1a6944fd
RR
97
98/*********************************
99 *
cd5bf2a6 100 * IBM AIX
1a6944fd
RR
101 *
102 *********************************/
cd5bf2a6
RR
103
104#ifdef DLDAPI_AIX_LOAD
105#define DLDAPI_DEFINED
106#include <sys/types.h>
107#include <sys/ldr.h>
108#include <sys/stat.h>
109#include <nlist.h>
1a6944fd
RR
110
111/*
cd5bf2a6 112 * Following id sting is a copyright mark. Removing(i.e. use the
1a6944fd 113 * source code in this .c file without include it or make it not
cd5bf2a6
RR
114 * appear in the final object file of AIX platform) or modifing
115 * it without permission from original author(kejin@empress.com)
1a6944fd
RR
116 * are copyright violation.
117 */
cd5bf2a6
RR
118static char sccsid[]
119= "@(#)dynamic load interface, Copyright(c) 1995 by Ke Jin";
1a6944fd 120
cd5bf2a6
RR
121#ifndef HTAB_SIZE
122#define HTAB_SIZE 256
123#endif
1a6944fd 124
cd5bf2a6 125#define FACTOR 0.618039887 /* i.e. (sqrt(5) - 1)/2 */
1a6944fd 126
cd5bf2a6
RR
127#ifndef ENTRY_SYM
128#define ENTRY_SYM ".__start" /* default entry point for aix */
129#endif
1a6944fd
RR
130
131typedef struct slot_s
cd5bf2a6
RR
132 {
133 char *sym;
134 long fdesc[3]; /* 12 bytes function descriptor */
135 struct slot_s *next;
136 }
137slot_t;
1a6944fd
RR
138
139/* Note: on AIX, a function pointer actually points to a
140 * function descriptor, a 12 bytes data. The first 4 bytes
cd5bf2a6 141 * is the virtual address of the function. The next 4 bytes
1a6944fd 142 * is the virtual address of TOC (Table of Contents) of the
cd5bf2a6
RR
143 * object module the function belong to. The last 4 bytes
144 * are always 0 for C and Fortran functions. Every object
1a6944fd
RR
145 * module has an entry point (which can be specified at link
146 * time by -e ld option). iODBC driver manager requires ODBC
147 * driver shared library always use the default entry point
148 * (so you shouldn't use -e ld option when creating a driver
cd5bf2a6 149 * share library). load() returns the function descriptor of
1a6944fd
RR
150 * a module's entry point. From which we can calculate function
151 * descriptors of other functions in the same module by using
cd5bf2a6
RR
152 * the fact that the load() doesn't change the relative
153 * offset of functions to their module entry point(i.e the
154 * offset in memory loaded by load() will be as same as in
155 * the module library file).
1a6944fd
RR
156 */
157
cd5bf2a6
RR
158typedef slot_t *hent_t;
159typedef struct nlist nlist_t;
160typedef struct stat stat_t;
1a6944fd 161
7e616b10 162typedef struct obj
cd5bf2a6
RR
163 {
164 int dev; /* device id */
165 int ino; /* inode number */
166 char *path; /* file name */
167 int (*pentry) (); /* entry point of this share library */
168 int refn; /* number of reference */
169 hent_t htab[HTAB_SIZE];
170 struct obj * next;
171 }
172obj_t;
173
174static char *errmsg = 0;
175
176static void
177init_htab (hent_t * ht)
1a6944fd
RR
178/* initate a hashing table */
179{
cd5bf2a6 180 int i;
1a6944fd 181
cd5bf2a6
RR
182 for (i = 0; i < HTAB_SIZE; i++)
183 ht[i] = (slot_t *) 0;
1a6944fd 184
cd5bf2a6 185 return;
1a6944fd
RR
186}
187
cd5bf2a6
RR
188
189static void
190clean_htab (hent_t * ht)
1a6944fd
RR
191/* free all slots */
192{
cd5bf2a6
RR
193 int i;
194 slot_t *ent;
195 slot_t *tent;
7e616b10 196
cd5bf2a6
RR
197 for (i = 0; i < HTAB_SIZE; i++)
198 {
199 for (ent = ht[i]; ent;)
200 {
201 tent = ent->next;
7e616b10 202
cd5bf2a6
RR
203 free (ent->sym);
204 free (ent);
7e616b10 205
cd5bf2a6
RR
206 ent = tent;
207 }
7e616b10 208
cd5bf2a6
RR
209 ht[i] = 0;
210 }
7e616b10 211
cd5bf2a6 212 return;
1a6944fd
RR
213}
214
cd5bf2a6
RR
215
216static int
217hash (char *sym)
1a6944fd 218{
cd5bf2a6
RR
219 int a, key;
220 double f;
1a6944fd 221
cd5bf2a6
RR
222 if (!sym || !*sym)
223 return 0;
1a6944fd 224
cd5bf2a6
RR
225 for (key = *sym; *sym; sym++)
226 {
227 key += *sym;
228 a = key;
1a6944fd 229
cd5bf2a6
RR
230 key = (int) ((a << 8) + (key >> 8));
231 key = (key > 0) ? key : -key;
232 }
1a6944fd 233
cd5bf2a6
RR
234 f = key * FACTOR;
235 a = (int) f;
1a6944fd 236
cd5bf2a6 237 return (int) ((HTAB_SIZE - 1) * (f - a));
1a6944fd
RR
238}
239
cd5bf2a6
RR
240
241static hent_t
242search (hent_t * htab, char *sym)
1a6944fd
RR
243/* search hashing table to find a matched slot */
244{
cd5bf2a6
RR
245 int key;
246 slot_t *ent;
1a6944fd 247
cd5bf2a6 248 key = hash (sym);
1a6944fd 249
cd5bf2a6
RR
250 for (ent = htab[key]; ent; ent = ent->next)
251 {
252 if (!strcmp (ent->sym, sym))
253 return ent;
254 }
1a6944fd 255
cd5bf2a6 256 return 0; /* no match */
1a6944fd
RR
257}
258
cd5bf2a6
RR
259
260static void
261insert (hent_t * htab, slot_t * ent)
1a6944fd
RR
262/* insert a new slot to hashing table */
263{
cd5bf2a6 264 int key;
1a6944fd 265
cd5bf2a6 266 key = hash (ent->sym);
1a6944fd 267
cd5bf2a6
RR
268 ent->next = htab[key];
269 htab[key] = ent;
1a6944fd 270
cd5bf2a6 271 return;
1a6944fd
RR
272}
273
cd5bf2a6
RR
274
275static slot_t *
276slot_alloc (char *sym)
1a6944fd
RR
277/* allocate a new slot with symbol */
278{
cd5bf2a6 279 slot_t *ent;
1a6944fd 280
cd5bf2a6 281 ent = (slot_t *) malloc (sizeof (slot_t));
1a6944fd 282
cd5bf2a6 283 ent->sym = (char *) malloc (strlen (sym) + 1);
1a6944fd 284
cd5bf2a6
RR
285 if (!ent->sym)
286 {
287 free (ent);
288 return 0;
289 }
1a6944fd 290
cd5bf2a6 291 strcpy (ent->sym, sym);
1a6944fd 292
cd5bf2a6 293 return ent;
1a6944fd
RR
294}
295
1a6944fd 296
cd5bf2a6 297static obj_t *obj_list = 0;
1a6944fd 298
cd5bf2a6
RR
299void *
300dlopen (char *file, int mode)
301{
302 stat_t st;
303 obj_t *pobj;
304 char buf[1024];
305
306 if (!file || !*file)
307 {
308 errno = EINVAL;
309 return 0;
310 }
311
312 errno = 0;
313 errmsg = 0;
314
315 if (stat (file, &st))
316 return 0;
317
318 for (pobj = obj_list; pobj; pobj = pobj->next)
319 /* find a match object */
320 {
321 if (pobj->ino == st.st_ino
322 && pobj->dev == st.st_dev)
323 {
324 /* found a match. increase its
325 * reference count and return
326 * its address */
327 pobj->refn++;
328 return pobj;
329 }
330 }
331
332 pobj = (obj_t *) malloc (sizeof (obj_t));
333
334 if (!pobj)
335 return 0;
336
337 pobj->path = (char *) malloc (strlen (file) + 1);
338
339 if (!pobj->path)
340 {
341 free (pobj);
342 return 0;
343 }
344
345 strcpy (pobj->path, file);
346
347 pobj->dev = st.st_dev;
348 pobj->ino = st.st_ino;
349 pobj->refn = 1;
350
351 pobj->pentry = (int (*)()) load (file, 0, 0);
352
353 if (!pobj->pentry)
354 {
355 free (pobj->path);
356 free (pobj);
357 return 0;
358 }
359
360 init_htab (pobj->htab);
361
362 pobj->next = obj_list;
363 obj_list = pobj;
364
365 return pobj;
1a6944fd
RR
366}
367
cd5bf2a6
RR
368
369int
370dlclose (void *hobj)
1a6944fd 371{
cd5bf2a6
RR
372 obj_t *pobj = (obj_t *) hobj;
373 obj_t *tpobj;
374 int match = 0;
375
376 if (!hobj)
377 {
378 errno = EINVAL;
379 return -1;
380 }
381
382 errno = 0;
383 errmsg = 0;
384
385 if (pobj == obj_list)
386 {
387 pobj->refn--;
388
389 if (pobj->refn)
390 return 0;
391
392 match = 1;
393 obj_list = pobj->next;
394 }
395
396 for (tpobj = obj_list; !match && tpobj; tpobj = tpobj->next)
397 {
398 if (tpobj->next == pobj)
399 {
400 pobj->refn--;
401
402 if (pobj->refn)
403 return 0;
404
405 match = 1;
406 tpobj->next = pobj->next;
407 }
408 }
409
410 if (match)
411 {
412 unload ((void *) (pobj->pentry));
413 clean_htab (pobj->htab);
414 free (pobj->path);
415 free (pobj);
416 }
417
418 return 0;
1a6944fd
RR
419}
420
cd5bf2a6
RR
421
422char *
423dlerror ()
1a6944fd 424{
cd5bf2a6 425 extern char *sys_errlist[];
1a6944fd 426
cd5bf2a6
RR
427 if (!errmsg || !errmsg[0])
428 {
429 if (errno >= 0)
430 return sys_errlist[errno];
7e616b10 431
cd5bf2a6
RR
432 return "";
433 }
1a6944fd 434
cd5bf2a6 435 return errmsg;
1a6944fd
RR
436}
437
cd5bf2a6
RR
438
439void *
440dlsym (void *hdl, char *sym)
1a6944fd 441{
cd5bf2a6
RR
442 nlist_t nl[3];
443 obj_t *pobj = (obj_t *) hdl;
444 slot_t *ent;
445 int (*fp) ();
446 long lbuf[3];
447
448 if (!hdl || !(pobj->htab) || !sym || !*sym)
449 {
450 errno = EINVAL;
451 return 0;
452 }
453
454 errno = 0;
455 errmsg = 0;
456
457 ent = search (pobj->htab, sym);
458
459 if (ent)
460 return ent->fdesc;
461
462#define n_name _n._n_name
463
464 nl[0].n_name = ENTRY_SYM;
465 nl[1].n_name = sym;
466 nl[2].n_name = 0;
467
468 /* There is a potential problem here. If application
469 * did not pass a full path name, and changed the
470 * working directory after the load(), then nlist()
471 * will be unable to open the original shared library
472 * file to resolve the symbols. there are 3 ways to working
473 * round this: 1. convert to full pathname in driver
474 * manager. 2. applications always pass driver's full
475 * path name. 3. if driver itself don't support
476 * SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS
477 * as flag immidately after SQLConnect(), SQLDriverConnect()
478 * and SQLBrowseConnect() to force the driver manager
479 * resolving all will be used symbols.
480 */
481 if (nlist (pobj->path, nl) == -1)
482 return 0;
483
484 if (!nl[0].n_type && !nl[0].n_value)
485 {
486 errmsg = "can't locate module entry symbol";
487 return 0;
488 }
489
490 /* Note: On AIX 3.x if the object library is not
491 * built with -g compiling option, .n_type field
492 * is always 0. While on 4.x it will be 32.
493 * On AIX 4.x, if the symbol is a entry point,
494 * n_value will be 0. However, one thing is for sure
495 * that if a symbol is not existance in the file,
496 * both .n_type and .n_value would be 0.
497 */
498
499 if (!nl[1].n_type && !nl[1].n_value)
500 {
501 errmsg = "symbol not existance in this module";
502 return 0;
503 }
504
505 ent = slot_alloc (sym);
506
507 if (!ent)
508 return 0;
509
510 /* catch it with a slot in the hashing table */
511 insert (pobj->htab, ent);
512
513 memcpy (ent->fdesc, pobj->pentry, sizeof (ent->fdesc));
514
515 /* now ent->fdesc[0] is the virtual address of entry point
516 * and ent->fdesc[1] is the TOC of the module
517 */
518
519 /* let's calculate the virtual address of the symbol
520 * by adding a relative offset getting from the module
521 * file symbol table, i.e
522 *
523 * functin virtual address = entry point virtual address +
524 * + ( function offset in file - entry point offset in file )
525 */
526
527 (ent->fdesc)[0] = (ent->fdesc)[0] +
528 (nl[1].n_value - nl[0].n_value);
529
530 /* return the function descriptor */
531 return ent->fdesc;
1a6944fd 532}
cd5bf2a6 533#endif /* end of IBM AIX Section */
1a6944fd
RR
534
535
cd5bf2a6 536/*********************************
1a6944fd 537 *
cd5bf2a6 538 * Windows 3.x, 95, NT
1a6944fd
RR
539 *
540 *********************************/
1a6944fd 541
cd5bf2a6
RR
542#ifdef DLDAPI_WINDOWS
543#define DLDAPI_DEFINED
544#include <windows.h>
1a6944fd 545
cd5bf2a6
RR
546void FAR *
547dlopen (char FAR * dll, int mode)
548{
549 HINSTANCE hint;
1a6944fd 550
cd5bf2a6
RR
551 if (dll == NULL)
552 {
553 return GetWindowWord (NULL, GWW_HINSTANCE);
554 }
1a6944fd 555
cd5bf2a6 556 hint = LoadLibrary (dll);
1a6944fd 557
cd5bf2a6
RR
558 if (hint < HINSTANCE_ERROR)
559 {
560 return NULL;
561 }
1a6944fd 562
cd5bf2a6 563 return (void FAR *) hint;
1a6944fd
RR
564}
565
1a6944fd 566
cd5bf2a6
RR
567void FAR *
568dlsym (void FAR * hdll, char FAR * sym)
1a6944fd 569{
cd5bf2a6 570 return (void FAR *) GetProcAddress (hdll, sym);
1a6944fd
RR
571}
572
1a6944fd 573
cd5bf2a6
RR
574char FAR *
575dlerror ()
7e616b10 576{
cd5bf2a6 577 return 0L; /* unimplemented yet */
7e616b10
RR
578}
579
7e616b10 580
cd5bf2a6
RR
581int
582dlclose (void FAR * hdll)
7e616b10 583{
cd5bf2a6 584 FreeLibrary ((HINSTANCE) hdll);
7e616b10 585}
cd5bf2a6 586#endif /* end of Windows family */
7e616b10 587
7e616b10
RR
588
589/***********************************
590 *
cd5bf2a6 591 * other platforms
7e616b10
RR
592 *
593 ***********************************/
cd5bf2a6
RR
594
595#ifdef DLDAPI_OS2
596#define DLDAPI_DEFINED
597/*
598 * DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ...
599 */
600#endif
601
602#ifdef DLDAPI_MAC
603#define DLDAPI_DEFINED
1a6944fd
RR
604#endif
605
606#ifdef DLDAPI_NEXT
cd5bf2a6 607#define DLDAPI_DEFINED
1a6944fd
RR
608#endif
609
610#ifndef DLDAPI_DEFINED
cd5bf2a6 611#error "dynamic load editor undefined"
1a6944fd 612#endif