add definition for ability to produce a backtrace
[unix-history] / usr / src / sys / kern / sys_generic.c
index 07c0425..eb7da95 100644 (file)
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
  *
  *
- *     @(#)sys_generic.c       7.4 (Berkeley) %G%
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sys_generic.c       8.9 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "dir.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
+#include <sys/ktrace.h>
+#endif
+
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
 
 /*
  * Read system call.
  */
 
 /*
  * Read system call.
  */
-read()
+/* ARGSUSED */
+int
+read(p, uap, retval)
+       struct proc *p;
+       register struct read_args /* {
+               syscallarg(int) fd;
+               syscallarg(char *) buf;
+               syscallarg(u_int) nbyte;
+       } */ *uap;
+       register_t *retval;
 {
 {
-       register struct a {
-               int     fdes;
-               char    *cbuf;
-               unsigned count;
-       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        struct iovec aiov;
        struct uio auio;
        struct iovec aiov;
+       long cnt, error = 0;
+#ifdef KTRACE
+       struct iovec ktriov;
+#endif
 
 
-       aiov.iov_base = (caddr_t)uap->cbuf;
-       aiov.iov_len = uap->count;
+       if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
+           (fp->f_flag & FREAD) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)SCARG(uap, buf);
+       aiov.iov_len = SCARG(uap, nbyte);
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
-       rwuio(&auio, UIO_READ);
+       auio.uio_resid = SCARG(uap, nbyte);
+       auio.uio_rw = UIO_READ;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))
+               ktriov = aiov;
+#endif
+       cnt = SCARG(uap, nbyte);
+       if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_GENIO) && error == 0)
+               ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov,
+                   cnt, error);
+#endif
+       *retval = cnt;
+       return (error);
 }
 
 }
 
-readv()
+/*
+ * Scatter read system call.
+ */
+int
+readv(p, uap, retval)
+       struct proc *p;
+       register struct readv_args /* {
+               syscallarg(int) fd;
+               syscallarg(struct iovec *) iovp;
+               syscallarg(u_int) iovcnt;
+       } */ *uap;
+       register_t *retval;
 {
 {
-       register struct a {
-               int     fdes;
-               struct  iovec *iovp;
-               unsigned iovcnt;
-       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        struct uio auio;
-       struct iovec aiov[16];          /* XXX */
+       register struct iovec *iov;
+       struct iovec *needfree;
+       struct iovec aiov[UIO_SMALLIOV];
+       long i, cnt, error = 0;
+       u_int iovlen;
+#ifdef KTRACE
+       struct iovec *ktriov = NULL;
+#endif
 
 
-       if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
-               u.u_error = EINVAL;
-               return;
+       if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
+           (fp->f_flag & FREAD) == 0)
+               return (EBADF);
+       /* note: can't use iovlen until iovcnt is validated */
+       iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
+       if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
+               if (SCARG(uap, iovcnt) > UIO_MAXIOV)
+                       return (EINVAL);
+               MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
+               needfree = iov;
+       } else {
+               iov = aiov;
+               needfree = NULL;
        }
        }
-       auio.uio_iov = aiov;
-       auio.uio_iovcnt = uap->iovcnt;
-       u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
-           uap->iovcnt * sizeof (struct iovec));
-       if (u.u_error)
-               return;
-       rwuio(&auio, UIO_READ);
+       auio.uio_iov = iov;
+       auio.uio_iovcnt = SCARG(uap, iovcnt);
+       auio.uio_rw = UIO_READ;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+       if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
+               goto done;
+       auio.uio_resid = 0;
+       for (i = 0; i < SCARG(uap, iovcnt); i++) {
+               if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
+                       error = EINVAL;
+                       goto done;
+               }
+               auio.uio_resid += iov->iov_len;
+               iov++;
+       }
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))  {
+               MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+               bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+       }
+#endif
+       cnt = auio.uio_resid;
+       if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (ktriov != NULL) {
+               if (error == 0)
+                       ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov,
+                           cnt, error);
+               FREE(ktriov, M_TEMP);
+       }
+#endif
+       *retval = cnt;
+done:
+       if (needfree)
+               FREE(needfree, M_IOV);
+       return (error);
 }
 
 /*
  * Write system call
  */
 }
 
 /*
  * Write system call
  */
