Cleanups for 4.4BSD-Lite
[unix-history] / usr / src / sys / kern / sys_generic.c
index ff6106a..a5db90f 100644 (file)
-/*     sys_generic.c   5.27    82/12/21        */
-
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/ioctl.h"
-#include "../h/tty.h"
-#include "../h/file.h"
-#include "../h/inode.h"
-#include "../h/buf.h"
-#include "../h/proc.h"
-#include "../h/conf.h"
-#include "../h/socket.h"
-#include "../h/socketvar.h"
-#include "../h/fs.h"
-#ifdef MUSH
-#include "../h/quota.h"
-#include "../h/share.h"
-#else
-#define        CHARGE(nothing)
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sys_generic.c       8.2 (Berkeley) %G%
+ */
+
+#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
 #endif
-#include "../h/descrip.h"
-#include "../h/uio.h"
-#include "../h/cmap.h"
 
 /*
  * Read system call.
  */
 
 /*
  * Read system call.
  */
-read()
+struct read_args {
+       int     fd;
+       char    *buf;
+       u_int   nbyte;
+};
+/* ARGSUSED */
+read(p, uap, retval)
+       struct proc *p;
+       register struct read_args *uap;
+       int *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)uap->fd) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
+           (fp->f_flag & FREAD) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)uap->buf;
+       aiov.iov_len = 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 = 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 = 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, uap->fd, UIO_READ, &ktriov, cnt, error);
+#endif
+       *retval = cnt;
+       return (error);
 }
 
 }
 
