version 1.42, 2011/03/08 18:28:01 |
version 1.51.2.3, 2014/08/20 00:02:20 |
|
|
* Client side routines for rump syscall proxy. |
* Client side routines for rump syscall proxy. |
*/ |
*/ |
|
|
#include <sys/cdefs.h> |
#include <rump/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. On Linux, we use signalfd in the same role |
|
* as kqueue on NetBSD to be able to take signals while waiting for a |
|
* response from the server. |
|
*/ |
|
|
|
#ifdef __NetBSD__ |
|
#define USE_KQUEUE |
|
#endif |
|
#if defined(__linux__) && !defined(__ANDROID__) |
|
#define USE_SIGNALFD |
|
#endif |
|
|
__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 67 __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 <poll.h> |
#include <poll.h> |
#include <pthread.h> |
#include <pthread.h> |
#include <signal.h> |
#include <signal.h> |
Line 64 int (*host_socket)(int, int, int); |
|
Line 86 int (*host_socket)(int, int, int); |
|
int (*host_close)(int); |
int (*host_close)(int); |
int (*host_connect)(int, const struct sockaddr *, socklen_t); |
int (*host_connect)(int, const struct sockaddr *, socklen_t); |
int (*host_fcntl)(int, int, ...); |
int (*host_fcntl)(int, int, ...); |
|
#ifdef __ANDROID__ |
|
int (*host_poll)(struct pollfd *, nfds_t, long); |
|
#else |
int (*host_poll)(struct pollfd *, nfds_t, int); |
int (*host_poll)(struct pollfd *, nfds_t, int); |
|
#endif |
ssize_t (*host_read)(int, void *, size_t); |
ssize_t (*host_read)(int, void *, size_t); |
|
#ifdef __ANDROID__ |
|
int (*host_sendmsg)(int, const struct msghdr *, unsigned int); |
|
#else |
ssize_t (*host_sendmsg)(int, const struct msghdr *, int); |
ssize_t (*host_sendmsg)(int, const struct msghdr *, int); |
|
#endif |
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 |
|
|
|
#ifdef USE_SIGNALFD |
|
#include <sys/signalfd.h> |
|
|
|
int (*host_signalfd)(int, const sigset_t *, int); |
|
#endif |
|
|
int (*host_execve)(const char *, char *const[], char *const[]); |
int (*host_execve)(const char *, char *const[], char *const[]); |
|
|
#include "sp_common.c" |
#include "sp_common.c" |
|
#include "rumpuser_sigtrans.c" |
|
|
static struct spclient clispc = { |
static struct spclient clispc = { |
.spc_fd = -1, |
.spc_fd = -1, |
}; |
}; |
|
|
static int kq = -1; |
static int holyfd = -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 133 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, struct iovec *iov, size_t iovlen) |
send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen) |
{ |
{ |
Line 111 send_with_recon(struct spclient *spc, st |
|
Line 153 send_with_recon(struct spclient *spc, st |
|
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 132 send_with_recon(struct spclient *spc, st |
|
Line 174 send_with_recon(struct spclient *spc, st |
|
|
|
/* check that we aren't over the limit */ |
/* check that we aren't over the limit */ |
if (retrytimo > 0) { |
if (retrytimo > 0) { |
struct timeval tmp; |
time_t tdiff; |
|
|
gettimeofday(&curtime, NULL); |
gettimeofday(&curtime, NULL); |
timersub(&curtime, &starttime, &tmp); |
tdiff = curtime.tv_sec - starttime.tv_sec; |
if (tmp.tv_sec >= retrytimo) { |
if (starttime.tv_usec > curtime.tv_usec) |
|
tdiff--; |
|
if (tdiff >= retrytimo) { |
fprintf(stderr, "rump_sp: reconnect " |
fprintf(stderr, "rump_sp: reconnect " |
"failed, %lld second timeout\n", |
"failed, %lld second timeout\n", |
(long long)retrytimo); |
(long long)retrytimo); |
Line 152 send_with_recon(struct spclient *spc, st |
|
Line 196 send_with_recon(struct spclient *spc, st |
|
} |
} |
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 238 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; ) { |
|
#ifdef USE_KQUEUE |
|
struct kevent kev[8]; |
|
int i; |
|
|
/* |
/* |
* typically we don't have a frame waiting |
* typically we don't have a frame waiting |
* when we come in here, so call kevent now |
* when we come in here, so call kevent now |
*/ |
*/ |
rv = host_kevent(kq, NULL, 0, |
rv = host_kevent(holyfd, NULL, 0, |
kev, __arraycount(kev), NULL); |
kev, __arraycount(kev), NULL); |
|
|
if (__predict_false(rv == -1)) { |
if (__predict_false(rv == -1)) { |
Line 236 cliwaitresp(struct spclient *spc, struct |
|
Line 283 cliwaitresp(struct spclient *spc, struct |
|
* determine what happens next. |
* determine what happens next. |
*/ |
*/ |
activity: |
activity: |
|
#else /* !USE_KQUEUE */ |
|
struct pollfd pfd[2]; |
|
|
|
pfd[0].fd = clispc.spc_fd; |
|
pfd[0].events = POLLIN; |
|
pfd[1].fd = holyfd; |
|
pfd[1].events = POLLIN; |
|
|
|
rv = host_poll(pfd, 2, -1); |
|
if (rv >= 1 && pfd[1].revents & POLLIN) { |
|
dosig = 1; |
|
goto cleanup; |
|
} |
|
#endif /* !USE_KQUEUE */ |
|
|
switch (readframe(spc)) { |
switch (readframe(spc)) { |
case 0: |
case 0: |
continue; |
continue; |
Line 329 handshake_req(struct spclient *spc, int |
|
Line 391 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; |
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; |
Line 340 handshake_req(struct spclient *spc, int |
|
Line 402 handshake_req(struct spclient *spc, int |
|
if (type == HANDSHAKE_FORK) { |
if (type == HANDSHAKE_FORK) { |
bonus = sizeof(rf); |
bonus = sizeof(rf); |
} else { |
} else { |
|
#ifdef __NetBSD__ |
|
/* would procfs work on NetBSD too? */ |
myprogname = getprogname(); |
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; |
bonus = strlen(myprogname)+1; |
} |
} |
|
|
Line 362 handshake_req(struct spclient *spc, int |
|
Line 447 handshake_req(struct spclient *spc, int |
|
rf.rf_cancel = cancel; |
rf.rf_cancel = cancel; |
IOVPUT(iov[1], rf); |
IOVPUT(iov[1], rf); |
} else { |
} else { |
IOVPUT_WITHSIZE(iov[1], __UNCONST(getprogname()), bonus); |
IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus); |
} |
} |
rv = send_with_recon(spc, iov, __arraycount(iov)); |
rv = send_with_recon(spc, iov, __arraycount(iov)); |
if (rv || cancel) { |
if (rv || cancel) { |
Line 528 handlereq(struct spclient *spc) |
|
Line 613 handlereq(struct spclient *spc) |
|
void *mapaddr; |
void *mapaddr; |
size_t maplen; |
size_t maplen; |
int reqtype = spc->spc_hdr.rsp_type; |
int reqtype = spc->spc_hdr.rsp_type; |
|
int sig; |
|
|
switch (reqtype) { |
switch (reqtype) { |
case RUMPSP_COPYIN: |
case RUMPSP_COPYIN: |
Line 554 handlereq(struct spclient *spc) |
|
Line 640 handlereq(struct spclient *spc) |
|
/*LINTED*/ |
/*LINTED*/ |
maplen = *(size_t *)spc->spc_buf; |
maplen = *(size_t *)spc->spc_buf; |
mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, |
mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE, |
MAP_ANON, -1, 0); |
MAP_ANON|MAP_PRIVATE, -1, 0); |
if (mapaddr == MAP_FAILED) |
if (mapaddr == MAP_FAILED) |
mapaddr = NULL; |
mapaddr = NULL; |
DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr)); |
DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr)); |
send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr); |
send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr); |
break; |
break; |
case RUMPSP_RAISE: |
case RUMPSP_RAISE: |
DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo)); |
sig = rumpuser__sig_rump2host(rhdr->rsp_signo); |
raise((int)rhdr->rsp_signo); |
DPRINTF(("rump_sp handlereq: raise sig %d\n", sig)); |
|
raise(sig); |
/* |
/* |
* We most likely have signals blocked, but the signal |
* We most likely have signals blocked, but the signal |
* will be handled soon enough when we return. |
* will be handled soon enough when we return. |
|
|
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 597 dupgood(int myfd, int mustchange) |
|
Line 685 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; |
} |
} |
|
|
|
#if defined(USE_KQUEUE) |
|
|
|
static int |
|
makeholyfd(void) |
|
{ |
|
struct kevent kev[NSIG+1]; |
|
int i, fd; |
|
|
|
/* setup kqueue, we want all signals and the fd */ |
|
if ((fd = dupgood(host_kqueue(), 0)) == -1) { |
|
ERRLOG(("rump_sp: cannot setup kqueue")); |
|
return -1; |
|
} |
|
|
|
for (i = 0; i < NSIG; i++) { |
|
EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); |
|
} |
|
EV_SET(&kev[NSIG], clispc.spc_fd, |
|
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
|
if (host_kevent(fd, kev, NSIG+1, NULL, 0, NULL) == -1) { |
|
ERRLOG(("rump_sp: kevent() failed")); |
|
host_close(fd); |
|
return -1; |
|
} |
|
|
|
return fd; |
|
} |
|
|
|
#elif defined(USE_SIGNALFD) /* !USE_KQUEUE */ |
|
|
|
static int |
|
makeholyfd(void) |
|
{ |
|
|
|
return host_signalfd(-1, &fullset, 0); |
|
} |
|
|
|
#else /* !USE_KQUEUE && !USE_SIGNALFD */ |
|
|
|
static int |
|
makeholyfd(void) |
|
{ |
|
|
|
return -1; |
|
} |
|
|
|
#endif |
|
|
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 (holyfd != -1) |
host_close(kq); |
host_close(holyfd); |
kq = -1; |
holyfd = -1; |
s = -1; |
s = -1; |
|
|
if (clispc.spc_fd != -1) |
if (clispc.spc_fd != -1) |
Line 655 doconnect(bool noisy) |
|
Line 796 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; |
|
holyfd = makeholyfd(); |
/* setup kqueue, we want all signals and the fd */ |
|
if ((kq = dupgood(host_kqueue(), 0)) == -1) { |
|
error = errno; |
|
if (noisy) |
|
fprintf(stderr, "rump_sp: cannot setup kqueue"); |
|
errno = error; |
|
return -1; |
|
} |
|
|
|
for (i = 0; i < NSIG; i++) { |
|
EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); |
|
} |
|
EV_SET(&kev[NSIG], clispc.spc_fd, |
|
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
|
if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) { |
|
error = errno; |
|
if (noisy) |
|
fprintf(stderr, "rump_sp: kevent() failed"); |
|
errno = error; |
|
return -1; |
|
} |
|
|
|
return 0; |
return 0; |
} |
} |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
#ifdef RTLD_NEXT |
void *rumpclient__dlsym(void *, const char *); |
void *rumpclient__dlsym(void *, const char *); |
void *rumphijack_dlsym(void *, const char *); |
|
void * |
void * |
rumpclient__dlsym(void *handle, const char *symbol) |
rumpclient__dlsym(void *handle, const char *symbol) |
{ |
{ |
|
|
return dlsym(handle, symbol); |
return dlsym(handle, symbol); |
} |
} |
__weak_alias(rumphijack_dlsym,rumpclient__dlsym); |
void *rumphijack_dlsym(void *, const char *) |
|
__attribute__((__weak__, alias("rumpclient__dlsym"))); |
|
#endif |
|
|
static pid_t init_done = 0; |
static pid_t init_done = 0; |
|
|
int |
int |
rumpclient_init() |
rumpclient_init(void) |
{ |
{ |
char *p; |
char *p; |
int error; |
int error; |
Line 772 rumpclient_init() |
|
Line 878 rumpclient_init() |
|
if (init_done == (mypid = getpid())) |
if (init_done == (mypid = getpid())) |
return 0; |
return 0; |
|
|
|
#ifdef USE_KQUEUE |
/* kq does not traverse fork() */ |
/* kq does not traverse fork() */ |
if (init_done != 0) |
holyfd = -1; |
kq = -1; |
#endif |
init_done = mypid; |
init_done = mypid; |
|
|
sigfillset(&fullset); |
sigfillset(&fullset); |
|
|
/* |
/* |
* 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? |
*/ |
*/ |
|
#ifdef RTLD_NEXT |
#define FINDSYM2(_name_,_syscall_) \ |
#define FINDSYM2(_name_,_syscall_) \ |
if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ |
if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \ |
#_syscall_)) == NULL) { \ |
#_syscall_)) == NULL) { \ |
if (rumphijack_dlsym == rumpclient__dlsym) \ |
if (rumphijack_dlsym == rumpclient__dlsym) \ |
host_##_name_ = _name_; /* static fallback */ \ |
host_##_name_ = _name_; /* static fallback */ \ |
if (host_##_name_ == NULL) \ |
if (host_##_name_ == NULL) { \ |
errx(1, "cannot find %s: %s", #_syscall_, \ |
fprintf(stderr,"cannot find %s: %s", #_syscall_,\ |
dlerror()); \ |
dlerror()); \ |
|
exit(1); \ |
|
} \ |
} |
} |
|
#else |
|
#define FINDSYM2(_name_,_syscall) \ |
|
host_##_name_ = _name_; |
|
#endif |
#define FINDSYM(_name_) FINDSYM2(_name_,_name_) |
#define FINDSYM(_name_) FINDSYM2(_name_,_name_) |
|
#ifdef __NetBSD__ |
FINDSYM2(socket,__socket30) |
FINDSYM2(socket,__socket30) |
|
#else |
|
FINDSYM(socket) |
|
#endif |
|
|
FINDSYM(close) |
FINDSYM(close) |
FINDSYM(connect) |
FINDSYM(connect) |
FINDSYM(fcntl) |
FINDSYM(fcntl) |
Line 802 rumpclient_init() |
|
Line 921 rumpclient_init() |
|
FINDSYM(sendmsg) |
FINDSYM(sendmsg) |
FINDSYM(setsockopt) |
FINDSYM(setsockopt) |
FINDSYM(dup) |
FINDSYM(dup) |
FINDSYM(kqueue) |
|
FINDSYM(execve) |
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 */ |
|
|
|
#ifdef USE_SIGNALFD |
|
FINDSYM(signalfd) |
|
#endif |
|
|
#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 828 rumpclient_init() |
|
Line 956 rumpclient_init() |
|
goto out; |
goto out; |
|
|
if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) { |
if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) { |
sscanf(p, "%d,%d", &clispc.spc_fd, &kq); |
sscanf(p, "%d,%d", &clispc.spc_fd, &holyfd); |
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 857 rumpclient_init() |
|
Line 985 rumpclient_init() |
|
struct rumpclient_fork { |
struct rumpclient_fork { |
uint32_t fork_auth[AUTHLEN]; |
uint32_t fork_auth[AUTHLEN]; |
struct spclient fork_spc; |
struct spclient fork_spc; |
int fork_kq; |
int fork_holyfd; |
}; |
}; |
|
|
struct rumpclient_fork * |
struct rumpclient_fork * |
Line 884 rumpclient_prefork(void) |
|
Line 1012 rumpclient_prefork(void) |
|
free(resp); |
free(resp); |
|
|
rpf->fork_spc = clispc; |
rpf->fork_spc = clispc; |
rpf->fork_kq = kq; |
rpf->fork_holyfd = holyfd; |
|
|
out: |
out: |
pthread_sigmask(SIG_SETMASK, &omask, NULL); |
pthread_sigmask(SIG_SETMASK, &omask, NULL); |
Line 901 rumpclient_fork_init(struct rumpclient_f |
|
Line 1029 rumpclient_fork_init(struct rumpclient_f |
|
memset(&clispc, 0, sizeof(clispc)); |
memset(&clispc, 0, sizeof(clispc)); |
clispc.spc_fd = osock; |
clispc.spc_fd = osock; |
|
|
kq = -1; /* kqueue descriptor is not copied over fork() */ |
#ifdef USE_KQUEUE |
|
holyfd = -1; /* kqueue descriptor is not copied over fork() */ |
|
#else |
|
if (holyfd != -1) { |
|
host_close(holyfd); |
|
holyfd = -1; |
|
} |
|
#endif |
|
|
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 933 rumpclient_fork_vparent(struct rumpclien |
|
Line 1068 rumpclient_fork_vparent(struct rumpclien |
|
{ |
{ |
|
|
clispc = rpf->fork_spc; |
clispc = rpf->fork_spc; |
kq = rpf->fork_kq; |
holyfd = rpf->fork_holyfd; |
} |
} |
|
|
void |
void |
Line 955 rumpclient__closenotify(int *fdp, enum r |
|
Line 1090 rumpclient__closenotify(int *fdp, enum r |
|
|
|
switch (variant) { |
switch (variant) { |
case RUMPCLIENT_CLOSE_FCLOSEM: |
case RUMPCLIENT_CLOSE_FCLOSEM: |
untilfd = MAX(clispc.spc_fd, kq); |
untilfd = MAX(clispc.spc_fd, holyfd); |
for (; fd <= untilfd; fd++) { |
for (; fd <= untilfd; fd++) { |
if (fd == clispc.spc_fd || fd == kq) |
if (fd == clispc.spc_fd || fd == holyfd) |
continue; |
continue; |
rv = host_close(fd); |
rv = host_close(fd); |
if (rv == -1) |
if (rv == -1) |
Line 969 rumpclient__closenotify(int *fdp, enum r |
|
Line 1104 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 983 rumpclient__closenotify(int *fdp, enum r |
|
Line 1121 rumpclient__closenotify(int *fdp, enum r |
|
EVFILT_READ, EV_DELETE, 0, 0, 0); |
EVFILT_READ, EV_DELETE, 0, 0, 0); |
EV_SET(&kev[1], newfd, |
EV_SET(&kev[1], newfd, |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); |
if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) { |
if (host_kevent(holyfd, kev, 2, NULL, 0, NULL) == -1) { |
int sverrno = errno; |
int sverrno = errno; |
host_close(newfd); |
host_close(newfd); |
errno = sverrno; |
errno = sverrno; |
return -1; |
return -1; |
} |
}} |
|
#endif /* !USE_KQUEUE */ |
clispc.spc_fd = newfd; |
clispc.spc_fd = newfd; |
} |
} |
if (fd == kq) { |
if (holyfd != -1 && fd == holyfd) { |
newfd = dupgood(kq, 1); |
newfd = dupgood(holyfd, 1); |
if (newfd == -1) |
if (newfd == -1) |
return -1; |
return -1; |
kq = newfd; |
holyfd = newfd; |
} |
} |
break; |
break; |
} |
} |
Line 1004 rumpclient__closenotify(int *fdp, enum r |
|
Line 1143 rumpclient__closenotify(int *fdp, enum r |
|
} |
} |
|
|
pid_t |
pid_t |
rumpclient_fork() |
rumpclient_fork(void) |
{ |
{ |
|
|
return rumpclient__dofork(fork); |
return rumpclient__dofork(fork); |
Line 1026 rumpclient_exec(const char *path, char * |
|
Line 1165 rumpclient_exec(const char *path, char * |
|
int rv, sverrno; |
int rv, sverrno; |
|
|
snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d", |
snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d", |
clispc.spc_fd, kq); |
clispc.spc_fd, holyfd); |
envstr = malloc(strlen(buf)+1); |
envstr = malloc(strlen(buf)+1); |
if (envstr == NULL) { |
if (envstr == NULL) { |
return ENOMEM; |
return ENOMEM; |
Line 1073 rumpclient_exec(const char *path, char * |
|
Line 1212 rumpclient_exec(const char *path, char * |
|
return rv; |
return rv; |
} |
} |
|
|
|
/* |
|
* daemon() is handwritten for the benefit of platforms which |
|
* do not support daemon(). |
|
*/ |
int |
int |
rumpclient_daemon(int nochdir, int noclose) |
rumpclient_daemon(int nochdir, int noclose) |
{ |
{ |
Line 1082 rumpclient_daemon(int nochdir, int noclo |
|
Line 1225 rumpclient_daemon(int nochdir, int noclo |
|
if ((rf = rumpclient_prefork()) == NULL) |
if ((rf = rumpclient_prefork()) == NULL) |
return -1; |
return -1; |
|
|
if (daemon(nochdir, noclose) == -1) { |
switch (fork()) { |
sverrno = errno; |
case 0: |
rumpclient_fork_cancel(rf); |
break; |
errno = sverrno; |
case -1: |
return -1; |
goto daemonerr; |
|
default: |
|
_exit(0); |
|
} |
|
|
|
if (setsid() == -1) |
|
goto daemonerr; |
|
if (!nochdir && chdir("/") == -1) |
|
goto daemonerr; |
|
if (!noclose) { |
|
int fd = open("/dev/null", O_RDWR); |
|
dup2(fd, 0); |
|
dup2(fd, 1); |
|
dup2(fd, 2); |
|
if (fd > 2) |
|
close(fd); |
} |
} |
|
|
|
/* note: fork is either completed or cancelled by the call */ |
if (rumpclient_fork_init(rf) == -1) |
if (rumpclient_fork_init(rf) == -1) |
return -1; |
return -1; |
|
|
return 0; |
return 0; |
|
|
|
daemonerr: |
|
sverrno = errno; |
|
rumpclient_fork_cancel(rf); |
|
errno = sverrno; |
|
return -1; |
} |
} |