Annotation of kernel/bsd/kern/sys_generic.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            26: /*
        !            27:  * Copyright (c) 1982, 1986, 1989, 1993
        !            28:  *     The Regents of the University of California.  All rights reserved.
        !            29:  * (c) UNIX System Laboratories, Inc.
        !            30:  * All or some portions of this file are derived from material licensed
        !            31:  * to the University of California by American Telephone and Telegraph
        !            32:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            33:  * the permission of UNIX System Laboratories, Inc.
        !            34:  *
        !            35:  * Redistribution and use in source and binary forms, with or without
        !            36:  * modification, are permitted provided that the following conditions
        !            37:  * are met:
        !            38:  * 1. Redistributions of source code must retain the above copyright
        !            39:  *    notice, this list of conditions and the following disclaimer.
        !            40:  * 2. Redistributions in binary form must reproduce the above copyright
        !            41:  *    notice, this list of conditions and the following disclaimer in the
        !            42:  *    documentation and/or other materials provided with the distribution.
        !            43:  * 3. All advertising materials mentioning features or use of this software
        !            44:  *    must display the following acknowledgement:
        !            45:  *     This product includes software developed by the University of
        !            46:  *     California, Berkeley and its contributors.
        !            47:  * 4. Neither the name of the University nor the names of its contributors
        !            48:  *    may be used to endorse or promote products derived from this software
        !            49:  *    without specific prior written permission.
        !            50:  *
        !            51:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            52:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            53:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            54:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            55:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            56:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            57:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            58:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            59:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            60:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            61:  * SUCH DAMAGE.
        !            62:  *
        !            63:  *     @(#)sys_generic.c       8.9 (Berkeley) 2/14/95
        !            64:  */
        !            65: 
        !            66: #include <sys/param.h>
        !            67: #include <sys/systm.h>
        !            68: #include <sys/filedesc.h>
        !            69: #include <sys/ioctl.h>
        !            70: #include <sys/file.h>
        !            71: #include <sys/proc.h>
        !            72: #include <sys/socketvar.h>
        !            73: #include <sys/uio.h>
        !            74: #include <sys/kernel.h>
        !            75: #include <sys/stat.h>
        !            76: #include <sys/malloc.h>
        !            77: #if KTRACE
        !            78: #include <sys/ktrace.h>
        !            79: #endif
        !            80: 
        !            81: #include <sys/mount.h>
        !            82: #include <sys/protosw.h>
        !            83: #include <sys/ev.h>
        !            84: #include <sys/user.h>
        !            85: #include <kern/kdebug.h>
        !            86: 
        !            87: /*
        !            88:  * Read system call.
        !            89:  */
        !            90: struct read_args {
        !            91:        int fd;
        !            92:        char *cbuf;
        !            93:        u_int nbyte;
        !            94: };
        !            95: /* ARGSUSED */
        !            96: read(p, uap, retval)
        !            97:        struct proc *p;
        !            98:        register struct read_args *uap;
        !            99:        register_t *retval;
        !           100: {
        !           101:        struct uio auio;
        !           102:        struct iovec aiov;
        !           103: 
        !           104:        aiov.iov_base = (caddr_t)uap->cbuf;
        !           105:        aiov.iov_len = uap->nbyte;
        !           106:        auio.uio_iov = &aiov;
        !           107:        auio.uio_iovcnt = 1;
        !           108:        auio.uio_rw = UIO_READ;
        !           109:        return (rwuio(p, uap->fd, &auio, UIO_READ, retval));    
        !           110: }
        !           111: 
        !           112: struct readv_args {
        !           113:        int fd;
        !           114:        struct iovec *iovp;
        !           115:        u_int iovcnt;
        !           116: };
        !           117: readv(p, uap, retval)
        !           118:        struct proc *p;
        !           119:        register struct readv_args *uap;
        !           120:        int *retval;
        !           121: {
        !           122:        struct uio auio;
        !           123:        register struct iovec *iov;
        !           124:        int error;
        !           125:        struct iovec aiov[UIO_SMALLIOV];
        !           126: 
        !           127:        if (uap->iovcnt > UIO_SMALLIOV) {
        !           128:                if (uap->iovcnt > UIO_MAXIOV)
        !           129:                        return (EINVAL);        
        !           130:                if ((iov = (struct iovec *)
        !           131:                            kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0)
        !           132:                        return (ENOMEM);
        !           133:        } else
        !           134:                iov = aiov;
        !           135:        auio.uio_iov = iov;
        !           136:        auio.uio_iovcnt = uap->iovcnt;
        !           137:        auio.uio_rw = UIO_READ;
        !           138:        error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
        !           139:            uap->iovcnt * sizeof (struct iovec));
        !           140:        if (!error)
        !           141:                error = rwuio(p, uap->fd, &auio, UIO_READ, retval);
        !           142:        if (uap->iovcnt > UIO_SMALLIOV)
        !           143:                kfree(iov, sizeof(struct iovec)*uap->iovcnt);
        !           144:        return (error);
        !           145: }
        !           146: 
        !           147: /*
        !           148:  * Write system call
        !           149:  */
        !           150: struct write_args {
        !           151:        int fd;
        !           152:        char *cbuf;
        !           153:        u_int nbyte;
        !           154: };
        !           155: write(p, uap, retval)
        !           156:        struct proc *p;
        !           157:        register struct write_args *uap;
        !           158:        int *retval;
        !           159: {
        !           160:        struct uio auio;
        !           161:        struct iovec aiov;
        !           162: 
        !           163:        aiov.iov_base = uap->cbuf;
        !           164:        aiov.iov_len = uap->nbyte;
        !           165:        auio.uio_iov = &aiov;
        !           166:        auio.uio_iovcnt = 1;
        !           167:        auio.uio_rw = UIO_WRITE;
        !           168:        return (rwuio(p, uap->fd, &auio, UIO_WRITE, retval));
        !           169: }
        !           170: 
        !           171: struct writev_args {
        !           172:        int fd;
        !           173:        struct iovec *iovp;
        !           174:        u_int iovcnt;
        !           175: };
        !           176: writev(p, uap, retval)
        !           177:        struct proc *p;
        !           178:        register struct writev_args *uap;
        !           179:        int *retval;
        !           180: {
        !           181:        struct uio auio;
        !           182:        register struct iovec *iov;
        !           183:        int error;
        !           184:        struct iovec aiov[UIO_SMALLIOV];
        !           185: 
        !           186:        if (uap->iovcnt > UIO_SMALLIOV) {
        !           187:                if (uap->iovcnt > UIO_MAXIOV)
        !           188:                        return (EINVAL);        
        !           189:                if ((iov = (struct iovec *)
        !           190:                            kalloc(sizeof(struct iovec) * (uap->iovcnt))) == 0)
        !           191:                        return (ENOMEM);
        !           192:        } else
        !           193:                iov = aiov;
        !           194:        auio.uio_iov = iov;
        !           195:        auio.uio_iovcnt = uap->iovcnt;
        !           196:        auio.uio_rw = UIO_WRITE;
        !           197:        error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
        !           198:            uap->iovcnt * sizeof (struct iovec));
        !           199:        if (!error)
        !           200:                error = rwuio(p, uap->fd, &auio, UIO_WRITE, retval);
        !           201:        if (uap->iovcnt > UIO_SMALLIOV)
        !           202:                kfree(iov, sizeof(struct iovec)*uap->iovcnt);
        !           203:        return (error);
        !           204: }
        !           205: 
        !           206: rwuio(p, fdes, uio, rw, retval)
        !           207:        struct proc *p;
        !           208:        int fdes;
        !           209:        register struct uio *uio;
        !           210:        enum uio_rw rw;
        !           211:        int *retval;
        !           212: {
        !           213:        register struct file *fp;
        !           214:        register struct iovec *iov;
        !           215:        int i, count, flag, error;
        !           216: 
        !           217:        if (error = fdgetf(p, fdes, &fp))
        !           218:                return (error);
        !           219: 
        !           220:        if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
        !           221:                return(EBADF);
        !           222:        }
        !           223:        uio->uio_resid = 0;
        !           224:        uio->uio_segflg = UIO_USERSPACE;
        !           225:        uio->uio_procp = p;
        !           226:        iov = uio->uio_iov;
        !           227:        for (i = 0; i < uio->uio_iovcnt; i++) {
        !           228:                if (iov->iov_len < 0) {
        !           229:                        return(EINVAL);
        !           230:                }
        !           231:                uio->uio_resid += iov->iov_len;
        !           232:                if (uio->uio_resid < 0) {
        !           233:                        return(EINVAL);
        !           234:                }
        !           235:                iov++;
        !           236:        }
        !           237:        count = uio->uio_resid;
        !           238:        if (rw == UIO_READ) {
        !           239:                if (error = (*fp->f_ops->fo_read)(fp, uio, fp->f_cred))
        !           240:                                if (uio->uio_resid != count && (error == ERESTART ||
        !           241:                                        error == EINTR || error == EWOULDBLOCK))
        !           242:                                                error = 0;
        !           243:        } else {
        !           244:                if (error = (*fp->f_ops->fo_write)(fp, uio, fp->f_cred)) {
        !           245:                        if (uio->uio_resid != count && (error == ERESTART ||
        !           246:                        error == EINTR || error == EWOULDBLOCK))
        !           247:                                error = 0;
        !           248:                        if (error == EPIPE)
        !           249:                                psignal(p, SIGPIPE);
        !           250:                }
        !           251:        }
        !           252:        *retval = count - uio->uio_resid;
        !           253:        return(error);
        !           254: }
        !           255: 
        !           256: /*
        !           257:  * Ioctl system call
        !           258:  */
        !           259: struct ioctl_args {
        !           260:        int fd;
        !           261:        u_long com;
        !           262:        caddr_t data;
        !           263: };
        !           264: /* ARGSUSED */
        !           265: ioctl(p, uap, retval)
        !           266:        struct proc *p;
        !           267:        register struct ioctl_args *uap;
        !           268:        register_t *retval;
        !           269: {
        !           270:        register struct file *fp;
        !           271:        register u_long com;
        !           272:        register int error;
        !           273:        register u_int size;
        !           274:        caddr_t data, memp;
        !           275:        int tmp;
        !           276: #define STK_PARAMS     128
        !           277:        char stkbuf[STK_PARAMS];
        !           278: 
        !           279:        if (error = fdgetf(p, uap->fd, &fp))
        !           280:                return (error);
        !           281: 
        !           282:        if ((fp->f_flag & (FREAD | FWRITE)) == 0)
        !           283:                return (EBADF);
        !           284:                
        !           285:        /*### LD 6/11/97 Hack Alert: this is to get AppleTalk to work
        !           286:         * while implementing an ATioctl system call
        !           287:         */
        !           288: #if NETAT
        !           289:        {
        !           290:                extern int appletalk_inited;
        !           291: 
        !           292:                if (appletalk_inited && ((uap->com & 0x0000FFFF) == 0xff99)) {
        !           293: #ifdef APPLETALK_DEBUG
        !           294:                        kprintf("ioctl: special AppleTalk \n");
        !           295: #endif
        !           296:                        error = (*fp->f_ops->fo_ioctl)(fp, uap->com, uap->data, p);
        !           297:                        return(error);
        !           298:                }
        !           299:        }
        !           300: 
        !           301: #endif /* NETAT */
        !           302: 
        !           303: 
        !           304:        switch (com = uap->com) {
        !           305:        case FIONCLEX:
        !           306:                *fdflags(p, uap->fd) &= ~UF_EXCLOSE;
        !           307:                return (0);
        !           308:        case FIOCLEX:
        !           309:                *fdflags(p, uap->fd) |= UF_EXCLOSE;
        !           310:                return (0);
        !           311:        }
        !           312: 
        !           313:        /*
        !           314:         * Interpret high order word to find amount of data to be
        !           315:         * copied to/from the user's address space.
        !           316:         */
        !           317:        size = IOCPARM_LEN(com);
        !           318:        if (size > IOCPARM_MAX)
        !           319:                return (ENOTTY);
        !           320:        memp = NULL;
        !           321:        if (size > sizeof (stkbuf)) {
        !           322:                if ((memp = (caddr_t)kalloc(size)) == 0)
        !           323:                        return(ENOMEM);
        !           324:                data = memp;
        !           325:        } else
        !           326:                data = stkbuf;
        !           327:        if (com&IOC_IN) {
        !           328:                if (size) {
        !           329:                        error = copyin(uap->data, data, (u_int)size);
        !           330:                        if (error) {
        !           331:                                if (memp)
        !           332:                                        kfree(memp, size);
        !           333:                                return (error);
        !           334:                        }
        !           335:                } else
        !           336:                        *(caddr_t *)data = uap->data;
        !           337:        } else if ((com&IOC_OUT) && size)
        !           338:                /*
        !           339:                 * Zero the buffer so the user always
        !           340:                 * gets back something deterministic.
        !           341:                 */
        !           342:                bzero(data, size);
        !           343:        else if (com&IOC_VOID)
        !           344:                *(caddr_t *)data = uap->data;
        !           345: 
        !           346:        switch (com) {
        !           347: 
        !           348:        case FIONBIO:
        !           349:                if (tmp = *(int *)data)
        !           350:                        fp->f_flag |= FNONBLOCK;
        !           351:                else
        !           352:                        fp->f_flag &= ~FNONBLOCK;
        !           353:                error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
        !           354:                break;
        !           355: 
        !           356:        case FIOASYNC:
        !           357:                if (tmp = *(int *)data)
        !           358:                        fp->f_flag |= FASYNC;
        !           359:                else
        !           360:                        fp->f_flag &= ~FASYNC;
        !           361:                error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
        !           362:                break;
        !           363: 
        !           364:        case FIOSETOWN:
        !           365:                tmp = *(int *)data;
        !           366:                if (fp->f_type == DTYPE_SOCKET) {
        !           367:                        ((struct socket *)fp->f_data)->so_pgid = tmp;
        !           368:                        error = 0;
        !           369:                        break;
        !           370:                }
        !           371:                if (tmp <= 0) {
        !           372:                        tmp = -tmp;
        !           373:                } else {
        !           374:                        struct proc *p1 = pfind(tmp);
        !           375:                        if (p1 == 0) {
        !           376:                                error = ESRCH;
        !           377:                                break;
        !           378:                        }
        !           379:                        tmp = p1->p_pgrp->pg_id;
        !           380:                }
        !           381:                error = (*fp->f_ops->fo_ioctl)
        !           382:                        (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
        !           383:                break;
        !           384: 
        !           385:        case FIOGETOWN:
        !           386:                if (fp->f_type == DTYPE_SOCKET) {
        !           387:                        error = 0;
        !           388:                        *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
        !           389:                        break;
        !           390:                }
        !           391:                error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
        !           392:                *(int *)data = -*(int *)data;
        !           393:                break;
        !           394: 
        !           395:        default:
        !           396:                error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
        !           397:                /*
        !           398:                 * Copy any data to user, size was
        !           399:                 * already set and checked above.
        !           400:                 */
        !           401:                if (error == 0 && (com&IOC_OUT) && size)
        !           402:                        error = copyout(data, uap->data, (u_int)size);
        !           403:                break;
        !           404:        }
        !           405:        if (memp)
        !           406:                kfree(memp, size);
        !           407:        return (error);
        !           408: }
        !           409: 
        !           410: 
        !           411: int    selwait, nselcoll;
        !           412: 
        !           413: /*
        !           414:  * Select system call.
        !           415:  */
        !           416: struct select_args {
        !           417:        u_int nd;
        !           418:        fd_set *in;
        !           419:        fd_set *ou;
        !           420:        fd_set *ex;
        !           421:        struct timeval *tv;
        !           422: };
        !           423: 
        !           424: select(p, uap, retval)
        !           425:        register struct proc *p;
        !           426:        register struct select_args *uap;
        !           427:        register_t *retval;
        !           428: {
        !           429:        fd_set ibits[3], obits[3];
        !           430:        struct timeval atv;
        !           431:        int s, ncoll, error = 0, timo;
        !           432:        u_int ni;
        !           433:        struct thread *th;
        !           434:        struct uthread  *uth;
        !           435: 
        !           436:        th = current_thread();
        !           437:        uth = th->_uthread;
        !           438: 
        !           439:        bzero((caddr_t)ibits, sizeof(ibits));
        !           440:        bzero((caddr_t)obits, sizeof(obits));
        !           441: 
        !           442:        if (uap->nd > FD_SETSIZE)
        !           443:                return (EINVAL);
        !           444:        if (uap->nd > p->p_fd->fd_nfiles) {
        !           445:                /* forgiving; slightly wrong */
        !           446:                uap->nd = p->p_fd->fd_nfiles;
        !           447:        }
        !           448:        ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
        !           449: 
        !           450: #define        getbits(name, x) \
        !           451:        if (uap->name && (error = copyin((caddr_t)uap->name, \
        !           452:            (caddr_t)&ibits[x], ni))) \
        !           453:                goto done;
        !           454:        getbits(in, 0);
        !           455:        getbits(ou, 1);
        !           456:        getbits(ex, 2);
        !           457: #undef getbits
        !           458:        if (uap->tv) {
        !           459:                error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
        !           460:                        sizeof (atv));
        !           461:                if (error)
        !           462:                        goto done;
        !           463:                if (itimerfix(&atv)) {
        !           464:                        error = EINVAL;
        !           465:                        goto done;
        !           466:                }
        !           467:                s = splhigh();
        !           468:                timeradd(&atv, &time, &atv);
        !           469:                timo = hzto(&atv);
        !           470:                splx(s);
        !           471:        } else
        !           472:                timo = 0;
        !           473: retry:
        !           474:        ncoll = nselcoll;
        !           475:        p->p_flag |= P_SELECT;
        !           476:        error = selscan(p, ibits, obits, uap->nd, retval);
        !           477:        if (error || *retval)
        !           478:                goto done;
        !           479:        s = splhigh();
        !           480:        /* this should be timercmp(&time, &atv, >=) */
        !           481:        if (uap->tv && (time.tv_sec > atv.tv_sec ||
        !           482:            time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
        !           483:                splx(s);
        !           484:                goto done;
        !           485:        }
        !           486:        /*
        !           487:         * To effect a poll, the timeout argument should be
        !           488:         * non-nil, pointing to a zero-valued timeval structure.
        !           489:         */
        !           490:        if (uap->tv && (timo == 0)) {
        !           491:                splx(s);
        !           492:                goto done;
        !           493:        }
        !           494:        if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
        !           495:                splx(s);
        !           496:                goto retry;
        !           497:        }
        !           498:        p->p_flag &= ~P_SELECT;
        !           499:        error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
        !           500:        splx(s);
        !           501:        if (error == 0)
        !           502:                goto retry;
        !           503: done:
        !           504:        p->p_flag &= ~P_SELECT;
        !           505:        /* select is not restarted after signals... */
        !           506:        if (error == ERESTART)
        !           507:                error = EINTR;
        !           508:        if (error == EWOULDBLOCK)
        !           509:                error = 0;
        !           510: #define        putbits(name, x) \
        !           511:        if (uap->name && (error2 = copyout((caddr_t)&obits[x], \
        !           512:            (caddr_t)uap->name, ni))) \
        !           513:                error = error2;
        !           514:        if (error == 0) {
        !           515:                int error2;
        !           516: 
        !           517:                putbits(in, 0);
        !           518:                putbits(ou, 1);
        !           519:                putbits(ex, 2);
        !           520: #undef putbits
        !           521:        }
        !           522:        return (error);
        !           523: }
        !           524: 
        !           525: selscan(p, ibits, obits, nfd, retval)
        !           526:        struct proc *p;
        !           527:        fd_set *ibits, *obits;
        !           528:        int nfd;
        !           529:        register_t *retval;
        !           530: {
        !           531:        register struct filedesc *fdp = p->p_fd;
        !           532:        register int msk, i, j, fd;
        !           533:        register fd_mask bits;
        !           534:        struct file *fp;
        !           535:        int n = 0;
        !           536:        static int flag[3] = { FREAD, FWRITE, 0 };
        !           537: 
        !           538:        for (msk = 0; msk < 3; msk++) {
        !           539:                for (i = 0; i < nfd; i += NFDBITS) {
        !           540:                        bits = ibits[msk].fds_bits[i/NFDBITS];
        !           541:                        while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
        !           542:                                bits &= ~(1 << j);
        !           543:                                fp = fdp->fd_ofiles[fd];
        !           544:                                if (fp == NULL || (fdp->fd_ofileflags[fd] &
        !           545:                                                                UF_RESERVED))
        !           546:                                        return (EBADF);
        !           547:                                if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
        !           548:                                        FD_SET(fd, &obits[msk]);
        !           549:                                        n++;
        !           550:                                }
        !           551:                        }
        !           552:                }
        !           553:        }
        !           554:        *retval = n;
        !           555:        return (0);
        !           556: }
        !           557: 
        !           558: /*ARGSUSED*/
        !           559: seltrue(dev, flag, p)
        !           560:        dev_t dev;
        !           561:        int flag;
        !           562:        struct proc *p;
        !           563: {
        !           564: 
        !           565:        return (1);
        !           566: }
        !           567: 
        !           568: /*
        !           569:  * Record a select request.
        !           570:  */
        !           571: void
        !           572: selrecord(selector, sip)
        !           573:        struct proc *selector;
        !           574:        struct selinfo *sip;
        !           575: {
        !           576:        int             oldpri = splhigh();
        !           577:        thread_t        my_thread = current_thread();
        !           578:        thread_t        selthread;
        !           579: 
        !           580:        selthread = sip->si_thread;
        !           581:        
        !           582:        if (selthread == my_thread) {
        !           583:                splx(oldpri);
        !           584:                return;
        !           585:        }
        !           586:        
        !           587:        if (selthread && selthread->active &&
        !           588:            selthread->wait_event == (caddr_t)&selwait) {
        !           589:                        sip->si_flags |= SI_COLL;
        !           590:                        splx(oldpri);
        !           591:        }
        !           592:        else {
        !           593:                        sip->si_thread = my_thread;
        !           594:                        splx(oldpri);
        !           595:                        thread_deallocate(selthread);
        !           596:                        thread_reference(sip->si_thread);
        !           597:        }
        !           598: 
        !           599:        return;
        !           600: }
        !           601: 
        !           602: void
        !           603: selwakeup(sip)
        !           604:        register struct selinfo *sip;
        !           605: {
        !           606:        register thread_t       the_thread = (thread_t)sip->si_thread;
        !           607:        int oldpri;
        !           608:        
        !           609:        if (the_thread == 0)
        !           610:                return;
        !           611: 
        !           612:        if (sip->si_flags & SI_COLL) {
        !           613:                nselcoll++;
        !           614:                sip->si_flags &= ~SI_COLL;
        !           615:                wakeup((caddr_t)&selwait);
        !           616:        }
        !           617:        
        !           618:        oldpri = splhigh();
        !           619: 
        !           620:        if (the_thread->active) {
        !           621:                /* protect p_flag minimally at splsched() */
        !           622:                if (the_thread->wait_event == &selwait)
        !           623:                        clear_wait(the_thread, THREAD_AWAKENED, TRUE);
        !           624:                if (the_thread->task->proc)
        !           625:                        the_thread->task->proc->p_flag &= ~P_SELECT;
        !           626:        }
        !           627:        
        !           628:        thread_deallocate_interrupt(the_thread);
        !           629:        
        !           630:        sip->si_thread = 0;
        !           631:        
        !           632:        splx(oldpri);
        !           633:        
        !           634: }
        !           635: 
        !           636: void selthreadclear(sip)
        !           637:        register struct selinfo *sip;
        !           638: {
        !           639: 
        !           640:        if (sip->si_thread)
        !           641:                        thread_deallocate_interrupt(sip->si_thread);
        !           642: 
        !           643: }
        !           644: 
        !           645: 
        !           646: /*
        !           647:  * called upon socket close. deque and free all events for
        !           648:  * the socket
        !           649:  */
        !           650: evsofree(struct socket *sp)
        !           651: {
        !           652:   struct eventqelt *eqp, *next;
        !           653: 
        !           654:   if (sp == NULL) return;
        !           655: 
        !           656:   for (eqp = sp->so_evlist.tqh_first; eqp != NULL; eqp = next) {
        !           657:     next = eqp->ee_slist.tqe_next;
        !           658:     evprocdeque(eqp->ee_proc, eqp); // remove from proc q if there
        !           659:     TAILQ_REMOVE(&sp->so_evlist, eqp, ee_slist); // remove from socket q
        !           660:     FREE(eqp, M_TEMP);
        !           661:   }
        !           662: }
        !           663: 
        !           664: 
        !           665: #define DBG_EVENT 0x10
        !           666: 
        !           667: #define DBG_POST 0x10
        !           668: #define DBG_WATCH 0x11
        !           669: #define DBG_WAIT 0x12
        !           670: #define DBG_MOD 0x13
        !           671: #define DBG_EWAKEUP 0x14
        !           672: 
        !           673: #define DBG_MISC_POST MISCDBG_CODE(DBG_EVENT,DBG_POST)
        !           674: #define DBG_MISC_WATCH MISCDBG_CODE(DBG_EVENT,DBG_WATCH)
        !           675: #define DBG_MISC_WAIT MISCDBG_CODE(DBG_EVENT,DBG_WAIT)
        !           676: #define DBG_MISC_MOD MISCDBG_CODE(DBG_EVENT,DBG_MOD)
        !           677: #define DBG_MISC_EWAKEUP MISCDBG_CODE(DBG_EVENT,DBG_EWAKEUP)
        !           678: 
        !           679: 
        !           680: 
        !           681: /*
        !           682:  * enque this event if it's not already queued. wakeup
        !           683:    the proc if we do queue this event to it.
        !           684:  */
        !           685: evprocenque(struct eventqelt *eqp)
        !           686: {
        !           687:   struct proc *p;
        !           688: 
        !           689:   assert(eqp);
        !           690:   if (eqp->ee_flags & EV_QUEUED) {
        !           691:     return;
        !           692:   }
        !           693:   eqp->ee_flags |= EV_QUEUED;
        !           694:   eqp->ee_eventmask = 0;  // disarm
        !           695:   p = eqp->ee_proc;
        !           696:   TAILQ_INSERT_TAIL(&p->p_evlist, eqp, ee_plist);
        !           697:   KERNEL_DEBUG(DBG_MISC_EWAKEUP,0,0,0,eqp,0);
        !           698:   wakeup(&p->p_evlist);
        !           699: }
        !           700: 
        !           701: /*
        !           702:  * given either a sockbuf or a socket run down the
        !           703:  * event list and queue ready events found
        !           704:  */
        !           705: postevent(struct socket *sp, struct sockbuf *sb, int event)
        !           706: {
        !           707:   int mask;
        !           708:   struct eventqelt *evq;
        !           709: 
        !           710:   if (sb) sp = sb->sb_so;
        !           711:   if (!sp || sp->so_evlist.tqh_first == NULL) return;
        !           712: 
        !           713:   KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_START, 0,0,0,0,0);
        !           714: 
        !           715:   for (evq = sp->so_evlist.tqh_first;
        !           716:        evq != NULL; evq = evq->ee_slist.tqe_next) {
        !           717: 
        !           718:     mask = 0;
        !           719: 
        !           720:     /* ready for reading:
        !           721:        - byte cnt >= receive low water mark
        !           722:        - read-half of conn closed
        !           723:        - conn pending for listening sock
        !           724:        - socket error pending
        !           725: 
        !           726:        ready for writing
        !           727:        - byte cnt avail >= send low water mark
        !           728:        - write half of conn closed
        !           729:        - socket error pending
        !           730:        - non-blocking conn completed successfully
        !           731: 
        !           732:        exception pending
        !           733:        - out of band data
        !           734:        - sock at out of band mark
        !           735: 
        !           736:     */
        !           737:     switch (event & EV_DMASK) {
        !           738: 
        !           739:     case EV_RWBYTES:
        !           740:     case EV_OOB:
        !           741:       if (event & EV_OOB) {
        !           742:       if ((evq->ee_eventmask & EV_EX)) {
        !           743:        if (sp->so_oobmark || ((sp->so_state & SS_RCVATMARK))) {
        !           744:          mask |= EV_EX|EV_OOB;
        !           745:        }
        !           746:       }
        !           747:       }
        !           748:       if (event & EV_RWBYTES) {
        !           749:       if ((evq->ee_eventmask & EV_RE) && soreadable(sp)) {
        !           750:        mask |= EV_RE;
        !           751:        evq->ee_req.er_rcnt = sp->so_rcv.sb_cc;
        !           752:       }
        !           753: 
        !           754:       if ((evq->ee_eventmask & EV_WR) && sowriteable(sp)) {
        !           755:        mask |= EV_WR;
        !           756:        evq->ee_req.er_wcnt = sbspace(&sp->so_snd);
        !           757:       }
        !           758:       }
        !           759:     break;
        !           760: 
        !           761:     case EV_RCONN:
        !           762:       if ((evq->ee_eventmask & EV_RE)) {
        !           763:        evq->ee_req.er_rcnt = sp->so_qlen + 1;  // incl this one
        !           764:        mask |= EV_RE|EV_RCONN;
        !           765:       }
        !           766:       break;
        !           767: 
        !           768:     case EV_WCONN:
        !           769:       if ((evq->ee_eventmask & EV_WR)) {
        !           770:        mask |= EV_WR|EV_WCONN;
        !           771:       }
        !           772:       break;
        !           773: 
        !           774:     case EV_RCLOSED:
        !           775:       if ((evq->ee_eventmask & EV_RE)) {
        !           776:        mask |= EV_RE|EV_RCLOSED;
        !           777:        break;
        !           778:       }
        !           779: 
        !           780:     case EV_WCLOSED:
        !           781:       if ((evq->ee_eventmask & EV_WR)) {
        !           782:        mask |= EV_WR|EV_WCLOSED;
        !           783:        break;
        !           784:       }
        !           785: 
        !           786:     case EV_FIN:
        !           787:       if (evq->ee_eventmask & EV_EX) {
        !           788:        mask |= EV_EX|EV_FIN;
        !           789:        break;
        !           790:       }
        !           791: 
        !           792:     case EV_RESET:
        !           793:       if (evq->ee_eventmask & EV_EX) {
        !           794:        mask |= EV_EX|EV_RESET;
        !           795:        break;
        !           796:       }
        !           797: 
        !           798:     default:
        !           799:       return;
        !           800:     } /* switch */
        !           801: 
        !           802:     if (mask) {
        !           803:       evq->ee_req.er_eventbits |= mask;
        !           804:       evprocenque(evq);
        !           805:     }
        !           806:   }
        !           807:   KERNEL_DEBUG(DBG_MISC_POST|DBG_FUNC_END, 0,0,0,0,0);
        !           808: }
        !           809: 
        !           810: /*
        !           811:  * remove and return the first event (eqp=NULL) or a specific
        !           812:  * event, or return NULL if no events found
        !           813:  */
        !           814: struct eventqelt *
        !           815: evprocdeque(struct proc *p, struct eventqelt *eqp)
        !           816: {
        !           817: 
        !           818:   
        !           819:   if (eqp && ((eqp->ee_flags & EV_QUEUED) == NULL))
        !           820:     return(NULL);
        !           821:   if (p->p_evlist.tqh_first == NULL)
        !           822:     return(NULL);
        !           823:   if (eqp == NULL) {  // remove first
        !           824:     eqp = p->p_evlist.tqh_first;
        !           825:   }
        !           826:   TAILQ_REMOVE(&p->p_evlist, eqp, ee_plist);
        !           827:   eqp->ee_flags &= ~EV_QUEUED;
        !           828:   return(eqp);
        !           829: }
        !           830: 
        !           831: struct evwatch_args {
        !           832:   struct eventreq  *u_req;
        !           833:   int               u_eventmask;
        !           834: };
        !           835: 
        !           836: 
        !           837: /*
        !           838:  * watchevent system call. user passes us an event to watch
        !           839:  * for. we malloc an event object, initialize it, and queue
        !           840:  * it to the open socket. when the event occurs, postevent()
        !           841:  * will enque it back to our proc where we can retrieve it
        !           842:  * via waitevent().
        !           843:  *
        !           844:  * should this prevent duplicate events on same socket?
        !           845:  */
        !           846: int
        !           847: watchevent(p, uap, retval)
        !           848:      struct proc *p;
        !           849:      struct evwatch_args *uap;
        !           850:      register_t *retval;
        !           851: {
        !           852:   struct eventqelt *eqp = (struct eventqelt *)0;
        !           853:   struct eventqelt *np;
        !           854:   struct eventreq *erp;
        !           855:   struct file *fp;
        !           856:   struct socket *sp;
        !           857:   int error;
        !           858: 
        !           859:   // get a qelt and fill with users req
        !           860:   MALLOC(eqp, struct eventqelt *, sizeof(struct eventqelt), M_TEMP, M_WAITOK);
        !           861:   if (!eqp) panic("can't MALLOC eqp");
        !           862:   erp = &eqp->ee_req;
        !           863:   // get users request pkt
        !           864:   if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp,
        !           865:                     sizeof(struct eventreq))) {
        !           866:     FREE(eqp, M_TEMP);
        !           867:     KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0);
        !           868:     return(error);
        !           869:   }
        !           870:   KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_START, 0,
        !           871:               erp->er_handle,uap->u_eventmask,eqp,0);
        !           872:   // validate, freeing qelt if errors
        !           873:   error = 0;
        !           874:   if (erp->er_type != EV_FD) {
        !           875:     error = EINVAL;
        !           876:   } else  if (erp->er_handle < 0) {
        !           877:     error = EBADF;
        !           878:   } else  if (erp->er_handle > p->p_fd->fd_nfiles) {
        !           879:     error = EBADF;
        !           880:   } else if ((fp = *fdfile(p, erp->er_handle)) == NULL) {
        !           881:     error = EBADF;
        !           882:   } else if (fp->f_type != DTYPE_SOCKET) {
        !           883:     error = EINVAL;
        !           884:   }
        !           885:   if (error) {
        !           886:     FREE(eqp,M_TEMP);
        !           887:     KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0);
        !           888:     return(error);
        !           889:   }
        !           890: 
        !           891:   erp->er_rcnt = erp->er_wcnt = erp->er_eventbits = 0;
        !           892:   eqp->ee_proc = p;
        !           893:   eqp->ee_eventmask = uap->u_eventmask & EV_MASK;
        !           894:   eqp->ee_flags = 0;
        !           895: 
        !           896:   sp = (struct socket *)fp->f_data;
        !           897:   assert(sp != NULL);
        !           898: 
        !           899:   // only allow one watch per file per proc
        !           900:   for (np = sp->so_evlist.tqh_first; np != NULL; np = np->ee_slist.tqe_next) {
        !           901:     if (np->ee_proc == p) {
        !           902:       FREE(eqp,M_TEMP);
        !           903:       KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0);
        !           904:       return(EINVAL);
        !           905:     }
        !           906:   }
        !           907: 
        !           908:   TAILQ_INSERT_TAIL(&sp->so_evlist, eqp, ee_slist);
        !           909:   postevent(sp, 0, EV_RWBYTES); // catch existing events
        !           910:   KERNEL_DEBUG(DBG_MISC_WATCH|DBG_FUNC_END, 0,0,0,0,0);
        !           911:   return(0);
        !           912: }
        !           913: 
        !           914: struct evwait_args {
        !           915:   struct eventreq *u_req;
        !           916:   struct timeval *tv;
        !           917: };
        !           918: 
        !           919: /*
        !           920:  * waitevent system call.
        !           921:  * grabs the next waiting event for this proc and returns
        !           922:  * it. if no events, user can request to sleep with timeout
        !           923:  * or poll mode (tv=NULL);
        !           924:  */
        !           925: int
        !           926: waitevent(p, uap, retval)
        !           927:      struct proc *p;
        !           928:      struct evwait_args *uap;
        !           929:      register_t *retval;
        !           930: {
        !           931:   int error = 0;
        !           932:   struct eventqelt *eqp;
        !           933:   int timo;
        !           934:   struct timeval atv;
        !           935:   int s;
        !           936: 
        !           937:        if (uap->tv) {
        !           938:                error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
        !           939:                        sizeof (atv));
        !           940:                if (error)
        !           941:                        return(error);
        !           942:                if (itimerfix(&atv)) {
        !           943:                        error = EINVAL;
        !           944:                        return(error);
        !           945:                }
        !           946:                s = splhigh();
        !           947:                timeradd(&atv, &time, &atv);
        !           948:                timo = hzto(&atv);
        !           949:                splx(s);
        !           950:        } else
        !           951:                timo = 0;
        !           952: 
        !           953:   KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_START, 0,0,0,0,0);
        !           954: 
        !           955: retry:
        !           956:   s = splhigh();
        !           957:   if ((eqp = evprocdeque(p,NULL)) != NULL) {
        !           958:     splx(s);
        !           959:     error = copyout((caddr_t)&eqp->ee_req, (caddr_t)uap->u_req,
        !           960:                    sizeof(struct eventreq));
        !           961:     KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,
        !           962:                 eqp->ee_req.er_handle,eqp->ee_req.er_eventbits,eqp,0);
        !           963:     return(error);
        !           964:   } else {
        !           965:     if (uap->tv && (timo == 0)) {
        !           966:         splx(s);
        !           967:         *retval = 1;  // poll failed
        !           968:        return(error);
        !           969:     }
        !           970: 
        !           971:     KERNEL_DEBUG(DBG_MISC_WAIT, 1,0,0,0,0);
        !           972:     error = tsleep(&p->p_evlist, PSOCK | PCATCH, "waitevent", timo);
        !           973:     KERNEL_DEBUG(DBG_MISC_WAIT, 0,0,2,p->p_evlist.tqh_first,0);
        !           974:     splx(s);
        !           975:     if (error == 0)
        !           976:       goto retry;
        !           977:     if (error == ERESTART)
        !           978:       error = EINTR;
        !           979:     if (error == EWOULDBLOCK) {
        !           980:       *retval = 1;
        !           981:       error = 0;
        !           982:     }
        !           983:   }
        !           984:   KERNEL_DEBUG(DBG_MISC_WAIT|DBG_FUNC_END, 0,0,0,0,0);
        !           985:   return(error);
        !           986: }
        !           987: 
        !           988: struct modwatch_args {
        !           989:   struct eventreq *u_req;
        !           990:   int               u_eventmask;
        !           991: };
        !           992: 
        !           993: /*
        !           994:  * modwatch system call. user passes in event to modify.
        !           995:  * if we find it we reset the event bits and que/deque event
        !           996:  * it needed.
        !           997:  */
        !           998: int
        !           999: modwatch(p, uap, retval)
        !          1000:      struct proc *p;
        !          1001:      struct modwatch_args *uap;
        !          1002:      register_t *retval;
        !          1003: {
        !          1004:   struct eventreq er;
        !          1005:   struct eventreq *erp = &er;
        !          1006:   struct eventqelt *evq;
        !          1007:   int error;
        !          1008:   struct file *fp;
        !          1009:   struct socket *sp;
        !          1010:   int flag;
        !          1011: 
        !          1012: 
        !          1013:   // get users request pkt
        !          1014:   if (error = copyin((caddr_t)uap->u_req, (caddr_t)erp,
        !          1015:                     sizeof(struct eventreq))) return(error);
        !          1016: 
        !          1017:   if (erp->er_type != EV_FD) return(EINVAL);
        !          1018:   if (erp->er_handle < 0) return(EBADF);
        !          1019:   if (erp->er_handle > p->p_fd->fd_nfiles) return(EBADF);
        !          1020:   if ((fp = *fdfile(p, erp->er_handle)) == NULL)
        !          1021:     return(EBADF);
        !          1022:   if (fp->f_type != DTYPE_SOCKET) return(EINVAL); // for now must be sock
        !          1023:   sp = (struct socket *)fp->f_data;
        !          1024:   assert(sp != NULL);
        !          1025: 
        !          1026:   // locate event if possible
        !          1027:   for (evq = sp->so_evlist.tqh_first;
        !          1028:        evq != NULL; evq = evq->ee_slist.tqe_next) {
        !          1029:     if (evq->ee_proc == p) break;
        !          1030:   }
        !          1031:   if (evq == NULL) {
        !          1032:     return(EINVAL);
        !          1033:   }
        !          1034: 
        !          1035: 
        !          1036:     if (uap->u_eventmask == EV_RM) {
        !          1037:     evprocdeque(p, evq);
        !          1038:     TAILQ_REMOVE(&sp->so_evlist, evq, ee_slist);
        !          1039:     FREE(evq, M_TEMP);
        !          1040:     return(0);
        !          1041:     }
        !          1042: 
        !          1043:   switch (uap->u_eventmask & EV_MASK) {
        !          1044:  
        !          1045:   case 0:
        !          1046:     flag = 0;
        !          1047:     break;
        !          1048: 
        !          1049:   case EV_RE:
        !          1050:   case EV_WR:
        !          1051:   case EV_RE|EV_WR:
        !          1052:     flag = EV_RWBYTES;
        !          1053:     break;
        !          1054: 
        !          1055:   case EV_EX:
        !          1056:     flag = EV_OOB;
        !          1057:     break;
        !          1058: 
        !          1059:   case EV_EX|EV_RE:
        !          1060:   case EV_EX|EV_WR:
        !          1061:   case EV_EX|EV_RE|EV_WR:
        !          1062:     flag = EV_OOB|EV_RWBYTES;
        !          1063:     break;
        !          1064: 
        !          1065:   default:
        !          1066:     return(EINVAL);
        !          1067:   }
        !          1068: 
        !          1069:    evq->ee_eventmask = uap->u_eventmask & EV_MASK;
        !          1070:    evprocdeque(p, evq);
        !          1071:    evq->ee_req.er_eventbits = 0;
        !          1072:    postevent(sp, 0, flag);
        !          1073:    return(0);
        !          1074: }
        !          1075: 
        !          1076: 
        !          1077: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.