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