no longer allocate vnode table or name cache table
[unix-history] / usr / src / sys / kern / tty.c
index 0abd03a..0b24a54 100644 (file)
@@ -1,21 +1,18 @@
 /*
 /*
- * Copyright (c) 1982, 1986 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1990 Regents of the University of California.
  * 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.c       7.16 (Berkeley) %G%
+ *     @(#)tty.c       7.21 (Berkeley) %G%
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "dir.h"
 #include "user.h"
 #include "ioctl.h"
 #include "user.h"
 #include "ioctl.h"
-#include "tty.h"
 #define TTYDEFCHARS
 #define TTYDEFCHARS
-#include "ttydefaults.h"
+#include "tty.h"
 #undef TTYDEFCHARS
 #undef TTYDEFCHARS
-#include "termios.h"
 #define TTYDEFCHARS
 #include "ttydefaults.h"
 #undef TTYDEFCHARS
 #define TTYDEFCHARS
 #include "ttydefaults.h"
 #undef TTYDEFCHARS
 #include "dkstat.h"
 #include "uio.h"
 #include "kernel.h"
 #include "dkstat.h"
 #include "uio.h"
 #include "kernel.h"
+#include "vnode.h"
 #include "syslog.h"
 
 #include "machine/reg.h"
 #include "syslog.h"
 
 #include "syslog.h"
 
 #include "machine/reg.h"
 #include "syslog.h"
 
+/* symbolic sleep message strings */
+char ttyin[] = "ttyin";
+char ttyout[] = "ttyout";
+char ttopen[] = "ttopen";
+char ttclos[] = "ttclos";
+char ttybg[] = "ttybg";
+char ttybuf[] = "ttybuf";
+
 /*
  * Table giving parity for characters and indicating
  * character classes to tty driver. The 8th bit
 /*
  * Table giving parity for characters and indicating
  * character classes to tty driver. The 8th bit
@@ -84,8 +90,8 @@ extern char partab[], maptab[];
 /*
  * Is 'c' a line delimiter ("break" character)?
  */
 /*
  * Is 'c' a line delimiter ("break" character)?
  */
-#define ttbreakc(c) (c == '\n' || CCEQ(cc[VEOF], c) || \
-               CCEQ(cc[VEOL], c) || CCEQ(cc[VEOL2], c))
+#define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \
+       (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
 
 /*
  * Debugging aids
 
 /*
  * Debugging aids
@@ -111,9 +117,11 @@ ttychars(tp)
 ttywflush(tp)
        struct tty *tp;
 {
 ttywflush(tp)
        struct tty *tp;
 {
+       int error;
 
 
-       ttywait(tp);
-       ttyflush(tp, FREAD);
+       if ((error = ttywait(tp)) == 0)
+               ttyflush(tp, FREAD);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -125,16 +133,19 @@ ttywflush(tp)
 ttywait(tp)
        register struct tty *tp;
 {
 ttywait(tp)
        register struct tty *tp;
 {
-       int s = spltty();
+       int error = 0, s = spltty();
 
        while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
            (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 
            tp->t_oproc) {
                (*tp->t_oproc)(tp);
                tp->t_state |= TS_ASLEEP;
 
        while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
            (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 
            tp->t_oproc) {
                (*tp->t_oproc)(tp);
                tp->t_state |= TS_ASLEEP;
-               sleep((caddr_t)&tp->t_outq, TTOPRI);
+               if (error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH,
+                   ttyout, 0))
+                       break;
        }
        splx(s);
        }
        splx(s);
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -205,8 +216,10 @@ ttrstrt(tp)
        struct tty *tp;
 {
 
        struct tty *tp;
 {
 
+#ifdef DIAGNOSTIC
        if (tp == 0)
                panic("ttrstrt");
        if (tp == 0)
                panic("ttrstrt");
+#endif
        tp->t_state &= ~TS_TIMEOUT;
        ttstart(tp);
 }
        tp->t_state &= ~TS_TIMEOUT;
        ttstart(tp);
 }
@@ -234,11 +247,9 @@ ttioctl(tp, com, data, flag)
        caddr_t data;
 {
        extern int nldisp;
        caddr_t data;
 {
        extern int nldisp;
-       int softset = 0;
        int soft;
        int s, error;
 
        int soft;
        int s, error;
 
-
        /*
         * If the ioctl involves modification,
         * hang if in the background.
        /*
         * If the ioctl involves modification,
         * hang if in the background.
@@ -252,17 +263,30 @@ ttioctl(tp, com, data, flag)
        case TIOCSETA:
        case TIOCSETAW:
        case TIOCSETAF:
        case TIOCSETA:
        case TIOCSETAW:
        case TIOCSETAF:
+/**** these get removed ****
        case TIOCSETAS:
        case TIOCSETAWS:
        case TIOCSETAFS:
        case TIOCSETAS:
        case TIOCSETAWS:
        case TIOCSETAFS:
-               while (u.u_procp->p_pgid != tp->t_pgid &&
-                  tp == u.u_ttyp &&
+/***************************/
+#ifdef COMPAT_43
+       case TIOCSETP:
+       case TIOCSETN:
+       case TIOCSETC:
+       case TIOCSLTC:
+       case TIOCLBIS:
+       case TIOCLBIC:
+       case TIOCLSET:
+       case OTIOCSETD:
+#endif
+               while (isbackground(u.u_procp, tp) && 
                   u.u_procp->p_pgrp->pg_jobc &&
                   (u.u_procp->p_flag&SVFORK) == 0 &&
                   u.u_procp->p_pgrp->pg_jobc &&
                   (u.u_procp->p_flag&SVFORK) == 0 &&
-                  !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
-                  !(u.u_procp->p_sigmask & sigmask(SIGTTOU))) {
+                  (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 &&
+                  (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0) {
                        pgsignal(u.u_procp->p_pgrp, SIGTTOU);
                        pgsignal(u.u_procp->p_pgrp, SIGTTOU);
-                       sleep((caddr_t)&lbolt, TTOPRI);
+                       if (error = tsleep((caddr_t)&lbolt, TTOPRI | PCATCH,
+                           ttybg, 0))
+                               return (error);
                }
                break;
        }
                }
                break;
        }