-readv()
+/*
+ * Scatter read system call.
+ */
+struct readv_args {
+       int     fdes;
+       struct  iovec *iovp;
+       u_int   iovcnt;
+};
+readv(p, uap, retval)
+       struct proc *p;
+       register struct readv_args *uap;
+       int *retval;
 {
 {
-       register struct a {
-               int     fdes;
-               struct  iovec *iovp;
-               int     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 <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
-               u.u_error = EINVAL;
-               return;
+       if (((u_int)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 */
+       iovlen = uap->iovcnt * sizeof (struct iovec);
+       if (uap->iovcnt > UIO_SMALLIOV) {
+               if (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_iov = iov;
        auio.uio_iovcnt = uap->iovcnt;
        auio.uio_iovcnt = uap->iovcnt;
-       if (copyin((caddr_t)uap->iovp, (caddr_t)aiov,
-           (unsigned)(uap->iovcnt * sizeof (struct iovec)))) {
-               u.u_error = EFAULT;
-               return;
+       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;
+       for (i = 0; i < uap->iovcnt; i++) {
+               if (iov->iov_len < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               auio.uio_resid += iov->iov_len;
+               if (auio.uio_resid < 0) {
+                       error = EINVAL;
+                       goto done;
+               }
+               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);
        }
        }
-       rwuio(&auio, UIO_READ);
+#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, uap->fdes, 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()
+struct write_args {
+       int     fd;
+       char    *buf;
+       u_int   nbyte;
+};
+write(p, uap, retval)
+       struct proc *p;
+       register struct write_args *uap;
+       int *retval;
 {
 {
-       register struct a {
-               int     fdes;
-               char    *cbuf;
-               int     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)uap->fd) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       aiov.iov_base = (caddr_t)uap->buf;
+       aiov.iov_len = 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;
-               int     iovcnt;
-       } *uap = (struct a *)u.u_ap;
-       struct uio auio;
-       struct iovec aiov[16];          /* XXX */
-
-       if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) {
-               u.u_error = EINVAL;
-               return;
-       }
-       auio.uio_iov = aiov;
-       auio.uio_iovcnt = uap->iovcnt;
-       if (copyin((caddr_t)uap->iovp, (caddr_t)aiov,
-           (unsigned)(uap->iovcnt * sizeof (struct iovec)))) {
-               u.u_error = EFAULT;
-               return;
+       auio.uio_resid = 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 = 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);
        }
        }
-       rwuio(&auio, UIO_WRITE);
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (KTRPOINT(p, KTR_GENIO) && error == 0)
+               ktrgenio(p->p_tracep, 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
+ */
+struct writev_args {
+       int     fd;
+       struct  iovec *iovp;
+       u_int   iovcnt;
+};
+writev(p, uap, retval)
+       struct proc *p;
+       register struct writev_args *uap;
+       int *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;
-       register struct inode *ip;
-       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)uap->fd) >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
+           (fp->f_flag & FWRITE) == 0)
+               return (EBADF);
+       /* note: can't use iovlen until iovcnt is validated */
+       iovlen = uap->iovcnt * sizeof (struct iovec);
+       if (uap->iovcnt > UIO_SMALLIOV) {
+               if (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 = 0;
-       iov = uio->uio_iov;
-       for (i = 0; i < uio->uio_iovcnt; i++) {
+       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;
+       for (i = 0; i < uap->iovcnt; i++) {
                if (iov->iov_len < 0) {
                if (iov->iov_len < 0) {
-                       u.u_error = EINVAL;
-                       return;
+                       error = EINVAL;
+                       goto done;
                }
                }
-               uio->uio_resid += iov->iov_len;
-               if (uio->uio_resid < 0) {
-                       u.u_error = EINVAL;
-                       return;
+               auio.uio_resid += iov->iov_len;
+               if (auio.uio_resid < 0) {
+                       error = EINVAL;
+                       goto done;
                }
                }
+               iov++;
        }
        }
-       count = uio->uio_resid;
-       if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) {
-               if (uio->uio_resid == count)
-                       u.u_eosys = RESTARTSYS;
-       } else if (fp->f_type == DTYPE_SOCKET) {
-               int sosend(), soreceive();
-               u.u_error = 
-                   (*(rw==UIO_READ?soreceive:sosend))
-                     (fp->f_socket, (struct sockaddr *)0, uio, 0);
-       } else {
-               ip = fp->f_inode;
-               uio->uio_offset = fp->f_offset;
-               if ((ip->i_mode&IFMT) == IFREG) {
-                       ILOCK(ip);
-                       u.u_error = rwip(ip, uio, rw);
-                       IUNLOCK(ip);
-               } else
-                       u.u_error = rwip(ip, uio, rw);
-               fp->f_offset += 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);
        }
        }
-       u.u_r.r_val1 = count - uio->uio_resid;
-}
-
-rdwri(rw, ip, base, len, offset, segflg, aresid)
-       struct inode *ip;
-       caddr_t base;
-       int len, offset, segflg;
-       int *aresid;
-       enum uio_rw rw;
-{
-       struct uio auio;
-       struct iovec aiov;
-       int error;
-
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       aiov.iov_base = base;
-       aiov.iov_len = len;
-       auio.uio_resid = len;
-       auio.uio_offset = offset;
-       auio.uio_segflg = segflg;
-       error = rwip(ip, &auio, rw);
-       if (aresid)
-               *aresid = auio.uio_resid;
-       else
-               if (auio.uio_resid)
-                       error = EIO;
-       return (error);
-}
-
-rwip(ip, uio, rw)
-       register struct inode *ip;
-       register struct uio *uio;
-       enum uio_rw rw;
-{
-       dev_t dev = (dev_t)ip->i_rdev;
-       struct buf *bp;
-       struct fs *fs;
-       daddr_t lbn, bn;
-       register int n, on, type;
-       int size;
-       long bsize;
-       extern int mem_no;
-       int error = 0;
-
-       if (rw != UIO_READ && rw != UIO_WRITE)
-               panic("rwip");
-       if (rw == UIO_READ && uio->uio_resid == 0)
-               return (0);
-       if (uio->uio_offset < 0 &&
-           ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
-               return (EINVAL);
-       if (rw == UIO_READ)
-               ip->i_flag |= IACC;
-       type = ip->i_mode&IFMT;
-       if (type == IFCHR) {
-#ifdef QUOTA
-               register c = uio->uio_resid;
 #endif
 #endif
-               if (rw == UIO_READ)
-                       u.u_error = (*cdevsw[major(dev)].d_read)(dev, uio);
-               else {
-                       ip->i_flag |= IUPD|ICHG;
-                       u.u_error = (*cdevsw[major(dev)].d_write)(dev, uio);
-               }
-               CHARGE(sc_tio * (c - uio->uio_resid));
-               return (u.u_error);
-       }
-       if (uio->uio_resid == 0)
-               return (0);
-       if (rw == UIO_WRITE && type == IFREG &&
-           uio->uio_offset + uio->uio_resid >
-             u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
-               psignal(u.u_procp, SIGXFSZ);
-               return (EMFILE);
+       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);
        }
        }
