version 1.33, 2011/02/18 16:22:10 |
version 1.51.2.1, 2012/11/20 03:00:45 |
|
|
* Client side routines for rump syscall proxy. |
* Client side routines for rump syscall proxy. |
*/ |
*/ |
|
|
|
#include "rumpuser_port.h" |
|
|
|
/* |
|
* We use kqueue on NetBSD, poll elsewhere. Theoretically we could |
|
* use kqueue on other BSD's too, but I haven't tested those. We |
|
* want to use kqueue because it will give us the ability to get signal |
|
* notifications but defer their handling to a stage where we do not |
|
* hold the communication lock. Taking a signal while holding on to |
|
* that lock may cause a deadlock. Therefore, block signals throughout |
|
* the RPC when using poll. This unfortunately means that the normal |
|
* SIGINT way of stopping a process while it is undergoing rump kernel |
|
* RPC will not work. If anyone know which Linux system call handles |
|
* the above scenario correctly, I'm all ears. |
|
*/ |
|
|
|
#ifdef __NetBSD__ |
|
#define USE_KQUEUE |
|
#endif |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__RCSID("$NetBSD"); |
__RCSID("$NetBSD$"); |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/event.h> |
|
#include <sys/mman.h> |
#include <sys/mman.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
|
#include <sys/time.h> |
|
|
|
#ifdef USE_KQUEUE |
|
#include <sys/event.h> |
|
#endif |
|
|
#include <arpa/inet.h> |
#include <arpa/inet.h> |
#include <netinet/in.h> |
#include <netinet/in.h> |
Line 43 __RCSID("$NetBSD"); |
|
Line 66 __RCSID("$NetBSD"); |
|
|
|
#include <assert.h> |
#include <assert.h> |
#include <dlfcn.h> |
#include <dlfcn.h> |
|
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <link.h> |
#include <link.h> |
Line 65 int (*host_connect)(int, const struct so |
|
Line 89 int (*host_connect)(int, const struct so |
|
int (*host_fcntl)(int, int, ...); |
int (*host_fcntl)(int, int, ...); |
int (*host_poll)(struct pollfd *, nfds_t, int); |
int (*host_poll)(struct pollfd *, nfds_t, int); |
ssize_t (*host_read)(int, void *, size_t); |
ssize_t (*host_read)(int, void *, size_t); |
ssize_t (*host_sendto)(int, const void *, size_t, int, |
ssize_t (*host_sendmsg)(int, const struct msghdr *, int); |
const struct sockaddr *, socklen_t); |
|
int (*host_setsockopt)(int, int, int, const void *, socklen_t); |
int (*host_setsockopt)(int, int, int, const void *, socklen_t); |
int (*host_dup)(int); |
int (*host_dup)(int); |
|
|
|
#ifdef USE_KQUEUE |
int (*host_kqueue)(void); |
int (*host_kqueue)(void); |
int (*host_kevent)(int, const struct kevent *, size_t, |
int (*host_kevent)(int, const struct kevent *, size_t, |
struct kevent *, size_t, const struct timespec *); |
struct kevent *, size_t, const struct timespec *); |
|
#endif |
|
|
int (*host_execve)(const char *, char *const[], char *const[]); |
int (*host_execve)(const char *, char *const[], char *const[]); |
|
|
Line 85 static struct spclient clispc = { |
|
Line 110 static struct spclient clispc = { |
|
static int kq = -1; |
static int kq = -1; |
static sigset_t fullset; |
static sigset_t fullset; |
|
|
static int doconnect(bool); |
static int doconnect(void); |
static int handshake_req(struct spclient *, int, void *, int, bool); |
static int handshake_req(struct spclient *, int, void *, int, bool); |
|
|
/* |
/* |
Line 94 static int handshake_req(struct spclient |
|
Line 119 static int handshake_req(struct spclient |
|
*/ |
*/ |
static time_t retrytimo = 0; |
static time_t retrytimo = 0; |
|
|
|
/* always defined to nothingness for now */ |
|
#define ERRLOG(a) |
|
|
static int |
static int |
send_with_recon(struct spclient *spc, const void *data, size_t dlen) |
send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen) |
{ |
{ |
struct timeval starttime, curtime; |
struct timeval starttime, curtime; |
time_t prevreconmsg; |
time_t prevreconmsg; |
Line 103 send_with_recon(struct spclient *spc, co |
|
Line 131 send_with_recon(struct spclient *spc, co |
|
int rv; |
int rv; |
|
|
for (prevreconmsg = 0, reconretries = 0;;) { |
for (prevreconmsg = 0, reconretries = 0;;) { |
rv = dosend(spc, data, dlen); |
rv = dosend(spc, iov, iovlen); |
if (__predict_false(rv == ENOTCONN || rv == EBADF)) { |
if (__predict_false(rv == ENOTCONN || rv == EBADF)) { |
/* no persistent connections */ |
/* no persistent connections */ |
if (retrytimo == 0) { |
if (retrytimo == 0) { |
Line 111 send_with_recon(struct spclient *spc, co |
|
Line 139 send_with_recon(struct spclient *spc, co |
|
break; |
break; |
} |
} |
if (retrytimo == RUMPCLIENT_RETRYCONN_DIE) |
if (retrytimo == RUMPCLIENT_RETRYCONN_DIE) |
exit(1); |
_exit(1); |
|
|
if (!prevreconmsg) { |
if (!prevreconmsg) { |
prevreconmsg = time(NULL); |
prevreconmsg = time(NULL); |
Line 152 send_with_recon(struct spclient *spc, co |
|
Line 180 send_with_recon(struct spclient *spc, co |
|
} |
} |
reconretries++; |
reconretries++; |
|
|
if ((rv = doconnect(false)) != 0) |
if ((rv = doconnect()) != 0) |
continue; |
continue; |
if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST, |
if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST, |
NULL, 0, true)) != 0) |
NULL, 0, true)) != 0) |
Line 194 cliwaitresp(struct spclient *spc, struct |
|
Line 222 cliwaitresp(struct spclient *spc, struct |
|
|
|
/* are we free to receive? */ |
/* are we free to receive? */ |
if (spc->spc_istatus == SPCSTATUS_FREE) { |
if (spc->spc_istatus == SPCSTATUS_FREE) { |
struct kevent kev[8]; |
int gotresp, dosig, rv; |
int gotresp, dosig, rv, i; |
|
|
|
spc->spc_istatus = SPCSTATUS_BUSY; |
spc->spc_istatus = SPCSTATUS_BUSY; |
pthread_mutex_unlock(&spc->spc_mtx); |
pthread_mutex_unlock(&spc->spc_mtx); |
|
|
dosig = 0; |
dosig = 0; |
for (gotresp = 0; !gotresp; ) { |
for (gotresp = 0; !gotresp; ) { |
switch (readframe(spc)) { |
#ifdef USE_KQUEUE |
case 0: |
struct kevent kev[8]; |
rv = host_kevent(kq, NULL, 0, |
int i; |
kev, __arraycount(kev), NULL); |
|
|
/* |
|
* typically we don't have a frame waiting |
|
* when we come in here, so call kevent now |
|
*/ |
|
rv = host_kevent(kq, NULL, 0, |
|
kev, __arraycount(kev), NULL); |
|
|
|
if (__predict_false(rv == -1)) { |
|
goto activity; |
|
} |
|
|
|
/* |
|
* XXX: don't know how this can happen |
|
* (timeout cannot expire since there |
|
* isn't one), but it does happen. |
|
* treat it as an expectional condition |
|
* and go through tryread to determine |
|
* alive status. |
|
*/ |
|
if (__predict_false(rv == 0)) |
|
goto activity; |
|
|
|
for (i = 0; i < rv; i++) { |
|
if (kev[i].filter == EVFILT_SIGNAL) |
|
dosig++; |
|
} |
|
if (dosig) |
|
goto cleanup; |
|
|
if (__predict_false(rv == -1)) { |
/* |
goto cleanup; |
* ok, activity. try to read a frame to |
} |
* determine what happens next. |
|
*/ |
/* |
activity: |
* XXX: don't know how this can |
#else /* USE_KQUEUE */ |
* happen (timeout cannot expire |
struct pollfd pfd; |
* since there isn't one), but |
|
* it does happen |
|
*/ |
|
if (__predict_false(rv == 0)) |
|
continue; |
|
|
|
for (i = 0; i < rv; i++) { |
|
if (kev[i].filter |
|
== EVFILT_SIGNAL) |
|
dosig++; |
|
} |
|
if (dosig) |
|
goto cleanup; |
|
|
|
|
pfd.fd = clispc.spc_fd; |
|
pfd.events = POLLIN; |
|
|
|
rv = host_poll(&pfd, 1, -1); |
|
#endif /* !USE_KQUEUE */ |
|
|
|
switch (readframe(spc)) { |
|
case 0: |
continue; |
continue; |
case -1: |
case -1: |
imalive = false; |
imalive = false; |
goto cleanup; |
goto cleanup; |
default: |
default: |
|
/* case 1 */ |
break; |
break; |
} |
} |
|
|
Line 286 syscall_req(struct spclient *spc, sigset |
|
Line 337 syscall_req(struct spclient *spc, sigset |
|
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
|
struct iovec iov[2]; |
int rv; |
int rv; |
|
|
rhdr.rsp_len = sizeof(rhdr) + dlen; |
rhdr.rsp_len = sizeof(rhdr) + dlen; |
Line 293 syscall_req(struct spclient *spc, sigset |
|
Line 345 syscall_req(struct spclient *spc, sigset |
|
rhdr.rsp_type = RUMPSP_SYSCALL; |
rhdr.rsp_type = RUMPSP_SYSCALL; |
rhdr.rsp_sysnum = sysnum; |
rhdr.rsp_sysnum = sysnum; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen); |
|
|
do { |
do { |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) { |
if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) { |
unputwait(spc, &rw); |
|
continue; |
|
} |
|
if ((rv = send_with_recon(spc, data, dlen)) != 0) { |
|
unputwait(spc, &rw); |
unputwait(spc, &rw); |
continue; |
continue; |
} |
} |
Line 318 handshake_req(struct spclient *spc, int |
|
Line 369 handshake_req(struct spclient *spc, int |
|
int cancel, bool haslock) |
int cancel, bool haslock) |
{ |
{ |
struct handshake_fork rf; |
struct handshake_fork rf; |
|
const char *myprogname = NULL; /* XXXgcc */ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
sigset_t omask; |
sigset_t omask; |
size_t bonus; |
size_t bonus; |
|
struct iovec iov[2]; |
int rv; |
int rv; |
|
|
if (type == HANDSHAKE_FORK) { |
if (type == HANDSHAKE_FORK) { |
bonus = sizeof(rf); |
bonus = sizeof(rf); |
} else { |
} else { |
bonus = strlen(getprogname())+1; |
#ifdef __NetBSD__ |
|
/* would procfs work on NetBSD too? */ |
|
myprogname = getprogname(); |
|
#else |
|
int fd = open("/proc/self/comm", O_RDONLY); |
|
if (fd == -1) { |
|
myprogname = "???"; |
|
} else { |
|
static char commname[128]; |
|
|
|
memset(commname, 0, sizeof(commname)); |
|
if (read(fd, commname, sizeof(commname)) > 0) { |
|
char *n; |
|
|
|
n = strrchr(commname, '\n'); |
|
if (n) |
|
*n = '\0'; |
|
myprogname = commname; |
|
} else { |
|
myprogname = "???"; |
|
} |
|
close(fd); |
|
} |
|
#endif |
|
bonus = strlen(myprogname)+1; |
} |
} |
|
|
/* performs server handshake */ |
/* performs server handshake */ |
Line 336 handshake_req(struct spclient *spc, int |
|
Line 413 handshake_req(struct spclient *spc, int |
|
rhdr.rsp_type = RUMPSP_HANDSHAKE; |
rhdr.rsp_type = RUMPSP_HANDSHAKE; |
rhdr.rsp_handshake = type; |
rhdr.rsp_handshake = type; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
|
pthread_sigmask(SIG_SETMASK, &fullset, &omask); |
pthread_sigmask(SIG_SETMASK, &fullset, &omask); |
if (haslock) |
if (haslock) |
putwait_locked(spc, &rw, &rhdr); |
putwait_locked(spc, &rw, &rhdr); |
else |
else |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
rv = dosend(spc, &rhdr, sizeof(rhdr)); |
|
if (type == HANDSHAKE_FORK) { |
if (type == HANDSHAKE_FORK) { |
memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */ |
memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */ |
rf.rf_cancel = cancel; |
rf.rf_cancel = cancel; |
rv = send_with_recon(spc, &rf, sizeof(rf)); |
IOVPUT(iov[1], rf); |
} else { |
} else { |
rv = dosend(spc, getprogname(), strlen(getprogname())+1); |
IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus); |
} |
} |
|
rv = send_with_recon(spc, iov, __arraycount(iov)); |
if (rv || cancel) { |
if (rv || cancel) { |
if (haslock) |
if (haslock) |
unputwait_locked(spc, &rw); |
unputwait_locked(spc, &rw); |
Line 376 prefork_req(struct spclient *spc, sigset |
|
Line 455 prefork_req(struct spclient *spc, sigset |
|
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct respwait rw; |
struct respwait rw; |
|
struct iovec iov[1]; |
int rv; |
int rv; |
|
|
rhdr.rsp_len = sizeof(rhdr); |
rhdr.rsp_len = sizeof(rhdr); |
Line 383 prefork_req(struct spclient *spc, sigset |
|
Line 463 prefork_req(struct spclient *spc, sigset |
|
rhdr.rsp_type = RUMPSP_PREFORK; |
rhdr.rsp_type = RUMPSP_PREFORK; |
rhdr.rsp_error = 0; |
rhdr.rsp_error = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
|
do { |
do { |
putwait(spc, &rw, &rhdr); |
putwait(spc, &rw, &rhdr); |
rv = send_with_recon(spc, &rhdr, sizeof(rhdr)); |
rv = send_with_recon(spc, iov, __arraycount(iov)); |
if (rv != 0) { |
if (rv != 0) { |
unputwait(spc, &rw); |
unputwait(spc, &rw); |
continue; |
continue; |
Line 429 send_copyin_resp(struct spclient *spc, u |
|
Line 511 send_copyin_resp(struct spclient *spc, u |
|
int wantstr) |
int wantstr) |
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
|
struct iovec iov[2]; |
|
|
if (wantstr) |
if (wantstr) |
dlen = MIN(dlen, strlen(data)+1); |
dlen = MIN(dlen, strlen(data)+1); |
Line 439 send_copyin_resp(struct spclient *spc, u |
|
Line 522 send_copyin_resp(struct spclient *spc, u |
|
rhdr.rsp_type = RUMPSP_COPYIN; |
rhdr.rsp_type = RUMPSP_COPYIN; |
rhdr.rsp_sysnum = 0; |
rhdr.rsp_sysnum = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT_WITHSIZE(iov[1], data, dlen); |
|
|
if (resp_sendlock(spc) != 0) |
if (resp_sendlock(spc) != 0) |
return; |
return; |
(void)dosend(spc, &rhdr, sizeof(rhdr)); |
(void)SENDIOV(spc, iov); |
(void)dosend(spc, data, dlen); |
|
sendunlock(spc); |
sendunlock(spc); |
} |
} |
|
|
|
|
send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) |
send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr) |
{ |
{ |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
|
struct iovec iov[2]; |
|
|
rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); |
rhdr.rsp_len = sizeof(rhdr) + sizeof(addr); |
rhdr.rsp_reqno = reqno; |
rhdr.rsp_reqno = reqno; |
Line 457 send_anonmmap_resp(struct spclient *spc, |
|
Line 543 send_anonmmap_resp(struct spclient *spc, |
|
rhdr.rsp_type = RUMPSP_ANONMMAP; |
rhdr.rsp_type = RUMPSP_ANONMMAP; |
rhdr.rsp_sysnum = 0; |
rhdr.rsp_sysnum = 0; |
|
|
|
IOVPUT(iov[0], rhdr); |
|
IOVPUT(iov[1], addr); |
|
|
if (resp_sendlock(spc) != 0) |
if (resp_sendlock(spc) != 0) |
return; |
return; |
(void)dosend(spc, &rhdr, sizeof(rhdr)); |
(void)SENDIOV(spc, iov); |
(void)dosend(spc, &addr, sizeof(addr)); |
|
sendunlock(spc); |
sendunlock(spc); |
} |
} |
|
|
|
|
dupgood(int myfd, int mustchange) |
dupgood(int myfd, int mustchange) |
{ |
{ |
int ofds[4]; |
int ofds[4]; |
int i; |
int sverrno; |
|
unsigned int i; |
|
|
for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) { |
for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) { |
assert(i < __arraycount(ofds)); |
assert(i < __arraycount(ofds)); |
Line 572 dupgood(int myfd, int mustchange) |
|
Line 661 dupgood(int myfd, int mustchange) |
|
} |
} |
} |
} |
|
|
for (i--; i >= 0; i--) { |
sverrno = 0; |
|
if (myfd == -1 && i > 0) |
|
sverrno = errno; |
|
|
|
while (i-- > 0) { |
host_close(ofds[i]); |
host_close(ofds[i]); |
} |
} |
|
|
|
if (sverrno) |
|
errno = sverrno; |
|
|
return myfd; |
return myfd; |
} |
} |
|
|
static int |
static int |
doconnect(bool noisy) |
doconnect(void) |
{ |
{ |
struct respwait rw; |
struct respwait rw; |
struct rsp_hdr rhdr; |
struct rsp_hdr rhdr; |
struct kevent kev[NSIG+1]; |
|
char banner[MAXBANNER]; |
char banner[MAXBANNER]; |
struct pollfd pfd; |
int s, error, flags; |
int s, error, flags, i; |
|
ssize_t n; |
ssize_t n; |
|
|
if (kq != -1) |
if (kq != -1) |
Line 630 doconnect(bool noisy) |
|
Line 724 doconnect(bool noisy) |
|
if (s == -1) |
if (s == -1) |
return -1; |
return -1; |
|
|
pfd.fd = s; |
while (host_connect(s, serv_sa, parsetab[ptab_idx].slen) == -1) { |
pfd.events = POLLIN; |
|
while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) { |
|
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
error = errno; |
ERRLOG(("rump_sp: client connect failed: %s\n", |
if (noisy) |
strerror(errno))); |
fprintf(stderr, "rump_sp: client connect failed: %s\n", |
|
strerror(errno)); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if ((error = parsetab[ptab_idx].connhook(s)) != 0) { |
if ((error = parsetab[ptab_idx].connhook(s)) != 0) { |
error = errno; |
ERRLOG(("rump_sp: connect hook failed\n")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: connect hook failed\n"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) { |
if ((n = host_read(s, banner, sizeof(banner)-1)) <= 0) { |
error = errno; |
ERRLOG(("rump_sp: failed to read banner\n")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: failed to read banner\n"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
if (banner[n-1] != '\n') { |
if (banner[n-1] != '\n') { |
if (noisy) |
ERRLOG(("rump_sp: invalid banner\n")); |
fprintf(stderr, "rump_sp: invalid banner\n"); |
|
errno = EINVAL; |
|
return -1; |
return -1; |
} |
} |
banner[n] = '\0'; |
banner[n] = '\0'; |
/* parse the banner some day */ |
/* XXX parse the banner some day */ |
|
|
flags = host_fcntl(s, F_GETFL, 0); |
flags = host_fcntl(s, F_GETFL, 0); |
if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { |
if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { |
if (noisy) |
ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno))); |
fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n", |
|
strerror(errno)); |
|
errno = EINVAL; |
|
return -1; |
return -1; |
} |
} |
clispc.spc_fd = s; |
clispc.spc_fd = s; |
clispc.spc_state = SPCSTATE_RUNNING; |
clispc.spc_state = SPCSTATE_RUNNING; |
clispc.spc_reconnecting = 0; |
clispc.spc_reconnecting = 0; |
|
|
|
#ifdef USE_KQUEUE |
|
{ |
|
struct kevent kev[NSIG+1]; |
|
int i; |
|
|
/* setup kqueue, we want all signals and the fd */ |
/* setup kqueue, we want all signals and the fd */ |
if ((kq = dupgood(host_kqueue(), 0)) == -1) { |
if ((kq = dupgood(host_kqueue(), 0)) == -1) { |
error = errno; |
ERRLOG(("rump_sp: cannot setup kqueue")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: cannot setup kqueue"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
|
Line 695 doconnect(bool noisy) |
|
Line 775 doconnect(bool noisy) |
|
EV_SET(&kev[NSIG], clispc.spc_fd, |
EV_SET(&kev[NSIG], clispc.spc_fd, |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { |
if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { |
error = errno; |
ERRLOG(("rump_sp: kevent() failed")); |
if (noisy) |
|
fprintf(stderr, "rump_sp: kevent() failed"); |
|
errno = error; |
|
return -1; |
return -1; |
} |
} |
|
} |
|
#endif /* USE_KQUEUE */ |
|
|
return 0; |
return 0; |
} |
} |
|
|
return 0; |
return 0; |
} |
} |
|
|
void *(*rumpclient_dlsym)(void *, const char *); |
void *rumpclient__dlsym(void *, const char *); |
static int init_done = 0; |
void * |
|
rumpclient__dlsym(void *handle, const char *symbol) |
|
{ |
|
|
|
return dlsym(handle, symbol); |
|
} |
|
void *rumphijack_dlsym(void *, const char *) |
|
__attribute__((__weak__, alias("rumpclient__dlsym"))); |
|
|
|
static pid_t init_done = 0; |
|
|
int |
int |
rumpclient_init() |
rumpclient_init(void) |
{ |
{ |
char *p; |
char *p; |
int error; |
int error; |
int rv = -1; |
int rv = -1; |
int hstype; |
int hstype; |
|
pid_t mypid; |
|
|
if (init_done) |
/* |
|
* Make sure we're not riding the context of a previous |
|
* host fork. Note: it's *possible* that after n>1 forks |
|
* we have the same pid as one of our exited parents, but |
|
* I'm pretty sure there are 0 practical implications, since |
|
* it means generations would have to skip rumpclient init. |
|
*/ |
|
if (init_done == (mypid = getpid())) |
return 0; |
return 0; |
init_done = 1; |
|
|
|
sigfillset(&fullset); |
/* kq does not traverse fork() */ |
|
if (init_done != 0) |
|
kq = -1; |
|
init_done = mypid; |
|
|
/* dlsym overrided by rumphijack? */ |
sigfillset(&fullset); |
if (!rumpclient_dlsym) |
|
rumpclient_dlsym = dlsym; |
|
|
|
/* |
/* |
* sag mir, wo die symbol sind. zogen fort, der krieg beginnt. |
* sag mir, wo die symbols sind. zogen fort, der krieg beginnt. |
* wann wird man je verstehen? wann wird man je verstehen? |
* wann wird man je verstehen? wann wird man je verstehen? |
*/ |
*/ |
#define FINDSYM2(_name_,_syscall_) \ |
#define FINDSYM2(_name_,_syscall_) \ |
if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT, \ |
if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ |
#_syscall_)) == NULL) \ |
#_syscall_)) == NULL) { \ |
/* host_##_name_ = _syscall_ */; |
if (rumphijack_dlsym == rumpclient__dlsym) \ |
|
host_##_name_ = _name_; /* static fallback */ \ |
|
if (host_##_name_ == NULL) \ |
|
errx(1, "cannot find %s: %s", #_syscall_, \ |
|
dlerror()); \ |
|
} |
#define FINDSYM(_name_) FINDSYM2(_name_,_name_) |
#define FINDSYM(_name_) FINDSYM2(_name_,_name_) |
FINDSYM2(socket,__socket30); |
#ifdef __NetBSD__ |
FINDSYM(close); |
FINDSYM2(socket,__socket30) |
FINDSYM(connect); |
#else |
FINDSYM(fcntl); |
FINDSYM(socket) |
FINDSYM(poll); |
#endif |
FINDSYM(read); |
|
FINDSYM(sendto); |
FINDSYM(close) |
FINDSYM(setsockopt); |
FINDSYM(connect) |
FINDSYM(dup); |
FINDSYM(fcntl) |
FINDSYM(kqueue); |
FINDSYM(poll) |
FINDSYM(execve); |
FINDSYM(read) |
|
FINDSYM(sendmsg) |
|
FINDSYM(setsockopt) |
|
FINDSYM(dup) |
|
FINDSYM(execve) |
|
|
|
#ifdef USE_KQUEUE |
|
FINDSYM(kqueue) |
#if !__NetBSD_Prereq__(5,99,7) |
#if !__NetBSD_Prereq__(5,99,7) |
FINDSYM(kevent); |
FINDSYM(kevent) |
#else |
#else |
FINDSYM2(kevent,_sys___kevent50); |
FINDSYM2(kevent,_sys___kevent50) |
#endif |
#endif |
|
#endif /* USE_KQUEUE */ |
|
|
#undef FINDSYM |
#undef FINDSYM |
#undef FINDSY2 |
#undef FINDSY2 |
|
|
if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) { |
if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) { |
if ((p = getenv("RUMP_SERVER")) == NULL) { |
if ((p = getenv("RUMP_SERVER")) == NULL) { |
|
fprintf(stderr, "error: RUMP_SERVER not set\n"); |
errno = ENOENT; |
errno = ENOENT; |
goto out; |
goto out; |
} |
} |
Line 785 rumpclient_init() |
|
Line 896 rumpclient_init() |
|
unsetenv("RUMPCLIENT__EXECFD"); |
unsetenv("RUMPCLIENT__EXECFD"); |
hstype = HANDSHAKE_EXEC; |
hstype = HANDSHAKE_EXEC; |
} else { |
} else { |
if (doconnect(true) == -1) |
if (doconnect() == -1) |
goto out; |
goto out; |
hstype = HANDSHAKE_GUEST; |
hstype = HANDSHAKE_GUEST; |
} |
} |
Line 858 rumpclient_fork_init(struct rumpclient_f |
|
Line 969 rumpclient_fork_init(struct rumpclient_f |
|
|
|
if (doinit() == -1) |
if (doinit() == -1) |
return -1; |
return -1; |
if (doconnect(false) == -1) |
if (doconnect() == -1) |
return -1; |
return -1; |
|
|
error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth, |
error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth, |
Line 873 rumpclient_fork_init(struct rumpclient_f |
|
Line 984 rumpclient_fork_init(struct rumpclient_f |
|
return 0; |
return 0; |
} |
} |
|
|
|
/*ARGSUSED*/ |
void |
void |
rumpclient_fork_cancel(struct rumpclient_fork *rpf) |
rumpclient_fork_cancel(struct rumpclient_fork *rpf) |
{ |
{ |
Line 921 rumpclient__closenotify(int *fdp, enum r |
|
Line 1033 rumpclient__closenotify(int *fdp, enum r |
|
case RUMPCLIENT_CLOSE_CLOSE: |
case RUMPCLIENT_CLOSE_CLOSE: |
case RUMPCLIENT_CLOSE_DUP2: |
case RUMPCLIENT_CLOSE_DUP2: |
if (fd == clispc.spc_fd) { |
if (fd == clispc.spc_fd) { |
struct kevent kev[2]; |
|
|
|
newfd = dupgood(clispc.spc_fd, 1); |
newfd = dupgood(clispc.spc_fd, 1); |
if (newfd == -1) |
if (newfd == -1) |
return -1; |
return -1; |
|
|
|
#ifdef USE_KQUEUE |
|
{ |
|
struct kevent kev[2]; |
|
|
/* |
/* |
* now, we have a new socket number, so change |
* now, we have a new socket number, so change |
* the file descriptor that kqueue is |
* the file descriptor that kqueue is |
Line 942 rumpclient__closenotify(int *fdp, enum r |
|
Line 1057 rumpclient__closenotify(int *fdp, enum r |
|
return -1; |
return -1; |
} |
} |
clispc.spc_fd = newfd; |
clispc.spc_fd = newfd; |
|
} |
} |
} |
if (fd == kq) { |
if (fd == kq) { |
newfd = dupgood(kq, 1); |
newfd = dupgood(kq, 1); |
if (newfd == -1) |
if (newfd == -1) |
return -1; |
return -1; |
kq = newfd; |
kq = newfd; |
|
#else /* USE_KQUEUE */ |
|
clispc.spc_fd = newfd; |
|
#endif /* !USE_KQUEUE */ |
} |
} |
break; |
break; |
} |
} |
Line 956 rumpclient__closenotify(int *fdp, enum r |
|
Line 1075 rumpclient__closenotify(int *fdp, enum r |
|
} |
} |
|
|
pid_t |
pid_t |
rumpclient_fork() |
rumpclient_fork(void) |
{ |
{ |
|
|
return rumpclient__dofork(fork); |
return rumpclient__dofork(fork); |