@@ -282,7 +306,6 @@ ttioctl(tp, com, data, flag)
                register int t = *(int *)data;
                dev_t dev = tp->t_dev;
                dev_t dev = tp->t_dev;
                register int t = *(int *)data;
                dev_t dev = tp->t_dev;
                dev_t dev = tp->t_dev;
-               int error = 0;
 
                if ((unsigned)t >= nldisp)
                        return (ENXIO);
 
                if ((unsigned)t >= nldisp)
                        return (ENXIO);
@@ -371,7 +394,7 @@ ttioctl(tp, com, data, flag)
        case TIOCSTI:
                if (u.u_uid && (flag & FREAD) == 0)
                        return (EPERM);
        case TIOCSTI:
                if (u.u_uid && (flag & FREAD) == 0)
                        return (EPERM);
-               if (u.u_uid && u.u_ttyp != tp)
+               if (u.u_uid && !isctty(u.u_procp, tp))
                        return (EACCES);
                (*linesw[tp->t_line].l_rint)(*(char *)data, tp);
                break;
                        return (EACCES);
                (*linesw[tp->t_line].l_rint)(*(char *)data, tp);
                break;
@@ -429,27 +452,25 @@ ttioctl(tp, com, data, flag)
                register struct proc *p = u.u_procp;
                register struct pgrp *pgrp = pgfind(*(int *)data);
 
                register struct proc *p = u.u_procp;
                register struct pgrp *pgrp = pgfind(*(int *)data);
 
-               if (u.u_uid && 
-                   (tp != u.u_ttyp ||
-                   (pgrp && pgrp->pg_session != p->p_session))) {
-                       if (u.u_ttyp == NULL)
-                               return (ENOTTY);
-                       else
-                               return (EPERM);
-               }
-               tp->t_pgid = *(int *)data;
+               if (!isctty(p, tp))
+                       return (ENOTTY);
+               else if (pgrp == NULL || pgrp->pg_session != p->p_session)
+                       return (EPERM);
+               tp->t_pgrp = pgrp;
                break;
        }
 
        case TIOCGPGRP:
                break;
        }
 
        case TIOCGPGRP:
