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 72typedef 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 83typedef 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 90static pthread_mutex_t dlmutex = PTHREAD_MUTEX_INITIALIZER; 91static xmlHashTablePtr dldir = (xmlHashTablePtr) NULL; /* DLL directory. */ 92static unsigned int dlflags = 0; /* Package flags. */ 93static pthread_key_t dlkey; 94static dlts_t static_buf; /* Static error buffer. */ 95 96 97 98static void 99dlthreadterm(void * mem) 100 101{ 102 free(mem); 103 pthread_setspecific(dlkey, NULL); 104} 105 106 107static void 108dlterm(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 137static void 138dlinit(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 173static void 174dlthreadinit(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 200static void 201dllock(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 228static void 229dlunlock(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 256const char * 257dlerror(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 277static void 278dlseterror_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 293static void 294dlseterror_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 336static int 337dlparentpath(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 350static int 351dlmakepath(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 405static int 406dlresolveLink(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 487static int 488dlGetObjectName(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 565static const char * 566getcomponent(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 591static int 592dlpath2QSYS(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 737static int 738dl_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 751static int 752dl_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 813static int 814dl_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 831static int 832dl_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 861static int 862dl_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 877static int 878dl_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 925static int 926dl_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 949static int 950dlreinit(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 976err: 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 985void * 986dlsym(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 1012error: 1013 dlseterror_from_exception(&excbuf); 1014 return (void *) NULL; 1015} 1016 1017 1018int 1019dlclose(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 1046static void * 1047dlopenqsys(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 1145error2: 1146 free((char *) dlip); 1147 dlunlock(); 1148 1149error1: 1150 dlseterror_from_exception(&excbuf); 1151 return (void *) NULL; 1152} 1153 1154 1155void * 1156dlopen(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