/ libxml2 / os400 / dlfcn / dlfcn.c
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  }