-       if (type != IFBLK) {
-               dev = ip->i_dev;
-               fs = ip->i_fs;
-               bsize = fs->fs_bsize;
-       } else
-               bsize = BLKDEV_IOSIZE;
-       do {
-               lbn = uio->uio_offset / bsize;
-               on = uio->uio_offset % bsize;
-               n = MIN((unsigned)(bsize - on), uio->uio_resid);
-               if (type != IFBLK) {
-                       if (rw == UIO_READ) {
-                               int diff = ip->i_size - uio->uio_offset;
-                               if (diff <= 0)
-                                       return (0);
-                               if (diff < n)
-                                       n = diff;
-                       }
-                       bn = fsbtodb(fs,
-                           bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n)));
-                       if (u.u_error || rw == UIO_WRITE && (long)bn<0)
-                               return (u.u_error);
-                       if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size &&
-                          (type == IFDIR || type == IFREG || type == IFLNK))
-                               ip->i_size = uio->uio_offset + n;
-                       size = blksize(fs, ip, lbn);
-               } else {
-                       bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
-                       rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
-                       rasize = size = bsize;
-               }
-               if (rw == UIO_READ) {
-                       if ((long)bn<0) {
-                               bp = geteblk(size);
-                               clrbuf(bp);
-                       } else if (ip->i_lastr + 1 == lbn)
-                               bp = breada(dev, bn, size, rablock, rasize);
-                       else
-                               bp = bread(dev, bn, size);
-                       ip->i_lastr = lbn;
-               } else {
-                       int i, count;
-                       extern struct cmap *mfind();
-
-                       count = howmany(size, DEV_BSIZE);
-                       for (i = 0; i < count; i += CLSIZE)
-                               if (mfind(dev, bn + i))
-                                       munhash(dev, bn + i);
-                       if (n == bsize) 
-                               bp = getblk(dev, bn, size);
-                       else
-                               bp = bread(dev, bn, size);
-               }
-               n = MIN(n, size - bp->b_resid);
-               if (bp->b_flags & B_ERROR) {
-                       error = EIO;
-                       brelse(bp);
-                       goto bad;
-               }
-               u.u_error =
-                   uiomove(bp->b_un.b_addr+on, n, rw, uio);
-               if (rw == UIO_READ) {
-                       if (n + on == bsize || uio->uio_offset == ip->i_size)
-                               bp->b_flags |= B_AGE;
-                       brelse(bp);
-               } else {
-                       if ((ip->i_mode&IFMT) == IFDIR)
-                               bwrite(bp);
-                       else if (n + on == bsize) {
-                               bp->b_flags |= B_AGE;
-                               bawrite(bp);
-                       } else
-                               bdwrite(bp);
-                       ip->i_flag |= IUPD|ICHG;
-                       if (u.u_ruid != 0)
-                               ip->i_mode &= ~(ISUID|ISGID);
-               }
-       } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0);
-bad:
-       return (error);
-}
-
-uiomove(cp, n, rw, uio)
-       register caddr_t cp;
-       register int n;
-       enum uio_rw rw;
-       register struct uio *uio;
-{
-       register struct iovec *iov;
-       u_int cnt;
-       int error = 0;
-
-       while (n > 0 && uio->uio_resid) {
-               iov = uio->uio_iov;
-               cnt = iov->iov_len;
-               if (cnt == 0) {
-                       uio->uio_iov++;
-                       uio->uio_iovcnt--;
-                       continue;
-               }
-               if (cnt > n)
-                       cnt = n;
-               switch (uio->uio_segflg) {
-
-               case 0:
-               case 2:
-                       if (rw == UIO_READ)
-                               error = copyout(cp, iov->iov_base, cnt);
-                       else
-                               error = copyin(iov->iov_base, cp, cnt);
-                       if (error)
-                               return (error);
-                       break;
-
-               case 1:
-                       if (rw == UIO_READ)
-                               bcopy((caddr_t)cp, iov->iov_base, cnt);
-                       else
-                               bcopy(iov->iov_base, (caddr_t)cp, cnt);
-                       break;
-               }
-               iov->iov_base += cnt;
-               iov->iov_len -= cnt;
-               uio->uio_resid -= cnt;
-               uio->uio_offset += cnt;
-               cp += cnt;
-               n -= cnt;
+       cnt -= auio.uio_resid;
+#ifdef KTRACE
+       if (ktriov != NULL) {
+               if (error == 0)
+                       ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
+                               ktriov, cnt, error);
+               FREE(ktriov, M_TEMP);
        }
        }
