diff options
Diffstat (limited to 'src/core/lt_path.c')
-rw-r--r-- | src/core/lt_path.c | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/src/core/lt_path.c b/src/core/lt_path.c index bc9ac07..b0335de 100644 --- a/src/core/lt_path.c +++ b/src/core/lt_path.c @@ -5,14 +5,17 @@ /*******************************************************************/ #include <limits.h> +#include <dlfcn.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> + #include <sltdl/sltdl.h> #include "sltdl_core.h" +#include "sltdl_module.h" static off_t lt_plen; static off_t lt_plocs; @@ -21,6 +24,12 @@ static char * lt_vpath; static char ** lt_vmark; static char ** lt_pathv; +static struct lt_modctx * lt_modv_head; +static struct lt_modctx * lt_modv_tail; + +static struct lt_modctx * lt_modv_next; +static struct lt_modctx * lt_modv_cap; + const char * lt_dlgetsearchpath(void) { return lt_upath; @@ -243,12 +252,16 @@ int lt_dlinsertsearchdir(const char * mark, const char * path) return lt_sunlock(ret); } -static int lt_dlpathopen_locked(const char * module, const char ** extv) +static int lt_dlpathopen_locked( + const char * module, + const char ** extv, + char ** mpath) { int fdat; int fdmod; char ** ppath; const char ** pext; + size_t plen; size_t mlen; size_t elen; char path[1024]; @@ -274,6 +287,19 @@ static int lt_dlpathopen_locked(const char * module, const char ** extv) fdmod = openat(fdat,path,O_EXEC|O_CLOEXEC,0); if (fdmod >= 0) { + if (mpath) { + plen = strlen(*ppath); + plen += mlen + 1 + elen + 1; + + if (!(*mpath = malloc(plen))) { + close(fdat); + close(fdmod); + return (-1); + } + + sprintf(*mpath,"%s/%s",*ppath,path); + } + close(fdat); return fdmod; } @@ -289,5 +315,90 @@ static int lt_dlpathopen_locked(const char * module, const char ** extv) int lt_dlpathopen(const char * module, const char ** extv) { lt_slock(); - return lt_sunlock(lt_dlpathopen_locked(module,extv)); + return lt_sunlock(lt_dlpathopen_locked(module,extv,0)); +} + +static struct lt_modctx * lt_dlopen_locked( + const char * module, + const char ** extv, + int mode) +{ + int fdmod; + char * mpath; + void * maddr; + struct lt_modctx * modctx; + struct lt_modctx * modctx_buf; + + /* path open */ + if ((fdmod = lt_dlpathopen_locked(module,extv,&mpath)) < 0) + return 0; + + close(fdmod); + + /* entry alloc */ + if (lt_modv_next == lt_modv_cap) { + if (!(modctx_buf = calloc(64,sizeof(*modctx)))) { + free(mpath); + return 0; + } + + lt_modv_next = modctx_buf; + lt_modv_cap = <_modv_next[64]; + } + + /* dlopen */ + if (!(maddr = dlopen(mpath,mode))) { + free(mpath); + return 0; + } + + /* already dlopen'ed? */ + for (modctx=lt_modv_head; modctx; modctx=modctx->mnext) { + if (!strcmp(modctx->mpath,mpath)) { + free(mpath); + modctx->mrefs++; + return modctx; + } + } + + /* module entry */ + modctx = lt_modv_next; + modctx->maddr = maddr; + modctx->mpath = mpath; + modctx->mrefs = 1; + lt_modv_next++; + + /* add to list */ + if (lt_modv_tail) { + lt_modv_tail->mnext = modctx; + lt_modv_tail = modctx; + } else { + lt_modv_head = modctx; + lt_modv_tail = modctx; + } + + /* all done */ + return modctx; +} + +struct lt_modctx * lt_dlopen(const char * module) +{ + struct lt_modctx * modctx; + const char * extv[2] = {"",0}; + + lt_slock(); + modctx = lt_dlopen_locked(module,extv,RTLD_NOW); + lt_sunlock(0); + return modctx; +} + +struct lt_modctx * lt_dlopenext(const char * module) +{ + struct lt_modctx * modctx; + const char * extv[3] = {"",OS_LIB_SUFFIX,0}; + + lt_slock(); + modctx = lt_dlopen_locked(module,extv,RTLD_NOW); + lt_sunlock(0); + return modctx; } |