more lint
[unix-history] / usr / src / sys / kern / sys_generic.c
index 30b6ed0..987754c 100644 (file)
@@ -1,21 +1,17 @@
-/*     sys_generic.c   5.3     82/07/24        */
+/*     sys_generic.c   5.18    82/10/17        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/tty.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/tty.h"
-#include "../h/fcntl.h"
 #include "../h/file.h"
 #include "../h/inode.h"
 #include "../h/buf.h"
 #include "../h/proc.h"
 #include "../h/file.h"
 #include "../h/inode.h"
 #include "../h/buf.h"
 #include "../h/proc.h"
-#include "../h/inline.h"
 #include "../h/conf.h"
 #include "../h/socket.h"
 #include "../h/socketvar.h"
 #include "../h/conf.h"
 #include "../h/socket.h"
 #include "../h/socketvar.h"
-#include "../h/cmap.h"
-#include "../h/vlimit.h"
 #include "../h/fs.h"
 #ifdef MUSH
 #include "../h/quota.h"
 #include "../h/fs.h"
 #ifdef MUSH
 #include "../h/quota.h"
 #define        CHARGE(nothing)
 #endif
 #include "../h/descrip.h"
 #define        CHARGE(nothing)
 #endif
 #include "../h/descrip.h"
+#include "../h/uio.h"
 
 /*
  * Read system call.
  */
 read()
 {
 
 /*
  * Read system call.
  */
 read()
 {
-       register struct file *fp;
-       register struct inode *ip;
        register struct a {
                int     fdes;
                char    *cbuf;
                unsigned count;
        register struct a {
                int     fdes;
                char    *cbuf;
                unsigned count;
-       } *uap;
+       } *uap = (struct a *)u.u_ap;
+       struct uio auio;
+       struct iovec aiov;
 
 
-       uap = (struct a *)u.u_ap;
-       if ((int)uap->count < 0) {
+       aiov.iov_base = (caddr_t)uap->cbuf;
+       aiov.iov_len = uap->count;
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       rwuio(&auio, UIO_READ);
+}
+
+readv()
+{
+       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;
        }
                u.u_error = EINVAL;
                return;
        }
-       GETF(fp, uap->fdes);
-       if ((fp->f_flag&FREAD) == 0) {
-               u.u_error = EBADF;
+       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;
        }
                return;
        }
-       u.u_base = (caddr_t)uap->cbuf;
-       u.u_count = uap->count;
-       u.u_segflg = 0;
-       if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
-               if (u.u_count == uap->count)
-                       u.u_eosys = RESTARTSYS;
-       } else if (fp->f_type == DTYPE_SOCKET)
-               u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0);
-       else {
-               ip = fp->f_inode;
-               u.u_offset = fp->f_offset;
-               if ((ip->i_mode&IFMT) == IFREG) {
-                       ilock(ip);
-                       readi(ip);
-                       iunlock(ip);
-               } else
-                       readi(ip);
-               fp->f_offset += uap->count - u.u_count;
-       }
-       u.u_r.r_val1 = uap->count - u.u_count;
+       rwuio(&auio, UIO_READ);
 }
 
 /*
 }
 
 /*
@@ -75,169 +71,167 @@ read()
  */
 write()
 {
  */
 write()
 {
-       register struct file *fp;
-       register struct inode *ip;
        register struct a {
                int     fdes;
                char    *cbuf;
        register struct a {
                int     fdes;
                char    *cbuf;
-               unsigned count;
-       } *uap;
-
-       uap = (struct a *)u.u_ap;
-       if ((int)uap->count < 0) {
-               u.u_error = EINVAL;
-               return;
-       }
-       GETF(fp, uap->fdes);
-       if ((fp->f_flag&FWRITE) == 0) {
-               u.u_error = EBADF;
-               return;
-       }
-       u.u_base = (caddr_t)uap->cbuf;
-       u.u_count = uap->count;
-       u.u_segflg = 0;
-       if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
-               if (u.u_count == uap->count)
-                       u.u_eosys = RESTARTSYS;
-       } else if (fp->f_type == DTYPE_SOCKET)
-               u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
-       else {
-               ip = fp->f_inode;
-               if (fp->f_flag & O_APPEND)
-                       fp->f_offset = ip->i_size;
-               u.u_offset = fp->f_offset;
-               if ((ip->i_mode&IFMT) == IFREG) {
-                       ilock(ip);
-                       writei(ip);
-                       iunlock(ip);
-               } else
-                       writei(ip);
-               fp->f_offset += uap->count - u.u_count;
-       }
-       u.u_r.r_val1 = uap->count - u.u_count;
-}
-
-readv()
-{
+               int     count;
+       } *uap = (struct a *)u.u_ap;
+       struct uio auio;
+       struct iovec aiov;
 
 
+       auio.uio_iov = &aiov;
+       auio.uio_iovcnt = 1;
+       aiov.iov_base = uap->cbuf;
+       aiov.iov_len = uap->count;
+       rwuio(&auio, UIO_WRITE);
 }
 
 writev()
 {
 }
 
 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;
