BSD 4_4 release
[unix-history] / usr / src / sys / kern / sys_generic.c
index 572eb8f..84b03c7 100644 (file)
@@ -1,52 +1,69 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * Redistribution is only permitted until one year after the first shipment
- * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
- * binary forms are permitted provided that: (1) source distributions retain
- * this entire copyright notice and comment, and (2) distributions including
- * binaries display the following acknowledgement:  This product includes
- * software developed by the University of California, Berkeley and its
- * contributors'' in the documentation or other materials provided with the
- * distribution and in all advertising materials mentioning features or use
- * of this software.  Neither the name of the University nor the names of
- * its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)sys_generic.c       7.23 (Berkeley) 7/22/90
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)sys_generic.c       8.1 (Berkeley) 7/19/93
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "user.h"
-#include "ioctl.h"
-#include "file.h"
-#include "proc.h"
-#include "uio.h"
-#include "kernel.h"
-#include "stat.h"
-#include "malloc.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/filedesc.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
 #ifdef KTRACE
 #ifdef KTRACE
-#include "ktrace.h"
+#include <sys/ktrace.h>
 #endif
 
 /*
  * Read system call.
  */
 #endif
 
 /*
  * Read system call.
  */
+struct read_args {
+       int     fdes;
+       char    *cbuf;
+       unsigned count;
+};
+/* ARGSUSED */
 read(p, uap, retval)
        struct proc *p;
 read(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     fdes;
-               char    *cbuf;
-               unsigned count;
-       } *uap;
+       register struct read_args *uap;
        int *retval;
 {
        register struct file *fp;
        int *retval;
 {
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        struct iovec aiov;
        long cnt, error = 0;
        struct uio auio;
        struct iovec aiov;
        long cnt, error = 0;
@@ -54,8 +71,8 @@ read(p, uap, retval)
        struct iovec ktriov;
 #endif
 
        struct iovec ktriov;
 #endif
 
-       if (((unsigned)uap->fdes) >= NOFILE ||
-           (fp = u.u_ofile[uap->fdes]) == NULL ||
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
            (fp->f_flag & FREAD) == 0)
                return (EBADF);
        aiov.iov_base = (caddr_t)uap->cbuf;
            (fp->f_flag & FREAD) == 0)
                return (EBADF);
        aiov.iov_base = (caddr_t)uap->cbuf;
@@ -65,6 +82,7 @@ read(p, uap, retval)
        auio.uio_resid = uap->count;
        auio.uio_rw = UIO_READ;
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_resid = uap->count;
        auio.uio_rw = UIO_READ;
        auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
 #ifdef KTRACE
        /*
         * if tracing, save a copy of iovec
 #ifdef KTRACE
        /*
         * if tracing, save a copy of iovec
@@ -89,19 +107,21 @@ read(p, uap, retval)
 /*
  * Scatter read system call.
  */
 /*
  * Scatter read system call.
  */
+struct readv_args {
+       int     fdes;
+       struct  iovec *iovp;
+       unsigned iovcnt;
+};
 readv(p, uap, retval)
        struct proc *p;
 readv(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     fdes;
-               struct  iovec *iovp;
-               unsigned iovcnt;
-       } *uap;
+       register struct readv_args *uap;
        int *retval;
 {
        register struct file *fp;
        int *retval;
 {
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        register struct iovec *iov;
        struct uio auio;
        register struct iovec *iov;
-       struct iovec *saveiov;
+       struct iovec *needfree;
        struct iovec aiov[UIO_SMALLIOV];
        long i, cnt, error = 0;
        unsigned iovlen;
        struct iovec aiov[UIO_SMALLIOV];
        long i, cnt, error = 0;
        unsigned iovlen;
@@ -109,8 +129,8 @@ readv(p, uap, retval)
        struct iovec *ktriov = NULL;
 #endif
 
        struct iovec *ktriov = NULL;
 #endif
 
-       if (((unsigned)uap->fdes) >= NOFILE ||
-           (fp = u.u_ofile[uap->fdes]) == NULL ||
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
            (fp->f_flag & FREAD) == 0)
                return (EBADF);
        /* note: can't use iovlen until iovcnt is validated */
            (fp->f_flag & FREAD) == 0)
                return (EBADF);
        /* note: can't use iovlen until iovcnt is validated */
@@ -119,13 +139,16 @@ readv(p, uap, retval)
                if (uap->iovcnt > UIO_MAXIOV)
                        return (EINVAL);
                MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
                if (uap->iovcnt > UIO_MAXIOV)
                        return (EINVAL);
                MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
-               saveiov = iov;
-       } else
+               needfree = iov;
+       } else {
                iov = aiov;
                iov = aiov;
+               needfree = NULL;
+       }
        auio.uio_iov = iov;
        auio.uio_iovcnt = uap->iovcnt;
        auio.uio_rw = UIO_READ;
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_iov = iov;
        auio.uio_iovcnt = uap->iovcnt;
        auio.uio_rw = UIO_READ;
        auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
        if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
                goto done;
        auio.uio_resid = 0;
        if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
                goto done;
        auio.uio_resid = 0;
