1
0
mirror of git://projects.qi-hardware.com/wernermisc.git synced 2024-12-22 15:13:54 +02:00

fakefile/: so far unsuccessful attempt at jailing Kicad

This commit is contained in:
Werner Almesberger 2012-03-29 18:42:01 -03:00
parent ddc5e0e935
commit 15067435ae
12 changed files with 1438 additions and 0 deletions

55
fakefile/Makefile Normal file
View File

@ -0,0 +1,55 @@
#
# Makefile - Build the Fakefile libraries
#
# Copyright 2012 by Werner Almesberger
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
CFLAGS = -Wall -g -Wextra -Wno-unused-parameter -fPIC
LDFLAGS = -L. -Wl,-rpath=$(shell pwd)
LDLIBS = -lfakefile
LIBFAKEFILE_OBJS = comm.o fakefile.o file.o launch.o
LIBFFSLAVE_OBJS = comm.o slave.o
TARGETS = libfakefile.so libfakefile_slave.so demo
CC_normal := $(CC)
LD_normal := $(LD)
DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
CC_quiet = @echo " CC " $@ && $(CC_normal)
LD_quiet = @echo " LD " $@ && $(LD_normal)
GEN_quiet = @echo " GENERATE " $@ &&
DEPEND_quiet = @$(DEPEND_normal)
ifeq ($(V),1)
CC = $(CC_normal)
LD = $(LD_normal)
GEN =
DEPEND = $(DEPEND_normal)
else
CC = $(CC_quiet)
LD = $(LD_quiet)
GEN = $(GEN_quiet)
DEPEND = $(DEPEND_quiet)
endif
.PHONY: all clean spotless
all: $(TARGETS)
libfakefile.so: $(LIBFAKEFILE_OBJS)
$(LD) -shared -o $@ $^
libfakefile_slave.so: $(LIBFFSLAVE_OBJS)
$(LD) -shared -o $@ $^ -ldl
clean:
rm -f $(LIBFAKEFILE_OBJS) $(LIBFFSLAVE_OBJS)
spotless: clean
rm -f $(TARGETS)

3
fakefile/README Normal file
View File

@ -0,0 +1,3 @@
Don't use this yet ! This was intended as a means to run Kicad in a
"jail", but that didn't pan out. Probably have to convert it to use
ptrace.

254
fakefile/comm.c Normal file
View File