-write()
+int
+write(p, uap, retval)
+       struct proc *p;
+       register struct write_args /* {
+               syscallarg(int) fd;
+               syscallarg(char *) buf;
+               syscallarg(u_int) nbyte;
+       } */ *uap;
+       register_t *retval;
 {
 {
-       register struct a {
-               int     fdes;
-               char    *cbuf;
-               unsigned count;
-       } *uap = (struct a *)u.u_ap;
+       register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
        struct uio auio;
        struct iovec aiov;
        struct uio auio;
        struct iovec aiov;
+       long cnt, error = 0;
+#ifdef KTRACE
+       struct iovec ktriov;
+#endif
 
 
+       if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)SCARG(uap, buf);
+       aiov.iov_len = SCARG(uap, nbyte);
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
-       aiov.iov_base = uap->cbuf;
-       aiov.iov_len = uap->count;
-       rwuio(&auio, UIO_WRITE);
-}
-
-writev()
-{
-       register struct a {
-               int     fdes;
-               struct  iovec *iovp;
-               unsigned iovcnt;
-       } *uap = (struct a *)u.u_ap;
-       struct uio auio;
-       struct iovec aiov[16];          /* XXX */
-
-       if (uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
-               u.u_error = EINVAL;
-               return;
+       auio.uio_resid = SCARG(uap, nbyte);
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))
+               ktriov = aiov;
+#endif
+       cnt = SCARG(uap, nbyte);
+       if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+               if (error == EPIPE)
+                       psignal(p, SIGPIPE);
        }
        }
-       auio.uio_iov = aiov;
-       auio.uio_iovcnt = uap->iovcnt;
-       u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov,
-           uap->iovcnt * sizeof (struct iovec));
-       if (u.u_error)
-               return;
-       rwuio(&auio, UIO_WRITE);
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_GENIO) && error == 0)
+               ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
+                   &ktriov, cnt, error);
+#endif
+       *retval = cnt;
+       return (error);
 }
 
 }
 
-rwuio(uio, rw)
-       register struct uio *uio;
-       enum uio_rw rw;
+/*
+ * Gather write system call
+ */
+int
+writev(p, uap, retval)
+       struct proc *p;
+       register struct writev_args /* {
+               syscallarg(int) fd;
+               syscallarg(struct iovec *) iovp;
+               syscallarg(u_int) iovcnt;
+       } */ *uap;
+       register_t *retval;
 {
 {
-       struct a {
-               int     fdes;
-       };
        register struct file *fp;
        register struct file *fp;
+       register struct filedesc *fdp = p->p_fd;
+       struct uio auio;
        register struct iovec *iov;
        register struct iovec *iov;
-       int i, count;
+       struct iovec *needfree;
+       struct iovec aiov[UIO_SMALLIOV];
+       long i, cnt, error = 0;
+       u_int iovlen;
+#ifdef KTRACE
+       struct iovec *ktriov = NULL;
+#endif
 
 
-       GETF(fp, ((struct a *)u.u_ap)->fdes);
-       if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
-               u.u_error = EBADF;
-               return;
+       if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       /* note: can't use iovlen until iovcnt is validated */
+       iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
+       if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
+               if (SCARG(uap, iovcnt) > UIO_MAXIOV)
+                       return (EINVAL);
+               MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
+               needfree = iov;
+       } else {
+               iov = aiov;
+               needfree = NULL;
        }
        }
-       uio->uio_resid = 0;
-       uio->uio_segflg = UIO_USERSPACE;
-       iov = uio->uio_iov;
-       for (i = 0; i < uio->uio_iovcnt; i++) {
-               if (iov->iov_len < 0) {
-                       u.u_error = EINVAL;
-                       return;
-               }
-               uio->uio_resid += iov->iov_len;
-               if (uio->uio_resid < 0) {
-                       u.u_error = EINVAL;
-                       return;
+       auio.uio_iov = iov;
+       auio.uio_iovcnt = SCARG(uap, iovcnt);
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_segflg = UIO_USERSPACE;
+       auio.uio_procp = p;
+       if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
+               goto done;
+       auio.uio_resid = 0;
+       for (i = 0; i < SCARG(uap, iovcnt); i++) {
+               if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
+                       error = EINVAL;
+                       goto done;
                }
                }
+               auio.uio_resid += iov->iov_len;
                iov++;
        }
                iov++;
        }