+       }
+       rwuio(&auio, UIO_WRITE);
 }
 
 }
 
-/*
- * Ioctl system call
- * Check legality, execute common code, and switch out to individual
- * device routine.
- */
-ioctl()
+rwuio(uio, rw)
+       register struct uio *uio;
+       enum uio_rw rw;
 {
 {
+       struct a {
+               int     fdes;
+       };
        register struct file *fp;
        register struct file *fp;
+       register struct iovec *iov;
        register struct inode *ip;
        register struct inode *ip;
-       register struct a {
-               int     fdes;
-               int     cmd;
-               caddr_t cmarg;
-       } *uap;
-       register dev_t dev;
-       register fmt;
+       int i, count;
 
 
-       uap = (struct a *)u.u_ap;
-       if ((fp = getf(uap->fdes)) == NULL)
-               return;
-       if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
+       GETF(fp, ((struct a *)u.u_ap)->fdes);
+       if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) {
                u.u_error = EBADF;
                return;
        }
                u.u_error = EBADF;
                return;
        }
-       if (uap->cmd==FIOCLEX) {
-               u.u_pofile[uap->fdes] |= EXCLOSE;
-               return;
-       }
-       if (uap->cmd==FIONCLEX) {
-               u.u_pofile[uap->fdes] &= ~EXCLOSE;
-               return;
-       }
-       if (fp->f_type == DTYPE_SOCKET) {
-               soioctl(fp->f_socket, uap->cmd, uap->cmarg);
-               return;
-       }
-       ip = fp->f_inode;
-       fmt = ip->i_mode & IFMT;
-       if (fmt != IFCHR) {
-               if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
-                       off_t nread = ip->i_size - fp->f_offset;
-
-                       if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
-                               u.u_error = EFAULT;
-               } else if (uap->cmd == FIONBIO || uap->cmd == FIOASYNC)
+       uio->uio_resid = 0;
+       uio->uio_segflg = 0;
+       iov = uio->uio_iov;
+       for (i = 0; i < uio->uio_iovcnt; i++) {
+               if (iov->iov_len < 0) {
+                       u.u_error = EINVAL;
                        return;
                        return;
-               else
-                       u.u_error = ENOTTY;
-               return;
+               }
+               uio->uio_resid += iov->iov_len;
+               if (uio->uio_resid < 0) {
+                       u.u_error = EINVAL;
+                       return;
+               }
        }
        }
-       dev = ip->i_rdev;
-       u.u_r.r_val1 = 0;
-       if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
-               u.u_eosys = RESTARTSYS;
-               return;
+       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;
        }
        }
-       (*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, 0);
+       u.u_r.r_val1 = count - uio->uio_resid;
 }
 
 }
 
-/*
- * Do nothing specific version of line
- * discipline specific ioctl command.
- */
-/*ARGSUSED*/
-nullioctl(tp, cmd, addr)
-       struct tty *tp;
-       caddr_t addr;
+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;
 
 
-       return (cmd);
+       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);
 }
 
 }
 
-/*
- * Read the file corresponding to
- * the inode pointed at by the argument.
- * The actual read arguments are found
- * in the variables:
- *     u_base          core address for destination
- *     u_offset        byte offset in file
- *     u_count         number of bytes to read
- *     u_segflg        read to kernel/user/user I
- */
-readi(ip)
+rwip(ip, uio, rw)
        register struct inode *ip;
        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;
        struct buf *bp;
        struct fs *fs;
-       dev_t dev;
        daddr_t lbn, bn;
        daddr_t lbn, bn;
-       off_t diff;
        register int on, type;
        register unsigned n;
        int size;
        long bsize;
        extern int mem_no;
        register int on, type;
        register unsigned n;
        int size;
        long bsize;
        extern int mem_no;