-               *(int *)data = tp->t_pgid;
+               if (!isctty(u.u_procp, tp))
+                       return (ENOTTY);
+               *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
                break;
 
        case TIOCSWINSZ:
                if (bcmp((caddr_t)&tp->t_winsize, data,
                    sizeof (struct winsize))) {
                        tp->t_winsize = *(struct winsize *)data;
                break;
 
        case TIOCSWINSZ:
                if (bcmp((caddr_t)&tp->t_winsize, data,
                    sizeof (struct winsize))) {
                        tp->t_winsize = *(struct winsize *)data;
-                       gsignal(tp->t_pgid, SIGWINCH);
+                       pgsignal(tp->t_pgrp, SIGWINCH);
                }
                break;
 
                }
                break;
 
@@ -482,8 +503,8 @@ ttioctl(tp, com, data, flag)
        case TIOCLBIC:
        case TIOCLSET:
        case TIOCLGET:
        case TIOCLBIC:
        case TIOCLSET:
        case TIOCLGET:
-       case TIOCGETDCOMPAT:
-       case TIOCSETDCOMPAT:
+       case OTIOCGETD:
+       case OTIOCSETD:
                return(ttcompat(tp, com, data, flag));
 #endif
 
                return(ttcompat(tp, com, data, flag));
 #endif
 
@@ -573,7 +594,7 @@ ttselect(dev, rw)
        case FREAD:
                nread = ttnread(tp);
                if (nread > 0 || 
        case FREAD:
                nread = ttnread(tp);
                if (nread > 0 || 
-                  (!(tp->t_cflag&CLOCAL) && !(tp->t_state&TS_CARR_ON)))
+                  ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
                        goto win;
                if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_RCOLL;
                        goto win;
                if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_RCOLL;
@@ -604,7 +625,6 @@ ttyopen(dev, tp)
        dev_t dev;
        register struct tty *tp;
 {
        dev_t dev;
        register struct tty *tp;
 {
-       register struct proc *pp;
 
        tp->t_dev = dev;
 
 
        tp->t_dev = dev;
 
@@ -639,8 +659,10 @@ ttyclose(tp)
        if (constty == tp)
                constty = NULL;
        ttyflush(tp, FREAD|FWRITE);
        if (constty == tp)
                constty = NULL;
        ttyflush(tp, FREAD|FWRITE);
-       tp->t_pgid = 0;
+       tp->t_session = NULL;
+       tp->t_pgrp = NULL;
        tp->t_state = 0;
        tp->t_state = 0;
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -670,8 +692,8 @@ ttymodem(tp, flag)
                tp->t_state &= ~TS_CARR_ON;
                if (tp->t_state & TS_ISOPEN) {
                        if ((tp->t_lflag & NOHANG) == 0) {
                tp->t_state &= ~TS_CARR_ON;
                if (tp->t_state & TS_ISOPEN) {
                        if ((tp->t_lflag & NOHANG) == 0) {
-                               gsignal(tp->t_pgid, SIGHUP);
-                               gsignal(tp->t_pgid, SIGCONT);
+                               pgsignal(tp->t_pgrp, SIGHUP);
+                               pgsignal(tp->t_pgrp, SIGCONT);
                                ttyflush(tp, FREAD|FWRITE);
                                return (0);
                        }
                                ttyflush(tp, FREAD|FWRITE);
                                return (0);
                        }
@@ -697,8 +719,11 @@ nullmodem(tp, flag)
        
        if (flag)
                tp->t_state |= TS_CARR_ON;
        
        if (flag)
                tp->t_state |= TS_CARR_ON;
-       else
+       else {
                tp->t_state &= ~TS_CARR_ON;
                tp->t_state &= ~TS_CARR_ON;
+               if ((tp->t_lflag & NOHANG) == 0)
+                       pgsignal(tp->t_pgrp, SIGHUP);
+       }
        return (flag);
 }
 
        return (flag);
 }
 
@@ -849,7 +874,13 @@ ttyinput(c, tp)
                        if ((lflag&NOFLSH) == 0)
                                ttyflush(tp, FREAD);
                        ttyecho(c, tp);
                        if ((lflag&NOFLSH) == 0)
                                ttyflush(tp, FREAD);
                        ttyecho(c, tp);
-                       gsignal(tp->t_pgid, SIGTSTP);
+                       pgsignal(tp->t_pgrp, SIGTSTP);
+                       goto endcase;
+               }
+               if (CCEQ(cc[VINFO], c)) {
+                       pgsignal(tp->t_pgrp, SIGINFO);
+                       if ((lflag&NOKERNINFO) == 0)
+                               ttyinfo(tp);
                        goto endcase;
                }
        }
                        goto endcase;
                }
        }
