summaryrefslogtreecommitdiffhomepage
path: root/src/core/lt_core.c
blob: e3cadd4cb71edf430538968a8e5d09de795cef27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*******************************************************************/
/*  sltdl: a surrogate ltdl implementation                         */
/*  Copyright (C) 2019 SysDeer Technologies, LLC                   */
/*  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_ERR_OK]                              = 0,
	[SLTDL_ERR_SYSTEM_ERROR]                    = 0,
	[SLTDL_ERR_DLFCN_ERROR]                     = 0,
	[SLTDL_ERR_SLTDL_ERROR]                     = "sltdl internal error",
	[SLTDL_ERR_DLEXIT_REF_COUNT]                = "lt_dlexit() reference count already zero",
	[SLTDL_ERR_MODULE_REF_COUNT]                = "module reference count already zero",
	[SLTDL_ERR_MODULE_PTR_INVALID]              = "module handle invalid",
	[SLTDL_ERR_PATH_INVALID_FIRST_CHAR]         = "invalid path (does not begin with a forward slash)",
	[SLTDL_ERR_PATH_INVALID_SEPARATTOR_CHAR]    = "invalid path (separator character is not a colon)",
	[SLTDL_ERR_PATH_INVALID_MARK]               = "invalid path (mark not within range)",
	[SLTDL_ERR_PATH_INVALID_LEN]                = "invalid path (string too long)",
	[SLTDL_ERR_PATH_NO_ENTRY]                   = "invalid path (not found)",
	[SLTDL_ERR_CANNOT_OPEN]                     = "could not open module",
	[SLTDL_ERR_CANNOT_CLOSE]                    = "could not close module",
	[SLTDL_ERR_SYMBOL_NOT_FOUND]                = "symbol not found",
};

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)
{
	if (pthread_mutex_lock(&lt_lock))
		return 1;

	lt_refs++;
	pthread_mutex_unlock(&lt_lock);

	return 0;
}

int lt_dlexit(void)
{
	if (pthread_mutex_lock(&lt_lock))
		return 1;

	if (!lt_refs) {
		lt_error = SLTDL_ERR_DLEXIT_REF_COUNT;
		pthread_mutex_unlock(&lt_lock);
		return 1;
	}

	lt_refs--;

	pthread_mutex_unlock(&lt_lock);

	return 0;
}

void lt_slock(void)
{
	int locked;

	do {
		locked = pthread_mutex_lock(&lt_lock);
	} while (locked);
}

int lt_sunlock(int ret, int error)
{
	if (error ==  0) {
		pthread_mutex_unlock(&lt_lock);
		return 0;
	}

	if ((error < 0) || (error >= SLTDL_ERR_CAP)) {
		error = SLTDL_ERR_SLTDL_ERROR;

	} else if (error == SLTDL_ERR_SYSTEM_ERROR) {
		lt_errno = errno;

	} else if (error == SLTDL_ERR_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_ERR_OK:
			errdesc = 0;
			break;

		case SLTDL_ERR_SYSTEM_ERROR:
			errdesc = strerror(lt_errno);
			break;

		case SLTDL_ERR_DLFCN_ERROR:
			errdesc = lt_dlerr;
			break;

		default:
			errdesc = lt_dlerror_desc[lt_error];
			break;
	}

	lt_error = 0;
	lt_sunlock(0,0);

	return errdesc;
}