|
 |
47891e |
/*******************************************************************/
|
|
 |
47891e |
/* sltdl: a surrogate ltdl implementation */
|
|
 |
84a51a |
/* Copyright (C) 2019 SysDeer Technologies, LLC */
|
|
 |
47891e |
/* Released under the Standard MIT License; see COPYING.SLTDL. */
|
|
 |
47891e |
/*******************************************************************/
|
|
 |
47891e |
|
|
 |
2d052c |
#include <glob.h>
|
|
 |
47891e |
#include <limits.h>
|
|
 |
303f79 |
#include <dlfcn.h>
|
|
 |
2d052c |
#include <errno.h>
|
|
 |
bb0941 |
#include <fcntl.h>
|
|
 |
47891e |
#include <stdio.h>
|
|
 |
47891e |
#include <stdlib.h>
|
|
 |
47891e |
#include <string.h>
|
|
 |
bb0941 |
#include <unistd.h>
|
|
 |
47891e |
#include <pthread.h>
|
|
 |
303f79 |
|
|
 |
47891e |
#include <sltdl/sltdl.h>
|
|
 |
47891e |
#include "sltdl_core.h"
|
|
 |
303f79 |
#include "sltdl_module.h"
|
|
 |
47891e |
|
|
 |
3f4643 |
#ifdef O_EXEC
|
|
 |
3f4643 |
#define SLTDL_MODULE_OPEN_OPTIONS (O_CLOEXEC|O_EXEC)
|
|
 |
3f4643 |
#else
|
|
 |
3f4643 |
#define SLTDL_MODULE_OPEN_OPTIONS (O_CLOEXEC)
|
|
 |
3f4643 |
#endif
|
|
 |
3f4643 |
|
|
 |
8744a5 |
static int lt_status;
|
|
 |
47891e |
static off_t lt_plen;
|
|
 |
47891e |
static off_t lt_plocs;
|
|
 |
47891e |
static char * lt_upath;
|
|
 |
47891e |
static char * lt_vpath;
|
|
 |
47891e |
static char ** lt_vmark;
|
|
 |
47891e |
static char ** lt_pathv;
|
|
 |
47891e |
|
|
 |
303f79 |
static struct lt_modctx * lt_modv_head;
|
|
 |
303f79 |
static struct lt_modctx * lt_modv_tail;
|
|
 |
303f79 |
|
|
 |
303f79 |
static struct lt_modctx * lt_modv_next;
|
|
 |
303f79 |
static struct lt_modctx * lt_modv_cap;
|
|
 |
303f79 |
|
|
 |
8744a5 |
static int lt_setstatus(int ret, int status)
|
|
 |
8744a5 |
{
|
|
 |
8744a5 |
lt_status = status;
|
|
 |
8744a5 |
return ret;
|
|
 |
8744a5 |
}
|
|
 |
8744a5 |
|
|
 |
47891e |
const char * lt_dlgetsearchpath(void)
|
|
 |