@@ -928,7 +959,7 @@ ttyinput(c, tp)
                goto endcase;
        }
                if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
                goto endcase;
        }
                if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
-                   !(lflag&ECHOPRT)) {
+                   (lflag&ECHOPRT) == 0) {
                        while (tp->t_rawq.c_cc)
                                ttyrub(unputc(&tp->t_rawq), tp);
                } else {
                        while (tp->t_rawq.c_cc)
                                ttyrub(unputc(&tp->t_rawq), tp);
                } else {
@@ -1185,65 +1216,55 @@ loop:
         */
        if (tp->t_lflag&PENDIN)
                ttypend(tp);
         */
        if (tp->t_lflag&PENDIN)
                ttypend(tp);
-       /*
-        * Handle carrier.
-        */
-       if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) {
-               if (tp->t_state&TS_ISOPEN) {
-                       splx(s);
-                       return (0);     /* EOF */
-               } else if (flag&FNDELAY) {
-                       splx(s);
-                       return (EWOULDBLOCK);
-               } else {
-                       /*
-                        * sleep awaiting carrier
-                        */
-                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
-                       splx(s);
-                       goto loop;
-               }
-       }
        splx(s);
        splx(s);
+
        /*
         * Hang process if it's in the background.
         */
        /*
         * Hang process if it's in the background.
         */
-       if (u.u_ttyp == tp && u.u_procp->p_pgid != tp->t_pgid) {
+       if (isbackground(u.u_procp, tp)) {
                if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
                   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
                    u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0)
                        return (EIO);
                pgsignal(u.u_procp->p_pgrp, SIGTTIN);
                if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
                   (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
                    u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0)
                        return (EIO);
                pgsignal(u.u_procp->p_pgrp, SIGTTIN);
-               sleep((caddr_t)&lbolt, TTIPRI);
+               if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0))
+                       return (error);
                goto loop;
        }
                goto loop;
        }
+
        /*
         * If canonical, use the canonical queue,
         * else use the raw queue.
         */
        qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
        /*
         * If canonical, use the canonical queue,
         * else use the raw queue.
         */
        qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
+
        /*
        /*
-        * No input, sleep on rawq awaiting hardware
-        * receipt and notification.
+        * If there is no input, sleep on rawq
+        * awaiting hardware receipt and notification.
+        * If we have data, we don't need to check for carrier.
         */
        s = spltty();
        if (qp->c_cc <= 0) {
         */
        s = spltty();
        if (qp->c_cc <= 0) {
-               /** XXX ??? ask mike why TS_CARR_ON was (once) necessary here
-               if ((tp->t_state&TS_CARR_ON) == 0 ||
-                   (tp->t_state&TS_NBIO)) {
+               int carrier;
+
+               carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
+               if (!carrier && tp->t_state&TS_ISOPEN) {
                        splx(s);
                        splx(s);
-                       return (EWOULDBLOCK);
+                       return (0);     /* EOF */
                }
                }
-               **/
-               if (flag&FNDELAY) {
+               if (flag & IO_NDELAY) {
                        splx(s);
                        return (EWOULDBLOCK);
                }
                        splx(s);
                        return (EWOULDBLOCK);
                }
-               sleep((caddr_t)&tp->t_rawq, TTIPRI);
+               error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+                   carrier ? ttyin : ttopen, 0);
                splx(s);
                splx(s);
+               if (error)
+                       return (error);
                goto loop;
        }
        splx(s);
                goto loop;
        }
        splx(s);
+
        /*
         * Input present, check for input mapping and processing.
         */
        /*
         * Input present, check for input mapping and processing.
         */
@@ -1253,9 +1274,11 @@ loop:
                 * delayed suspend (^Y)
                 */
                if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
                 * delayed suspend (^Y)
                 */
                if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
