lint, add comments on %r
[unix-history] / usr / src / sys / kern / tty_pty.c
index 1456b5c..c6eaca1 100644 (file)
@@ -3,7 +3,7 @@
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)tty_pty.c   7.2 (Berkeley) %G%
+ *     @(#)tty_pty.c   7.3.1.1 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -24,6 +24,7 @@
 #include "proc.h"
 #include "uio.h"
 #include "kernel.h"
 #include "proc.h"
 #include "uio.h"
 #include "kernel.h"
+#include "tsleep.h"
 
 #if NPTY == 1
 #undef NPTY
 
 #if NPTY == 1
 #undef NPTY
@@ -42,17 +43,23 @@ struct      pt_ioctl {
        struct  proc *pt_selr, *pt_selw;
        u_char  pt_send;
        u_char  pt_ucntl;
        struct  proc *pt_selr, *pt_selw;
        u_char  pt_send;
        u_char  pt_ucntl;
+       struct  clist pt_ioc;
 } pt_ioctl[NPTY];
 int    npty = NPTY;            /* for pstat -t */
 
 } pt_ioctl[NPTY];
 int    npty = NPTY;            /* for pstat -t */
 
-#define        PF_RCOLL        0x01
-#define        PF_WCOLL        0x02
-#define        PF_NBIO         0x04
-#define        PF_PKT          0x08            /* packet mode */
-#define        PF_STOPPED      0x10            /* user told stopped */
-#define        PF_REMOTE       0x20            /* remote and flow controlled input */
-#define        PF_NOSTOP       0x40
-#define PF_UCNTL       0x80            /* user control mode */
+#define        PF_RCOLL        0x0001
+#define        PF_WCOLL        0x0002
+#define        PF_NBIO         0x0004
+#define        PF_PKT          0x0008          /* packet mode */
+#define        PF_STOPPED      0x0010          /* user told stopped */
+#define        PF_REMOTE       0x0020          /* remote and flow controlled input */
+#define        PF_NOSTOP       0x0040
+#define        PF_UCNTL        0x0080          /* user control mode */
+#define        PF_TIOC         0x0100          /* transparent control mode */
+#define        PF_LIOC         0x0200          /* transparent control locked */
+#define        PF_WIOC         0x0400          /* waiting for PF_LIOC to clear */
+#define        PF_BLOCK        0x0800          /* block writes to slave */
+#define        PF_OWAIT        0x1000          /* waiting for PF_BLOCK to clear */
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
 
 /*ARGSUSED*/
 ptsopen(dev, flag)
@@ -93,6 +100,7 @@ ptsclose(dev)
        (*linesw[tp->t_line].l_close)(tp);
        ttyclose(tp);
        ptcwakeup(tp, FREAD|FWRITE);
        (*linesw[tp->t_line].l_close)(tp);
        ttyclose(tp);
        ptcwakeup(tp, FREAD|FWRITE);
+       return (0);
 }
 
 ptsread(dev, uio)
 }
 
 ptsread(dev, uio)
@@ -144,11 +152,17 @@ ptswrite(dev, uio)
        dev_t dev;
        struct uio *uio;
 {
        dev_t dev;
        struct uio *uio;
 {
-       register struct tty *tp;
+       register struct tty *tp = &pt_tty[minor(dev)];
+       register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
 
 
-       tp = &pt_tty[minor(dev)];
        if (tp->t_oproc == 0)
                return (EIO);
        if (tp->t_oproc == 0)
                return (EIO);
+
+       while (pti->pt_flags & PF_BLOCK) {
+               pti->pt_flags |= PF_OWAIT;
+               sleep((caddr_t)pti + 1, TTOPRI);
+       }
+
        return ((*linesw[tp->t_line].l_write)(tp, uio));
 }
 
        return ((*linesw[tp->t_line].l_write)(tp, uio));
 }
 
@@ -224,6 +238,7 @@ ptcclose(dev)
        (void)(*linesw[tp->t_line].l_modem)(tp, 0);
        tp->t_state &= ~TS_CARR_ON;
        tp->t_oproc = 0;                /* mark closed */
        (void)(*linesw[tp->t_line].l_modem)(tp, 0);
        tp->t_state &= ~TS_CARR_ON;
        tp->t_oproc = 0;                /* mark closed */
+       return (0);
 }
 
 ptcread(dev, uio)
 }
 
 ptcread(dev, uio)
@@ -257,6 +272,19 @@ ptcread(dev, uio)
                                pti->pt_ucntl = 0;
                                return (0);
                        }
                                pti->pt_ucntl = 0;
                                return (0);
                        }
+                       if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) {
+                               if (uio->uio_resid < pti->pt_ioc.c_cc + 1)
+                                       return (E2BIG);
+                               error = ureadc(TIOCPKT_TIOC, uio);
+                               while (error == 0 && pti->pt_ioc.c_cc > 0) {
+                                       cc = q_to_b(&pti->pt_ioc, buf,
+                                           MIN(pti->pt_ioc.c_cc, BUFSIZ));
+                                       if (cc <= 0)    /* impossible? */
+                                               break;
+                                       error = uiomove(buf, cc, UIO_READ, uio);
+                               }
+                               return (error);
+                       }
                        if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
                                break;
                }
                        if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
                                break;
                }