@ -0,0 +1,254 @@
/*
* comm.c - Fakefile IPC functions
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include "util.h"
#include "comm.h"
#define BUF_SIZE 4096
struct fakefile_peer {
int in, out;
uint8_t buf[BUF_SIZE];
void *pos;
const void *end;
};
struct fakefile_msg {
struct fakefile_peer *peer;
void *buf; /* NULL if reading */
void *pos; /* current position in buffer; write only */
size_t len; /* amount of data read/written so far */
size_t msg_size; /* declared size */
size_t buf_size; /* allocated size; write only */
};
static int master_fd(const char *name)
{
const char *s;
char *end;
long n;
s = getenv(name);
if (!s) {
fprintf(stderr, "%s not set\n", name);
exit(1);
}
n = strtol(s, &end, 0);
if (*end || n < 0) {
fprintf(stderr, "invalid fd \"%s\" for %s\n", s, name);
exit(1);
}
return n;
}
static struct fakefile_peer *sanitize_peer(struct fakefile_peer *peer)
{
static int have_peer = 0;
static struct fakefile_peer master;
if (peer)
return peer;
if (!have_peer) {
master.in = master_fd(FAKEFILE_MASTER_OUT_VAR);
master.out = master_fd(FAKEFILE_MASTER_IN_VAR);
master.pos = master.buf;
master.end = master.buf;
have_peer = 1;
}
return &master;
}
struct fakefile_peer *fakefile_peer(int in, int out)
{
struct fakefile_peer *peer;
peer = alloc_type(struct fakefile_peer);
peer->in = in;
peer->out = out;
peer->pos = peer->buf;
peer->end = peer->buf;
return peer;
}
void fakefile_peer_close(struct fakefile_peer *peer)
{
(void) close(peer->in);
(void) close(peer->out);
free(peer);
}
int fakefile_peer_fd(const struct fakefile_peer *peer)
{
return peer->in;
}
struct fakefile_msg *fakefile_msg_new(struct fakefile_peer *peer, int size)
{
struct fakefile_msg *msg;
size_t buf_size;
size += sizeof(int);
buf_size = size > BUF_SIZE ? BUF_SIZE : size;
msg = alloc_size(sizeof(struct fakefile_msg)+buf_size);
msg->peer = sanitize_peer(peer);
msg->buf = msg->pos = msg+1;
msg->len = 0;
msg->msg_size = size;
msg->buf_size = buf_size;
fakefile_msg_add_int(msg, size);
return msg;
}
static void flush_out(struct fakefile_msg *msg)
{
const void *p;
ssize_t len;
if (msg->pos == msg->buf)
return;
for (p = msg->buf; p != msg->pos; p += len) {
len = write(msg->peer->out, p, msg->pos-p);
if (len <= 0) {
perror("fakefile IPC write");
exit(1);
}
}
}
struct fakefile_msg *fakefile_msg_recv(struct fakefile_peer *peer)
{
struct fakefile_msg *msg;
msg = alloc_type(struct fakefile_msg);
msg->peer = sanitize_peer(peer);
msg->buf = NULL;
msg->len = 0;
msg->msg_size = sizeof(int);
msg->msg_size = fakefile_msg_get_int(msg);
return msg;
}
void fakefile_msg_end(struct fakefile_msg *msg)
{
#if 0
fprintf(stderr, "end: len %d size %d (%p)\n",
(int) msg->len, (int) msg->msg_size, msg->buf);
#endif
assert(msg->len == msg->msg_size);
if (msg->buf)
flush_out(msg);
free(msg);
}
static void add_chunk(struct fakefile_msg *msg, const void *buf, size_t len)
{
memcpy(msg->pos, buf, len);
msg->pos += len;
if (msg->pos == msg->buf+msg->buf_size) {
flush_out(msg);
msg->pos = msg->buf;
}
}
void fakefile_msg_add(struct fakefile_msg *msg, const void *buf, size_t len)
{
size_t chunk;
#if 0
fprintf(stderr, "add: %d+%d/%d (%p)\n",
(int) msg->len, (int) len, (int) msg->msg_size, msg->buf);
#endif
assert(msg->len+len <= msg->msg_size);
while (len && msg->pos+len > msg->buf+msg->buf_size) {
chunk = msg->buf+msg->buf_size-msg->pos;
if (chunk > len)
chunk = len;
add_chunk(msg, buf, chunk);
buf += chunk;
len -= chunk;
msg->len += chunk;
}
if (len) {
add_chunk(msg, buf, len);
msg->len += len;
}
}
static size_t get_chunk(struct fakefile_peer *peer, void *buf, size_t len)
{
ssize_t got;
got = read(peer->in, buf, len);
if (got < 0) {
perror("fakefile IPC read");
exit(1);
}
if (!got) {
fprintf(stderr, "fakefile EOF\n");
exit(1);
}
return got;
}
void fakefile_msg_get(struct fakefile_msg *msg, void *buf, size_t len)
{
struct fakefile_peer *peer = msg->peer;
size_t chunk, got;
assert(msg->len+len <= msg->msg_size);
if (!len)
return;
if (peer->pos != peer->end) {
chunk = peer->end-peer->pos;
if (chunk > len)
chunk = len;
memcpy(buf, peer->pos, chunk);
peer->pos += chunk;
buf += chunk;
len -= chunk;
msg->len += chunk;
}
while (len >= BUF_SIZE) {
got = get_chunk(peer, buf, BUF_SIZE);
buf += got;
len -= got;
msg->len += got;
}
if (!len)
return;
peer->pos = peer->buf;
peer->end = peer->buf+get_chunk(peer, peer->buf, BUF_SIZE);
fakefile_msg_get(msg, buf, len);
}

