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 | * 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 | |
24 | struct event { |
25 | struct fakefile_event ev; |
26 | struct fakefile *ff; |
27 | void *tmp; |
28 | void (*respond)(struct event *ev); |
29 | }; |
30 | |
31 | static struct fakefile *fakefiles = NULL; |
32 | static struct pollfd *fds = NULL; |
33 | static int nfds = 0; |
34 | |
35 | |
36 | static 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 | |
48 | static 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 | |
59 | static 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 | |
70 | struct 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 | |
90 | static 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 | |
105 | static 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 | |
122 | static 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 | |
138 | static void respond_exit(struct event *ev) |
139 | { |
140 | } |
141 | |
142 | |
143 | static 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 | |
155 | static 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 | |
242 | static 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 | |
262 | struct 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 | |
291 | void 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 | |
300 | void fakefile_end(struct fakefile *ff) |
301 | { |
302 | } |
303 |
Branches:
master