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