65
fakefile/comm.h Normal file
View File

@ -0,0 +1,65 @@
/*
* comm.h - Fakefile IPC functions
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef COMM_H
#define COMM_H
#include <sys/types.h>
#define FAKEFILE_MASTER_OUT_VAR "FAKEFILE_MASTER_OUT"
#define FAKEFILE_MASTER_IN_VAR "FAKEFILE_MASTER_IN"
struct fakefile_peer;
struct fakefile_msg;
struct fakefile_peer *fakefile_peer(int in, int out);
void fakefile_peer_close(struct fakefile_peer *peer);
int fakefile_peer_fd(const struct fakefile_peer *peer);
struct fakefile_msg *fakefile_msg_new(struct fakefile_peer *peer,
int size);
struct fakefile_msg *fakefile_msg_recv(struct fakefile_peer *peer);
void fakefile_msg_end(struct fakefile_msg *msg);
void fakefile_msg_add(struct fakefile_msg *msg, const void *buf, size_t len);
void fakefile_msg_get(struct fakefile_msg *msg, void *buf, size_t len);
#define decl_add(type) \
static inline void fakefile_msg_add_##type( \
struct fakefile_msg *msg, type value) \
{ \
fakefile_msg_add(msg, &value, sizeof(value)); \
}
#define decl_get(type) \
static inline type fakefile_msg_get_##type( \
struct fakefile_msg *msg) \
{ \
type value; \
\
fakefile_msg_get(msg, &value, sizeof(value)); \
return value; \
}
#define decl_access(type) decl_add(type) decl_get(type)
decl_access(int)
decl_access(size_t)
decl_access(ssize_t)
#undef decl_add
#undef decl_get
#undef decl_access
#endif /* !COMM_H */

94
fakefile/demo.c Normal file
View File

