don't feather, removes stuff like rogue .o's
[unix-history] / usr / src / sys / kern / tty_pty.c
index 7b77e2b..3a9986f 100644 (file)
@@ -1,4 +1,4 @@
-/*     tty_pty.c       4.15    82/01/17        */
+/*     tty_pty.c       6.1     83/07/29        */
 
 /*
  * Pseudo-teletype Driver
 
 /*
  * Pseudo-teletype Driver
@@ -9,16 +9,20 @@
 #if NPTY > 0
 #include "../h/param.h"
 #include "../h/systm.h"
 #if NPTY > 0
 #include "../h/param.h"
 #include "../h/systm.h"
+#include "../h/ioctl.h"
 #include "../h/tty.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/conf.h"
 #include "../h/tty.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/conf.h"
-#include "../h/buf.h"
 #include "../h/file.h"
 #include "../h/proc.h"
 #include "../h/file.h"
 #include "../h/proc.h"
-#undef NPTY
+#include "../h/uio.h"
+#include "../h/kernel.h"
 
 
-#define NPTY 16
+#if NPTY == 1
+#undef NPTY
+#define        NPTY    32              /* crude XXX */
+#endif
 
 #define BUFSIZ 100             /* Chunk size iomoved from user */
 
 
 #define BUFSIZ 100             /* Chunk size iomoved from user */
 
@@ -38,7 +42,9 @@ struct        pt_ioctl {
 #define        PF_WCOLL        0x02
 #define        PF_NBIO         0x04
 #define        PF_PKT          0x08            /* packet mode */
 #define        PF_WCOLL        0x02
 #define        PF_NBIO         0x04
 #define        PF_PKT          0x08            /* packet mode */
-#define        PF_FLOWCTL      0x10            /* peers flow control mode */
+#define        PF_STOPPED      0x10            /* user told stopped */
+#define        PF_REMOTE       0x20            /* remote and flow controlled input */
+#define        PF_NOSTOP       0x40
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
@@ -46,25 +52,22 @@ ptsopen(dev, flag)
 {
        register struct tty *tp;
 
 {
        register struct tty *tp;
 
-       if (minor(dev) >= NPTY) {
-               u.u_error = ENXIO;
-               return;
-       }
+       if (minor(dev) >= NPTY)
+               return (ENXIO);
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state & TS_ISOPEN) == 0) {
                ttychars(tp);           /* Set up default chars */
        tp = &pt_tty[minor(dev)];
        if ((tp->t_state & TS_ISOPEN) == 0) {
                ttychars(tp);           /* Set up default chars */
+               tp->t_ispeed = tp->t_ospeed = EXTB;
                tp->t_flags = 0;        /* No features (nor raw mode) */
                tp->t_flags = 0;        /* No features (nor raw mode) */
-       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
-               u.u_error = EBUSY;
-               return;
-       }
+       } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
+               return (EBUSY);
        if (tp->t_oproc)                        /* Ctrlr still around. */
                tp->t_state |= TS_CARR_ON;
        while ((tp->t_state & TS_CARR_ON) == 0) {
                tp->t_state |= TS_WOPEN;
                sleep((caddr_t)&tp->t_rawq, TTIPRI);
        }
        if (tp->t_oproc)                        /* Ctrlr still around. */
                tp->t_state |= TS_CARR_ON;
        while ((tp->t_state & TS_CARR_ON) == 0) {
                tp->t_state |= TS_WOPEN;
                sleep((caddr_t)&tp->t_rawq, TTIPRI);
        }
-       (*linesw[tp->t_line].l_open)(dev, tp);
+       return ((*linesw[tp->t_line].l_open)(dev, tp));
 }
 
 ptsclose(dev)
 }
 
 ptsclose(dev)
@@ -74,25 +77,55 @@ ptsclose(dev)
 
        tp = &pt_tty[minor(dev)];
        (*linesw[tp->t_line].l_close)(tp);
 
        tp = &pt_tty[minor(dev)];
        (*linesw[tp->t_line].l_close)(tp);
