Werner's Miscellanea
Sign in or create your account | Project List | Help
Werner's Miscellanea Git Source Tree
Root/
Source at commit f732d7ea72374a29e9c3ab65a19c7140c47080f3 created 10 years 5 months ago. By Werner Almesberger, ircstat/ML: update for 9/2013 | |
---|---|
1 | /* |
2 | * slave.c - Fakefile slave library |
3 | * |
4 | * Copyright 2012 by Werner Almesberger |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | */ |
11 | |
12 | #include <stdarg.h> |
13 | #include <stdlib.h> |
14 | #include <stdio.h> |
15 | #include <unistd.h> |
16 | #include <string.h> |
17 | #include <fcntl.h> |
18 | #include <errno.h> |
19 | #include <assert.h> |
20 | #include <sys/types.h> |
21 | #include <sys/stat.h> |
22 | |
23 | #define __USE_GNU /* for RTLD_NEXT */ |
24 | #include <dlfcn.h> |
25 | |
26 | #include "util.h" |
27 | #include "fakefile.h" |
28 | #include "comm.h" |
29 | |
30 | |
31 | #define DUMMY_FILE "/dev/null" |
32 | #define master NULL |
33 | |
34 | |
35 | static struct fd_entry { |
36 | int fd; |
37 | struct fd_entry *next; |
38 | } *fake_fds = NULL; |
39 | |
40 | static int (*libc_close)(int fd); |
41 | static int (*libc_dup)(int oldfd); |
42 | static int (*libc_dup2)(int oldfd, int newfd); |
43 | static int (*libc_open)(const char *pathname, int flags, mode_t mode); |
44 | static ssize_t (*libc_read)(int fd, void *buf, size_t count); |
45 | |
46 | static FILE *(*libc_fopen)(const char *path, const char *mode); |
47 | |
48 | static void init_self(void) |
49 | { |
50 | static int initialized = 0; |
51 | |
52 | if (initialized) |
53 | return; |
54 | libc_close = dlsym(RTLD_NEXT, "close"); |
55 | libc_dup = dlsym(RTLD_NEXT, "dup"); |
56 | libc_dup2 = dlsym(RTLD_NEXT, "dup2"); |
57 | libc_open = dlsym(RTLD_NEXT, "open"); |
58 | libc_read = dlsym(RTLD_NEXT, "read"); |
59 | libc_fopen = dlsym(RTLD_NEXT, "fopen"); |
60 | if (!libc_close || !libc_dup || !libc_dup2 || !libc_open || |
61 | !libc_read) { |
62 | perror("dlsym"); |
63 | _exit(1); |
64 | } |
65 | initialized = 1; |
66 | } |
67 | |
68 | |
69 | static int get_fd(void) |
70 | { |
71 | int fd; |
72 | |
73 | fd = libc_open(DUMMY_FILE, O_RDONLY, 0); |
74 | if (fd < 0) { |
75 | perror(DUMMY_FILE); |
76 | exit(1); |
77 | } |
78 | assert(fd); |
79 | return fd; |
80 | } |
81 | |
82 | |
83 | static void add_fake_fd(int fd) |
84 | { |
85 | struct fd_entry *e; |
86 | |
87 | e = alloc_type(struct fd_entry); |
88 | e->fd = fd; |
89 | e->next = fake_fds; |
90 | fake_fds =e; |
91 | } |
92 | |
93 | |
94 | static int is_fake_fd(int fd) |
95 | { |
96 | const struct fd_entry *e; |
97 | |
98 | for (e = fake_fds; e && e->fd != fd; e = e->next); |
99 | return !!e; |
100 | } |
101 | |
102 | |
103 | static int del_fake_fd(int fd) |
104 | { |
105 | struct fd_entry **e, *next; |
106 | |
107 | for (e = &fake_fds; *e; e = &(*e)->next) |
108 | if ((*e)->fd == fd) |
109 | break; |
110 | if (!*e) |
111 | return 0; |
112 | next = (*e)->next; |
113 | free(*e); |
114 | *e = next; |
115 | (void) libc_close(fd); |
116 | return 1; |
117 | } |
118 | |
119 | |
120 | int open(const char *pathname, int flags, ...) |
121 | { |
122 | va_list ap; |
123 | struct fakefile_msg *msg; |
124 | size_t len; |
125 | int mode = 0; |
126 | int fd, res; |
127 | |
128 | init_self(); |
129 | if (flags & O_CREAT) { |
130 | va_start(ap, flags); |
131 | mode = va_arg(ap, int); |
132 | va_end(ap); |
133 | } |
134 | |
135 | fd = get_fd(); |
136 | len = strlen(pathname); |
137 | |
138 | msg = fakefile_msg_new(master, len+5*sizeof(int)); |
139 | fakefile_msg_add_int(msg, ff_et_open); |
140 | fakefile_msg_add_int(msg, flags); |
141 | fakefile_msg_add_int(msg, mode); |
142 | fakefile_msg_add_int(msg, fd); |
143 | fakefile_msg_add_int(msg, len); |
144 | fakefile_msg_add(msg, pathname, len); |
145 | fakefile_msg_end(msg); |
146 | |
147 | msg = fakefile_msg_recv(master); |
148 | res = fakefile_msg_get_int(msg); |
149 | fakefile_msg_end(msg); |
150 | |
151 | //fprintf(stderr, "res %d\n", (int) res); |
152 | if (res <= 0) { |
153 | (void) close(fd); |
154 | if (res < 0) { |
155 | errno = -res; |
156 | return -1; |
157 | } |
158 | } |
159 | if (res) |
160 | add_fake_fd(fd); |
161 | else |
162 | res = libc_open(pathname, flags, mode); |
163 | return res; |
164 | } |
165 | |
166 | |
167 | ssize_t read(int fd, void *buf, size_t count) |
168 | { |
169 | struct fakefile_msg *msg; |
170 | ssize_t res; |
171 | |
172 | init_self(); |
173 | if (!is_fake_fd(fd)) |
174 | return libc_read(fd, buf, count); |
175 | msg = fakefile_msg_new(master, 2*sizeof(int)+sizeof(size_t)); |
176 | fakefile_msg_add_int(msg, ff_et_read); |
177 | fakefile_msg_add_int(msg, fd); |
178 | fakefile_msg_add_size_t(msg, count); |
179 | fakefile_msg_end(msg); |
180 | |
181 | msg = fakefile_msg_recv(master); |
182 | res = fakefile_msg_get_size_t(msg); |
183 | if (res > 0) { |
184 | assert((size_t) res <= count); |
185 | fakefile_msg_get(msg, buf, res); |
186 | } else if (res < 0) { |
187 | errno = -res; |
188 | res = -1; |
189 | } |
190 | fakefile_msg_end(msg); |
191 | //fprintf(stderr, "READ %d\n", (int) res); |
192 | return res; |
193 | } |
194 | |
195 | |
196 | int fstat(int fd, struct stat *buf) |
197 | { |
198 | struct fakefile_msg *msg; |
199 | int res; |
200 | |
201 | init_self(); |
202 | msg = fakefile_msg_new(master, 2*sizeof(int)); |
203 | fakefile_msg_add_int(msg, ff_et_fstat); |
204 | fakefile_msg_add_int(msg, fd); |
205 | fakefile_msg_end(msg); |
206 | |
207 | msg = fakefile_msg_recv(master); |
208 | res = fakefile_msg_get_size_t(msg); |
209 | if (res < 0) { |
210 | errno = -res; |
211 | res = -1; |
212 | } else { |
213 | fakefile_msg_get(msg, buf, sizeof(struct stat)); |
214 | } |
215 | fakefile_msg_end(msg); |
216 | |
217 | return res; |
218 | } |
219 | |
220 | |
221 | int stat(const char *path, struct stat *buf) |
222 | { |
223 | int fd, res; |
224 | |
225 | fd = open(path, O_RDONLY); |
226 | if (fd < 0) |
227 | return fd; |
228 | res = fstat(fd, buf); |
229 | (void) close(fd); |
230 | |
231 | return res; |
232 | } |
233 | |
234 | |
235 | int lstat(const char *path, struct stat *buf) |
236 | { |
237 | return stat(path, buf); |
238 | } |
239 | |
240 | |
241 | int close(int fd) |
242 | { |
243 | struct fakefile_msg *msg; |
244 | int res; |
245 | |
246 | init_self(); |
247 | if (!del_fake_fd(fd)) |
248 | return libc_close(fd); |
249 | |
250 | msg = fakefile_msg_new(master, 2*sizeof(int)); |
251 | fakefile_msg_add_int(msg, ff_et_close); |
252 | fakefile_msg_add_int(msg, fd); |
253 | fakefile_msg_end(msg); |
254 | |
255 | msg = fakefile_msg_recv(master); |
256 | res = fakefile_msg_get_int(msg); |
257 | fakefile_msg_end(msg); |
258 | |
259 | if (res < 0) { |
260 | errno = -res; |
261 | return -1; |
262 | } |
263 | |
264 | return res; |
265 | } |
266 | |
267 | |
268 | FILE *fopen(const char *path, const char *mode) |
269 | { |
270 | init_self(); |
271 | fprintf(stderr, "fopen \"%s\"\n", path); |
272 | return libc_fopen(path, mode); |
273 | } |
274 | |
275 | |
276 | int dup(int oldfd) |
277 | { |
278 | init_self(); |
279 | if (is_fake_fd(oldfd)) { |
280 | fprintf(stderr, "not supporting \"dup\" yet\n"); |
281 | exit(1); |
282 | } |
283 | return libc_dup(oldfd); |
284 | } |
285 | |
286 | |
287 | |
288 | int dup2(int oldfd, int newfd) |
289 | { |
290 | int res; |
291 | |
292 | init_self(); |
293 | if (oldfd == newfd) |
294 | return 0; |
295 | if (is_fake_fd(oldfd)) { |
296 | fprintf(stderr, "not supporting \"dup2\" yet\n"); |
297 | exit(1); |
298 | } |
299 | if (is_fake_fd(newfd)) { |
300 | res = close(newfd); |
301 | if (res < 0) |
302 | return res; |
303 | } |
304 | return libc_dup2(oldfd, newfd); |
305 | } |
306 |
Branches:
master