summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/lt_core.c80
-rw-r--r--src/core/lt_path.c92
-rw-r--r--src/internal/sltdl_core.h18
3 files changed, 149 insertions, 41 deletions
diff --git a/src/core/lt_core.c b/src/core/lt_core.c
index df9f58f..8c26ff3 100644
--- a/src/core/lt_core.c
+++ b/src/core/lt_core.c
@@ -4,12 +4,36 @@
/* Released under the Standard MIT License; see COPYING.SLTDL. */
/*******************************************************************/
+#include <dlfcn.h>
+#include <errno.h>
#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
#include <pthread.h>
+
#include <sltdl/sltdl.h>
+#include "sltdl_core.h"
+
+static const char * lt_dlerror_desc[] = {
+ [SLTDL_OK] = 0,
+ [SLTDL_SYSTEM_ERROR] = 0,
+ [SLTDL_DLFCN_ERROR] = 0,
+ [SLTDL_SLTDL_ERROR] = "sltdl internal error",
+ [SLTDL_DLEXIT_REF_COUNT] = "lt_dlexit() reference count already zero",
+ [SLTDL_MODULE_REF_COUNT] = "module reference count already zero",
+ [SLTDL_MODULE_PTR_INVALID] = "module handle invalid",
+ [SLTDL_PATH_INVALID_FIRST_CHAR] = "invalid path (does not begin with a forward slash)",
+ [SLTDL_PATH_INVALID_SEPARATTOR_CHAR] = "invalid path (separator character is not a colon)",
+ [SLTDL_PATH_INVALID_MARK] = "invalid path (mark not within range)",
+ [SLTDL_PATH_INVALID_LEN] = "invalid path (string too long)",
+ [SLTDL_PATH_NO_ENTRY] = "invalid path (not found)",
+};
-static int lt_refs = 0;
-static pthread_mutex_t lt_lock = PTHREAD_MUTEX_INITIALIZER;
+static int lt_refs = 0;
+static int lt_error = 0;
+static int lt_errno = 0;
+static char * lt_dlerr = 0;
+static pthread_mutex_t lt_lock = PTHREAD_MUTEX_INITIALIZER;
int lt_dlinit(void)
{
@@ -28,6 +52,7 @@ int lt_dlexit(void)
return 1;
if (!lt_refs) {
+ lt_error = SLTDL_DLEXIT_REF_COUNT;
pthread_mutex_unlock(&lt_lock);
return 1;
}
@@ -48,8 +73,57 @@ void lt_slock(void)
} while (locked);
}
-int lt_sunlock(int ret)
+int lt_sunlock(int ret, int error)
{
+ if (error == 0) {
+ pthread_mutex_unlock(&lt_lock);
+ return 0;
+ }
+
+ if ((error < 0) || (error >= SLTDL_ERROR_CAP)) {
+ error = SLTDL_SLTDL_ERROR;
+
+ } else if (error == SLTDL_SYSTEM_ERROR) {
+ lt_errno = errno;
+
+ } else if (error == SLTDL_DLFCN_ERROR) {
+ if (lt_dlerr)
+ free(lt_dlerr);
+
+ lt_dlerr = strdup(dlerror());
+ }
+
+ lt_error = error;
pthread_mutex_unlock(&lt_lock);
return ret;
}
+
+const char * lt_dlerror(void)
+{
+ const char * errdesc;
+
+ lt_slock();
+
+ switch (lt_error) {
+ case SLTDL_OK:
+ errdesc = 0;
+ break;
+
+ case SLTDL_SYSTEM_ERROR:
+ errdesc = strerror(lt_errno);
+ break;
+
+ case SLTDL_DLFCN_ERROR:
+ errdesc = lt_dlerr;
+ break;
+
+ default:
+ errdesc = lt_dlerror_desc[lt_error];
+ break;
+ }
+
+ lt_error = 0;
+ lt_sunlock(0,0);
+
+ return errdesc;
+}
diff --git a/src/core/lt_path.c b/src/core/lt_path.c
index 4981b1e..06252a4 100644
--- a/src/core/lt_path.c
+++ b/src/core/lt_path.c
@@ -17,6 +17,7 @@
#include "sltdl_core.h"
#include "sltdl_module.h"
+static int lt_status;
static off_t lt_plen;
static off_t lt_plocs;
static char * lt_upath;
@@ -30,6 +31,12 @@ static struct lt_modctx * lt_modv_tail;
static struct lt_modctx * lt_modv_next;
static struct lt_modctx * lt_modv_cap;
+static int lt_setstatus(int ret, int status)
+{
+ lt_status = status;
+ return ret;
+}
+
const char * lt_dlgetsearchpath(void)
{
return lt_upath;
@@ -44,14 +51,14 @@ static int lt_dlsetsearchpath_locked(const char * path)
off_t elements;
if (path[0] != '/')
- return 1;
+ return lt_setstatus(1,SLTDL_PATH_INVALID_FIRST_CHAR);
elements = 1;
for (ch=&path[1]; *ch; ch++) {
if (*ch == ':') {
if (ch[1] != '/')
- return 1;
+ return lt_setstatus(1,SLTDL_PATH_INVALID_FIRST_CHAR);
elements++;
}
@@ -69,7 +76,7 @@ static int lt_dlsetsearchpath_locked(const char * path)
lt_plocs ^= 0x3f;
if (!(lt_pathv = calloc(lt_plocs,sizeof(char *))))
- return 1;
+ return lt_setstatus(1,SLTDL_SYSTEM_ERROR);
}
if ((ch - path) > lt_plen) {
@@ -84,9 +91,8 @@ static int lt_dlsetsearchpath_locked(const char * path)
lt_plen += 0x7ff;
lt_plen |= 0x7ff;
lt_plen ^= 0x7ff;
-
if (!(lt_upath = calloc(2*lt_plen,1)))
- return 1;
+ return lt_setstatus(1,SLTDL_SYSTEM_ERROR);
lt_vpath = &lt_upath[lt_plen];
}
@@ -113,16 +119,18 @@ static int lt_dlsetsearchpath_locked(const char * path)
lt_vmark = pathv;
- return 0;
+ return lt_setstatus(0,SLTDL_OK);
}
int lt_dlsetsearchpath(const char * path)
{
+ int ret;
lt_slock();
- return lt_sunlock(lt_dlsetsearchpath_locked(path));
+ ret = lt_dlsetsearchpath_locked(path);
+ return lt_sunlock(ret,lt_status);
}
-int lt_dladdsearchdir(const char * path)
+static int lt_dladdsearchdir_locked(const char * path)
{
int ret;
const char * ch;
@@ -131,13 +139,11 @@ int lt_dladdsearchdir(const char * path)
off_t plen;
if (path[0] != '/')
- return 1;
+ return lt_setstatus(1,SLTDL_PATH_INVALID_FIRST_CHAR);
for (ch=path; *ch; ch++)
if (*ch == ':')
- return 1;
-
- lt_slock();
+ return lt_setstatus(1,SLTDL_PATH_INVALID_SEPARATTOR_CHAR);
alen = strlen(path);
plen = strlen(lt_upath);
@@ -154,12 +160,12 @@ int lt_dladdsearchdir(const char * path)
*lt_vmark++ = &lt_vpath[plen];
- return lt_sunlock(0);
+ return lt_setstatus(0,SLTDL_OK);
}
/* (allocation needed) */
if (!(buf = malloc(plen + 1 + alen + 1)))
- return lt_sunlock(1);
+ return lt_setstatus(1,SLTDL_SYSTEM_ERROR);
sprintf(buf,"%s:%s",lt_upath,path);
@@ -167,7 +173,15 @@ int lt_dladdsearchdir(const char * path)
free(buf);
- return lt_sunlock(ret);
+ return ret;
+}
+
+int lt_dladdsearchdir(const char * path)
+{
+ int ret;
+ lt_slock();
+ ret = lt_dladdsearchdir_locked(path);
+ return lt_sunlock(ret,lt_status);
}
int lt_dlinsertsearchdir(const char * mark, const char * path)
@@ -182,26 +196,26 @@ int lt_dlinsertsearchdir(const char * mark, const char * path)
off_t offset;
char ** pathv;
- if (path[0] != '/')
- return 1;
-
if (!mark)
return lt_dladdsearchdir(path);
+ lt_slock();
+
+ if (path[0] != '/')
+ return lt_sunlock(1,SLTDL_PATH_INVALID_FIRST_CHAR);
+
for (ch=path; *ch; ch++)
if (*ch == ':')
- return 1;
-
- lt_slock();
+ return lt_sunlock(1,SLTDL_PATH_INVALID_SEPARATTOR_CHAR);
alen = strlen(path);
plen = strlen(lt_upath);
if ((mark < lt_upath) || (mark >= &lt_upath[plen]))
- return lt_sunlock(1);
+ return lt_sunlock(1,SLTDL_PATH_INVALID_MARK);
if ((mark > lt_upath) && (mark[-1] != ':'))
- return lt_sunlock(1);
+ return lt_sunlock(1,SLTDL_PATH_INVALID_MARK);
mark = &lt_vpath[mark - lt_upath];
@@ -226,14 +240,14 @@ int lt_dlinsertsearchdir(const char * mark, const char * path)
memcpy(&lt_upath[offset],path,alen);
lt_upath[offset+alen] = ':';
lt_vmark++;
- return lt_sunlock(0);
+ return lt_sunlock(0,SLTDL_OK);
}
}
}
/* (allocation needed) */
if (!(buf = malloc(plen + 1 + alen + 1)))
- return lt_sunlock(1);
+ return lt_sunlock(1,SLTDL_SYSTEM_ERROR);
for (dst=buf, pathv=lt_pathv; *pathv; pathv++) {
if (*pathv == mark)
@@ -249,7 +263,7 @@ int lt_dlinsertsearchdir(const char * mark, const char * path)
free(buf);
- return lt_sunlock(ret);
+ return lt_sunlock(ret,lt_status);
}
static int lt_dlpathopen_locked(
@@ -267,7 +281,7 @@ static int lt_dlpathopen_locked(
char path[1024];
if ((mlen = strlen(module)) >= sizeof(path))
- return -1;
+ return lt_setstatus(-1,SLTDL_PATH_INVALID_LEN);
memcpy(path,module,mlen);
@@ -278,7 +292,7 @@ static int lt_dlpathopen_locked(
for (pext=extv; *pext; pext++) {
if (mlen + (elen = strlen(*pext)) >= (sizeof(path))) {
close(fdat);
- return (-1);
+ return lt_setstatus(-1,SLTDL_PATH_INVALID_LEN);
}
memcpy(&path[mlen],*pext,elen);
@@ -294,14 +308,14 @@ static int lt_dlpathopen_locked(
if (!(*mpath = malloc(plen))) {
close(fdat);
close(fdmod);
- return (-1);
+ return lt_setstatus(-1,SLTDL_SYSTEM_ERROR);
}
sprintf(*mpath,"%s/%s",*ppath,path);
}
close(fdat);
- return fdmod;
+ return lt_setstatus(fdmod,SLTDL_OK);
}
}
@@ -309,13 +323,15 @@ static int lt_dlpathopen_locked(
}
}
- return -1;
+ return lt_setstatus(-1,SLTDL_PATH_NO_ENTRY);
}
int lt_dlpathopen(const char * module, const char ** extv)
{
+ int ret;
lt_slock();
- return lt_sunlock(lt_dlpathopen_locked(module,extv,0));
+ ret = lt_dlpathopen_locked(module,extv,0);
+ return lt_sunlock(ret,lt_status);
}
static struct lt_modctx * lt_dlopen_locked(
@@ -339,6 +355,7 @@ static struct lt_modctx * lt_dlopen_locked(
if (lt_modv_next == lt_modv_cap) {
if (!(modctx_buf = calloc(64,sizeof(*modctx)))) {
free(mpath);
+ lt_setstatus(0,SLTDL_SYSTEM_ERROR);
return 0;
}
@@ -349,6 +366,7 @@ static struct lt_modctx * lt_dlopen_locked(
/* dlopen */
if (!(maddr = dlopen(mpath,mode))) {
free(mpath);
+ lt_setstatus(0,SLTDL_DLFCN_ERROR);
return 0;
}
@@ -388,7 +406,7 @@ struct lt_modctx * lt_dlopen(const char * module)
lt_slock();
modctx = lt_dlopen_locked(module,extv,RTLD_NOW);
- lt_sunlock(0);
+ lt_sunlock(0,lt_status);
return modctx;
}
@@ -399,7 +417,7 @@ struct lt_modctx * lt_dlopenext(const char * module)
lt_slock();
modctx = lt_dlopen_locked(module,extv,RTLD_NOW);
- lt_sunlock(0);
+ lt_sunlock(0,lt_status);
return modctx;
}
@@ -424,12 +442,12 @@ int lt_dlclose(struct lt_modctx * modctx)
if (pmod == modctx) {
if (pmod->mrefs) {
pmod->mrefs--;
- return lt_sunlock(0);
+ return lt_sunlock(0,SLTDL_OK);
}
- return lt_sunlock(-1);
+ return lt_sunlock(-1,SLTDL_MODULE_REF_COUNT);
}
}
- return lt_sunlock(-1);
+ return lt_sunlock(-1,SLTDL_MODULE_PTR_INVALID);
}
diff --git a/src/internal/sltdl_core.h b/src/internal/sltdl_core.h
index f74542e..35e1a24 100644
--- a/src/internal/sltdl_core.h
+++ b/src/internal/sltdl_core.h
@@ -1,7 +1,23 @@
#ifndef SLTDL_CORE_H
#define SLTDL_CORE_H
+enum sltdl_error {
+ SLTDL_OK,
+ SLTDL_SYSTEM_ERROR,
+ SLTDL_DLFCN_ERROR,
+ SLTDL_SLTDL_ERROR,
+ SLTDL_DLEXIT_REF_COUNT,
+ SLTDL_MODULE_REF_COUNT,
+ SLTDL_MODULE_PTR_INVALID,
+ SLTDL_PATH_INVALID_FIRST_CHAR,
+ SLTDL_PATH_INVALID_SEPARATTOR_CHAR,
+ SLTDL_PATH_INVALID_MARK,
+ SLTDL_PATH_INVALID_LEN,
+ SLTDL_PATH_NO_ENTRY,
+ SLTDL_ERROR_CAP,
+};
+
void lt_slock(void);
-int lt_sunlock(int);
+int lt_sunlock(int,int);
#endif