Imported Upstream version 2.9.4
[platform/upstream/libxml2.git] / os400 / dlfcn / dlfcn.c
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
72 typedef 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
83 typedef 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
90 static pthread_mutex_t  dlmutex = PTHREAD_MUTEX_INITIALIZER;
91 static xmlHashTablePtr  dldir = (xmlHashTablePtr) NULL; /* DLL directory. */
92 static unsigned int     dlflags = 0;                    /* Package flags. */
93 static pthread_key_t    dlkey;
94 static dlts_t           static_buf;             /* Static error buffer. */
95
96
97
98 static void
99 dlthreadterm(void * mem)
100
101 {
102         free(mem);
103         pthread_setspecific(dlkey, NULL);
104 }
105
106
107 static void
108 dlterm(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
137 static void
138 dlinit(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
173 static void
174 dlthreadinit(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
200 static void
201 dllock(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
228 static void
229 dlunlock(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
256 const char *
257 dlerror(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
277 static void
278 dlseterror_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
293 static void
294 dlseterror_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
336 static int
337 dlparentpath(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
350 static int
351 dlmakepath(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
405 static int
406 dlresolveLink(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
487 static int
488 dlGetObjectName(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
565 static const char *
566 getcomponent(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
591 static int
592 dlpath2QSYS(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
737 static int
738 dl_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
751 static int
752 dl_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
813 static int
814 dl_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
831 static int
832 dl_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
861 static int
862 dl_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
877 static int
878 dl_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
925 static int
926 dl_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
949 static int
950 dlreinit(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
976 err:
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
985 void *
986 dlsym(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
1012 error:
1013         dlseterror_from_exception(&excbuf);
1014         return (void *) NULL;
1015 }
1016
1017
1018 int
1019 dlclose(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
1046 static void *
1047 dlopenqsys(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
1145 error2:
1146         free((char *) dlip);
1147         dlunlock();
1148
1149 error1:
1150         dlseterror_from_exception(&excbuf);
1151         return (void *) NULL;
1152 }
1153
1154
1155 void *
1156 dlopen(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 }