+#endif
+       *retval = cnt;
+done:
+       if (needfree)
+               FREE(needfree, M_IOV);
        return (error);
 }
 
 /*
        return (error);
 }
 
 /*
- * Give next character to user as result of read.
+ * Ioctl system call
  */
  */
-ureadc(c, uio)
-       register int c;
-       register struct uio *uio;
+struct ioctl_args {
+       int     fd;
+       int     com;
+       caddr_t data;
+};
+/* ARGSUSED */
+ioctl(p, uap, retval)
+       struct proc *p;
+       register struct ioctl_args *uap;
+       int *retval;
 {
 {
-       register struct iovec *iov;
+       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;
+       int tmp;
+
+       if ((u_int)uap->fd >= fdp->fd_nfiles ||
+           (fp = fdp->fd_ofiles[uap->fd]) == NULL)
+               return (EBADF);
+       if ((fp->f_flag & (FREAD|FWRITE)) == 0)
+               return (EBADF);
+       com = uap->com;
 
 
-again:
-       if (uio->uio_iovcnt == 0)
-               panic("ureadc");
-       iov = uio->uio_iov;
-       if (iov->iov_len <= 0 || uio->uio_resid <= 0) {
-               uio->uio_iovcnt--;
-               uio->uio_iov++;
-               goto again;
+       if (com == FIOCLEX) {
+               fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
+               return (0);
+       }
+       if (com == FIONCLEX) {
+               fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
+               return (0);
        }
        }
-       switch (uio->uio_segflg) {
-
-       case 0:
-               if (subyte(iov->iov_base, c) < 0)
-                       return (EFAULT);
-               break;
 
 
-       case 1:
-               *iov->iov_base = c;
+       /*
+        * Interpret high order word to find
+        * amount of data to be copied to/from the
+        * user's address space.
+        */
+       size = IOCPARM_LEN(com);
+       if (size > IOCPARM_MAX)
+               return (ENOTTY);
+       if (size > sizeof (stkbuf)) {
+               memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
+               data = memp;
+       }
+       if (com&IOC_IN) {
+               if (size) {
+                       error = copyin(uap->data, data, (u_int)size);
+                       if (error) {
+                               if (memp)
+                                       free(memp, M_IOCTLOPS);
+                               return (error);
+                       }
+               } else
+                       *(caddr_t *)data = uap->data;
+       } else if ((com&IOC_OUT) && size)
+               /*
+                * Zero the buffer so the user always
+                * gets back something deterministic.
+                */
+               bzero(data, size);
+       else if (com&IOC_VOID)
+               *(caddr_t *)data = uap->data;
+
+       switch (com) {
+
+       case FIONBIO:
+               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;
 
                break;
 
-       case 2:
-               if (suibyte(iov->iov_base, c) < 0)
-                       return (EFAULT);
+       case FIOASYNC:
+               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;
                break;
-       }
-       iov->iov_base++;
-       iov->iov_len--;
-       uio->uio_resid--;
-       uio->uio_offset++;
-       return (0);
-}
-
-#ifdef notdef
-/*
- * Get next character written in by user from uio.
- */
-uwritec(uio)
-       struct uio *uio;
-{
-       register struct iovec *iov;
-       register int c;
-
-again:
-       if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0)
-               panic("uwritec");
-       iov = uio->uio_iov;
-       if (iov->iov_len == 0) {
-               uio->uio_iovcnt--;
-               uio->uio_iov++;
-               goto again;
-       }
-       switch (uio->uio_segflg) {
 
 
-       case 0:
-               c = fubyte(iov->iov_base);
+       case FIOSETOWN:
+               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;
 
                break;
 
-       case 1:
-               c = *iov->iov_base & 0377;
+       case FIOGETOWN:
+               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;
 
-       case 2:
-               c = fuibyte(iov->iov_base);
+       default:
+               error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
+               /*
+                * Copy any data to user, size was
+                * already set and checked above.
+                */
+               if (error == 0 && (com&IOC_OUT) && size)
+                       error = copyout(data, uap->data, (u_int)size);
                break;
        }
                break;
        }
-       if (c < 0)
-               return (-1);
-       iov->iov_base++;
-       iov->iov_len--;
-       uio->uio_resid--;
-       uio->uio_offset++;
-       return (c & 0377);
+       if (memp)
+               free(memp, M_IOCTLOPS);
+       return (error);
 }
 }
