Date:2012-03-29 23:42:01 (7 years 5 months ago)
Author:Werner Almesberger
Commit:15067435ae364dafdddbea319c3cc3b020a8a4ba
Message:fakefile/: so far unsuccessful attempt at jailing Kicad

Files: fakefile/Makefile (1 diff)
fakefile/README (1 diff)
fakefile/comm.c (1 diff)
fakefile/comm.h (1 diff)
fakefile/demo.c (1 diff)
fakefile/fakefile.c (1 diff)
fakefile/fakefile.h (1 diff)
fakefile/file.c (1 diff)
fakefile/internal.h (1 diff)
fakefile/launch.c (1 diff)
fakefile/slave.c (1 diff)
fakefile/util.h (1 diff)

Change Details

fakefile/Makefile
1#
2# Makefile - Build the Fakefile libraries
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
12CFLAGS = -Wall -g -Wextra -Wno-unused-parameter -fPIC
13LDFLAGS = -L. -Wl,-rpath=$(shell pwd)
14LDLIBS = -lfakefile
15
16LIBFAKEFILE_OBJS = comm.o fakefile.o file.o launch.o
17LIBFFSLAVE_OBJS = comm.o slave.o
18TARGETS = libfakefile.so libfakefile_slave.so demo
19
20CC_normal := $(CC)
21LD_normal := $(LD)
22DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
23
24CC_quiet = @echo " CC " $@ && $(CC_normal)
25LD_quiet = @echo " LD " $@ && $(LD_normal)
26GEN_quiet = @echo " GENERATE " $@ &&
27DEPEND_quiet = @$(DEPEND_normal)
28
29ifeq ($(V),1)
30    CC = $(CC_normal)
31    LD = $(LD_normal)
32    GEN =
33    DEPEND = $(DEPEND_normal)
34else
35    CC = $(CC_quiet)
36    LD = $(LD_quiet)
37    GEN = $(GEN_quiet)
38    DEPEND = $(DEPEND_quiet)
39endif
40
41.PHONY: all clean spotless
42
43all: $(TARGETS)
44
45libfakefile.so: $(LIBFAKEFILE_OBJS)
46        $(LD) -shared -o $@ $^
47
48libfakefile_slave.so: $(LIBFFSLAVE_OBJS)
49        $(LD) -shared -o $@ $^ -ldl
50
51clean:
52        rm -f $(LIBFAKEFILE_OBJS) $(LIBFFSLAVE_OBJS)
53
54spotless: clean
55        rm -f $(TARGETS)
fakefile/README
1Don't use this yet ! This was intended as a means to run Kicad in a
2"jail", but that didn't pan out. Probably have to convert it to use
3ptrace.
fakefile/comm.c
1/*
2 * comm.c - Fakefile IPC functions
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 <stdint.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <string.h>
17#include <assert.h>
18#include <sys/types.h>
19
20#include "util.h"
21#include "comm.h"
22
23
24#define BUF_SIZE 4096
25
26
27struct fakefile_peer {
28    int in, out;
29    uint8_t buf[BUF_SIZE];
30    void *pos;
31    const void *end;
32};
33
34
35struct fakefile_msg {
36    struct fakefile_peer *peer;
37    void *buf; /* NULL if reading */
38    void *pos; /* current position in buffer; write only */
39    size_t len; /* amount of data read/written so far */
40    size_t msg_size; /* declared size */
41    size_t buf_size; /* allocated size; write only */
42};
43
44
45static int master_fd(const char *name)
46{
47    const char *s;
48    char *end;
49    long n;
50
51    s = getenv(name);
52    if (!s) {
53        fprintf(stderr, "%s not set\n", name);
54        exit(1);
55    }
56    n = strtol(s, &end, 0);
57    if (*end || n < 0) {
58        fprintf(stderr, "invalid fd \"%s\" for %s\n", s, name);
59        exit(1);
60    }
61    return n;
62}
63
64
65static struct fakefile_peer *sanitize_peer(struct fakefile_peer *peer)
66{
67    static int have_peer = 0;
68    static struct fakefile_peer master;
69
70    if (peer)
71        return peer;
72    if (!have_peer) {
73        master.in = master_fd(FAKEFILE_MASTER_OUT_VAR);
74        master.out = master_fd(FAKEFILE_MASTER_IN_VAR);
75        master.pos = master.buf;
76        master.end = master.buf;
77        have_peer = 1;
78    }
79    return &master;
80}
81
82
83struct fakefile_peer *fakefile_peer(int in, int out)
84{
85    struct fakefile_peer *peer;
86
87    peer = alloc_type(struct fakefile_peer);
88    peer->in = in;
89    peer->out = out;
90    peer->pos = peer->buf;
91    peer->end = peer->buf;
92    return peer;
93}
94
95
96void fakefile_peer_close(struct fakefile_peer *peer)
97{
98    (void) close(peer->in);
99    (void) close(peer->out);
100    free(peer);
101}
102
103
104int fakefile_peer_fd(const struct fakefile_peer *peer)
105{
106    return peer->in;
107}
108
109
110struct fakefile_msg *fakefile_msg_new(struct fakefile_peer *peer, int size)
111{
112    struct fakefile_msg *msg;
113    size_t buf_size;
114
115    size += sizeof(int);
116    buf_size = size > BUF_SIZE ? BUF_SIZE : size;
117    msg = alloc_size(sizeof(struct fakefile_msg)+buf_size);
118    msg->peer = sanitize_peer(peer);
119    msg->buf = msg->pos = msg+1;
120    msg->len = 0;
121    msg->msg_size = size;
122    msg->buf_size = buf_size;
123    fakefile_msg_add_int(msg, size);
124    return msg;
125}
126
127
128static void flush_out(struct fakefile_msg *msg)
129{
130    const void *p;
131    ssize_t len;
132
133    if (msg->pos == msg->buf)
134        return;
135    for (p = msg->buf; p != msg->pos; p += len) {
136        len = write(msg->peer->out, p, msg->pos-p);
137        if (len <= 0) {
138            perror("fakefile IPC write");
139            exit(1);
140        }
141    }
142}
143
144
145struct fakefile_msg *fakefile_msg_recv(struct fakefile_peer *peer)
146{
147    struct fakefile_msg *msg;
148
149    msg = alloc_type(struct fakefile_msg);
150    msg->peer = sanitize_peer(peer);
151    msg->buf = NULL;
152    msg->len = 0;
153    msg->msg_size = sizeof(int);
154    msg->msg_size = fakefile_msg_get_int(msg);
155    return msg;
156}
157
158
159void fakefile_msg_end(struct fakefile_msg *msg)
160{
161#if 0
162fprintf(stderr, "end: len %d size %d (%p)\n",
163  (int) msg->len, (int) msg->msg_size, msg->buf);
164#endif
165    assert(msg->len == msg->msg_size);
166    if (msg->buf)
167        flush_out(msg);
168    free(msg);
169}
170
171
172static void add_chunk(struct fakefile_msg *msg, const void *buf, size_t len)
173{
174    memcpy(msg->pos, buf, len);
175    msg->pos += len;
176    if (msg->pos == msg->buf+msg->buf_size) {
177        flush_out(msg);
178        msg->pos = msg->buf;
179    }
180}
181
182
183void fakefile_msg_add(struct fakefile_msg *msg, const void *buf, size_t len)
184{
185    size_t chunk;
186
187#if 0
188fprintf(stderr, "add: %d+%d/%d (%p)\n",
189    (int) msg->len, (int) len, (int) msg->msg_size, msg->buf);
190#endif
191    assert(msg->len+len <= msg->msg_size);
192    while (len && msg->pos+len > msg->buf+msg->buf_size) {
193        chunk = msg->buf+msg->buf_size-msg->pos;
194        if (chunk > len)
195            chunk = len;
196        add_chunk(msg, buf, chunk);
197        buf += chunk;
198        len -= chunk;
199        msg->len += chunk;
200    }
201    if (len) {
202        add_chunk(msg, buf, len);
203        msg->len += len;
204    }
205}
206
207
208static size_t get_chunk(struct fakefile_peer *peer, void *buf, size_t len)
209{
210    ssize_t got;
211
212    got = read(peer->in, buf, len);
213    if (got < 0) {
214        perror("fakefile IPC read");
215        exit(1);
216    }
217    if (!got) {
218        fprintf(stderr, "fakefile EOF\n");
219        exit(1);
220    }
221    return got;
222}
223
224
225void fakefile_msg_get(struct fakefile_msg *msg, void *buf, size_t len)
226{
227    struct fakefile_peer *peer = msg->peer;
228    size_t chunk, got;
229
230    assert(msg->len+len <= msg->msg_size);
231    if (!len)
232        return;
233    if (peer->pos != peer->end) {
234        chunk = peer->end-peer->pos;
235        if (chunk > len)
236            chunk = len;
237        memcpy(buf, peer->pos, chunk);
238        peer->pos += chunk;
239        buf += chunk;
240        len -= chunk;
241        msg->len += chunk;
242    }
243    while (len >= BUF_SIZE) {
244        got = get_chunk(peer, buf, BUF_SIZE);
245        buf += got;
246        len -= got;
247        msg->len += got;
248    }
249    if (!len)
250        return;
251    peer->pos = peer->buf;
252    peer->end = peer->buf+get_chunk(peer, peer->buf, BUF_SIZE);
253    fakefile_msg_get(msg, buf, len);
254}
fakefile/comm.h
1/*
2 * comm.h - Fakefile IPC functions
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#ifndef COMM_H
13#define COMM_H
14
15#include <sys/types.h>
16
17
18#define FAKEFILE_MASTER_OUT_VAR "FAKEFILE_MASTER_OUT"
19#define FAKEFILE_MASTER_IN_VAR "FAKEFILE_MASTER_IN"
20
21
22struct fakefile_peer;
23struct fakefile_msg;
24
25struct fakefile_peer *fakefile_peer(int in, int out);
26void fakefile_peer_close(struct fakefile_peer *peer);
27int fakefile_peer_fd(const struct fakefile_peer *peer);
28
29struct fakefile_msg *fakefile_msg_new(struct fakefile_peer *peer,
30    int size);
31struct fakefile_msg *fakefile_msg_recv(struct fakefile_peer *peer);
32void fakefile_msg_end(struct fakefile_msg *msg);
33
34void fakefile_msg_add(struct fakefile_msg *msg, const void *buf, size_t len);
35void fakefile_msg_get(struct fakefile_msg *msg, void *buf, size_t len);
36
37
38#define decl_add(type) \
39    static inline void fakefile_msg_add_##type( \
40        struct fakefile_msg *msg, type value) \
41    { \
42        fakefile_msg_add(msg, &value, sizeof(value)); \
43    }
44
45#define decl_get(type) \
46    static inline type fakefile_msg_get_##type( \
47        struct fakefile_msg *msg) \
48    { \
49        type value; \
50                                \
51        fakefile_msg_get(msg, &value, sizeof(value)); \
52        return value; \
53    }
54
55#define decl_access(type) decl_add(type) decl_get(type)
56
57decl_access(int)
58decl_access(size_t)
59decl_access(ssize_t)
60
61#undef decl_add
62#undef decl_get
63#undef decl_access
64
65#endif /* !COMM_H */
fakefile/demo.c
1/*
2 * demo.c - Fakefile demo
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 <string.h>
16
17#include "fakefile.h"
18
19
20static void usage(const char *name)
21{
22    fprintf(stderr,
23        "usage: %s command [arg ...]\n"
24        " %s -e path errno command\n"
25        " %s -f path content command\n",
26        name, name, name);
27    exit(1);
28}
29
30
31int main(int argc, char **argv)
32{
33    struct fakefile *ff;
34    struct fakefile_event *ev;
35    int error = 0;
36    const char *path = NULL, *fake = NULL;
37    char *end;
38
39    if (argc == 1)
40        usage(*argv);
41    if (*argv[1] == '-') {
42        if (argc < 5)
43            usage(*argv);
44        path = argv[2];
45        switch (argv[1][1]) {
46        case 'e':
47            error = strtoul(argv[3], &end, 0);
48            if (*end)
49                usage(*argv);
50            break;
51        case 'f':
52            fake = argv[3];
53            break;
54        default:
55            usage(*argv);
56        }
57        argv += 3;
58    }
59    ff = fakefile_execv(argv[1], argv+1);
60    while (1) {
61        ev = fakefile_poll();
62        switch (ev->type) {
63        case ff_et_open:
64            fprintf(stderr, "\"%s\"\n", ev->u.open.name);
65            if (path && !strcmp(ev->u.open.name, path)) {
66                if (!fake)
67                    ev->u.open.res = -error;
68            } else {
69                ev->u.open.res = 0;
70            }
71            break;
72        case ff_et_read: {
73            size_t len, left;
74
75            len = ev->u.read.len;
76            left = strlen(fake);
77            if (len > left)
78                len = left;
79            ev->u.read.buf = (void *) fake;
80            ev->u.read.len = len;
81            fake += len;
82            break;
83        }
84        case ff_et_exit:
85            goto out;
86        default:
87            break;
88        }
89        fakefile_respond(ev);
90    }
91out:
92    fakefile_end(ff);
93    return 0;
94}
fakefile/fakefile.c
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}
fakefile/fakefile.h
1/*
2 * fakefile.h - 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#ifndef FAKEFILE_H
13#define FAKEFILE_H
14
15#include <sys/types.h>
16#include <sys/stat.h>
17
18
19enum fakefile_event_type {
20    ff_et_exit,
21    ff_et_open,
22    ff_et_read,
23    ff_et_write,
24    ff_et_close,
25    ff_et_unlink,
26    ff_et_rename,
27    ff_et_fstat,
28};
29
30struct fakefile_event {
31    enum fakefile_event_type type;
32    union {
33        struct fakefile_exit {
34            /* in */
35            int status;
36        } exit;
37        struct fakefile_open {
38            /* in */
39            char *name;
40            int flags;
41            int mode;
42            /* out */
43            void *handle;
44            int res; /* < 0: -errno; 0: regular open (in slave) */
45        } open;
46        struct fakefile_read {
47            /* in */
48            const void *handle;
49            /* in/out */
50            void *buf;
51            ssize_t len;
52        } read;
53        struct fakefile_write {
54            /* in */
55            const void *handle;
56            void *buf;
57            /* in/out */
58            ssize_t len;
59        } write;
60        struct fakefile_close {
61            /* in */
62            const void *handle;
63            /* out */
64            int res;
65        } close;
66        struct fakefile_unlink {
67        } unlink;
68        struct fakefile_rename {
69        } rename;
70        struct fakefile_fstat {
71            /* in */
72            const void *handle;
73            /* out */
74            struct stat st;
75            int res;
76        } fstat;
77    } u;
78    void *user;
79};
80
81
82struct fakefile *fakefile_execv(const char *path, char *const argv[]);
83struct fakefile_event *fakefile_poll(void);
84void fakefile_respond(struct fakefile_event *event);
85void fakefile_end(struct fakefile *ff);
86
87void fakefile_file(struct fakefile *ff, const char *name,
88    const void *in, size_t len, void **out);
89void fakefile_antifile(struct fakefile *ff, const char *name);
90
91#endif /* !FAKEFILE_H */
fakefile/file.c
1/*
2 * file.c - Whole file operations
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 "fakefile.h"
14#include "internal.h"
15
16
17int fakefile_internal_event(struct event *ev)
18{
19    (void) ev;
20    return 0;
21}
22
23
24static void add_file(struct fakefile *ff, const char *name,
25    const void *in, size_t len, void **out)
26{
27    /* ... */
28}
29
30
31void fakefile_file(struct fakefile *ff, const char *name,
32    const void *in, size_t len, void **out)
33{
34    add_file(ff, name, in, len, out);
35}
36
37
38void fakefile_antifile(struct fakefile *ff, const char *name)
39{
40    add_file(ff, name, NULL, 0, NULL);
41}
fakefile/internal.h
1/*
2 * internal.h - Internal functions and data structures at master
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#ifndef INTERNAL_H
13#define INTERNAL_H
14
15#include <unistd.h>
16
17#include "comm.h"
18
19
20struct fd_map {
21    int fd;
22    void *handle;
23    struct fd_map *next;
24};
25
26struct fakefile {
27    pid_t pid;
28    struct fakefile_peer *peer;
29    struct fd_map *map;
30    struct fakefile *next;
31};
32
33
34struct event;
35
36
37struct fakefile *fakefile_launch(const char *path, char *const argv[]);
38int fakefile_internal_event(struct event *ev);
39
40#endif /* !INTERNAL_H */
fakefile/launch.c
1/*
2 * launch.c - Fakefile process launcher
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 <stdarg.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <fcntl.h>
18#include <dirent.h>
19#include <sys/types.h>
20
21#include "util.h"
22#include "fakefile.h"
23#include "comm.h"
24#include "internal.h"
25
26
27#define FD_DIR "/proc/self/fd"
28
29
30static void safe_setenvf(const char *var, const char *fmt, ...)
31{
32    va_list ap;
33    char *buf;
34    ssize_t len;
35
36    va_start(ap, fmt);
37    len = vsnprintf(NULL, 0, fmt, ap);
38    va_end(ap);
39    if (len < 0) {
40        perror("vsprintf");
41        exit(1);
42    }
43
44    buf = alloc_size(len+1);
45
46    va_start(ap, fmt);
47    vsprintf(buf, fmt, ap);
48    va_end(ap);
49
50    if (setenv(var, buf, 1) < 0) {
51        perror("setenv");
52        exit(1);
53    }
54
55    free(buf);
56}
57
58
59static void env_append(const char *var, const char *s)
60{
61    const char *old;
62    char *tmp;
63    size_t len1, len2;
64
65    old = getenv(var);
66    if (!old) {
67        safe_setenvf(var, "%s", s+1);
68        return;
69    }
70    len1 = strlen(old);
71    len2 = strlen(s);
72    tmp = alloc_size(len1+len2+1);
73    memcpy(tmp, old, len1);
74    memcpy(tmp+len1, s, len2+1);
75    safe_setenvf(var, "%s", tmp);
76    free(tmp);
77}
78
79
80static void closefds(int preserve, ...)
81{
82    va_list ap;
83    DIR *dir;
84    int fd;
85    struct dirent *de;
86    int n;
87
88    fd = open(FD_DIR, O_RDONLY);
89    if (fd < 0) {
90        perror(FD_DIR);
91        exit(1);
92    }
93    dir = fdopendir(fd);
94    if (!dir) {
95        perror("fdopendir");
96        exit(1);
97    }
98    while (1) {
99next:
100        de = readdir(dir);
101        if (!de)
102            break;
103        n = atoi(de->d_name);
104        if (n <= 2 || n == fd)
105            continue;
106        if (preserve > 0) {
107            if (n == preserve)
108                continue;
109            va_start(ap, preserve);
110            while (1) {
111                n = va_arg(ap, int);
112                if (n < 0)
113                    break;
114                if (n == n)
115                    goto next;
116            }
117            va_end(ap);
118        }
119        (void) close(n);
120    }
121    if (closedir(dir) < 0) {
122        perror("closedir");
123        exit(1);
124    }
125}
126
127
128struct fakefile *fakefile_launch(const char *path, char *const argv[])
129{
130    struct fakefile *ff;
131    int m2s[2], s2m[2];
132    pid_t pid;
133
134    if (pipe(m2s) < 0 || pipe(s2m) < 0) {
135        perror("pipe");
136        exit(1);
137    }
138    pid = fork();
139    if (pid < 0) {
140        perror("fork");
141        exit(1);
142    }
143    if (!pid) {
144        env_append("LD_LIBRARY_PATH", ":.");
145        env_append("LD_PRELOAD", " libfakefile_slave.so");
146        safe_setenvf(FAKEFILE_MASTER_OUT_VAR, "%d", m2s[0]);
147        safe_setenvf(FAKEFILE_MASTER_IN_VAR, "%d", s2m[1]);
148        closefds(m2s[0], s2m[1], -1);
149        execv(path, argv);
150        perror(path);
151        _exit(1);
152    }
153
154    (void) close(m2s[0]);
155    (void) close(s2m[1]);
156
157    ff = alloc_type(struct fakefile);
158    ff->pid = pid;
159    ff->peer = fakefile_peer(s2m[0], m2s[1]);
160
161    return ff;
162}
fakefile/slave.c
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}
fakefile/util.h
1/*
2 * util.h - Utility functions
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#ifndef UTIL_H
13#define UTIL_H
14
15#include <stdlib.h>
16
17
18#define alloc_size(s) \
19    ({ void *alloc_size_tmp = malloc(s); \
20    if (!alloc_size_tmp) \
21        abort(); \
22    alloc_size_tmp; })
23
24#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
25
26#endif /* !UTIL_H */

Archive Download the corresponding diff file

Branches:
master



interactive