(root)/
libxml2-2.12.3/
os400/
dlfcn/
dlfcn.c
       1  /**
       2  ***     dlopen(), dlclose() dlsym(), dlerror() emulation for OS/400.
       3  ***
       4  ***     See Copyright for the status of this software.
       5  ***
       6  ***     Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A.
       7  **/
       8  
       9  #include <stdarg.h>
      10  #include <stdio.h>
      11  #include <ctype.h>
      12  #include <errno.h>
      13  #include <stdlib.h>
      14  #include <unistd.h>
      15  #include <string.h>
      16  #include <dirent.h>
      17  #include <pthread.h>
      18  
      19  #include <sys/types.h>
      20  #include <sys/stat.h>
      21  
      22  #include <except.h>             /* AS400 exceptions. */
      23  #include <miptrnam.h>           /* MI pointers support. */
      24  #include <qusec.h>              /* Error structures. */
      25  #include <qp0lstdi.h>           /* Path to QSYS object name. */
      26  #include <qp0z1170.h>           /* For Qp0zInitEnv(). */
      27  #include <qleawi.h>             /* For QleActBndPgmLong() definitions. */
      28  #include <qsy.h>                /* Qualified name structure. */
      29  #include <qmhrtvm.h>            /* Retrieve message from message file. */
      30  
      31  #include <mih/rinzstat.h>
      32  #include <mih/matactex.h>
      33  
      34  #include "libxml/hash.h"
      35  #include "dlfcn.h"
      36  
      37  
      38  /**
      39  ***     Maximum internal path length.
      40  **/
      41  
      42  #define MAXPATHLEN              5120
      43  
      44  
      45  /**
      46  ***     Maximum error string length.
      47  **/
      48  
      49  #define MAX_ERR_STR             511
      50  
      51  
      52  /**
      53  ***     Field address macro.
      54  **/
      55  
      56  #define offset_by(t, b, o)      ((t *) ((char *) (b) + (unsigned int) (o)))
      57  
      58  
      59  /**
      60  ***     Global flags.
      61  **/
      62  
      63  #define INITED          000001          /* Package has been initialized. */
      64  #define THREADS         000002          /* Multithreaded job. */
      65  #define MULTIBUF        000004          /* One error buffer per thread. */
      66  
      67  
      68  /**
      69  ***     DLL handle private structure.
      70  **/
      71  
      72  typedef struct {
      73          Qle_ABP_Info_Long_t     actinfo;        /* Activation information. */
      74          _SYSPTR                 pointer;        /* Pointer to DLL object. */
      75          unsigned int            actcount;       /* Activation count. */
      76  }               dlinfo;
      77  
      78  
      79  /**
      80  ***     Per-thread structure.
      81  **/
      82  
      83  typedef struct {
      84          unsigned int    lockcount;              /* Mutex lock count. */
      85          unsigned int    iserror;                /* Flag error present. */
      86          char            str[MAX_ERR_STR + 1];   /* Error string buffer. */
      87  }               dlts_t;
      88  
      89  
      90  static pthread_mutex_t  dlmutex = PTHREAD_MUTEX_INITIALIZER;
      91  static xmlHashTablePtr  dldir = (xmlHashTablePtr) NULL; /* DLL directory. */
      92  static unsigned int     dlflags = 0;                    /* Package flags. */
      93  static pthread_key_t    dlkey;
      94  static dlts_t           static_buf;             /* Static error buffer. */
      95  
      96  
      97  
      98  static void
      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  }