@@ -166,24 +189,26 @@ readv(p, uap, retval)
 #endif
        *retval = cnt;
 done:
 #endif
        *retval = cnt;
 done:
-       if (uap->iovcnt > UIO_SMALLIOV)
-               FREE(saveiov, M_IOV);
+       if (needfree)
+               FREE(needfree, M_IOV);
        return (error);
 }
 
 /*
  * Write system call
  */
        return (error);
 }
 
 /*
  * Write system call
  */
+struct write_args {
+       int     fdes;
+       char    *cbuf;
+       unsigned count;
+};
 write(p, uap, retval)
        struct proc *p;
 write(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     fdes;
-               char    *cbuf;
-               unsigned count;
-       } *uap;
+       register struct write_args *uap;
        int *retval;
 {
        register struct file *fp;
        int *retval;
 {
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        struct iovec aiov;
        long cnt, error = 0;
        struct uio auio;
        struct iovec aiov;
        long cnt, error = 0;
@@ -191,8 +216,8 @@ write(p, uap, retval)
        struct iovec ktriov;
 #endif
 
        struct iovec ktriov;
 #endif
 
-       if (((unsigned)uap->fdes) >= NOFILE ||
-           (fp = u.u_ofile[uap->fdes]) == NULL ||
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
            (fp->f_flag & FWRITE) == 0)
                return (EBADF);
        aiov.iov_base = (caddr_t)uap->cbuf;
            (fp->f_flag & FWRITE) == 0)
                return (EBADF);
        aiov.iov_base = (caddr_t)uap->cbuf;
@@ -202,6 +227,7 @@ write(p, uap, retval)
        auio.uio_resid = uap->count;
        auio.uio_rw = UIO_WRITE;
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_resid = uap->count;
        auio.uio_rw = UIO_WRITE;
        auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
 #ifdef KTRACE
        /*
         * if tracing, save a copy of iovec
 #ifdef KTRACE
        /*
         * if tracing, save a copy of iovec
@@ -230,19 +256,21 @@ write(p, uap, retval)
 /*
  * Gather write system call
  */
 /*
  * Gather write system call
  */
+struct writev_args {
+       int     fdes;
+       struct  iovec *iovp;
+       unsigned iovcnt;
+};
 writev(p, uap, retval)
        struct proc *p;
 writev(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     fdes;
-               struct  iovec *iovp;
-               unsigned iovcnt;
-       } *uap;
+       register struct writev_args *uap;
        int *retval;
 {
        register struct file *fp;
        int *retval;
 {
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        register struct iovec *iov;
        struct uio auio;
        register struct iovec *iov;
-       struct iovec *saveiov;
+       struct iovec *needfree;
        struct iovec aiov[UIO_SMALLIOV];
        long i, cnt, error = 0;
        unsigned iovlen;
        struct iovec aiov[UIO_SMALLIOV];
        long i, cnt, error = 0;
        unsigned iovlen;
@@ -250,8 +278,8 @@ writev(p, uap, retval)
        struct iovec *ktriov = NULL;
 #endif
 
        struct iovec *ktriov = NULL;
 #endif
 
-       if (((unsigned)uap->fdes) >= NOFILE ||
-           (fp = u.u_ofile[uap->fdes]) == NULL ||
+       if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
            (fp->f_flag & FWRITE) == 0)
                return (EBADF);
        /* note: can't use iovlen until iovcnt is validated */
            (fp->f_flag & FWRITE) == 0)
                return (EBADF);
        /* note: can't use iovlen until iovcnt is validated */
@@ -260,13 +288,16 @@ writev(p, uap, retval)
                if (uap->iovcnt > UIO_MAXIOV)
                        return (EINVAL);
                MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
                if (uap->iovcnt > UIO_MAXIOV)
                        return (EINVAL);
                MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
-               saveiov = iov;
-       } else
+               needfree = iov;
+       } else {
                iov = aiov;
                iov = aiov;
+               needfree = NULL;
+       }
        auio.uio_iov = iov;
        auio.uio_iovcnt = uap->iovcnt;
        auio.uio_rw = UIO_WRITE;
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_iov = iov;
        auio.uio_iovcnt = uap->iovcnt;
        auio.uio_rw = UIO_WRITE;
        auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
        if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
                goto done;
        auio.uio_resid = 0;
        if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
                goto done;
        auio.uio_resid = 0;