@ -0,0 +1,94 @@
/*
* demo.c - Fakefile demo
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fakefile.h"
static void usage(const char *name)
{
fprintf(stderr,
"usage: %s command [arg ...]\n"
" %s -e path errno command\n"
" %s -f path content command\n",
name, name, name);
exit(1);
}
int main(int argc, char **argv)
{
struct fakefile *ff;
struct fakefile_event *ev;
int error = 0;
const char *path = NULL, *fake = NULL;
char *end;
if (argc == 1)
usage(*argv);
if (*argv[1] == '-') {
if (argc < 5)
usage(*argv);
path = argv[2];
switch (argv[1][1]) {
case 'e':
error = strtoul(argv[3], &end, 0);
if (*end)
usage(*argv);
break;
case 'f':
fake = argv[3];
break;
default:
usage(*argv);
}
argv += 3;
}
ff = fakefile_execv(argv[1], argv+1);
while (1) {
ev = fakefile_poll();
switch (ev->type) {
case ff_et_open:
fprintf(stderr, "\"%s\"\n", ev->u.open.name);
if (path && !strcmp(ev->u.open.name, path)) {
if (!fake)
ev->u.open.res = -error;
} else {
ev->u.open.res = 0;
}
break;
case ff_et_read: {
size_t len, left;
len = ev->u.read.len;
left = strlen(fake);
if (len > left)
len = left;
ev->u.read.buf = (void *) fake;
ev->u.read.len = len;
fake += len;
break;
}
case ff_et_exit:
goto out;
default:
break;
}
fakefile_respond(ev);
}
out:
fakefile_end(ff);
return 0;
}

302
fakefile/fakefile.c Normal file
View File

@ -0,0 +1,302 @@
/*
* fakefile.c - Programmed file system illusion
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <poll.h>
#include <assert.h>
#include <sys/wait.h>
#include "util.h"
#include "internal.h"
#include "fakefile.h"
struct event {
struct fakefile_event ev;
struct fakefile *ff;
void *tmp;
void (*respond)(struct event *ev);
};
static struct fakefile *fakefiles = NULL;
static struct pollfd *fds = NULL;
static int nfds = 0;
static void map_slave_fd(struct fakefile *ff, int fd, void *handle)
{
struct fd_map *map;
map = alloc_type(struct fd_map);
map->fd = fd;
map->handle = handle;
map->next = ff->map;
ff->map = map;
}
static void *lookup_slave_fd(struct fakefile *ff, int fd)
{
const struct fd_map *map;
for (map = ff->map; map; map = map->next)
if (map->fd == fd)
return map->handle;
abort();
}
static void unmap_slave_fd(struct fakefile *ff, int fd)
{
struct fd_map **map, *next;
for (map = &ff->map; (*map)->fd != fd; map = &(*map)->next);
next = (*map)->next;
free(*map);
*map = next;
}
struct fakefile *fakefile_execv(const char *path, char *const argv[])
{
struct fakefile *ff;
ff = fakefile_launch(path, argv);
ff->map = NULL;
ff->next = fakefiles;
fakefiles = ff;
fds = realloc(fds, sizeof(struct pollfd)*(nfds+1));
if (!fds) {
perror("realloc");
exit(1);
}
fds[nfds].fd = fakefile_peer_fd(ff->peer);
fds[nfds].events = POLLIN | POLLHUP;
nfds++;
return ff;
}
static void respond_open(struct event *ev)
{
const struct fakefile_open *prm = &ev->ev.u.open;
struct fakefile *ff = ev->ff;
struct fakefile_msg *msg;
msg = fakefile_msg_new(ff->peer, sizeof(int));
if (prm->res > 0)
map_slave_fd(ff, prm->res, prm->handle);
fakefile_msg_add_int(msg, prm->res);
fakefile_msg_end(msg);
free(prm->name);
}
static void respond_read(struct event *ev)
{
const struct fakefile_read *prm = &ev->ev.u.read;
struct fakefile *ff = ev->ff;
struct fakefile_msg *msg;
ssize_t size;
size = prm->len < 0 ? 0 : prm->len;
msg = fakefile_msg_new(ff->peer, sizeof(ssize_t)+size);
fakefile_msg_add_ssize_t(msg, prm->len);
if (size)
fakefile_msg_add(msg, prm->buf, size);
fakefile_msg_end(msg);
free(ev->tmp);
}
static void respond_fstat(struct event *ev)
{
const struct fakefile_fstat *prm = &ev->ev.u.fstat;
struct fakefile *ff = ev->ff;
struct fakefile_msg *msg;
ssize_t size;
size = prm->res < 0 ? 0 : sizeof(struct stat);
msg = fakefile_msg_new(ff->peer, sizeof(int)+size);
fakefile_msg_add_int(msg, prm->res);
if (size)
fakefile_msg_add(msg, &prm->st, sizeof(struct stat));
fakefile_msg_end(msg);
}
static void respond_exit(struct event *ev)
{
}
static void respond_close(struct event *ev)
{
const struct fakefile_close *prm = &ev->ev.u.close;
struct fakefile *ff = ev->ff;
struct fakefile_msg *msg;
msg = fakefile_msg_new(ff->peer, sizeof(int));
fakefile_msg_add_int(msg, prm->res);
fakefile_msg_end(msg);
}
static struct fakefile_event *get_event(int fd)
{
struct fakefile *ff;
struct event *ev;
struct fakefile_msg *msg;
for (ff = fakefiles; ff; ff = ff->next)
if (fakefile_peer_fd(ff->peer) == fd)
break;
assert(ff);
ev = alloc_type(struct event);
ev->ff = ff;
msg = fakefile_msg_recv(ff->peer);
ev->ev.type = fakefile_msg_get_int(msg);
switch (ev->ev.type) {
case ff_et_exit: {
struct fakefile_exit *prm = &ev->ev.u.exit;
ev->respond = respond_exit;
prm->status = fakefile_msg_get_int(msg);
break;
}
case ff_et_open: {
struct fakefile_open *prm = &ev->ev.u.open;
int len;
ev->respond = respond_open;
prm->flags = fakefile_msg_get_int(msg);
prm->mode = fakefile_msg_get_int(msg);
prm->res = fakefile_msg_get_int(msg);
len = fakefile_msg_get_int(msg);
prm->name = alloc_size(len+1);
fakefile_msg_get(msg, prm->name, len);
prm->name[len] = 0;
prm->handle = NULL;
break;
}
case ff_et_read: {
struct fakefile_read *prm = &ev->ev.u.read;
int fd;
ev->respond = respond_read;
fd = fakefile_msg_get_int(msg);
prm->handle = lookup_slave_fd(ff, fd);
prm->len = fakefile_msg_get_size_t(msg);
prm->buf = ev->tmp = alloc_size(prm->len);
break;
}
case ff_et_write: {
abort();
}
case ff_et_close: {
struct fakefile_close *prm = &ev->ev.u.close;
int fd;
ev->respond = respond_close;
fd = fakefile_msg_get_int(msg);
prm->handle = lookup_slave_fd(ff, fd);
prm->res = 0;
break;
}
case ff_et_unlink:
abort();
case ff_et_rename:
abort();
case ff_et_fstat: {
struct fakefile_fstat *prm = &ev->ev.u.fstat;
int fd;
ev->respond = respond_fstat;
fd = fakefile_msg_get_int(msg);
prm->handle = lookup_slave_fd(ff, fd);
prm->res = fstat(fd, &prm->st);
break;
}
default:
abort();
}
fakefile_msg_end(msg);
if (fakefile_internal_event(ev))
return NULL;
return &ev->ev;
}
static struct fakefile_event *handle_exit(int fd)
{
struct fakefile *ff;
struct fakefile_event *event;
for (ff = fakefiles; ff; ff = ff->next)
if (fakefile_peer_fd(ff->peer) == fd)
break;
assert(ff);
event = alloc_type(struct fakefile_event);
event->type = ff_et_exit;
if (waitpid(ff->pid, &event->u.exit.status, 0) < 0) {
perror("waitpid");
exit(1);
}
//@@@ destroy
return event;
}
struct fakefile_event *fakefile_poll(void)
{
struct fakefile_event *event;
struct pollfd *p;
int n;
while (1) {
n = poll(fds, nfds, -1);
if (n < 0) {
perror("poll");
exit(1);
}
if (!n) {
fprintf(stderr, "poll() returned 0\n");
exit(1);
}
for (p = fds; n && p != fds+nfds; p++) {
if (p->revents & POLLIN) {
event = get_event(p->fd);
if (event)
return event;
}
if (p->revents & POLLHUP)
return handle_exit(p->fd);
}
}
}
void fakefile_respond(struct fakefile_event *event)
{
struct event *ev = (struct event *) event;
ev->respond(ev);
free(ev);
}
void fakefile_end(struct fakefile *ff)
{
}

91
fakefile/fakefile.h Normal file
View File

@ -0,0 +1,91 @@
/*
* fakefile.h - Programmed file system illusion
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef FAKEFILE_H
#define FAKEFILE_H
#include <sys/types.h>
#include <sys/stat.h>
enum fakefile_event_type {
ff_et_exit,
ff_et_open,
ff_et_read,
ff_et_write,
ff_et_close,
ff_et_unlink,
ff_et_rename,
ff_et_fstat,
};
struct fakefile_event {
enum fakefile_event_type type;
union {
struct fakefile_exit {
/* in */
int status;
} exit;
struct fakefile_open {
/* in */
char *name;
int flags;
int mode;
/* out */
void *handle;
int res; /* < 0: -errno; 0: regular open (in slave) */
} open;
struct fakefile_read {
/* in */
const void *handle;
/* in/out */
void *buf;
ssize_t len;
} read;
struct fakefile_write {
/* in */
const void *handle;
void *buf;
/* in/out */
ssize_t len;
} write;
struct fakefile_close {
/* in */
const void *handle;
/* out */
int res;
} close;
struct fakefile_unlink {
} unlink;
struct fakefile_rename {
} rename;
struct fakefile_fstat {
/* in */
const void *handle;
/* out */
struct stat st;
int res;
} fstat;
} u;
void *user;
};
struct fakefile *fakefile_execv(const char *path, char *const argv[]);
struct fakefile_event *fakefile_poll(void);
void fakefile_respond(struct fakefile_event *event);
void fakefile_end(struct fakefile *ff);
void fakefile_file(struct fakefile *ff, const char *name,
const void *in, size_t len, void **out);
void fakefile_antifile(struct fakefile *ff, const char *name);
#endif /* !FAKEFILE_H */