@@ -266,7 +294,7 @@ ptcread(dev, uio)
                        return (EWOULDBLOCK);
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
        }
                        return (EWOULDBLOCK);
                sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
        }
-       if (pti->pt_flags & (PF_PKT|PF_UCNTL))
+       if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC))
                error = ureadc(0, uio);
        while (uio->uio_resid > 0 && error == 0) {
                cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
                error = ureadc(0, uio);
        while (uio->uio_resid > 0 && error == 0) {
                cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
@@ -274,20 +302,25 @@ ptcread(dev, uio)
                        break;
                error = uiomove(buf, cc, UIO_READ, uio);
        }
                        break;
                error = uiomove(buf, cc, UIO_READ, uio);
        }
-       if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
-               if (tp->t_state&TS_ASLEEP) {
-                       tp->t_state &= ~TS_ASLEEP;
-                       wakeup((caddr_t)&tp->t_outq);
-               }
-               if (tp->t_wsel) {
-                       selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
-                       tp->t_wsel = 0;
-                       tp->t_state &= ~TS_WCOLL;
-               }
-       }
+       if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK))
+               ptswake(tp);
        return (error);
 }
 
        return (error);
 }
 
+ptswake(tp)
+       register struct tty *tp;
+{
+       if (tp->t_state&TS_ASLEEP) {
+               tp->t_state &= ~TS_ASLEEP;
+               wakeup((caddr_t)&tp->t_outq);
+       }
+       if (tp->t_wsel) {
+               selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+               tp->t_wsel = 0;
+               tp->t_state &= ~TS_WCOLL;
+       }
+}
+
 ptsstop(tp, flush)
        register struct tty *tp;
        int flush;
 ptsstop(tp, flush)
        register struct tty *tp;
        int flush;