-                       gsignal(tp->t_pgid, SIGTSTP);
+                       pgsignal(tp->t_pgrp, SIGTSTP);
                        if (first) {
                        if (first) {
-                               sleep((caddr_t)&lbolt, TTIPRI);
+                               if (error = tsleep((caddr_t)&lbolt,
+                                   TTIPRI | PCATCH, ttybg, 0))
+                                       break;
                                goto loop;
                        }
                        break;
                                goto loop;
                        }
                        break;
@@ -1280,10 +1303,8 @@ loop:
                if (lflag&ICANON && ttbreakc(c)) {
                        break;
                }
                if (lflag&ICANON && ttbreakc(c)) {
                        break;
                }
-               }
                first = 0;
        }
                first = 0;
        }
-checktandem:
        /*
         * Look to unblock output now that (presumably)
         * the input queue has gone down.
        /*
         * Look to unblock output now that (presumably)
         * the input queue has gone down.
@@ -1340,7 +1361,7 @@ ttwrite(tp, uio, flag)
        register struct uio *uio;
 {
        register char *cp;
        register struct uio *uio;
 {
        register char *cp;
-       register int cc, ce, c;
+       register int cc = 0, ce;
        int i, hiwat, cnt, error, s;
        char obuf[OBUFSIZ];
 
        int i, hiwat, cnt, error, s;
        char obuf[OBUFSIZ];
 
@@ -1349,19 +1370,23 @@ ttwrite(tp, uio, flag)
        error = 0;
 loop:
        s = spltty();
        error = 0;
 loop:
        s = spltty();
-       if (!(tp->t_state&TS_CARR_ON) && !(tp->t_cflag&CLOCAL)) {
+       if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
                if (tp->t_state&TS_ISOPEN) {
                        splx(s);
                        return (EIO);
                if (tp->t_state&TS_ISOPEN) {
                        splx(s);
                        return (EIO);
-               } else if (flag&FNDELAY) {
+               } else if (flag & IO_NDELAY) {
                        splx(s);
                        splx(s);
-                       return (EWOULDBLOCK);
+                       error = EWOULDBLOCK;
+                       goto out;
                } else {
                        /*
                         * sleep awaiting carrier
                         */
                } else {
                        /*
                         * sleep awaiting carrier
                         */
-                       sleep((caddr_t)&tp->t_rawq, TTIPRI);
+                       error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
+                           ttopen, 0);
                        splx(s);
                        splx(s);
+                       if (error)
+                               goto out;
                        goto loop;
                }
        }
                        goto loop;
                }
        }