+       ttyclose(tp);
 }
 
 }
 
-ptsread(dev)
+ptsread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
 {
-       register struct tty *tp;
-       register struct pt_ioctl *pti;
-
-       tp = &pt_tty[minor(dev)];
-       if (tp->t_oproc) {
-               (*linesw[tp->t_line].l_read)(tp);
-               wakeup((caddr_t)&tp->t_rawq.c_cf);
-               if (tp->t_rawq.c_cc < TTYHOG/2 &&
-                   (pti = &pt_ioctl[minor(tp->t_dev)])->pt_selw) {
-                       selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
-                       pti->pt_selw = 0;
-                       pti->pt_flags &= ~PF_WCOLL;
+       register struct tty *tp = &pt_tty[minor(dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
+       int error = 0;
+
+again:
+       if (pti->pt_flags & PF_REMOTE) {
+               while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
+                       if (u.u_signal[SIGTTIN] == SIG_IGN ||
+                           u.u_signal[SIGTTIN] == SIG_HOLD ||
+       /*
+                           (u.u_procp->p_flag&SDETACH) ||
+       */
+                           u.u_procp->p_flag&SVFORK)
+                               return (EIO);
+                       gsignal(u.u_procp->p_pgrp, SIGTTIN);
+                       sleep((caddr_t)&lbolt, TTIPRI);
+               }
+               if (tp->t_rawq.c_cc == 0) {
+                       if (tp->t_state & TS_NBIO)
+                               return (EWOULDBLOCK);
+                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
+                       goto again;
                }
                }
+               while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
+                       if (ureadc(getc(&tp->t_rawq), uio) < 0) {
+                               error = EFAULT;
+                               break;
+                       }
+               if (tp->t_rawq.c_cc == 1)
+                       (void) getc(&tp->t_rawq);
+               if (tp->t_rawq.c_cc)
+                       return (error);
+       } else
+               if (tp->t_oproc)
+                       error = (*linesw[tp->t_line].l_read)(tp, uio);
+       wakeup((caddr_t)&tp->t_rawq.c_cf);
+       if (pti->pt_selw) {
+               selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
+               pti->pt_selw = 0;
+               pti->pt_flags &= ~PF_WCOLL;
        }
        }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -100,14 +133,16 @@ ptsread(dev)
  * Wakeups of controlling tty will happen
  * indirectly, when tty driver calls ptsstart.
  */
  * Wakeups of controlling tty will happen
  * indirectly, when tty driver calls ptsstart.
  */
-ptswrite(dev)
+ptswrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register struct tty *tp;
 
        tp = &pt_tty[minor(dev)];
 {
        register struct tty *tp;
 
        tp = &pt_tty[minor(dev)];
-       if (tp->t_oproc)
-               (*linesw[tp->t_line].l_write)(tp);
+       if (tp->t_oproc == 0)
+               return (EIO);
+       return ((*linesw[tp->t_line].l_write)(tp, uio));
 }
 
 /*
 }
 
 /*
@@ -117,9 +152,14 @@ ptswrite(dev)
 ptsstart(tp)
        struct tty *tp;
 {
 ptsstart(tp)
        struct tty *tp;
 {
+       register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
 
        if (tp->t_state & TS_TTSTOP)
                return;
 
        if (tp->t_state & TS_TTSTOP)
                return;
+       if (pti->pt_flags & PF_STOPPED) {
+               pti->pt_flags &= ~PF_STOPPED;
+               pti->pt_send = TIOCPKT_START;
+       }
        ptcwakeup(tp);
 }
 
        ptcwakeup(tp);
 }
 
@@ -144,15 +184,11 @@ ptcopen(dev, flag)
        register struct tty *tp;
        struct pt_ioctl *pti;
 
        register struct tty *tp;
        struct pt_ioctl *pti;
 
-       if (minor(dev) >= NPTY) {
-               u.u_error = ENXIO;
-               return;
-       }
+       if (minor(dev) >= NPTY)
+               return (ENXIO);
        tp = &pt_tty[minor(dev)];
        tp = &pt_tty[minor(dev)];
-       if (tp->t_oproc) {
-               u.u_error = EIO;
-               return;
-       }
+       if (tp->t_oproc)
+               return (EIO);
        tp->t_oproc = ptsstart;
        if (tp->t_state & TS_WOPEN)
                wakeup((caddr_t)&tp->t_rawq);
        tp->t_oproc = ptsstart;
        if (tp->t_state & TS_WOPEN)
                wakeup((caddr_t)&tp->t_rawq);
@@ -160,6 +196,7 @@ ptcopen(dev, flag)
        pti = &pt_ioctl[minor(dev)];
        pti->pt_flags = 0;
        pti->pt_send = 0;
        pti = &pt_ioctl[minor(dev)];
        pti->pt_flags = 0;
        pti->pt_send = 0;
+       return (0);
 }
 
 ptcclose(dev)
 }
 
 ptcclose(dev)
@@ -171,37 +208,41 @@ ptcclose(dev)
        if (tp->t_state & TS_ISOPEN)
                gsignal(tp->t_pgrp, SIGHUP);
        tp->t_state &= ~TS_CARR_ON;     /* virtual carrier gone */
        if (tp->t_state & TS_ISOPEN)
                gsignal(tp->t_pgrp, SIGHUP);
        tp->t_state &= ~TS_CARR_ON;     /* virtual carrier gone */
-       flushtty(tp, FREAD|FWRITE);
+       ttyflush(tp, FREAD|FWRITE);
        tp->t_oproc = 0;                /* mark closed */
 }
 
        tp->t_oproc = 0;                /* mark closed */
 }
 
