Root/fakefile/slave.c

Source at commit a9ee51921bbb2435a8b3df66b38f3029d288f264 created 5 years 6 months ago.
By Werner Almesberger, ircstat/ML: update for 2014-03
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
35static struct fd_entry {
36    int fd;
37    struct fd_entry *next;
38} *fake_fds = NULL;
39
40static int (*libc_close)(int fd);
41static int (*libc_dup)(int oldfd);
42static int (*libc_dup2)(int oldfd, int newfd);
43static int (*libc_open)(const char *pathname, int flags, mode_t mode);
44static ssize_t (*libc_read)(int fd, void *buf, size_t count);
45
46static FILE *(*libc_fopen)(const char *path, const char *mode);
47
48static 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");
59libc_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
69static 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
83static 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
94static 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
103static 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
120int 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
167ssize_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
196int 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
221int 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
235int lstat(const char *path, struct stat *buf)
236{
237    return stat(path, buf);
238}
239
240
241int 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
268FILE *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
276int 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
288int 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

Archive Download this file

Branches:
master



interactive