aboutsummaryrefslogtreecommitdiffstats
path: root/pseudo_wrappers.c
blob: 84bdce7db898f64eabc201f18de2983cc9a25f03 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* wrapper code -- this is the shared code used around the pseduo
 * wrapper functions, which are in pseudo_wrapfuncs.c.
 */
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dlfcn.h>

/* used for various specific function arguments */
#include <dirent.h>
#include <fts.h>
#include <ftw.h>
#include <glob.h>
#include <grp.h>
#include <pwd.h>
#include <utime.h>

#include "pseudo.h"
#include "pseudo_wrapfuncs.h"
#include "pseudo_ipc.h"
#include "pseudo_client.h"

static void pseudo_enosys(const char *);
static int pseudo_populate_wrappers(void);
static volatile int antimagic = 0;
static pthread_mutex_t pseudo_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t pseudo_mutex_holder;
static int pseudo_mutex_recursion = 0;
static int pseudo_getlock(void);
static void pseudo_droplock(void);

extern char *program_invocation_short_name;

/* the generated code goes here */
#include "pseudo_wrapper_table.c"
#include "pseudo_wrapfuncs.c"

static int
pseudo_getlock(void) {
	if (pthread_equal(pseudo_mutex_holder, pthread_self())) {
		++pseudo_mutex_recursion;
		return 0;
	} else {
		if (pthread_mutex_lock(&pseudo_mutex) == 0) {
			pseudo_mutex_recursion = 1;
			pseudo_mutex_holder = pthread_self();
			return 0;
		} else {
			return -1;
		}
	}
}

static void
pseudo_droplock(void) {
	if (--pseudo_mutex_recursion == 0) {
		pseudo_mutex_holder = 0;
		pthread_mutex_unlock(&pseudo_mutex);
	}
}

void
pseudo_antimagic() {
	++antimagic;
}

void
pseudo_magic() {
	if (antimagic > 0)
		--antimagic;
}

static void
pseudo_enosys(const char *func) {
	pseudo_diag("pseudo: ENOSYS for '%s'.\n", func ? func : "<nil>");
	if (getenv("PSEUDO_ENOSYS_ABORT"))
		abort();
}

static int
pseudo_populate_wrappers(void) {
	int i;
	char *debug;
	static int done = 0;
	char *pseudo_path = 0;

	if (done)
		return done;
	pseudo_getlock();
	pseudo_antimagic();
	for (i = 0; pseudo_functions[i].name; ++i) {
		if (*pseudo_functions[i].real == pseudo_functions[i].dummy) {
			int (*f)(void);
			char *e;
			dlerror();
			f = dlsym(RTLD_NEXT, pseudo_functions[i].name);
			if ((e = dlerror()) != NULL) {
				/* leave it pointed to dummy */
				pseudo_diag("No wrapper for %s: %s\n", pseudo_functions[i].name, e);
			} else {
				if (f)
					*pseudo_functions[i].real = f;
			}
		}
	}
	done = 1;
	debug = getenv("PSEUDO_DEBUG");
	if (debug) {
		int level = atoi(debug);
		for (i = 0; i < level; ++i) {
			pseudo_debug_verbose();
		}
	}
	/* must happen after wrappers are set up, because it can call
	 * getcwd(), which needs wrappers, but must happen here so that
	 * any attempt to use a path in a wrapper function will have a
	 * value for cwd.
	 */
	pseudo_client_reset();
	pseudo_path = pseudo_prefix_path(NULL);
	if (pseudo_dir_fd == -1) {
		if (pseudo_path) {
			pseudo_dir_fd = open(pseudo_path, O_RDONLY);
			pseudo_dir_fd = pseudo_fd(pseudo_dir_fd, MOVE_FD);
			free(pseudo_path);
		} else {
			pseudo_diag("No prefix available to to find server.\n");
			exit(1);
		}
		if (pseudo_dir_fd == -1) {
			pseudo_diag("Can't open prefix path (%s) for server.\n",
				strerror(errno));
			exit(1);
		}
	}
	pseudo_debug(2, "(%s) set up wrappers\n", program_invocation_short_name);
	pseudo_magic();
	pseudo_droplock();
	return done;
}