-ptcread(dev)
+ptcread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
 {
-       register struct tty *tp;
+       register struct tty *tp = &pt_tty[minor(dev)];
        struct pt_ioctl *pti;
        struct pt_ioctl *pti;
+       int error = 0;
 
 
-       tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
-               return;
+               return (EIO);
        pti = &pt_ioctl[minor(dev)];
        if (pti->pt_flags & PF_PKT) {
                if (pti->pt_send) {
        pti = &pt_ioctl[minor(dev)];
        if (pti->pt_flags & PF_PKT) {
                if (pti->pt_send) {
-                       passc(pti->pt_send);
+                       error = ureadc(pti->pt_send, uio);
+                       if (error)
+                               return (error);
                        pti->pt_send = 0;
                        pti->pt_send = 0;
-                       return;
+                       return (0);
                }
                }
-               passc(0);
+               error = ureadc(0, uio);
        }
        while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
        }
        while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
-               if (pti->pt_flags&PF_NBIO) {
-                       u.u_error = EWOULDBLOCK;
-                       return;
-               }
+               if (pti->pt_flags&PF_NBIO)
+                       return (EWOULDBLOCK);
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
        }
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
        }
-       while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
-               ;
+       while (tp->t_outq.c_cc && uio->uio_resid > 0)
+               if (ureadc(getc(&tp->t_outq), uio) < 0) {
+                       error = EFAULT;
+                       break;
+               }
        if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
        if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
                if (tp->t_state&TS_ASLEEP) {
                        tp->t_state &= ~TS_ASLEEP;
@@ -213,6 +254,7 @@ ptcread(dev)
                        tp->t_state &= ~TS_WCOLL;
                }
        }
                        tp->t_state &= ~TS_WCOLL;
                }
        }
+       return (error);
 }
 
 ptsstop(tp, flush)
 }
 
 ptsstop(tp, flush)
@@ -221,8 +263,13 @@ ptsstop(tp, flush)
 {
        struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
 
 {
        struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
 
-       if (flush == 0)
-               return;
+       /* note: FLUSHREAD and FLUSHWRITE already ok */
+       if (flush == 0) {
+               flush = TIOCPKT_STOP;
+               pti->pt_flags |= PF_STOPPED;
+       } else {
+               pti->pt_flags &= ~PF_STOPPED;
+       }
        pti->pt_send |= flush;
        ptcwakeup(tp);
 }
        pti->pt_send |= flush;
        ptcwakeup(tp);
 }
