mirror of
git://projects.qi-hardware.com/wernermisc.git
synced 2024-11-22 02:31:53 +02:00
fakefile/: so far unsuccessful attempt at jailing Kicad
This commit is contained in:
parent
ddc5e0e935
commit
15067435ae
55
fakefile/Makefile
Normal file
55
fakefile/Makefile
Normal 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
3
fakefile/README
Normal 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
254
fakefile/comm.c
Normal 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
65
fakefile/comm.h
Normal 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
94
fakefile/demo.c
Normal 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
302
fakefile/fakefile.c
Normal 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
91
fakefile/fakefile.h
Normal 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
41
fakefile/file.c
Normal 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
40
fakefile/internal.h
Normal 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
162
fakefile/launch.c
Normal 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
305
fakefile/slave.c
Normal 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
26
fakefile/util.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user