-       count = uio->uio_resid;
-       if (setjmp(&u.u_qsave)) {
-               if (uio->uio_resid == count) {
-                       if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
-                               u.u_error = EINTR;
-                       else
-                               u.u_eosys = RESTARTSYS;
-               }
-       } else
-               u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio);
-       u.u_r.r_val1 = count - uio->uio_resid;
+#ifdef KTRACE
+       /*
+        * if tracing, save a copy of iovec
+        */
+       if (KTRPOINT(p, KTR_GENIO))  {
+               MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+               bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+       }
+#endif
+       cnt = auio.uio_resid;
+       if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
+               if (auio.uio_resid != cnt && (error == ERESTART ||
+                   error == EINTR || error == EWOULDBLOCK))
+                       error = 0;
+               if (error == EPIPE)
+                       psignal(p, SIGPIPE);
+       }
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (ktriov != NULL) {
+               if (error == 0)
+                       ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
+                               ktriov, cnt, error);
+               FREE(ktriov, M_TEMP);
+       }
+#endif
+       *retval = cnt;
+done:
+       if (needfree)
+               FREE(needfree, M_IOV);
+       return (error);
 }
 
 /*
  * Ioctl system call
  */
 }
 
 /*
  * Ioctl system call
  */
-ioctl()
+/* ARGSUSED */
+int
+ioctl(p, uap, retval)
+       struct proc *p;
+       register struct ioctl_args /* {
+               syscallarg(int) fd;
+               syscallarg(u_long) com;
+               syscallarg(caddr_t) data;
+       } */ *uap;
+       register_t *retval;
 {
        register struct file *fp;
 {
        register struct file *fp;
-       struct a {
-               int     fdes;
-               int     cmd;
-               caddr_t cmarg;
-       } *uap;
-       register int com;
+       register struct filedesc *fdp;
+       register u_long com;
+       register int error;
        register u_int size;
        register u_int size;
-       caddr_t memp = 0;
+       caddr_t data, memp;
+       int tmp;
 #define STK_PARAMS     128
 #define STK_PARAMS     128
-       char buf[STK_PARAMS];
-       caddr_t data = buf;
-
-       uap = (struct a *)u.u_ap;
-       GETF(fp, uap->fdes);
-       if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
-               u.u_error = EBADF;
-               return;
+       char stkbuf[STK_PARAMS];
+
+       fdp = p->p_fd;
+       if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
+               return (EBADF);
+
+       if ((fp->f_flag & (FREAD | FWRITE)) == 0)
+               return (EBADF);
+
+       switch (com = SCARG(uap, com)) {
+       case FIONCLEX:
+               fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
+               return (0);
+       case FIOCLEX:
+               fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
+               return (0);
        }
        }
-       com = uap->cmd;
 
 
-#if defined(vax) && defined(COMPAT)
        /*
        /*
-        * Map old style ioctl's into new for the
-        * sake of backwards compatibility (sigh).
-        */
-       if ((com&~0xffff) == 0) {
-               com = mapioctl(com);
-               if (com == 0) {
-                       u.u_error = EINVAL;
-                       return;
-               }
-       }
-#endif
-       if (com == FIOCLEX) {
-               u.u_pofile[uap->fdes] |= UF_EXCLOSE;
-               return;
-       }
-       if (com == FIONCLEX) {
-               u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
-               return;
-       }
-
-       /*
-        * Interpret high order word to find
-        * amount of data to be copied to/from the
-        * user's address space.
+        * Interpret high order word to find amount of data to be
+        * copied to/from the user's address space.
         */
        size = IOCPARM_LEN(com);
         */
        size = IOCPARM_LEN(com);
-       if (size > IOCPARM_MAX) {
-               u.u_error = EFAULT;
-               return;
-       }
-       if (size > sizeof (buf)) {
-               memp = (caddr_t)malloc(IOCPARM_MAX, M_IOCTLOPS, M_WAITOK);
+       if (size > IOCPARM_MAX)
+               return (ENOTTY);
+       memp = NULL;
+       if (size > sizeof (stkbuf)) {
+               memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
                data = memp;
                data = memp;
-       }
+       } else
+               data = stkbuf;
        if (com&IOC_IN) {
                if (size) {
        if (com&IOC_IN) {
                if (size) {
-                       u.u_error =
-                           copyin(uap->cmarg, data, (u_int)size);
-                       if (u.u_error) {
+                       error = copyin(SCARG(uap, data), data, (u_int)size);
+                       if (error) {
                                if (memp)
                                        free(memp, M_IOCTLOPS);
                                if (memp)
                                        free(memp, M_IOCTLOPS);
-                               return;
+                               return (error);
                        }
                } else
                        }
                } else
-                       *(caddr_t *)data = uap->cmarg;
+                       *(caddr_t *)data = SCARG(uap, data);
        } else if ((com&IOC_OUT) && size)
                /*
        } else if ((com&IOC_OUT) && size)
                /*
-                * Zero the buffer on the stack so the user
-                * always gets back something deterministic.
+                * Zero the buffer so the user always
+                * gets back something deterministic.
                 */
                bzero(data, size);
        else if (com&IOC_VOID)
                 */
                bzero(data, size);
        else if (com&IOC_VOID)
-               *(caddr_t *)data = uap->cmarg;
+               *(caddr_t *)data = SCARG(uap, data);
 
        switch (com) {
 
        case FIONBIO:
 
        switch (com) {
 
        case FIONBIO:
-               u.u_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:
-               u.u_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:
-               u.u_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, TIOCSPGRP, (caddr_t)&tmp, p);
                break;
 
        case FIOGETOWN:
                break;
 
        case FIOGETOWN:
-               u.u_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, TIOCGPGRP, data, p);
+               *(int *)data = -*(int *)data;
                break;
                break;
+
        default:
        default:
-               if (setjmp(&u.u_qsave))
-                       u.u_error = EINTR;
-               else
-                       u.u_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.
                 */
-               if (u.u_error == 0 && (com&IOC_OUT) && size)
-                       u.u_error = copyout(data, uap->cmarg, (u_int)size);
+               if (error == 0 && (com&IOC_OUT) && size)
+                       error = copyout(data, SCARG(uap, data), (u_int)size);
                break;
        }
        if (memp)
                free(memp, M_IOCTLOPS);
                break;
        }
        if (memp)
                free(memp, M_IOCTLOPS);