@@ -232,7 +279,7 @@ ptcselect(dev, rw)
        int rw;
 {
        register struct tty *tp = &pt_tty[minor(dev)];
        int rw;
 {
        register struct tty *tp = &pt_tty[minor(dev)];
-       struct pt_ioctl *pti;
+       struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
        struct proc *p;
        int s;
 
        struct proc *p;
        int s;
 
@@ -246,7 +293,6 @@ ptcselect(dev, rw)
                        splx(s);
                        return (1);
                }
                        splx(s);
                        return (1);
                }
-               pti = &pt_ioctl[minor(dev)];
                if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
                        pti->pt_flags |= PF_RCOLL;
                else
                if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
                        pti->pt_flags |= PF_RCOLL;
                else
@@ -254,11 +300,10 @@ ptcselect(dev, rw)
                break;
 
        case FWRITE:
                break;
 
        case FWRITE:
-               if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG/2) {
+               if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
                        splx(s);
                        return (1);
                }
                        splx(s);
                        return (1);
                }
-               pti = &pt_ioctl[minor(dev)];
                if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
                        pti->pt_flags |= PF_WCOLL;
                else
                if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
                        pti->pt_flags |= PF_WCOLL;
                else
@@ -269,83 +314,142 @@ ptcselect(dev, rw)
        return (0);
 }
 
        return (0);
 }
 
