1*fb68413fSrin /* $NetBSD: rumpclient.c,v 1.71 2023/07/31 04:37:04 rin Exp $ */
26b1f3dc0Spooka
36b1f3dc0Spooka /*
4fd993ea3Spooka * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
56b1f3dc0Spooka *
66b1f3dc0Spooka * Redistribution and use in source and binary forms, with or without
76b1f3dc0Spooka * modification, are permitted provided that the following conditions
86b1f3dc0Spooka * are met:
96b1f3dc0Spooka * 1. Redistributions of source code must retain the above copyright
106b1f3dc0Spooka * notice, this list of conditions and the following disclaimer.
116b1f3dc0Spooka * 2. Redistributions in binary form must reproduce the above copyright
126b1f3dc0Spooka * notice, this list of conditions and the following disclaimer in the
136b1f3dc0Spooka * documentation and/or other materials provided with the distribution.
146b1f3dc0Spooka *
156b1f3dc0Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
166b1f3dc0Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
176b1f3dc0Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
186b1f3dc0Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196b1f3dc0Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206b1f3dc0Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
216b1f3dc0Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226b1f3dc0Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236b1f3dc0Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246b1f3dc0Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256b1f3dc0Spooka * SUCH DAMAGE.
266b1f3dc0Spooka */
276b1f3dc0Spooka
286b1f3dc0Spooka /*
296b1f3dc0Spooka * Client side routines for rump syscall proxy.
306b1f3dc0Spooka */
316b1f3dc0Spooka
320f188198Spooka #include <rump/rumpuser_port.h>
33fa3922beSpooka
34fa3922beSpooka /*
3561b4fed9Sjustin * We use kqueue on the BSDs, poll elsewhere. We
36fa3922beSpooka * want to use kqueue because it will give us the ability to get signal
37fa3922beSpooka * notifications but defer their handling to a stage where we do not
38fa3922beSpooka * hold the communication lock. Taking a signal while holding on to
39fa3922beSpooka * that lock may cause a deadlock. Therefore, block signals throughout
4090c25cb3Spooka * the RPC when using poll. On Linux, we use signalfd in the same role
4190c25cb3Spooka * as kqueue on NetBSD to be able to take signals while waiting for a
4290c25cb3Spooka * response from the server.
43fa3922beSpooka */
44fa3922beSpooka
4561b4fed9Sjustin #if defined(__NetBSD__) || defined(__FreeBSD__) || \
4661b4fed9Sjustin defined(__DragonFly__) || defined(__OpenBSD__)
47fa3922beSpooka #define USE_KQUEUE
48fa3922beSpooka #endif
497b800c0cSjustin #if defined(__linux__)
5090c25cb3Spooka #define USE_SIGNALFD
5190c25cb3Spooka #endif
52fa3922beSpooka
53*fb68413fSrin __RCSID("$NetBSD: rumpclient.c,v 1.71 2023/07/31 04:37:04 rin Exp $");
546b1f3dc0Spooka
556b71288cSpooka #include <sys/param.h>
566b1f3dc0Spooka #include <sys/mman.h>
576b1f3dc0Spooka #include <sys/socket.h>
58fa3922beSpooka #include <sys/time.h>
59fa3922beSpooka
60fa3922beSpooka #ifdef USE_KQUEUE
61fa3922beSpooka #include <sys/event.h>
62fa3922beSpooka #endif
636b1f3dc0Spooka
646b1f3dc0Spooka #include <arpa/inet.h>
656b1f3dc0Spooka #include <netinet/in.h>
666b1f3dc0Spooka #include <netinet/tcp.h>
676b1f3dc0Spooka
686b1f3dc0Spooka #include <assert.h>
6991aad9bdSpooka #include <dlfcn.h>
706b1f3dc0Spooka #include <errno.h>
716b1f3dc0Spooka #include <fcntl.h>
726b1f3dc0Spooka #include <poll.h>
736b1f3dc0Spooka #include <pthread.h>
74fd993ea3Spooka #include <signal.h>
756b1f3dc0Spooka #include <stdarg.h>
7619a57922Spooka #include <stdbool.h>
776b1f3dc0Spooka #include <stdio.h>
786b1f3dc0Spooka #include <stdlib.h>
796b1f3dc0Spooka #include <string.h>
806b1f3dc0Spooka #include <unistd.h>
816b1f3dc0Spooka
826b1f3dc0Spooka #include <rump/rumpclient.h>
836b1f3dc0Spooka
8491aad9bdSpooka #define HOSTOPS
8591aad9bdSpooka int (*host_socket)(int, int, int);
8691aad9bdSpooka int (*host_close)(int);
8791aad9bdSpooka int (*host_connect)(int, const struct sockaddr *, socklen_t);
885064fa59Spooka int (*host_fcntl)(int, int, ...);
8991aad9bdSpooka int (*host_poll)(struct pollfd *, nfds_t, int);
9091aad9bdSpooka ssize_t (*host_read)(int, void *, size_t);
9100e34b22Spooka ssize_t (*host_sendmsg)(int, const struct msghdr *, int);
9291aad9bdSpooka int (*host_setsockopt)(int, int, int, const void *, socklen_t);
9382aa8837Spooka int (*host_dup)(int);
9491aad9bdSpooka
95fa3922beSpooka #ifdef USE_KQUEUE
967d6e6b81Spooka int (*host_kqueue)(void);
977e80a07cSjustin #ifdef __NetBSD__
987d6e6b81Spooka int (*host_kevent)(int, const struct kevent *, size_t,
997d6e6b81Spooka struct kevent *, size_t, const struct timespec *);
1007e80a07cSjustin #else
1017e80a07cSjustin int (*host_kevent)(int, const struct kevent *, int,
1027e80a07cSjustin struct kevent *, int, const struct timespec *);
1037e80a07cSjustin #endif
104fa3922beSpooka #endif
1057d6e6b81Spooka
10690c25cb3Spooka #ifdef USE_SIGNALFD
10790c25cb3Spooka #include <sys/signalfd.h>
10890c25cb3Spooka
10990c25cb3Spooka int (*host_signalfd)(int, const sigset_t *, int);
11090c25cb3Spooka #endif
11190c25cb3Spooka
112f4ba3dcdSpooka int (*host_execve)(const char *, char *const[], char *const[]);
113f4ba3dcdSpooka
1146b1f3dc0Spooka #include "sp_common.c"
115437e54a7Spooka #include "rumpuser_sigtrans.c"
1166b1f3dc0Spooka
117fd993ea3Spooka static struct spclient clispc = {
118fd993ea3Spooka .spc_fd = -1,
119fd993ea3Spooka };
1206b1f3dc0Spooka
121e8083ecfSpooka static int holyfd = -1;
122c45d9404Spooka static sigset_t fullset;
1235064fa59Spooka
124754d118eSpooka static int doconnect(void);
1255e301bc4Spooka static int handshake_req(struct spclient *, int, void *, int, bool);
12619a57922Spooka
1272e577637Spooka /*
1282e577637Spooka * Default: don't retry. Most clients can't handle it
1292e577637Spooka * (consider e.g. fds suddenly going missing).
1302e577637Spooka */
1312e577637Spooka static time_t retrytimo = 0;
13219a57922Spooka
133754d118eSpooka /* always defined to nothingness for now */
134754d118eSpooka #define ERRLOG(a)
135754d118eSpooka
136c45d9404Spooka static int
send_with_recon(struct spclient * spc,struct iovec * iov,size_t iovlen)13700e34b22Spooka send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen)
138c45d9404Spooka {
13941434db3Spooka struct timeval starttime, curtime;
14041434db3Spooka time_t prevreconmsg;
14141434db3Spooka unsigned reconretries;
14219a57922Spooka int rv;
14319a57922Spooka
14441434db3Spooka for (prevreconmsg = 0, reconretries = 0;;) {
14500e34b22Spooka rv = dosend(spc, iov, iovlen);
14619a57922Spooka if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
14741434db3Spooka /* no persistent connections */
1482e577637Spooka if (retrytimo == 0) {
1492e577637Spooka rv = ENOTCONN;
15041434db3Spooka break;
1512e577637Spooka }
152065ac12bSpooka if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
153a7f29797Spooka _exit(1);
15441434db3Spooka
15541434db3Spooka if (!prevreconmsg) {
15641434db3Spooka prevreconmsg = time(NULL);
15741434db3Spooka gettimeofday(&starttime, NULL);
15841434db3Spooka }
15941434db3Spooka if (reconretries == 1) {
16041434db3Spooka if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
16119a57922Spooka rv = ENOTCONN;
16219a57922Spooka break;
16319a57922Spooka }
16441434db3Spooka fprintf(stderr, "rump_sp: connection to "
16541434db3Spooka "kernel lost, trying to reconnect ...\n");
16641434db3Spooka } else if (time(NULL) - prevreconmsg > 120) {
16741434db3Spooka fprintf(stderr, "rump_sp: still trying to "
16841434db3Spooka "reconnect ...\n");
16941434db3Spooka prevreconmsg = time(NULL);
17041434db3Spooka }
17141434db3Spooka
17241434db3Spooka /* check that we aren't over the limit */
17341434db3Spooka if (retrytimo > 0) {
17456665b94Spooka time_t tdiff;
17541434db3Spooka
17641434db3Spooka gettimeofday(&curtime, NULL);
17756665b94Spooka tdiff = curtime.tv_sec - starttime.tv_sec;
17856665b94Spooka if (starttime.tv_usec > curtime.tv_usec)
17956665b94Spooka tdiff--;
18056665b94Spooka if (tdiff >= retrytimo) {
18141434db3Spooka fprintf(stderr, "rump_sp: reconnect "
18241434db3Spooka "failed, %lld second timeout\n",
18341434db3Spooka (long long)retrytimo);
18441434db3Spooka return ENOTCONN;
18541434db3Spooka }
18641434db3Spooka }
18741434db3Spooka
18841434db3Spooka /* adhoc backoff timer */
18941434db3Spooka if (reconretries < 10) {
19041434db3Spooka usleep(100000 * reconretries);
19141434db3Spooka } else {
19241434db3Spooka sleep(MIN(10, reconretries-9));
19341434db3Spooka }
19441434db3Spooka reconretries++;
19541434db3Spooka
196754d118eSpooka if ((rv = doconnect()) != 0)
19741434db3Spooka continue;
1985e301bc4Spooka if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
1995e301bc4Spooka NULL, 0, true)) != 0)
20041434db3Spooka continue;
20141434db3Spooka
20241434db3Spooka /*
203b5860281Sandvar * ok, reconnect successful. we need to return to
20441434db3Spooka * the upper layer to get the entire PDU resent.
20541434db3Spooka */
20641434db3Spooka if (reconretries != 1)
20741434db3Spooka fprintf(stderr, "rump_sp: reconnected!\n");
20841434db3Spooka rv = EAGAIN;
20941434db3Spooka break;
21041434db3Spooka } else {
21141434db3Spooka _DIAGASSERT(errno != EAGAIN);
21241434db3Spooka break;
21341434db3Spooka }
21441434db3Spooka }
21519a57922Spooka
21619a57922Spooka return rv;
21719a57922Spooka }
21819a57922Spooka
21919a57922Spooka static int
cliwaitresp(struct spclient * spc,struct respwait * rw,sigset_t * mask,bool keeplock)22019a57922Spooka cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
22119a57922Spooka bool keeplock)
22219a57922Spooka {
22319a57922Spooka uint64_t mygen;
22419a57922Spooka bool imalive = true;
225c45d9404Spooka
2265064fa59Spooka pthread_mutex_lock(&spc->spc_mtx);
22719a57922Spooka if (!keeplock)
228c45d9404Spooka sendunlockl(spc);
22919a57922Spooka mygen = spc->spc_generation;
230c45d9404Spooka
231c45d9404Spooka rw->rw_error = 0;
23219a57922Spooka while (!rw->rw_done && rw->rw_error == 0) {
23319a57922Spooka if (__predict_false(spc->spc_generation != mygen || !imalive))
23419a57922Spooka break;
23519a57922Spooka
236c45d9404Spooka /* are we free to receive? */
237c45d9404Spooka if (spc->spc_istatus == SPCSTATUS_FREE) {
238fa3922beSpooka int gotresp, dosig, rv;
2395064fa59Spooka
240c45d9404Spooka spc->spc_istatus = SPCSTATUS_BUSY;
241c45d9404Spooka pthread_mutex_unlock(&spc->spc_mtx);
242c45d9404Spooka
2435064fa59Spooka dosig = 0;
2445064fa59Spooka for (gotresp = 0; !gotresp; ) {
245fa3922beSpooka #ifdef USE_KQUEUE
246fa3922beSpooka struct kevent kev[8];
247fa3922beSpooka int i;
248fa3922beSpooka
2497905447eSpooka /*
2507905447eSpooka * typically we don't have a frame waiting
2517905447eSpooka * when we come in here, so call kevent now
2527905447eSpooka */
25390c25cb3Spooka rv = host_kevent(holyfd, NULL, 0,
2545064fa59Spooka kev, __arraycount(kev), NULL);
25519a57922Spooka
2562ba7fe55Spooka if (__predict_false(rv == -1)) {
2577905447eSpooka goto activity;
2582ba7fe55Spooka }
2592ba7fe55Spooka
26019a57922Spooka /*
2617905447eSpooka * XXX: don't know how this can happen
2627905447eSpooka * (timeout cannot expire since there
2637905447eSpooka * isn't one), but it does happen.
2647905447eSpooka * treat it as an expectional condition
2657905447eSpooka * and go through tryread to determine
2667905447eSpooka * alive status.
26719a57922Spooka */
26819a57922Spooka if (__predict_false(rv == 0))
2697905447eSpooka goto activity;
27019a57922Spooka
2715064fa59Spooka for (i = 0; i < rv; i++) {
2727905447eSpooka if (kev[i].filter == EVFILT_SIGNAL)
2735064fa59Spooka dosig++;
2745064fa59Spooka }
2755064fa59Spooka if (dosig)
2765064fa59Spooka goto cleanup;
2775064fa59Spooka
2787905447eSpooka /*
2797905447eSpooka * ok, activity. try to read a frame to
2807905447eSpooka * determine what happens next.
2817905447eSpooka */
2827905447eSpooka activity:
28390c25cb3Spooka #else /* !USE_KQUEUE */
28490c25cb3Spooka struct pollfd pfd[2];
285fa3922beSpooka
28690c25cb3Spooka pfd[0].fd = clispc.spc_fd;
28790c25cb3Spooka pfd[0].events = POLLIN;
28890c25cb3Spooka pfd[1].fd = holyfd;
28990c25cb3Spooka pfd[1].events = POLLIN;
290fa3922beSpooka
29190c25cb3Spooka rv = host_poll(pfd, 2, -1);
292d9bf6db7Spooka if (rv >= 1 && pfd[1].revents & POLLIN) {
29390c25cb3Spooka dosig = 1;
29490c25cb3Spooka goto cleanup;
29590c25cb3Spooka }
296fa3922beSpooka #endif /* !USE_KQUEUE */
297fa3922beSpooka
2987905447eSpooka switch (readframe(spc)) {
2997905447eSpooka case 0:
300c45d9404Spooka continue;
301c45d9404Spooka case -1:
30219a57922Spooka imalive = false;
3035064fa59Spooka goto cleanup;
304c45d9404Spooka default:
3057905447eSpooka /* case 1 */
306c45d9404Spooka break;
307c45d9404Spooka }
308c45d9404Spooka
309c45d9404Spooka switch (spc->spc_hdr.rsp_class) {
310c45d9404Spooka case RUMPSP_RESP:
311c45d9404Spooka case RUMPSP_ERROR:
312c45d9404Spooka kickwaiter(spc);
3135064fa59Spooka gotresp = spc->spc_hdr.rsp_reqno ==
3145064fa59Spooka rw->rw_reqno;
315c45d9404Spooka break;
316c45d9404Spooka case RUMPSP_REQ:
317c45d9404Spooka handlereq(spc);
318c45d9404Spooka break;
319c45d9404Spooka default:
320c45d9404Spooka /* panic */
321c45d9404Spooka break;
322c45d9404Spooka }
3235064fa59Spooka }
324c45d9404Spooka
3255064fa59Spooka cleanup:
3265064fa59Spooka pthread_mutex_lock(&spc->spc_mtx);
3275064fa59Spooka if (spc->spc_istatus == SPCSTATUS_WANTED)
3285064fa59Spooka kickall(spc);
3295064fa59Spooka spc->spc_istatus = SPCSTATUS_FREE;
3305064fa59Spooka
3315064fa59Spooka /* take one for the team */
3325064fa59Spooka if (dosig) {
3335064fa59Spooka pthread_mutex_unlock(&spc->spc_mtx);
3345064fa59Spooka pthread_sigmask(SIG_SETMASK, mask, NULL);
3355064fa59Spooka pthread_sigmask(SIG_SETMASK, &fullset, NULL);
3365064fa59Spooka pthread_mutex_lock(&spc->spc_mtx);
3375064fa59Spooka }
338c45d9404Spooka } else {
339c45d9404Spooka spc->spc_istatus = SPCSTATUS_WANTED;
340c45d9404Spooka pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
341c45d9404Spooka }
342c45d9404Spooka }
343c45d9404Spooka TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
344c45d9404Spooka pthread_mutex_unlock(&spc->spc_mtx);
345c45d9404Spooka pthread_cond_destroy(&rw->rw_cv);
346c45d9404Spooka
34719a57922Spooka if (spc->spc_generation != mygen || !imalive) {
348c45d9404Spooka return ENOTCONN;
34919a57922Spooka }
350c45d9404Spooka return rw->rw_error;
351c45d9404Spooka }
352c45d9404Spooka
3536b1f3dc0Spooka static int
syscall_req(struct spclient * spc,sigset_t * omask,int sysnum,const void * data,size_t dlen,void ** resp)35482355571Spooka syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
35552f22b2cSpooka const void *data, size_t dlen, void **resp)
3566b1f3dc0Spooka {
3576b1f3dc0Spooka struct rsp_hdr rhdr;
35852f22b2cSpooka struct respwait rw;
35900e34b22Spooka struct iovec iov[2];
36052f22b2cSpooka int rv;
3616b1f3dc0Spooka
3626b1f3dc0Spooka rhdr.rsp_len = sizeof(rhdr) + dlen;
36352f22b2cSpooka rhdr.rsp_class = RUMPSP_REQ;
36452f22b2cSpooka rhdr.rsp_type = RUMPSP_SYSCALL;
3656b1f3dc0Spooka rhdr.rsp_sysnum = sysnum;
3666b1f3dc0Spooka
36700e34b22Spooka IOVPUT(iov[0], rhdr);
36800e34b22Spooka IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen);
36900e34b22Spooka
370d402686fSpooka do {
37152f22b2cSpooka putwait(spc, &rw, &rhdr);
37200e34b22Spooka if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) {
37319a57922Spooka unputwait(spc, &rw);
37419a57922Spooka continue;
3755e5fac56Spooka }
37652f22b2cSpooka
37782355571Spooka rv = cliwaitresp(spc, &rw, omask, false);
37841434db3Spooka if (rv == ENOTCONN)
37941434db3Spooka rv = EAGAIN;
38041434db3Spooka } while (rv == EAGAIN);
381d402686fSpooka
38252f22b2cSpooka *resp = rw.rw_data;
38352f22b2cSpooka return rv;
3846b1f3dc0Spooka }
3856b1f3dc0Spooka
3866b1f3dc0Spooka static int
handshake_req(struct spclient * spc,int type,void * data,int cancel,bool haslock)3875e301bc4Spooka handshake_req(struct spclient *spc, int type, void *data,
3885e301bc4Spooka int cancel, bool haslock)
389393eecc1Spooka {
390fd993ea3Spooka struct handshake_fork rf;
391a7f29797Spooka const char *myprogname = NULL; /* XXXgcc */
392393eecc1Spooka struct rsp_hdr rhdr;
393393eecc1Spooka struct respwait rw;
394c45d9404Spooka sigset_t omask;
395dac4423fSpooka size_t bonus;
39600e34b22Spooka struct iovec iov[2];
397393eecc1Spooka int rv;
398393eecc1Spooka
3995e301bc4Spooka if (type == HANDSHAKE_FORK) {
400dac4423fSpooka bonus = sizeof(rf);
401dac4423fSpooka } else {
402fa3922beSpooka #ifdef __NetBSD__
403fa3922beSpooka /* would procfs work on NetBSD too? */
40400e34b22Spooka myprogname = getprogname();
405fa3922beSpooka #else
406fa3922beSpooka int fd = open("/proc/self/comm", O_RDONLY);
407fa3922beSpooka if (fd == -1) {
408fa3922beSpooka myprogname = "???";
409fa3922beSpooka } else {
410fa3922beSpooka static char commname[128];
411fa3922beSpooka
412932ef25eSpooka memset(commname, 0, sizeof(commname));
413fa3922beSpooka if (read(fd, commname, sizeof(commname)) > 0) {
414fa3922beSpooka char *n;
415fa3922beSpooka
416fa3922beSpooka n = strrchr(commname, '\n');
417fa3922beSpooka if (n)
418fa3922beSpooka *n = '\0';
419fa3922beSpooka myprogname = commname;
420fa3922beSpooka } else {
421fa3922beSpooka myprogname = "???";
422fa3922beSpooka }
423fa3922beSpooka close(fd);
424fa3922beSpooka }
425fa3922beSpooka #endif
42600e34b22Spooka bonus = strlen(myprogname)+1;
427dac4423fSpooka }
428dac4423fSpooka
429393eecc1Spooka /* performs server handshake */
430dac4423fSpooka rhdr.rsp_len = sizeof(rhdr) + bonus;
431393eecc1Spooka rhdr.rsp_class = RUMPSP_REQ;
432393eecc1Spooka rhdr.rsp_type = RUMPSP_HANDSHAKE;
4335e301bc4Spooka rhdr.rsp_handshake = type;
434393eecc1Spooka
43500e34b22Spooka IOVPUT(iov[0], rhdr);
43600e34b22Spooka
437c45d9404Spooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
43819a57922Spooka if (haslock)
43919a57922Spooka putwait_locked(spc, &rw, &rhdr);
44019a57922Spooka else
441393eecc1Spooka putwait(spc, &rw, &rhdr);
4425e301bc4Spooka if (type == HANDSHAKE_FORK) {
4435e301bc4Spooka memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
444fd993ea3Spooka rf.rf_cancel = cancel;
44500e34b22Spooka IOVPUT(iov[1], rf);
446dac4423fSpooka } else {
447a7f29797Spooka IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus);
448fd993ea3Spooka }
44900e34b22Spooka rv = send_with_recon(spc, iov, __arraycount(iov));
45019a57922Spooka if (rv || cancel) {
45119a57922Spooka if (haslock)
45219a57922Spooka unputwait_locked(spc, &rw);
45319a57922Spooka else
454393eecc1Spooka unputwait(spc, &rw);
45519a57922Spooka if (cancel) {
45682355571Spooka goto out;
457393eecc1Spooka }
45819a57922Spooka } else {
45919a57922Spooka rv = cliwaitresp(spc, &rw, &omask, haslock);
46019a57922Spooka }
461393eecc1Spooka if (rv)
46282355571Spooka goto out;
463393eecc1Spooka
464393eecc1Spooka rv = *(int *)rw.rw_data;
465393eecc1Spooka free(rw.rw_data);
466393eecc1Spooka
46782355571Spooka out:
46882355571Spooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
469393eecc1Spooka return rv;
470393eecc1Spooka }
471393eecc1Spooka
472393eecc1Spooka static int
prefork_req(struct spclient * spc,sigset_t * omask,void ** resp)47382355571Spooka prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
474fd993ea3Spooka {
475fd993ea3Spooka struct rsp_hdr rhdr;
476fd993ea3Spooka struct respwait rw;
47700e34b22Spooka struct iovec iov[1];
478fd993ea3Spooka int rv;
479fd993ea3Spooka
480fd993ea3Spooka rhdr.rsp_len = sizeof(rhdr);
481fd993ea3Spooka rhdr.rsp_class = RUMPSP_REQ;
482fd993ea3Spooka rhdr.rsp_type = RUMPSP_PREFORK;
483fd993ea3Spooka rhdr.rsp_error = 0;
484fd993ea3Spooka
48500e34b22Spooka IOVPUT(iov[0], rhdr);
48600e34b22Spooka
48719a57922Spooka do {
488fd993ea3Spooka putwait(spc, &rw, &rhdr);
48900e34b22Spooka rv = send_with_recon(spc, iov, __arraycount(iov));
490fd993ea3Spooka if (rv != 0) {
491fd993ea3Spooka unputwait(spc, &rw);
49219a57922Spooka continue;
493fd993ea3Spooka }
494fd993ea3Spooka
49582355571Spooka rv = cliwaitresp(spc, &rw, omask, false);
49641434db3Spooka if (rv == ENOTCONN)
49741434db3Spooka rv = EAGAIN;
49841434db3Spooka } while (rv == EAGAIN);
49919a57922Spooka
500fd993ea3Spooka *resp = rw.rw_data;
501fd993ea3Spooka return rv;
502fd993ea3Spooka }
503fd993ea3Spooka
50419a57922Spooka /*
50519a57922Spooka * prevent response code from deadlocking with reconnect code
50619a57922Spooka */
507fd993ea3Spooka static int
resp_sendlock(struct spclient * spc)50819a57922Spooka resp_sendlock(struct spclient *spc)
50919a57922Spooka {
51019a57922Spooka int rv = 0;
51119a57922Spooka
51219a57922Spooka pthread_mutex_lock(&spc->spc_mtx);
51319a57922Spooka while (spc->spc_ostatus != SPCSTATUS_FREE) {
51419a57922Spooka if (__predict_false(spc->spc_reconnecting)) {
51519a57922Spooka rv = EBUSY;
51619a57922Spooka goto out;
51719a57922Spooka }
51819a57922Spooka spc->spc_ostatus = SPCSTATUS_WANTED;
51919a57922Spooka pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
52019a57922Spooka }
52119a57922Spooka spc->spc_ostatus = SPCSTATUS_BUSY;
52219a57922Spooka
52319a57922Spooka out:
52419a57922Spooka pthread_mutex_unlock(&spc->spc_mtx);
52519a57922Spooka return rv;
52619a57922Spooka }
52719a57922Spooka
52819a57922Spooka static void
send_copyin_resp(struct spclient * spc,uint64_t reqno,void * data,size_t dlen,int wantstr)5296b71288cSpooka send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
5306b71288cSpooka int wantstr)
5316b1f3dc0Spooka {
5326b1f3dc0Spooka struct rsp_hdr rhdr;
53300e34b22Spooka struct iovec iov[2];
5346b1f3dc0Spooka
5356b71288cSpooka if (wantstr)
5366b71288cSpooka dlen = MIN(dlen, strlen(data)+1);
5376b71288cSpooka
5386b1f3dc0Spooka rhdr.rsp_len = sizeof(rhdr) + dlen;
5396b1f3dc0Spooka rhdr.rsp_reqno = reqno;
54052f22b2cSpooka rhdr.rsp_class = RUMPSP_RESP;
54152f22b2cSpooka rhdr.rsp_type = RUMPSP_COPYIN;
5426b1f3dc0Spooka rhdr.rsp_sysnum = 0;
5436b1f3dc0Spooka
54400e34b22Spooka IOVPUT(iov[0], rhdr);
54500e34b22Spooka IOVPUT_WITHSIZE(iov[1], data, dlen);
54600e34b22Spooka
54719a57922Spooka if (resp_sendlock(spc) != 0)
54819a57922Spooka return;
54900e34b22Spooka (void)SENDIOV(spc, iov);
55052f22b2cSpooka sendunlock(spc);
5516b1f3dc0Spooka }
5526b1f3dc0Spooka
55319a57922Spooka static void
send_anonmmap_resp(struct spclient * spc,uint64_t reqno,void * addr)5546b1f3dc0Spooka send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
5556b1f3dc0Spooka {
5566b1f3dc0Spooka struct rsp_hdr rhdr;
55700e34b22Spooka struct iovec iov[2];
5586b1f3dc0Spooka
5596b1f3dc0Spooka rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
5606b1f3dc0Spooka rhdr.rsp_reqno = reqno;
56152f22b2cSpooka rhdr.rsp_class = RUMPSP_RESP;
56252f22b2cSpooka rhdr.rsp_type = RUMPSP_ANONMMAP;
5636b1f3dc0Spooka rhdr.rsp_sysnum = 0;
5646b1f3dc0Spooka
56500e34b22Spooka IOVPUT(iov[0], rhdr);
56600e34b22Spooka IOVPUT(iov[1], addr);
56700e34b22Spooka
56819a57922Spooka if (resp_sendlock(spc) != 0)
56919a57922Spooka return;
57000e34b22Spooka (void)SENDIOV(spc, iov);
57152f22b2cSpooka sendunlock(spc);
5726b1f3dc0Spooka }
5736b1f3dc0Spooka
5746b1f3dc0Spooka int
rumpclient_syscall(int sysnum,const void * data,size_t dlen,register_t * retval)5756b1f3dc0Spooka rumpclient_syscall(int sysnum, const void *data, size_t dlen,
5766b1f3dc0Spooka register_t *retval)
5776b1f3dc0Spooka {
5786b1f3dc0Spooka struct rsp_sysresp *resp;
57982355571Spooka sigset_t omask;
58052f22b2cSpooka void *rdata;
58152f22b2cSpooka int rv;
58252f22b2cSpooka
58382355571Spooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
58482355571Spooka
58552f22b2cSpooka DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
58652f22b2cSpooka sysnum, data, dlen));
58752f22b2cSpooka
58882355571Spooka rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
58952f22b2cSpooka if (rv)
59082355571Spooka goto out;
59152f22b2cSpooka
59252f22b2cSpooka resp = rdata;
593832d276eSmartin DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %"
594832d276eSmartin PRIxREGISTER"/%"PRIxREGISTER"\n",
595832d276eSmartin sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
59652f22b2cSpooka
59752f22b2cSpooka memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
59852f22b2cSpooka rv = resp->rsys_error;
59952f22b2cSpooka free(rdata);
60052f22b2cSpooka
60182355571Spooka out:
60282355571Spooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
60352f22b2cSpooka return rv;
60452f22b2cSpooka }
60552f22b2cSpooka
60652f22b2cSpooka static void
handlereq(struct spclient * spc)60752f22b2cSpooka handlereq(struct spclient *spc)
60852f22b2cSpooka {
6096b1f3dc0Spooka struct rsp_copydata *copydata;
6109fba158bSpooka struct rsp_hdr *rhdr = &spc->spc_hdr;
6116b1f3dc0Spooka void *mapaddr;
61252f22b2cSpooka size_t maplen;
6136b71288cSpooka int reqtype = spc->spc_hdr.rsp_type;
614437e54a7Spooka int sig;
6156b1f3dc0Spooka
6166b71288cSpooka switch (reqtype) {
61752f22b2cSpooka case RUMPSP_COPYIN:
6186b71288cSpooka case RUMPSP_COPYINSTR:
6196b1f3dc0Spooka /*LINTED*/
62052f22b2cSpooka copydata = (struct rsp_copydata *)spc->spc_buf;
62152f22b2cSpooka DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
6226b1f3dc0Spooka copydata->rcp_addr, copydata->rcp_len));
62352f22b2cSpooka send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
6246b71288cSpooka copydata->rcp_addr, copydata->rcp_len,
6256b71288cSpooka reqtype == RUMPSP_COPYINSTR);
6266b1f3dc0Spooka break;
62752f22b2cSpooka case RUMPSP_COPYOUT:
6286b71288cSpooka case RUMPSP_COPYOUTSTR:
6296b1f3dc0Spooka /*LINTED*/
63052f22b2cSpooka copydata = (struct rsp_copydata *)spc->spc_buf;
63152f22b2cSpooka DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
6326b1f3dc0Spooka copydata->rcp_addr, copydata->rcp_len));
6336b1f3dc0Spooka /*LINTED*/
6346b1f3dc0Spooka memcpy(copydata->rcp_addr, copydata->rcp_data,
6356b1f3dc0Spooka copydata->rcp_len);
6366b1f3dc0Spooka break;
63752f22b2cSpooka case RUMPSP_ANONMMAP:
6386b1f3dc0Spooka /*LINTED*/
63952f22b2cSpooka maplen = *(size_t *)spc->spc_buf;
6406b1f3dc0Spooka mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
64194265f33Spooka MAP_ANON|MAP_PRIVATE, -1, 0);
6426b1f3dc0Spooka if (mapaddr == MAP_FAILED)
6436b1f3dc0Spooka mapaddr = NULL;
64452f22b2cSpooka DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
64552f22b2cSpooka send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
6466b1f3dc0Spooka break;
6479fba158bSpooka case RUMPSP_RAISE:
648437e54a7Spooka sig = rumpuser__sig_rump2host(rhdr->rsp_signo);
649437e54a7Spooka DPRINTF(("rump_sp handlereq: raise sig %d\n", sig));
650437e54a7Spooka raise(sig);
6519fba158bSpooka /*
6529fba158bSpooka * We most likely have signals blocked, but the signal
6539fba158bSpooka * will be handled soon enough when we return.
6549fba158bSpooka */
6559fba158bSpooka break;
65652f22b2cSpooka default:
657c45d9404Spooka printf("PANIC: INVALID TYPE %d\n", reqtype);
65852f22b2cSpooka abort();
6596b1f3dc0Spooka break;
6606b1f3dc0Spooka }
6616b1f3dc0Spooka
662d402686fSpooka spcfreebuf(spc);
6636b1f3dc0Spooka }
6646b1f3dc0Spooka
665fd993ea3Spooka static unsigned ptab_idx;
666fd993ea3Spooka static struct sockaddr *serv_sa;
667fd993ea3Spooka
66882aa8837Spooka /* dup until we get a "good" fd which does not collide with stdio */
66982aa8837Spooka static int
dupgood(int myfd,int mustchange)6702ba7fe55Spooka dupgood(int myfd, int mustchange)
67182aa8837Spooka {
6722ba7fe55Spooka int ofds[4];
673df45d61fSalnsn int sverrno;
674e1a2f47fSmatt unsigned int i;
67582aa8837Spooka
6762ba7fe55Spooka for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
67782aa8837Spooka assert(i < __arraycount(ofds));
67882aa8837Spooka ofds[i] = myfd;
67982aa8837Spooka myfd = host_dup(myfd);
6802ba7fe55Spooka if (mustchange) {
6812ba7fe55Spooka i--; /* prevent closing old fd */
6822ba7fe55Spooka mustchange = 0;
6832ba7fe55Spooka }
68482aa8837Spooka }
68582aa8837Spooka
686df45d61fSalnsn sverrno = 0;
687df45d61fSalnsn if (myfd == -1 && i > 0)
688df45d61fSalnsn sverrno = errno;
689df45d61fSalnsn
690e1a2f47fSmatt while (i-- > 0) {
69182aa8837Spooka host_close(ofds[i]);
69282aa8837Spooka }
69382aa8837Spooka
694df45d61fSalnsn if (sverrno)
695df45d61fSalnsn errno = sverrno;
696df45d61fSalnsn
69782aa8837Spooka return myfd;
69882aa8837Spooka }
69982aa8837Spooka
70090c25cb3Spooka #if defined(USE_KQUEUE)
70190c25cb3Spooka
70290c25cb3Spooka static int
makeholyfd(void)70390c25cb3Spooka makeholyfd(void)
70490c25cb3Spooka {
70590c25cb3Spooka struct kevent kev[NSIG+1];
70690c25cb3Spooka int i, fd;
70790c25cb3Spooka
70890c25cb3Spooka /* setup kqueue, we want all signals and the fd */
70990c25cb3Spooka if ((fd = dupgood(host_kqueue(), 0)) == -1) {
71090c25cb3Spooka ERRLOG(("rump_sp: cannot setup kqueue"));
71190c25cb3Spooka return -1;
71290c25cb3Spooka }
71390c25cb3Spooka
71490c25cb3Spooka for (i = 0; i < NSIG; i++) {
71590c25cb3Spooka EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
71690c25cb3Spooka }
71790c25cb3Spooka EV_SET(&kev[NSIG], clispc.spc_fd,
71890c25cb3Spooka EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
71990c25cb3Spooka if (host_kevent(fd, kev, NSIG+1, NULL, 0, NULL) == -1) {
72090c25cb3Spooka ERRLOG(("rump_sp: kevent() failed"));
721e152ae2dSpooka host_close(fd);
72290c25cb3Spooka return -1;
723e152ae2dSpooka }
72490c25cb3Spooka
72590c25cb3Spooka return fd;
72690c25cb3Spooka }
72790c25cb3Spooka
72890c25cb3Spooka #elif defined(USE_SIGNALFD) /* !USE_KQUEUE */
72990c25cb3Spooka
73090c25cb3Spooka static int
makeholyfd(void)73190c25cb3Spooka makeholyfd(void)
73290c25cb3Spooka {
73390c25cb3Spooka
73490c25cb3Spooka return host_signalfd(-1, &fullset, 0);
73590c25cb3Spooka }
73690c25cb3Spooka
73790c25cb3Spooka #else /* !USE_KQUEUE && !USE_SIGNALFD */
73890c25cb3Spooka
73990c25cb3Spooka static int
makeholyfd(void)74090c25cb3Spooka makeholyfd(void)
74190c25cb3Spooka {
74290c25cb3Spooka
74390c25cb3Spooka return -1;
74490c25cb3Spooka }
74590c25cb3Spooka
74690c25cb3Spooka #endif
74790c25cb3Spooka
748fd993ea3Spooka static int
doconnect(void)749754d118eSpooka doconnect(void)
7506b1f3dc0Spooka {
75119a57922Spooka struct respwait rw;
75219a57922Spooka struct rsp_hdr rhdr;
7533c4a27f7Spooka char banner[MAXBANNER];
754fa3922beSpooka int s, error, flags;
7553c4a27f7Spooka ssize_t n;
7566b1f3dc0Spooka
75790c25cb3Spooka if (holyfd != -1)
75890c25cb3Spooka host_close(holyfd);
75990c25cb3Spooka holyfd = -1;
760e6450adeSpooka s = -1;
76119a57922Spooka
76219a57922Spooka if (clispc.spc_fd != -1)
76319a57922Spooka host_close(clispc.spc_fd);
76419a57922Spooka clispc.spc_fd = -1;
76519a57922Spooka
76619a57922Spooka /*
76719a57922Spooka * for reconnect, gate everyone out of the receiver code
76819a57922Spooka */
76919a57922Spooka putwait_locked(&clispc, &rw, &rhdr);
77019a57922Spooka
77119a57922Spooka pthread_mutex_lock(&clispc.spc_mtx);
77219a57922Spooka clispc.spc_reconnecting = 1;
77319a57922Spooka pthread_cond_broadcast(&clispc.spc_cv);
77419a57922Spooka clispc.spc_generation++;
77519a57922Spooka while (clispc.spc_istatus != SPCSTATUS_FREE) {
77619a57922Spooka clispc.spc_istatus = SPCSTATUS_WANTED;
77719a57922Spooka pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
77819a57922Spooka }
77919a57922Spooka kickall(&clispc);
78019a57922Spooka
78119a57922Spooka /*
78219a57922Spooka * we can release it already since we hold the
78319a57922Spooka * send lock during reconnect
78419a57922Spooka * XXX: assert it
78519a57922Spooka */
78619a57922Spooka clispc.spc_istatus = SPCSTATUS_FREE;
78719a57922Spooka pthread_mutex_unlock(&clispc.spc_mtx);
78819a57922Spooka unputwait_locked(&clispc, &rw);
78919a57922Spooka
79019a57922Spooka free(clispc.spc_buf);
79119a57922Spooka clispc.spc_off = 0;
79219a57922Spooka
7932ba7fe55Spooka s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
794fd993ea3Spooka if (s == -1)
79583463bddSpooka return -1;
7966b1f3dc0Spooka
797fa3922beSpooka while (host_connect(s, serv_sa, parsetab[ptab_idx].slen) == -1) {
79819a57922Spooka if (errno == EINTR)
79919a57922Spooka continue;
800754d118eSpooka ERRLOG(("rump_sp: client connect failed: %s\n",
801754d118eSpooka strerror(errno)));
80283463bddSpooka return -1;
80383463bddSpooka }
8046b1f3dc0Spooka
805fd993ea3Spooka if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
806754d118eSpooka ERRLOG(("rump_sp: connect hook failed\n"));
80783463bddSpooka return -1;
8086b1f3dc0Spooka }
8095e5fac56Spooka
810df45d61fSalnsn if ((n = host_read(s, banner, sizeof(banner)-1)) <= 0) {
811754d118eSpooka ERRLOG(("rump_sp: failed to read banner\n"));
8123c4a27f7Spooka return -1;
8133c4a27f7Spooka }
8143c4a27f7Spooka
8153c4a27f7Spooka if (banner[n-1] != '\n') {
816754d118eSpooka ERRLOG(("rump_sp: invalid banner\n"));
8173c4a27f7Spooka return -1;
8183c4a27f7Spooka }
8193c4a27f7Spooka banner[n] = '\0';
820df45d61fSalnsn /* XXX parse the banner some day */
8213c4a27f7Spooka
8225064fa59Spooka flags = host_fcntl(s, F_GETFL, 0);
8235064fa59Spooka if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
824754d118eSpooka ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno)));
8255064fa59Spooka return -1;
8265064fa59Spooka }
82719a57922Spooka clispc.spc_fd = s;
82819a57922Spooka clispc.spc_state = SPCSTATE_RUNNING;
82919a57922Spooka clispc.spc_reconnecting = 0;
83090c25cb3Spooka holyfd = makeholyfd();
8315064fa59Spooka
83219a57922Spooka return 0;
83319a57922Spooka }
83419a57922Spooka
83519a57922Spooka static int
doinit(void)83619a57922Spooka doinit(void)
83719a57922Spooka {
83819a57922Spooka
839fd993ea3Spooka TAILQ_INIT(&clispc.spc_respwait);
840fd993ea3Spooka pthread_mutex_init(&clispc.spc_mtx, NULL);
841fd993ea3Spooka pthread_cond_init(&clispc.spc_cv, NULL);
842fd993ea3Spooka
843fd993ea3Spooka return 0;
844fd993ea3Spooka }
845fd993ea3Spooka
8465c4b55caSpooka #ifdef RTLD_NEXT
847b8eb9b59Spooka void *rumpclient__dlsym(void *, const char *);
848b8eb9b59Spooka void *
rumpclient__dlsym(void * handle,const char * symbol)849b8eb9b59Spooka rumpclient__dlsym(void *handle, const char *symbol)
850b8eb9b59Spooka {
851b8eb9b59Spooka
852b8eb9b59Spooka return dlsym(handle, symbol);
853b8eb9b59Spooka }
854fa3922beSpooka void *rumphijack_dlsym(void *, const char *)
855fa3922beSpooka __attribute__((__weak__, alias("rumpclient__dlsym")));
8565c4b55caSpooka #endif
857b8eb9b59Spooka
858ee6e286cSpooka static pid_t init_done = 0;
85991aad9bdSpooka
860fd993ea3Spooka int
rumpclient_init(void)861c7d626a6Sjoerg rumpclient_init(void)
862fd993ea3Spooka {
863fd993ea3Spooka char *p;
864fd993ea3Spooka int error;
8655e301bc4Spooka int rv = -1;
8665e301bc4Spooka int hstype;
867ee6e286cSpooka pid_t mypid;
8685e301bc4Spooka
869ee6e286cSpooka /*
870ee6e286cSpooka * Make sure we're not riding the context of a previous
871ee6e286cSpooka * host fork. Note: it's *possible* that after n>1 forks
872ee6e286cSpooka * we have the same pid as one of our exited parents, but
873ee6e286cSpooka * I'm pretty sure there are 0 practical implications, since
874ee6e286cSpooka * it means generations would have to skip rumpclient init.
875ee6e286cSpooka */
876ee6e286cSpooka if (init_done == (mypid = getpid()))
8775e301bc4Spooka return 0;
878ee6e286cSpooka
87990c25cb3Spooka #ifdef USE_KQUEUE
880e8083ecfSpooka /* kq does not traverse fork() */
88190c25cb3Spooka holyfd = -1;
88290c25cb3Spooka #endif
883ee6e286cSpooka init_done = mypid;
884fd993ea3Spooka
88558bfec3eSpooka sigfillset(&fullset);
88658bfec3eSpooka
88791aad9bdSpooka /*
888fa3922beSpooka * sag mir, wo die symbols sind. zogen fort, der krieg beginnt.
88991aad9bdSpooka * wann wird man je verstehen? wann wird man je verstehen?
89091aad9bdSpooka */
8915c4b55caSpooka #ifdef RTLD_NEXT
89291aad9bdSpooka #define FINDSYM2(_name_,_syscall_) \
893b8eb9b59Spooka if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \
894e1463ae3Spooka #_syscall_)) == NULL) { \
8958c15d641Spooka if (rumphijack_dlsym == rumpclient__dlsym) \
896e1463ae3Spooka host_##_name_ = _name_; /* static fallback */ \
89756665b94Spooka if (host_##_name_ == NULL) { \
89856665b94Spooka fprintf(stderr,"cannot find %s: %s", #_syscall_,\
899e1463ae3Spooka dlerror()); \
90056665b94Spooka exit(1); \
90156665b94Spooka } \
902e1463ae3Spooka }
9035c4b55caSpooka #else
9045c4b55caSpooka #define FINDSYM2(_name_,_syscall) \
9055c4b55caSpooka host_##_name_ = _name_;
9065c4b55caSpooka #endif
90791aad9bdSpooka #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
908fa3922beSpooka #ifdef __NetBSD__
909e1463ae3Spooka FINDSYM2(socket,__socket30)
910fa3922beSpooka #else
911fa3922beSpooka FINDSYM(socket)
912fa3922beSpooka #endif
913fa3922beSpooka
914e1463ae3Spooka FINDSYM(close)
915e1463ae3Spooka FINDSYM(connect)
916e1463ae3Spooka FINDSYM(fcntl)
917e1463ae3Spooka FINDSYM(poll)
918e1463ae3Spooka FINDSYM(read)
91900e34b22Spooka FINDSYM(sendmsg)
920e1463ae3Spooka FINDSYM(setsockopt)
921e1463ae3Spooka FINDSYM(dup)
922e1463ae3Spooka FINDSYM(execve)
923fa3922beSpooka
924fa3922beSpooka #ifdef USE_KQUEUE
925fa3922beSpooka FINDSYM(kqueue)
9267e80a07cSjustin #ifdef __NetBSD__
927fe247b6fSpooka #if !__NetBSD_Prereq__(5,99,7)
928e1463ae3Spooka FINDSYM(kevent)
929*fb68413fSrin #elif !__NetBSD_Prereq__(10,99,7)
930e1463ae3Spooka FINDSYM2(kevent,_sys___kevent50)
931d11110f4Schristos #else
932d11110f4Schristos FINDSYM2(kevent,_sys___kevent100)
933fe247b6fSpooka #endif
9347e80a07cSjustin #else
9357e80a07cSjustin FINDSYM(kevent)
9367e80a07cSjustin #endif
937fa3922beSpooka #endif /* USE_KQUEUE */
938fa3922beSpooka
93990c25cb3Spooka #ifdef USE_SIGNALFD
94090c25cb3Spooka FINDSYM(signalfd)
94190c25cb3Spooka #endif
94290c25cb3Spooka
94391aad9bdSpooka #undef FINDSYM
94491aad9bdSpooka #undef FINDSY2
94591aad9bdSpooka
9462ba7fe55Spooka if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
947fd993ea3Spooka if ((p = getenv("RUMP_SERVER")) == NULL) {
9481220d536Spooka fprintf(stderr, "error: RUMP_SERVER not set\n");
949fd993ea3Spooka errno = ENOENT;
9505e301bc4Spooka goto out;
951fd993ea3Spooka }
9522ba7fe55Spooka }
953fd993ea3Spooka
954fd993ea3Spooka if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
955393eecc1Spooka errno = error;
9565e301bc4Spooka goto out;
957393eecc1Spooka }
958393eecc1Spooka
95919a57922Spooka if (doinit() == -1)
9605e301bc4Spooka goto out;
9612ba7fe55Spooka
9622ba7fe55Spooka if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
96390c25cb3Spooka sscanf(p, "%d,%d", &clispc.spc_fd, &holyfd);
9642ba7fe55Spooka unsetenv("RUMPCLIENT__EXECFD");
9655e301bc4Spooka hstype = HANDSHAKE_EXEC;
9665e301bc4Spooka } else {
967754d118eSpooka if (doconnect() == -1)
9685e301bc4Spooka goto out;
9695e301bc4Spooka hstype = HANDSHAKE_GUEST;
9702ba7fe55Spooka }
9712ba7fe55Spooka
9725e301bc4Spooka error = handshake_req(&clispc, hstype, NULL, 0, false);
973393eecc1Spooka if (error) {
974393eecc1Spooka pthread_mutex_destroy(&clispc.spc_mtx);
975393eecc1Spooka pthread_cond_destroy(&clispc.spc_cv);
97619a57922Spooka if (clispc.spc_fd != -1)
97791aad9bdSpooka host_close(clispc.spc_fd);
978fd993ea3Spooka errno = error;
9795e301bc4Spooka goto out;
980393eecc1Spooka }
9815e301bc4Spooka rv = 0;
982fd993ea3Spooka
9835e301bc4Spooka out:
9845e301bc4Spooka if (rv == -1)
9855e301bc4Spooka init_done = 0;
9865e301bc4Spooka return rv;
987fd993ea3Spooka }
988fd993ea3Spooka
989fd993ea3Spooka struct rumpclient_fork {
990fd993ea3Spooka uint32_t fork_auth[AUTHLEN];
99136f68180Spooka struct spclient fork_spc;
99290c25cb3Spooka int fork_holyfd;
993fd993ea3Spooka };
994fd993ea3Spooka
995fd993ea3Spooka struct rumpclient_fork *
rumpclient_prefork(void)996fd993ea3Spooka rumpclient_prefork(void)
997fd993ea3Spooka {
998fd993ea3Spooka struct rumpclient_fork *rpf;
99982355571Spooka sigset_t omask;
1000fd993ea3Spooka void *resp;
1001fd993ea3Spooka int rv;
1002fd993ea3Spooka
100382355571Spooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
1004fd993ea3Spooka rpf = malloc(sizeof(*rpf));
1005fd993ea3Spooka if (rpf == NULL)
1006f4ba3dcdSpooka goto out;
1007fd993ea3Spooka
100882355571Spooka if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
1009fd993ea3Spooka free(rpf);
1010fd993ea3Spooka errno = rv;
101182355571Spooka rpf = NULL;
101282355571Spooka goto out;
1013fd993ea3Spooka }
1014fd993ea3Spooka
1015fd993ea3Spooka memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
1016fd993ea3Spooka free(resp);
1017fd993ea3Spooka
101836f68180Spooka rpf->fork_spc = clispc;
101990c25cb3Spooka rpf->fork_holyfd = holyfd;
102036f68180Spooka
102182355571Spooka out:
102282355571Spooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
1023fd993ea3Spooka return rpf;
1024fd993ea3Spooka }
1025fd993ea3Spooka
1026fd993ea3Spooka int
rumpclient_fork_init(struct rumpclient_fork * rpf)1027fd993ea3Spooka rumpclient_fork_init(struct rumpclient_fork *rpf)
1028fd993ea3Spooka {
1029fd993ea3Spooka int error;
10309f3861f6Spooka int osock;
1031fd993ea3Spooka
10329f3861f6Spooka osock = clispc.spc_fd;
1033fd993ea3Spooka memset(&clispc, 0, sizeof(clispc));
10349f3861f6Spooka clispc.spc_fd = osock;
10359f3861f6Spooka
103690c25cb3Spooka #ifdef USE_KQUEUE
103790c25cb3Spooka holyfd = -1; /* kqueue descriptor is not copied over fork() */
103890c25cb3Spooka #else
103990c25cb3Spooka if (holyfd != -1) {
104090c25cb3Spooka host_close(holyfd);
104190c25cb3Spooka holyfd = -1;
104290c25cb3Spooka }
104390c25cb3Spooka #endif
1044fd993ea3Spooka
104519a57922Spooka if (doinit() == -1)
104619a57922Spooka return -1;
1047754d118eSpooka if (doconnect() == -1)
1048fd993ea3Spooka return -1;
1049fd993ea3Spooka
10505e301bc4Spooka error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
10515e301bc4Spooka 0, false);
1052fd993ea3Spooka if (error) {
1053fd993ea3Spooka pthread_mutex_destroy(&clispc.spc_mtx);
1054fd993ea3Spooka pthread_cond_destroy(&clispc.spc_cv);
1055fd993ea3Spooka errno = error;
1056fd993ea3Spooka return -1;
1057fd993ea3Spooka }
1058fd993ea3Spooka
1059fd993ea3Spooka return 0;
10606b1f3dc0Spooka }
106141434db3Spooka
1062d06a7e79Spooka /*ARGSUSED*/
106341434db3Spooka void
rumpclient_fork_cancel(struct rumpclient_fork * rpf)106436f68180Spooka rumpclient_fork_cancel(struct rumpclient_fork *rpf)
106536f68180Spooka {
106636f68180Spooka
106736f68180Spooka /* EUNIMPL */
106836f68180Spooka }
106936f68180Spooka
107036f68180Spooka void
rumpclient_fork_vparent(struct rumpclient_fork * rpf)107136f68180Spooka rumpclient_fork_vparent(struct rumpclient_fork *rpf)
107236f68180Spooka {
107336f68180Spooka
107436f68180Spooka clispc = rpf->fork_spc;
107590c25cb3Spooka holyfd = rpf->fork_holyfd;
107636f68180Spooka }
107736f68180Spooka
107836f68180Spooka void
rumpclient_setconnretry(time_t timeout)107941434db3Spooka rumpclient_setconnretry(time_t timeout)
108041434db3Spooka {
108141434db3Spooka
1082065ac12bSpooka if (timeout < RUMPCLIENT_RETRYCONN_DIE)
108341434db3Spooka return; /* gigo */
108441434db3Spooka
108541434db3Spooka retrytimo = timeout;
108641434db3Spooka }
10872ba7fe55Spooka
10882ba7fe55Spooka int
rumpclient__closenotify(int * fdp,enum rumpclient_closevariant variant)10892ba7fe55Spooka rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
10902ba7fe55Spooka {
10912ba7fe55Spooka int fd = *fdp;
109270764037Schristos int untilfd;
10932ba7fe55Spooka int newfd;
10942ba7fe55Spooka
10952ba7fe55Spooka switch (variant) {
10962ba7fe55Spooka case RUMPCLIENT_CLOSE_FCLOSEM:
109790c25cb3Spooka untilfd = MAX(clispc.spc_fd, holyfd);
10982ba7fe55Spooka for (; fd <= untilfd; fd++) {
109990c25cb3Spooka if (fd == clispc.spc_fd || fd == holyfd)
11002ba7fe55Spooka continue;
110170764037Schristos (void)host_close(fd);
11022ba7fe55Spooka }
11032ba7fe55Spooka *fdp = fd;
11042ba7fe55Spooka break;
11052ba7fe55Spooka
11062ba7fe55Spooka case RUMPCLIENT_CLOSE_CLOSE:
11072ba7fe55Spooka case RUMPCLIENT_CLOSE_DUP2:
11082ba7fe55Spooka if (fd == clispc.spc_fd) {
11092ba7fe55Spooka newfd = dupgood(clispc.spc_fd, 1);
11102ba7fe55Spooka if (newfd == -1)
11112ba7fe55Spooka return -1;
1112fa3922beSpooka
1113fa3922beSpooka #ifdef USE_KQUEUE
1114fa3922beSpooka {
1115fa3922beSpooka struct kevent kev[2];
1116fa3922beSpooka
11172ba7fe55Spooka /*
11182ba7fe55Spooka * now, we have a new socket number, so change
11192ba7fe55Spooka * the file descriptor that kqueue is
11202ba7fe55Spooka * monitoring. remove old and add new.
11212ba7fe55Spooka */
11222ba7fe55Spooka EV_SET(&kev[0], clispc.spc_fd,
11232ba7fe55Spooka EVFILT_READ, EV_DELETE, 0, 0, 0);
11242ba7fe55Spooka EV_SET(&kev[1], newfd,
11252ba7fe55Spooka EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
112690c25cb3Spooka if (host_kevent(holyfd, kev, 2, NULL, 0, NULL) == -1) {
11272ba7fe55Spooka int sverrno = errno;
11282ba7fe55Spooka host_close(newfd);
11292ba7fe55Spooka errno = sverrno;
11302ba7fe55Spooka return -1;
113190c25cb3Spooka }}
113290c25cb3Spooka #endif /* !USE_KQUEUE */
11332ba7fe55Spooka clispc.spc_fd = newfd;
11342ba7fe55Spooka }
113590c25cb3Spooka if (holyfd != -1 && fd == holyfd) {
113690c25cb3Spooka newfd = dupgood(holyfd, 1);
11372ba7fe55Spooka if (newfd == -1)
11382ba7fe55Spooka return -1;
113990c25cb3Spooka holyfd = newfd;
11402ba7fe55Spooka }
11412ba7fe55Spooka break;
11422ba7fe55Spooka }
11432ba7fe55Spooka
11442ba7fe55Spooka return 0;
11452ba7fe55Spooka }
11462ba7fe55Spooka
1147f4ba3dcdSpooka pid_t
rumpclient_fork(void)1148c7d626a6Sjoerg rumpclient_fork(void)
1149f4ba3dcdSpooka {
1150f4ba3dcdSpooka
115136f68180Spooka return rumpclient__dofork(fork);
1152f4ba3dcdSpooka }
1153f4ba3dcdSpooka
11542ba7fe55Spooka /*
11552ba7fe55Spooka * Process is about to exec. Save info about our existing connection
11562ba7fe55Spooka * in the env. rumpclient will check for this info in init().
11572ba7fe55Spooka * This is mostly for the benefit of rumphijack, but regular applications
11582ba7fe55Spooka * may use it as well.
11592ba7fe55Spooka */
11602ba7fe55Spooka int
rumpclient_exec(const char * path,char * const argv[],char * const envp[])1161f4ba3dcdSpooka rumpclient_exec(const char *path, char *const argv[], char *const envp[])
11622ba7fe55Spooka {
11632ba7fe55Spooka char buf[4096];
11642ba7fe55Spooka char **newenv;
11652ba7fe55Spooka char *envstr, *envstr2;
1166f4ba3dcdSpooka size_t nelem;
1167f4ba3dcdSpooka int rv, sverrno;
11682ba7fe55Spooka
11692ba7fe55Spooka snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
117090c25cb3Spooka clispc.spc_fd, holyfd);
11712ba7fe55Spooka envstr = malloc(strlen(buf)+1);
11722ba7fe55Spooka if (envstr == NULL) {
11732ba7fe55Spooka return ENOMEM;
11742ba7fe55Spooka }
11752ba7fe55Spooka strcpy(envstr, buf);
11762ba7fe55Spooka
11772ba7fe55Spooka /* do we have a fully parsed url we want to forward in the env? */
11782ba7fe55Spooka if (*parsedurl != '\0') {
11792ba7fe55Spooka snprintf(buf, sizeof(buf),
11802ba7fe55Spooka "RUMP__PARSEDSERVER=%s", parsedurl);
11812ba7fe55Spooka envstr2 = malloc(strlen(buf)+1);
11822ba7fe55Spooka if (envstr2 == NULL) {
11832ba7fe55Spooka free(envstr);
11842ba7fe55Spooka return ENOMEM;
11852ba7fe55Spooka }
11862ba7fe55Spooka strcpy(envstr2, buf);
11872ba7fe55Spooka } else {
11882ba7fe55Spooka envstr2 = NULL;
11892ba7fe55Spooka }
11902ba7fe55Spooka
1191f4ba3dcdSpooka for (nelem = 0; envp && envp[nelem]; nelem++)
11922ba7fe55Spooka continue;
11932ba7fe55Spooka
11944674f092Spooka newenv = malloc(sizeof(*newenv) * (nelem+3));
11952ba7fe55Spooka if (newenv == NULL) {
11962ba7fe55Spooka free(envstr2);
11972ba7fe55Spooka free(envstr);
11982ba7fe55Spooka return ENOMEM;
11992ba7fe55Spooka }
1200f4ba3dcdSpooka memcpy(&newenv[0], envp, nelem*sizeof(*envp));
12012ba7fe55Spooka
1202f4ba3dcdSpooka newenv[nelem] = envstr;
1203f4ba3dcdSpooka newenv[nelem+1] = envstr2;
1204f4ba3dcdSpooka newenv[nelem+2] = NULL;
12052ba7fe55Spooka
1206f4ba3dcdSpooka rv = host_execve(path, argv, newenv);
12072ba7fe55Spooka
1208f4ba3dcdSpooka _DIAGASSERT(rv != 0);
1209f4ba3dcdSpooka sverrno = errno;
1210f4ba3dcdSpooka free(envstr2);
1211f4ba3dcdSpooka free(envstr);
1212f4ba3dcdSpooka free(newenv);
1213f4ba3dcdSpooka errno = sverrno;
1214f4ba3dcdSpooka return rv;
12152ba7fe55Spooka }
121636f68180Spooka
121756665b94Spooka /*
121856665b94Spooka * daemon() is handwritten for the benefit of platforms which
121956665b94Spooka * do not support daemon().
122056665b94Spooka */
122136f68180Spooka int
rumpclient_daemon(int nochdir,int noclose)122236f68180Spooka rumpclient_daemon(int nochdir, int noclose)
122336f68180Spooka {
122436f68180Spooka struct rumpclient_fork *rf;
122536f68180Spooka int sverrno;
122636f68180Spooka
122736f68180Spooka if ((rf = rumpclient_prefork()) == NULL)
122836f68180Spooka return -1;
122936f68180Spooka
123056665b94Spooka switch (fork()) {
123156665b94Spooka case 0:
123256665b94Spooka break;
123356665b94Spooka case -1:
123456665b94Spooka goto daemonerr;
123556665b94Spooka default:
123656665b94Spooka _exit(0);
123736f68180Spooka }
123836f68180Spooka
123956665b94Spooka if (setsid() == -1)
124056665b94Spooka goto daemonerr;
124156665b94Spooka if (!nochdir && chdir("/") == -1)
124256665b94Spooka goto daemonerr;
124356665b94Spooka if (!noclose) {
124456665b94Spooka int fd = open("/dev/null", O_RDWR);
124556665b94Spooka dup2(fd, 0);
124656665b94Spooka dup2(fd, 1);
124756665b94Spooka dup2(fd, 2);
124856665b94Spooka if (fd > 2)
124956665b94Spooka close(fd);
125056665b94Spooka }
125156665b94Spooka
125256665b94Spooka /* note: fork is either completed or cancelled by the call */
125336f68180Spooka if (rumpclient_fork_init(rf) == -1)
125436f68180Spooka return -1;
125536f68180Spooka
125636f68180Spooka return 0;
125756665b94Spooka
125856665b94Spooka daemonerr:
125956665b94Spooka sverrno = errno;
126056665b94Spooka rumpclient_fork_cancel(rf);
126156665b94Spooka errno = sverrno;
126256665b94Spooka return -1;
126336f68180Spooka }
1264