rumpclient.c revision 1.43 1 1.43 pooka /* $NetBSD: rumpclient.c,v 1.43 2011/03/09 15:09:21 pooka Exp $ */
2 1.1 pooka
3 1.1 pooka /*
4 1.11 pooka * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
5 1.1 pooka *
6 1.1 pooka * Redistribution and use in source and binary forms, with or without
7 1.1 pooka * modification, are permitted provided that the following conditions
8 1.1 pooka * are met:
9 1.1 pooka * 1. Redistributions of source code must retain the above copyright
10 1.1 pooka * notice, this list of conditions and the following disclaimer.
11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 pooka * notice, this list of conditions and the following disclaimer in the
13 1.1 pooka * documentation and/or other materials provided with the distribution.
14 1.1 pooka *
15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 pooka * SUCH DAMAGE.
26 1.1 pooka */
27 1.1 pooka
28 1.1 pooka /*
29 1.1 pooka * Client side routines for rump syscall proxy.
30 1.1 pooka */
31 1.1 pooka
32 1.1 pooka #include <sys/cdefs.h>
33 1.43 pooka __RCSID("$NetBSD: rumpclient.c,v 1.43 2011/03/09 15:09:21 pooka Exp $");
34 1.1 pooka
35 1.5 pooka #include <sys/param.h>
36 1.15 pooka #include <sys/event.h>
37 1.1 pooka #include <sys/mman.h>
38 1.1 pooka #include <sys/socket.h>
39 1.1 pooka
40 1.1 pooka #include <arpa/inet.h>
41 1.1 pooka #include <netinet/in.h>
42 1.1 pooka #include <netinet/tcp.h>
43 1.1 pooka
44 1.1 pooka #include <assert.h>
45 1.13 pooka #include <dlfcn.h>
46 1.34 pooka #include <err.h>
47 1.1 pooka #include <errno.h>
48 1.1 pooka #include <fcntl.h>
49 1.13 pooka #include <link.h>
50 1.1 pooka #include <poll.h>
51 1.1 pooka #include <pthread.h>
52 1.11 pooka #include <signal.h>
53 1.1 pooka #include <stdarg.h>
54 1.18 pooka #include <stdbool.h>
55 1.1 pooka #include <stdio.h>
56 1.1 pooka #include <stdlib.h>
57 1.1 pooka #include <string.h>
58 1.1 pooka #include <unistd.h>
59 1.1 pooka
60 1.1 pooka #include <rump/rumpclient.h>
61 1.1 pooka
62 1.13 pooka #define HOSTOPS
63 1.13 pooka int (*host_socket)(int, int, int);
64 1.13 pooka int (*host_close)(int);
65 1.13 pooka int (*host_connect)(int, const struct sockaddr *, socklen_t);
66 1.15 pooka int (*host_fcntl)(int, int, ...);
67 1.13 pooka int (*host_poll)(struct pollfd *, nfds_t, int);
68 1.13 pooka ssize_t (*host_read)(int, void *, size_t);
69 1.39 pooka ssize_t (*host_sendmsg)(int, const struct msghdr *, int);
70 1.13 pooka int (*host_setsockopt)(int, int, int, const void *, socklen_t);
71 1.27 pooka int (*host_dup)(int);
72 1.13 pooka
73 1.17 pooka int (*host_kqueue)(void);
74 1.17 pooka int (*host_kevent)(int, const struct kevent *, size_t,
75 1.17 pooka struct kevent *, size_t, const struct timespec *);
76 1.17 pooka
77 1.30 pooka int (*host_execve)(const char *, char *const[], char *const[]);
78 1.30 pooka
79 1.1 pooka #include "sp_common.c"
80 1.1 pooka
81 1.11 pooka static struct spclient clispc = {
82 1.11 pooka .spc_fd = -1,
83 1.11 pooka };
84 1.1 pooka
85 1.18 pooka static int kq = -1;
86 1.15 pooka static sigset_t fullset;
87 1.12 pooka
88 1.20 pooka static int doconnect(bool);
89 1.29 pooka static int handshake_req(struct spclient *, int, void *, int, bool);
90 1.18 pooka
91 1.32 pooka /*
92 1.32 pooka * Default: don't retry. Most clients can't handle it
93 1.32 pooka * (consider e.g. fds suddenly going missing).
94 1.32 pooka */
95 1.32 pooka static time_t retrytimo = 0;
96 1.18 pooka
97 1.18 pooka static int
98 1.39 pooka send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen)
99 1.18 pooka {
100 1.20 pooka struct timeval starttime, curtime;
101 1.20 pooka time_t prevreconmsg;
102 1.20 pooka unsigned reconretries;
103 1.18 pooka int rv;
104 1.18 pooka
105 1.20 pooka for (prevreconmsg = 0, reconretries = 0;;) {
106 1.39 pooka rv = dosend(spc, iov, iovlen);
107 1.18 pooka if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
108 1.20 pooka /* no persistent connections */
109 1.32 pooka if (retrytimo == 0) {
110 1.32 pooka rv = ENOTCONN;
111 1.20 pooka break;
112 1.32 pooka }
113 1.24 pooka if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
114 1.43 pooka _exit(1);
115 1.20 pooka
116 1.20 pooka if (!prevreconmsg) {
117 1.20 pooka prevreconmsg = time(NULL);
118 1.20 pooka gettimeofday(&starttime, NULL);
119 1.20 pooka }
120 1.20 pooka if (reconretries == 1) {
121 1.20 pooka if (retrytimo == RUMPCLIENT_RETRYCONN_ONCE) {
122 1.20 pooka rv = ENOTCONN;
123 1.20 pooka break;
124 1.20 pooka }
125 1.20 pooka fprintf(stderr, "rump_sp: connection to "
126 1.20 pooka "kernel lost, trying to reconnect ...\n");
127 1.20 pooka } else if (time(NULL) - prevreconmsg > 120) {
128 1.20 pooka fprintf(stderr, "rump_sp: still trying to "
129 1.20 pooka "reconnect ...\n");
130 1.20 pooka prevreconmsg = time(NULL);
131 1.20 pooka }
132 1.20 pooka
133 1.20 pooka /* check that we aren't over the limit */
134 1.20 pooka if (retrytimo > 0) {
135 1.20 pooka struct timeval tmp;
136 1.20 pooka
137 1.20 pooka gettimeofday(&curtime, NULL);
138 1.20 pooka timersub(&curtime, &starttime, &tmp);
139 1.20 pooka if (tmp.tv_sec >= retrytimo) {
140 1.20 pooka fprintf(stderr, "rump_sp: reconnect "
141 1.20 pooka "failed, %lld second timeout\n",
142 1.20 pooka (long long)retrytimo);
143 1.20 pooka return ENOTCONN;
144 1.20 pooka }
145 1.20 pooka }
146 1.20 pooka
147 1.20 pooka /* adhoc backoff timer */
148 1.20 pooka if (reconretries < 10) {
149 1.20 pooka usleep(100000 * reconretries);
150 1.20 pooka } else {
151 1.20 pooka sleep(MIN(10, reconretries-9));
152 1.20 pooka }
153 1.20 pooka reconretries++;
154 1.20 pooka
155 1.20 pooka if ((rv = doconnect(false)) != 0)
156 1.18 pooka continue;
157 1.29 pooka if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
158 1.29 pooka NULL, 0, true)) != 0)
159 1.18 pooka continue;
160 1.20 pooka
161 1.20 pooka /*
162 1.20 pooka * ok, reconnect succesful. we need to return to
163 1.20 pooka * the upper layer to get the entire PDU resent.
164 1.20 pooka */
165 1.20 pooka if (reconretries != 1)
166 1.20 pooka fprintf(stderr, "rump_sp: reconnected!\n");
167 1.20 pooka rv = EAGAIN;
168 1.20 pooka break;
169 1.20 pooka } else {
170 1.20 pooka _DIAGASSERT(errno != EAGAIN);
171 1.18 pooka break;
172 1.18 pooka }
173 1.20 pooka }
174 1.18 pooka
175 1.18 pooka return rv;
176 1.18 pooka }
177 1.18 pooka
178 1.12 pooka static int
179 1.18 pooka cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
180 1.18 pooka bool keeplock)
181 1.12 pooka {
182 1.18 pooka uint64_t mygen;
183 1.18 pooka bool imalive = true;
184 1.12 pooka
185 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
186 1.18 pooka if (!keeplock)
187 1.18 pooka sendunlockl(spc);
188 1.18 pooka mygen = spc->spc_generation;
189 1.12 pooka
190 1.12 pooka rw->rw_error = 0;
191 1.18 pooka while (!rw->rw_done && rw->rw_error == 0) {
192 1.18 pooka if (__predict_false(spc->spc_generation != mygen || !imalive))
193 1.18 pooka break;
194 1.18 pooka
195 1.12 pooka /* are we free to receive? */
196 1.12 pooka if (spc->spc_istatus == SPCSTATUS_FREE) {
197 1.15 pooka struct kevent kev[8];
198 1.15 pooka int gotresp, dosig, rv, i;
199 1.15 pooka
200 1.12 pooka spc->spc_istatus = SPCSTATUS_BUSY;
201 1.12 pooka pthread_mutex_unlock(&spc->spc_mtx);
202 1.12 pooka
203 1.15 pooka dosig = 0;
204 1.15 pooka for (gotresp = 0; !gotresp; ) {
205 1.40 pooka /*
206 1.40 pooka * typically we don't have a frame waiting
207 1.40 pooka * when we come in here, so call kevent now
208 1.40 pooka */
209 1.40 pooka rv = host_kevent(kq, NULL, 0,
210 1.40 pooka kev, __arraycount(kev), NULL);
211 1.40 pooka
212 1.40 pooka if (__predict_false(rv == -1)) {
213 1.40 pooka goto activity;
214 1.40 pooka }
215 1.40 pooka
216 1.40 pooka /*
217 1.40 pooka * XXX: don't know how this can happen
218 1.40 pooka * (timeout cannot expire since there
219 1.40 pooka * isn't one), but it does happen.
220 1.40 pooka * treat it as an expectional condition
221 1.40 pooka * and go through tryread to determine
222 1.40 pooka * alive status.
223 1.40 pooka */
224 1.40 pooka if (__predict_false(rv == 0))
225 1.40 pooka goto activity;
226 1.40 pooka
227 1.40 pooka for (i = 0; i < rv; i++) {
228 1.40 pooka if (kev[i].filter == EVFILT_SIGNAL)
229 1.40 pooka dosig++;
230 1.40 pooka }
231 1.40 pooka if (dosig)
232 1.40 pooka goto cleanup;
233 1.40 pooka
234 1.40 pooka /*
235 1.40 pooka * ok, activity. try to read a frame to
236 1.40 pooka * determine what happens next.
237 1.40 pooka */
238 1.40 pooka activity:
239 1.15 pooka switch (readframe(spc)) {
240 1.15 pooka case 0:
241 1.15 pooka continue;
242 1.15 pooka case -1:
243 1.18 pooka imalive = false;
244 1.15 pooka goto cleanup;
245 1.15 pooka default:
246 1.40 pooka /* case 1 */
247 1.15 pooka break;
248 1.15 pooka }
249 1.12 pooka
250 1.15 pooka switch (spc->spc_hdr.rsp_class) {
251 1.12 pooka case RUMPSP_RESP:
252 1.12 pooka case RUMPSP_ERROR:
253 1.12 pooka kickwaiter(spc);
254 1.15 pooka gotresp = spc->spc_hdr.rsp_reqno ==
255 1.15 pooka rw->rw_reqno;
256 1.12 pooka break;
257 1.12 pooka case RUMPSP_REQ:
258 1.12 pooka handlereq(spc);
259 1.12 pooka break;
260 1.12 pooka default:
261 1.12 pooka /* panic */
262 1.12 pooka break;
263 1.15 pooka }
264 1.12 pooka }
265 1.12 pooka
266 1.15 pooka cleanup:
267 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
268 1.15 pooka if (spc->spc_istatus == SPCSTATUS_WANTED)
269 1.15 pooka kickall(spc);
270 1.15 pooka spc->spc_istatus = SPCSTATUS_FREE;
271 1.15 pooka
272 1.15 pooka /* take one for the team */
273 1.15 pooka if (dosig) {
274 1.15 pooka pthread_mutex_unlock(&spc->spc_mtx);
275 1.15 pooka pthread_sigmask(SIG_SETMASK, mask, NULL);
276 1.15 pooka pthread_sigmask(SIG_SETMASK, &fullset, NULL);
277 1.15 pooka pthread_mutex_lock(&spc->spc_mtx);
278 1.15 pooka }
279 1.12 pooka } else {
280 1.12 pooka spc->spc_istatus = SPCSTATUS_WANTED;
281 1.12 pooka pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx);
282 1.12 pooka }
283 1.12 pooka }
284 1.12 pooka TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries);
285 1.12 pooka pthread_mutex_unlock(&spc->spc_mtx);
286 1.12 pooka pthread_cond_destroy(&rw->rw_cv);
287 1.12 pooka
288 1.18 pooka if (spc->spc_generation != mygen || !imalive) {
289 1.12 pooka return ENOTCONN;
290 1.18 pooka }
291 1.12 pooka return rw->rw_error;
292 1.12 pooka }
293 1.12 pooka
294 1.1 pooka static int
295 1.26 pooka syscall_req(struct spclient *spc, sigset_t *omask, int sysnum,
296 1.3 pooka const void *data, size_t dlen, void **resp)
297 1.1 pooka {
298 1.1 pooka struct rsp_hdr rhdr;
299 1.3 pooka struct respwait rw;
300 1.39 pooka struct iovec iov[2];
301 1.3 pooka int rv;
302 1.1 pooka
303 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + dlen;
304 1.3 pooka rhdr.rsp_class = RUMPSP_REQ;
305 1.3 pooka rhdr.rsp_type = RUMPSP_SYSCALL;
306 1.1 pooka rhdr.rsp_sysnum = sysnum;
307 1.1 pooka
308 1.39 pooka IOVPUT(iov[0], rhdr);
309 1.39 pooka IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen);
310 1.39 pooka
311 1.6 pooka do {
312 1.6 pooka putwait(spc, &rw, &rhdr);
313 1.39 pooka if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) {
314 1.6 pooka unputwait(spc, &rw);
315 1.18 pooka continue;
316 1.6 pooka }
317 1.6 pooka
318 1.26 pooka rv = cliwaitresp(spc, &rw, omask, false);
319 1.20 pooka if (rv == ENOTCONN)
320 1.20 pooka rv = EAGAIN;
321 1.20 pooka } while (rv == EAGAIN);
322 1.3 pooka
323 1.3 pooka *resp = rw.rw_data;
324 1.3 pooka return rv;
325 1.1 pooka }
326 1.1 pooka
327 1.1 pooka static int
328 1.29 pooka handshake_req(struct spclient *spc, int type, void *data,
329 1.29 pooka int cancel, bool haslock)
330 1.10 pooka {
331 1.11 pooka struct handshake_fork rf;
332 1.43 pooka const char *myprogname = NULL; /* XXXgcc */
333 1.10 pooka struct rsp_hdr rhdr;
334 1.10 pooka struct respwait rw;
335 1.12 pooka sigset_t omask;
336 1.21 pooka size_t bonus;
337 1.39 pooka struct iovec iov[2];
338 1.10 pooka int rv;
339 1.10 pooka
340 1.29 pooka if (type == HANDSHAKE_FORK) {
341 1.21 pooka bonus = sizeof(rf);
342 1.21 pooka } else {
343 1.39 pooka myprogname = getprogname();
344 1.39 pooka bonus = strlen(myprogname)+1;
345 1.21 pooka }
346 1.21 pooka
347 1.10 pooka /* performs server handshake */
348 1.21 pooka rhdr.rsp_len = sizeof(rhdr) + bonus;
349 1.10 pooka rhdr.rsp_class = RUMPSP_REQ;
350 1.10 pooka rhdr.rsp_type = RUMPSP_HANDSHAKE;
351 1.29 pooka rhdr.rsp_handshake = type;
352 1.10 pooka
353 1.39 pooka IOVPUT(iov[0], rhdr);
354 1.39 pooka
355 1.12 pooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
356 1.18 pooka if (haslock)
357 1.18 pooka putwait_locked(spc, &rw, &rhdr);
358 1.18 pooka else
359 1.18 pooka putwait(spc, &rw, &rhdr);
360 1.29 pooka if (type == HANDSHAKE_FORK) {
361 1.29 pooka memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
362 1.11 pooka rf.rf_cancel = cancel;
363 1.39 pooka IOVPUT(iov[1], rf);
364 1.21 pooka } else {
365 1.43 pooka IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus);
366 1.11 pooka }
367 1.39 pooka rv = send_with_recon(spc, iov, __arraycount(iov));
368 1.18 pooka if (rv || cancel) {
369 1.18 pooka if (haslock)
370 1.18 pooka unputwait_locked(spc, &rw);
371 1.18 pooka else
372 1.18 pooka unputwait(spc, &rw);
373 1.18 pooka if (cancel) {
374 1.26 pooka goto out;
375 1.18 pooka }
376 1.18 pooka } else {
377 1.18 pooka rv = cliwaitresp(spc, &rw, &omask, haslock);
378 1.10 pooka }
379 1.10 pooka if (rv)
380 1.26 pooka goto out;
381 1.10 pooka
382 1.10 pooka rv = *(int *)rw.rw_data;
383 1.10 pooka free(rw.rw_data);
384 1.10 pooka
385 1.26 pooka out:
386 1.26 pooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
387 1.10 pooka return rv;
388 1.10 pooka }
389 1.10 pooka
390 1.10 pooka static int
391 1.26 pooka prefork_req(struct spclient *spc, sigset_t *omask, void **resp)
392 1.11 pooka {
393 1.11 pooka struct rsp_hdr rhdr;
394 1.11 pooka struct respwait rw;
395 1.39 pooka struct iovec iov[1];
396 1.11 pooka int rv;
397 1.11 pooka
398 1.11 pooka rhdr.rsp_len = sizeof(rhdr);
399 1.11 pooka rhdr.rsp_class = RUMPSP_REQ;
400 1.11 pooka rhdr.rsp_type = RUMPSP_PREFORK;
401 1.11 pooka rhdr.rsp_error = 0;
402 1.11 pooka
403 1.39 pooka IOVPUT(iov[0], rhdr);
404 1.39 pooka
405 1.18 pooka do {
406 1.18 pooka putwait(spc, &rw, &rhdr);
407 1.39 pooka rv = send_with_recon(spc, iov, __arraycount(iov));
408 1.18 pooka if (rv != 0) {
409 1.18 pooka unputwait(spc, &rw);
410 1.18 pooka continue;
411 1.18 pooka }
412 1.11 pooka
413 1.26 pooka rv = cliwaitresp(spc, &rw, omask, false);
414 1.20 pooka if (rv == ENOTCONN)
415 1.20 pooka rv = EAGAIN;
416 1.20 pooka } while (rv == EAGAIN);
417 1.18 pooka
418 1.11 pooka *resp = rw.rw_data;
419 1.11 pooka return rv;
420 1.11 pooka }
421 1.11 pooka
422 1.18 pooka /*
423 1.18 pooka * prevent response code from deadlocking with reconnect code
424 1.18 pooka */
425 1.11 pooka static int
426 1.18 pooka resp_sendlock(struct spclient *spc)
427 1.18 pooka {
428 1.18 pooka int rv = 0;
429 1.18 pooka
430 1.18 pooka pthread_mutex_lock(&spc->spc_mtx);
431 1.18 pooka while (spc->spc_ostatus != SPCSTATUS_FREE) {
432 1.18 pooka if (__predict_false(spc->spc_reconnecting)) {
433 1.18 pooka rv = EBUSY;
434 1.18 pooka goto out;
435 1.18 pooka }
436 1.18 pooka spc->spc_ostatus = SPCSTATUS_WANTED;
437 1.18 pooka pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
438 1.18 pooka }
439 1.18 pooka spc->spc_ostatus = SPCSTATUS_BUSY;
440 1.18 pooka
441 1.18 pooka out:
442 1.18 pooka pthread_mutex_unlock(&spc->spc_mtx);
443 1.18 pooka return rv;
444 1.18 pooka }
445 1.18 pooka
446 1.18 pooka static void
447 1.5 pooka send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
448 1.5 pooka int wantstr)
449 1.1 pooka {
450 1.1 pooka struct rsp_hdr rhdr;
451 1.39 pooka struct iovec iov[2];
452 1.1 pooka
453 1.5 pooka if (wantstr)
454 1.5 pooka dlen = MIN(dlen, strlen(data)+1);
455 1.5 pooka
456 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + dlen;
457 1.1 pooka rhdr.rsp_reqno = reqno;
458 1.3 pooka rhdr.rsp_class = RUMPSP_RESP;
459 1.3 pooka rhdr.rsp_type = RUMPSP_COPYIN;
460 1.1 pooka rhdr.rsp_sysnum = 0;
461 1.1 pooka
462 1.39 pooka IOVPUT(iov[0], rhdr);
463 1.39 pooka IOVPUT_WITHSIZE(iov[1], data, dlen);
464 1.39 pooka
465 1.18 pooka if (resp_sendlock(spc) != 0)
466 1.18 pooka return;
467 1.39 pooka (void)SENDIOV(spc, iov);
468 1.3 pooka sendunlock(spc);
469 1.1 pooka }
470 1.1 pooka
471 1.18 pooka static void
472 1.1 pooka send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
473 1.1 pooka {
474 1.1 pooka struct rsp_hdr rhdr;
475 1.39 pooka struct iovec iov[2];
476 1.1 pooka
477 1.1 pooka rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
478 1.1 pooka rhdr.rsp_reqno = reqno;
479 1.3 pooka rhdr.rsp_class = RUMPSP_RESP;
480 1.3 pooka rhdr.rsp_type = RUMPSP_ANONMMAP;
481 1.1 pooka rhdr.rsp_sysnum = 0;
482 1.1 pooka
483 1.39 pooka IOVPUT(iov[0], rhdr);
484 1.39 pooka IOVPUT(iov[1], addr);
485 1.39 pooka
486 1.18 pooka if (resp_sendlock(spc) != 0)
487 1.18 pooka return;
488 1.39 pooka (void)SENDIOV(spc, iov);
489 1.3 pooka sendunlock(spc);
490 1.1 pooka }
491 1.1 pooka
492 1.1 pooka int
493 1.1 pooka rumpclient_syscall(int sysnum, const void *data, size_t dlen,
494 1.1 pooka register_t *retval)
495 1.1 pooka {
496 1.1 pooka struct rsp_sysresp *resp;
497 1.26 pooka sigset_t omask;
498 1.3 pooka void *rdata;
499 1.3 pooka int rv;
500 1.3 pooka
501 1.26 pooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
502 1.26 pooka
503 1.3 pooka DPRINTF(("rumpsp syscall_req: syscall %d with %p/%zu\n",
504 1.3 pooka sysnum, data, dlen));
505 1.3 pooka
506 1.26 pooka rv = syscall_req(&clispc, &omask, sysnum, data, dlen, &rdata);
507 1.3 pooka if (rv)
508 1.26 pooka goto out;
509 1.3 pooka
510 1.3 pooka resp = rdata;
511 1.3 pooka DPRINTF(("rumpsp syscall_resp: syscall %d error %d, rv: %d/%d\n",
512 1.3 pooka sysnum, rv, resp->rsys_retval[0], resp->rsys_retval[1]));
513 1.1 pooka
514 1.3 pooka memcpy(retval, &resp->rsys_retval, sizeof(resp->rsys_retval));
515 1.3 pooka rv = resp->rsys_error;
516 1.3 pooka free(rdata);
517 1.1 pooka
518 1.26 pooka out:
519 1.26 pooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
520 1.3 pooka return rv;
521 1.3 pooka }
522 1.1 pooka
523 1.3 pooka static void
524 1.3 pooka handlereq(struct spclient *spc)
525 1.3 pooka {
526 1.3 pooka struct rsp_copydata *copydata;
527 1.16 pooka struct rsp_hdr *rhdr = &spc->spc_hdr;
528 1.3 pooka void *mapaddr;
529 1.3 pooka size_t maplen;
530 1.5 pooka int reqtype = spc->spc_hdr.rsp_type;
531 1.1 pooka
532 1.5 pooka switch (reqtype) {
533 1.3 pooka case RUMPSP_COPYIN:
534 1.5 pooka case RUMPSP_COPYINSTR:
535 1.3 pooka /*LINTED*/
536 1.3 pooka copydata = (struct rsp_copydata *)spc->spc_buf;
537 1.3 pooka DPRINTF(("rump_sp handlereq: copyin request: %p/%zu\n",
538 1.3 pooka copydata->rcp_addr, copydata->rcp_len));
539 1.3 pooka send_copyin_resp(spc, spc->spc_hdr.rsp_reqno,
540 1.5 pooka copydata->rcp_addr, copydata->rcp_len,
541 1.5 pooka reqtype == RUMPSP_COPYINSTR);
542 1.3 pooka break;
543 1.3 pooka case RUMPSP_COPYOUT:
544 1.5 pooka case RUMPSP_COPYOUTSTR:
545 1.3 pooka /*LINTED*/
546 1.3 pooka copydata = (struct rsp_copydata *)spc->spc_buf;
547 1.3 pooka DPRINTF(("rump_sp handlereq: copyout request: %p/%zu\n",
548 1.3 pooka copydata->rcp_addr, copydata->rcp_len));
549 1.3 pooka /*LINTED*/
550 1.3 pooka memcpy(copydata->rcp_addr, copydata->rcp_data,
551 1.3 pooka copydata->rcp_len);
552 1.3 pooka break;
553 1.3 pooka case RUMPSP_ANONMMAP:
554 1.3 pooka /*LINTED*/
555 1.3 pooka maplen = *(size_t *)spc->spc_buf;
556 1.3 pooka mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
557 1.3 pooka MAP_ANON, -1, 0);
558 1.3 pooka if (mapaddr == MAP_FAILED)
559 1.3 pooka mapaddr = NULL;
560 1.3 pooka DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
561 1.3 pooka send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
562 1.3 pooka break;
563 1.16 pooka case RUMPSP_RAISE:
564 1.16 pooka DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
565 1.18 pooka raise((int)rhdr->rsp_signo);
566 1.16 pooka /*
567 1.16 pooka * We most likely have signals blocked, but the signal
568 1.16 pooka * will be handled soon enough when we return.
569 1.16 pooka */
570 1.16 pooka break;
571 1.3 pooka default:
572 1.12 pooka printf("PANIC: INVALID TYPE %d\n", reqtype);
573 1.3 pooka abort();
574 1.3 pooka break;
575 1.1 pooka }
576 1.1 pooka
577 1.6 pooka spcfreebuf(spc);
578 1.1 pooka }
579 1.1 pooka
580 1.11 pooka static unsigned ptab_idx;
581 1.11 pooka static struct sockaddr *serv_sa;
582 1.11 pooka
583 1.27 pooka /* dup until we get a "good" fd which does not collide with stdio */
584 1.27 pooka static int
585 1.28 pooka dupgood(int myfd, int mustchange)
586 1.27 pooka {
587 1.28 pooka int ofds[4];
588 1.27 pooka int i;
589 1.27 pooka
590 1.28 pooka for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
591 1.27 pooka assert(i < __arraycount(ofds));
592 1.27 pooka ofds[i] = myfd;
593 1.27 pooka myfd = host_dup(myfd);
594 1.28 pooka if (mustchange) {
595 1.28 pooka i--; /* prevent closing old fd */
596 1.28 pooka mustchange = 0;
597 1.28 pooka }
598 1.27 pooka }
599 1.27 pooka
600 1.27 pooka for (i--; i >= 0; i--) {
601 1.27 pooka host_close(ofds[i]);
602 1.27 pooka }
603 1.27 pooka
604 1.27 pooka return myfd;
605 1.27 pooka }
606 1.27 pooka
607 1.11 pooka static int
608 1.20 pooka doconnect(bool noisy)
609 1.1 pooka {
610 1.18 pooka struct respwait rw;
611 1.18 pooka struct rsp_hdr rhdr;
612 1.15 pooka struct kevent kev[NSIG+1];
613 1.9 pooka char banner[MAXBANNER];
614 1.18 pooka struct pollfd pfd;
615 1.15 pooka int s, error, flags, i;
616 1.9 pooka ssize_t n;
617 1.1 pooka
618 1.18 pooka if (kq != -1)
619 1.18 pooka host_close(kq);
620 1.18 pooka kq = -1;
621 1.19 pooka s = -1;
622 1.18 pooka
623 1.18 pooka if (clispc.spc_fd != -1)
624 1.18 pooka host_close(clispc.spc_fd);
625 1.18 pooka clispc.spc_fd = -1;
626 1.18 pooka
627 1.18 pooka /*
628 1.18 pooka * for reconnect, gate everyone out of the receiver code
629 1.18 pooka */
630 1.18 pooka putwait_locked(&clispc, &rw, &rhdr);
631 1.18 pooka
632 1.18 pooka pthread_mutex_lock(&clispc.spc_mtx);
633 1.18 pooka clispc.spc_reconnecting = 1;
634 1.18 pooka pthread_cond_broadcast(&clispc.spc_cv);
635 1.18 pooka clispc.spc_generation++;
636 1.18 pooka while (clispc.spc_istatus != SPCSTATUS_FREE) {
637 1.18 pooka clispc.spc_istatus = SPCSTATUS_WANTED;
638 1.18 pooka pthread_cond_wait(&rw.rw_cv, &clispc.spc_mtx);
639 1.18 pooka }
640 1.18 pooka kickall(&clispc);
641 1.18 pooka
642 1.18 pooka /*
643 1.18 pooka * we can release it already since we hold the
644 1.18 pooka * send lock during reconnect
645 1.18 pooka * XXX: assert it
646 1.18 pooka */
647 1.18 pooka clispc.spc_istatus = SPCSTATUS_FREE;
648 1.18 pooka pthread_mutex_unlock(&clispc.spc_mtx);
649 1.18 pooka unputwait_locked(&clispc, &rw);
650 1.18 pooka
651 1.18 pooka free(clispc.spc_buf);
652 1.18 pooka clispc.spc_off = 0;
653 1.18 pooka
654 1.28 pooka s = dupgood(host_socket(parsetab[ptab_idx].domain, SOCK_STREAM, 0), 0);
655 1.11 pooka if (s == -1)
656 1.2 pooka return -1;
657 1.1 pooka
658 1.18 pooka pfd.fd = s;
659 1.18 pooka pfd.events = POLLIN;
660 1.18 pooka while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {
661 1.18 pooka if (errno == EINTR)
662 1.18 pooka continue;
663 1.20 pooka error = errno;
664 1.20 pooka if (noisy)
665 1.18 pooka fprintf(stderr, "rump_sp: client connect failed: %s\n",
666 1.18 pooka strerror(errno));
667 1.20 pooka errno = error;
668 1.20 pooka return -1;
669 1.2 pooka }
670 1.1 pooka
671 1.11 pooka if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
672 1.2 pooka error = errno;
673 1.20 pooka if (noisy)
674 1.20 pooka fprintf(stderr, "rump_sp: connect hook failed\n");
675 1.2 pooka errno = error;
676 1.2 pooka return -1;
677 1.1 pooka }
678 1.4 pooka
679 1.13 pooka if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {
680 1.2 pooka error = errno;
681 1.20 pooka if (noisy)
682 1.20 pooka fprintf(stderr, "rump_sp: failed to read banner\n");
683 1.2 pooka errno = error;
684 1.2 pooka return -1;
685 1.1 pooka }
686 1.9 pooka
687 1.9 pooka if (banner[n-1] != '\n') {
688 1.20 pooka if (noisy)
689 1.20 pooka fprintf(stderr, "rump_sp: invalid banner\n");
690 1.9 pooka errno = EINVAL;
691 1.9 pooka return -1;
692 1.9 pooka }
693 1.9 pooka banner[n] = '\0';
694 1.18 pooka /* parse the banner some day */
695 1.9 pooka
696 1.15 pooka flags = host_fcntl(s, F_GETFL, 0);
697 1.15 pooka if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
698 1.20 pooka if (noisy)
699 1.20 pooka fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",
700 1.20 pooka strerror(errno));
701 1.15 pooka errno = EINVAL;
702 1.15 pooka return -1;
703 1.15 pooka }
704 1.18 pooka clispc.spc_fd = s;
705 1.18 pooka clispc.spc_state = SPCSTATE_RUNNING;
706 1.18 pooka clispc.spc_reconnecting = 0;
707 1.15 pooka
708 1.15 pooka /* setup kqueue, we want all signals and the fd */
709 1.28 pooka if ((kq = dupgood(host_kqueue(), 0)) == -1) {
710 1.15 pooka error = errno;
711 1.20 pooka if (noisy)
712 1.20 pooka fprintf(stderr, "rump_sp: cannot setup kqueue");
713 1.15 pooka errno = error;
714 1.15 pooka return -1;
715 1.15 pooka }
716 1.15 pooka
717 1.15 pooka for (i = 0; i < NSIG; i++) {
718 1.15 pooka EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
719 1.15 pooka }
720 1.18 pooka EV_SET(&kev[NSIG], clispc.spc_fd,
721 1.18 pooka EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
722 1.17 pooka if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {
723 1.15 pooka error = errno;
724 1.20 pooka if (noisy)
725 1.20 pooka fprintf(stderr, "rump_sp: kevent() failed");
726 1.15 pooka errno = error;
727 1.15 pooka return -1;
728 1.15 pooka }
729 1.15 pooka
730 1.18 pooka return 0;
731 1.18 pooka }
732 1.18 pooka
733 1.18 pooka static int
734 1.18 pooka doinit(void)
735 1.18 pooka {
736 1.18 pooka
737 1.11 pooka TAILQ_INIT(&clispc.spc_respwait);
738 1.11 pooka pthread_mutex_init(&clispc.spc_mtx, NULL);
739 1.11 pooka pthread_cond_init(&clispc.spc_cv, NULL);
740 1.11 pooka
741 1.11 pooka return 0;
742 1.11 pooka }
743 1.11 pooka
744 1.35 pooka void *rumpclient__dlsym(void *, const char *);
745 1.35 pooka void *rumphijack_dlsym(void *, const char *);
746 1.35 pooka void *
747 1.35 pooka rumpclient__dlsym(void *handle, const char *symbol)
748 1.35 pooka {
749 1.35 pooka
750 1.35 pooka return dlsym(handle, symbol);
751 1.35 pooka }
752 1.35 pooka __weak_alias(rumphijack_dlsym,rumpclient__dlsym);
753 1.35 pooka
754 1.38 pooka static pid_t init_done = 0;
755 1.13 pooka
756 1.11 pooka int
757 1.11 pooka rumpclient_init()
758 1.11 pooka {
759 1.11 pooka char *p;
760 1.11 pooka int error;
761 1.29 pooka int rv = -1;
762 1.29 pooka int hstype;
763 1.38 pooka pid_t mypid;
764 1.29 pooka
765 1.38 pooka /*
766 1.38 pooka * Make sure we're not riding the context of a previous
767 1.38 pooka * host fork. Note: it's *possible* that after n>1 forks
768 1.38 pooka * we have the same pid as one of our exited parents, but
769 1.38 pooka * I'm pretty sure there are 0 practical implications, since
770 1.38 pooka * it means generations would have to skip rumpclient init.
771 1.38 pooka */
772 1.38 pooka if (init_done == (mypid = getpid()))
773 1.29 pooka return 0;
774 1.38 pooka
775 1.38 pooka /* kq does not traverse fork() */
776 1.38 pooka if (init_done != 0)
777 1.38 pooka kq = -1;
778 1.38 pooka init_done = mypid;
779 1.11 pooka
780 1.25 pooka sigfillset(&fullset);
781 1.25 pooka
782 1.13 pooka /*
783 1.13 pooka * sag mir, wo die symbol sind. zogen fort, der krieg beginnt.
784 1.13 pooka * wann wird man je verstehen? wann wird man je verstehen?
785 1.13 pooka */
786 1.13 pooka #define FINDSYM2(_name_,_syscall_) \
787 1.35 pooka if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT, \
788 1.34 pooka #_syscall_)) == NULL) { \
789 1.36 pooka if (rumphijack_dlsym == rumpclient__dlsym) \
790 1.34 pooka host_##_name_ = _name_; /* static fallback */ \
791 1.36 pooka if (host_##_name_ == NULL) \
792 1.34 pooka errx(1, "cannot find %s: %s", #_syscall_, \
793 1.34 pooka dlerror()); \
794 1.34 pooka }
795 1.13 pooka #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
796 1.34 pooka FINDSYM2(socket,__socket30)
797 1.34 pooka FINDSYM(close)
798 1.34 pooka FINDSYM(connect)
799 1.34 pooka FINDSYM(fcntl)
800 1.34 pooka FINDSYM(poll)
801 1.34 pooka FINDSYM(read)
802 1.39 pooka FINDSYM(sendmsg)
803 1.34 pooka FINDSYM(setsockopt)
804 1.34 pooka FINDSYM(dup)
805 1.34 pooka FINDSYM(kqueue)
806 1.34 pooka FINDSYM(execve)
807 1.22 pooka #if !__NetBSD_Prereq__(5,99,7)
808 1.34 pooka FINDSYM(kevent)
809 1.22 pooka #else
810 1.34 pooka FINDSYM2(kevent,_sys___kevent50)
811 1.22 pooka #endif
812 1.13 pooka #undef FINDSYM
813 1.13 pooka #undef FINDSY2
814 1.13 pooka
815 1.28 pooka if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
816 1.28 pooka if ((p = getenv("RUMP_SERVER")) == NULL) {
817 1.28 pooka errno = ENOENT;
818 1.29 pooka goto out;
819 1.28 pooka }
820 1.11 pooka }
821 1.11 pooka
822 1.11 pooka if ((error = parseurl(p, &serv_sa, &ptab_idx, 0)) != 0) {
823 1.11 pooka errno = error;
824 1.29 pooka goto out;
825 1.11 pooka }
826 1.11 pooka
827 1.18 pooka if (doinit() == -1)
828 1.29 pooka goto out;
829 1.28 pooka
830 1.28 pooka if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
831 1.28 pooka sscanf(p, "%d,%d", &clispc.spc_fd, &kq);
832 1.28 pooka unsetenv("RUMPCLIENT__EXECFD");
833 1.29 pooka hstype = HANDSHAKE_EXEC;
834 1.29 pooka } else {
835 1.29 pooka if (doconnect(true) == -1)
836 1.29 pooka goto out;
837 1.29 pooka hstype = HANDSHAKE_GUEST;
838 1.28 pooka }
839 1.28 pooka
840 1.29 pooka error = handshake_req(&clispc, hstype, NULL, 0, false);
841 1.11 pooka if (error) {
842 1.11 pooka pthread_mutex_destroy(&clispc.spc_mtx);
843 1.11 pooka pthread_cond_destroy(&clispc.spc_cv);
844 1.18 pooka if (clispc.spc_fd != -1)
845 1.18 pooka host_close(clispc.spc_fd);
846 1.10 pooka errno = error;
847 1.29 pooka goto out;
848 1.10 pooka }
849 1.29 pooka rv = 0;
850 1.10 pooka
851 1.29 pooka out:
852 1.29 pooka if (rv == -1)
853 1.29 pooka init_done = 0;
854 1.29 pooka return rv;
855 1.11 pooka }
856 1.11 pooka
857 1.11 pooka struct rumpclient_fork {
858 1.11 pooka uint32_t fork_auth[AUTHLEN];
859 1.31 pooka struct spclient fork_spc;
860 1.31 pooka int fork_kq;
861 1.11 pooka };
862 1.11 pooka
863 1.11 pooka struct rumpclient_fork *
864 1.11 pooka rumpclient_prefork(void)
865 1.11 pooka {
866 1.11 pooka struct rumpclient_fork *rpf;
867 1.26 pooka sigset_t omask;
868 1.11 pooka void *resp;
869 1.11 pooka int rv;
870 1.11 pooka
871 1.26 pooka pthread_sigmask(SIG_SETMASK, &fullset, &omask);
872 1.11 pooka rpf = malloc(sizeof(*rpf));
873 1.11 pooka if (rpf == NULL)
874 1.30 pooka goto out;
875 1.11 pooka
876 1.26 pooka if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
877 1.11 pooka free(rpf);
878 1.11 pooka errno = rv;
879 1.26 pooka rpf = NULL;
880 1.26 pooka goto out;
881 1.11 pooka }
882 1.11 pooka
883 1.11 pooka memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
884 1.11 pooka free(resp);
885 1.11 pooka
886 1.31 pooka rpf->fork_spc = clispc;
887 1.31 pooka rpf->fork_kq = kq;
888 1.31 pooka
889 1.26 pooka out:
890 1.26 pooka pthread_sigmask(SIG_SETMASK, &omask, NULL);
891 1.11 pooka return rpf;
892 1.11 pooka }
893 1.11 pooka
894 1.11 pooka int
895 1.11 pooka rumpclient_fork_init(struct rumpclient_fork *rpf)
896 1.11 pooka {
897 1.11 pooka int error;
898 1.23 pooka int osock;
899 1.11 pooka
900 1.23 pooka osock = clispc.spc_fd;
901 1.11 pooka memset(&clispc, 0, sizeof(clispc));
902 1.23 pooka clispc.spc_fd = osock;
903 1.23 pooka
904 1.23 pooka kq = -1; /* kqueue descriptor is not copied over fork() */
905 1.11 pooka
906 1.18 pooka if (doinit() == -1)
907 1.18 pooka return -1;
908 1.20 pooka if (doconnect(false) == -1)
909 1.11 pooka return -1;
910 1.10 pooka
911 1.29 pooka error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
912 1.29 pooka 0, false);
913 1.10 pooka if (error) {
914 1.10 pooka pthread_mutex_destroy(&clispc.spc_mtx);
915 1.10 pooka pthread_cond_destroy(&clispc.spc_cv);
916 1.11 pooka errno = error;
917 1.11 pooka return -1;
918 1.10 pooka }
919 1.11 pooka
920 1.11 pooka return 0;
921 1.1 pooka }
922 1.20 pooka
923 1.42 pooka /*ARGSUSED*/
924 1.20 pooka void
925 1.31 pooka rumpclient_fork_cancel(struct rumpclient_fork *rpf)
926 1.31 pooka {
927 1.31 pooka
928 1.31 pooka /* EUNIMPL */
929 1.31 pooka }
930 1.31 pooka
931 1.31 pooka void
932 1.31 pooka rumpclient_fork_vparent(struct rumpclient_fork *rpf)
933 1.31 pooka {
934 1.31 pooka
935 1.31 pooka clispc = rpf->fork_spc;
936 1.31 pooka kq = rpf->fork_kq;
937 1.31 pooka }
938 1.31 pooka
939 1.31 pooka void
940 1.20 pooka rumpclient_setconnretry(time_t timeout)
941 1.20 pooka {
942 1.20 pooka
943 1.24 pooka if (timeout < RUMPCLIENT_RETRYCONN_DIE)
944 1.20 pooka return; /* gigo */
945 1.20 pooka
946 1.20 pooka retrytimo = timeout;
947 1.20 pooka }
948 1.28 pooka
949 1.28 pooka int
950 1.28 pooka rumpclient__closenotify(int *fdp, enum rumpclient_closevariant variant)
951 1.28 pooka {
952 1.28 pooka int fd = *fdp;
953 1.28 pooka int untilfd, rv;
954 1.28 pooka int newfd;
955 1.28 pooka
956 1.28 pooka switch (variant) {
957 1.28 pooka case RUMPCLIENT_CLOSE_FCLOSEM:
958 1.28 pooka untilfd = MAX(clispc.spc_fd, kq);
959 1.28 pooka for (; fd <= untilfd; fd++) {
960 1.28 pooka if (fd == clispc.spc_fd || fd == kq)
961 1.28 pooka continue;
962 1.28 pooka rv = host_close(fd);
963 1.28 pooka if (rv == -1)
964 1.28 pooka return -1;
965 1.28 pooka }
966 1.28 pooka *fdp = fd;
967 1.28 pooka break;
968 1.28 pooka
969 1.28 pooka case RUMPCLIENT_CLOSE_CLOSE:
970 1.28 pooka case RUMPCLIENT_CLOSE_DUP2:
971 1.28 pooka if (fd == clispc.spc_fd) {
972 1.28 pooka struct kevent kev[2];
973 1.28 pooka
974 1.28 pooka newfd = dupgood(clispc.spc_fd, 1);
975 1.28 pooka if (newfd == -1)
976 1.28 pooka return -1;
977 1.28 pooka /*
978 1.28 pooka * now, we have a new socket number, so change
979 1.28 pooka * the file descriptor that kqueue is
980 1.28 pooka * monitoring. remove old and add new.
981 1.28 pooka */
982 1.28 pooka EV_SET(&kev[0], clispc.spc_fd,
983 1.28 pooka EVFILT_READ, EV_DELETE, 0, 0, 0);
984 1.28 pooka EV_SET(&kev[1], newfd,
985 1.28 pooka EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
986 1.28 pooka if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {
987 1.28 pooka int sverrno = errno;
988 1.28 pooka host_close(newfd);
989 1.28 pooka errno = sverrno;
990 1.28 pooka return -1;
991 1.28 pooka }
992 1.28 pooka clispc.spc_fd = newfd;
993 1.28 pooka }
994 1.28 pooka if (fd == kq) {
995 1.28 pooka newfd = dupgood(kq, 1);
996 1.28 pooka if (newfd == -1)
997 1.28 pooka return -1;
998 1.28 pooka kq = newfd;
999 1.28 pooka }
1000 1.28 pooka break;
1001 1.28 pooka }
1002 1.28 pooka
1003 1.28 pooka return 0;
1004 1.28 pooka }
1005 1.28 pooka
1006 1.30 pooka pid_t
1007 1.31 pooka rumpclient_fork()
1008 1.30 pooka {
1009 1.30 pooka
1010 1.31 pooka return rumpclient__dofork(fork);
1011 1.30 pooka }
1012 1.30 pooka
1013 1.28 pooka /*
1014 1.28 pooka * Process is about to exec. Save info about our existing connection
1015 1.28 pooka * in the env. rumpclient will check for this info in init().
1016 1.28 pooka * This is mostly for the benefit of rumphijack, but regular applications
1017 1.28 pooka * may use it as well.
1018 1.28 pooka */
1019 1.28 pooka int
1020 1.30 pooka rumpclient_exec(const char *path, char *const argv[], char *const envp[])
1021 1.28 pooka {
1022 1.28 pooka char buf[4096];
1023 1.28 pooka char **newenv;
1024 1.28 pooka char *envstr, *envstr2;
1025 1.30 pooka size_t nelem;
1026 1.30 pooka int rv, sverrno;
1027 1.28 pooka
1028 1.28 pooka snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
1029 1.28 pooka clispc.spc_fd, kq);
1030 1.28 pooka envstr = malloc(strlen(buf)+1);
1031 1.28 pooka if (envstr == NULL) {
1032 1.28 pooka return ENOMEM;
1033 1.28 pooka }
1034 1.28 pooka strcpy(envstr, buf);
1035 1.28 pooka
1036 1.28 pooka /* do we have a fully parsed url we want to forward in the env? */
1037 1.28 pooka if (*parsedurl != '\0') {
1038 1.28 pooka snprintf(buf, sizeof(buf),
1039 1.28 pooka "RUMP__PARSEDSERVER=%s", parsedurl);
1040 1.28 pooka envstr2 = malloc(strlen(buf)+1);
1041 1.28 pooka if (envstr2 == NULL) {
1042 1.28 pooka free(envstr);
1043 1.28 pooka return ENOMEM;
1044 1.28 pooka }
1045 1.28 pooka strcpy(envstr2, buf);
1046 1.28 pooka } else {
1047 1.28 pooka envstr2 = NULL;
1048 1.28 pooka }
1049 1.28 pooka
1050 1.30 pooka for (nelem = 0; envp && envp[nelem]; nelem++)
1051 1.30 pooka continue;
1052 1.28 pooka
1053 1.33 pooka newenv = malloc(sizeof(*newenv) * (nelem+3));
1054 1.28 pooka if (newenv == NULL) {
1055 1.28 pooka free(envstr2);
1056 1.28 pooka free(envstr);
1057 1.28 pooka return ENOMEM;
1058 1.28 pooka }
1059 1.30 pooka memcpy(&newenv[0], envp, nelem*sizeof(*envp));
1060 1.28 pooka
1061 1.30 pooka newenv[nelem] = envstr;
1062 1.30 pooka newenv[nelem+1] = envstr2;
1063 1.30 pooka newenv[nelem+2] = NULL;
1064 1.30 pooka
1065 1.30 pooka rv = host_execve(path, argv, newenv);
1066 1.30 pooka
1067 1.30 pooka _DIAGASSERT(rv != 0);
1068 1.30 pooka sverrno = errno;
1069 1.30 pooka free(envstr2);
1070 1.30 pooka free(envstr);
1071 1.30 pooka free(newenv);
1072 1.30 pooka errno = sverrno;
1073 1.30 pooka return rv;
1074 1.28 pooka }
1075 1.31 pooka
1076 1.31 pooka int
1077 1.31 pooka rumpclient_daemon(int nochdir, int noclose)
1078 1.31 pooka {
1079 1.31 pooka struct rumpclient_fork *rf;
1080 1.31 pooka int sverrno;
1081 1.31 pooka
1082 1.31 pooka if ((rf = rumpclient_prefork()) == NULL)
1083 1.31 pooka return -1;
1084 1.31 pooka
1085 1.31 pooka if (daemon(nochdir, noclose) == -1) {
1086 1.31 pooka sverrno = errno;
1087 1.31 pooka rumpclient_fork_cancel(rf);
1088 1.31 pooka errno = sverrno;
1089 1.31 pooka return -1;
1090 1.31 pooka }
1091 1.31 pooka
1092 1.31 pooka if (rumpclient_fork_init(rf) == -1)
1093 1.31 pooka return -1;
1094 1.31 pooka
1095 1.31 pooka return 0;
1096 1.31 pooka }
1097