Home | History | Annotate | Download | only in dlfcn
      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 (at) datasphere.ch>, DATASPHERE S.A.
      7 **/
      8 
      9 #include <stdarg.h>
     10 #include <stdio.h>
     11 #include <ctype.h>
     12 #include <errno.h>
     13 #include <stdlib.h>
     14 #include <unistd.h>
     15 #include <string.h>
     16 #include <dirent.h>
     17 #include <pthread.h>
     18 
     19 #include <sys/types.h>
     20 #include <sys/stat.h>
     21 
     22 #include <except.h>             /* AS400 exceptions. */
     23 #include <miptrnam.h>           /* MI pointers support. */
     24 #include <qusec.h>              /* Error structures. */
     25 #include <qp0lstdi.h>           /* Path to QSYS object name. */
     26 #include <qp0z1170.h>           /* For Qp0zInitEnv(). */
     27 #include <qleawi.h>             /* For QleActBndPgmLong() definitions. */
     28 #include <qsy.h>                /* Qualified name structure. */
     29 #include <qmhrtvm.h>            /* Retrieve message from message file. */
     30 
     31 #include <mih/rinzstat.h>
     32 #include <mih/matactex.h>
     33 
     34 #include "libxml/hash.h"
     35 #include "dlfcn.h"
     36 
     37 
     38 /**
     39 ***     Maximum internal path length.
     40 **/
     41 
     42 #define MAXPATHLEN              5120
     43 
     44 
     45 /**
     46 ***     Maximum error string length.
     47 **/
     48 
     49 #define MAX_ERR_STR             511
     50 
     51 
     52 /**
     53 ***     Field address macro.
     54 **/
     55 
     56 #define offset_by(t, b, o)      ((t *) ((char *) (b) + (unsigned int) (o)))
     57 
     58 
     59 /**
     60 ***     Global flags.
     61 **/
     62 
     63 #define INITED          000001          /* Package has been initialized. */
     64 #define THREADS         000002          /* Multithreaded job. */
     65 #define MULTIBUF        000004          /* One error buffer per thread. */
     66 
     67 
     68 /**
     69 ***     DLL handle private structure.
     70 **/
     71 
     72 typedef struct {
     73         Qle_ABP_Info_Long_t     actinfo;        /* Activation information. */
     74         _SYSPTR                 pointer;        /* Pointer to DLL object. */
     75         unsigned int            actcount;       /* Activation count. */
     76 }               dlinfo;
     77 
     78 
     79 /**
     80 ***     Per-thread structure.
     81 **/
     82 
     83 typedef struct {
     84         unsigned int    lockcount;              /* Mutex lock count. */
     85         unsigned int    iserror;                /* Flag error present. */
     86         char            str[MAX_ERR_STR + 1];   /* Error string buffer. */
     87 }               dlts_t;
     88 
     89 
     90 static pthread_mutex_t  dlmutex = PTHREAD_MUTEX_INITIALIZER;
     91 static xmlHashTablePtr  dldir = (xmlHashTablePtr) NULL; /* DLL directory. */
     92 static unsigned int     dlflags = 0;                    /* Package flags. */
     93 static pthread_key_t    dlkey;
     94 static dlts_t           static_buf;             /* Static error buffer. */
     95 
     96 
     97 
     98 static void
     99 dlthreadterm(void * mem)
    100 
    101 {
    102         free(mem);
    103         pthread_setspecific(dlkey, NULL);
    104 }
    105 
    106 
    107 static void
    108 dlterm(void)
    109 
    110 {
    111         void * p;
    112 
    113         if (dlflags & MULTIBUF) {
    114                 p = pthread_getspecific(dlkey);
    115 
    116                 if (p)
    117                         dlthreadterm(p);
    118                 }
    119 
    120         if (dlflags & THREADS)
    121                 pthread_mutex_lock(&dlmutex);
    122 
    123         if (dldir) {
    124                 xmlHashFree(dldir, (xmlHashDeallocator) NULL);
    125                 dldir = NULL;
    126                 }
    127 
    128         if (dlflags & MULTIBUF)
    129                 pthread_key_delete(dlkey);
    130 
    131         dlflags |= ~(INITED | MULTIBUF);
    132         pthread_mutex_unlock(&dlmutex);
    133         pthread_mutex_destroy(&dlmutex);
    134 }
    135 
    136 
    137 static void
    138 dlinit(void)
    139 
    140 {
    141         int locked;
    142 
    143         /**
    144         ***     Initialize the package.
    145         ***     Should be call once per process.
    146         **/
    147 
    148         locked = !pthread_mutex_lock(&dlmutex);
    149 
    150         if (!(dlflags & INITED)) {
    151                 dlflags &= ~THREADS;
    152 
    153                 if (locked)
    154                         dlflags |= THREADS;
    155 
    156                 Qp0zInitEnv();
    157                 dldir = xmlHashCreate(16);
    158                 dlflags &= ~MULTIBUF;
    159 
    160                 if (dlflags & THREADS)
    161                         if (!pthread_key_create(&dlkey, dlthreadterm))
    162                                 dlflags |= MULTIBUF;
    163 
    164                 atexit(dlterm);
    165                 dlflags |= INITED;
    166                 }
    167 
    168         if (locked)
    169                 pthread_mutex_unlock(&dlmutex);
    170 }
    171 
    172 
    173 static void
    174 dlthreadinit(void)
    175 
    176 {
    177         dlts_t * p;
    178 
    179         if (!(dlflags & INITED))
    180                 dlinit();
    181 
    182         if (dlflags & MULTIBUF) {
    183                 p = pthread_getspecific(dlkey);
    184 
    185                 if (!p) {
    186                         p = (dlts_t *) malloc(sizeof *p);
    187 
    188                         if (p) {
    189                                 p->lockcount = 0;
    190                                 p->iserror = 0;
    191 
    192                                 if (pthread_setspecific(dlkey, p))
    193                                         free(p);
    194                                 }
    195                         }
    196                 }
    197 }
    198 
    199 
    200 static void
    201 dllock(void)
    202 
    203 {
    204         dlts_t * p;
    205 
    206         if (!(dlflags & THREADS))
    207                 return;
    208 
    209         if (dlflags & MULTIBUF) {
    210                 p = pthread_getspecific(dlkey);
    211 
    212                 if (p && p->lockcount) {
    213                         p->lockcount++;
    214                         return;
    215                         }
    216                 }
    217         else
    218                 p = (dlts_t *) NULL;
    219 
    220         if (pthread_mutex_lock(&dlmutex))
    221                 return;
    222 
    223         if (p)
    224                 p->lockcount++;
    225 }
    226 
    227 
    228 static void
    229 dlunlock(void)
    230 
    231 {
    232         dlts_t * p;
    233 
    234         if (!(dlflags & THREADS))
    235                 return;
    236 
    237         if (dlflags & MULTIBUF) {
    238                 p = pthread_getspecific(dlkey);
    239 
    240                 if (p && p->lockcount > 1) {
    241                         p->lockcount--;
    242                         return;
    243                         }
    244                 }
    245         else
    246                 p = (dlts_t *) NULL;
    247 
    248         if (pthread_mutex_unlock(&dlmutex))
    249                 return;
    250 
    251         if (p)
    252                 p->lockcount--;
    253 }
    254 
    255 
    256 const char *
    257 dlerror(void)
    258 
    259 {
    260         dlts_t * p;
    261 
    262         dlthreadinit();
    263 
    264         if (!(dlflags & MULTIBUF))
    265                 p = &static_buf;
    266         else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
    267                 p = &static_buf;
    268 
    269         if (!p->iserror)
    270                 return (const char *) NULL;
    271 
    272         p->iserror = 0;
    273         return p->str;
    274 }
    275 
    276 
    277 static void
    278 dlseterror_from_errno(unsigned int err_no)
    279 
    280 {
    281         dlts_t * p;
    282 
    283         if (!(dlflags & MULTIBUF))
    284                 p = &static_buf;
    285         else if (!(p = (dlts_t *) pthread_getspecific(dlkey)))
    286                 p = &static_buf;
    287 
    288         strcpy(p->str, strerror(err_no));
    289         p->iserror = 1;
    290 }
    291 
    292 
    293 static void
    294 dlseterror_from_exception(volatile _INTRPT_Hndlr_Parms_T * excp)
    295 
    296 {
    297         int i;
    298         Qmh_Rtvm_RTVM0300_t * imp;
    299         char * cp;
    300         _INTRPT_Hndlr_Parms_T * p;
    301         dlts_t * q;
    302         char rtvmbuf[30000];
    303         Qus_EC_t errinfo;
    304 
    305         p = (_INTRPT_Hndlr_Parms_T *) excp;
    306         errinfo.Bytes_Provided = 0;             /* Exception on error. */
    307         QMHRTVM(rtvmbuf, sizeof rtvmbuf, "RTVM0300", p->Msg_Id,
    308             "QCPFMSG   QSYS      ", p->Ex_Data, p->Msg_Data_Len,
    309             "*YES      ", "*NO       ", &errinfo);
    310         imp = offset_by(Qmh_Rtvm_RTVM0300_t, rtvmbuf, 0);
    311 
    312         if (!(dlflags & MULTIBUF))
    313                 q = &static_buf;
    314         else if (!(q = (dlts_t *) pthread_getspecific(dlkey)))
    315                 q = &static_buf;
    316 
    317         if (i = imp->Length_Message_Returned)
    318                 cp = offset_by(char, imp, imp->Offset_Message_Returned);
    319         else if (i = imp->Length_Help_Returned)
    320                 cp = offset_by(char, imp, imp->Offset_Help_Returned);
    321         else {
    322                 q->iserror = 0;
    323                 return;
    324                 }
    325 
    326         q->iserror = 1;
    327 
    328         if (i > sizeof q->str - 1)
    329                 i = sizeof q->str - 1;
    330 
    331         memcpy(q->str, cp, i);
    332         q->str[i] = '\0';
    333 }
    334 
    335 
    336 static int
    337 dlparentpath(const char * path, size_t len)
    338 
    339 {
    340         if (len <= 1)
    341                 return len;
    342 
    343         while (path[--len] != '/')
    344                 ;
    345 
    346         return len? len: 1;
    347 }
    348 
    349 
    350 static int
    351 dlmakepath(char * path, size_t pathlen, const char * tail, size_t taillen)
    352 
    353 {
    354         int i;
    355 
    356         if (taillen && tail[0] == '/')
    357                 pathlen = 0;
    358 
    359         for (;;) {
    360                 while (taillen && *tail == '/') {
    361                         tail++;
    362                         taillen--;
    363                         }
    364 
    365                 if (!taillen)
    366                         break;
    367 
    368                 for (i = 0; i < taillen; i++)
    369                         if (tail[i] == '/')
    370                                 break;
    371 
    372                 if (*tail == '.')
    373                         switch (i) {
    374 
    375                         case 2:
    376                                 if (tail[1] != '.')
    377                                         break;
    378 
    379                                 pathlen = dlparentpath(path, pathlen);
    380 
    381                         case 1:
    382                                 tail += i;
    383                                 taillen -= i;
    384                                 continue;
    385                                 }
    386 
    387                 if (pathlen + i + 1 >= MAXPATHLEN) {
    388                         errno = ENAMETOOLONG;
    389                         return -1;
    390                         }
    391 
    392                 path[pathlen++] = '/';
    393                 memcpy(path + pathlen, tail, i);
    394                 pathlen += i;
    395                 }
    396 
    397         if (!pathlen)
    398                 path[pathlen++] = '/';
    399 
    400         path[pathlen] = '\0';
    401         return pathlen;
    402 }
    403 
    404 
    405 static int
    406 dlresolveLink(const char * path, char * buf, size_t bufsiz)
    407 
    408 {
    409         int n;
    410         int l1;
    411         int l2;
    412         struct stat sbuf;
    413         char buf1[MAXPATHLEN + 1];
    414         char buf2[MAXPATHLEN + 1];
    415 
    416         /**
    417         ***     Resolve symbolic link to IFS object name.
    418         **/
    419 
    420         if (!buf) {
    421                 errno = EFAULT;
    422                 return -1;
    423                 }
    424 
    425         if (!path || !*path || !bufsiz) {
    426                 errno = EINVAL;
    427                 return -1;
    428                 }
    429 
    430         if (*path != '/') {
    431                 if (!getcwd(buf1, sizeof buf1))
    432                         return -1;
    433 
    434                 l1 = strlen(buf1);
    435                 }
    436         else
    437                 l1 = 0;
    438 
    439         l1 = dlmakepath(buf1, l1, path, strlen(path));
    440         n = 0;
    441 
    442         for (;;) {
    443                 if (l1 < 0)
    444                         return -1;
    445 
    446                 if (n++ >= 256) {
    447                         errno = ELOOP;
    448                         return -1;
    449                         }
    450 
    451                 if (lstat(buf1, &sbuf)) {
    452                         if (errno == ENOENT)
    453                                 break;
    454 
    455                         return -1;
    456                         }
    457 
    458                 if (!S_ISLNK(sbuf.st_mode))
    459                         break;
    460 
    461                 if (sbuf.st_size > MAXPATHLEN) {
    462                         errno = ENAMETOOLONG;
    463                         return -1;
    464                         }
    465 
    466                 l2 = readlink(buf1, buf2, MAXPATHLEN + 1);
    467 
    468                 if (l2 < 0)
    469                         return -1;
    470 
    471                 if (buf2[0] != '/')
    472                         l1 = dlparentpath(buf1, l1);
    473 
    474                 l1 = dlmakepath(buf1, l1, buf2, l2);
    475                 }
    476 
    477         if (l1 >= bufsiz) {
    478                 errno = ENAMETOOLONG;
    479                 return -1;
    480                 }
    481 
    482         memcpy(buf, buf1, l1 + 1);
    483         return l1;
    484 }
    485 
    486 
    487 static int
    488 dlGetObjectName(Qp0l_QSYS_Info_t * qsysinfo, const char * dir,
    489                         int dirlen, const char * link)
    490 
    491 {
    492         int n;
    493         char * namebuf;
    494         Qlg_Path_Name_T * qptp;
    495         char pathbuf[sizeof(Qlg_Path_Name_T) + _QP0L_DIR_NAME_LG + 4];
    496         Qus_EC_t errinfo;
    497         struct stat sbuf;
    498 
    499         /**
    500         ***     Get QSYS object library/name/member and type corresponding to
    501         ***             the symbolic `link' in directory `dir'.
    502         **/
    503 
    504         if (!qsysinfo) {
    505                 errno = EFAULT;
    506                 return -1;
    507                 }
    508 
    509         if (!dir && !link) {
    510                 errno = EINVAL;
    511                 return -1;
    512                 }
    513 
    514         qptp = (Qlg_Path_Name_T *) pathbuf;
    515         namebuf = pathbuf + sizeof(Qlg_Path_Name_T);
    516         n = 0;
    517 
    518         /**
    519         ***     Build full path.
    520         **/
    521 
    522         if (dir) {
    523                 if (dirlen < 0 || dirlen > _QP0L_DIR_NAME_LG + 4)
    524                         dirlen = _QP0L_DIR_NAME_LG + 4;
    525 
    526                 while (*dir && n < dirlen)
    527                         namebuf[n++] = *dir++;
    528                 }
    529 
    530         if (n && namebuf[n - 1] == '/')
    531                 n--;
    532 
    533         if (link) {
    534                 if (*link && *link != '/' && n < _QP0L_DIR_NAME_LG + 4)
    535                         namebuf[n++] = '/';
    536 
    537                 while (*link && n < _QP0L_DIR_NAME_LG + 4)
    538                         namebuf[n++] = *link++;
    539                 }
    540 
    541         if (!n || n > _QP0L_DIR_NAME_LG) {
    542                 errno = ENAMETOOLONG;
    543                 return -1;
    544                 }
    545 
    546         namebuf[n] = '\0';
    547         n = dlresolveLink(namebuf, namebuf, _QP0L_DIR_NAME_LG + 1);
    548 
    549         if (n == -1)
    550                 return -1;
    551 
    552         if (stat(namebuf, &sbuf))
    553                 return -1;
    554 
    555         memset((char *) qptp, 0, sizeof *qptp);
    556         qptp->Path_Length = n;
    557         qptp->Path_Name_Delimiter[0] = '/';
    558         errinfo.Bytes_Provided = sizeof errinfo;
    559         Qp0lCvtPathToQSYSObjName(qptp, qsysinfo, "QSYS0100", sizeof *qsysinfo,
    560             0, &errinfo);
    561         return errinfo.Bytes_Available? -1: 0;
    562 }
    563 
    564 
    565 static const char *
    566 getcomponent(char * dst, const char * src)
    567 
    568 {
    569         int i;
    570 
    571         /**
    572         ***     Get a path component of at most 10 characters and
    573         ***             map it to upper case.
    574         ***     Return the address of the next delimiter in source.
    575         **/
    576 
    577         for (i = 0;; src++) {
    578                 if (!*src || *src == ' ' || *src == '/') {
    579                         *dst = '\0';
    580                         return src;
    581                         }
    582 
    583                 if (i < 10) {
    584                         *dst++ = toupper(*src);
    585                         i++;
    586                         }
    587                 }
    588 }
    589 
    590 
    591 static int
    592 dlpath2QSYS(Qp0l_QSYS_Info_t * qsysinfo, const char * path, const char * dftlib)
    593 
    594 {
    595         unsigned int flags;
    596         char * cp;
    597 
    598         /**
    599         ***     Convert the given path to a QSYS object name.
    600         ***     Syntax rules for paths are:
    601         ***
    602         ***     '/'+ [ <library> [  '/'+ <file> [ '/'+ <member> ] ] '/'* ]
    603         ***     <library> '/'+ <file> [ '/'+ <member> ] '/'*
    604         ***     <file> '/'*
    605         ***
    606         ***     If default library is not given, *LIBL is assumed.
    607         ***     Components may no contain spaces. They are translated to
    608         ***             uppercase. Only the first 10 characters are significant.
    609         ***     There is no check for the validity of the given components and
    610         ***             for the object existence.
    611         ***     Component types are not in the path, but generated internally.
    612         ***     CCSID is not processed.
    613         ***
    614         ***     Return 0 upon success, else -1.
    615         **/
    616 
    617         if (!qsysinfo || !path) {
    618                 errno = EFAULT;
    619                 return -1;
    620                 }
    621 
    622         /**
    623         ***     Strip leading spaces.
    624         **/
    625 
    626         while (*path == ' ')
    627                 path++;
    628 
    629         /**
    630         ***     Check for null path.
    631         **/
    632 
    633         if (!*path) {
    634                 errno = EINVAL;
    635                 return -1;
    636                 }
    637 
    638         /**
    639         ***     Preset the result structure.
    640         **/
    641 
    642         memset((char *) qsysinfo, 0, sizeof *qsysinfo);
    643 
    644         /**
    645         ***     Determine the format.
    646         **/
    647 
    648         if (*path == '/') {
    649                 /**
    650                 ***     Library component present.
    651                 **/
    652 
    653                 while (*++path == '/')
    654                         ;
    655 
    656                 if (!*path || *path == ' ')
    657                         strcpy(qsysinfo->Lib_Name, "QSYS");
    658                 else
    659                         path = getcomponent(qsysinfo->Lib_Name, path);
    660 
    661                 /**
    662                 ***     Check for file component and get it.
    663                 **/
    664 
    665                 if (*path == '/') {
    666                         while (*++path == '/')
    667                                 ;
    668 
    669                         if (*path && *path != ' ')
    670                                 path = getcomponent(qsysinfo->Obj_Name, path);
    671                         }
    672                 }
    673         else {
    674                 /**
    675                 ***     The mandatory component is the <file>.
    676                 **/
    677 
    678                 path = getcomponent(qsysinfo->Obj_Name, path);
    679 
    680                 while (*path == '/')
    681                         path++;
    682 
    683                 /**
    684                 ***     If there is a second component, move the first to
    685                 ***             the library name and parse the file name.
    686                 **/
    687 
    688                 if (*path && *path != ' ') {
    689                         strcpy(qsysinfo->Lib_Name, qsysinfo->Obj_Name);
    690                         memset(qsysinfo->Obj_Name, 0,
    691                             sizeof qsysinfo->Obj_Name);
    692                         path = getcomponent(qsysinfo->Obj_Name, path);
    693                         }
    694                 else
    695                         strcpy(qsysinfo->Lib_Name, dftlib? dftlib: "*LIBL");
    696                 }
    697 
    698         /**
    699         ***     Check and set-up member.
    700         **/
    701 
    702         while (*path == '/')
    703                 path++;
    704 
    705         if (*path && *path != ' ') {
    706                 path = getcomponent(qsysinfo->Mbr_Name, path);
    707                 strcpy(qsysinfo->Mbr_Type, "*MBR");
    708 
    709                 while (*path == '/')
    710                         path++;
    711                 }
    712 
    713         strcpy(qsysinfo->Lib_Type, "*LIB");
    714 
    715         if (qsysinfo->Obj_Name[0])
    716                 strcpy(qsysinfo->Obj_Type, "*FILE");
    717 
    718         qsysinfo->Bytes_Returned = sizeof *qsysinfo;
    719         qsysinfo->Bytes_Available = sizeof *qsysinfo;
    720 
    721         /**
    722         ***     Strip trailing spaces.
    723         **/
    724 
    725         while (*path == ' ')
    726                 path++;
    727 
    728         if (*path) {
    729                 errno = EINVAL;
    730                 return -1;
    731                 }
    732 
    733         return 0;
    734 }
    735 
    736 
    737 static int
    738 dl_ifs_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
    739 
    740 {
    741         /**
    742         ***     If `pathname' is a link found in IFS, set `qsysinfo' to its
    743         ***             DB2 name.
    744         ***     Return 0 if OK, else -1.
    745         **/
    746 
    747         return dlGetObjectName(qsysinfo, (const char *) NULL, 0, pathname);
    748 }
    749 
    750 
    751 static int
    752 dl_path_link(Qp0l_QSYS_Info_t * qsysinfo, const char * pathvar,
    753         const char * filename, int (* testproc)(const Qp0l_QSYS_Info_t *))
    754 
    755 {
    756         const char * p;
    757         const char * q;
    758         unsigned int i;
    759         const char * path;
    760 
    761         /**
    762         ***     If `filename' is not a path and is a link found in one of the
    763         ***             colon-separated paths in environment variable `pathvar',
    764         ***             set `qsysinfo' to its DB2 name.
    765         ***     Return 0 if OK, else -1.
    766         **/
    767 
    768         i = _QP0L_DIR_NAME_LG;
    769 
    770         for (p = filename; *p; p++)
    771                 if (*p == '/' || !--i)
    772                         return -1;              /* Too long or a path. */
    773 
    774         /**
    775         ***     Make sure we have the LD_LIBRARY_PATH environment
    776         ***             variable value.
    777         **/
    778 
    779         path = getenv(pathvar);
    780 
    781         if (!path)
    782                 return -1;                      /* No path list. */
    783 
    784         /**
    785         ***     Try in each path listed.
    786         **/
    787 
    788         q = path;
    789 
    790         if (!*q)
    791                 return -1;                      /* No path list. */
    792 
    793         for (;;) {
    794                 for (p = q; *p && *p != ':'; p++)
    795                         ;
    796 
    797                 if (p > q)                      /* Ignore null path. */
    798                         if (!dlGetObjectName(qsysinfo, q, p - q, filename))
    799                                 if (!testproc || (*testproc)(qsysinfo))
    800                                         return 0;       /* Found: return. */
    801 
    802                 if (!*p)
    803                         break;
    804 
    805                 q = p + 1;
    806                 }
    807 
    808         errno = ENOENT;
    809         return -1;
    810 }
    811 
    812 
    813 static int
    814 dl_DB2_path(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
    815 
    816 {
    817         if (dlpath2QSYS(qsysinfo, pathname, (const char *) NULL))
    818                 return -1;
    819 
    820         if (qsysinfo->Mbr_Type[0])
    821                 return -1;      /* Service program may not have members. */
    822 
    823         if (!qsysinfo->Obj_Type[0])
    824                 return -1;      /* Object must be specified. */
    825 
    826         strcpy(qsysinfo->Obj_Type, "*SRVPGM");  /* Set our object type. */
    827         return 0;
    828 }
    829 
    830 
    831 static int
    832 dl_DB2_name(char * dst, const char * name)
    833 
    834 {
    835         int i;
    836 
    837         for (i = 0; i < 10; i++) {
    838                 switch (*name) {
    839 
    840                 default:
    841                         if (!islower(*name))
    842                                 break;
    843 
    844                 case '\0':
    845                 case '/':
    846                 case ' ':
    847                         return -1;
    848                         }
    849 
    850                 *dst++ = *name++;
    851                 }
    852 
    853         if (!i)
    854                 return -1;
    855 
    856         *dst = '\0';
    857         return 0;
    858 }
    859 
    860 
    861 static int
    862 dl_qualified_object(Qp0l_QSYS_Info_t * qsysinfo, const char * pathname)
    863 
    864 {
    865         memset((char *) qsysinfo, 0, sizeof *qsysinfo);
    866 
    867         if (dl_DB2_name(qsysinfo->Obj_Name, pathname) ||
    868             dl_DB2_name(qsysinfo->Lib_Name, pathname + 10))
    869                 return -1;
    870 
    871         strcpy(qsysinfo->Lib_Type, "*LIB");
    872         strcpy(qsysinfo->Obj_Type, "*SRVPGM");
    873         return 0;
    874 }
    875 
    876 
    877 static int
    878 dl_lib_object(Qp0l_QSYS_Info_t * qsysinfo,
    879                                 const char * libname, const char * pathname)
    880 
    881 {
    882         int i;
    883         char * cp;
    884 
    885         strcpy(qsysinfo->Lib_Name, libname);
    886         strcpy(qsysinfo->Lib_Type, "*LIB");
    887         strcpy(qsysinfo->Obj_Type, "*SRVPGM");
    888         cp = qsysinfo->Obj_Name;
    889 
    890         while (*pathname == ' ')
    891                 pathname++;
    892 
    893         for (i = 0;; pathname++) {
    894                 switch (*pathname) {
    895 
    896                 case '\0':
    897                 case ' ':
    898                         break;
    899 
    900                 case '/':
    901                         return -1;
    902 
    903                 default:
    904                         if (i < 10)
    905                                 *cp++ = toupper(*pathname);
    906 
    907                         i++;
    908                         continue;
    909                         }
    910 
    911                 break;
    912                 }
    913 
    914         while (*pathname == ' ')
    915                 pathname++;
    916 
    917         if (!i || *pathname)
    918                 return -1;
    919 
    920         *cp = '\0';
    921         return 0;
    922 }
    923 
    924 
    925 static int
    926 dl_is_srvpgm(const Qp0l_QSYS_Info_t * qsysinfo)
    927 
    928 {
    929         struct stat sbuf;
    930         char namebuf[100];
    931 
    932         if (!qsysinfo->Lib_Name[0] || strcmp(qsysinfo->Lib_Type, "*LIB") ||
    933             !qsysinfo->Obj_Name[0] || strcmp(qsysinfo->Obj_Type, "*SRVPGM") ||
    934             qsysinfo->Mbr_Name[0] || qsysinfo->Mbr_Type[0])
    935                 return 0;
    936 
    937         /**
    938         ***     Build the IFS path name for the DB2 object.
    939         **/
    940 
    941         sprintf(namebuf, "%s/%s.LIB/%s.SRVPGM",
    942             strcmp(qsysinfo->Lib_Name, "QSYS")? "/QSYS.LIB": "",
    943             qsysinfo->Lib_Name, qsysinfo->Obj_Name);
    944 
    945         return stat(namebuf, &sbuf) == 0;
    946 }
    947 
    948 
    949 static int
    950 dlreinit(dlinfo * dlip)
    951 
    952 {
    953         RINZ_TEMPL_T t;
    954         RINZ_TEMPL_T * p;
    955         volatile _INTRPT_Hndlr_Parms_T excbuf;
    956 
    957         if (dlip->actinfo.Flags & QLE_ABP_WAS_ACTIVE)
    958                 return 0;
    959 
    960         /**
    961         ***     Attempt to reinitialize the service program that was loaded.
    962         ***     The service program must be created to allow re-initialization:
    963         ***             ALWRINZ(*YES) for this to work. The default is
    964         ***             ALWRINZ(*NO).
    965         **/
    966 
    967 #pragma exception_handler(err, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
    968         p = &t;
    969         t.rinz_pgm = dlip->pointer;
    970         t.rinz_agpmk = dlip->actinfo.Act_Grp_Mark;
    971         _RINZSTAT(p);
    972 #pragma disable_handler
    973 
    974         return 0;
    975 
    976 err:
    977         if (!memcmp((char *) excbuf.Msg_Id, "MCH4421", 7))
    978                 return 0;       /* Program cannot be reinitialized. */
    979 
    980         dlseterror_from_exception(&excbuf);
    981         return -1;
    982 }
    983 
    984 
    985 void *
    986 dlsym(void * handle, const char * symbol)
    987 
    988 {
    989         dlinfo * dlip;
    990         void * p;
    991         int export_type;
    992         Qus_EC_t errinfo;
    993         volatile _INTRPT_Hndlr_Parms_T excbuf;
    994         static int zero = 0;
    995 
    996         dlthreadinit();
    997 
    998         if (!handle || !symbol) {
    999                 dlseterror_from_errno(EFAULT);
   1000                 return (void *) NULL;
   1001                 }
   1002 
   1003         dlip = (dlinfo *) handle;
   1004 
   1005 #pragma exception_handler(error, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
   1006         errinfo.Bytes_Provided = 0;
   1007         QleGetExpLong(&dlip->actinfo.Act_Mark, &zero, &zero,
   1008             (char *) symbol, &p, &export_type, &errinfo);
   1009         return p;
   1010 #pragma disable_handler
   1011 
   1012 error:
   1013         dlseterror_from_exception(&excbuf);
   1014         return (void *) NULL;
   1015 }
   1016 
   1017 
   1018 int
   1019 dlclose(void * handle)
   1020 
   1021 {
   1022         dlinfo * dlip;
   1023         void (* _fini)(void);
   1024 
   1025         dlthreadinit();
   1026 
   1027         if (!handle) {
   1028                 dlseterror_from_errno(EFAULT);
   1029                 return -1;
   1030                 }
   1031 
   1032         dlip = (dlinfo *) handle;
   1033 
   1034         if (dlip->actcount) {
   1035                 if (--(dlip->actcount))
   1036                         return 0;
   1037 
   1038                 if (_fini = dlsym(handle, "_fini"))
   1039                         (*_fini)();
   1040                 }
   1041 
   1042         return dlreinit(dlip);
   1043 }
   1044 
   1045 
   1046 static void *
   1047 dlopenqsys(const Qp0l_QSYS_Info_t * dllinfo)
   1048 
   1049 {
   1050         dlinfo * dlip;
   1051         dlinfo * dlip2;
   1052         void (* _init)(void);
   1053         unsigned int i;
   1054         _SYSPTR pgmptr;
   1055         unsigned long long actmark;
   1056         Qus_EC_t errinfo;
   1057         char actmarkstr[2 * sizeof actmark + 1];
   1058         static int actinfo_size = sizeof dlip->actinfo;
   1059         volatile _INTRPT_Hndlr_Parms_T excbuf;
   1060 
   1061         /**
   1062         ***     Capture any type of error and if any occurs,
   1063         ***             return not found.
   1064         **/
   1065 
   1066 #pragma exception_handler(error1, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
   1067         pgmptr = rslvsp(WLI_SRVPGM, (char *) dllinfo->Obj_Name,
   1068             (char *) dllinfo->Lib_Name ,_AUTH_NONE);
   1069 
   1070         if (!pgmptr) {
   1071                 errno = ENOENT;
   1072                 return (void *) NULL;
   1073                 }
   1074 
   1075         /**
   1076         ***     Create a new DLL info block.
   1077         **/
   1078 
   1079         dlip = (dlinfo *) malloc(sizeof *dlip);
   1080 
   1081         if (!dlip)
   1082                 return (void *) NULL;           /* Cannot create block. */
   1083 #pragma disable_handler
   1084 
   1085         dllock();
   1086 
   1087 #pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
   1088         memset((char *) dlip, 0, sizeof *dlip);
   1089         dlip->pointer = pgmptr;
   1090 
   1091         /**
   1092         ***     Activate the DLL.
   1093         **/
   1094 
   1095         errinfo.Bytes_Provided = 0;
   1096         QleActBndPgmLong(&pgmptr, &actmark,
   1097             &dlip->actinfo, &actinfo_size, &errinfo);
   1098         dlip->actinfo.Act_Mark = actmark;
   1099 
   1100         /**
   1101         ***     Dummy string encoding activation mark to use as hash table key.
   1102         **/
   1103 
   1104         for (i = 0; actmark; actmark >>= 6)
   1105                 actmarkstr[i++] = 0x40 + (actmark & 0x3F);
   1106 
   1107         actmarkstr[i] = '\0';
   1108 
   1109         /**
   1110         ***     Check if already activated.
   1111         **/
   1112 
   1113         dlip2 = (dlinfo *) xmlHashLookup(dldir, actmarkstr);
   1114 
   1115         if (dlip2) {
   1116                 free((char *) dlip);
   1117                 dlip = dlip2;
   1118                 }
   1119         else if (xmlHashAddEntry(dldir, (const xmlChar *) actmarkstr, dlip)) {
   1120                 dlreinit(dlip);
   1121                 free((char *) dlip);
   1122                 dlunlock();
   1123                 return (void *) NULL;
   1124                 }
   1125 #pragma disable_handler
   1126 
   1127 #pragma exception_handler(error2, excbuf, 0, _C2_MH_ESCAPE, _CTLA_HANDLE_NO_MSG)
   1128 
   1129         /**
   1130         ***     Bump activation counter.
   1131         **/
   1132 
   1133         if (!(dlip->actcount++) && (_init = dlsym(dlip, "_init")))
   1134                 (*_init)();
   1135 
   1136         dlunlock();
   1137 
   1138         /**
   1139         ***     Return the handle.
   1140         **/
   1141 
   1142         return (void *) dlip;
   1143 #pragma disable_handler
   1144 
   1145 error2:
   1146         free((char *) dlip);
   1147         dlunlock();
   1148 
   1149 error1:
   1150         dlseterror_from_exception(&excbuf);
   1151         return (void *) NULL;
   1152 }
   1153 
   1154 
   1155 void *
   1156 dlopen(const char * filename, int flag)
   1157 
   1158 {
   1159         void * dlhandle;
   1160         int sverrno;
   1161         Qp0l_QSYS_Info_t dllinfo;
   1162 
   1163         sverrno = errno;
   1164         errno = 0;
   1165 
   1166         dlthreadinit();
   1167 
   1168         if (!filename) {
   1169                 dlseterror_from_errno(EFAULT);
   1170                 errno = sverrno;
   1171                 return NULL;
   1172                 }
   1173 
   1174         /**
   1175         ***     Try to locate the object in the following order:
   1176         ***     _       `filename' is an IFS path.
   1177         ***     _       `filename' is not a path and resides in one of
   1178         ***                     LD_LIBRARY_PATH colon-separated paths.
   1179         ***     _       `filename' is not a path and resides in one of
   1180         ***                     PATH colon-separated paths.
   1181         ***     _       `filename' is a DB2 path (as /library/object).
   1182         ***     _       `filename' is a qualified object name.
   1183         ***     _       `filename' is an object in *CURLIB.
   1184         ***     _       `filename' is an object in *LIBL.
   1185         **/
   1186 
   1187         if (!dl_ifs_link(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
   1188                 dlhandle = dlopenqsys(&dllinfo);
   1189         else if (!dl_path_link(&dllinfo,
   1190             "LD_LIBRARY_PATH", filename, dl_is_srvpgm))
   1191                 dlhandle = dlopenqsys(&dllinfo);
   1192         else if (!dl_path_link(&dllinfo, "PATH", filename, dl_is_srvpgm))
   1193                 dlhandle = dlopenqsys(&dllinfo);
   1194         else if (!dl_DB2_path(&dllinfo, filename) && dl_is_srvpgm(&dllinfo))
   1195                 dlhandle = dlopenqsys(&dllinfo);
   1196         else if (!dl_qualified_object(&dllinfo, filename) &&
   1197             dl_is_srvpgm(&dllinfo))
   1198                 dlhandle = dlopenqsys(&dllinfo);
   1199         else if (!dl_lib_object(&dllinfo, "*CURLIB", filename) &&
   1200             dl_is_srvpgm(&dllinfo))
   1201                 dlhandle = dlopenqsys(&dllinfo);
   1202         else if (!dl_lib_object(&dllinfo, "*LIBL", filename) &&
   1203             dl_is_srvpgm(&dllinfo))
   1204                 dlhandle = dlopenqsys(&dllinfo);
   1205         else
   1206                 dlhandle = NULL;
   1207 
   1208         if (!dlhandle && errno)
   1209                 dlseterror_from_errno(errno);
   1210 
   1211         errno = sverrno;
   1212         return dlhandle;
   1213 }
   1214