@@ -310,45 +341,48 @@ writev(p, uap, retval)
 #endif
        *retval = cnt;
 done:
 #endif
        *retval = cnt;
 done:
-       if (uap->iovcnt > UIO_SMALLIOV)
-               FREE(saveiov, M_IOV);
+       if (needfree)
+               FREE(needfree, M_IOV);
        return (error);
 }
 
 /*
  * Ioctl system call
  */
        return (error);
 }
 
 /*
  * Ioctl system call
  */
+struct ioctl_args {
+       int     fdes;
+       int     cmd;
+       caddr_t cmarg;
+};
 /* ARGSUSED */
 ioctl(p, uap, retval)
        struct proc *p;
 /* ARGSUSED */
 ioctl(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     fdes;
-               int     cmd;
-               caddr_t cmarg;
-       } *uap;
+       register struct ioctl_args *uap;
        int *retval;
 {
        register struct file *fp;
        int *retval;
 {
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        register int com, error;
        register u_int size;
        caddr_t memp = 0;
 #define STK_PARAMS     128
        char stkbuf[STK_PARAMS];
        caddr_t data = stkbuf;
        register int com, error;
        register u_int size;
        caddr_t memp = 0;
 #define STK_PARAMS     128
        char stkbuf[STK_PARAMS];
        caddr_t data = stkbuf;
+       int tmp;
 
 
-       if ((unsigned)uap->fdes >= NOFILE ||
-           (fp = u.u_ofile[uap->fdes]) == NULL)
+       if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
                return (EBADF);
        if ((fp->f_flag & (FREAD|FWRITE)) == 0)
                return (EBADF);
        com = uap->cmd;
 
        if (com == FIOCLEX) {
                return (EBADF);
        if ((fp->f_flag & (FREAD|FWRITE)) == 0)
                return (EBADF);
        com = uap->cmd;
 
        if (com == FIOCLEX) {
-               u.u_pofile[uap->fdes] |= UF_EXCLOSE;
+               fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
                return (0);
        }
        if (com == FIONCLEX) {
                return (0);
        }
        if (com == FIONCLEX) {
-               u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
+               fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
                return (0);
        }
 
                return (0);
        }
 
@@ -386,22 +420,54 @@ ioctl(p, uap, retval)
        switch (com) {
 
        case FIONBIO:
        switch (com) {
 
        case FIONBIO:
-               error = fset(fp, FNDELAY, *(int *)data);
+               if (tmp = *(int *)data)
+                       fp->f_flag |= FNONBLOCK;
+               else
+                       fp->f_flag &= ~FNONBLOCK;
+               error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
                break;
 
        case FIOASYNC:
                break;
 
        case FIOASYNC:
-               error = fset(fp, FASYNC, *(int *)data);
+               if (tmp = *(int *)data)
+                       fp->f_flag |= FASYNC;
+               else
+                       fp->f_flag &= ~FASYNC;
+               error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
                break;
 
        case FIOSETOWN:
                break;
 
        case FIOSETOWN:
-               error = fsetown(fp, *(int *)data);
+               tmp = *(int *)data;
+               if (fp->f_type == DTYPE_SOCKET) {
+                       ((struct socket *)fp->f_data)->so_pgid = tmp;
+                       error = 0;
+                       break;
+               }
+               if (tmp <= 0) {
+                       tmp = -tmp;
+               } else {
+                       struct proc *p1 = pfind(tmp);
+                       if (p1 == 0) {
+                               error = ESRCH;
+                               break;
+                       }
+                       tmp = p1->p_pgrp->pg_id;
+               }
+               error = (*fp->f_ops->fo_ioctl)
+                       (fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
                break;
 
        case FIOGETOWN:
                break;
 
        case FIOGETOWN:
-               error = fgetown(fp, (int *)data);
+               if (fp->f_type == DTYPE_SOCKET) {
+                       error = 0;
+                       *(int *)data = ((struct socket *)fp->f_data)->so_pgid;
+                       break;
+               }
+               error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
+               *(int *)data = -*(int *)data;
                break;
                break;
+
        default:
        default:
-               error = (*fp->f_ops->fo_ioctl)(fp, com, data);
+               error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
                /*
                 * Copy any data to user, size was
                 * already set and checked above.
                /*
                 * Copy any data to user, size was
                 * already set and checked above.
@@ -415,37 +481,38 @@ ioctl(p, uap, retval)
        return (error);
 }
 
        return (error);
 }
 
-int    nselcoll;
+int    selwait, nselcoll;
 
 /*
  * Select system call.
  */
 
 /*
  * Select system call.
  */
+struct select_args {
+       u_int   nd;
+       fd_set  *in, *ou, *ex;
+       struct  timeval *tv;
+};
 select(p, uap, retval)
        register struct proc *p;
 select(p, uap, retval)
        register struct proc *p;
-       register struct args {
-               int     nd;
-               fd_set  *in, *ou, *ex;
-               struct  timeval *tv;
-       } *uap;
+       register struct select_args *uap;
        int *retval;
 {
        fd_set ibits[3], obits[3];
        struct timeval atv;
        int *retval;
 {
        fd_set ibits[3], obits[3];
        struct timeval atv;
-       int s, ncoll, ni, error = 0, timo;
+       int s, ncoll, error = 0, timo;
+       u_int ni;
 
        bzero((caddr_t)ibits, sizeof(ibits));
        bzero((caddr_t)obits, sizeof(obits));
 
        bzero((caddr_t)ibits, sizeof(ibits));
        bzero((caddr_t)obits, sizeof(obits));
-       if (uap->nd > NOFILE)
-               uap->nd = NOFILE;       /* forgiving, if slightly wrong */
-       ni = howmany(uap->nd, NFDBITS);
+       if (uap->nd > FD_SETSIZE)
+               return (EINVAL);
+       if (uap->nd > p->p_fd->fd_nfiles)
+               uap->nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
+       ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
 
 #define        getbits(name, x) \
 
 #define        getbits(name, x) \
-       if (uap->name) { \
-               error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
-                   (unsigned)(ni * sizeof(fd_mask))); \
-               if (error) \
-                       goto done; \
-       }
+       if (uap->name && \
+           (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \
+               goto done;
        getbits(in, 0);
        getbits(ou, 1);
        getbits(ex, 2);
        getbits(in, 0);
        getbits(ou, 1);
        getbits(ex, 2);
@@ -460,14 +527,21 @@ select(p, uap, retval)
                        error = EINVAL;
                        goto done;
                }
                        error = EINVAL;
                        goto done;
                }
-               s = splhigh(); timevaladd(&atv, &time); splx(s);
+               s = splclock();
+               timevaladd(&atv, (struct timeval *)&time);
                timo = hzto(&atv);
                timo = hzto(&atv);
+               /*
+                * Avoid inadvertently sleeping forever.
+                */
+               if (timo == 0)
+                       timo = 1;
+               splx(s);
        } else
                timo = 0;
 retry:
        ncoll = nselcoll;
        p->p_flag |= SSEL;
        } else
                timo = 0;
 retry:
        ncoll = nselcoll;
        p->p_flag |= SSEL;
-       error = selscan(ibits, obits, uap->nd, retval);
+       error = selscan(p, ibits, obits, uap->nd, retval);
        if (error || *retval)
                goto done;
        s = splhigh();
        if (error || *retval)
                goto done;
        s = splhigh();
@@ -494,13 +568,12 @@ done:
        if (error == EWOULDBLOCK)
                error = 0;
 #define        putbits(name, x) \
        if (error == EWOULDBLOCK)
                error = 0;
 #define        putbits(name, x) \
-       if (uap->name) { \
-               int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
-                   (unsigned)(ni * sizeof(fd_mask))); \
-               if (error2) \
-                       error = error2; \
-       }
+       if (uap->name && \
+           (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
+               error = error2;
        if (error == 0) {
        if (error == 0) {
+               int error2;
+
                putbits(in, 0);
                putbits(ou, 1);
                putbits(ex, 2);
                putbits(in, 0);
                putbits(ou, 1);
                putbits(ex, 2);
@@ -509,68 +582,89 @@ done:
        return (error);
 }
 
        return (error);
 }
 
-selscan(ibits, obits, nfd, retval)
+selscan(p, ibits, obits, nfd, retval)
+       struct proc *p;
        fd_set *ibits, *obits;
        int nfd, *retval;
 {
        fd_set *ibits, *obits;
        int nfd, *retval;
 {
-       register int which, i, j;
+       register struct filedesc *fdp = p->p_fd;
+       register int msk, i, j, fd;
        register fd_mask bits;
        register fd_mask bits;
-       int flag;
        struct file *fp;
        struct file *fp;
-       int error = 0, n = 0;
-
-       for (which = 0; which < 3; which++) {
-               switch (which) {
-
-               case 0:
-                       flag = FREAD; break;
-
-               case 1:
-                       flag = FWRITE; break;
+       int n = 0;
+       static int flag[3] = { FREAD, FWRITE, 0 };
 
 
-               case 2:
-                       flag = 0; break;
-               }
+       for (msk = 0; msk < 3; msk++) {
                for (i = 0; i < nfd; i += NFDBITS) {
                for (i = 0; i < nfd; i += NFDBITS) {
-                       bits = ibits[which].fds_bits[i/NFDBITS];
-                       while ((j = ffs(bits)) && i + --j < nfd) {
+                       bits = ibits[msk].fds_bits[i/NFDBITS];
+                       while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
                                bits &= ~(1 << j);
                                bits &= ~(1 << j);
-                               fp = u.u_ofile[i + j];
-                               if (fp == NULL) {
-                                       error = EBADF;
-                                       break;
-                               }
-                               if ((*fp->f_ops->fo_select)(fp, flag)) {
-                                       FD_SET(i + j, &obits[which]);
+                               fp = fdp->fd_ofiles[fd];
+                               if (fp == NULL)
+                                       return (EBADF);
+                               if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
+                                       FD_SET(fd, &obits[msk]);
                                        n++;
                                }
                        }
                }
        }
        *retval = n;
                                        n++;
                                }
                        }
                }
        }
        *retval = n;
-       return (error);
+       return (0);
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
-seltrue(dev, flag)
+seltrue(dev, flag, p)
        dev_t dev;
        int flag;
        dev_t dev;
        int flag;
+       struct proc *p;
 {
 
        return (1);
 }
 
 {
 
        return (1);
 }
 
-selwakeup(p, coll)
-       register struct proc *p;
-       int coll;
+/*
+ * Record a select request.
+ */
+void
+selrecord(selector, sip)
+       struct proc *selector;
+       struct selinfo *sip;
 {
 {
+       struct proc *p;
+       pid_t mypid;
+
+       mypid = selector->p_pid;
+       if (sip->si_pid == mypid)
+               return;
+       if (sip->si_pid && (p = pfind(sip->si_pid)) &&
+           p->p_wchan == (caddr_t)&selwait)
+               sip->si_flags |= SI_COLL;
+       else
+               sip->si_pid = mypid;
+}
+
+/*
+ * Do a wakeup when a selectable event occurs.
+ */
+void
+selwakeup(sip)
+       register struct selinfo *sip;
+{
+       register struct proc *p;
+       int s;
 
 
-       if (coll) {
+       if (sip->si_pid == 0)
+               return;
+       if (sip->si_flags & SI_COLL) {
                nselcoll++;
                nselcoll++;
+               sip->si_flags &= ~SI_COLL;
                wakeup((caddr_t)&selwait);
        }
                wakeup((caddr_t)&selwait);
        }
-       if (p) {
-               int s = splhigh();
+       p = pfind(sip->si_pid);
+       sip->si_pid = 0;
+       if (p != NULL) {
+               s = splhigh();
                if (p->p_wchan == (caddr_t)&selwait) {
                        if (p->p_stat == SSLEEP)
                                setrun(p);
                if (p->p_wchan == (caddr_t)&selwait) {
                        if (p->p_stat == SSLEEP)
                                setrun(p);