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