Root/fakefile/fakefile.c

Source at commit a9ee51921bbb2435a8b3df66b38f3029d288f264 created 5 years 6 months ago.
By Werner Almesberger, ircstat/ML: update for 2014-03
1/*
2 * fakefile.c - Programmed file system illusion
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
13#include <stdlib.h>
14#include <stdio.h>
15#include <poll.h>
16#include <assert.h>
17#include <sys/wait.h>
18
19#include "util.h"
20#include "internal.h"
21#include "fakefile.h"
22
23
24struct event {
25    struct fakefile_event ev;
26    struct fakefile *ff;
27    void *tmp;
28    void (*respond)(struct event *ev);
29};
30
31static struct fakefile *fakefiles = NULL;
32static struct pollfd *fds = NULL;
33static int nfds = 0;
34
35
36static void map_slave_fd(struct fakefile *ff, int fd, void *handle)
37{
38    struct fd_map *map;
39
40    map = alloc_type(struct fd_map);
41    map->fd = fd;
42    map->handle = handle;
43    map->next = ff->map;
44    ff->map = map;
45}
46
47
48static void *lookup_slave_fd(struct fakefile *ff, int fd)
49{
50    const struct fd_map *map;
51
52    for (map = ff->map; map; map = map->next)
53        if (map->fd == fd)
54            return map->handle;
55    abort();
56}
57
58
59static void unmap_slave_fd(struct fakefile *ff, int fd)
60{
61    struct fd_map **map, *next;
62
63    for (map = &ff->map; (*map)->fd != fd; map = &(*map)->next);
64    next = (*map)->next;
65    free(*map);
66    *map = next;
67}
68
69
70struct fakefile *fakefile_execv(const char *path, char *const argv[])
71{
72    struct fakefile *ff;
73
74    ff = fakefile_launch(path, argv);
75    ff->map = NULL;
76    ff->next = fakefiles;
77    fakefiles = ff;
78    fds = realloc(fds, sizeof(struct pollfd)*(nfds+1));
79    if (!fds) {
80        perror("realloc");
81        exit(1);
82    }
83    fds[nfds].fd = fakefile_peer_fd(ff->peer);
84    fds[nfds].events = POLLIN | POLLHUP;
85    nfds++;
86    return ff;
87}
88
89
90static void respond_open(struct event *ev)
91{
92    const struct fakefile_open *prm = &ev->ev.u.open;
93    struct fakefile *ff = ev->ff;
94    struct fakefile_msg *msg;
95
96    msg = fakefile_msg_new(ff->peer, sizeof(int));
97    if (prm->res > 0)
98        map_slave_fd(ff, prm->res, prm->handle);
99    fakefile_msg_add_int(msg, prm->res);
100    fakefile_msg_end(msg);
101    free(prm->name);
102}
103
104
105static void respond_read(struct event *ev)
106{
107    const struct fakefile_read *prm = &ev->ev.u.read;
108    struct fakefile *ff = ev->ff;
109    struct fakefile_msg *msg;
110    ssize_t size;
111
112    size = prm->len < 0 ? 0 : prm->len;
113    msg = fakefile_msg_new(ff->peer, sizeof(ssize_t)+size);
114    fakefile_msg_add_ssize_t(msg, prm->len);
115    if (size)
116        fakefile_msg_add(msg, prm->buf, size);
117    fakefile_msg_end(msg);
118    free(ev->tmp);
119}
120
121
122static void respond_fstat(struct event *ev)
123{
124    const struct fakefile_fstat *prm = &ev->ev.u.fstat;
125    struct fakefile *ff = ev->ff;
126    struct fakefile_msg *msg;
127    ssize_t size;
128
129    size = prm->res < 0 ? 0 : sizeof(struct stat);
130    msg = fakefile_msg_new(ff->peer, sizeof(int)+size);
131    fakefile_msg_add_int(msg, prm->res);
132    if (size)
133        fakefile_msg_add(msg, &prm->st, sizeof(struct stat));
134    fakefile_msg_end(msg);
135}
136
137
138static void respond_exit(struct event *ev)
139{
140}
141
142
143static void respond_close(struct event *ev)
144{
145    const struct fakefile_close *prm = &ev->ev.u.close;
146    struct fakefile *ff = ev->ff;
147    struct fakefile_msg *msg;
148
149    msg = fakefile_msg_new(ff->peer, sizeof(int));
150    fakefile_msg_add_int(msg, prm->res);
151    fakefile_msg_end(msg);
152}
153
154
155static struct fakefile_event *get_event(int fd)
156{
157    struct fakefile *ff;
158    struct event *ev;
159    struct fakefile_msg *msg;
160
161    for (ff = fakefiles; ff; ff = ff->next)
162        if (fakefile_peer_fd(ff->peer) == fd)
163            break;
164    assert(ff);
165
166    ev = alloc_type(struct event);
167    ev->ff = ff;
168
169    msg = fakefile_msg_recv(ff->peer);
170    ev->ev.type = fakefile_msg_get_int(msg);
171    switch (ev->ev.type) {
172    case ff_et_exit: {
173        struct fakefile_exit *prm = &ev->ev.u.exit;
174
175        ev->respond = respond_exit;
176        prm->status = fakefile_msg_get_int(msg);
177        break;
178    }
179    case ff_et_open: {
180        struct fakefile_open *prm = &ev->ev.u.open;
181        int len;
182
183        ev->respond = respond_open;
184        prm->flags = fakefile_msg_get_int(msg);
185        prm->mode = fakefile_msg_get_int(msg);
186        prm->res = fakefile_msg_get_int(msg);
187        len = fakefile_msg_get_int(msg);
188        prm->name = alloc_size(len+1);
189        fakefile_msg_get(msg, prm->name, len);
190        prm->name[len] = 0;
191        prm->handle = NULL;
192        break;
193    }
194    case ff_et_read: {
195        struct fakefile_read *prm = &ev->ev.u.read;
196        int fd;
197
198        ev->respond = respond_read;
199        fd = fakefile_msg_get_int(msg);
200        prm->handle = lookup_slave_fd(ff, fd);
201        prm->len = fakefile_msg_get_size_t(msg);
202        prm->buf = ev->tmp = alloc_size(prm->len);
203        break;
204    }
205    case ff_et_write: {
206        abort();
207    }
208    case ff_et_close: {
209        struct fakefile_close *prm = &ev->ev.u.close;
210        int fd;
211
212        ev->respond = respond_close;
213        fd = fakefile_msg_get_int(msg);
214        prm->handle = lookup_slave_fd(ff, fd);
215        prm->res = 0;
216        break;
217    }
218    case ff_et_unlink:
219        abort();
220    case ff_et_rename:
221        abort();
222    case ff_et_fstat: {
223        struct fakefile_fstat *prm = &ev->ev.u.fstat;
224        int fd;
225
226        ev->respond = respond_fstat;
227        fd = fakefile_msg_get_int(msg);
228        prm->handle = lookup_slave_fd(ff, fd);
229        prm->res = fstat(fd, &prm->st);
230        break;
231    }
232    default:
233        abort();
234    }
235    fakefile_msg_end(msg);
236    if (fakefile_internal_event(ev))
237        return NULL;
238    return &ev->ev;
239}
240
241
242static struct fakefile_event *handle_exit(int fd)
243{
244    struct fakefile *ff;
245    struct fakefile_event *event;
246
247    for (ff = fakefiles; ff; ff = ff->next)
248        if (fakefile_peer_fd(ff->peer) == fd)
249            break;
250    assert(ff);
251    event = alloc_type(struct fakefile_event);
252    event->type = ff_et_exit;
253    if (waitpid(ff->pid, &event->u.exit.status, 0) < 0) {
254        perror("waitpid");
255        exit(1);
256    }
257//@@@ destroy
258    return event;
259}
260
261
262struct fakefile_event *fakefile_poll(void)
263{
264    struct fakefile_event *event;
265    struct pollfd *p;
266    int n;
267
268    while (1) {
269        n = poll(fds, nfds, -1);
270        if (n < 0) {
271            perror("poll");
272            exit(1);
273        }
274        if (!n) {
275            fprintf(stderr, "poll() returned 0\n");
276            exit(1);
277        }
278        for (p = fds; n && p != fds+nfds; p++) {
279            if (p->revents & POLLIN) {
280                event = get_event(p->fd);
281                if (event)
282                    return event;
283            }
284            if (p->revents & POLLHUP)
285                return handle_exit(p->fd);
286        }
287    }
288}
289
290
291void fakefile_respond(struct fakefile_event *event)
292{
293    struct event *ev = (struct event *) event;
294
295    ev->respond(ev);
296    free(ev);
297}
298
299
300void fakefile_end(struct fakefile *ff)
301{
302}
303

Archive Download this file

Branches:
master



interactive