-#endif
+
+int    selwait, nselcoll;
 
 /*
 
 /*
- * Ioctl system call
- * Check legality, execute common code,
- * and switch out to individual device routine.
+ * Select system call.
  */
  */
-ioctl()
+struct select_args {
+       u_int   nd;
+       fd_set  *in, *ou, *ex;
+       struct  timeval *tv;
+};
+select(p, uap, retval)
+       register struct proc *p;
+       register struct select_args *uap;
+       int *retval;
 {
 {
-       register struct file *fp;
-       struct a {
-               int     fdes;
-               int     cmd;
-               caddr_t cmarg;
-       } *uap;
-       register int com;
-       register u_int size;
-       char data[IOCPARM_MASK+1];
-
-       uap = (struct a *)u.u_ap;
-       if ((fp = getf(uap->fdes)) == NULL)
-               return;
-       if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
-               u.u_error = EBADF;
-               return;
-       }
-       com = uap->cmd;
-
-#ifndef NOCOMPAT
-       /*
-        * 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;
+       fd_set ibits[3], obits[3];
+       struct timeval atv;
+       int s, ncoll, error = 0, timo;
+       u_int ni;
+
+       bzero((caddr_t)ibits, sizeof(ibits));
+       bzero((caddr_t)obits, sizeof(obits));
+       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) \
+       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);
+#undef getbits
+
+       if (uap->tv) {
+               error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
+                       sizeof (atv));
+               if (error)
+                       goto done;
+               if (itimerfix(&atv)) {
+                       error = EINVAL;
+                       goto done;
                }
                }
+               s = splclock();
+               timevaladd(&atv, (struct timeval *)&time);
+               timo = hzto(&atv);
+               /*
+                * Avoid inadvertently sleeping forever.
+                */
+               if (timo == 0)
+                       timo = 1;
+               splx(s);
+       } else
+               timo = 0;
+retry:
+       ncoll = nselcoll;
+       p->p_flag |= SSEL;
+       error = selscan(p, ibits, obits, uap->nd, retval);
+       if (error || *retval)
+               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;
        }
        }
-#endif
-       if (com == FIOCLEX) {
-               u.u_pofile[uap->fdes] |= UF_EXCLOSE;
-               return;
+       if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
+               splx(s);
+               goto retry;
        }
        }