@@ -340,6 +373,7 @@ ptcselect(dev, rw)
        case 0:                                 /* exceptional */
                if ((tp->t_state&TS_ISOPEN) &&
                    (pti->pt_flags&PF_PKT && pti->pt_send ||
        case 0:                                 /* exceptional */
                if ((tp->t_state&TS_ISOPEN) &&
                    (pti->pt_flags&PF_PKT && pti->pt_send ||
+                    pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc ||
                     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
                        return (1);
                if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
                     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
                        return (1);
                if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
@@ -483,7 +517,14 @@ ptyioctl(dev, cmd, data, flag)
         * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
         * ttywflush(tp) will hang if there are characters in the outq.
         */
         * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
         * ttywflush(tp) will hang if there are characters in the outq.
         */
-       if (cdevsw[major(dev)].d_open == ptcopen)
+       if (cdevsw[major(dev)].d_open == ptcopen) {
+               if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) {
+                       if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc)
+                               return (EINVAL);
+                       (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
+                       wakeup((caddr_t)&pti->pt_ioc);
+                       return (0);
+               }
                switch (cmd) {
 
                case TIOCPKT:
                switch (cmd) {
 
                case TIOCPKT:
@@ -504,6 +545,30 @@ ptyioctl(dev, cmd, data, flag)
                                pti->pt_flags &= ~PF_UCNTL;
                        return (0);
 
                                pti->pt_flags &= ~PF_UCNTL;
                        return (0);
 
+               case TIOCTIOC:
+                       if (*(int *)data) {
+                               if (pti->pt_flags & PF_UCNTL)
+                                       return (EINVAL);
+                               pti->pt_flags |= PF_TIOC;
+                       } else {
+                               pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC);
+                               while (pti->pt_ioc.c_cc)
+                                       (void) getc(&pti->pt_ioc);
+                               wakeup((caddr_t)&pti->pt_ioc);
+                       }
+                       return (0);
+
+               case TIOCBLK:
+                       if (*(int *)data)
+                               pti->pt_flags |= PF_BLOCK;
+                       else {
+                               if (pti->pt_flags & PF_OWAIT)
+                                       wakeup((caddr_t)pti + 1);
+                               pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT);
+                               ptswake(tp);
+                       }
+                       return (0);
+
                case TIOCREMOTE:
                        if (*(int *)data)
                                pti->pt_flags |= PF_REMOTE;
                case TIOCREMOTE:
                        if (*(int *)data)
                                pti->pt_flags |= PF_REMOTE;
@@ -519,6 +584,10 @@ ptyioctl(dev, cmd, data, flag)
                                pti->pt_flags &= ~PF_NBIO;
                        return (0);
 
                                pti->pt_flags &= ~PF_NBIO;
                        return (0);
 
+               case FIONREAD:
+                       *(int *)data = tp->t_outq.c_cc;
+                       return (0);
+
                case TIOCSETP:
                case TIOCSETN:
                case TIOCSETD:
                case TIOCSETP:
                case TIOCSETN:
                case TIOCSETD:
@@ -526,12 +595,83 @@ ptyioctl(dev, cmd, data, flag)
                                ;
                        break;
                }
                                ;
                        break;
                }
+       } else if (pti->pt_flags & PF_TIOC) {
+               while (pti->pt_flags & PF_LIOC) {
+                       pti->pt_flags |= PF_WIOC;
+                       switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) {
+                       case TS_OK:
+                               continue;
+                       case TS_SIG:
+                       case TS_TIME:
+                               return (EBUSY);
+                       }
+               }
+               pti->pt_flags |= PF_LIOC | PF_BLOCK;
+               while (pti->pt_ioc.c_cc)
+                       (void) getc(&pti->pt_ioc);
+               (void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc);
+               if (cmd & IOC_IN)
+                       (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc);
+               ptcwakeup(tp, FREAD);
+               switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) {
+               case TS_SIG:
+               case TS_TIME:
+                       while (pti->pt_ioc.c_cc)
+                               (void) getc(&pti->pt_ioc);
+                       if (pti->pt_flags & PF_WIOC)
+                               wakeup((caddr_t)&pti->pt_flags);
+                       if (pti->pt_flags & PF_OWAIT)
+                               wakeup((caddr_t)pti + 1);
+                       pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+                       ptswake(tp);
+                       return (EBUSY);
+               case TS_OK:
+                       break;
+               }
+               if (pti->pt_ioc.c_cc == 0) {
+                       if (pti->pt_flags & PF_WIOC)
+                               wakeup((caddr_t)&pti->pt_flags);
+                       if (pti->pt_flags & PF_OWAIT)
+                               wakeup((caddr_t)pti + 1);
+                       pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+                       ptswake(tp);
+                       goto doioctl;
+               }
+               if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error)
+                       error = EINVAL;
+               if (error == 0 && cmd & IOC_OUT) {
+                       if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc)
+                               error = EINVAL;
+                       else
+                               (void) q_to_b(&pti->pt_ioc, data,
+                                   pti->pt_ioc.c_cc);
+               }
+               while (pti->pt_ioc.c_cc)
+                       (void) getc(&pti->pt_ioc);
+               if (pti->pt_flags & PF_WIOC)
+                       wakeup((caddr_t)&pti->pt_flags);
+               if (pti->pt_flags & PF_OWAIT)
+                       wakeup((caddr_t)pti + 1);
+               pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT);
+               ptswake(tp);
+               return (error);
+       }
+
+ doioctl:
        error = ttioctl(tp, cmd, data, flag);
        /*
         * Since we use the tty queues internally,
         * pty's can't be switched to disciplines which overwrite
         * the queues.  We can't tell anything about the discipline
         * from here...
        error = ttioctl(tp, cmd, data, flag);
        /*
         * Since we use the tty queues internally,
         * pty's can't be switched to disciplines which overwrite
         * the queues.  We can't tell anything about the discipline
         * from here...
+        *
+        * Nb: this is not really good enough, the line disc open routine
+        * may have done anything at all, no guarantees that close
+        * will fix it.  This also has the effect of losing the
+        * previous discipline, which an error on a TIOCSETD shouldn't
+        * do...  Sometime it should be done via an explicit check
+        * for TIOCSETD, then check to see what linesw[new_number].l_rint
+        * really is.
         */
        if (linesw[tp->t_line].l_rint != ttyinput) {
                (*linesw[tp->t_line].l_close)(tp);
         */
        if (linesw[tp->t_line].l_rint != ttyinput) {
                (*linesw[tp->t_line].l_close)(tp);
@@ -539,6 +679,7 @@ ptyioctl(dev, cmd, data, flag)
                (void)(*linesw[tp->t_line].l_open)(dev, tp);
                error = ENOTTY;
        }
                (void)(*linesw[tp->t_line].l_open)(dev, tp);
                error = ENOTTY;
        }
+
        if (error < 0) {
                if (pti->pt_flags & PF_UCNTL &&
                    (cmd & ~0xff) == UIOCCMD(0)) {
        if (error < 0) {
                if (pti->pt_flags & PF_UCNTL &&
                    (cmd & ~0xff) == UIOCCMD(0)) {
@@ -551,7 +692,7 @@ ptyioctl(dev, cmd, data, flag)
                error = ENOTTY;
        }
        stop = (tp->t_flags & RAW) == 0 &&
                error = ENOTTY;
        }
        stop = (tp->t_flags & RAW) == 0 &&
-           tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
+           tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q');
        if (pti->pt_flags & PF_NOSTOP) {
                if (stop) {
                        pti->pt_send &= ~TIOCPKT_NOSTOP;
        if (pti->pt_flags & PF_NOSTOP) {
                if (stop) {
                        pti->pt_send &= ~TIOCPKT_NOSTOP;