+       return (error);
 }
 
 }
 
-int    unselect();
-int    nselcoll;
+int    selwait, nselcoll;
 
 /*
  * Select system call.
  */
 
 /*
  * Select system call.
  */
-select()
+int
+select(p, uap, retval)
+       register struct proc *p;
+       register struct select_args /* {
+               syscallarg(u_int) nd;
+               syscallarg(fd_set *) in;
+               syscallarg(fd_set *) ou;
+               syscallarg(fd_set *) ex;
+               syscallarg(struct timeval *) tv;
+       } */ *uap;
+       register_t *retval;
 {
 {
-       register struct uap  {
-               int     nd;
-               fd_set  *in, *ou, *ex;
-               struct  timeval *tv;
-       } *uap = (struct uap *)u.u_ap;
        fd_set ibits[3], obits[3];
        struct timeval atv;
        fd_set ibits[3], obits[3];
        struct timeval atv;
-       int s, ncoll, ni;
-       label_t lqsave;
+       int s, ncoll, error, timo = 0;
+       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 (SCARG(uap, nd) > FD_SETSIZE)
+               return (EINVAL);
+       if (SCARG(uap, nd) > p->p_fd->fd_nfiles) {
+               /* forgiving; slightly wrong */
+               SCARG(uap, nd) = p->p_fd->fd_nfiles;
+       }
+       ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask);
 
 #define        getbits(name, x) \
 
 #define        getbits(name, x) \
-       if (uap->name) { \
-               u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
-                   (unsigned)(ni * sizeof(fd_mask))); \
-               if (u.u_error) \
-                       goto done; \
-       }
+       if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
+           (caddr_t)&ibits[x], ni))) \
+               goto done;
        getbits(in, 0);
        getbits(ou, 1);
        getbits(ex, 2);
 #undef getbits
 
        getbits(in, 0);
        getbits(ou, 1);
        getbits(ex, 2);
 #undef getbits
 
-       if (uap->tv) {
-               u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
+       if (SCARG(uap, tv)) {
+               error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv,
                        sizeof (atv));
                        sizeof (atv));
-               if (u.u_error)
+               if (error)
                        goto done;
                if (itimerfix(&atv)) {
                        goto done;
                if (itimerfix(&atv)) {
-                       u.u_error = EINVAL;
+                       error = EINVAL;
                        goto done;
                }
                        goto done;
                }
-               s = splhigh(); timevaladd(&atv, &time); splx(s);
+               s = splclock();
+               timevaladd(&atv, (struct timeval *)&time);
+               splx(s);
        }
 retry:
        ncoll = nselcoll;
        }
 retry:
        ncoll = nselcoll;
