diff options
author | midipix <writeonce@midipix.org> | 2019-12-21 14:40:23 +0000 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2019-12-21 14:43:47 +0000 |
commit | 8744a55869e9d0288bebf8f340d5186dc99922e9 (patch) | |
tree | 7e85b418d7a9949ee7946a21933a3c951830826f | |
parent | 64a26cc67d6782d1ee8812c8c1307a2607144b97 (diff) | |
download | sltdl-8744a55869e9d0288bebf8f340d5186dc99922e9.tar.bz2 sltdl-8744a55869e9d0288bebf8f340d5186dc99922e9.tar.xz |
lt_dlerror(): initial implementation and integration.
-rw-r--r-- | src/core/lt_core.c | 80 | ||||
-rw-r--r-- | src/core/lt_path.c | 92 | ||||
-rw-r--r-- | src/internal/sltdl_core.h | 18 |
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(<_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(<_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(<_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 = <_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++ = <_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 >= <_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 = <_vpath[mark - lt_upath]; @@ -226,14 +240,14 @@ int lt_dlinsertsearchdir(const char * mark, const char * path) memcpy(<_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 |