+       int error = 0;
 
 
-       if (u.u_count == 0)
-               return;
-       dev = (dev_t)ip->i_rdev;
-       if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
-           mem_no != major(dev))) {
-               u.u_error = EINVAL;
-               return;
-       }
-       ip->i_flag |= IACC;
+       if (rw != UIO_READ && rw != UIO_WRITE)
+               panic("rwip");
+       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) {
        type = ip->i_mode&IFMT;
        if (type == IFCHR) {
-               register c = u.u_count;
-               (*cdevsw[major(dev)].d_read)(dev);
-               CHARGE(sc_tio * (c - u.u_count));
-               return;
+#ifdef QUOTA
+               register c = uio->uio_resid;
+#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 (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);
        }
        if (type != IFBLK) {
                dev = ip->i_dev;
        }
        if (type != IFBLK) {
                dev = ip->i_dev;
@@ -246,207 +240,342 @@ readi(ip)
        } else
                bsize = BLKDEV_IOSIZE;
        do {
        } else
                bsize = BLKDEV_IOSIZE;
        do {
-               lbn = u.u_offset / bsize;
-               on = u.u_offset % bsize;
-               n = MIN((unsigned)(bsize - on), u.u_count);
+               lbn = uio->uio_offset / bsize;
+               on = uio->uio_offset % bsize;
+               n = MIN((unsigned)(bsize - on), uio->uio_resid);
                if (type != IFBLK) {
                if (type != IFBLK) {
-                       diff = ip->i_size - u.u_offset;
-                       if (diff <= 0)
-                               return;
-                       if (diff < n)
-                               n = diff;
-                       bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
-                       if (u.u_error)
-                               return;
+                       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 {
                        size = blksize(fs, ip, lbn);
                } else {
-                       size = bsize;
                        bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
                        rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
                        bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
                        rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
-                       rasize = 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);
                }
                }
-               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;
                n = MIN(n, size - bp->b_resid);
                n = MIN(n, size - bp->b_resid);
-               if (n != 0) {
-#ifdef UNFAST
-                       iomove(bp->b_un.b_addr + on, n, B_READ);
-#else
-                       if (u.u_segflg != 1) {
-                               if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
-                                       u.u_error = EFAULT;
-                                       goto bad;
-                               }
+               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
                        } else
-                               bcopy(bp->b_un.b_addr + on, u.u_base, n);
-                       u.u_base += n;
-                       u.u_offset += n;
-                       u.u_count -= n;
+                               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:
 bad:
-                       ;
-#endif
+       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;
+       int error;
+       u_int cnt;
+
+       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;
                }
                }
-               if (n + on == bsize || u.u_offset == ip->i_size)
-                       bp->b_flags |= B_AGE;
-               brelse(bp);
-       } while (u.u_error == 0 && u.u_count != 0 && n != 0);
+               iov->iov_base += cnt;
+               iov->iov_len -= cnt;
+               uio->uio_resid -= cnt;
+               uio->uio_offset += cnt;
+               cp += cnt;
+               n -= cnt;
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
- * Write the file corresponding to
- * the inode pointed at by the argument.
- * The actual write arguments are found
- * in the variables:
- *     u_base          core address for source
- *     u_offset        byte offset in file
- *     u_count         number of bytes to write
- *     u_segflg        write to kernel/user/user I
+ * Give next character to user as result of read.
  */
  */
-writei(ip)
-       register struct inode *ip;
+ureadc(c, uio)
+       register int c;
+       register struct uio *uio;
 {
 {
-       struct buf *bp;
-       register struct fs *fs;
-       dev_t dev;
-       daddr_t lbn, bn;
-       register int on, type;
-       register unsigned n;
-       long bsize;
-       int size, i, count;
-       extern int mem_no;
+       register struct iovec *iov;
 
 
-       dev = (dev_t)ip->i_rdev;
-       if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
-           mem_no != major(dev)) ) {
-               u.u_error = EINVAL;
-               return;
+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;
        }
        }
-       type = ip->i_mode & IFMT;
-       if (type == IFCHR) {
-               ip->i_flag |= IUPD|ICHG;
-               CHARGE(sc_tio * u.u_count);
-               (*cdevsw[major(dev)].d_write)(dev);
+       switch (uio->uio_segflg) {
+
+       case 0:
+               if (subyte(iov->iov_base, c) < 0)
+                       return (EFAULT);
+               break;
+
+       case 1:
+               *iov->iov_base = c;
+               break;
+
+       case 2:
+               if (suibyte(iov->iov_base, c) < 0)
+                       return (EFAULT);
+               break;
+       }
+       iov->iov_base++;
+       iov->iov_len--;
+       uio->uio_resid--;
+       uio->uio_offset++;
+       return (0);
+}
+
+/*
+ * 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);
+               break;
+
+       case 1:
+               c = *iov->iov_base & 0377;
+               break;
+
+       case 2:
+               c = fuibyte(iov->iov_base);
+               break;
+       }
+       if (c < 0)
+               return (-1);
+       iov->iov_base++;
+       iov->iov_len--;
+       uio->uio_resid--;
+       uio->uio_offset++;
+       return (c & 0377);
+}
+
+/*
+ * Ioctl system call
+ * Check legality, execute common code,
+ * and switch out to individual device routine.
+ */
+ioctl()
+{
+       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;
        }
                return;
        }