-       u.u_procp->p_flag |= SSEL;
-       u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
-       if (u.u_error || u.u_r.r_val1)
+       p->p_flag |= P_SELECT;
+       error = selscan(p, ibits, obits, SCARG(uap, nd), retval);
+       if (error || *retval)
                goto done;
        s = splhigh();
                goto done;
        s = splhigh();
-       /* this should be timercmp(&time, &atv, >=) */
-       if (uap->tv && (time.tv_sec > atv.tv_sec ||
-           time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
-               splx(s);
-               goto done;
-       }
-       if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
-               u.u_procp->p_flag &= ~SSEL;
-               splx(s);
-               goto retry;
-       }
-       u.u_procp->p_flag &= ~SSEL;
-       if (uap->tv) {
-               lqsave = u.u_qsave;
-               if (setjmp(&u.u_qsave)) {
-                       untimeout(unselect, (caddr_t)u.u_procp);
-                       u.u_error = EINTR;
+       if (SCARG(uap, tv)) {
+               if (timercmp(&time, &atv, >=)) {
                        splx(s);
                        goto done;
                }
                        splx(s);
                        goto done;
                }
-               timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
+               /*
+                * If poll wait was tiny, this could be zero; we will
+                * have to round it up to avoid sleeping forever.  If
+                * we retry below, the timercmp above will get us out.
+                * Note that if wait was 0, the timercmp will prevent
+                * us from getting here the first time.
+                */
+               timo = hzto(&atv);
+               if (timo == 0)
+                       timo = 1;
        }
        }
-       sleep((caddr_t)&selwait, PZERO+1);
-       if (uap->tv) {
-               u.u_qsave = lqsave;
-               untimeout(unselect, (caddr_t)u.u_procp);
+       if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
+               splx(s);
+               goto retry;
        }
        }
+       p->p_flag &= ~P_SELECT;
+       error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
        splx(s);
        splx(s);
-       goto retry;
+       if (error == 0)
+               goto retry;
 done:
 done:
+       p->p_flag &= ~P_SELECT;
+       /* select is not restarted after signals... */
+       if (error == ERESTART)
+               error = EINTR;
+       if (error == EWOULDBLOCK)
+               error = 0;
 #define        putbits(name, x) \
 #define        putbits(name, x) \
-       if (uap->name) { \
-               int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
-                   (unsigned)(ni * sizeof(fd_mask))); \
-               if (error) \
-                       u.u_error = error; \
-       }
-       if (u.u_error == 0) {
+       if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
+           (caddr_t)SCARG(uap, name), ni))) \
+               error = error2;
+       if (error == 0) {
+               int error2;
+
                putbits(in, 0);
                putbits(ou, 1);
                putbits(ex, 2);
 #undef putbits
        }
                putbits(in, 0);
                putbits(ou, 1);
                putbits(ex, 2);
 #undef putbits
        }
+       return (error);
 }
 
 }
 
-unselect(p)
-       register struct proc *p;
-{
-       register int s = splhigh();
-
-       switch (p->p_stat) {
-
-       case SSLEEP:
-               setrun(p);
-               break;
-
-       case SSTOP:
-               unsleep(p);
-               break;
-       }
-       splx(s);
-}
-
-selscan(ibits, obits, nfd)
+int
+selscan(p, ibits, obits, nfd, retval)
+       struct proc *p;
        fd_set *ibits, *obits;
        fd_set *ibits, *obits;
+       int nfd;
+       register_t *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;
        int n = 0;
        struct file *fp;
        int n = 0;
+       static int flag[3] = { FREAD, FWRITE, 0 };
 
 
-       for (which = 0; which < 3; which++) {
-               switch (which) {
-
-               case 0:
-                       flag = FREAD; break;
-
-               case 1:
-                       flag = FWRITE; break;
-
-               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) {
-                                       u.u_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++;
                                }
                        }
                }
        }
                                        n++;
                                }
                        }
                }
        }
-       return (n);
+       *retval = n;
+       return (0);
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
-seltrue(dev, flag)
+int
+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)
                if (p->p_wchan == (caddr_t)&selwait) {
                        if (p->p_stat == SSLEEP)
-                               setrun(p);
+                               setrunnable(p);
                        else
                                unsleep(p);
                        else
                                unsleep(p);
-               } else if (p->p_flag & SSEL)
-                       p->p_flag &= ~SSEL;
+               } else if (p->p_flag & P_SELECT)
+                       p->p_flag &= ~P_SELECT;
                splx(s);
        }
 }
                splx(s);
        }
 }