47891e |
{
|
|
 |
47891e |
return lt_upath;
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
static int lt_dlsetsearchpath_locked(const char * path)
|
|
 |
47891e |
{
|
|
 |
47891e |
const char * ch;
|
|
 |
47891e |
char * uch;
|
|
 |
47891e |
char * vch;
|
|
 |
47891e |
char ** pathv;
|
|
 |
47891e |
off_t elements;
|
|
 |
47891e |
|
|
 |
47891e |
if (path[0] != '/')
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_PATH_INVALID_FIRST_CHAR);
|
|
 |
47891e |
|
|
 |
47891e |
elements = 1;
|
|
 |
47891e |
|
|
 |
47891e |
for (ch=&path[1]; *ch; ch++) {
|
|
 |
47891e |
if (*ch == ':') {
|
|
 |
47891e |
if (ch[1] != '/')
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_PATH_INVALID_FIRST_CHAR);
|
|
 |
47891e |
|
|
 |
47891e |
elements++;
|
|
 |
47891e |
}
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
if (++elements > lt_plocs) {
|
|
 |
47891e |
if (lt_pathv) {
|
|
 |
47891e |
free(lt_pathv);
|
|
 |
47891e |
lt_pathv = 0;
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
lt_plocs = elements;
|
|
 |
47891e |
lt_plocs += 0x3f;
|
|
 |
47891e |
lt_plocs |= 0x3f;
|
|
 |
47891e |
lt_plocs ^= 0x3f;
|
|
 |
47891e |
|
|
 |
47891e |
if (!(lt_pathv = calloc(lt_plocs,sizeof(char *))))
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
if ((ch - path) > lt_plen) {
|
|
 |
47891e |
if (lt_upath) {
|
|
 |
47891e |
free(lt_upath);
|
|
 |
47891e |
lt_upath = 0;
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
lt_plen = ((ch - path + 1) <= 0x800)
|
|
 |
47891e |
? 0x800 : ch - path + 1;
|
|
 |
47891e |
|
|
 |
47891e |
lt_plen += 0x7ff;
|
|
 |
47891e |
lt_plen |= 0x7ff;
|
|
 |
47891e |
lt_plen ^= 0x7ff;
|
|
 |
47891e |
if (!(lt_upath = calloc(2*lt_plen,1)))
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
47891e |
|
|
 |
47891e |
lt_vpath = <_upath[lt_plen];
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
pathv = lt_pathv;
|
|
 |
47891e |
*pathv++ = lt_vpath;
|
|
 |
47891e |
|
|
 |
47891e |
for (ch=path, uch=lt_upath, vch=lt_vpath; *ch; ch++) {
|
|
 |
47891e |
if (*ch == ':') {
|
|
 |
47891e |
*uch++ = ch[0];
|
|
 |
47891e |
*uch++ = ch[1];
|
|
 |
47891e |
|
|
 |
47891e |
*vch++ = 0;
|
|
 |
47891e |
*pathv = vch;
|
|
 |
47891e |
*vch++ = ch[1];
|
|
 |
47891e |
|
|
 |
47891e |
ch++;
|
|
 |
47891e |
pathv++;
|
|
 |
47891e |
} else {
|
|
 |
47891e |
*uch++ = *ch;
|
|
 |
47891e |
*vch++ = *ch;
|
|
 |
47891e |
}
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
lt_vmark = pathv;
|
|
 |
47891e |
|
|
 |
178478 |
return lt_setstatus(0,SLTDL_ERR_OK);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
int lt_dlsetsearchpath(const char * path)
|
|
 |
47891e |
{
|
|
 |
8744a5 |
int ret;
|
|
 |
47891e |
lt_slock();
|
|
 |
8744a5 |
ret = lt_dlsetsearchpath_locked(path);
|
|
 |
8744a5 |
return lt_sunlock(ret,lt_status);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
8744a5 |
static int lt_dladdsearchdir_locked(const char * path)
|
|
 |
47891e |
{
|
|
 |
47891e |
int ret;
|
|
 |
47891e |
const char * ch;
|
|
 |
47891e |
char * buf;
|
|
 |
47891e |
off_t alen;
|
|
 |
47891e |
off_t plen;
|
|
 |
47891e |
|
|
 |
47891e |
if (path[0] != '/')
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_PATH_INVALID_FIRST_CHAR);
|
|
 |
47891e |
|
|
 |
47891e |
for (ch=path; *ch; ch++)
|
|
 |
47891e |
if (*ch == ':')
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_PATH_INVALID_SEPARATTOR_CHAR);
|
|
 |
47891e |
|
|
 |
47891e |
alen = strlen(path);
|
|
 |
47891e |
plen = strlen(lt_upath);
|
|
 |
47891e |
|
|
 |
47891e |
/* no allocation needed? */
|
|
 |
47891e |
if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
|
|
 |
47891e |
lt_upath[plen] = ':';
|
|
 |
47891e |
lt_vpath[plen] = 0;
|
|
 |
47891e |
|
|
 |
47891e |
plen++;
|
|
 |
47891e |
|
|
 |
47891e |
strcpy(<_upath[plen],path);
|
|
 |
47891e |
strcpy(<_vpath[plen],path);
|
|
 |
47891e |
|
|
 |
47891e |
*lt_vmark++ = <_vpath[plen];
|
|
 |
47891e |
|
|
 |
178478 |
return lt_setstatus(0,SLTDL_ERR_OK);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
/* (allocation needed) */
|
|
 |
47891e |
if (!(buf = malloc(plen + 1 + alen + 1)))
|
|
 |
178478 |
return lt_setstatus(1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
47891e |
|
|
 |
47891e |
sprintf(buf,"%s:%s",lt_upath,path);
|
|
 |
47891e |
|
|
 |
47891e |
ret = lt_dlsetsearchpath_locked(buf);
|
|
 |
47891e |
|
|
 |
47891e |
free(buf);
|
|
 |
47891e |
|
|
 |
8744a5 |
return ret;
|
|
 |
8744a5 |
}
|
|
 |
8744a5 |
|
|
 |
8744a5 |
int lt_dladdsearchdir(const char * path)
|
|
 |
8744a5 |
{
|
|
 |
8744a5 |
int ret;
|
|
 |
8744a5 |
lt_slock();
|
|
 |
8744a5 |
ret = lt_dladdsearchdir_locked(path);
|
|
 |
8744a5 |
return lt_sunlock(ret,lt_status);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
int lt_dlinsertsearchdir(const char * mark, const char * path)
|
|
 |
47891e |
{
|
|
 |
47891e |
int ret;
|
|
 |
47891e |
const char * ch;
|
|
 |
47891e |
char * buf;
|
|
 |
47891e |
char * dst;
|
|
 |
47891e |
off_t alen;
|
|
 |
47891e |
off_t plen;
|
|
 |
47891e |
off_t slen;
|
|
 |
47891e |
off_t offset;
|
|
 |
47891e |
char ** pathv;
|
|
 |
47891e |
|
|
 |
47891e |
if (!mark)
|
|
 |
47891e |
return lt_dladdsearchdir(path);
|
|
 |
47891e |
|
|
 |
8744a5 |
lt_slock();
|
|
 |
8744a5 |
|
|
 |
8744a5 |
if (path[0] != '/')
|
|
 |
178478 |
return lt_sunlock(1,SLTDL_ERR_PATH_INVALID_FIRST_CHAR);
|
|
 |
8744a5 |
|
|
 |
47891e |
for (ch=path; *ch; ch++)
|
|
 |
47891e |
if (*ch == ':')
|
|
 |
178478 |
return lt_sunlock(1,SLTDL_ERR_PATH_INVALID_SEPARATTOR_CHAR);
|
|
 |
47891e |
|
|
 |
47891e |
alen = strlen(path);
|
|
 |
47891e |
plen = strlen(lt_upath);
|
|
 |
47891e |
|
|
 |
47891e |
if ((mark < lt_upath) || (mark >= <_upath[plen]))
|
|
 |
178478 |
return lt_sunlock(1,SLTDL_ERR_PATH_INVALID_MARK);
|
|
 |
47891e |
|
|
 |
47891e |
if ((mark > lt_upath) && (mark[-1] != ':'))
|
|
 |
178478 |
return lt_sunlock(1,SLTDL_ERR_PATH_INVALID_MARK);
|
|
 |
47891e |
|
|
 |
47891e |
mark = <_vpath[mark - lt_upath];
|
|
 |
47891e |
|
|
 |
47891e |
/* no allocation needed? */
|
|
 |
47891e |
if (!lt_pathv[lt_plocs - 2] && ((plen + 1 + alen + 1) <= lt_plen)) {
|
|
 |
47891e |
for (pathv=lt_vmark; pathv>=lt_pathv; pathv--) {
|
|
 |
47891e |
slen = strlen(pathv[-1]);
|
|
 |
47891e |
offset = pathv[-1] - lt_vpath;
|
|
 |
47891e |
offset += alen + 1;
|
|
 |
47891e |
|
|
 |
47891e |
memcpy(<_upath[offset],pathv[-1],slen);
|
|
 |
47891e |
memcpy(<_vpath[offset],<_upath[offset],slen);
|
|
 |
47891e |
|
|
 |
47891e |
if (pathv < lt_vmark)
|
|
 |
47891e |
lt_upath[offset + slen] = ':';
|
|
 |
47891e |
|
|
 |
76a627 |
pathv[0] = pathv[-1] + alen + 1;
|
|
 |
47891e |
|
|
 |
47891e |
if (pathv[-1] == mark) {
|
|
 |
47891e |
offset = mark - lt_vpath;
|
|
 |
47891e |
strcpy(<_vpath[offset],path);
|
|
 |
47891e |
memcpy(<_upath[offset],path,alen);
|
|
 |
47891e |
lt_upath[offset+alen] = ':';
|
|
 |
47891e |
lt_vmark++;
|
|
 |
178478 |
return lt_sunlock(0,SLTDL_ERR_OK);
|
|
 |
47891e |
}
|
|
 |
47891e |
}
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
/* (allocation needed) */
|
|
 |
47891e |
if (!(buf = malloc(plen + 1 + alen + 1)))
|
|
 |
178478 |
return lt_sunlock(1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
47891e |
|
|
 |
47891e |
for (dst=buf, pathv=lt_pathv; *pathv; pathv++) {
|
|
 |
47891e |
if (*pathv == mark)
|
|
 |
47891e |
dst += sprintf(dst,"%s:",path);
|
|
 |
47891e |
|
|
 |
47891e |
if (pathv[1])
|
|
 |
47891e |
dst += sprintf(dst,"%s:",*pathv);
|
|
 |
47891e |
else
|
|
 |
47891e |
dst += sprintf(dst,"%s",*pathv);
|
|
 |
47891e |
}
|
|
 |
47891e |
|
|
 |
47891e |
ret = lt_dlsetsearchpath_locked(buf);
|
|
 |
47891e |
|
|
 |
47891e |
free(buf);
|
|
 |
47891e |
|
|
 |
8744a5 |
return lt_sunlock(ret,lt_status);
|
|
 |
47891e |
}
|
|
 |
bb0941 |
|
|
 |
303f79 |
static int lt_dlpathopen_locked(
|
|
 |
303f79 |
const char * module,
|
|
 |
303f79 |
const char ** extv,
|
|
 |
303f79 |
char ** mpath)
|
|
 |
bb0941 |
{
|
|
 |
bb0941 |
int fdat;
|
|
 |
bb0941 |
int fdmod;
|
|
 |
bb0941 |
char ** ppath;
|
|
 |
bb0941 |
const char ** pext;
|
|
 |
303f79 |
size_t plen;
|
|
 |
bb0941 |
size_t mlen;
|
|
 |
bb0941 |
size_t elen;
|
|
 |
bb0941 |
char path[1024];
|
|
 |
bb0941 |
|
|
 |
bb0941 |
if ((mlen = strlen(module)) >= sizeof(path))
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_PATH_INVALID_LEN);
|
|
 |
bb0941 |
|
|
 |
bb0941 |
memcpy(path,module,mlen);
|
|
 |
bb0941 |
|
|
 |
b21404 |
if (path[0] == '/') {
|
|
 |
b21404 |
if ((fdmod = open(path,SLTDL_MODULE_OPEN_OPTIONS,0)) >= 0) {
|
|
 |
b21404 |
if (mpath) {
|
|
 |
b21404 |
if (!(*mpath = realpath(path,0))) {
|
|
 |
b21404 |
close(fdmod);
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
b21404 |
}
|
|
 |
b21404 |
}
|
|
 |
b21404 |
|
|
 |
178478 |
return lt_setstatus(fdmod,SLTDL_ERR_OK);
|
|
 |
b21404 |
}
|
|
 |
b21404 |
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_PATH_NO_ENTRY);
|
|
 |
b21404 |
}
|
|
 |
b21404 |
|
|
 |
d4d5c9 |
for (ppath=lt_pathv; ppath && *ppath; ppath++) {
|
|
 |
bb0941 |
fdat = open(*ppath,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0);
|
|
 |
bb0941 |
|
|
 |
bb0941 |
if (fdat >= 0) {
|
|
 |
bb0941 |
for (pext=extv; *pext; pext++) {
|
|
 |
bb0941 |
if (mlen + (elen = strlen(*pext)) >= (sizeof(path))) {
|
|
 |
bb0941 |
close(fdat);
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_PATH_INVALID_LEN);
|
|
 |
bb0941 |
}
|
|
 |
bb0941 |
|
|
 |
bb0941 |
memcpy(&path[mlen],*pext,elen);
|
|
 |
bb0941 |
path[mlen+elen] = 0;
|
|
 |
bb0941 |
|
|
 |
3f4643 |
fdmod = openat(fdat,path,SLTDL_MODULE_OPEN_OPTIONS,0);
|
|
 |
bb0941 |
|
|
 |
bb0941 |
if (fdmod >= 0) {
|
|
 |
303f79 |
if (mpath) {
|
|
 |
303f79 |
plen = strlen(*ppath);
|
|
 |
303f79 |
plen += mlen + 1 + elen + 1;
|
|
 |
303f79 |
|
|
 |
303f79 |
if (!(*mpath = malloc(plen))) {
|
|
 |
303f79 |
close(fdat);
|
|
 |
303f79 |
close(fdmod);
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
sprintf(*mpath,"%s/%s",*ppath,path);
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
bb0941 |
close(fdat);
|
|
 |
178478 |
return lt_setstatus(fdmod,SLTDL_ERR_OK);
|
|
 |
bb0941 |
}
|
|
 |
bb0941 |
}
|
|
 |
bb0941 |
|
|
 |
bb0941 |
close(fdat);
|
|
 |
bb0941 |
}
|
|
 |
bb0941 |
}
|
|
 |
bb0941 |
|
|
 |
178478 |
return lt_setstatus(-1,SLTDL_ERR_PATH_NO_ENTRY);
|
|
 |
709fde |
}
|
|
 |
709fde |
|
|
 |
709fde |
int lt_dlpathopen(const char * module, const char ** extv)
|
|
 |
709fde |
{
|
|
 |
8744a5 |
int ret;
|
|
 |
709fde |
lt_slock();
|
|
 |
8744a5 |
ret = lt_dlpathopen_locked(module,extv,0);
|
|
 |
8744a5 |
return lt_sunlock(ret,lt_status);
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
static struct lt_modctx * lt_dlopen_locked(
|
|
 |
8c3ccc |
const struct lt_symdef * symtbl,
|
|
 |
01192f |
const char * module,
|
|
 |
01192f |
const char ** extv,
|
|
 |
01192f |
int mode)
|
|
 |
303f79 |
{
|
|
 |
01192f |
int fdmod;
|
|
 |
01192f |
char * mpath;
|
|
 |
01192f |
void * maddr;
|
|
 |
01192f |
struct lt_modctx * modctx;
|
|
 |
01192f |
struct lt_modctx * modctx_buf;
|
|
 |
303f79 |
|
|
 |
8c3ccc |
/* init */
|
|
 |
8c3ccc |
mpath = 0;
|
|
 |
8c3ccc |
maddr = 0;
|
|
 |
8c3ccc |
|
|
 |
8c3ccc |
/* path open (module) */
|
|
 |
8c3ccc |
if (module) {
|
|
 |
8c3ccc |
if ((fdmod = lt_dlpathopen_locked(module,extv,&mpath)) < 0)
|
|
 |
8c3ccc |
return 0;
|
|
 |
303f79 |
|
|
 |
8c3ccc |
close(fdmod);
|
|
 |
8c3ccc |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
/* entry alloc */
|
|
 |
303f79 |
if (lt_modv_next == lt_modv_cap) {
|
|
 |
303f79 |
if (!(modctx_buf = calloc(64,sizeof(*modctx)))) {
|
|
 |
303f79 |
free(mpath);
|
|
 |
178478 |
lt_setstatus(0,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
303f79 |
return 0;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
lt_modv_next = modctx_buf;
|
|
 |
303f79 |
lt_modv_cap = <_modv_next[64];
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
8c3ccc |
/* dlopen (module) */
|
|
 |
8c3ccc |
if (module && !(maddr = dlopen(mpath,mode))) {
|
|
 |
303f79 |
free(mpath);
|
|
 |
178478 |
lt_setstatus(0,SLTDL_ERR_DLFCN_ERROR);
|
|
 |
303f79 |
return 0;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
8c3ccc |
/* module already dlopen'ed? */
|
|
 |
8c3ccc |
for (modctx=lt_modv_head; module && modctx; modctx=modctx->mnext) {
|
|
 |
303f79 |
if (!strcmp(modctx->mpath,mpath)) {
|
|
 |
303f79 |
free(mpath);
|
|
 |
303f79 |
modctx->mrefs++;
|
|
 |
303f79 |
return modctx;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
8c3ccc |
/* module or symtbl entry */
|
|
 |
01192f |
modctx = lt_modv_next;
|
|
 |
8c3ccc |
modctx->symtbl = symtbl;
|
|
 |
01192f |
modctx->maddr = maddr;
|
|
 |
01192f |
modctx->mpath = mpath;
|
|
 |
01192f |
modctx->mrefs = 1;
|
|
 |
303f79 |
lt_modv_next++;
|
|
 |
303f79 |
|
|
 |
303f79 |
/* add to list */
|
|
 |
303f79 |
if (lt_modv_tail) {
|
|
 |
303f79 |
lt_modv_tail->mnext = modctx;
|
|
 |
303f79 |
lt_modv_tail = modctx;
|
|
 |
303f79 |
} else {
|
|
 |
303f79 |
lt_modv_head = modctx;
|
|
 |
303f79 |
lt_modv_tail = modctx;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
/* all done */
|
|
 |
303f79 |
return modctx;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
struct lt_modctx * lt_dlopen(const char * module)
|
|
 |
303f79 |
{
|
|
 |
54b252 |
char * dot;
|
|
 |
54b252 |
size_t slen;
|
|
 |
303f79 |
struct lt_modctx * modctx;
|
|
 |
303f79 |
const char * extv[2] = {"",0};
|
|
 |
54b252 |
char dsobuf[PATH_MAX];
|
|
 |
303f79 |
|
|
 |
303f79 |
lt_slock();
|
|
 |
54b252 |
|
|
 |
54b252 |
if ((slen = strlen(module)) >= PATH_MAX) {
|
|
 |
178478 |
lt_setstatus(0,SLTDL_ERR_SYSTEM_ERROR);
|
|
 |
54b252 |
lt_sunlock(0,lt_status);
|
|
 |
54b252 |
return 0;
|
|
 |
54b252 |
}
|
|
 |
54b252 |
|
|
 |
54b252 |
strcpy(dsobuf,module);
|
|
 |
54b252 |
|
|
 |
54b252 |
if ((dot = strrchr(dsobuf,'.')))
|
|
 |
54b252 |
if (!strcmp(dot,".la"))
|
|
 |
54b252 |
if ((slen = (dot - dsobuf)))
|
|
 |
54b252 |
if (PATH_MAX - slen > strlen(OS_LIB_SUFFIX))
|
|
 |
54b252 |
strcpy(dot,OS_LIB_SUFFIX);
|
|
 |
54b252 |
|
|
 |
54b252 |
module = dsobuf;
|
|
 |
8c3ccc |
modctx = lt_dlopen_locked(0,module,extv,RTLD_NOW);
|
|
 |
8744a5 |
lt_sunlock(0,lt_status);
|
|
 |
303f79 |
return modctx;
|
|
 |
303f79 |
}
|
|
 |
303f79 |
|
|
 |
303f79 |
struct lt_modctx * lt_dlopenext(const char * module)
|
|
 |
303f79 |
{
|
|
 |
303f79 |
struct lt_modctx * modctx;
|
|
 |
303f79 |
const char * extv[3] = {"",OS_LIB_SUFFIX,0};
|
|
 |
303f79 |
|
|
 |
303f79 |
lt_slock();
|
|
 |
8c3ccc |
modctx = lt_dlopen_locked(0,module,extv,RTLD_NOW);
|
|
 |
8744a5 |
lt_sunlock(0,lt_status);
|
|
 |
303f79 |
return modctx;
|
|
 |
bb0941 |
}
|
|
 |
2af0aa |
|
|
 |
2af0aa |
struct lt_modctx * lt_dlopenadvise(const char * module, struct lt_modctl * modctl)
|
|
 |
2af0aa |
{
|
|
 |
2af0aa |
(void)modctl;
|
|
 |
2af0aa |
return lt_dlopenext(module);
|
|
 |
2af0aa |
}
|
|
 |
64a26c |
|
|
 |
64a26c |
void * lt_dlsym(struct lt_modctx * modctx, const char * symname)
|
|
 |
64a26c |
{
|
|
 |
abbfe7 |
const struct lt_symdef * sym;
|
|
 |
abbfe7 |
|
|
 |
abbfe7 |
if (modctx->maddr)
|
|
 |
abbfe7 |
return dlsym(modctx->maddr,symname);
|
|
 |
abbfe7 |
|
|
 |
abbfe7 |
for (sym=modctx->symtbl; sym->name; sym++)
|
|
 |
abbfe7 |
if (!strcmp(sym->name,symname))
|
|
 |
abbfe7 |
return sym->address;
|
|
 |
abbfe7 |
|
|
 |
abbfe7 |
return 0;
|
|
 |
64a26c |
}
|
|
 |
64a26c |
|
|
 |
64a26c |
int lt_dlclose(struct lt_modctx * modctx)
|
|
 |
64a26c |
{
|
|
 |
64a26c |
struct lt_modctx * pmod;
|
|
 |
64a26c |
|
|
 |
64a26c |
lt_slock();
|
|
 |
64a26c |
|
|
 |
64a26c |
for (pmod=lt_modv_head; pmod ; pmod=pmod->mnext) {
|
|
 |
64a26c |
if (pmod == modctx) {
|
|
 |
64a26c |
if (pmod->mrefs) {
|
|
 |
64a26c |
pmod->mrefs--;
|
|
 |
178478 |
return lt_sunlock(0,SLTDL_ERR_OK);
|
|
 |
64a26c |
}
|
|
 |
64a26c |
|
|
 |
178478 |
return lt_sunlock(-1,SLTDL_ERR_MODULE_REF_COUNT);
|
|
 |
64a26c |
}
|
|
 |
64a26c |
}
|
|
 |
64a26c |
|
|
 |
178478 |
return lt_sunlock(-1,SLTDL_ERR_MODULE_PTR_INVALID);
|
|
 |
64a26c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
static int lt_dlforeachfile_one(
|
|
 |
2d052c |
const char * path,
|
|
 |
2d052c |
int (*fusr)(const char * direntry, void * data),
|
|
 |
2d052c |
void * data)
|
|
 |
2d052c |
{
|
|
 |
2d052c |
int ret;
|
|
 |
2d052c |
char ** argv;
|
|
 |
2d052c |
glob_t globbuf;
|
|
 |
2d052c |
char pathbuf[PATH_MAX];
|
|
 |
2d052c |
|
|
 |
2d052c |
globbuf.gl_pathc = 0;
|
|
 |
2d052c |
globbuf.gl_pathv = 0;
|
|
 |
2d052c |
globbuf.gl_offs = 0;
|
|
 |
2d052c |
|
|
 |
2d052c |
ret = snprintf(
|
|
 |
2d052c |
pathbuf,
|
|
 |
2d052c |
sizeof(pathbuf),
|
|
 |
2d052c |
"%s/" "*" OS_LIB_SUFFIX,
|
|
 |
2d052c |
path);
|
|
 |
2d052c |
|
|
 |
2d052c |
if (ret >= PATH_MAX) {
|
|
 |
2d052c |
errno = EINVAL;
|
|
 |
2d052c |
return -1;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
if ((ret = glob(pathbuf,0,0,&globbuf)) < 0)
|
|
 |
2d052c |
return ret;
|
|
 |
2d052c |
|
|
 |
2d052c |
for (argv=globbuf.gl_pathv; argv && *argv; argv++) {
|
|
 |
2d052c |
if ((ret = fusr(*argv,data))) {
|
|
 |
2d052c |
globfree(&globbuf);
|
|
 |
2d052c |
return ret;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
globfree(&globbuf);
|
|
 |
2d052c |
|
|
 |
2d052c |
return 0;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
int lt_dlforeachfile(
|
|
 |
2d052c |
const char * path,
|
|
 |
2d052c |
int (*fusr)(const char * direntry, void * data),
|
|
 |
2d052c |
void * data)
|
|
 |
2d052c |
{
|
|
 |
2d052c |
int ret;
|
|
 |
2d052c |
char ** pathv;
|
|
 |
2d052c |
char * spath;
|
|
 |
2d052c |
char * mark;
|
|
 |
2d052c |
char * ch;
|
|
 |
2d052c |
|
|
 |
2d052c |
if (path) {
|
|
 |
2d052c |
if (!(spath = strdup(path)))
|
|
 |
2d052c |
return -1;
|
|
 |
2d052c |
|
|
 |
2d052c |
mark = spath;
|
|
 |
2d052c |
ch = spath;
|
|
 |
2d052c |
|
|
 |
2d052c |
for (; *ch; ) {
|
|
 |
2d052c |
for (ch=mark; ch[0] && ch[0] != ':'; ch++)
|
|
 |
2d052c |
(void)0;
|
|
 |
2d052c |
|
|
 |
2d052c |
if (ch[0])
|
|
 |
2d052c |
*ch++ = '\0';
|
|
 |
2d052c |
|
|
 |
2d052c |
if ((ret = lt_dlforeachfile_one(mark,fusr,data))) {
|
|
 |
2d052c |
free(spath);
|
|
 |
2d052c |
return ret;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
mark = ch;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
free(spath);
|
|
 |
2d052c |
} else {
|
|
 |
2d052c |
for (pathv=lt_pathv; pathv && *pathv; pathv++)
|
|
 |
2d052c |
if ((ret = lt_dlforeachfile_one(*pathv,fusr,data)))
|
|
 |
2d052c |
return ret;
|
|
 |
2d052c |
}
|
|
 |
2d052c |
|
|
 |
2d052c |
return 0;
|
|
 |
2d052c |
}
|
|
 |
1accae |
|
|
 |
1accae |
int lt_dlloader_add(const struct lt_dlentry * ldr)
|
|
 |
1accae |
{
|
|
 |
1accae |
(void)ldr;
|
|
 |
1accae |
return -1;
|
|
 |
1accae |
}
|
|
 |
1accae |
|
|
 |
1accae |
const struct lt_dlentry * lt_dlloader_find(const char * ldrname)
|
|
 |
1accae |
{
|
|
 |
1accae |
(void)ldrname;
|
|
 |
1accae |
return 0;
|
|
 |
1accae |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
static int lt_dlpreload_remove_locked(const struct lt_symdef * symtbl)
|
|
 |
a09152 |
{
|
|
 |
a09152 |
struct lt_modctx * pmod;
|
|
 |
a09152 |
|
|
 |
a09152 |
for (pmod=lt_modv_head; pmod ; pmod=pmod->mnext) {
|
|
 |
a09152 |
if (pmod->symtbl == symtbl) {
|
|
 |
a09152 |
if (pmod->mrefs > 0) {
|
|
 |
a09152 |
pmod->mrefs--;
|
|
 |
a09152 |
return 0;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
return SLTDL_ERR_MODULE_REF_COUNT;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
return SLTDL_ERR_MODULE_PTR_INVALID;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
static void lt_dlpreload_reset_locked(void)
|
|
 |
a09152 |
{
|
|
 |
a09152 |
struct lt_modctx * pmod;
|
|
 |
a09152 |
|
|
 |
a09152 |
for (pmod=lt_modv_head; pmod ; pmod=pmod->mnext)
|
|
 |
a09152 |
if (pmod->symtbl && (pmod->mrefs > 0))
|
|
 |
a09152 |
pmod->mrefs = 0;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
static int lt_dlpreload_modctl_locked(
|
|
 |
a09152 |
const struct lt_symdef * symtbl,
|
|
 |
a09152 |
enum sltdl_modctl op)
|
|
 |
a09152 |
{
|
|
 |
a09152 |
struct lt_modctx * modctx;
|
|
 |
a09152 |
switch (op) {
|
|
 |
a09152 |
case SLTDL_MODCTL_PRELOAD_ADD:
|
|
 |
a09152 |
return lt_dlopen_locked(symtbl,0,0,1)
|
|
 |
a09152 |
? 0 : -1;
|
|
 |
a09152 |
|
|
 |
a09152 |
case SLTDL_MODCTL_PRELOAD_REMOVE:
|
|
 |
a09152 |
return lt_dlpreload_remove_locked(symtbl)
|
|
 |
a09152 |
? 0 : -1;
|
|
 |
a09152 |
|
|
 |
a09152 |
case SLTDL_MODCTL_PRELOAD_DEFAULT:
|
|
 |
a09152 |
if (!(modctx = lt_dlopen_locked(symtbl,0,0,(-1))))
|
|
 |
a09152 |
return -1;
|
|
 |
a09152 |
|
|
 |
a09152 |
modctx->mrefs = -1;
|
|
 |
a09152 |
return 0;
|
|
 |
a09152 |
|
|
 |
a09152 |
case SLTDL_MODCTL_PRELOAD_RESET:
|
|
 |
a09152 |
lt_dlpreload_reset_locked();
|
|
 |
a09152 |
break;
|
|
 |
a09152 |
|
|
 |
a09152 |
default:
|
|
 |
a09152 |
break;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
return 0;
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
static int lt_dlpreload_modctl_impl(
|
|
 |
a09152 |
const struct lt_symdef * symtbl,
|
|
 |
a09152 |
enum sltdl_modctl op)
|
|
 |
a09152 |
{
|
|
 |
a09152 |
int ret;
|
|
 |
a09152 |
|
|
 |
a09152 |
lt_slock();
|
|
 |
a09152 |
|
|
 |
a09152 |
ret = lt_dlpreload_modctl_locked(
|
|
 |
a09152 |
symtbl,op);
|
|
 |
a09152 |
|
|
 |
a09152 |
return lt_sunlock((-1)*!!ret,ret);
|
|
 |
a09152 |
}
|
|
 |
a09152 |
|
|
 |
a09152 |
int lt_dlpreload_modctl(
|
|
 |
a09152 |
const struct lt_symdef * symtbl,
|
|
 |
a09152 |
enum sltdl_modctl op)
|
|
 |
a09152 |
{
|
|
 |
a09152 |
return lt_dlpreload_modctl_impl(symtbl,op);
|
|
 |
a09152 |
}
|