-       if (com == FIONCLEX) {
-               u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
-               return;
+       p->p_flag &= ~SSEL;
+       error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
+       splx(s);
+       if (error == 0)
+               goto retry;
+done:
+       p->p_flag &= ~SSEL;
+       /* select is not restarted after signals... */
+       if (error == ERESTART)
+               error = EINTR;
+       if (error == EWOULDBLOCK)
+               error = 0;
+#define        putbits(name, x) \
+       if (uap->name && \
+           (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
+               error = error2;
+       if (error == 0) {
+               int error2;
+
+               putbits(in, 0);
+               putbits(ou, 1);
+               putbits(ex, 2);
+#undef putbits
        }
        }
+       return (error);
+}
 
 
-       /*
-        * Interpret high order word to find
-        * amount of data to be copied to/from the
-        * user's address space.
-        */
-       size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
-       if (size > sizeof (data)) {
-               u.u_error = EFAULT;
-               return;
-       }
-       if (com&IOC_IN && size) {
-               if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-       } else
-               *(caddr_t *)data = uap->cmarg;
-       /*
-        * Zero the buffer on the stack so the user
-        * always gets back something deterministic.
-        */
-       if ((com&IOC_OUT) && size)
-               bzero((caddr_t)data, size);
-
-       if (fp->f_type == DTYPE_SOCKET)
-               u.u_error = soioctl(fp->f_socket, com, data);
-       else {
-               register struct inode *ip = fp->f_inode;
-               int fmt = ip->i_mode & IFMT;
-               dev_t dev;
-
-               if (fmt != IFCHR) {
-                       if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
-                               *(off_t *)data = ip->i_size - fp->f_offset;
-                               goto returndata;
+selscan(p, ibits, obits, nfd, retval)
+       struct proc *p;
+       fd_set *ibits, *obits;
+       int nfd, *retval;
+{
+       register struct filedesc *fdp = p->p_fd;
+       register int msk, i, j, fd;
+       register fd_mask bits;
+       struct file *fp;
+       int n = 0;
+       static int flag[3] = { FREAD, FWRITE, 0 };
+
+       for (msk = 0; msk < 3; msk++) {
+               for (i = 0; i < nfd; i += NFDBITS) {
+                       bits = ibits[msk].fds_bits[i/NFDBITS];
+                       while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
+                               bits &= ~(1 << j);
+                               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++;
+                               }
                        }
                        }
-                       if (com != FIONBIO && com != FIOASYNC)
-                               u.u_error = ENOTTY;
-                       return;
-               }
-               dev = ip->i_rdev;
-               u.u_r.r_val1 = 0;
-               if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) {
-                       u.u_eosys = RESTARTSYS;
-                       return;
                }
                }
-               u.u_error = (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
        }
        }
-
-returndata:
-       /*
-        * Copy any data to user, size was
-        * already set and checked above.
-        */
-       if (u.u_error == 0 && (com&IOC_OUT))
-               if (size && copyout(data, uap->cmarg, (u_int)size))
-                       u.u_error = EFAULT;
+       *retval = n;
+       return (0);
 }
 
 }
 
-/*
- * Do nothing specific version of line
- * discipline specific ioctl command.
- */
 /*ARGSUSED*/
 /*ARGSUSED*/
-nullioctl(tp, cmd, data, flags)
-       struct tty *tp;
-       char *data;
-       int flags;
+seltrue(dev, flag, p)
+       dev_t dev;
+       int flag;
+       struct proc *p;
 {
 
 {
 
-#ifdef lint
-       tp = tp; data = data; flags = flags;
-#endif
-       return (-1);
+       return (1);
 }
 
 }
 
-ostty()
+/*
+ * 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;
 }
 
 }
 
-ogtty()
+/*
+ * Do a wakeup when a selectable event occurs.
+ */
+void
+selwakeup(sip)
+       register struct selinfo *sip;
 {
 {
+       register struct proc *p;
+       int s;
 
 
+       if (sip->si_pid == 0)
+               return;
+       if (sip->si_flags & SI_COLL) {
+               nselcoll++;
+               sip->si_flags &= ~SI_COLL;
+               wakeup((caddr_t)&selwait);
+       }
+       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);
+                       else
+                               unsleep(p);
+               } else if (p->p_flag & SSEL)
+                       p->p_flag &= ~SSEL;
+               splx(s);
+       }
 }
 }