Blame src/core/lt_core.c

564b3c
/*******************************************************************/
564b3c
/*  sltdl: a surrogate ltdl implementation                         */
84a51a
/*  Copyright (C) 2019 SysDeer Technologies, LLC                   */
564b3c
/*  Released under the Standard MIT License; see COPYING.SLTDL.    */
564b3c
/*******************************************************************/
564b3c
8744a5
#include <dlfcn.h>
8744a5
#include <errno.h>
564b3c
#include <limits.h>
8744a5
#include <stdlib.h>
8744a5
#include <string.h>
564b3c
#include <pthread.h>
8744a5
564b3c
#include <sltdl/sltdl.h>
8744a5
#include "sltdl_core.h"
8744a5
8744a5
static const char * lt_dlerror_desc[] = {
8744a5
	[SLTDL_OK]                              = 0,
8744a5
	[SLTDL_SYSTEM_ERROR]                    = 0,
8744a5
	[SLTDL_DLFCN_ERROR]                     = 0,
8744a5
	[SLTDL_SLTDL_ERROR]                     = "sltdl internal error",
8744a5
	[SLTDL_DLEXIT_REF_COUNT]                = "lt_dlexit() reference count already zero",
8744a5
	[SLTDL_MODULE_REF_COUNT]                = "module reference count already zero",
8744a5
	[SLTDL_MODULE_PTR_INVALID]              = "module handle invalid",
8744a5
	[SLTDL_PATH_INVALID_FIRST_CHAR]         = "invalid path (does not begin with a forward slash)",
8744a5
	[SLTDL_PATH_INVALID_SEPARATTOR_CHAR]    = "invalid path (separator character is not a colon)",
8744a5
	[SLTDL_PATH_INVALID_MARK]               = "invalid path (mark not within range)",
8744a5
	[SLTDL_PATH_INVALID_LEN]                = "invalid path (string too long)",
8744a5
	[SLTDL_PATH_NO_ENTRY]                   = "invalid path (not found)",
8744a5
};
564b3c
8744a5
static int             lt_refs  = 0;
8744a5
static int             lt_error = 0;
8744a5
static int             lt_errno = 0;
8744a5
static char *          lt_dlerr = 0;
8744a5
static pthread_mutex_t lt_lock  = PTHREAD_MUTEX_INITIALIZER;
564b3c
564b3c
int lt_dlinit(void)
564b3c
{
564b3c
	if (pthread_mutex_lock(&lt_lock))
564b3c
		return 1;
564b3c
564b3c
	lt_refs++;
564b3c
	pthread_mutex_unlock(&lt_lock);
564b3c
564b3c
	return 0;
564b3c
}
564b3c
564b3c
int lt_dlexit(void)
564b3c
{
564b3c
	if (pthread_mutex_lock(&lt_lock))
564b3c
		return 1;
564b3c
564b3c
	if (!lt_refs) {
8744a5
		lt_error = SLTDL_DLEXIT_REF_COUNT;
564b3c
		pthread_mutex_unlock(&lt_lock);
564b3c
		return 1;
564b3c
	}
564b3c
564b3c
	lt_refs--;
564b3c
564b3c
	pthread_mutex_unlock(&lt_lock);
564b3c
564b3c
	return 0;
564b3c
}
c42bd5
c42bd5
void lt_slock(void)
c42bd5
{
c42bd5
	int locked;
c42bd5
c42bd5
	do {
c42bd5
		locked = pthread_mutex_lock(&lt_lock);
c42bd5
	} while (locked);
c42bd5
}
c42bd5
8744a5
int lt_sunlock(int ret, int error)
c42bd5
{
8744a5
	if (error ==  0) {
8744a5
		pthread_mutex_unlock(&lt_lock);
8744a5
		return 0;
8744a5
	}
8744a5
8744a5
	if ((error < 0) || (error >= SLTDL_ERROR_CAP)) {
8744a5
		error = SLTDL_SLTDL_ERROR;
8744a5
8744a5
	} else if (error == SLTDL_SYSTEM_ERROR) {
8744a5
		lt_errno = errno;
8744a5
8744a5
	} else if (error == SLTDL_DLFCN_ERROR) {
8744a5
		if (lt_dlerr)
8744a5
			free(lt_dlerr);
8744a5
8744a5
		lt_dlerr = strdup(dlerror());
8744a5
	}
8744a5
8744a5
	lt_error = error;
c42bd5
	pthread_mutex_unlock(&lt_lock);
c42bd5
	return ret;
c42bd5
}
8744a5
8744a5
const char * lt_dlerror(void)
8744a5
{
8744a5
	const char * errdesc;
8744a5
8744a5
	lt_slock();
8744a5
8744a5
	switch (lt_error) {
8744a5
		case SLTDL_OK:
8744a5
			errdesc = 0;
8744a5
			break;
8744a5
8744a5
		case SLTDL_SYSTEM_ERROR:
8744a5
			errdesc = strerror(lt_errno);
8744a5
			break;
8744a5
8744a5
		case SLTDL_DLFCN_ERROR:
8744a5
			errdesc = lt_dlerr;
8744a5
			break;
8744a5
8744a5
		default:
8744a5
			errdesc = lt_dlerror_desc[lt_error];
8744a5
			break;
8744a5
	}
8744a5
8744a5
	lt_error = 0;
8744a5
	lt_sunlock(0,0);
8744a5
8744a5
	return errdesc;
8744a5
}