1/*
2 *  dlf.c
3 *
4 *  $Id: dlf.c,v 1.4 2006/02/13 16:01:41 source Exp $
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 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
12 *  All Rights Reserved.
13 *
14 *  This software is released under the terms of either of the following
15 *  licenses:
16 *
17 *      - GNU Library General Public License (see LICENSE.LGPL)
18 *      - The BSD License (see LICENSE.BSD).
19 *
20 *  Note that the only valid version of the LGPL license as far as this
21 *  project is concerned is the original GNU Library General Public License
22 *  Version 2, dated June 1991.
23 *
24 *  While not mandated by the BSD license, any patches you make to the
25 *  iODBC source code may be contributed back into the iODBC project
26 *  at your discretion. Contributions will benefit the Open Source and
27 *  Data Access community as a whole. Submissions may be made at:
28 *
29 *      http://www.iodbc.org
30 *
31 *
32 *  GNU Library Generic Public License Version 2
33 *  ============================================
34 *  This library is free software; you can redistribute it and/or
35 *  modify it under the terms of the GNU Library General Public
36 *  License as published by the Free Software Foundation; only
37 *  Version 2 of the License dated June 1991.
38 *
39 *  This library is distributed in the hope that it will be useful,
40 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
41 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42 *  Library General Public License for more details.
43 *
44 *  You should have received a copy of the GNU Library General Public
45 *  License along with this library; if not, write to the Free
46 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
47 *
48 *
49 *  The BSD License
50 *  ===============
51 *  Redistribution and use in source and binary forms, with or without
52 *  modification, are permitted provided that the following conditions
53 *  are met:
54 *
55 *  1. Redistributions of source code must retain the above copyright
56 *     notice, this list of conditions and the following disclaimer.
57 *  2. Redistributions in binary form must reproduce the above copyright
58 *     notice, this list of conditions and the following disclaimer in
59 *     the documentation and/or other materials provided with the
60 *     distribution.
61 *  3. Neither the name of OpenLink Software Inc. nor the names of its
62 *     contributors may be used to endorse or promote products derived
63 *     from this software without specific prior written permission.
64 *
65 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
66 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
67 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
68 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
69 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
70 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
71 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
72 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
73 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
74 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
75 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
76 */
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92#include <dlf.h>
93#include <errno.h>
94
95#ifdef	DLDAPI_DEFINED
96#undef DLDAPI_DEFINED
97#endif
98
99#ifdef	DLDAPI_SVR4_DLFCN
100#define DLDAPI_DEFINED
101static char sccsid[] = "@(#)dynamic load interface -- SVR4 (dlfcn)";
102#endif
103
104/*********************************
105 *
106 *	HP/UX
107 *
108 *********************************/
109
110#ifdef	DLDAPI_HP_SHL
111#define	DLDAPI_DEFINED
112static char sccsid[] = "@(#)dynamic load interface -- HP/UX (shl)";
113
114#include <dl.h>
115
116
117void *
118dlopen (char *path, int mode)
119{
120  return (void *) shl_load ((char *) (path), BIND_IMMEDIATE | BIND_NONFATAL, 0L);
121}
122
123
124void *
125dlsym (void *hdll, char *sym)
126{
127  void *symaddr = 0;
128  int ret;
129
130#if 0
131  /*
132   *  iODBC does not need a handle to itself
133   */
134  if (!hdll)
135    hdll = (void *) PROG_HANDLE;
136#endif
137
138  /* Remember, a driver may export calls as function pointers
139   * (i.e. with type TYPE_DATA) rather than as functions
140   * (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we
141   * uses TYPE_UNDEFINED to cover all of them.
142   */
143  ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr);
144
145  if (ret == -1)
146    return 0;
147
148  return symaddr;
149}
150
151
152char *
153dlerror ()
154{
155  extern char *strerror ();
156
157  return strerror (errno);
158}
159
160
161int
162dlclose (void *hdll)
163{
164  struct shl_descriptor d;
165
166  /*
167   *  As HP/UX does not use a reference counter for unloading,
168   *  we can only unload the driver when it is loaded once.
169   */
170  if (shl_gethandle_r ((shl_t) hdll, &d) < 0 || d.ref_count > 1)
171  {
172    return 0;
173  }
174
175  return shl_unload ((shl_t) hdll);
176}
177#endif /* end of HP/UX Section */
178
179
180/*********************************
181 *
182 *	IBM AIX
183 *
184 *********************************/
185
186#ifdef	DLDAPI_AIX_LOAD
187#define	DLDAPI_DEFINED
188static char sccsid[] = "@(#)dynamic load interface -- AIX (ldr)";
189
190#include <sys/types.h>
191#include <sys/ldr.h>
192#include <sys/stat.h>
193#include <nlist.h>
194
195#ifndef	HTAB_SIZE
196#define	HTAB_SIZE	256
197#endif
198
199#define	FACTOR		0.618039887	/* i.e. (sqrt(5) - 1)/2 */
200
201#ifndef	ENTRY_SYM
202#define	ENTRY_SYM	".__start"	/* default entry point for aix */
203#endif
204
205typedef struct slot_s
206{
207  char *sym;
208  long fdesc[3];		/* 12 bytes function descriptor */
209  struct slot_s *next;
210}
211slot_t;
212
213/* Note: on AIX, a function pointer actually points to a
214 * function descriptor, a 12 bytes data. The first 4 bytes
215 * is the virtual address of the function. The next 4 bytes
216 * is the virtual address of TOC (Table of Contents) of the
217 * object module the function belong to. The last 4 bytes
218 * are always 0 for C and Fortran functions. Every object
219 * module has an entry point (which can be specified at link
220 * time by -e ld option). iODBC driver manager requires ODBC
221 * driver shared library always use the default entry point
222 * (so you shouldn't use -e ld option when creating a driver
223 * share library). load() returns the function descriptor of
224 * a module's entry point. From which we can calculate function
225 * descriptors of other functions in the same module by using
226 * the fact that the load() doesn't change the relative
227 * offset of functions to their module entry point(i.e the
228 * offset in memory loaded by load() will be as same as in
229 * the module library file).
230 */
231
232typedef slot_t *hent_t;
233typedef struct nlist nlist_t;
234typedef struct stat stat_t;
235
236typedef struct obj
237  {
238    int dev;			/* device id */
239    int ino;			/* inode number */
240    char *path;			/* file name */
241    int (*pentry) ();		/* entry point of this share library */
242    int refn;			/* number of reference */
243    hent_t htab[HTAB_SIZE];
244    struct obj *next;
245  }
246obj_t;
247
248static char *errmsg = 0;
249
250static void
251init_htab (hent_t * ht)
252/* initialize a hashing table */
253{
254  int i;
255
256  for (i = 0; i < HTAB_SIZE; i++)
257    ht[i] = (slot_t *) 0;
258
259  return;
260}
261
262
263static void
264clean_htab (hent_t * ht)
265/* free all slots */
266{
267  int i;
268  slot_t *ent;
269  slot_t *tent;
270
271  for (i = 0; i < HTAB_SIZE; i++)
272    {
273      for (ent = ht[i]; ent;)
274	{
275	  tent = ent->next;
276
277	  free (ent->sym);
278	  free (ent);
279
280	  ent = tent;
281	}
282
283      ht[i] = 0;
284    }
285
286  return;
287}
288
289
290static int
291hash (char *sym)
292{
293  int a, key;
294  double f;
295
296  if (!sym || !*sym)
297    return 0;
298
299  for (key = *sym; *sym; sym++)
300    {
301      key += *sym;
302      a = key;
303
304      key = (int) ((a << 8) + (key >> 8));
305      key = (key > 0) ? key : -key;
306    }
307
308  f = key * FACTOR;
309  a = (int) f;
310
311  return (int) ((HTAB_SIZE - 1) * (f - a));
312}
313
314
315static hent_t
316search (hent_t * htab, char *sym)
317/* search hashing table to find a matched slot */
318{
319  int key;
320  slot_t *ent;
321
322  key = hash (sym);
323
324  for (ent = htab[key]; ent; ent = ent->next)
325    {
326      if (!strcmp (ent->sym, sym))
327	return ent;
328    }
329
330  return 0;			/* no match */
331}
332
333
334static void
335insert (hent_t * htab, slot_t * ent)
336/* insert a new slot to hashing table */
337{
338  int key;
339
340  key = hash (ent->sym);
341
342  ent->next = htab[key];
343  htab[key] = ent;
344
345  return;
346}
347
348
349static slot_t *
350slot_alloc (char *sym)
351/* allocate a new slot with symbol */
352{
353  slot_t *ent;
354
355  ent = (slot_t *) malloc (sizeof (slot_t));
356
357  ent->sym = (char *) malloc (STRLEN (sym) + 1);
358
359  if (!ent->sym)
360    {
361      free (ent);
362      return 0;
363    }
364
365  STRCPY (ent->sym, sym);
366
367  return ent;
368}
369
370
371static obj_t *obj_list = 0;
372
373void *
374dlopen (char *file, int mode)
375{
376  stat_t st;
377  obj_t *pobj;
378  char buf[1024];
379
380  if (!file || !*file)
381    {
382      errno = EINVAL;
383      return 0;
384    }
385
386  errno = 0;
387  errmsg = 0;
388
389  if (stat (file, &st))
390    return 0;
391
392  for (pobj = obj_list; pobj; pobj = pobj->next)
393    /* find a match object */
394    {
395      if (pobj->ino == st.st_ino
396	  && pobj->dev == st.st_dev)
397	{
398	  /* found a match. increase its
399	   * reference count and return
400	   * its address */
401	  pobj->refn++;
402	  return pobj;
403	}
404    }
405
406  pobj = (obj_t *) malloc (sizeof (obj_t));
407
408  if (!pobj)
409    return 0;
410
411  pobj->path = (char *) malloc (STRLEN (file) + 1);
412
413  if (!pobj->path)
414    {
415      free (pobj);
416      return 0;
417    }
418
419  STRCPY (pobj->path, file);
420
421  pobj->dev = st.st_dev;
422  pobj->ino = st.st_ino;
423  pobj->refn = 1;
424
425  pobj->pentry = (int (*)()) load (file, 0, 0);
426
427  if (!pobj->pentry)
428    {
429      free (pobj->path);
430      free (pobj);
431      return 0;
432    }
433
434  init_htab (pobj->htab);
435
436  pobj->next = obj_list;
437  obj_list = pobj;
438
439  return pobj;
440}
441
442
443int
444dlclose (void *hobj)
445{
446  obj_t *pobj = (obj_t *) hobj;
447  obj_t *tpobj;
448  int match = 0;
449
450  if (!hobj)
451    {
452      errno = EINVAL;
453      return -1;
454    }
455
456  errno = 0;
457  errmsg = 0;
458
459  if (pobj == obj_list)
460    {
461      pobj->refn--;
462
463      if (pobj->refn)
464	return 0;
465
466      match = 1;
467      obj_list = pobj->next;
468    }
469
470  for (tpobj = obj_list; !match && tpobj; tpobj = tpobj->next)
471    {
472      if (tpobj->next == pobj)
473	{
474	  pobj->refn--;
475
476	  if (pobj->refn)
477	    return 0;
478
479	  match = 1;
480	  tpobj->next = pobj->next;
481	}
482    }
483
484  if (match)
485    {
486      unload ((void *) (pobj->pentry));
487      clean_htab (pobj->htab);
488      free (pobj->path);
489      free (pobj);
490    }
491
492  return 0;
493}
494
495
496char *
497dlerror ()
498{
499  extern char *sys_errlist[];
500
501  if (!errmsg || !errmsg[0])
502    {
503      if (errno >= 0)
504	return sys_errlist[errno];
505
506      return "";
507    }
508
509  return errmsg;
510}
511
512
513void *
514dlsym (void *hdl, char *sym)
515{
516  nlist_t nl[3];
517  obj_t *pobj = (obj_t *) hdl;
518  slot_t *ent;
519  int (*fp) ();
520  long lbuf[3];
521
522  if (!hdl || !(pobj->htab) || !sym || !*sym)
523    {
524      errno = EINVAL;
525      return 0;
526    }
527
528  errno = 0;
529  errmsg = 0;
530
531  ent = search (pobj->htab, sym);
532
533  if (ent)
534    return ent->fdesc;
535
536#define	n_name	_n._n_name
537
538  nl[0].n_name = ENTRY_SYM;
539  nl[1].n_name = sym;
540  nl[2].n_name = 0;
541
542  /* There is a potential problem here. If application
543   * did not pass a full path name, and changed the
544   * working directory after the load(), then nlist()
545   * will be unable to open the original shared library
546   * file to resolve the symbols. there are 3 ways to working
547   * round this: 1. convert to full pathname in driver
548   * manager. 2. applications always pass driver's full
549   * path name. 3. if driver itself don't support
550   * SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS
551   * as flag immediately after SQLConnect(), SQLDriverConnect()
552   * and SQLBrowseConnect() to force the driver manager
553   * resolving all will be used symbols.
554   */
555  if (nlist (pobj->path, nl) == -1)
556    return 0;
557
558  if (!nl[0].n_type && !nl[0].n_value)
559    {
560      errmsg = "can't locate module entry symbol";
561      return 0;
562    }
563
564  /* Note: On AIX 3.x if the object library is not
565   * built with -g compiling option, .n_type field
566   * is always 0. While on 4.x it will be 32.
567   * On AIX 4.x, if the symbol is a entry point,
568   * n_value will be 0. However, one thing is for sure
569   * that if a symbol does not exists in the file,
570   * both .n_type and .n_value would be 0.
571   */
572
573  if (!nl[1].n_type && !nl[1].n_value)
574    {
575      errmsg = "symbol does not exist in this module";
576      return 0;
577    }
578
579  ent = slot_alloc (sym);
580
581  if (!ent)
582    return 0;
583
584  /* catch it with a slot in the hashing table */
585  insert (pobj->htab, ent);
586
587  memcpy (ent->fdesc, pobj->pentry, sizeof (ent->fdesc));
588
589  /* now ent->fdesc[0] is the virtual address of entry point
590   * and ent->fdesc[1] is the TOC of the module
591   */
592
593  /* let's calculate the virtual address of the symbol
594   * by adding a relative offset getting from the module
595   * file symbol table, i.e
596   *
597   *  function virtual address = entry point virtual address +
598   *     + ( function offset in file - entry point offset in file )
599   */
600
601  (ent->fdesc)[0] = (ent->fdesc)[0] +
602      (nl[1].n_value - nl[0].n_value);
603
604  /* return the function descriptor */
605  return ent->fdesc;
606}
607#endif /* end of IBM AIX Section */
608
609
610/*********************************
611 *
612 *	Windows 3.x, 95, NT
613 *
614 *********************************/
615
616#ifdef	DLDAPI_WINDOWS
617#define	DLDAPI_DEFINED
618static char sccsid[] = "@(#)dynamic load interface -- Windows (LoadLibrary)";
619
620#include <windows.h>
621
622void *
623dlopen (char * dll, int mode)
624{
625  HINSTANCE hint;
626
627  if (dll == NULL)
628    {
629      return GetWindowWord (NULL, GWW_HINSTANCE);
630    }
631
632  hint = LoadLibrary (dll);
633
634  if (hint < HINSTANCE_ERROR)
635    {
636      return NULL;
637    }
638
639  return (void *) hint;
640}
641
642
643void *
644dlsym (void * hdll, char * sym)
645{
646  return (void *) GetProcAddress (hdll, sym);
647}
648
649
650char *
651dlerror ()
652{
653  return 0L;			/* unimplemented yet */
654}
655
656
657int
658dlclose (void * hdll)
659{
660  FreeLibrary ((HINSTANCE) hdll);
661}
662#endif /* end of Windows family */
663
664
665/***********************************
666 *
667 * 	VMS
668 *
669 ***********************************/
670
671#ifdef VMS
672#define	DLDAPI_DEFINED
673#ifdef DLDAPI_VMS_IODBC
674static char sccsid[] = "@(#)dynamic load interface -- VMS";
675
676#include <stdio.h>
677#include <descrip.h>
678#include <starlet.h>
679#include <ssdef.h>
680#include <libdef.h>
681#include <lib$routines>
682#include <rmsdef.h>
683#include <fabdef.h>
684#include <namdef.h>
685
686#ifndef LIB$M_FIS_MIXCASE
687#define LIB$M_FIS_MIXCASE 1<<4
688#endif
689
690typedef struct
691{
692  struct dsc$descriptor_s filename_d;
693  struct dsc$descriptor_s image_d;
694  char filename[NAM$C_MAXRSS];	/* $PARSEd image name */
695}
696dll_t;
697
698/*
699 *  The following static int contains the last VMS error returned. It is kept
700 *  static so that dlerror() can get it. This method is dangerous if you have
701 *  threaded applications, but this is the way the UNIX dlopen() etc
702 *  is defined.
703 */
704static int saved_status = SS$_NORMAL;
705static char dlerror_buf[256];
706
707
708static int
709iodbc_find_image_symbol (
710    struct dsc$descriptor_s *filename_d,
711    struct dsc$descriptor_s *symbol_d,
712    void **rp,
713    struct dsc$descriptor_s *image_d, int flag)
714{
715  lib$establish (lib$sig_to_ret);
716  return lib$find_image_symbol (filename_d, symbol_d, rp, image_d, flag);
717}
718
719
720void *
721iodbc_dlopen (char *path, int unused_flag)
722{
723  int status;
724  dll_t *dll;
725  struct FAB imgfab;
726  struct NAM imgnam;
727  static char defimg[] = "SYS$SHARE:.EXE";
728
729  if (path == NULL)
730    {
731      saved_status = SS$_UNSUPPORTED;
732      return NULL;
733    }
734
735  dll = malloc (sizeof (dll_t));
736  if (dll == NULL)
737    {
738      saved_status = SS$_INSFMEM;
739      return NULL;
740    }
741
742  imgfab = cc$rms_fab;
743  imgfab.fab$l_fna = path;
744  imgfab.fab$b_fns = STRLEN (path);
745  imgfab.fab$w_ifi = 0;
746  imgfab.fab$l_dna = defimg;
747  imgfab.fab$b_dns = sizeof (defimg);
748  imgfab.fab$l_fop = FAB$M_NAM;
749  imgfab.fab$l_nam = &imgnam;
750  imgnam = cc$rms_nam;
751  imgnam.nam$l_esa = dll->filename;
752  imgnam.nam$b_ess = NAM$C_MAXRSS;
753  status = sys$parse (&imgfab);
754  if (!(status & 1))
755    {
756      free (dll);
757      saved_status = status;
758      return NULL;
759    }
760
761  dll->filename_d.dsc$b_dtype = DSC$K_DTYPE_T;
762  dll->filename_d.dsc$b_class = DSC$K_CLASS_S;
763  dll->filename_d.dsc$a_pointer = imgnam.nam$l_name;
764  dll->filename_d.dsc$w_length = imgnam.nam$b_name;
765  dll->image_d.dsc$b_dtype = DSC$K_DTYPE_T;
766  dll->image_d.dsc$b_class = DSC$K_CLASS_S;
767  dll->image_d.dsc$a_pointer = dll->filename;
768  dll->image_d.dsc$w_length = imgnam.nam$b_esl;
769
770  /*
771   *  VMS does not have the concept of first opening a shared library and then
772   *  asking for symbols; the LIB$FIND_IMAGE_SYMBOL routine does both.
773   *  Since I want my implementation of dlopen() to return an error if the
774   *  shared library can not be loaded, I try to find a dummy symbol in the
775   *  library.
776   */
777  iodbc_dlsym (dll, "THIS_ROUTINE_MIGHT_NOT_EXIST");
778  if (!((saved_status ^ LIB$_KEYNOTFOU) & ~7))
779    {
780      saved_status = SS$_NORMAL;
781    }
782  if (saved_status & 1)
783    {
784      return dll;
785    }
786  else
787    {
788      free (dll);
789      return NULL;
790    }
791}
792
793
794void *
795iodbc_dlsym (void *hdll, char *sym)
796{
797  int status;
798  dll_t *dll;
799  struct dsc$descriptor_s symbol_d;
800  void *rp;
801
802  dll = hdll;
803  if (dll == NULL)
804    return NULL;
805
806  symbol_d.dsc$b_dtype = DSC$K_DTYPE_T;
807  symbol_d.dsc$b_class = DSC$K_CLASS_S;
808  symbol_d.dsc$a_pointer = sym;
809  symbol_d.dsc$w_length = STRLEN (sym);
810  status = iodbc_find_image_symbol (&dll->filename_d, &symbol_d, &rp,
811      &dll->image_d, 0);
812  if (!((saved_status ^ LIB$_KEYNOTFOU) & ~7))
813    {
814      status = iodbc_find_image_symbol (&dll->filename_d, &symbol_d, &rp,
815	  &dll->image_d, LIB$M_FIS_MIXCASE);
816    }
817  if (status & 1)
818    {
819      return rp;
820    }
821  else
822    {
823      saved_status = status;
824      return NULL;
825    }
826}
827
828
829char *
830iodbc_dlerror ()
831{
832  struct dsc$descriptor desc;
833  short outlen;
834  int status;
835
836  if (saved_status & 1)
837    {
838      return NULL;
839    }
840
841  desc.dsc$b_dtype = DSC$K_DTYPE_T;
842  desc.dsc$b_class = DSC$K_CLASS_S;
843  desc.dsc$a_pointer = dlerror_buf;
844  desc.dsc$w_length = sizeof (dlerror_buf);
845  status = sys$getmsg (saved_status, &outlen, &desc, 15, 0);
846  if (status & 1)
847    {
848      dlerror_buf[outlen] = '\0';
849    }
850  else
851    {
852      sprintf (dlerror_buf, "Message number %8X", saved_status);
853    }
854  saved_status = SS$_NORMAL;
855  return (dlerror_buf);
856}
857
858
859int
860iodbc_dlclose (void *hdll)
861{
862  /*
863   *  Not really implemented since VMS doesn't support unloading images.
864   *  The hdll pointer is released though.
865   */
866  free (hdll);
867  return 0;
868}
869#endif /* DLDAPI_VMS_IODBC */
870#endif /* VMS */
871
872
873/*********************************
874 *
875 *	Apple MacOS X Rhapsody
876 *
877 *********************************/
878#ifdef	DLDAPI_DYLD
879#define	DLDAPI_DEFINED
880static char sccsid[] = "@(#)dynamic load interface -- Mac OS X (dyld)";
881
882#include <stdio.h>
883#include <mach-o/dyld.h>
884
885
886static void
887undefined_symbol_handler (const char *symbolName)
888{
889  fprintf (stderr, "dyld found undefined symbol: %s\n", symbolName);
890
891  abort ();
892}
893
894
895static NSModule
896multiple_symbol_handler (NSSymbol s, NSModule old, NSModule new)
897{
898  /*
899   *  Since we can't unload symbols, we're going to run into this
900   *  every time we reload a module. Workaround here is to just
901   *  rebind to the new symbol, and forget about the old one.
902   *  This is crummy, because it's basically a memory leak.
903   */
904
905  return (new);
906}
907
908
909static void
910linkEdit_symbol_handler (NSLinkEditErrors c, int errorNumber,
911    const char *fileName, const char *errorString)
912{
913  fprintf (stderr, "dyld errors during link edit for file %s\n%s\n",
914      fileName, errorString);
915
916  abort ();
917}
918
919
920void *
921dlopen (char *path, int mode)
922{
923  NSObjectFileImage image;
924  NSLinkEditErrorHandlers handlers;
925  NSModule handle = NULL;
926  int i;
927
928  /*
929   *  Install error handler
930   */
931  handlers.undefined = undefined_symbol_handler;
932#if !defined (NSLINKMODULE_OPTION_PRIVATE)
933  handlers.multiple = multiple_symbol_handler;
934#endif
935  handlers.linkEdit = linkEdit_symbol_handler;
936
937  NSInstallLinkEditErrorHandlers (&handlers);
938
939  /*
940   *  Load object
941   */
942  i = NSCreateObjectFileImageFromFile (path, &image);
943  if (i != NSObjectFileImageSuccess)
944    {
945      static char *ErrorStrings[] =
946      {
947	  "%s(%d): Object Image Load Failure\n",
948	  "%s(%d): Object Image Load Success\n",
949	  "%s(%d): Not an recognizable object file\n",
950	  "%s(%d): No valid architecture\n",
951	  "%s(%d): Object image has an invalid format\n",
952	  "%s(%d): Invalid access (permissions?)\n",
953	  "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
954      };
955
956      if (i < 0 || i > 6)
957	i = 6;
958
959      fprintf (stderr, ErrorStrings[i], path, i);
960    }
961  else
962    {
963#if !defined (NSLINKMODULE_OPTION_PRIVATE)
964      handle = NSLinkModule (image, path, TRUE);
965#else
966      handle = NSLinkModule (image, path, NSLINKMODULE_OPTION_PRIVATE);
967#endif
968    }
969
970  return (void *) handle;
971}
972
973
974void *
975dlsym (void *hdll, char *sym)
976{
977  NSSymbol symbol;
978
979#if !defined (NSLINKMODULE_OPTION_PRIVATE)
980  if (NSIsSymbolNameDefined (sym))
981    {
982      symbol = NSLookupAndBindSymbol (sym);
983
984      return NSAddressOfSymbol (symbol);
985    }
986
987  return NULL;
988#else
989  symbol = NSLookupSymbolInModule ((NSModule) hdll, sym);
990
991  return NSAddressOfSymbol (symbol);
992#endif
993}
994
995
996char *
997dlerror ()
998{
999  return NULL;
1000}
1001
1002
1003int
1004dlclose (void *hdll)
1005{
1006  NSUnLinkModule (hdll, FALSE);
1007  return 0;
1008}
1009#endif	/* end of Rhapsody Section */
1010
1011
1012/*********************************
1013 *
1014 *	Apple MacOS X Rhapsody
1015 *
1016 *********************************/
1017#ifdef	DLDAPI_MACX
1018#define	DLDAPI_DEFINED
1019static char sccsid[] = "@(#)dynamic load interface -- Mac OS X 10.x (dyld)";
1020
1021static struct dlopen_handle *dlopen_handles = NULL;
1022static const struct dlopen_handle main_program_handle = { 0 };
1023static char *dlerror_pointer = NULL;
1024
1025/*
1026 * NSMakePrivateModulePublic() is not part of the public dyld API so we define
1027 * it here.  The internal dyld function pointer for
1028 * __dyld_NSMakePrivateModulePublic is returned so thats all that matters to get
1029 * the functionality need to implement the dlopen() interfaces.
1030 */
1031static int
1032NSMakePrivateModulePublic (NSModule module)
1033{
1034  static int (*p) (NSModule module) = NULL;
1035
1036  if (p == NULL)
1037    _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic",
1038	(void *) &p);
1039  if (p == NULL)
1040    {
1041#ifdef DEBUG
1042      printf ("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic "
1043	  "failed\n");
1044#endif
1045      return (FALSE);
1046    }
1047  return (p (module));
1048}
1049
1050
1051/*
1052 * dlopen() the MacOS X version of the FreeBSD dlopen() interface.
1053 */
1054void *
1055iodbc_dlopen (char * path, int mode)
1056{
1057  void *retval;
1058  struct stat stat_buf;
1059  NSObjectFileImage objectFileImage;
1060  NSObjectFileImageReturnCode ofile_result_code;
1061  NSModule module;
1062  struct dlopen_handle *p;
1063  unsigned long options;
1064  NSSymbol NSSymbol;
1065  void (*init) (void);
1066  static char errbuf[640];
1067
1068  dlerror_pointer = NULL;
1069
1070  /*
1071   * A NULL path is to indicate the caller wants a handle for the
1072   * main program.
1073   */
1074  if (path == NULL)
1075    {
1076      retval = (void *) &main_program_handle;
1077      return (retval);
1078    }
1079
1080  /* see if the path exists and if so get the device and inode number */
1081  if (stat (path, &stat_buf) == -1)
1082    {
1083      dlerror_pointer = strerror (errno);
1084      return (NULL);
1085    }
1086
1087  /*
1088   * If we don't want an unshared handle see if we already have a handle
1089   * for this path.
1090   */
1091  if ((mode & RTLD_UNSHARED) != RTLD_UNSHARED)
1092    {
1093      p = dlopen_handles;
1094      while (p != NULL)
1095	{
1096	  if (p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino)
1097	    {
1098	      /* skip unshared handles */
1099	      if ((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED)
1100		continue;
1101	      /*
1102	       * We have already created a handle for this path.  The
1103	       * caller might be trying to promote an RTLD_LOCAL handle
1104	       * to a RTLD_GLOBAL.  Or just looking it up with
1105	       * RTLD_NOLOAD.
1106	       */
1107	      if ((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL &&
1108		  (mode & RTLD_GLOBAL) == RTLD_GLOBAL)
1109		{
1110		  /* promote the handle */
1111		  if (NSMakePrivateModulePublic (p->module) == TRUE)
1112		    {
1113		      p->dlopen_mode &= ~RTLD_LOCAL;
1114		      p->dlopen_mode |= RTLD_GLOBAL;
1115		      p->dlopen_count++;
1116		      return (p);
1117		    }
1118		  else
1119		    {
1120		      dlerror_pointer = "can't promote handle from "
1121			  "RTLD_LOCAL to RTLD_GLOBAL";
1122		      return (NULL);
1123		    }
1124		}
1125	      p->dlopen_count++;
1126	      return (p);
1127	    }
1128	  p = p->next;
1129	}
1130    }
1131
1132  /*
1133   * We do not have a handle for this path if we were just trying to
1134   * look it up return NULL to indicate we don't have it.
1135   */
1136  if ((mode & RTLD_NOLOAD) == RTLD_NOLOAD)
1137    {
1138      dlerror_pointer = "no existing handle for path RTLD_NOLOAD test";
1139      return (NULL);
1140    }
1141
1142  /* try to create an object file image from this path */
1143  ofile_result_code = NSCreateObjectFileImageFromFile (path,
1144      &objectFileImage);
1145  if (ofile_result_code != NSObjectFileImageSuccess)
1146    {
1147      switch (ofile_result_code)
1148	{
1149	case NSObjectFileImageFailure:
1150	  dlerror_pointer = "object file setup failure";
1151	  return (NULL);
1152	case NSObjectFileImageInappropriateFile:
1153	  dlerror_pointer = "not a Mach-O MH_BUNDLE file type";
1154	  return (NULL);
1155	case NSObjectFileImageArch:
1156	  dlerror_pointer = "no object for this architecture";
1157	  return (NULL);
1158	case NSObjectFileImageFormat:
1159	  dlerror_pointer = "bad object file format";
1160	  return (NULL);
1161	case NSObjectFileImageAccess:
1162	  dlerror_pointer = "can't read object file";
1163	  return (NULL);
1164	default:
1165	  dlerror_pointer = "unknown error from "
1166	      "NSCreateObjectFileImageFromFile()";
1167	  return (NULL);
1168	}
1169    }
1170
1171  /* try to link in this object file image */
1172  options = NSLINKMODULE_OPTION_NONE |
1173    NSLINKMODULE_OPTION_PRIVATE |
1174    NSLINKMODULE_OPTION_RETURN_ON_ERROR;
1175  if ((mode & RTLD_NOW) == RTLD_NOW)
1176    options |= NSLINKMODULE_OPTION_BINDNOW;
1177  module = NSLinkModule (objectFileImage, path, options);
1178  NSDestroyObjectFileImage (objectFileImage);
1179  if (module == NULL)
1180    {
1181      NSLinkEditErrors lerr;
1182      int errNum;
1183      const char *fname;
1184      const char *errStr;
1185      NSLinkEditError(&lerr, &errNum, &fname, &errStr);
1186      sprintf(errbuf, "NSLinkModule() failed for dlopen() ([%.256s][%.256s])",
1187      		fname, errStr);
1188      dlerror_pointer = errbuf;
1189      return (NULL);
1190    }
1191
1192  /*
1193   * If the handle is to be global promote the handle.  It is done this
1194   * way to avoid multiply defined symbols.
1195   */
1196  if ((mode & RTLD_GLOBAL) == RTLD_GLOBAL)
1197    {
1198      if (NSMakePrivateModulePublic (module) == FALSE)
1199	{
1200	  dlerror_pointer = "can't promote handle from RTLD_LOCAL to "
1201	      "RTLD_GLOBAL";
1202	  return (NULL);
1203	}
1204    }
1205
1206  p = malloc (sizeof (struct dlopen_handle));
1207  if (p == NULL)
1208    {
1209      dlerror_pointer = "can't allocate memory for the dlopen handle";
1210      return (NULL);
1211    }
1212
1213  /* fill in the handle */
1214  p->dev = stat_buf.st_dev;
1215  p->ino = stat_buf.st_ino;
1216  if (mode & RTLD_GLOBAL)
1217    p->dlopen_mode = RTLD_GLOBAL;
1218  else
1219    p->dlopen_mode = RTLD_LOCAL;
1220  p->dlopen_mode |= (mode & RTLD_UNSHARED) |
1221      (mode & RTLD_NODELETE) | (mode & RTLD_LAZY_UNDEF);
1222  p->dlopen_count = 1;
1223  p->module = module;
1224  p->prev = NULL;
1225  p->next = dlopen_handles;
1226  if (dlopen_handles != NULL)
1227    dlopen_handles->prev = p;
1228  dlopen_handles = p;
1229
1230  /* call the init function if one exists */
1231  NSSymbol = NSLookupSymbolInModule (p->module, "__init");
1232  if (NSSymbol != NULL)
1233    {
1234      init = NSAddressOfSymbol (NSSymbol);
1235      init ();
1236    }
1237
1238  return (p);
1239}
1240
1241
1242/*
1243 * dlsym() the MacOS X version of the FreeBSD dlopen() interface.
1244 */
1245void *
1246iodbc_dlsym (void * handle, char * symbol)
1247{
1248  struct dlopen_handle *dlopen_handle, *p;
1249  char symbol2[1024];
1250  NSSymbol NSSymbol;
1251  void *address;
1252
1253  symbol2[0] = '_';
1254  strcpy (symbol2 + 1, symbol);
1255
1256  dlopen_handle = (struct dlopen_handle *) handle;
1257
1258  /*
1259   * If this is the handle for the main program do a global lookup.
1260   */
1261  if (dlopen_handle == (struct dlopen_handle *) &main_program_handle)
1262    {
1263      if (NSIsSymbolNameDefined (symbol2) == TRUE)
1264	{
1265	  NSSymbol = NSLookupAndBindSymbol (symbol2);
1266	  address = NSAddressOfSymbol (NSSymbol);
1267	  dlerror_pointer = NULL;
1268	  return (address);
1269	}
1270      else
1271	{
1272	  dlerror_pointer = "symbol not found";
1273	  return (NULL);
1274	}
1275    }
1276
1277  /*
1278   * Find this handle and do a lookup in just this module.
1279   */
1280  p = dlopen_handles;
1281  while (p != NULL)
1282    {
1283      if (dlopen_handle == p)
1284	{
1285	  NSSymbol = NSLookupSymbolInModule (p->module, symbol2);
1286	  if (NSSymbol != NULL)
1287	    {
1288	      address = NSAddressOfSymbol (NSSymbol);
1289	      dlerror_pointer = NULL;
1290	      return (address);
1291	    }
1292	  else
1293	    {
1294	      dlerror_pointer = "symbol not found";
1295	      return (NULL);
1296	    }
1297	}
1298      p = p->next;
1299    }
1300
1301  dlerror_pointer = "bad handle passed to dlsym()";
1302  return (NULL);
1303}
1304
1305
1306/*
1307 * dlerror() the MacOS X version of the FreeBSD dlopen() interface.
1308 */
1309char *
1310iodbc_dlerror (void)
1311{
1312  const char *p;
1313
1314  p = (const char *) dlerror_pointer;
1315  dlerror_pointer = NULL;
1316  return (char *)(p);
1317}
1318
1319
1320/*
1321 * dlclose() the MacOS X version of the FreeBSD dlopen() interface.
1322 */
1323int
1324iodbc_dlclose (void * handle)
1325{
1326  struct dlopen_handle *p, *q;
1327  unsigned long options;
1328  NSSymbol NSSymbol;
1329  void (*fini) (void);
1330
1331  dlerror_pointer = NULL;
1332  q = (struct dlopen_handle *) handle;
1333  p = dlopen_handles;
1334  while (p != NULL)
1335    {
1336      if (p == q)
1337	{
1338	  /* if the dlopen() count is not zero we are done */
1339	  p->dlopen_count--;
1340	  if (p->dlopen_count != 0)
1341	    return (0);
1342
1343	  /* call the fini function if one exists */
1344	  NSSymbol = NSLookupSymbolInModule (p->module, "__fini");
1345	  if (NSSymbol != NULL)
1346	    {
1347	      fini = NSAddressOfSymbol (NSSymbol);
1348	      fini ();
1349	    }
1350
1351	  /* unlink the module for this handle */
1352	  options = 0;
1353	  if (p->dlopen_mode & RTLD_NODELETE)
1354	    options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
1355	  if (p->dlopen_mode & RTLD_LAZY_UNDEF)
1356	    options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
1357	  if (NSUnLinkModule (p->module, options) == FALSE)
1358	    {
1359	      dlerror_pointer = "NSUnLinkModule() failed for dlclose()";
1360	      return (-1);
1361	    }
1362	  if (p->prev != NULL)
1363	    p->prev->next = p->next;
1364	  if (p->next != NULL)
1365	    p->next->prev = p->prev;
1366	  if (dlopen_handles == p)
1367	    dlopen_handles = p->next;
1368	  free (p);
1369	  return (0);
1370	}
1371      p = p->next;
1372    }
1373  dlerror_pointer = "invalid handle passed to dlclose()";
1374  return (-1);
1375}
1376
1377#endif /* end of Rhapsody Section */
1378
1379/*********************************
1380 *
1381 *	Macintosh
1382 *
1383 *********************************/
1384#ifdef	DLDAPI_MAC
1385static char sccsid[] = "@(#)dynamic load interface -- Mac Classic";
1386
1387#include <CodeFragments.h>
1388#include <strconv.h>
1389
1390static char *msg_error = NULL;
1391
1392void *
1393dlopen (char *dll, int mode)
1394{
1395#ifdef __POWERPC__
1396  CFragConnectionID conn_id;
1397  Ptr main_addr;
1398  Str255 name;
1399  OSErr err;
1400
1401  if (dll == NULL)
1402    {
1403      msg_error = "Library name not valid.";
1404      return NULL;
1405    }
1406
1407  if ((err = GetSharedLibrary ((unsigned char *) str_to_Str255 (dll),
1408	      kPowerPCCFragArch, kLoadCFrag, &conn_id, &main_addr,
1409	      name)) != noErr)
1410    {
1411      msg_error = "Library cannot be loaded.";
1412      return NULL;
1413    }
1414
1415  msg_error = NULL;
1416  return (void *) conn_id;
1417#else
1418  CFragConnectionID conn_id;
1419  Ptr main_addr;
1420  Str255 name;
1421  OSErr err;
1422
1423  if (dll == NULL)
1424    {
1425      msg_error = "Library name not valid.";
1426      return NULL;
1427    }
1428
1429  if ((err = GetSharedLibrary ((unsigned char *) str_to_Str255 (dll),
1430	      kMotorola68KCFragArch, kLoadCFrag, &conn_id, &main_addr,
1431	      name)) != noErr)
1432    {
1433      msg_error = "Library cannot be loaded.";
1434      return NULL;
1435    }
1436
1437  msg_error = NULL;
1438  return (void *) conn_id;
1439#endif
1440}
1441
1442
1443void *
1444dlsym (void *hdll, char *sym)
1445{
1446#ifdef __POWERPC__
1447  Ptr symbol;
1448  CFragSymbolClass symbol_type;
1449  OSErr err;
1450
1451  if (sym == NULL)
1452    {
1453      msg_error = "Symbol name not valid.";
1454      return NULL;
1455    }
1456
1457  if ((err =
1458	  FindSymbol ((CFragConnectionID) hdll,
1459	   (unsigned char *) str_to_Str255 (sym), &symbol,
1460	      &symbol_type)) != noErr)
1461    {
1462      msg_error = "Symbol cannot be loaded.";
1463      return NULL;
1464    }
1465
1466  msg_error = NULL;
1467  return symbol;
1468#else
1469  Ptr symbol;
1470  CFragSymbolClass symbol_type;
1471
1472  if (sym == NULL)
1473    {
1474      msg_error = "Symbol name not valid.";
1475      return NULL;
1476    }
1477
1478  if (FindSymbol ((CFragConnectionID) hdll,
1479	  (unsigned char *) str_to_Str255 (sym), &symbol,
1480	  &symbol_type) != noErr)
1481    {
1482      msg_error = "Symbol cannot be loaded.";
1483      return NULL;
1484    }
1485
1486  msg_error = NULL;
1487  return symbol;
1488#endif
1489}
1490
1491
1492char *
1493dlerror ()
1494{
1495  return (msg_error) ? msg_error : "No error detected.";
1496}
1497
1498
1499int
1500dlclose (void *hdll)
1501{
1502  /* It should be something like that ....  */
1503  /* but some applications like Office 2001 */
1504  /* have a problem with that ... just let  */
1505  /* the Mac unload the library when the    */
1506  /* application stop ...                   */
1507#ifdef __POWERPC__
1508/*		if( CloseConnection((CFragConnectionID*)hdll) )
1509		{
1510			msg_error = "Library cannot be unloaded.";
1511			return 1;
1512		}
1513		msg_error = NULL;
1514		return 0;*/
1515#else
1516  if (CloseConnection ((CFragConnectionID *) hdll))
1517    {
1518      msg_error = "Library cannot be unloaded.";
1519      return 1;
1520    }
1521
1522  msg_error = NULL;
1523  return 0;
1524#endif
1525}
1526
1527#define	DLDAPI_DEFINED
1528#endif /* end of Macintosh family */
1529
1530
1531/*********************************
1532 *
1533 *	BeOS
1534 *
1535 *********************************/
1536#ifdef	DLDAPI_BE
1537#define	DLDAPI_DEFINED
1538static char sccsid[] = "@(#)dynamic load interface -- BeOS";
1539
1540#include <kernel/image.h>
1541#include <be/support/Errors.h>
1542
1543static char *msg_error = NULL;
1544
1545void *
1546dlopen (char *dll, int mode)
1547{
1548  image_id dll_id;
1549
1550  if (dll == NULL)
1551    {
1552      msg_error = "Library name not valid.";
1553      return NULL;
1554    }
1555
1556  dll_id = load_add_on (dll);
1557
1558  if (dll_id == B_ERROR)
1559    {
1560      msg_error = "Library cannot be loaded.";
1561      return NULL;
1562    }
1563
1564  msg_error = NULL;
1565  return (void *) dll_id;
1566}
1567
1568
1569void *
1570dlsym (void *hdll, char *sym)
1571{
1572  void *address = NULL;
1573
1574  if (sym == NULL)
1575    {
1576      msg_error = "Symbol name not valid.";
1577      return NULL;
1578    }
1579
1580  if (get_image_symbol ((image_id) hdll, sym, B_SYMBOL_TYPE_ANY,
1581	  &address) != B_OK)
1582    {
1583      msg_error = "Symbol cannot be loaded.";
1584      return NULL;
1585    }
1586
1587  msg_error = NULL;
1588  return address;
1589}
1590
1591
1592char *
1593dlerror ()
1594{
1595  return (msg_error) ? msg_error : "No error detected.";
1596}
1597
1598
1599int
1600dlclose (void *hdll)
1601{
1602  if (unload_add_on ((image_id) hdll) != B_OK)
1603    {
1604      msg_error = "Library cannot be unloaded.";
1605      return 1;
1606    }
1607
1608  msg_error = NULL;
1609  return 0;
1610}
1611
1612#endif /* end of BeOS */
1613
1614
1615
1616/***********************************
1617 *
1618 * 	other platforms
1619 *
1620 ***********************************/
1621
1622#ifdef DLDAPI_OS2
1623#define	DLDAPI_DEFINED
1624/*
1625 *    DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ...
1626 */
1627#endif
1628
1629#ifdef DLDAPI_NEXT
1630#define	DLDAPI_DEFINED
1631#endif
1632
1633#ifndef DLDAPI_DEFINED
1634#error	"dynamic load editor undefined"
1635#endif
1636