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
dlthreadterm(void * mem)99 dlthreadterm(void * mem)
100 
101 {
102         free(mem);
103         pthread_setspecific(dlkey, NULL);
104 }
105 
106 
107 static void
dlterm(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
dlinit(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
dlthreadinit(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
dllock(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
dlunlock(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 *
dlerror(void)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
dlseterror_from_errno(unsigned int err_no)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
dlseterror_from_exception(volatile _INTRPT_Hndlr_Parms_T * excp)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
dlparentpath(const char * path,size_t len)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
dlmakepath(char * path,size_t pathlen,const char * tail,size_t taillen)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
dlresolveLink(const char * path,char * buf,size_t bufsiz)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
dlGetObjectName(Qp0l_QSYS_Info_t * qsysinfo,const char * dir,int dirlen,const char * link)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 *
getcomponent(char * dst,const char * src)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
dlpath2QSYS(Qp0l_QSYS_Info_t * qsysinfo,const char * path,const char * dftlib)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
dl_ifs_link(Qp0l_QSYS_Info_t * qsysinfo,const char * pathname)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
dl_path_link(Qp0l_QSYS_Info_t * qsysinfo,const char * pathvar,const char * filename,int (* testproc)(const Qp0l_QSYS_Info_t *))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
dl_DB2_path(Qp0l_QSYS_Info_t * qsysinfo,const char * pathname)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
dl_DB2_name(char * dst,const char * name)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
dl_qualified_object(Qp0l_QSYS_Info_t * qsysinfo,const char * pathname)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
dl_lib_object(Qp0l_QSYS_Info_t * qsysinfo,const char * libname,const char * pathname)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
dl_is_srvpgm(const Qp0l_QSYS_Info_t * qsysinfo)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
dlreinit(dlinfo * dlip)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 *
dlsym(void * handle,const char * symbol)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
dlclose(void * handle)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 *
dlopenqsys(const Qp0l_QSYS_Info_t * dllinfo)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 *
dlopen(const char * filename,int flag)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 }
1214