41
fakefile/file.c Normal file
View File

@ -0,0 +1,41 @@
/*
* file.c - Whole file operations
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "fakefile.h"
#include "internal.h"
int fakefile_internal_event(struct event *ev)
{
(void) ev;
return 0;
}
static void add_file(struct fakefile *ff, const char *name,
const void *in, size_t len, void **out)
{
/* ... */
}
void fakefile_file(struct fakefile *ff, const char *name,
const void *in, size_t len, void **out)
{
add_file(ff, name, in, len, out);
}
void fakefile_antifile(struct fakefile *ff, const char *name)
{
add_file(ff, name, NULL, 0, NULL);
}

40
fakefile/internal.h Normal file
View File

@ -0,0 +1,40 @@
/*
* internal.h - Internal functions and data structures at master
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef INTERNAL_H
#define INTERNAL_H
#include <unistd.h>
#include "comm.h"
struct fd_map {
int fd;
void *handle;
struct fd_map *next;
};
struct fakefile {
pid_t pid;
struct fakefile_peer *peer;
struct fd_map *map;
struct fakefile *next;
};
struct event;
struct fakefile *fakefile_launch(const char *path, char *const argv[]);
int fakefile_internal_event(struct event *ev);
#endif /* !INTERNAL_H */

162
fakefile/launch.c Normal file
View File