@@ -1370,44 +1395,40 @@ loop:
         * Hang the process if it's in the background.
         */
            (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
         * Hang the process if it's in the background.
         */
            (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 &&
-           !(u.u_procp->p_sigignore & sigmask(SIGTTOU)) &&
-           !(u.u_procp->p_sigmask & sigmask(SIGTTOU)) &&
+           (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 &&
+           (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0 &&
             u.u_procp->p_pgrp->pg_jobc) {
                pgsignal(u.u_procp->p_pgrp, SIGTTOU);
             u.u_procp->p_pgrp->pg_jobc) {
                pgsignal(u.u_procp->p_pgrp, SIGTTOU);
-               sleep((caddr_t)&lbolt, TTIPRI);
+               if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0))
+                       goto out;
                goto loop;
        }
        /*
         * Process the user's data in at most OBUFSIZ
                goto loop;
        }
        /*
         * Process the user's data in at most OBUFSIZ
-        * chunks.  Perform lower case simulation and
-        * similar hacks.  Keep track of high water
-        * mark, sleep on overflow awaiting device aid
-        * in acquiring new space.
+        * chunks.  Perform any output translation.
+        * Keep track of high water mark, sleep on overflow
+        * awaiting device aid in acquiring new space.
         */
         */
-       while (uio->uio_resid > 0) {
-               if (tp->t_outq.c_cc > hiwat) {
-                       cc = 0;
-                       goto ovhiwat;
+       while (uio->uio_resid > 0 || cc > 0) {
+               if (tp->t_lflag&FLUSHO) {
+                       uio->uio_resid = 0;
+                       return (0);
                }
                }
+               if (tp->t_outq.c_cc > hiwat)
+                       goto ovhiwat;
                /*
                /*
-                * Grab a hunk of data from the user.
+                * Grab a hunk of data from the user,
+                * unless we have some leftover from last time.
                 */
                 */
-               cc = uio->uio_iov->iov_len;
                if (cc == 0) {
                if (cc == 0) {
-                       uio->uio_iovcnt--;
-                       uio->uio_iov++;
-                       if (uio->uio_iovcnt <= 0)
-                               panic("ttwrite");
-                       continue;
+                       cc = min(uio->uio_resid, OBUFSIZ);
+                       cp = obuf;
+                       error = uiomove(cp, cc, uio);
+                       if (error) {
+                               cc = 0;
+                               break;
+                       }
                }
                }
-               if (cc > OBUFSIZ)
-                       cc = OBUFSIZ;
-               cp = obuf;
-               error = uiomove(cp, cc, UIO_WRITE, uio);
-               if (error)
-                       break;
-               if (tp->t_lflag&FLUSHO)
-                       continue;
 #ifdef notdef
                /*
                 * If nothing fancy need be done, grab those characters we
 #ifdef notdef
                /*
                 * If nothing fancy need be done, grab those characters we
@@ -1433,13 +1454,9 @@ loop:
                                        if (ttyoutput(*cp, tp) >= 0) {
                                            /* no c-lists, wait a bit */
                                            ttstart(tp);
                                        if (ttyoutput(*cp, tp) >= 0) {
                                            /* no c-lists, wait a bit */
                                            ttstart(tp);
-                                           sleep((caddr_t)&lbolt, TTOPRI);
-                                           if (cc != 0) {
-                                               uio->uio_iov->iov_base -= cc;
-                                               uio->uio_iov->iov_len += cc;
-                                               uio->uio_resid += cc;
-                                               uio->uio_offset -= cc;
-                                           }
+                                           if (error = tsleep((caddr_t)&lbolt,
+                                               TTOPRI | PCATCH, ttybuf, 0))
+                                                   break;
                                            goto loop;
                                        }
                                        cp++, cc--;
                                            goto loop;
                                        }
                                        cp++, cc--;
@@ -1466,27 +1483,28 @@ loop:
                        if (i > 0) {
                                /* out of c-lists, wait a bit */
                                ttstart(tp);
                        if (i > 0) {
                                /* out of c-lists, wait a bit */
                                ttstart(tp);
-                               sleep((caddr_t)&lbolt, TTOPRI);
-                               uio->uio_iov->iov_base -= cc;
-                               uio->uio_iov->iov_len += cc;
-                               uio->uio_resid += cc;
-                               uio->uio_offset -= cc;
+                               if (error = tsleep((caddr_t)&lbolt,
+                                   TTOPRI | PCATCH, ttybuf, 0))
+                                       break;
                                goto loop;
                        }
                        if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
                                goto loop;
                        }
                        if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
-                               goto ovhiwat;
+                               break;
                }
                ttstart(tp);
                ttstart(tp);
        }
                }
                ttstart(tp);
                ttstart(tp);
        }
+out:
+       /*
+        * If cc is nonzero, we leave the uio structure inconsistent,
+        * as the offset and iov pointers have moved forward,
+        * but it doesn't matter (the call will either return short
+        * or restart with a new uio).
+        */
+       uio->uio_resid += cc;
        return (error);
        return (error);
+
 ovhiwat:
 ovhiwat:
