aboutsummaryrefslogtreecommitdiff
path: root/libxml2-2.9.10/os400/dlfcn/dlfcn.c
diff options
context:
space:
mode:
Diffstat (limited to 'libxml2-2.9.10/os400/dlfcn/dlfcn.c')
-rw-r--r--libxml2-2.9.10/os400/dlfcn/dlfcn.c1213
1 files changed, 1213 insertions, 0 deletions
diff --git a/libxml2-2.9.10/os400/dlfcn/dlfcn.c b/libxml2-2.9.10/os400/dlfcn/dlfcn.c
new file mode 100644
index 0000000..77190b3
--- /dev/null
+++ b/libxml2-2.9.10/os400/dlfcn/dlfcn.c
@@ -0,0 +1,1213 @@
+/**
+*** dlopen(), dlclose() dlsym(), dlerror() emulation for OS/400.
+***
+*** See Copyright for the status of this software.
+***
+*** Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A.
+**/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <except.h> /* AS400 exceptions. */
+#include <miptrnam.h> /* MI pointers support. */
+#include <qusec.h> /* Error structures. */
+#include <qp0lstdi.h> /* Path to QSYS object name. */
+#include <qp0z1170.h> /* For Qp0zInitEnv(). */
+#include <qleawi.h> /* For QleActBndPgmLong() definitions. */
+#include <qsy.h> /* Qualified name structure. */
+#include <qmhrtvm.h> /* Retrieve message from message file. */
+
+#include <mih/rinzstat.h>
+#include <mih/matactex.h>
+
+#include "libxml/hash.h"
+#include "dlfcn.h"
+
+
+/**
+*** Maximum internal path length.
+**/
+
+#define MAXPATHLEN 5120
+
+
+/**
+*** Maximum error string length.
+**/
+
+#define MAX_ERR_STR 511
+
+
+/**
+*** Field address macro.
+**/
+
+#define offset_by(t, b, o) ((t *) ((char *) (b) + (unsigned int) (o)))
+
+
+/**
+*** Global flags.
+**/
+
+#define INITED 000001 /* Package has been initialized. */
+#define THREADS 000002 /* Multithreaded job. */
+#define MULTIBUF 000004 /* One error buffer per thread. */
+
+
+/**
+*** DLL handle private structure.
+**/
+
+typedef struct {
+ Qle_ABP_Info_Long_t actinfo; /* Activation information. */
+ _SYSPTR pointer; /* Pointer to DLL object. */
+ unsigned int actcount; /* Activation count. */
+} dlinfo;
+
+
+/**
+*** Per-thread structure.
+**/
+
+typedef struct {
+ unsigned int lockcount; /* Mutex lock count. */
+ unsigned int iserror; /* Flag error present. */
+ char str[MAX_ERR_STR + 1]; /* Error string buffer. */
+} dlts_t;
+
+
+static pthread_mutex_t dlmutex = PTHREAD_MUTEX_INITIALIZER;
+static xmlHashTablePtr dldir = (xmlHashTablePtr) NULL; /* DLL directory. */
+static unsigned int dlflags = 0; /* Package flags. */
+static pthread_key_t dlkey;
+static dlts_t static_buf; /* Static error buffer. */
+
+
+
+static void
+dlthreadterm(void * mem)
+
+{
+ free(mem);
+ pthread_setspecific(dlkey, NULL);
+}
+
+
+static void
+dlterm(void)
+
+{
+ void * p;
+
+ if (dlflags & MULTIBUF) {
+ p = pthread_getspecific(dlkey);
+
+ if (p)
+ dlthreadterm(p);
+ }
+
+ if (dlflags & THREADS)
+ pthread_mutex_lock(&dlmutex);
+
+ if (dldir) {
+ xmlHashFree(dldir, (xmlHashDeallocator) NULL);
+ dldir = NULL;
+ }
+
+ if (dlflags & MULTIBUF)
+ pthread_key_delete(dlkey);
+
+ dlflags |= ~(INITED | MULTIBUF);
+ pthread_mutex_unlock(&dlmutex);
+ pthread_mutex_destroy(&dlmutex);
+}
+
+
+static void
+dlinit(void)
+
+{
+ int locked;
+
+ /**
+ *** Initialize the package.
+ *** Should be call once per process.
+ **/
+
+ locked = !pthread_mutex_lock(&dlmutex);
+
+ if (!(dlflags & INITED)) {
+ dlflags &= ~THREADS;
+
+ if (locked)
+ dlflags |= THREADS;
+
+ Qp0zInitEnv();
+ dldir = xmlHashCreate(16);
+ dlflags &= ~MULTIBUF;
+
+ if (dlflags & THREADS)
+ if (!pthread_key_create(&dlkey, dlthreadterm))
+ dlflags |= MULTIBUF;
+
+ atexit(dlterm);
+ dlflags |= INITED;
+ }
+
+ if (locked)
+ pthread_mutex_unlock(&dlmutex);
+}
+
+
+static void
+dlthreadinit(void)
+
+{
+ dlts_t * p;
+
+ if (!(dlflags & INITED))
+ dlinit();
+
+ if (dlflags & MULTIBUF) {
+ p = pthread_getspecific(dlkey);
+
+ if (!p) {
+ p = (dlts_t *) malloc(sizeof *p);
+
+ if (p) {
+ p->lockcount = 0;
+ p->iserror = 0;
+
+ if (pthread_setspecific(dlkey, p))
+ free(p);
+ }
+ }
+ }
+}
+
+
+static void
+dllock(void)
+
+{
+ dlts_t * p;
+
+ if (!(dlflags & THREADS))
+ return;
+
+ if (dlflags & MULTIBUF) {
+ p = pthread_getspecific(dlkey);
+
+ if (p && p->lockcount) {
+ p->lockcount++;
+ return;
+ }
+ }
+ else
+ p = (dlts_t *) NULL;
+
+ if (pthread_mutex_lock(&dlmutex))
+ return;
+
+ if (p)
+ p->lockcount++;
+}
+
+
+static void
+dlunlock(void)
+
+{
+ dlts_t * p;
+
+ if (!(dlflags & THREADS))
+ return;
+
+ if (dlflags & MULTIBUF) {
+ p = pthread_getspecific(dlkey);
+
+ if (p && p->lockcount > 1) {
+ p->lockcount--;
+ return;
+ }
+ }
+ else
+ p = (dlts_t *) NULL;
+
+ if (pthread_mutex_unlock(&dlmutex))
+ return;
+
+ if (p)
+ p->lockcount--;
+}
+
+
+const char *
+dlerror(void)
+
+{
+ dlts_t * p;
+
+ dlthreadinit();
+
+ if (!(dlflags & MULTIBUF))
+ p = &static_buf;
+ else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
+ p = &static_buf;
+
+ if (!p->iserror)
+ return (const char *) NULL;
+
+ p->iserror = 0;
+ return p->str;
+}
+
+
+static void
+dlseterror_from_errno(unsigned int err_no)
+
+{
+ dlts_t * p;
+
+ if (!(dlflags & MULTIBUF))
+ p = &static_buf;
+ else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
+ p = &static_buf;
+
+ strcpy(p->str, strerror(err_no));
+ p->iserror = 1;
+}
+
+
+static void
+dlseterror_from_exception(volatile _INTRPT_Hndlr_Parms_T * excp)
+
+{
+ int i;
+ Qmh_Rtvm_RTVM0300_t * imp;
+ char * cp;
+ _INTRPT_Hndlr_Parms_T * p;
+ dlts_t * q;
+ char rtvmbuf[30000];
+ Qus_EC_t errinfo;
+
+ p = (_INTRPT_Hndlr_Parms_T *) excp;
+ errinfo.Bytes_Provided = 0; /* Exception on error. */
+ QMHRTVM(rtvmbuf, sizeof rtvmbuf, "RTVM0300", p->Msg_Id,
+ "QCPFMSG QSYS ", p->Ex_Data, p->Msg_Data_Len,
+ "*YES ", "*NO ", &errinfo);
+ imp = offset_by(Qmh_Rtvm_RTVM0300_t, rtvmbuf, 0);
+
+ if (!(dlflags & MULTIBUF))
+ q = &static_buf;
+ else if (!(q = (dlts_t *) pthread_getspecific(dlkey)))
+ q = &static_buf;
+
+ if (i = imp->Length_Message_Returned)
+ cp = offset_by(char, imp, imp->Offset_Message_Returned);
+ else if (i = imp->Length_Help_Returned)
+ cp = offset_by(char, imp, imp->Offset_Help_Returned);
+ else {
+ q->iserror = 0;
+ return;
+ }
+
+ q->iserror = 1;
+
+ if (i > sizeof q->str - 1)
+ i = sizeof q->str - 1;
+
+ memcpy(q->str, cp, i);
+ q->str[i] = '\0';
+}
+
+
+static int
+dlparentpath(const char * path, size_t len)
+
+{
+ if (len <= 1)
+ return len;
+
+ while (path[--len] != '/')
+ ;
+
+ return len? len: 1;
+}
+
+
+static int
+dlmakepath(char * path, size_t pathlen, const char * tail, size_t taillen)
+
+{
+ int i;
+
+ if (taillen && tail[0] == '/')
+ pathlen = 0;
+
+ for (;;) {
+ while (taillen && *tail == '/') {
+ tail++;
+ taillen--;
+ }
+
+ if (!taillen)
+ break;
+
+ for (i = 0; i < taillen; i++)
+ if (tail[i] == '/')
+ break;
+
+ if (*tail == '.')
+ switch (i) {
+
+ case 2:
+ if (tail[1] != '.')
+ break;
+
+ pathlen = dlparentpath(path, pathlen);
+
+ case 1:
+ tail += i;
+ taillen -= i;
+ continue;
+ }
+
+ if (pathlen + i + 1 >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ path[pathlen++] = '/';
+ memcpy(path + pathlen, tail, i);
+ pathlen += i;
+ }
+
+ if (!pathlen)
+ path[pathlen++] = '/';
+
+ path[pathlen] = '\0';
+ return pathlen;
+}
+
+
+static int
+dlresolveLink(const char * path, char * buf, size_t bufsiz)
+
+{
+ int n;
+ int l1;
+ int l2;
+ struct stat sbuf;
+ char buf1[MAXPATHLEN + 1];
+ char buf2[MAXPATHLEN + 1];
+
+ /**
+ *** Resolve symbolic link to IFS object name.
+ **/
+
+ if (!buf) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (!path || !*path || !bufsiz) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*path != '/') {
+ if (!getcwd(buf1, sizeof buf1))
+ return -1;
+
+ l1 = strlen(buf1);
+ }
+ else
+ l1 = 0;
+
+ l1 = dlmakepath(buf1, l1, path, strlen(path));
+ n = 0;
+
+ for (;;) {
+ if (l1 < 0)
+ return -1;
+
+ if (n++ >= 256) {
+ errno = ELOOP;
+ return -1;
+ }
+
+ if (lstat(buf1, &sbuf)) {
+ if (errno == ENOENT)
+ break;
+
+ return -1;
+ }
+
+ if (!S_ISLNK(sbuf.st_mode))
+ break;
+
+ if (sbuf.st_size > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ l2 = readlink(buf1, buf2, MAXPATHLEN + 1);
+
+ if (l2 < 0)
+ return -1;
+
+ if (buf2[0] != '/')
+ l1 = dlparentpath(buf1, l1);
+
+ l1 = dlmakepath(buf1, l1, buf2, l2);
+ }
+
+ if (l1 >= bufsiz) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ memcpy(buf, buf1, l1 + 1);
+ return l1;
+}
+
+
+static int
+dlGetObjectName(Qp0l_QSYS_Info_t * qsysinfo, const char * dir,
+ int dirlen, const char * link)
+
+{
+ int n;
+ char * namebuf;
+ Qlg_Path_Name_T * qptp;
+ char pathbuf[sizeof(Qlg_Path_Name_T) + _QP0L_DIR_NAME_LG + 4];
+ Qus_EC_t errinfo;
+ struct stat sbuf;
+
+ /**
+ *** Get QSYS object library/name/member and type corresponding to
+ *** the symbolic `link' in directory `dir'.
+ **/
+
+ if (!qsysinfo) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (!dir && !link) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ qptp = (Qlg_Path_Name_T *) pathbuf;
+ namebuf = pathbuf + sizeof(Qlg_Path_Name_T);
+ n = 0;
+
+ /**
+ *** Build full path.
+ **/
+
+ if (dir) {
+ if (dirlen < 0 || dirlen > _QP0L_DIR_NAME_LG + 4)
+ dirlen = _QP0L_DIR_NAME_LG + 4;
+
+ while (*dir && n < dirlen)
+ namebuf[n++] = *dir++;
+ }
+
+ if (n && namebuf[n - 1] == '/')
+ n--;
+
+ if (link) {
+ if (*link && *link != '/' && n < _QP0L_DIR_NAME_LG + 4)
+ namebuf[n++] = '/';
+
+ while (*link && n < _QP0L_DIR_NAME_LG + 4)
+ namebuf[n++] = *link++;
+ }
+
+ if (!n || n > _QP0L_DIR_NAME_LG) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ namebuf[n] = '\0';
+ n = dlresolveLink(namebuf, namebuf, _QP0L_DIR_NAME_LG + 1);
+
+ if (n == -1)
+ return -1;
+
+ if (stat(namebuf, &sbuf))
+ return -1;
+
+ memset((char *) qptp, 0, sizeof *qptp);
+ qptp->Path_Length = n;
+ qptp->Path_Name_Delimiter[0] = '/';
+ errinfo.Bytes_Provided = sizeof errinfo;
+ Qp0lCvtPathToQSYSObjName(qptp, qsysinfo, "QSYS0100", sizeof *qsysinfo,
+ 0, &errinfo);
+ return errinfo.Bytes_Available? -1: 0;
+}
+
+
+static const char *
+getcomponent(char * dst, const char * src)
+
+{
+ int i;
+
+ /**
+ *** Get a path component of at most 10 characters and
+ *** map it to upper case.
+ *** Return the address of the next delimiter in source.
+ **/
+
+ for (i = 0;; src++) {
+ if (!*src || *src == ' ' || *src == '/') {
+ *dst = '\0';
+ return src;
+ }
+
+ if (i < 10) {
+ *dst++ = toupper(*src);
+ i++;
+ }
+ }
+}
+
+
+static int
+dlpath2QSYS(Qp0l_QSYS_Info_t * qsysinfo, const char * path, const char * dftlib)
+
+{
+ unsigned int flags;
+ char * cp;
+
+ /**
+ *** Convert the given path to a QSYS object name.
+ *** Syntax rules for paths are:
+ ***
+ *** '/'+ [ <library> [ '/'+ <file> [ '/'+ <member> ] ] '/'* ]
+ *** <library> '/'+ <file> [ '/'+ <member> ] '/'*
+ *** <file> '/'*
+ ***
+ *** If default library is not given, *LIBL is assumed.
+ *** Components may no contain spaces. They are translated to
+ *** uppercase. Only the first 10 characters are significant.
+ *** There is no check for the validity of the given components and
+ *** for the object existence.
+ *** Component types are not in the path, but generated internally.
+ *** CCSID is not processed.
+ ***
+ *** Return 0 upon success, else -1.
+ **/
+
+ if (!qsysinfo || !path) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /**
+ *** Strip leading spaces.
+ **/
+
+ while (*path == ' ')
+ path++;
+
+ /**
+ *** Check for null path.
+ **/
+
+ if (!*path) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /**
+ *** Preset the result structure.
+ **/
+
+ memset((char *) qsysinfo, 0, sizeof *qsysinfo);
+
+ /**
+ *** Determine the format.
+ **/
+
+ if (*path == '/') {
+ /**
+ *** Library component present.
+ **/
+
+ while (*++path == '/')
+ ;
+
+ if (!*path || *path == ' ')
+ strcpy(qsysinfo->Lib_Name, "QSYS");
+ else
+ path = getcomponent(qsysinfo->Lib_Name, path);
+
+ /**
+ *** Check for file component and get it.
+ **/
+
+ if (*path == '/') {
+ while (*++path == '/')
+ ;
+
+ if (*path && *path != ' ')
+ path = getcomponent(qsysinfo->Obj_Name, path);
+ }
+ }
+ else {
+ /**
+ *** The mandatory component is the <file>.
+ **/
+
+ path = getcomponent(qsysinfo->Obj_Name, path);
+
+ while (*path == '/')
+ path++;
+
+ /**
+ *** If there is a second component, move the first to
+ *** the library name and parse the file name.
+ **/
+
+ if (*path && *path != ' ') {
+ strcpy(qsysinfo->Lib_Name, qsysinfo->Obj_Name);
+ memset(qsysinfo->Obj_Name, 0,
+ sizeof qsysinfo->Obj_Name);
+ path = getcomponent(qsysinfo->Obj_Name, path);
+ }
+ else
+ strcpy(qsysinfo->Lib_Name, dftlib? dftlib: "*LIBL");
+ }
+
+ /**
+ *** Check and set-up member.
+ **/
+
+ while (*path == '/')
+ path++;
+
+ if (*path && *path != ' ') {
+ path = getcomponent(qsysinfo->Mbr_Name, path);
+ strcpy(qsysinfo->Mbr_Type, "*MBR");
+
+ while (*path == '/')
+ path++;
+ }
+
+ strcpy(qsysinfo->Lib_Type, "*LIB");
+
+ if (qsysinfo->Obj_Name[0])
+ strcpy(qsysinfo->Obj_Type, "*FILE");
+
+ qsysinfo->Bytes_Returned = sizeof *qsysinfo;
+ qsysinfo->Bytes_Available = sizeof *qsysinfo;
+
+ /**
+ *** Strip trailing spaces.
+ **/
+
+ while (*path == ' ')
+ path++;
+
+ if (*path) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+dl_ifs_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
+
+{
+ /**
+ *** If `pathname' is a link found in IFS, set `qsysinfo' to its
+ *** DB2 name.
+ *** Return 0 if OK, else -1.
+ **/
+
+ return dlGetObjectName(qsysinfo, (const char *) NULL, 0, pathname);
+}
+
+
+static int
+dl_path_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathvar,
+ const char * filename, int (* testproc)(const Qp0l_QSYS_Info_t *))
+
+{
+ const char * p;
+ const char * q;
+ unsigned int i;
+ const char * path;
+
+ /**
+ *** If `filename' is not a path and is a link found in one of the
+ *** colon-separated paths in environment variable `pathvar',
+ *** set `qsysinfo' to its DB2 name.
+ *** Return 0 if OK, else -1.
+ **/
+
+ i = _QP0L_DIR_NAME_LG;
+
+ for (p = filename; *p; p++)
+ if (*p == '/' || !--i)
+ return -1; /* Too long or a path. */
+
+ /**
+ *** Make sure we have the LD_LIBRARY_PATH environment
+ *** variable value.
+ **/
+
+ path = getenv(pathvar);
+
+ if (!path)
+ return -1; /* No path list. */
+
+ /**
+ *** Try in each path listed.
+ **/
+
+ q = path;
+
+ if (!*q)
+ return -1; /* No path list. */
+
+ for (;;) {
+ for (p = q; *p && *p != ':'; p++)
+ ;
+
+ if (p > q) /* Ignore null path. */
+ if (!dlGetObjectName(qsysinfo, q, p - q, filename))
+ if (!testproc || (*testproc)(qsysinfo))
+ return 0; /* Found: return. */
+
+ if (!*p)
+ break;
+
+ q = p + 1;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+
+static int
+dl_DB2_path(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
+
+{
+ if (dlpath2QSYS(qsysinfo, pathname, (const char *) NULL))
+ return -1;
+
+ if (qsysinfo->Mbr_Type[0])
+ return -1; /* Service program may not have members. */
+
+ if (!qsysinfo->Obj_Type[0])
+ return -1; /* Object must be specified. */
+
+ strcpy(qsysinfo->Obj_Type, "*SRVPGM"); /* Set our object type. */
+ return 0;
+}
+
+
+static int
+dl_DB2_name(char * dst, const char * name)
+
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ switch (*name) {
+
+ default:
+ if (!islower(*name))
+ break;
+
+ case '\0':
+ case '/':
+ case ' ':
+ return -1;
+ }
+
+ *dst++ = *name++;
+ }
+
+ if (!i)
+ return -1;
+
+ *dst = '\0';
+ return 0;
+}
+
+
+static int
+dl_qualified_object(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
+
+{
+ memset((char *) qsysinfo, 0, sizeof *qsysinfo);
+
+ if (dl_DB2_name(qsysinfo->Obj_Name, pathname) ||
+ dl_DB2_name(qsysinfo->Lib_Name, pathname + 10))
+ return -1;
+
+ strcpy(qsysinfo->Lib_Type, "*LIB");
+ strcpy(qsysinfo->Obj_Type, "*SRVPGM");
+ return 0;
+}
+
+
+static int
+dl_lib_object(Qp0l_QSYS_Info_t * qsysinfo,
+ const char * libname, const char * pathname)
+
+{
+ int i;
+ char * cp;
+
+ strcpy(qsysinfo->Lib_Name, libname);
+ strcpy(qsysinfo->Lib_Type, "*LIB");
+ strcpy(qsysinfo->Obj_Type, "*SRVPGM");
+ cp = qsysinfo->Obj_Name;
+
+ while (*pathname == ' ')
+ pathname++;
+
+ for (i = 0;; pathname++) {
+ switch (*pathname) {
+
+ case '\0':
+ case ' ':
+ break;
+
+ case '/':
+ return -1;
+
+ default:
+ if (i < 10)
+ *cp++ = toupper(*pathname);
+
+ i++;
+ continue;
+ }
+
+ break;
+ }
+
+ while (*pathname == ' ')
+ pathname++;
+
+ if (!i || *pathname)
+ return -1;
+
+ *cp = '\0';
+ return 0;
+}
+
+
+static int
+dl_is_srvpgm(const Qp0l_QSYS_Info_t * qsysinfo)
+
+{
+ struct stat sbuf;
+ char namebuf[100];
+
+ if (!qsysinfo->Lib_Name[0] || strcmp(qsysinfo->Lib_Type, "*LIB") ||
+ !qsysinfo->Obj_Name[0] || strcmp(qsysinfo->Obj_Type, "*SRVPGM") ||
+ qsysinfo->Mbr_Name[0] || qsysinfo->Mbr_Type[0])
+ return 0;
+
+ /**
+ *** Build the IFS path name for the DB2 object.
+ **/
+
+ sprintf(namebuf, "%s/%s.LIB/%s.SRVPGM",
+ strcmp(qsysinfo->Lib_Name, "QSYS")? "/QSYS.LIB": "",
+ qsysinfo->Lib_Name, qsysinfo->Obj_Name);
+
+ return stat(namebuf, &sbuf) == 0;
+}
+
+
+static int
+dlreinit(dlinfo * dlip)
+
+{
+ RINZ_TEMPL_T t;
+ RINZ_TEMPL_T * p;
+ volatile _INTRPT_Hndlr_Parms_T excbuf;
+
+ if (dlip->actinfo.Flags & QLE_ABP_WAS_ACTIVE)
+ return 0;
+
+ /**
+ *** Attempt to reinitialize the service program that was loaded.
+ *** The service program must be created to allow re-initialization:
+ *** ALWRINZ(*YES) for this to work. The default is
+ *** ALWRINZ(*NO).
+ **/
+
+#pragma exception_handler(err, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
+ p = &t;
+ t.rinz_pgm = dlip->pointer;
+ t.rinz_agpmk = dlip->actinfo.Act_Grp_Mark;
+ _RINZSTAT(p);
+#pragma disable_handler
+
+ return 0;
+
+err:
+ if (!memcmp((char *) excbuf.Msg_Id, "MCH4421", 7))
+ return 0; /* Program cannot be reinitialized. */
+
+ dlseterror_from_exception(&excbuf);
+ return -1;
+}
+
+
+void *
+dlsym(void * handle, const char * symbol)
+
+{
+ dlinfo * dlip;
+ void * p;
+ int export_type;
+ Qus_EC_t errinfo;
+ volatile _INTRPT_Hndlr_Parms_T excbuf;
+ static int zero = 0;
+
+ dlthreadinit();
+
+ if (!handle || !symbol) {
+ dlseterror_from_errno(EFAULT);
+ return (void *) NULL;
+ }
+
+ dlip = (dlinfo *) handle;
+
+#pragma exception_handler(error, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
+ errinfo.Bytes_Provided = 0;
+ QleGetExpLong(&dlip->actinfo.Act_Mark, &zero, &zero,
+ (char *) symbol, &p, &export_type, &errinfo);
+ return p;
+#pragma disable_handler
+
+error:
+ dlseterror_from_exception(&excbuf);
+ return (void *) NULL;
+}
+
+
+int
+dlclose(void * handle)
+
+{
+ dlinfo * dlip;
+ void (* _fini)(void);
+
+ dlthreadinit();
+
+ if (!handle) {
+ dlseterror_from_errno(EFAULT);
+ return -1;
+ }
+
+ dlip = (dlinfo *) handle;
+
+ if (dlip->actcount) {
+ if (--(dlip->actcount))
+ return 0;
+
+ if (_fini = dlsym(handle, "_fini"))
+ (*_fini)();
+ }
+
+ return dlreinit(dlip);
+}
+
+
+static void *
+dlopenqsys(const Qp0l_QSYS_Info_t * dllinfo)
+
+{
+ dlinfo * dlip;
+ dlinfo * dlip2;
+ void (* _init)(void);
+ unsigned int i;
+ _SYSPTR pgmptr;
+ unsigned long long actmark;
+ Qus_EC_t errinfo;
+ char actmarkstr[2 * sizeof actmark + 1];
+ static int actinfo_size = sizeof dlip->actinfo;
+ volatile _INTRPT_Hndlr_Parms_T excbuf;
+
+ /**
+ *** Capture any type of error and if any occurs,
+ *** return not found.
+ **/
+
+#pragma exception_handler(error1, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
+ pgmptr = rslvsp(WLI_SRVPGM, (char *) dllinfo->Obj_Name,
+ (char *) dllinfo->Lib_Name ,_AUTH_NONE);
+
+ if (!pgmptr) {
+ errno = ENOENT;
+ return (void *) NULL;
+ }
+
+ /**
+ *** Create a new DLL info block.
+ **/
+
+ dlip = (dlinfo *) malloc(sizeof *dlip);
+
+ if (!dlip)
+ return (void *) NULL; /* Cannot create block. */
+#pragma disable_handler
+
+ dllock();
+
+#pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
+ memset((char *) dlip, 0, sizeof *dlip);
+ dlip->pointer = pgmptr;
+
+ /**
+ *** Activate the DLL.
+ **/
+
+ errinfo.Bytes_Provided = 0;
+ QleActBndPgmLong(&pgmptr, &actmark,
+ &dlip->actinfo, &actinfo_size, &errinfo);
+ dlip->actinfo.Act_Mark = actmark;
+
+ /**
+ *** Dummy string encoding activation mark to use as hash table key.
+ **/
+
+ for (i = 0; actmark; actmark >>= 6)
+ actmarkstr[i++] = 0x40 + (actmark & 0x3F);
+
+ actmarkstr[i] = '\0';
+
+ /**
+ *** Check if already activated.
+ **/
+
+ dlip2 = (dlinfo *) xmlHashLookup(dldir, actmarkstr);
+
+ if (dlip2) {
+ free((char *) dlip);
+ dlip = dlip2;
+ }
+ else if (xmlHashAddEntry(dldir, (const xmlChar *) actmarkstr, dlip)) {
+ dlreinit(dlip);
+ free((char *) dlip);
+ dlunlock();
+ return (void *) NULL;
+ }
+#pragma disable_handler
+
+#pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
+
+ /**
+ *** Bump activation counter.
+ **/
+
+ if (!(dlip->actcount++) && (_init = dlsym(dlip, "_init")))
+ (*_init)();
+
+ dlunlock();
+
+ /**
+ *** Return the handle.
+ **/
+
+ return (void *) dlip;
+#pragma disable_handler
+
+error2:
+ free((char *) dlip);
+ dlunlock();
+
+error1:
+ dlseterror_from_exception(&excbuf);
+ return (void *) NULL;
+}
+
+
+void *
+dlopen(const char * filename, int flag)
+
+{
+ void * dlhandle;
+ int sverrno;
+ Qp0l_QSYS_Info_t dllinfo;
+
+ sverrno = errno;
+ errno = 0;
+
+ dlthreadinit();
+
+ if (!filename) {
+ dlseterror_from_errno(EFAULT);
+ errno = sverrno;
+ return NULL;
+ }
+
+ /**
+ *** Try to locate the object in the following order:
+ *** _ `filename' is an IFS path.
+ *** _ `filename' is not a path and resides in one of
+ *** LD_LIBRARY_PATH colon-separated paths.
+ *** _ `filename' is not a path and resides in one of
+ *** PATH colon-separated paths.
+ *** _ `filename' is a DB2 path (as /library/object).
+ *** _ `filename' is a qualified object name.
+ *** _ `filename' is an object in *CURLIB.
+ *** _ `filename' is an object in *LIBL.
+ **/
+
+ if (!dl_ifs_link(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_path_link(&dllinfo,
+ "LD_LIBRARY_PATH", filename, dl_is_srvpgm))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_path_link(&dllinfo, "PATH", filename, dl_is_srvpgm))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_DB2_path(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_qualified_object(&dllinfo, filename) &&
+ dl_is_srvpgm(&dllinfo))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_lib_object(&dllinfo, "*CURLIB", filename) &&
+ dl_is_srvpgm(&dllinfo))
+ dlhandle = dlopenqsys(&dllinfo);
+ else if (!dl_lib_object(&dllinfo, "*LIBL", filename) &&
+ dl_is_srvpgm(&dllinfo))
+ dlhandle = dlopenqsys(&dllinfo);
+ else
+ dlhandle = NULL;
+
+ if (!dlhandle && errno)
+ dlseterror_from_errno(errno);
+
+ errno = sverrno;
+ return dlhandle;
+}