@ -0,0 +1,162 @@
/*
* launch.c - Fakefile process launcher
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include "util.h"
#include "fakefile.h"
#include "comm.h"
#include "internal.h"
#define FD_DIR "/proc/self/fd"
static void safe_setenvf(const char *var, const char *fmt, ...)
{
va_list ap;
char *buf;
ssize_t len;
va_start(ap, fmt);
len = vsnprintf(NULL, 0, fmt, ap);
va_end(ap);
if (len < 0) {
perror("vsprintf");
exit(1);
}
buf = alloc_size(len+1);
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
if (setenv(var, buf, 1) < 0) {
perror("setenv");
exit(1);
}
free(buf);
}
static void env_append(const char *var, const char *s)
{
const char *old;
char *tmp;
size_t len1, len2;
old = getenv(var);
if (!old) {
safe_setenvf(var, "%s", s+1);
return;
}
len1 = strlen(old);
len2 = strlen(s);
tmp = alloc_size(len1+len2+1);
memcpy(tmp, old, len1);
memcpy(tmp+len1, s, len2+1);
safe_setenvf(var, "%s", tmp);
free(tmp);
}
static void closefds(int preserve, ...)
{
va_list ap;
DIR *dir;
int fd;
struct dirent *de;
int n;
fd = open(FD_DIR, O_RDONLY);
if (fd < 0) {
perror(FD_DIR);
exit(1);
}
dir = fdopendir(fd);
if (!dir) {
perror("fdopendir");
exit(1);
}
while (1) {
next:
de = readdir(dir);
if (!de)
break;
n = atoi(de->d_name);
if (n <= 2 || n == fd)
continue;
if (preserve > 0) {
if (n == preserve)
continue;
va_start(ap, preserve);
while (1) {
n = va_arg(ap, int);
if (n < 0)
break;
if (n == n)
goto next;
}
va_end(ap);
}
(void) close(n);
}
if (closedir(dir) < 0) {
perror("closedir");
exit(1);
}
}
struct fakefile *fakefile_launch(const char *path, char *const argv[])
{
struct fakefile *ff;
int m2s[2], s2m[2];
pid_t pid;
if (pipe(m2s) < 0 || pipe(s2m) < 0) {
perror("pipe");
exit(1);
}
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (!pid) {
env_append("LD_LIBRARY_PATH", ":.");
env_append("LD_PRELOAD", " libfakefile_slave.so");
safe_setenvf(FAKEFILE_MASTER_OUT_VAR, "%d", m2s[0]);
safe_setenvf(FAKEFILE_MASTER_IN_VAR, "%d", s2m[1]);
closefds(m2s[0], s2m[1], -1);
execv(path, argv);
perror(path);
_exit(1);
}
(void) close(m2s[0]);
(void) close(s2m[1]);
ff = alloc_type(struct fakefile);
ff->pid = pid;
ff->peer = fakefile_peer(s2m[0], m2s[1]);
return ff;
}

305
fakefile/slave.c Normal file
View File

@ -0,0 +1,305 @@
/*
* slave.c - Fakefile slave library
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#define __USE_GNU /* for RTLD_NEXT */
#include <dlfcn.h>
#include "util.h"
#include "fakefile.h"
#include "comm.h"
#define DUMMY_FILE "/dev/null"
#define master NULL
static struct fd_entry {
int fd;
struct fd_entry *next;
} *fake_fds = NULL;
static int (*libc_close)(int fd);
static int (*libc_dup)(int oldfd);
static int (*libc_dup2)(int oldfd, int newfd);
static int (*libc_open)(const char *pathname, int flags, mode_t mode);
static ssize_t (*libc_read)(int fd, void *buf, size_t count);
static FILE *(*libc_fopen)(const char *path, const char *mode);
static void init_self(void)
{
static int initialized = 0;
if (initialized)
return;
libc_close = dlsym(RTLD_NEXT, "close");
libc_dup = dlsym(RTLD_NEXT, "dup");
libc_dup2 = dlsym(RTLD_NEXT, "dup2");
libc_open = dlsym(RTLD_NEXT, "open");
libc_read = dlsym(RTLD_NEXT, "read");
libc_fopen = dlsym(RTLD_NEXT, "fopen");
if (!libc_close || !libc_dup || !libc_dup2 || !libc_open ||
!libc_read) {
perror("dlsym");
_exit(1);
}
initialized = 1;
}
static int get_fd(void)
{
int fd;
fd = libc_open(DUMMY_FILE, O_RDONLY, 0);
if (fd < 0) {
perror(DUMMY_FILE);
exit(1);
}
assert(fd);
return fd;
}
static void add_fake_fd(int fd)
{
struct fd_entry *e;
e = alloc_type(struct fd_entry);
e->fd = fd;
e->next = fake_fds;
fake_fds =e;
}
static int is_fake_fd(int fd)
{
const struct fd_entry *e;
for (e = fake_fds; e && e->fd != fd; e = e->next);
return !!e;
}
static int del_fake_fd(int fd)
{
struct fd_entry **e, *next;
for (e = &fake_fds; *e; e = &(*e)->next)
if ((*e)->fd == fd)
break;
if (!*e)
return 0;
next = (*e)->next;
free(*e);
*e = next;
(void) libc_close(fd);
return 1;
}
int open(const char *pathname, int flags, ...)
{
va_list ap;
struct fakefile_msg *msg;
size_t len;
int mode = 0;
int fd, res;
init_self();
if (flags & O_CREAT) {
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
}
fd = get_fd();
len = strlen(pathname);
msg = fakefile_msg_new(master, len+5*sizeof(int));
fakefile_msg_add_int(msg, ff_et_open);
fakefile_msg_add_int(msg, flags);
fakefile_msg_add_int(msg, mode);
fakefile_msg_add_int(msg, fd);
fakefile_msg_add_int(msg, len);
fakefile_msg_add(msg, pathname, len);
fakefile_msg_end(msg);
msg = fakefile_msg_recv(master);
res = fakefile_msg_get_int(msg);
fakefile_msg_end(msg);
//fprintf(stderr, "res %d\n", (int) res);
if (res <= 0) {
(void) close(fd);
if (res < 0) {
errno = -res;
return -1;
}
}
if (res)
add_fake_fd(fd);
else
res = libc_open(pathname, flags, mode);
return res;
}
ssize_t read(int fd, void *buf, size_t count)
{
struct fakefile_msg *msg;
ssize_t res;
init_self();
if (!is_fake_fd(fd))
return libc_read(fd, buf, count);
msg = fakefile_msg_new(master, 2*sizeof(int)+sizeof(size_t));
fakefile_msg_add_int(msg, ff_et_read);
fakefile_msg_add_int(msg, fd);
fakefile_msg_add_size_t(msg, count);
fakefile_msg_end(msg);
msg = fakefile_msg_recv(master);
res = fakefile_msg_get_size_t(msg);
if (res > 0) {
assert((size_t) res <= count);
fakefile_msg_get(msg, buf, res);
} else if (res < 0) {
errno = -res;
res = -1;
}
fakefile_msg_end(msg);
//fprintf(stderr, "READ %d\n", (int) res);
return res;
}
int fstat(int fd, struct stat *buf)
{
struct fakefile_msg *msg;
int res;
init_self();
msg = fakefile_msg_new(master, 2*sizeof(int));
fakefile_msg_add_int(msg, ff_et_fstat);
fakefile_msg_add_int(msg, fd);
fakefile_msg_end(msg);
msg = fakefile_msg_recv(master);
res = fakefile_msg_get_size_t(msg);
if (res < 0) {
errno = -res;
res = -1;
} else {
fakefile_msg_get(msg, buf, sizeof(struct stat));
}
fakefile_msg_end(msg);
return res;
}
int stat(const char *path, struct stat *buf)
{
int fd, res;
fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
res = fstat(fd, buf);
(void) close(fd);
return res;
}
int lstat(const char *path, struct stat *buf)
{
return stat(path, buf);
}
int close(int fd)
{
struct fakefile_msg *msg;
int res;
init_self();
if (!del_fake_fd(fd))
return libc_close(fd);
msg = fakefile_msg_new(master, 2*sizeof(int));
fakefile_msg_add_int(msg, ff_et_close);
fakefile_msg_add_int(msg, fd);
fakefile_msg_end(msg);
msg = fakefile_msg_recv(master);
res = fakefile_msg_get_int(msg);
fakefile_msg_end(msg);
if (res < 0) {
errno = -res;
return -1;
}
return res;
}
FILE *fopen(const char *path, const char *mode)
{
init_self();
fprintf(stderr, "fopen \"%s\"\n", path);
return libc_fopen(path, mode);
}
int dup(int oldfd)
{
init_self();
if (is_fake_fd(oldfd)) {
fprintf(stderr, "not supporting \"dup\" yet\n");
exit(1);
}
return libc_dup(oldfd);
}
int dup2(int oldfd, int newfd)
{
int res;
init_self();
if (oldfd == newfd)
return 0;
if (is_fake_fd(oldfd)) {
fprintf(stderr, "not supporting \"dup2\" yet\n");
exit(1);
}
if (is_fake_fd(newfd)) {
res = close(newfd);
if (res < 0)
return res;
}
return libc_dup2(oldfd, newfd);
}

26
fakefile/util.h Normal file
View File

@ -0,0 +1,26 @@
/*
* util.h - Utility functions
*
* Copyright 2012 by Werner Almesberger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef UTIL_H
#define UTIL_H
#include <stdlib.h>
#define alloc_size(s) \
({ void *alloc_size_tmp = malloc(s); \
if (!alloc_size_tmp) \
abort(); \
alloc_size_tmp; })
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
#endif /* !UTIL_H */