[libxml2] OS400: create architecture directory. Implement dlfcn emulation.



commit a6c5b022f1d515f20beb01b70466893b64e33325
Author: Patrick Monnerat <pm datasphere ch>
Date:   Tue Mar 4 15:47:08 2014 +0100

    OS400: create architecture directory. Implement dlfcn emulation.

 os400/dlfcn/dlfcn.c | 1213 +++++++++++++++++++++++++++++++++++++++++++++++++++
 os400/dlfcn/dlfcn.h |   32 ++
 2 files changed, 1245 insertions(+), 0 deletions(-)
---
diff --git a/os400/dlfcn/dlfcn.c b/os400/dlfcn/dlfcn.c
new file mode 100644
index 0000000..1488e12
--- /dev/null
+++ b/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;
+}
diff --git a/os400/dlfcn/dlfcn.h b/os400/dlfcn/dlfcn.h
new file mode 100644
index 0000000..0cf691e
--- /dev/null
+++ b/os400/dlfcn/dlfcn.h
@@ -0,0 +1,32 @@
+/**
+***     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.
+**/
+
+#ifndef _DLFCN_H_
+#define _DLFCN_H_
+
+
+/**
+***     Flags for dlopen().
+***     Ignored for OS400.
+**/
+
+#define RTLD_LAZY               000
+#define RTLD_NOW                001
+#define RTLD_GLOBAL             010
+
+
+/**
+***     Prototypes.
+**/
+
+extern void *           dlopen(const char * filename, int flag);
+extern void *           dlsym(void * handle, const char * symbol);
+extern const char *     dlerror(void);
+extern int              dlclose(void * handle);
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]