Rewrite to declare most dual-kernel calls with macros. This helps

with adding new calls and makes all existing fd-accepting hijacked
calls dual-kernel.  It would be better to autogenerate the code
from syscalls.master, but this is easier for now.
This commit is contained in:
pooka 2011-01-25 12:18:33 +00:00
parent 984da15cb1
commit 9d0409a087
1 changed files with 294 additions and 450 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: hijack.c,v 1.16 2011/01/19 11:27:01 pooka Exp $ */
/* $NetBSD: hijack.c,v 1.17 2011/01/25 12:18:33 pooka Exp $ */
/*-
* Copyright (c) 2011 Antti Kantee. All Rights Reserved.
@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: hijack.c,v 1.16 2011/01/19 11:27:01 pooka Exp $");
__RCSID("$NetBSD: hijack.c,v 1.17 2011/01/25 12:18:33 pooka Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -53,160 +53,81 @@ __RCSID("$NetBSD: hijack.c,v 1.16 2011/01/19 11:27:01 pooka Exp $");
#include <time.h>
#include <unistd.h>
enum { RUMPCALL_SOCKET, RUMPCALL_ACCEPT, RUMPCALL_BIND, RUMPCALL_CONNECT,
RUMPCALL_GETPEERNAME, RUMPCALL_GETSOCKNAME, RUMPCALL_LISTEN,
RUMPCALL_RECVFROM, RUMPCALL_RECVMSG,
RUMPCALL_SENDTO, RUMPCALL_SENDMSG,
RUMPCALL_GETSOCKOPT, RUMPCALL_SETSOCKOPT,
RUMPCALL_SHUTDOWN,
RUMPCALL_READ, RUMPCALL_READV,
RUMPCALL_WRITE, RUMPCALL_WRITEV,
RUMPCALL_IOCTL, RUMPCALL_FCNTL,
RUMPCALL_CLOSE,
RUMPCALL_POLLTS,
RUMPCALL__NUM
enum dualcall {
DUALCALL_WRITE, DUALCALL_WRITEV,
DUALCALL_IOCTL, DUALCALL_FCNTL,
DUALCALL_SOCKET, DUALCALL_ACCEPT, DUALCALL_BIND, DUALCALL_CONNECT,
DUALCALL_GETPEERNAME, DUALCALL_GETSOCKNAME, DUALCALL_LISTEN,
DUALCALL_RECVFROM, DUALCALL_RECVMSG,
DUALCALL_SENDTO, DUALCALL_SENDMSG,
DUALCALL_GETSOCKOPT, DUALCALL_SETSOCKOPT,
DUALCALL_SHUTDOWN,
DUALCALL_READ, DUALCALL_READV,
DUALCALL_DUP2, DUALCALL_CLOSE,
DUALCALL_POLLTS,
DUALCALL__NUM
};
#define RSYS_STRING(a) __STRING(a)
#define RSYS_NAME(a) RSYS_STRING(__CONCAT(RUMP_SYS_RENAME_,a))
const char *sysnames[] = {
RSYS_NAME(SOCKET),
RSYS_NAME(ACCEPT),
RSYS_NAME(BIND),
RSYS_NAME(CONNECT),
RSYS_NAME(GETPEERNAME),
RSYS_NAME(GETSOCKNAME),
RSYS_NAME(LISTEN),
RSYS_NAME(RECVFROM),
RSYS_NAME(RECVMSG),
RSYS_NAME(SENDTO),
RSYS_NAME(SENDMSG),
RSYS_NAME(GETSOCKOPT),
RSYS_NAME(SETSOCKOPT),
RSYS_NAME(SHUTDOWN),
RSYS_NAME(READ),
RSYS_NAME(READV),
RSYS_NAME(WRITE),
RSYS_NAME(WRITEV),
RSYS_NAME(IOCTL),
RSYS_NAME(FCNTL),
RSYS_NAME(CLOSE),
RSYS_NAME(POLLTS),
};
static int (*host_socket)(int, int, int);
static int (*host_connect)(int, const struct sockaddr *, socklen_t);
static int (*host_bind)(int, const struct sockaddr *, socklen_t);
static int (*host_listen)(int, int);
static int (*host_accept)(int, struct sockaddr *, socklen_t *);
static int (*host_getpeername)(int, struct sockaddr *, socklen_t *);
static int (*host_getsockname)(int, struct sockaddr *, socklen_t *);
static int (*host_setsockopt)(int, int, int, const void *, socklen_t);
static ssize_t (*host_read)(int, void *, size_t);
static ssize_t (*host_readv)(int, const struct iovec *, int);
static ssize_t (*host_write)(int, const void *, size_t);
static ssize_t (*host_writev)(int, const struct iovec *, int);
static int (*host_ioctl)(int, unsigned long, ...);
static int (*host_fcntl)(int, int, ...);
static int (*host_close)(int);
static int (*host_pollts)(struct pollfd *, nfds_t,
const struct timespec *, const sigset_t *);
static pid_t (*host_fork)(void);
static int (*host_dup2)(int, int);
static int (*host_shutdown)(int, int);
/* XXX */
static void *host_sendto;
static void *host_recvfrom;
static void *rumpcalls[RUMPCALL__NUM];
/*
* Would be nice to get this automatically in sync with libc.
* Also, this does not work for compat-using binaries!
*/
#if !__NetBSD_Prereq__(5,99,7)
#define SELECT select
#define POLLTS pollts
#define POLL poll
#define LIBCSELECT select
#define LIBCPOLLTS pollts
#define LIBCPOLL poll
#else
#define SELECT __select50
#define POLLTS __pollts50
#define POLL __poll50
#define LIBCSELECT __select50
#define LIBCPOLLTS __pollts50
#define LIBCPOLL __poll50
#endif
int SELECT(int, fd_set *, fd_set *, fd_set *, struct timeval *);
int POLLTS(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *);
int POLL(struct pollfd *, nfds_t, int);
#endif
/*
* This is called from librumpclient in case of LD_PRELOAD.
* It ensures correct RTLD_NEXT.
*/
static void *
hijackdlsym(void *handle, const char *symbol)
{
#define S(a) __STRING(a)
struct sysnames {
enum dualcall scm_callnum;
const char *scm_hostname;
const char *scm_rumpname;
} syscnames[] = {
{ DUALCALL_SOCKET, "__socket30", RSYS_NAME(SOCKET) },
{ DUALCALL_ACCEPT, "accept", RSYS_NAME(ACCEPT) },
{ DUALCALL_BIND, "bind", RSYS_NAME(BIND) },
{ DUALCALL_CONNECT, "connect", RSYS_NAME(CONNECT) },
{ DUALCALL_GETPEERNAME, "getpeername", RSYS_NAME(GETPEERNAME) },
{ DUALCALL_GETSOCKNAME, "getsockname", RSYS_NAME(GETSOCKNAME) },
{ DUALCALL_LISTEN, "listen", RSYS_NAME(LISTEN) },
{ DUALCALL_RECVFROM, "recvfrom", RSYS_NAME(RECVFROM) },
{ DUALCALL_RECVMSG, "recvmsg", RSYS_NAME(RECVMSG) },
{ DUALCALL_SENDTO, "sendto", RSYS_NAME(SENDTO) },
{ DUALCALL_SENDMSG, "sendmsg", RSYS_NAME(SENDMSG) },
{ DUALCALL_GETSOCKOPT, "getsockopt", RSYS_NAME(GETSOCKOPT) },
{ DUALCALL_SETSOCKOPT, "setsockopt", RSYS_NAME(SETSOCKOPT) },
{ DUALCALL_SHUTDOWN, "shutdown", RSYS_NAME(SHUTDOWN) },
{ DUALCALL_READ, "read", RSYS_NAME(READ) },
{ DUALCALL_READV, "readv", RSYS_NAME(READV) },
{ DUALCALL_WRITE, "write", RSYS_NAME(WRITE) },
{ DUALCALL_WRITEV, "writev", RSYS_NAME(WRITEV) },
{ DUALCALL_IOCTL, "ioctl", RSYS_NAME(IOCTL) },
{ DUALCALL_FCNTL, "fcntl", RSYS_NAME(FCNTL) },
{ DUALCALL_DUP2, "dup2", RSYS_NAME(DUP2) },
{ DUALCALL_CLOSE, "close", RSYS_NAME(CLOSE) },
{ DUALCALL_POLLTS, S(LIBCPOLLTS), RSYS_NAME(POLLTS) },
};
#undef S
return dlsym(handle, symbol);
}
struct bothsys {
void *bs_host;
void *bs_rump;
} syscalls[DUALCALL__NUM];
#define GETSYSCALL(which, name) syscalls[DUALCALL_##name].bs_##which
/* low calorie sockets? */
static bool hostlocalsockets = true;
static void __attribute__((constructor))
rcinit(void)
{
int (*rumpcinit)(void);
void **rumpcdlsym;
void *hand;
int i;
hand = dlopen("librumpclient.so", RTLD_LAZY|RTLD_GLOBAL);
if (!hand)
err(1, "cannot open librumpclient.so");
rumpcinit = dlsym(hand, "rumpclient_init");
_DIAGASSERT(rumpcinit);
rumpcdlsym = dlsym(hand, "rumpclient_dlsym");
*rumpcdlsym = hijackdlsym;
host_socket = dlsym(RTLD_NEXT, "__socket30");
host_listen = dlsym(RTLD_NEXT, "listen");
host_connect = dlsym(RTLD_NEXT, "connect");
host_bind = dlsym(RTLD_NEXT, "bind");
host_accept = dlsym(RTLD_NEXT, "accept");
host_getpeername = dlsym(RTLD_NEXT, "getpeername");
host_getsockname = dlsym(RTLD_NEXT, "getsockname");
host_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
host_read = dlsym(RTLD_NEXT, "read");
host_readv = dlsym(RTLD_NEXT, "readv");
host_write = dlsym(RTLD_NEXT, "write");
host_writev = dlsym(RTLD_NEXT, "writev");
host_ioctl = dlsym(RTLD_NEXT, "ioctl");
host_fcntl = dlsym(RTLD_NEXT, "fcntl");
host_close = dlsym(RTLD_NEXT, "close");
host_pollts = dlsym(RTLD_NEXT, "pollts");
host_fork = dlsym(RTLD_NEXT, "fork");
host_dup2 = dlsym(RTLD_NEXT, "dup2");
host_shutdown = dlsym(RTLD_NEXT, "shutdown");
host_sendto = dlsym(RTLD_NEXT, "sendto");
host_recvfrom = dlsym(RTLD_NEXT, "recvfrom");
for (i = 0; i < RUMPCALL__NUM; i++) {
rumpcalls[i] = dlsym(hand, sysnames[i]);
if (!rumpcalls[i]) {
fprintf(stderr, "rumphijack: cannot find symbol: %s\n",
sysnames[i]);
exit(1);
}
}
if (rumpcinit() == -1)
err(1, "rumpclient init");
}
pid_t (*host_fork)(void);
static unsigned dup2mask;
#define ISDUP2D(fd) (1<<(fd) & dup2mask)
@ -231,6 +152,84 @@ mydprintf(const char *fmt, ...)
#define DPRINTF(x)
#endif
#define FDCALL(type, name, rcname, args, proto, vars) \
type name args \
{ \
type (*fun) proto; \
\
if (fd_isrump(fd)) { \
fun = syscalls[rcname].bs_rump; \
fd = fd_host2rump(fd); \
} else { \
fun = syscalls[rcname].bs_host; \
} \
\
return fun vars; \
}
/*
* This is called from librumpclient in case of LD_PRELOAD.
* It ensures correct RTLD_NEXT.
*/
static void *
hijackdlsym(void *handle, const char *symbol)
{
return dlsym(handle, symbol);
}
/* low calorie sockets? */
static bool hostlocalsockets = true;
static void __attribute__((constructor))
rcinit(void)
{
int (*rumpcinit)(void);
void **rumpcdlsym;
void *hand;
int i, j;
hand = dlopen("librumpclient.so", RTLD_LAZY|RTLD_GLOBAL);
if (!hand)
err(1, "cannot open librumpclient.so");
rumpcinit = dlsym(hand, "rumpclient_init");
_DIAGASSERT(rumpcinit);
rumpcdlsym = dlsym(hand, "rumpclient_dlsym");
*rumpcdlsym = hijackdlsym;
host_fork = dlsym(RTLD_NEXT, "fork");
/*
* In theory cannot print anything during lookups because
* we might not have the call vector set up. so, the errx()
* is a bit of a strech, but it might work.
*/
for (i = 0; i < DUALCALL__NUM; i++) {
/* build runtime O(1) access */
for (j = 0; j < __arraycount(syscnames); j++) {
if (syscnames[j].scm_callnum == i)
break;
}
if (j == __arraycount(syscnames))
errx(1, "rumphijack error: syscall pos %d missing", i);
syscalls[i].bs_host = dlsym(hand,syscnames[j].scm_hostname);
if (syscalls[i].bs_host == NULL)
errx(1, "hostcall %s not found missing",
syscnames[j].scm_hostname);
syscalls[i].bs_rump = dlsym(hand,syscnames[j].scm_rumpname);
if (syscalls[i].bs_rump == NULL)
errx(1, "rumpcall %s not found missing",
syscnames[j].scm_rumpname);
}
if (rumpcinit() == -1)
err(1, "rumpclient init");
}
/* XXX: need runtime selection. low for now due to FD_SETSIZE */
#define HIJACK_FDOFF 128
#define HIJACK_SELECT 128 /* XXX */
@ -271,17 +270,17 @@ int __socket30(int, int, int);
int
__socket30(int domain, int type, int protocol)
{
int (*rc_socket)(int, int, int);
int (*op_socket)(int, int, int);
int fd;
bool dohost;
dohost = hostlocalsockets && (domain == AF_LOCAL);
if (dohost)
rc_socket = host_socket;
op_socket = GETSYSCALL(host, SOCKET);
else
rc_socket = rumpcalls[RUMPCALL_SOCKET];
fd = rc_socket(domain, type, protocol);
op_socket = GETSYSCALL(rump, SOCKET);
fd = op_socket(domain, type, protocol);
if (!dohost)
fd = fd_rump2host(fd);
@ -293,7 +292,7 @@ __socket30(int domain, int type, int protocol)
int
accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int (*rc_accept)(int, struct sockaddr *, socklen_t *);
int (*op_accept)(int, struct sockaddr *, socklen_t *);
int fd;
bool isrump;
@ -301,12 +300,12 @@ accept(int s, struct sockaddr *addr, socklen_t *addrlen)
DPRINTF(("accept -> %d", s));
if (isrump) {
rc_accept = rumpcalls[RUMPCALL_ACCEPT];
op_accept = GETSYSCALL(rump, ACCEPT);
s = fd_host2rump(s);
} else {
rc_accept = host_accept;
op_accept = GETSYSCALL(host, ACCEPT);
}
fd = rc_accept(s, addr, addrlen);
fd = op_accept(s, addr, addrlen);
if (fd != -1 && isrump)
fd = fd_rump2host(fd);
@ -315,195 +314,67 @@ accept(int s, struct sockaddr *addr, socklen_t *addrlen)
return fd;
}
/*
* ioctl and fcntl are varargs calls and need special treatment
*/
int
bind(int s, const struct sockaddr *name, socklen_t namelen)
ioctl(int fd, unsigned long cmd, ...)
{
int (*rc_bind)(int, const struct sockaddr *, socklen_t);
int (*op_ioctl)(int, unsigned long cmd, ...);
va_list ap;
int rv;
DPRINTF(("bind -> %d\n", s));
if (fd_isrump(s)) {
rc_bind = rumpcalls[RUMPCALL_BIND];
s = fd_host2rump(s);
DPRINTF(("ioctl -> %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_ioctl = GETSYSCALL(rump, IOCTL);
} else {
rc_bind = host_bind;
op_ioctl = GETSYSCALL(host, IOCTL);
}
return rc_bind(s, name, namelen);
va_start(ap, cmd);
rv = op_ioctl(fd, cmd, va_arg(ap, void *));
va_end(ap);
return rv;
}
int
connect(int s, const struct sockaddr *name, socklen_t namelen)
fcntl(int fd, int cmd, ...)
{
int (*rc_connect)(int, const struct sockaddr *, socklen_t);
int (*op_fcntl)(int, int, ...);
va_list ap;
int rv;
DPRINTF(("connect -> %d\n", s));
if (fd_isrump(s)) {
rc_connect = rumpcalls[RUMPCALL_CONNECT];
s = fd_host2rump(s);
DPRINTF(("fcntl -> %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_fcntl = GETSYSCALL(rump, FCNTL);
} else {
rc_connect = host_connect;
op_fcntl = GETSYSCALL(host, FCNTL);
}
return rc_connect(s, name, namelen);
}
int
getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
int (*rc_getpeername)(int, struct sockaddr *, socklen_t *);
DPRINTF(("getpeername -> %d\n", s));
if (fd_isrump(s)) {
rc_getpeername = rumpcalls[RUMPCALL_GETPEERNAME];
s = fd_host2rump(s);
} else {
rc_getpeername = host_getpeername;
}
return rc_getpeername(s, name, namelen);
}
int
getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
int (*rc_getsockname)(int, struct sockaddr *, socklen_t *);
DPRINTF(("getsockname -> %d\n", s));
if (fd_isrump(s)) {
rc_getsockname = rumpcalls[RUMPCALL_GETSOCKNAME];
s = fd_host2rump(s);
} else {
rc_getsockname = host_getsockname;
}
return rc_getsockname(s, name, namelen);
}
int
listen(int s, int backlog)
{
int (*rc_listen)(int, int);
DPRINTF(("listen -> %d\n", s));
if (fd_isrump(s)) {
rc_listen = rumpcalls[RUMPCALL_LISTEN];
s = fd_host2rump(s);
} else {
rc_listen = host_listen;
}
return rc_listen(s, backlog);
va_start(ap, cmd);
rv = op_fcntl(fd, cmd, va_arg(ap, void *));
va_end(ap);
return rv;
}
/*
* write cannot issue a standard debug printf due to recursion
*/
ssize_t
recv(int s, void *buf, size_t len, int flags)
write(int fd, const void *buf, size_t blen)
{
ssize_t (*op_write)(int, const void *, size_t);
return recvfrom(s, buf, len, flags, NULL, NULL);
}
ssize_t
recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
socklen_t *fromlen)
{
int (*rc_recvfrom)(int, void *, size_t, int,
struct sockaddr *, socklen_t *);
DPRINTF(("recvfrom\n"));
if (fd_isrump(s)) {
rc_recvfrom = rumpcalls[RUMPCALL_RECVFROM];
s = fd_host2rump(s);
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_write = GETSYSCALL(rump, WRITE);
} else {
rc_recvfrom = host_recvfrom;
op_write = GETSYSCALL(host, WRITE);
}
return rc_recvfrom(s, buf, len, flags, from, fromlen);
}
ssize_t
recvmsg(int s, struct msghdr *msg, int flags)
{
int (*rc_recvmsg)(int, struct msghdr *, int);
DPRINTF(("recvmsg\n"));
assertfd(s);
rc_recvmsg = rumpcalls[RUMPCALL_RECVMSG];
return rc_recvmsg(fd_host2rump(s), msg, flags);
}
ssize_t
send(int s, const void *buf, size_t len, int flags)
{
return sendto(s, buf, len, flags, NULL, 0);
}
ssize_t
sendto(int s, const void *buf, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen)
{
int (*rc_sendto)(int, const void *, size_t, int,
const struct sockaddr *, socklen_t);
if (s == -1)
return len;
DPRINTF(("sendto\n"));
if (fd_isrump(s)) {
rc_sendto = rumpcalls[RUMPCALL_SENDTO];
s = fd_host2rump(s);
} else {
rc_sendto = host_sendto;
}
return rc_sendto(s, buf, len, flags, to, tolen);
}
ssize_t
sendmsg(int s, const struct msghdr *msg, int flags)
{
int (*rc_sendmsg)(int, const struct msghdr *, int);
DPRINTF(("sendmsg\n"));
assertfd(s);
rc_sendmsg = rumpcalls[RUMPCALL_SENDTO];
return rc_sendmsg(fd_host2rump(s), msg, flags);
}
int
getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
int (*rc_getsockopt)(int, int, int, void *, socklen_t *);
DPRINTF(("getsockopt -> %d\n", s));
assertfd(s);
rc_getsockopt = rumpcalls[RUMPCALL_GETSOCKOPT];
return rc_getsockopt(fd_host2rump(s), level, optname, optval, optlen);
}
int
setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
int (*rc_setsockopt)(int, int, int, const void *, socklen_t);
DPRINTF(("setsockopt -> %d\n", s));
if (fd_isrump(s)) {
rc_setsockopt = rumpcalls[RUMPCALL_SETSOCKOPT];
s = fd_host2rump(s);
} else {
rc_setsockopt = host_setsockopt;
}
return rc_setsockopt(s, level, optname, optval, optlen);
}
int
shutdown(int s, int how)
{
int (*rc_shutdown)(int, int);
DPRINTF(("shutdown -> %d\n", s));
if (fd_isrump(s)) {
rc_shutdown = rumpcalls[RUMPCALL_SHUTDOWN];
s = fd_host2rump(s);
} else {
rc_shutdown = host_shutdown;
}
return rc_shutdown(s, how);
return op_write(fd, buf, blen);
}
/*
@ -512,12 +383,11 @@ shutdown(int s, int how)
* not >= fdoff is an error.
*
* Note: cannot rump2host newd, because it is often hardcoded.
*
* XXX: should disable debug prints after stdout/stderr are dup2'd
*/
int
dup2(int oldd, int newd)
{
int (*host_dup2)(int, int);
int rv;
DPRINTF(("dup2 -> %d (o) -> %d (n)\n", oldd, newd));
@ -530,6 +400,7 @@ dup2(int oldd, int newd)
if (rv != -1)
dup2mask |= 1<<newd;
} else {
host_dup2 = syscalls[DUALCALL_DUP2].bs_host;
rv = host_dup2(oldd, newd);
}
@ -541,7 +412,6 @@ dup2(int oldd, int newd)
* the file descriptors of the forked parent in the child, but
* prevent double use of connection fd.
*/
pid_t
fork()
{
@ -570,134 +440,10 @@ fork()
}
/*
* Hybrids
* select is done by calling poll.
*/
ssize_t
read(int fd, void *buf, size_t len)
{
ssize_t (*op_read)(int, void *, size_t);
ssize_t n;
DPRINTF(("read %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_read = rumpcalls[RUMPCALL_READ];
} else {
op_read = host_read;
}
n = op_read(fd, buf, len);
return n;
}
ssize_t
readv(int fd, const struct iovec *iov, int iovcnt)
{
ssize_t (*op_readv)(int, const struct iovec *, int);
DPRINTF(("readv %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_readv = rumpcalls[RUMPCALL_READV];
} else {
op_readv = host_readv;
}
return op_readv(fd, iov, iovcnt);
}
ssize_t
write(int fd, const void *buf, size_t len)
{
ssize_t (*op_write)(int, const void *, size_t);
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_write = rumpcalls[RUMPCALL_WRITE];
} else {
op_write = host_write;
}
return op_write(fd, buf, len);
}
ssize_t
writev(int fd, const struct iovec *iov, int iovcnt)
{
ssize_t (*op_writev)(int, const struct iovec *, int);
DPRINTF(("writev %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_writev = rumpcalls[RUMPCALL_WRITEV];
} else {
op_writev = host_writev;
}
return op_writev(fd, iov, iovcnt);
}
int
ioctl(int fd, unsigned long cmd, ...)
{
int (*op_ioctl)(int, unsigned long cmd, ...);
va_list ap;
int rv;
DPRINTF(("ioctl\n"));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_ioctl = rumpcalls[RUMPCALL_IOCTL];
} else {
op_ioctl = host_ioctl;
}
va_start(ap, cmd);
rv = op_ioctl(fd, cmd, va_arg(ap, void *));
va_end(ap);
return rv;
}
int
fcntl(int fd, int cmd, ...)
{
int (*op_fcntl)(int, int, ...);
va_list ap;
int rv;
DPRINTF(("fcntl\n"));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_fcntl = rumpcalls[RUMPCALL_FCNTL];
} else {
op_fcntl = host_fcntl;
}
va_start(ap, cmd);
rv = op_fcntl(fd, cmd, va_arg(ap, void *));
va_end(ap);
return rv;
}
int
close(int fd)
{
int (*op_close)(int);
DPRINTF(("close %d\n", fd));
if (fd_isrump(fd)) {
fd = fd_host2rump(fd);
op_close = rumpcalls[RUMPCALL_CLOSE];
} else {
op_close = host_close;
}
return op_close(fd);
}
int
SELECT(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
LIBCSELECT(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
struct pollfd *pfds;
@ -710,7 +456,7 @@ SELECT(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
/*
* Well, first we must scan the fds to figure out how many
* fds there really are. This is because up to and including
* nb5 poll() silently refuses nfds > process_open_fds.
* nb5 poll() silently refuses nfds > process_maxopen_fds.
* Seems to be fixed in current, thank the maker.
* god damn cluster...bomb.
*/
@ -847,10 +593,13 @@ struct pollarg {
static void *
hostpoll(void *arg)
{
int (*op_pollts)(struct pollfd *, nfds_t, const struct timespec *,
const sigset_t *);
struct pollarg *parg = arg;
intptr_t rv;
rv = host_pollts(parg->pfds, parg->nfds, parg->ts, parg->sigmask);
op_pollts = syscalls[DUALCALL_POLLTS].bs_host;
rv = op_pollts(parg->pfds, parg->nfds, parg->ts, parg->sigmask);
if (rv == -1)
parg->errnum = errno;
rump_sys_write(parg->pipefd, &rv, sizeof(rv));
@ -859,11 +608,12 @@ hostpoll(void *arg)
}
int
POLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
LIBCPOLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
const sigset_t *sigmask)
{
int (*op_pollts)(struct pollfd *, nfds_t, const struct timespec *,
const sigset_t *);
int (*host_close)(int);
int hostcall = 0, rumpcall = 0;
pthread_t pt;
nfds_t i;
@ -941,7 +691,7 @@ POLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
parg.pipefd = rpipe[1];
pthread_create(&pt, NULL, hostpoll, &parg);
op_pollts = rumpcalls[RUMPCALL_POLLTS];
op_pollts = syscalls[DUALCALL_POLLTS].bs_rump;
lrv = op_pollts(pfd_rump, nfds+1, ts, NULL);
sverrno = errno;
write(hpipe[1], &rv, sizeof(rv));
@ -968,6 +718,7 @@ POLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
}
out:
host_close = syscalls[DUALCALL_CLOSE].bs_host;
if (rpipe[0] != -1)
rump_sys_close(rpipe[0]);
if (rpipe[1] != -1)
@ -981,9 +732,9 @@ POLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
errno = sverrno;
} else {
if (hostcall) {
op_pollts = host_pollts;
op_pollts = syscalls[DUALCALL_POLLTS].bs_host;
} else {
op_pollts = rumpcalls[RUMPCALL_POLLTS];
op_pollts = syscalls[DUALCALL_POLLTS].bs_rump;
adjustpoll(fds, nfds, fd_host2rump);
}
@ -996,7 +747,7 @@ POLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
}
int
POLL(struct pollfd *fds, nfds_t nfds, int timeout)
LIBCPOLL(struct pollfd *fds, nfds_t nfds, int timeout)
{
struct timespec ts;
struct timespec *tsp = NULL;
@ -1015,14 +766,107 @@ int
kqueue(void)
{
fprintf(stderr, "kqueue unsupported");
abort();
/*NOTREACHED*/
}
/*ARGSUSED*/
int
kevent(int kq, const struct kevent *changelist, size_t nchanges,
struct kevent *eventlist, size_t nevents,
const struct timespec *timeout)
{
fprintf(stderr, "kqueue unsupported");
abort();
/*NOTREACHED*/
}
/*
* Rest are std type calls.
*/
FDCALL(int, bind, DUALCALL_BIND, \
(int fd, const struct sockaddr *name, socklen_t namelen), \
(int, const struct sockaddr *, socklen_t), \
(fd, name, namelen))
FDCALL(int, connect, DUALCALL_CONNECT, \
(int fd, const struct sockaddr *name, socklen_t namelen), \
(int, const struct sockaddr *, socklen_t), \
(fd, name, namelen))
FDCALL(int, getpeername, DUALCALL_GETPEERNAME, \
(int fd, struct sockaddr *name, socklen_t *namelen), \
(int, struct sockaddr *, socklen_t *), \
(fd, name, namelen))
FDCALL(int, getsockname, DUALCALL_GETSOCKNAME, \
(int fd, struct sockaddr *name, socklen_t *namelen), \
(int, struct sockaddr *, socklen_t *), \
(fd, name, namelen))
FDCALL(int, listen, DUALCALL_LISTEN, \
(int fd, int backlog), \
(int, int), \
(fd, backlog))
FDCALL(ssize_t, recvfrom, DUALCALL_RECVFROM, \
(int fd, void *buf, size_t len, int flags, \
struct sockaddr *from, socklen_t *fromlen), \
(int, void *, size_t, int, struct sockaddr *, socklen_t *), \
(fd, buf, len, flags, from, fromlen))
FDCALL(ssize_t, sendto, DUALCALL_SENDTO, \
(int fd, const void *buf, size_t len, int flags, \
const struct sockaddr *to, socklen_t tolen), \
(int, const void *, size_t, int, \
const struct sockaddr *, socklen_t), \
(fd, buf, len, flags, to, tolen))
FDCALL(ssize_t, recvmsg, DUALCALL_RECVMSG, \
(int fd, struct msghdr *msg, int flags), \
(int, struct msghdr *, int), \
(fd, msg, flags))
FDCALL(ssize_t, sendmsg, DUALCALL_SENDMSG, \
(int fd, const struct msghdr *msg, int flags), \
(int, const struct msghdr *, int), \
(fd, msg, flags))
FDCALL(int, getsockopt, DUALCALL_GETSOCKOPT, \
(int fd, int level, int optn, void *optval, socklen_t *optlen), \
(int, int, int, void *, socklen_t *), \
(fd, level, optn, optval, optlen))
FDCALL(int, setsockopt, DUALCALL_SETSOCKOPT, \
(int fd, int level, int optn, \
const void *optval, socklen_t optlen), \
(int, int, int, const void *, socklen_t), \
(fd, level, optn, optval, optlen))
FDCALL(int, shutdown, DUALCALL_SHUTDOWN, \
(int fd, int how), \
(int, int), \
(fd, how))
FDCALL(ssize_t, read, DUALCALL_READ, \
(int fd, void *buf, size_t buflen), \
(int, void *, size_t), \
(fd, buf, buflen))
FDCALL(ssize_t, readv, DUALCALL_READV, \
(int fd, const struct iovec *iov, int iovcnt), \
(int, const struct iovec *, int), \
(fd, iov, iovcnt))
FDCALL(ssize_t, writev, DUALCALL_WRITEV, \
(int fd, const struct iovec *iov, int iovcnt), \
(int, const struct iovec *, int), \
(fd, iov, iovcnt))
FDCALL(int, close, DUALCALL_CLOSE, \
(int fd), \
(int), \
(fd))