-       if (u.u_count == 0)
+       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;
+               }
+       }
+#endif
+       if (com == FIOCLEX) {
+               u.u_pofile[uap->fdes] |= EXCLOSE;
                return;
                return;
-       if ((ip->i_mode & IFMT) == IFREG &&
-           u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
-               psignal(u.u_procp, SIGXFSZ);
-               u.u_error = EMFILE;
+       }
+       if (com == FIONCLEX) {
+               u.u_pofile[uap->fdes] &= ~EXCLOSE;
                return;
        }
                return;
        }
-       if (type!=IFBLK) {
-               dev = ip->i_dev;
-               fs = ip->i_fs;
-               bsize = fs->fs_bsize;
-       } else {
-               bsize = BLKDEV_IOSIZE;
+
+       /*
+        * 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;
        }
        }
-       do {
-               lbn = u.u_offset / bsize;
-               on = u.u_offset % bsize;
-               n = MIN((unsigned)(bsize - on), u.u_count);
-               if (type != IFBLK) {
-                       bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
-                       if ((long)bn<0)
-                               return;
-                       if(u.u_offset + n > ip->i_size &&
-                          (type == IFDIR || type == IFREG || type == IFLNK))
-                               ip->i_size = u.u_offset + n;
-                       size = blksize(fs, ip, lbn);
-               } else {
-                       size = bsize;
-                       bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
+       if (com&IOC_IN && size) {
+               if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) {
+                       u.u_error = EFAULT;
+                       return;
                }
                }
-               if (bn) {
-                       count = howmany(size, DEV_BSIZE);
-                       for (i = 0; i < count; i += CLSIZE) {
-                               if (mfind(dev, bn + i))
-                                       munhash(dev, bn + i);
+       } 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;
                        }
                        }
+                       if (com != FIONBIO && com != FIOASYNC)
+                               u.u_error = ENOTTY;
+                       return;
                }
                }
-               if(n == bsize) 
-                       bp = getblk(dev, bn, size);
-               else
-                       bp = bread(dev, bn, size);
-#ifdef UNFAST
-               iomove(bp->b_un.b_addr + on, n, B_WRITE);
-#else
-               if (u.u_segflg != 1) {
-                       if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
-                               u.u_error = EFAULT;
-                               goto bad;
-                       }
-               } else
-                       bcopy(u.u_base, bp->b_un.b_addr + on, n);
-               u.u_base += n;
-               u.u_offset += n;
-               u.u_count -= n;
-bad:
-               ;
-#endif
-               if (u.u_error != 0)
-                       brelse(bp);
-               else {
-                       if ((ip->i_mode&IFMT) == IFDIR)
-                               /*
-                                * Writing to clear a directory entry.
-                                * Must insure the write occurs before
-                                * the inode is freed, or may end up
-                                * pointing at a new (different) file
-                                * if inode is quickly allocated again
-                                * and system crashes.
-                                */
-                               bwrite(bp);
-                       else if (n + on == bsize) {
-                               bp->b_flags |= B_AGE;
-                               bawrite(bp);
-                       } else
-                               bdwrite(bp);
+               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;
                }
                }
-               ip->i_flag |= IUPD|ICHG;
-               if (u.u_ruid != 0)
-                       ip->i_mode &= ~(ISUID|ISGID);
-       } while (u.u_error == 0 && u.u_count != 0);
+               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;
 }
 
 /*
 }
 
 /*
- * Move n bytes at byte location
- * &bp->b_un.b_addr[o] to/from (flag) the
- * user/kernel (u.segflg) area starting at u.base.
- * Update all the arguments by the number
- * of bytes moved.
+ * Do nothing specific version of line
+ * discipline specific ioctl command.
  */
  */
-iomove(cp, n, flag)
-       register caddr_t cp;
-       register unsigned n;
+/*ARGSUSED*/
+nullioctl(tp, cmd, data, flags)
+       struct tty *tp;
+       char *data;
+       int flags;
+{
+
+#ifdef lint
+       tp = tp; data = data; flags = flags;
+#endif
+       return (-1);
+}
+
+ostty()
+{
+
+}
+
+ogtty()
 {
 {
-       register int t;
 
 
-       if (n==0)
-               return;
-       if (u.u_segflg != 1) {
-               if (flag==B_WRITE)
-                       t = copyin(u.u_base, (caddr_t)cp, n);
-               else
-                       t = copyout((caddr_t)cp, u.u_base, n);
-               if (t) {
-                       u.u_error = EFAULT;
-                       return;
-               }
-       } else
-               if (flag == B_WRITE)
-                       bcopy(u.u_base, (caddr_t)cp, n);
-               else
-                       bcopy((caddr_t)cp, u.u_base, n);
-       u.u_base += n;
-       u.u_offset += n;
-       u.u_count -= n;
 }
 }