[BACK]Return to rumpclient.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / librumpclient

Annotation of src/lib/librumpclient/rumpclient.c, Revision 1.55

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

CVSweb <webmaster@jp.NetBSD.org>