-ptcwrite(dev)
+ptcwrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
 {
-       register struct tty *tp;
+       register struct tty *tp = &pt_tty[minor(dev)];
        register char *cp, *ce;
        register int cc;
        char locbuf[BUFSIZ];
        int cnt = 0;
        register char *cp, *ce;
        register int cc;
        char locbuf[BUFSIZ];
        int cnt = 0;
+       struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
+       int error = 0;
 
 
-       tp = &pt_tty[minor(dev)];
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
        if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
-               return;
-       while (u.u_count) {
-               cc = MIN(u.u_count, BUFSIZ);
+               return (EIO);
+       do {
+               register struct iovec *iov;
+
+               if (uio->uio_iovcnt == 0)
+                       break;
+               iov = uio->uio_iov;
+               if (iov->iov_len == 0) {
+                       uio->uio_iovcnt--;      
+                       uio->uio_iov++;
+                       if (uio->uio_iovcnt < 0)
+                               panic("ptcwrite");
+                       continue;
+               }
+               cc = MIN(iov->iov_len, BUFSIZ);
                cp = locbuf;
                cp = locbuf;
-               iomove(cp, (unsigned)cc, B_WRITE);
-               if (u.u_error)
+               error = uiomove(cp, cc, UIO_WRITE, uio);
+               if (error)
                        break;
                ce = cp + cc;
                        break;
                ce = cp + cc;
+again:
+               if (pti->pt_flags & PF_REMOTE) {
+                       if (tp->t_rawq.c_cc) {
+                               if (pti->pt_flags & PF_NBIO) {
+                                       iov->iov_base -= ce - cp;
+                                       iov->iov_len += ce - cp;
+                                       uio->uio_resid += ce - cp;
+                                       uio->uio_offset -= ce - cp;
+                                       return (EWOULDBLOCK);
+                               }
+                               sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
+                               goto again;
+                       }
+                       (void) b_to_q(cp, cc, &tp->t_rawq);
+                       (void) putc(0, &tp->t_rawq);
+                       wakeup((caddr_t)&tp->t_rawq);
+                       return (0);
+               }
                while (cp < ce) {
                        while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
                                wakeup((caddr_t)&tp->t_rawq);
                                if (tp->t_state & TS_NBIO) {
                while (cp < ce) {
                        while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
                                wakeup((caddr_t)&tp->t_rawq);
                                if (tp->t_state & TS_NBIO) {
-                                       u.u_count += ce - cp;
+                                       iov->iov_base -= ce - cp;
+                                       iov->iov_len += ce - cp;
+                                       uio->uio_resid += ce - cp;
+                                       uio->uio_offset -= ce - cp;
                                        if (cnt == 0)
                                        if (cnt == 0)
-                                               u.u_error = EWOULDBLOCK;
-                                       return;
+                                               return (EWOULDBLOCK);
+                                       return (0);
                                }
                                /* Better than just flushing it! */
                                /* Wait for something to be read */
                                sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
                                }
                                /* Better than just flushing it! */
                                /* Wait for something to be read */
                                sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
+                               goto again;
                        }
                        (*linesw[tp->t_line].l_rint)(*cp++, tp);
                        cnt++;
                }
                        }
                        (*linesw[tp->t_line].l_rint)(*cp++, tp);
                        cnt++;
                }
-       }
+       } while (uio->uio_resid);
+       return (error);
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
-ptyioctl(dev, cmd, addr, flag)
-       caddr_t addr;
+ptyioctl(dev, cmd, data, flag)
+       caddr_t data;
        dev_t dev;
 {
        dev_t dev;
 {
-       register struct tty *tp;
+       register struct tty *tp = &pt_tty[minor(dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
+       int error;
 
 
-       tp = &pt_tty[minor(dev)];
        /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
        /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
-       if (cdevsw[major(dev)].d_open == ptcopen) {
-               register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
-               if (cmd == TIOCPKT) {
-                       int packet;
-                       if (copyin((caddr_t)addr, &packet, sizeof (packet))) {
-                               u.u_error = EFAULT;
-                               return;
-                       }
-                       if (packet)
+       if (cdevsw[major(dev)].d_open == ptcopen)
+               switch (cmd) {
+
+               case TIOCPKT:
+                       if (*(int *)data)
                                pti->pt_flags |= PF_PKT;
                        else
                                pti->pt_flags &= ~PF_PKT;
                                pti->pt_flags |= PF_PKT;
                        else
                                pti->pt_flags &= ~PF_PKT;
-                       return;
-               }
-               if (cmd == FIONBIO) {
-                       int nbio;
-                       if (copyin(addr, &nbio, sizeof (nbio))) {
-                               u.u_error = EFAULT;
-                               return;
-                       }
-                       if (nbio)
+                       return (0);
+
+               case TIOCREMOTE:
+                       if (*(int *)data)
+                               pti->pt_flags |= PF_REMOTE;
+                       else
+                               pti->pt_flags &= ~PF_REMOTE;
+                       ttyflush(tp, FREAD|FWRITE);
+                       return (0);
+
+               case FIONBIO:
+                       if (*(int *)data)
                                pti->pt_flags |= PF_NBIO;
                        else
                                pti->pt_flags &= ~PF_NBIO;
                                pti->pt_flags |= PF_NBIO;
                        else
                                pti->pt_flags &= ~PF_NBIO;
-                       return;
+                       return (0);
+
+               case TIOCSETP:
+                       while (getc(&tp->t_outq) >= 0)
+                               ;
+                       break;
                }
                }
-               if (cmd == TIOCSETP)
-                       while (getc(&tp->t_outq) >= 0);
+       error = ttioctl(tp, cmd, data, dev);
+       if (error < 0)
+               error = ENOTTY;
+       { int stop = (tp->t_stopc == ('s'&037) &&
+                     tp->t_startc == ('q'&037));
+       if (pti->pt_flags & PF_NOSTOP) {
+               if (stop) {
+                       pti->pt_send &= TIOCPKT_NOSTOP;
+                       pti->pt_send |= TIOCPKT_DOSTOP;
+                       pti->pt_flags &= ~PF_NOSTOP;
+                       ptcwakeup(tp);
+               }
+       } else {
+               if (stop == 0) {
+                       pti->pt_send &= ~TIOCPKT_DOSTOP;
+                       pti->pt_send |= TIOCPKT_NOSTOP;
+                       pti->pt_flags |= PF_NOSTOP;
+                       ptcwakeup(tp);
+               }
+       }
        }
        }
-       if (ttioctl(tp, cmd, addr, dev) == 0)
-               u.u_error = ENOTTY;
+       return (error);
 }
 #endif
 }
 #endif