-       if (cc != 0) {
-               uio->uio_iov->iov_base -= cc;
-               uio->uio_iov->iov_len += cc;
-               uio->uio_resid += cc;
-               uio->uio_offset -= cc;
-       }
        ttstart(tp);
        s = spltty();
        /*
        ttstart(tp);
        s = spltty();
        /*
@@ -1497,15 +1515,18 @@ ovhiwat:
                splx(s);
                goto loop;
        }
                splx(s);
                goto loop;
        }
-       if (flag&FNDELAY) {
+       if (flag & IO_NDELAY) {
                splx(s);
                splx(s);
+               uio->uio_resid += cc;
                if (uio->uio_resid == cnt)
                        return (EWOULDBLOCK);
                return (0);
        }
        tp->t_state |= TS_ASLEEP;
                if (uio->uio_resid == cnt)
                        return (EWOULDBLOCK);
                return (0);
        }
        tp->t_state |= TS_ASLEEP;
-       sleep((caddr_t)&tp->t_outq, TTOPRI);
+       error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
        splx(s);
        splx(s);
+       if (error)
+               goto out;
        goto loop;
 }
 
        goto loop;
 }
 
@@ -1606,7 +1627,7 @@ ttyrubo(tp, cnt)
        register char *rubostring = tp->t_lflag&ECHOE ? "\b \b" : "\b";
 
        while (--cnt >= 0)
        register char *rubostring = tp->t_lflag&ECHOE ? "\b \b" : "\b";
 
        while (--cnt >= 0)
-               ttyout("\b \b", tp);
+               ttyoutstr("\b \b", tp);
 }
 
 /*
 }
 
 /*
@@ -1651,7 +1672,8 @@ ttyecho(c, tp)
        if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n'))
                return;
        if (tp->t_lflag&ECHOCTL) {
        if ((tp->t_lflag&ECHO) == 0 && !(tp->t_lflag&ECHONL && c == '\n'))
                return;
        if (tp->t_lflag&ECHOCTL) {
-               if ((c&TTY_CHARMASK)<=037 && c!='\t' && c!='\n' || c==0177) {
+               if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
+                   c == 0177) {
                        (void) ttyoutput('^', tp);
                        c &= TTY_CHARMASK;
                        if (c == 0177)
                        (void) ttyoutput('^', tp);
                        c &= TTY_CHARMASK;
                        if (c == 0177)
@@ -1665,7 +1687,7 @@ ttyecho(c, tp)
        (void) ttyoutput(c, tp);
  * send string cp to tp
  */
        (void) ttyoutput(c, tp);
  * send string cp to tp
  */
-ttyout(cp, tp)
+ttyoutstr(cp, tp)
        register char *cp;
        register struct tty *tp;
 {
        register char *cp;
        register struct tty *tp;
 {
@@ -1685,7 +1707,7 @@ ttwakeup(tp)
                tp->t_rsel = 0;
        }
        if (tp->t_state & TS_ASYNC)
                tp->t_rsel = 0;
        }
        if (tp->t_state & TS_ASYNC)
-               gsignal(tp->t_pgid, SIGIO); 
+               pgsignal(tp->t_pgrp, SIGIO); 
        wakeup((caddr_t)&tp->t_rawq);
 }
 
        wakeup((caddr_t)&tp->t_rawq);
 }
 
@@ -1720,3 +1742,66 @@ ttspeedtab(speed, table)
                        return(table[i].sp_code);
        return(-1);
 }
                        return(table[i].sp_code);
        return(-1);
 }
+
+/*
+ * (^T)
+ * Report on state of foreground process group.
+ */
+ttyinfo(tp)
+       struct tty *tp;
+{
+       register struct proc *p;
+
+       if (ttycheckoutq(tp,0) == 0) 
+               return;
+       if (tp->t_session == NULL)
+               ttyprintf(tp, "kernel: not a controlling terminal\n");
+       else if (tp->t_pgrp == NULL || 
+               (p = tp->t_pgrp->pg_mem) == NULL)
+               ttyprintf(tp, "kernel: no foreground process group\n");
+       else {
+               int i = 0;
+
+               for (; p != NULL; p = p->p_pgrpnxt) {
+                       ttyprintf(tp, 
+                        "kernel: pid: %d state: %x wchan: %x ticks: %d\n",
+                               p->p_pid, p->p_stat, p->p_wchan, p->p_cpticks);
+                       if (++i > 6) {
+                               ttyprintf(tp, "kernel: more...\n");
+                               break;
+                       }
+               }
+       }
+}
+
+#define TOTTY  0x2     /* XXX should be in header */
+/*VARARGS2*/
+ttyprintf(tp, fmt, x1)
+       struct tty *tp;
+       char *fmt;
+       unsigned x1;
+{
+       prf(fmt, &x1, TOTTY, (caddr_t)tp);
+}
+
+/*
+ * Output char to tty; console putchar style.
+ */
+tputchar(c, tp)
+       int c;
+       struct tty *tp;
+{
+       register s = spltty();
+
+       if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN)) 
+           == (TS_CARR_ON | TS_ISOPEN)) {
+               if (c == '\n')
+                       (void) ttyoutput('\r', tp);
+               (void) ttyoutput(c, tp);
+               ttstart(tp);
+               splx(s);
+               return (0);
+       }
+       splx(s);
+       return (-1);
+}