1/**
2***     dlopen(), dlclose() dlsym(), dlerror() emulation for OS/400.
3***
4***     See Copyright for the status of this software.
5***
6***     Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A.
7**/
8
9#include <stdarg.h>
10#include <stdio.h>
11#include <ctype.h>
12#include <errno.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <dirent.h>
17#include <pthread.h>
18
19#include <sys/types.h>
20#include <sys/stat.h>
21
22#include <except.h>             /* AS400 exceptions. */
23#include <miptrnam.h>           /* MI pointers support. */
24#include <qusec.h>              /* Error structures. */
25#include <qp0lstdi.h>           /* Path to QSYS object name. */
26#include <qp0z1170.h>           /* For Qp0zInitEnv(). */
27#include <qleawi.h>             /* For QleActBndPgmLong() definitions. */
28#include <qsy.h>                /* Qualified name structure. */
29#include <qmhrtvm.h>            /* Retrieve message from message file. */
30
31#include <mih/rinzstat.h>
32#include <mih/matactex.h>
33
34#include "libxml/hash.h"
35#include "dlfcn.h"
36
37
38/**
39***     Maximum internal path length.
40**/
41
42#define MAXPATHLEN              5120
43
44
45/**
46***     Maximum error string length.
47**/
48
49#define MAX_ERR_STR             511
50
51
52/**
53***     Field address macro.
54**/
55
56#define offset_by(t, b, o)      ((t *) ((char *) (b) + (unsigned int) (o)))
57
58
59/**
60***     Global flags.
61**/
62
63#define INITED          000001          /* Package has been initialized. */
64#define THREADS         000002          /* Multithreaded job. */
65#define MULTIBUF        000004          /* One error buffer per thread. */
66
67
68/**
69***     DLL handle private structure.
70**/
71
72typedef struct {
73        Qle_ABP_Info_Long_t     actinfo;        /* Activation information. */
74        _SYSPTR                 pointer;        /* Pointer to DLL object. */
75        unsigned int            actcount;       /* Activation count. */
76}               dlinfo;
77
78
79/**
80***     Per-thread structure.
81**/
82
83typedef struct {
84        unsigned int    lockcount;              /* Mutex lock count. */
85        unsigned int    iserror;                /* Flag error present. */
86        char            str[MAX_ERR_STR + 1];   /* Error string buffer. */
87}               dlts_t;
88
89
90static pthread_mutex_t  dlmutex = PTHREAD_MUTEX_INITIALIZER;
91static xmlHashTablePtr  dldir = (xmlHashTablePtr) NULL; /* DLL directory. */
92static unsigned int     dlflags = 0;                    /* Package flags. */
93static pthread_key_t    dlkey;
94static dlts_t           static_buf;             /* Static error buffer. */
95
96
97
98static void
99dlthreadterm(void * mem)
100
101{
102        free(mem);
103        pthread_setspecific(dlkey, NULL);
104}
105
106
107static void
108dlterm(void)
109
110{
111        void * p;
112
113        if (dlflags & MULTIBUF) {
114                p = pthread_getspecific(dlkey);
115
116                if (p)
117                        dlthreadterm(p);
118                }
119
120        if (dlflags & THREADS)
121                pthread_mutex_lock(&dlmutex);
122
123        if (dldir) {
124                xmlHashFree(dldir, (xmlHashDeallocator) NULL);
125                dldir = NULL;
126                }
127
128        if (dlflags & MULTIBUF)
129                pthread_key_delete(dlkey);
130
131        dlflags |= ~(INITED | MULTIBUF);
132        pthread_mutex_unlock(&dlmutex);
133        pthread_mutex_destroy(&dlmutex);
134}
135
136
137static void
138dlinit(void)
139
140{
141        int locked;
142
143        /**
144        ***     Initialize the package.
145        ***     Should be call once per process.
146        **/
147
148        locked = !pthread_mutex_lock(&dlmutex);
149
150        if (!(dlflags & INITED)) {
151                dlflags &= ~THREADS;
152
153                if (locked)
154                        dlflags |= THREADS;
155
156                Qp0zInitEnv();
157                dldir = xmlHashCreate(16);
158                dlflags &= ~MULTIBUF;
159
160                if (dlflags & THREADS)
161                        if (!pthread_key_create(&dlkey, dlthreadterm))
162                                dlflags |= MULTIBUF;
163
164                atexit(dlterm);
165                dlflags |= INITED;
166                }
167
168        if (locked)
169                pthread_mutex_unlock(&dlmutex);
170}
171
172
173static void
174dlthreadinit(void)
175
176{
177        dlts_t * p;
178
179        if (!(dlflags & INITED))
180                dlinit();
181
182        if (dlflags & MULTIBUF) {
183                p = pthread_getspecific(dlkey);
184
185                if (!p) {
186                        p = (dlts_t *) malloc(sizeof *p);
187
188                        if (p) {
189                                p->lockcount = 0;
190                                p->iserror = 0;
191
192                                if (pthread_setspecific(dlkey, p))
193                                        free(p);
194                                }
195                        }
196                }
197}
198
199
200static void
201dllock(void)
202
203{
204        dlts_t * p;
205
206        if (!(dlflags & THREADS))
207                return;
208
209        if (dlflags & MULTIBUF) {
210                p = pthread_getspecific(dlkey);
211
212                if (p && p->lockcount) {
213                        p->lockcount++;
214                        return;
215                        }
216                }
217        else
218                p = (dlts_t *) NULL;
219
220        if (pthread_mutex_lock(&dlmutex))
221                return;
222
223        if (p)
224                p->lockcount++;
225}
226
227
228static void
229dlunlock(void)
230
231{
232        dlts_t * p;
233
234        if (!(dlflags & THREADS))
235                return;
236
237        if (dlflags & MULTIBUF) {
238                p = pthread_getspecific(dlkey);
239
240                if (p && p->lockcount > 1) {
241                        p->lockcount--;
242                        return;
243                        }
244                }
245        else
246                p = (dlts_t *) NULL;
247
248        if (pthread_mutex_unlock(&dlmutex))
249                return;
250
251        if (p)
252                p->lockcount--;
253}
254
255
256const char *
257dlerror(void)
258
259{
260        dlts_t * p;
261
262        dlthreadinit();
263
264        if (!(dlflags & MULTIBUF))
265                p = &static_buf;
266        else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
267                p = &static_buf;
268
269        if (!p->iserror)
270                return (const char *) NULL;
271
272        p->iserror = 0;
273        return p->str;
274}
275
276
277static void
278dlseterror_from_errno(unsigned int err_no)
279
280{
281        dlts_t * p;
282
283        if (!(dlflags & MULTIBUF))
284                p = &static_buf;
285        else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
286                p = &static_buf;
287
288        strcpy(p->str, strerror(err_no));
289        p->iserror = 1;
290}
291
292
293static void
294dlseterror_from_exception(volatile _INTRPT_Hndlr_Parms_T * excp)
295
296{
297        int i;
298        Qmh_Rtvm_RTVM0300_t * imp;
299        char * cp;
300        _INTRPT_Hndlr_Parms_T * p;
301        dlts_t * q;
302        char rtvmbuf[30000];
303        Qus_EC_t errinfo;
304
305        p = (_INTRPT_Hndlr_Parms_T *) excp;
306        errinfo.Bytes_Provided = 0;             /* Exception on error. */
307        QMHRTVM(rtvmbuf, sizeof rtvmbuf, "RTVM0300", p->Msg_Id,
308            "QCPFMSG   QSYS      ", p->Ex_Data, p->Msg_Data_Len,
309            "*YES      ", "*NO       ", &errinfo);
310        imp = offset_by(Qmh_Rtvm_RTVM0300_t, rtvmbuf, 0);
311
312        if (!(dlflags & MULTIBUF))
313                q = &static_buf;
314        else if (!(q = (dlts_t *) pthread_getspecific(dlkey)))
315                q = &static_buf;
316
317        if (i = imp->Length_Message_Returned)
318                cp = offset_by(char, imp, imp->Offset_Message_Returned);
319        else if (i = imp->Length_Help_Returned)
320                cp = offset_by(char, imp, imp->Offset_Help_Returned);
321        else {
322                q->iserror = 0;
323                return;
324                }
325
326        q->iserror = 1;
327
328        if (i > sizeof q->str - 1)
329                i = sizeof q->str - 1;
330
331        memcpy(q->str, cp, i);
332        q->str[i] = '\0';
333}
334
335
336static int
337dlparentpath(const char * path, size_t len)
338
339{
340        if (len <= 1)
341                return len;
342
343        while (path[--len] != '/')
344                ;
345
346        return len? len: 1;
347}
348
349
350static int
351dlmakepath(char * path, size_t pathlen, const char * tail, size_t taillen)
352
353{
354        int i;
355
356        if (taillen && tail[0] == '/')
357                pathlen = 0;
358
359        for (;;) {
360                while (taillen && *tail == '/') {
361                        tail++;
362                        taillen--;
363                        }
364
365                if (!taillen)
366                        break;
367
368                for (i = 0; i < taillen; i++)
369                        if (tail[i] == '/')
370                                break;
371
372                if (*tail == '.')
373                        switch (i) {
374
375                        case 2:
376                                if (tail[1] != '.')
377                                        break;
378
379                                pathlen = dlparentpath(path, pathlen);
380
381                        case 1:
382                                tail += i;
383                                taillen -= i;
384                                continue;
385                                }
386
387                if (pathlen + i + 1 >= MAXPATHLEN) {
388                        errno = ENAMETOOLONG;
389                        return -1;
390                        }
391
392                path[pathlen++] = '/';
393                memcpy(path + pathlen, tail, i);
394                pathlen += i;
395                }
396
397        if (!pathlen)
398                path[pathlen++] = '/';
399
400        path[pathlen] = '\0';
401        return pathlen;
402}
403
404
405static int
406dlresolveLink(const char * path, char * buf, size_t bufsiz)
407
408{
409        int n;
410        int l1;
411        int l2;
412        struct stat sbuf;
413        char buf1[MAXPATHLEN + 1];
414        char buf2[MAXPATHLEN + 1];
415
416        /**
417        ***     Resolve symbolic link to IFS object name.
418        **/
419
420        if (!buf) {
421                errno = EFAULT;
422                return -1;
423                }
424
425        if (!path || !*path || !bufsiz) {
426                errno = EINVAL;
427                return -1;
428                }
429
430        if (*path != '/') {
431                if (!getcwd(buf1, sizeof buf1))
432                        return -1;
433
434                l1 = strlen(buf1);
435                }
436        else
437                l1 = 0;
438
439        l1 = dlmakepath(buf1, l1, path, strlen(path));
440        n = 0;
441
442        for (;;) {
443                if (l1 < 0)
444                        return -1;
445
446                if (n++ >= 256) {
447                        errno = ELOOP;
448                        return -1;
449                        }
450
451                if (lstat(buf1, &sbuf)) {
452                        if (errno == ENOENT)
453                                break;
454
455                        return -1;
456                        }
457
458                if (!S_ISLNK(sbuf.st_mode))
459                        break;
460
461                if (sbuf.st_size > MAXPATHLEN) {
462                        errno = ENAMETOOLONG;
463                        return -1;
464                        }
465
466                l2 = readlink(buf1, buf2, MAXPATHLEN + 1);
467
468                if (l2 < 0)
469                        return -1;
470
471                if (buf2[0] != '/')
472                        l1 = dlparentpath(buf1, l1);
473
474                l1 = dlmakepath(buf1, l1, buf2, l2);
475                }
476
477        if (l1 >= bufsiz) {
478                errno = ENAMETOOLONG;
479                return -1;
480                }
481
482        memcpy(buf, buf1, l1 + 1);
483        return l1;
484}
485
486
487static int
488dlGetObjectName(Qp0l_QSYS_Info_t * qsysinfo, const char * dir,
489                        int dirlen, const char * link)
490
491{
492        int n;
493        char * namebuf;
494        Qlg_Path_Name_T * qptp;
495        char pathbuf[sizeof(Qlg_Path_Name_T) + _QP0L_DIR_NAME_LG + 4];
496        Qus_EC_t errinfo;
497        struct stat sbuf;
498
499        /**
500        ***     Get QSYS object library/name/member and type corresponding to
501        ***             the symbolic `link' in directory `dir'.
502        **/
503
504        if (!qsysinfo) {
505                errno = EFAULT;
506                return -1;
507                }
508
509        if (!dir && !link) {
510                errno = EINVAL;
511                return -1;
512                }
513
514        qptp = (Qlg_Path_Name_T *) pathbuf;
515        namebuf = pathbuf + sizeof(Qlg_Path_Name_T);
516        n = 0;
517
518        /**
519        ***     Build full path.
520        **/
521
522        if (dir) {
523                if (dirlen < 0 || dirlen > _QP0L_DIR_NAME_LG + 4)
524                        dirlen = _QP0L_DIR_NAME_LG + 4;
525
526                while (*dir && n < dirlen)
527                        namebuf[n++] = *dir++;
528                }
529
530        if (n && namebuf[n - 1] == '/')
531                n--;
532
533        if (link) {
534                if (*link && *link != '/' && n < _QP0L_DIR_NAME_LG + 4)
535                        namebuf[n++] = '/';
536
537                while (*link && n < _QP0L_DIR_NAME_LG + 4)
538                        namebuf[n++] = *link++;
539                }
540
541        if (!n || n > _QP0L_DIR_NAME_LG) {
542                errno = ENAMETOOLONG;
543                return -1;
544                }
545
546        namebuf[n] = '\0';
547        n = dlresolveLink(namebuf, namebuf, _QP0L_DIR_NAME_LG + 1);
548
549        if (n == -1)
550                return -1;
551
552        if (stat(namebuf, &sbuf))
553                return -1;
554
555        memset((char *) qptp, 0, sizeof *qptp);
556        qptp->Path_Length = n;
557        qptp->Path_Name_Delimiter[0] = '/';
558        errinfo.Bytes_Provided = sizeof errinfo;
559        Qp0lCvtPathToQSYSObjName(qptp, qsysinfo, "QSYS0100", sizeof *qsysinfo,
560            0, &errinfo);
561        return errinfo.Bytes_Available? -1: 0;
562}
563
564
565static const char *
566getcomponent(char * dst, const char * src)
567
568{
569        int i;
570
571        /**
572        ***     Get a path component of at most 10 characters and
573        ***             map it to upper case.
574        ***     Return the address of the next delimiter in source.
575        **/
576
577        for (i = 0;; src++) {
578                if (!*src || *src == ' ' || *src == '/') {
579                        *dst = '\0';
580                        return src;
581                        }
582
583                if (i < 10) {
584                        *dst++ = toupper(*src);
585                        i++;
586                        }
587                }
588}
589
590
591static int
592dlpath2QSYS(Qp0l_QSYS_Info_t * qsysinfo, const char * path, const char * dftlib)
593
594{
595        unsigned int flags;
596        char * cp;
597
598        /**
599        ***     Convert the given path to a QSYS object name.
600        ***     Syntax rules for paths are:
601        ***
602        ***     '/'+ [ <library> [  '/'+ <file> [ '/'+ <member> ] ] '/'* ]
603        ***     <library> '/'+ <file> [ '/'+ <member> ] '/'*
604        ***     <file> '/'*
605        ***
606        ***     If default library is not given, *LIBL is assumed.
607        ***     Components may no contain spaces. They are translated to
608        ***             uppercase. Only the first 10 characters are significant.
609        ***     There is no check for the validity of the given components and
610        ***             for the object existence.
611        ***     Component types are not in the path, but generated internally.
612        ***     CCSID is not processed.
613        ***
614        ***     Return 0 upon success, else -1.
615        **/
616
617        if (!qsysinfo || !path) {
618                errno = EFAULT;
619                return -1;
620                }
621
622        /**
623        ***     Strip leading spaces.
624        **/
625
626        while (*path == ' ')
627                path++;
628
629        /**
630        ***     Check for null path.
631        **/
632
633        if (!*path) {
634                errno = EINVAL;
635                return -1;
636                }
637
638        /**
639        ***     Preset the result structure.
640        **/
641
642        memset((char *) qsysinfo, 0, sizeof *qsysinfo);
643
644        /**
645        ***     Determine the format.
646        **/
647
648        if (*path == '/') {
649                /**
650                ***     Library component present.
651                **/
652
653                while (*++path == '/')
654                        ;
655
656                if (!*path || *path == ' ')
657                        strcpy(qsysinfo->Lib_Name, "QSYS");
658                else
659                        path = getcomponent(qsysinfo->Lib_Name, path);
660
661                /**
662                ***     Check for file component and get it.
663                **/
664
665                if (*path == '/') {
666                        while (*++path == '/')
667                                ;
668
669                        if (*path && *path != ' ')
670                                path = getcomponent(qsysinfo->Obj_Name, path);
671                        }
672                }
673        else {
674                /**
675                ***     The mandatory component is the <file>.
676                **/
677
678                path = getcomponent(qsysinfo->Obj_Name, path);
679
680                while (*path == '/')
681                        path++;
682
683                /**
684                ***     If there is a second component, move the first to
685                ***             the library name and parse the file name.
686                **/
687
688                if (*path && *path != ' ') {
689                        strcpy(qsysinfo->Lib_Name, qsysinfo->Obj_Name);
690                        memset(qsysinfo->Obj_Name, 0,
691                            sizeof qsysinfo->Obj_Name);
692                        path = getcomponent(qsysinfo->Obj_Name, path);
693                        }
694                else
695                        strcpy(qsysinfo->Lib_Name, dftlib? dftlib: "*LIBL");
696                }
697
698        /**
699        ***     Check and set-up member.
700        **/
701
702        while (*path == '/')
703                path++;
704
705        if (*path && *path != ' ') {
706                path = getcomponent(qsysinfo->Mbr_Name, path);
707                strcpy(qsysinfo->Mbr_Type, "*MBR");
708
709                while (*path == '/')
710                        path++;
711                }
712
713        strcpy(qsysinfo->Lib_Type, "*LIB");
714
715        if (qsysinfo->Obj_Name[0])
716                strcpy(qsysinfo->Obj_Type, "*FILE");
717
718        qsysinfo->Bytes_Returned = sizeof *qsysinfo;
719        qsysinfo->Bytes_Available = sizeof *qsysinfo;
720
721        /**
722        ***     Strip trailing spaces.
723        **/
724
725        while (*path == ' ')
726                path++;
727
728        if (*path) {
729                errno = EINVAL;
730                return -1;
731                }
732
733        return 0;
734}
735
736
737static int
738dl_ifs_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
739
740{
741        /**
742        ***     If `pathname' is a link found in IFS, set `qsysinfo' to its
743        ***             DB2 name.
744        ***     Return 0 if OK, else -1.
745        **/
746
747        return dlGetObjectName(qsysinfo, (const char *) NULL, 0, pathname);
748}
749
750
751static int
752dl_path_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathvar,
753        const char * filename, int (* testproc)(const Qp0l_QSYS_Info_t *))
754
755{
756        const char * p;
757        const char * q;
758        unsigned int i;
759        const char * path;
760
761        /**
762        ***     If `filename' is not a path and is a link found in one of the
763        ***             colon-separated paths in environment variable `pathvar',
764        ***             set `qsysinfo' to its DB2 name.
765        ***     Return 0 if OK, else -1.
766        **/
767
768        i = _QP0L_DIR_NAME_LG;
769
770        for (p = filename; *p; p++)
771                if (*p == '/' || !--i)
772                        return -1;              /* Too long or a path. */
773
774        /**
775        ***     Make sure we have the LD_LIBRARY_PATH environment
776        ***             variable value.
777        **/
778
779        path = getenv(pathvar);
780
781        if (!path)
782                return -1;                      /* No path list. */
783
784        /**
785        ***     Try in each path listed.
786        **/
787
788        q = path;
789
790        if (!*q)
791                return -1;                      /* No path list. */
792
793        for (;;) {
794                for (p = q; *p && *p != ':'; p++)
795                        ;
796
797                if (p > q)                      /* Ignore null path. */
798                        if (!dlGetObjectName(qsysinfo, q, p - q, filename))
799                                if (!testproc || (*testproc)(qsysinfo))
800                                        return 0;       /* Found: return. */
801
802                if (!*p)
803                        break;
804
805                q = p + 1;
806                }
807
808        errno = ENOENT;
809        return -1;
810}
811
812
813static int
814dl_DB2_path(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
815
816{
817        if (dlpath2QSYS(qsysinfo, pathname, (const char *) NULL))
818                return -1;
819
820        if (qsysinfo->Mbr_Type[0])
821                return -1;      /* Service program may not have members. */
822
823        if (!qsysinfo->Obj_Type[0])
824                return -1;      /* Object must be specified. */
825
826        strcpy(qsysinfo->Obj_Type, "*SRVPGM");  /* Set our object type. */
827        return 0;
828}
829
830
831static int
832dl_DB2_name(char * dst, const char * name)
833
834{
835        int i;
836
837        for (i = 0; i < 10; i++) {
838                switch (*name) {
839
840                default:
841                        if (!islower(*name))
842                                break;
843
844                case '\0':
845                case '/':
846                case ' ':
847                        return -1;
848                        }
849
850                *dst++ = *name++;
851                }
852
853        if (!i)
854                return -1;
855
856        *dst = '\0';
857        return 0;
858}
859
860
861static int
862dl_qualified_object(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
863
864{
865        memset((char *) qsysinfo, 0, sizeof *qsysinfo);
866
867        if (dl_DB2_name(qsysinfo->Obj_Name, pathname) ||
868            dl_DB2_name(qsysinfo->Lib_Name, pathname + 10))
869                return -1;
870
871        strcpy(qsysinfo->Lib_Type, "*LIB");
872        strcpy(qsysinfo->Obj_Type, "*SRVPGM");
873        return 0;
874}
875
876
877static int
878dl_lib_object(Qp0l_QSYS_Info_t * qsysinfo,
879                                const char * libname, const char * pathname)
880
881{
882        int i;
883        char * cp;
884
885        strcpy(qsysinfo->Lib_Name, libname);
886        strcpy(qsysinfo->Lib_Type, "*LIB");
887        strcpy(qsysinfo->Obj_Type, "*SRVPGM");
888        cp = qsysinfo->Obj_Name;
889
890        while (*pathname == ' ')
891                pathname++;
892
893        for (i = 0;; pathname++) {
894                switch (*pathname) {
895
896                case '\0':
897                case ' ':
898                        break;
899
900                case '/':
901                        return -1;
902
903                default:
904                        if (i < 10)
905                                *cp++ = toupper(*pathname);
906
907                        i++;
908                        continue;
909                        }
910
911                break;
912                }
913
914        while (*pathname == ' ')
915                pathname++;
916
917        if (!i || *pathname)
918                return -1;
919
920        *cp = '\0';
921        return 0;
922}
923
924
925static int
926dl_is_srvpgm(const Qp0l_QSYS_Info_t * qsysinfo)
927
928{
929        struct stat sbuf;
930        char namebuf[100];
931
932        if (!qsysinfo->Lib_Name[0] || strcmp(qsysinfo->Lib_Type, "*LIB") ||
933            !qsysinfo->Obj_Name[0] || strcmp(qsysinfo->Obj_Type, "*SRVPGM") ||
934            qsysinfo->Mbr_Name[0] || qsysinfo->Mbr_Type[0])
935                return 0;
936
937        /**
938        ***     Build the IFS path name for the DB2 object.
939        **/
940
941        sprintf(namebuf, "%s/%s.LIB/%s.SRVPGM",
942            strcmp(qsysinfo->Lib_Name, "QSYS")? "/QSYS.LIB": "",
943            qsysinfo->Lib_Name, qsysinfo->Obj_Name);
944
945        return stat(namebuf, &sbuf) == 0;
946}
947
948
949static int
950dlreinit(dlinfo * dlip)
951
952{
953        RINZ_TEMPL_T t;
954        RINZ_TEMPL_T * p;
955        volatile _INTRPT_Hndlr_Parms_T excbuf;
956
957        if (dlip->actinfo.Flags & QLE_ABP_WAS_ACTIVE)
958                return 0;
959
960        /**
961        ***     Attempt to reinitialize the service program that was loaded.
962        ***     The service program must be created to allow re-initialization:
963        ***             ALWRINZ(*YES) for this to work. The default is
964        ***             ALWRINZ(*NO).
965        **/
966
967#pragma exception_handler(err, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
968        p = &t;
969        t.rinz_pgm = dlip->pointer;
970        t.rinz_agpmk = dlip->actinfo.Act_Grp_Mark;
971        _RINZSTAT(p);
972#pragma disable_handler
973
974        return 0;
975
976err:
977        if (!memcmp((char *) excbuf.Msg_Id, "MCH4421", 7))
978                return 0;       /* Program cannot be reinitialized. */
979
980        dlseterror_from_exception(&excbuf);
981        return -1;
982}
983
984
985void *
986dlsym(void * handle, const char * symbol)
987
988{
989        dlinfo * dlip;
990        void * p;
991        int export_type;
992        Qus_EC_t errinfo;
993        volatile _INTRPT_Hndlr_Parms_T excbuf;
994        static int zero = 0;
995
996        dlthreadinit();
997
998        if (!handle || !symbol) {
999                dlseterror_from_errno(EFAULT);
1000                return (void *) NULL;
1001                }
1002
1003        dlip = (dlinfo *) handle;
1004
1005#pragma exception_handler(error, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
1006        errinfo.Bytes_Provided = 0;
1007        QleGetExpLong(&dlip->actinfo.Act_Mark, &zero, &zero,
1008            (char *) symbol, &p, &export_type, &errinfo);
1009        return p;
1010#pragma disable_handler
1011
1012error:
1013        dlseterror_from_exception(&excbuf);
1014        return (void *) NULL;
1015}
1016
1017
1018int
1019dlclose(void * handle)
1020
1021{
1022        dlinfo * dlip;
1023        void (* _fini)(void);
1024
1025        dlthreadinit();
1026
1027        if (!handle) {
1028                dlseterror_from_errno(EFAULT);
1029                return -1;
1030                }
1031
1032        dlip = (dlinfo *) handle;
1033
1034        if (dlip->actcount) {
1035                if (--(dlip->actcount))
1036                        return 0;
1037
1038                if (_fini = dlsym(handle, "_fini"))
1039                        (*_fini)();
1040                }
1041
1042        return dlreinit(dlip);
1043}
1044
1045
1046static void *
1047dlopenqsys(const Qp0l_QSYS_Info_t * dllinfo)
1048
1049{
1050        dlinfo * dlip;
1051        dlinfo * dlip2;
1052        void (* _init)(void);
1053        unsigned int i;
1054        _SYSPTR pgmptr;
1055        unsigned long long actmark;
1056        Qus_EC_t errinfo;
1057        char actmarkstr[2 * sizeof actmark + 1];
1058        static int actinfo_size = sizeof dlip->actinfo;
1059        volatile _INTRPT_Hndlr_Parms_T excbuf;
1060
1061        /**
1062        ***     Capture any type of error and if any occurs,
1063        ***             return not found.
1064        **/
1065
1066#pragma exception_handler(error1, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
1067        pgmptr = rslvsp(WLI_SRVPGM, (char *) dllinfo->Obj_Name,
1068            (char *) dllinfo->Lib_Name ,_AUTH_NONE);
1069
1070        if (!pgmptr) {
1071                errno = ENOENT;
1072                return (void *) NULL;
1073                }
1074
1075        /**
1076        ***     Create a new DLL info block.
1077        **/
1078
1079        dlip = (dlinfo *) malloc(sizeof *dlip);
1080
1081        if (!dlip)
1082                return (void *) NULL;           /* Cannot create block. */
1083#pragma disable_handler
1084
1085        dllock();
1086
1087#pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
1088        memset((char *) dlip, 0, sizeof *dlip);
1089        dlip->pointer = pgmptr;
1090
1091        /**
1092        ***     Activate the DLL.
1093        **/
1094
1095        errinfo.Bytes_Provided = 0;
1096        QleActBndPgmLong(&pgmptr, &actmark,
1097            &dlip->actinfo, &actinfo_size, &errinfo);
1098        dlip->actinfo.Act_Mark = actmark;
1099
1100        /**
1101        ***     Dummy string encoding activation mark to use as hash table key.
1102        **/
1103
1104        for (i = 0; actmark; actmark >>= 6)
1105                actmarkstr[i++] = 0x40 + (actmark & 0x3F);
1106
1107        actmarkstr[i] = '\0';
1108
1109        /**
1110        ***     Check if already activated.
1111        **/
1112
1113        dlip2 = (dlinfo *) xmlHashLookup(dldir, actmarkstr);
1114
1115        if (dlip2) {
1116                free((char *) dlip);
1117                dlip = dlip2;
1118                }
1119        else if (xmlHashAddEntry(dldir, (const xmlChar *) actmarkstr, dlip)) {
1120                dlreinit(dlip);
1121                free((char *) dlip);
1122                dlunlock();
1123                return (void *) NULL;
1124                }
1125#pragma disable_handler
1126
1127#pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
1128
1129        /**
1130        ***     Bump activation counter.
1131        **/
1132
1133        if (!(dlip->actcount++) && (_init = dlsym(dlip, "_init")))
1134                (*_init)();
1135
1136        dlunlock();
1137
1138        /**
1139        ***     Return the handle.
1140        **/
1141
1142        return (void *) dlip;
1143#pragma disable_handler
1144
1145error2:
1146        free((char *) dlip);
1147        dlunlock();
1148
1149error1:
1150        dlseterror_from_exception(&excbuf);
1151        return (void *) NULL;
1152}
1153
1154
1155void *
1156dlopen(const char * filename, int flag)
1157
1158{
1159        void * dlhandle;
1160        int sverrno;
1161        Qp0l_QSYS_Info_t dllinfo;
1162
1163        sverrno = errno;
1164        errno = 0;
1165
1166        dlthreadinit();
1167
1168        if (!filename) {
1169                dlseterror_from_errno(EFAULT);
1170                errno = sverrno;
1171                return NULL;
1172                }
1173
1174        /**
1175        ***     Try to locate the object in the following order:
1176        ***     _       `filename' is an IFS path.
1177        ***     _       `filename' is not a path and resides in one of
1178        ***                     LD_LIBRARY_PATH colon-separated paths.
1179        ***     _       `filename' is not a path and resides in one of
1180        ***                     PATH colon-separated paths.
1181        ***     _       `filename' is a DB2 path (as /library/object).
1182        ***     _       `filename' is a qualified object name.
1183        ***     _       `filename' is an object in *CURLIB.
1184        ***     _       `filename' is an object in *LIBL.
1185        **/
1186
1187        if (!dl_ifs_link(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
1188                dlhandle = dlopenqsys(&dllinfo);
1189        else if (!dl_path_link(&dllinfo,
1190            "LD_LIBRARY_PATH", filename, dl_is_srvpgm))
1191                dlhandle = dlopenqsys(&dllinfo);
1192        else if (!dl_path_link(&dllinfo, "PATH", filename, dl_is_srvpgm))
1193                dlhandle = dlopenqsys(&dllinfo);
1194        else if (!dl_DB2_path(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
1195                dlhandle = dlopenqsys(&dllinfo);
1196        else if (!dl_qualified_object(&dllinfo, filename) &&
1197            dl_is_srvpgm(&dllinfo))
1198                dlhandle = dlopenqsys(&dllinfo);
1199        else if (!dl_lib_object(&dllinfo, "*CURLIB", filename) &&
1200            dl_is_srvpgm(&dllinfo))
1201                dlhandle = dlopenqsys(&dllinfo);
1202        else if (!dl_lib_object(&dllinfo, "*LIBL", filename) &&
1203            dl_is_srvpgm(&dllinfo))
1204                dlhandle = dlopenqsys(&dllinfo);
1205        else
1206                dlhandle = NULL;
1207
1208        if (!dlhandle && errno)
1209                dlseterror_from_errno(errno);
1210
1211        errno = sverrno;
1212        return dlhandle;
1213}
1214