Change logging to core dumps, to log as LOG_INFO - this should appease
[unix-history] / sys / kern / tty.c
index 3ba838a..0b2b715 100644 (file)
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.c 7.44 (Berkeley) 5/28/91
  * SUCH DAMAGE.
  *
  *     from: @(#)tty.c 7.44 (Berkeley) 5/28/91
- *     $Id: tty.c,v 1.16 1994/01/28 23:17:43 ache Exp $
+ *     $Id: tty.c,v 1.28 1994/03/26 14:08:23 ache Exp $
+ */
+
+/*-
+ * TODO:
+ *    o Fix or remove TS_WOPEN.  It's only used for forcing a HUPCL
+ *      when a port is closed without being fully opened (this is
+ *      better decided by noticing if the close is a device close)
+ *      and for distinguishing the first CD change from later ones
+ *      for MDMBUF handling.  TS_WOPEN is broken for multiple opens
+ *      and for non-blocking opens.
+ *    o Fix races in ttnread().
+ *    o Do ttymodem() and nullmodem() in the same order and with
+ *      early returns instead of inconsistent elses.
+ *    o Some or all of the t_out wakeups need to do a selwakeup()
+ *      since ttselect() now blocks when ttwrite() would be blocked
+ *      by lack of carrier.
+ *    o Fix various flags races in sio.  E.g., the CLOCAL locking is
+ *      harmed by the wakeups for delta-CLOCAL, the carrier wait loop
+ *      needs to start nearer the top of sioopen(), and the there may
+ *      need to be a wakeup on t_raw in comhardclose() to kick other
+ *      processes out of the wait loop.  "take it from the top" code
+ *      gives DTR glitch in usual case (!com->active).  bidir open
+ *      doesn't set TS_WOPEN and triggers ttymodem() warning.  com->
+ *      active may help recover.  bidir open doesn't set CLOCAL early
+ *      enough.
+ *    o Call suser() to log privileged CLOCAL changes.
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #include "dkstat.h"
 #include "uio.h"
 #include "kernel.h"
 #include "dkstat.h"
 #include "uio.h"
 #include "kernel.h"
+#include "malloc.h"
 #include "vnode.h"
 #include "syslog.h"
 #include "signalvar.h"
 #include "vnode.h"
 #include "syslog.h"
 #include "signalvar.h"
-
 #include "vm/vm.h"
 #include "vm/vm.h"
+#include "kinfo.h"
+#include "kinfo_proc.h"
+
 
 /*
  * Input control starts when we would not be able to fit the maximum
 
 /*
  * Input control starts when we would not be able to fit the maximum
@@ -62,7 +91,7 @@
 #define        I_LOW_WATER     ((TTYHOG - 2 * 256) * 7 / 8)    /* XXX */
 
 /* XXX RB_LEN() is too slow. */
 #define        I_LOW_WATER     ((TTYHOG - 2 * 256) * 7 / 8)    /* XXX */
 
 /* XXX RB_LEN() is too slow. */
-#define INPUT_LEN(tp)  (RB_LEN(&(tp)->t_can) + RB_LEN(&(tp)->t_raw))
+#define INPUT_LEN(tp)  (RB_LEN((tp)->t_can) + RB_LEN((tp)->t_raw))
 #undef MAX_INPUT               /* XXX wrong in <sys/syslimits.h> */
 #define        MAX_INPUT       TTYHOG
 
 #undef MAX_INPUT               /* XXX wrong in <sys/syslimits.h> */
 #define        MAX_INPUT       TTYHOG
 
@@ -200,9 +229,8 @@ ttywait(tp)
 {
        int error = 0, s = spltty();
 
 {
        int error = 0, s = spltty();
 
-       while ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
-           (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 
-           tp->t_oproc) {
+       while ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+              CAN_DO_IO(tp) && tp->t_oproc) {
                /*
                 * XXX temporary fix for deadlock.
                 *
                /*
                 * XXX temporary fix for deadlock.
                 *
@@ -219,11 +247,11 @@ ttywait(tp)
                tp->t_lowat = 0;
 
                (*tp->t_oproc)(tp);
                tp->t_lowat = 0;
 
                (*tp->t_oproc)(tp);
-               if ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
-                   (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL)) {
+               if ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+                   CAN_DO_IO(tp)) {
                        tp->t_state |= TS_ASLEEP;
                        tp->t_state |= TS_ASLEEP;
-                       if (error = ttysleep(tp, (caddr_t)&tp->t_out,
-                           TTOPRI | PCATCH, ttyout, 0))
+                       if (error = ttysleep(tp, (caddr_t)tp->t_out,
+                           TTOPRI | PCATCH, "ttywai", 0))
                                break;
                } else
                        break;
                                break;
                } else
                        break;
@@ -255,16 +283,16 @@ ttyflush(tp, rw)
                tp->t_state &= ~TS_TTSTOP;
        (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
        if (rw & FREAD) {
                tp->t_state &= ~TS_TTSTOP;
        (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
        if (rw & FREAD) {
-               flushq(&tp->t_can);
-               flushq(&tp->t_raw);
+               flushq(tp->t_can);
+               flushq(tp->t_raw);
                tp->t_rocount = 0;
                tp->t_rocol = 0;
                tp->t_state &= ~TS_LOCAL;
                ttwakeup(tp);
        }
        if (rw & FWRITE) {
                tp->t_rocount = 0;
                tp->t_rocol = 0;
                tp->t_state &= ~TS_LOCAL;
                ttwakeup(tp);
        }
        if (rw & FWRITE) {
-               flushq(&tp->t_out);
-               wakeup((caddr_t)&tp->t_out);
+               flushq(tp->t_out);
+               wakeup((caddr_t)tp->t_out);
                if (tp->t_wsel) {
                        selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
                        tp->t_wsel = 0;
                if (tp->t_wsel) {
                        selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
                        tp->t_wsel = 0;
@@ -284,16 +312,16 @@ ttyflush(tp, rw)
                         * is still tricky because we don't want to add a
                         * new obstruction to draining the output queue.
                         */
                         * is still tricky because we don't want to add a
                         * new obstruction to draining the output queue.
                         */
-                       out_cc = RB_LEN(&tp->t_out);
+                       out_cc = RB_LEN(tp->t_out);
                        t_state = tp->t_state;
                        ttyunblock(tp);
                        tp->t_state &= ~TS_TBLOCK;
                        t_state = tp->t_state;
                        ttyunblock(tp);
                        tp->t_state &= ~TS_TBLOCK;
-                       if (t_state & TS_TBLOCK && RB_LEN(&tp->t_out) != 0)
-                               ttysleep(tp, (caddr_t)&tp->t_out, TTIPRI,
-                                        ttyout, hz / 10);
-                       if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) {
+                       if (t_state & TS_TBLOCK && RB_LEN(tp->t_out) != 0)
+                               ttysleep(tp, (caddr_t)tp->t_out, TTIPRI,
+                                        "ttyfls", hz / 10);
+                       if (out_cc == 0 && RB_LEN(tp->t_out) != 0) {
                                (*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE);
                                (*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE);
-                               flushq(&tp->t_out);
+                               flushq(tp->t_out);
                        }
                }
        }
                        }
                }
        }
@@ -312,7 +340,7 @@ ttyblock(tp)
 
        if ((tp->t_state & TS_TBLOCK) == 0
            && tp->t_cc[VSTOP] != _POSIX_VDISABLE
 
        if ((tp->t_state & TS_TBLOCK) == 0
            && tp->t_cc[VSTOP] != _POSIX_VDISABLE
-           && putc(tp->t_cc[VSTOP], &tp->t_out) == 0)
+           && putc(tp->t_cc[VSTOP], tp->t_out) == 0)
                tp->t_state |= TS_TBLOCK;
        if (tp->t_cflag & CDTR_IFLOW)
                tp->t_state |= TS_DTR_IFLOW;
                tp->t_state |= TS_TBLOCK;
        if (tp->t_cflag & CDTR_IFLOW)
                tp->t_state |= TS_DTR_IFLOW;
@@ -332,7 +360,7 @@ ttyunblock(tp)
 
        if (tp->t_state & TS_TBLOCK
            && tp->t_cc[VSTART] != _POSIX_VDISABLE
 
        if (tp->t_state & TS_TBLOCK
            && tp->t_cc[VSTART] != _POSIX_VDISABLE
-           && putc(tp->t_cc[VSTART], &tp->t_out) == 0)
+           && putc(tp->t_cc[VSTART], tp->t_out) == 0)
                tp->t_state &= ~TS_TBLOCK;
        tp->t_state &= ~TS_HW_IFLOW;
        ttstart(tp);
                tp->t_state &= ~TS_TBLOCK;
        tp->t_state &= ~TS_HW_IFLOW;
        ttstart(tp);
@@ -492,7 +520,7 @@ ttioctl(tp, com, data, flag)
                break;
 
        case TIOCOUTQ:
                break;
 
        case TIOCOUTQ:
-               *(int *)data = RB_LEN(&tp->t_out);
+               *(int *)data = RB_LEN(tp->t_out);
                break;
 
        case TIOCSTOP:
                break;
 
        case TIOCSTOP:
@@ -547,41 +575,26 @@ ttioctl(tp, com, data, flag)
                                ttyflush(tp, FREAD);
                }
                if ((t->c_cflag&CIGNORE) == 0) {
                                ttyflush(tp, FREAD);
                }
                if ((t->c_cflag&CIGNORE) == 0) {
+                       tcflag_t old_cflag;
+
                        /*
                         * set device hardware
                         */
                        if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
                                splx(s);
                                return (error);
                        /*
                         * set device hardware
                         */
                        if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
                                splx(s);
                                return (error);
-                       } else {
-                               /*
-                                * XXX doubtful.  We mostly check both CLOCAL
-                                * and TS_CARR_ON before doing anything, and
-                                * changing TS_ISOPEN here just give another
-                                * flag to worry about, and is probably
-                                * inconsistent with not changing TS_ISOPEN
-                                * when carrier drops or CLOCAL rises.  OTOH
-                                * we should maintain a flag to keep track
-                                * of the combination of CLOCAL and TS_CARR_ON.
-                                * This could be just TS_CARR_ON (if we don't
-                                * need to 
-                                *
-                                * XXX ttselect() doesn't worry about
-                                * TS_ISOPEN, so it is inconsistent with
-                                * ttread() after TS_ISOPEN gets cleared here.
-                                */
-                               if ((tp->t_state&TS_CARR_ON) == 0 &&
-                                   (tp->t_cflag&CLOCAL) &&
-                                   (t->c_cflag&CLOCAL) == 0) {
-                                       tp->t_state &= ~TS_ISOPEN;
-                                       tp->t_state |= TS_WOPEN;
-                                       ttwakeup(tp);
-                               }
-                               tp->t_cflag = t->c_cflag;
-                               tp->t_ispeed = t->c_ispeed;
-                               tp->t_ospeed = t->c_ospeed;
                        }
                        }
+                       old_cflag = tp->t_cflag;
+                       tp->t_cflag = t->c_cflag;
+                       tp->t_ispeed = t->c_ispeed;
+                       tp->t_ospeed = t->c_ospeed;
                        ttsetwater(tp);
                        ttsetwater(tp);
+                       if (tp->t_cflag & CLOCAL)
+                               tp->t_state &= ~TS_ZOMBIE;
+                       if ((tp->t_cflag ^ old_cflag) & CLOCAL) {
+                               ttwakeup(tp);
+                               wakeup((caddr_t)tp->t_out);
+                       }
                }
                if (com != TIOCSETAF) {
                        if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
                }
                if (com != TIOCSETAF) {
                        if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
@@ -590,8 +603,8 @@ ttioctl(tp, com, data, flag)
                                        ttwakeup(tp);
                                }
                                else {
                                        ttwakeup(tp);
                                }
                                else {
-                                       catb(&tp->t_raw, &tp->t_can);
-                                       catb(&tp->t_can, &tp->t_raw);
+                                       catb(tp->t_raw, tp->t_can);
+                                       catb(tp->t_can, tp->t_raw);
                                }
                }
                tp->t_iflag = t->c_iflag;
                                }
                }
                tp->t_iflag = t->c_iflag;
@@ -638,7 +651,9 @@ ttioctl(tp, com, data, flag)
        case TIOCSPGRP: {
                register struct pgrp *pgrp = pgfind(*(int *)data);
 
        case TIOCSPGRP: {
                register struct pgrp *pgrp = pgfind(*(int *)data);
 
-               if (!isctty(p, tp))
+               if (!suser(p->p_ucred, &p->p_acflag))
+                       ;
+               else if (!isctty(p, tp))
                        return (ENOTTY);
                else if (pgrp == NULL || pgrp->pg_session != p->p_session)
                        return (EPERM);
                        return (ENOTTY);
                else if (pgrp == NULL || pgrp->pg_session != p->p_session)
                        return (EPERM);
@@ -666,9 +681,7 @@ ttioctl(tp, com, data, flag)
 
        case TIOCCONS:
                if (*(int *)data) {
 
        case TIOCCONS:
                if (*(int *)data) {
-                       if (constty && constty != tp &&
-                           (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
-                           (TS_CARR_ON|TS_ISOPEN))
+                       if (constty && constty != tp && CAN_DO_IO(constty))
                                return (EBUSY);
 #ifndef        UCONSOLE
                        if (error = suser(p->p_ucred, &p->p_acflag))
                                return (EBUSY);
 #ifndef        UCONSOLE
                        if (error = suser(p->p_ucred, &p->p_acflag))
@@ -703,9 +716,9 @@ ttnread(tp)
        /* XXX races. */
        if (tp->t_lflag & PENDIN)
                ttypend(tp);
        /* XXX races. */
        if (tp->t_lflag & PENDIN)
                ttypend(tp);
-       nread = RB_LEN(&tp->t_can);
+       nread = RB_LEN(tp->t_can);
        if ((tp->t_lflag & ICANON) == 0) {
        if ((tp->t_lflag & ICANON) == 0) {
-               nread += RB_LEN(&tp->t_raw);
+               nread += RB_LEN(tp->t_raw);
                if (nread < tp->t_cc[VMIN])
                        nread = 0;
        }
                if (nread < tp->t_cc[VMIN])
                        nread = 0;
        }
@@ -718,17 +731,14 @@ ttselect(dev, rw, p)
        int rw;
        struct proc *p;
 {
        int rw;
        struct proc *p;
 {
-       register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
-       int nread;
+       register struct tty *tp = cdevsw[major(dev)].d_ttys[minor(dev)];
        int s = spltty();
        struct proc *selp;
 
        switch (rw) {
 
        case FREAD:
        int s = spltty();
        struct proc *selp;
 
        switch (rw) {
 
        case FREAD:
-               nread = ttnread(tp);
-               if (nread > 0 || 
-                  ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+               if (ttnread(tp) > 0 || tp->t_state & TS_ZOMBIE)
                        goto win;
                if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_RCOLL;
                        goto win;
                if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_RCOLL;
@@ -737,7 +747,8 @@ ttselect(dev, rw, p)
                break;
 
        case FWRITE:
                break;
 
        case FWRITE:
-               if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+               if (RB_LEN(tp->t_out) <= tp->t_lowat && CAN_DO_IO(tp)
+                   || tp->t_state & TS_ZOMBIE)
                        goto win;
                if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_WCOLL;
                        goto win;
                if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
                        tp->t_state |= TS_WCOLL;
@@ -767,9 +778,9 @@ ttyopen(dev, tp, dummy)
        tp->t_state &= ~TS_WOPEN;
        if ((tp->t_state & TS_ISOPEN) == 0) {
                tp->t_state |= TS_ISOPEN;
        tp->t_state &= ~TS_WOPEN;
        if ((tp->t_state & TS_ISOPEN) == 0) {
                tp->t_state |= TS_ISOPEN;
-               initrb(&tp->t_raw);
-               initrb(&tp->t_can);
-               initrb(&tp->t_out);
+               initrb(tp->t_raw);
+               initrb(tp->t_can);
+               initrb(tp->t_out);
                bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
        }
        return (0);
                bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
        }
        return (0);
@@ -791,7 +802,7 @@ ttylclose(tp, flag)
 }
 
 /*
 }
 
 /*
- * Handle close() on a tty line: flush and set to initial state,
+ * Handle close() on a tty line: set to initial state,
  * bumping generation number so that pending read/write calls
  * can detect recycling of the tty.
  */
  * bumping generation number so that pending read/write calls
  * can detect recycling of the tty.
  */
@@ -801,7 +812,6 @@ ttyclose(tp)
 {
        if (constty == tp)
                constty = NULL;
 {
        if (constty == tp)
                constty = NULL;
-       ttyflush(tp, FREAD|FWRITE);
        tp->t_session = NULL;
        tp->t_pgrp = NULL;
        tp->t_state = 0;
        tp->t_session = NULL;
        tp->t_pgrp = NULL;
        tp->t_state = 0;
@@ -820,6 +830,10 @@ ttymodem(tp, flag)
        int flag;
 {
 
        int flag;
 {
 
+#ifdef DIAGNOSTIC
+       if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0)
+               printf("ttymodem: not open\n");
+#endif
        if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
                /*
                 * MDMBUF: do flow control according to carrier flag
        if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
                /*
                 * MDMBUF: do flow control according to carrier flag
@@ -837,10 +851,14 @@ ttymodem(tp, flag)
                 */
                tp->t_state &= ~TS_CARR_ON;
                if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
                 */
                tp->t_state &= ~TS_CARR_ON;
                if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
+                       tp->t_state |= TS_ZOMBIE;
                        if (tp->t_session && tp->t_session->s_leader)
                                psignal(tp->t_session->s_leader, SIGHUP);
                        ttyflush(tp, FREAD|FWRITE);
                        return (0);
                        if (tp->t_session && tp->t_session->s_leader)
                                psignal(tp->t_session->s_leader, SIGHUP);
                        ttyflush(tp, FREAD|FWRITE);
                        return (0);
+               } else {
+                       wakeup((caddr_t)tp->t_raw);
+                       wakeup((caddr_t)tp->t_out);
                }
        } else {
                /*
                }
        } else {
                /*
@@ -848,6 +866,7 @@ ttymodem(tp, flag)
                 */
                tp->t_state |= TS_CARR_ON;
                ttwakeup(tp);
                 */
                tp->t_state |= TS_CARR_ON;
                ttwakeup(tp);
+               wakeup((caddr_t)tp->t_out);
        }
        return (1);
 }
        }
        return (1);
 }
@@ -861,12 +880,17 @@ nullmodem(tp, flag)
        register struct tty *tp;
        int flag;
 {
        register struct tty *tp;
        int flag;
 {
-       
+
+#ifdef DIAGNOSTIC
+       if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0)
+               printf("nullmodem: not open\n");
+#endif
        if (flag)
                tp->t_state |= TS_CARR_ON;
        else {
                tp->t_state &= ~TS_CARR_ON;
        if (flag)
                tp->t_state |= TS_CARR_ON;
        else {
                tp->t_state &= ~TS_CARR_ON;
-               if ((tp->t_cflag&CLOCAL) == 0) {
+               if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
+                       tp->t_state |= TS_ZOMBIE;
                        if (tp->t_session && tp->t_session->s_leader)
                                psignal(tp->t_session->s_leader, SIGHUP);
                        return (0);
                        if (tp->t_session && tp->t_session->s_leader)
                                psignal(tp->t_session->s_leader, SIGHUP);
                        return (0);
@@ -887,12 +911,12 @@ ttypend(tp)
 
        tp->t_lflag &= ~PENDIN;
        tp->t_state |= TS_TYPEN;
 
        tp->t_lflag &= ~PENDIN;
        tp->t_state |= TS_TYPEN;
-       hd = tp->t_raw.rb_hd;
-       tl = tp->t_raw.rb_tl;
-       flushq(&tp->t_raw);
+       hd = tp->t_raw->rb_hd;
+       tl = tp->t_raw->rb_tl;
+       flushq(tp->t_raw);
        while (hd != tl) {
                ttyinput(*hd, tp);
        while (hd != tl) {
                ttyinput(*hd, tp);
-               hd = RB_SUCC(&tp->t_raw, hd);
+               hd = RB_SUCC(tp->t_raw, hd);
        }
        tp->t_state &= ~TS_TYPEN;
 }
        }
        tp->t_state &= ~TS_TYPEN;
 }
@@ -935,7 +959,7 @@ ttyinput(c, tp)
        if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0
             || tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0)
            && INPUT_LEN(tp) > I_HIGH_WATER - 3
        if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0
             || tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0)
            && INPUT_LEN(tp) > I_HIGH_WATER - 3
-           && ((lflag & ICANON) == 0 || RB_LEN(&tp->t_can) != 0))
+           && ((lflag & ICANON) == 0 || RB_LEN(tp->t_can) != 0))
                ttyblock(tp);
        /*
         * Handle exceptional conditions (break, parity, framing).
                ttyblock(tp);
        /*
         * Handle exceptional conditions (break, parity, framing).
@@ -957,9 +981,9 @@ ttyinput(c, tp)
 parmrk:
                                if (INPUT_LEN(tp) > MAX_INPUT - 3)
                                        goto input_overflow;
 parmrk:
                                if (INPUT_LEN(tp) > MAX_INPUT - 3)
                                        goto input_overflow;
-                               putc(0377|TTY_QUOTE, &tp->t_raw);
-                               putc(0|TTY_QUOTE, &tp->t_raw);
-                               putc(c|TTY_QUOTE, &tp->t_raw);
+                               putc(0377|TTY_QUOTE, tp->t_raw);
+                               putc(0|TTY_QUOTE, tp->t_raw);
+                               putc(c|TTY_QUOTE, tp->t_raw);
                                goto endcase;
                        } else
                                c = 0;
                                goto endcase;
                        } else
                                c = 0;
@@ -1072,23 +1096,23 @@ parmrk:
                 * erase (^H / ^?)
                 */
                if (CCEQ(cc[VERASE], c)) {
                 * erase (^H / ^?)
                 */
                if (CCEQ(cc[VERASE], c)) {
-                       if (RB_LEN(&tp->t_raw))
-                               ttyrub(unputc(&tp->t_raw), tp);
+                       if (RB_LEN(tp->t_raw))
+                               ttyrub(unputc(tp->t_raw), tp);
                        goto endcase;
                }
                /*
                 * kill (^U)
                 */
                if (CCEQ(cc[VKILL], c)) {
                        goto endcase;
                }
                /*
                 * kill (^U)
                 */
                if (CCEQ(cc[VKILL], c)) {
-                       if (lflag&ECHOKE && RB_LEN(&tp->t_raw) == tp->t_rocount &&
+                       if (lflag&ECHOKE && RB_LEN(tp->t_raw) == tp->t_rocount &&
                            (lflag&ECHOPRT) == 0) {
                            (lflag&ECHOPRT) == 0) {
-                               while (RB_LEN(&tp->t_raw))
-                                       ttyrub(unputc(&tp->t_raw), tp);
+                               while (RB_LEN(tp->t_raw))
+                                       ttyrub(unputc(tp->t_raw), tp);
                        } else {
                                ttyecho(c, tp);
                                if (lflag&ECHOK || lflag&ECHOKE)
                                        ttyecho('\n', tp);
                        } else {
                                ttyecho(c, tp);
                                if (lflag&ECHOK || lflag&ECHOKE)
                                        ttyecho('\n', tp);
-                               while (getc(&tp->t_raw) > 0)
+                               while (getc(tp->t_raw) > 0)
                                        ;
                                tp->t_rocount = 0;
                        }
                                        ;
                                tp->t_rocount = 0;
                        }
@@ -1104,7 +1128,7 @@ parmrk:
                        /* 
                         * erase whitespace 
                         */
                        /* 
                         * erase whitespace 
                         */
-                       while ((c = unputc(&tp->t_raw)) == ' ' || c == '\t')
+                       while ((c = unputc(tp->t_raw)) == ' ' || c == '\t')
                                ttyrub(c, tp);
                        if (c == -1)
                                goto endcase;
                                ttyrub(c, tp);
                        if (c == -1)
                                goto endcase;
@@ -1113,14 +1137,14 @@ parmrk:
                         * next chars type (for ALTWERASE)
                         */
                        ttyrub(c, tp);
                         * next chars type (for ALTWERASE)
                         */
                        ttyrub(c, tp);
-                       c = unputc(&tp->t_raw);
+                       c = unputc(tp->t_raw);
                        if (c == -1)
                                goto endcase;
                        /*
                         * Handle one-letter word cases.
                         */
                        if (c == ' ' || c == '\t') {
                        if (c == -1)
                                goto endcase;
                        /*
                         * Handle one-letter word cases.
                         */
                        if (c == ' ' || c == '\t') {
-                               putc(c, &tp->t_raw);
+                               putc(c, tp->t_raw);
                                goto endcase;
                        }
                        ctype = ISALPHA(c);
                                goto endcase;
                        }
                        ctype = ISALPHA(c);
@@ -1129,13 +1153,13 @@ parmrk:
                         */
                        do {
                                ttyrub(c, tp);
                         */
                        do {
                                ttyrub(c, tp);
-                               c = unputc(&tp->t_raw);
+                               c = unputc(tp->t_raw);
                                if (c == -1)
                                        goto endcase;
                        } while (c != ' ' && c != '\t' && 
                                ((lflag & ALTWERASE) == 0
                                 || ISALPHA(c) == ctype));
                                if (c == -1)
                                        goto endcase;
                        } while (c != ' ' && c != '\t' && 
                                ((lflag & ALTWERASE) == 0
                                 || ISALPHA(c) == ctype));
-                       (void) putc(c, &tp->t_raw);
+                       (void) putc(c, tp->t_raw);
                        goto endcase;
                }
                /*
                        goto endcase;
                }
                /*
@@ -1161,7 +1185,7 @@ parmrk:
        if (INPUT_LEN(tp) >= MAX_INPUT) {
 input_overflow:
                if (iflag&IMAXBEL) {
        if (INPUT_LEN(tp) >= MAX_INPUT) {
 input_overflow:
                if (iflag&IMAXBEL) {
-                       if (RB_LEN(&tp->t_out) < tp->t_hiwat)
+                       if (RB_LEN(tp->t_out) < tp->t_hiwat)
                                (void) ttyoutput(CTRL('g'), tp);
                } else
                        ttyflush(tp, FREAD);
                                (void) ttyoutput(CTRL('g'), tp);
                } else
                        ttyflush(tp, FREAD);
@@ -1171,7 +1195,7 @@ input_overflow:
         * Put data char in q for user and
         * wakeup on seeing a line delimiter.
         */
         * Put data char in q for user and
         * wakeup on seeing a line delimiter.
         */
-       if (putc(c, &tp->t_raw) >= 0) {
+       if (putc(c, tp->t_raw) >= 0) {
                if ((lflag&ICANON) == 0) {
                        ttwakeup(tp);
                        ttyecho(c, tp);
                if ((lflag&ICANON) == 0) {
                        ttwakeup(tp);
                        ttyecho(c, tp);
@@ -1179,7 +1203,7 @@ input_overflow:
                }
                if (ttbreakc(c)) {
                        tp->t_rocount = 0;
                }
                if (ttbreakc(c)) {
                        tp->t_rocount = 0;
-                       catb(&tp->t_raw, &tp->t_can);
+                       catb(tp->t_raw, tp->t_can);
                        ttwakeup(tp);
                } else if (tp->t_rocount++ == 0)
                        tp->t_rocol = tp->t_col;
                        ttwakeup(tp);
                } else if (tp->t_rocount++ == 0)
                        tp->t_rocol = tp->t_col;
@@ -1234,7 +1258,7 @@ ttyoutput(c, tp)
        if ((oflag&OPOST) == 0) {
                if (tp->t_lflag&FLUSHO) 
                        return (-1);
        if ((oflag&OPOST) == 0) {
                if (tp->t_lflag&FLUSHO) 
                        return (-1);
-               if (putc(c, &tp->t_out))
+               if (putc(c, tp->t_out))
                        return (c);
                tk_nout++;
                tp->t_outcc++;
                        return (c);
                tk_nout++;
                tp->t_outcc++;
@@ -1259,17 +1283,17 @@ ttyoutput(c, tp)
 #ifdef was
                        c -= b_to_q("        ", c, &tp->t_outq);
 #else
 #ifdef was
                        c -= b_to_q("        ", c, &tp->t_outq);
 #else
-                       i = imin(c, RB_CONTIGPUT(&tp->t_out));
-                       bcopy("        ", tp->t_out.rb_tl, i);
-                       tp->t_out.rb_tl =
-                               RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
-                       i = imin(c - i, RB_CONTIGPUT(&tp->t_out));
+                       i = imin(c, RB_CONTIGPUT(tp->t_out));
+                       bcopy("        ", tp->t_out->rb_tl, i);
+                       tp->t_out->rb_tl =
+                               RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
+                       i = imin(c - i, RB_CONTIGPUT(tp->t_out));
 
                        /* off end and still have space? */
                        if (i) {
 
                        /* off end and still have space? */
                        if (i) {
-                               bcopy("        ", tp->t_out.rb_tl, i);
-                               tp->t_out.rb_tl =
-                                  RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
+                               bcopy("        ", tp->t_out->rb_tl, i);
+                               tp->t_out->rb_tl =
+                                  RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
                        }
 #endif
                        tk_nout += c;
                        }
 #endif
                        tk_nout += c;
@@ -1289,7 +1313,7 @@ ttyoutput(c, tp)
         */
        if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
                return (c);
         */
        if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
                return (c);
-       if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_out))
+       if ((tp->t_lflag&FLUSHO) == 0 && putc(c, tp->t_out))
                return (c);
 
        col = tp->t_col;
                return (c);
 
        col = tp->t_col;
@@ -1371,7 +1395,7 @@ loop:
         * If canonical, use the canonical queue,
         * else use the raw queue.
         */
         * If canonical, use the canonical queue,
         * else use the raw queue.
         */
-       qp = lflag&ICANON ? &tp->t_can : &tp->t_raw;
+       qp = lflag&ICANON ? tp->t_can : tp->t_raw;
        rblen = RB_LEN(qp);
 
        if ((lflag & ICANON) == 0) {
        rblen = RB_LEN(qp);
 
        if ((lflag & ICANON) == 0) {
@@ -1421,6 +1445,8 @@ loop:
                        } else {
                                /* nothing, check expiration */
                                slp = t - diff(timecopy, stime);
                        } else {
                                /* nothing, check expiration */
                                slp = t - diff(timecopy, stime);
+                               if (slp <= 0)
+                                       goto read;
                        }
                        last_cc = rblen;
                } else {        /* m == 0 */
                        }
                        last_cc = rblen;
                } else {        /* m == 0 */
@@ -1443,35 +1469,32 @@ loop:
                        }
                }
 #undef diff
                        }
                }
 #undef diff
-               if (slp > 0) {
-                       /*
-                        * Rounding down may make us wake up just short
-                        * of the target, so we round up.
-                        * The formula is ceiling(slp * hz/1000000).
-                        * 32-bit arithmetic is enough for hz < 169.
-                        * XXX see hzto() for how to avoid overflow if hz
-                        * is large (divide by `tick' and/or arrange to
-                        * use hzto() if hz is large).
-                        */
-                       slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
-                       goto sleep;
-               } else
-                       slp = 0;
+               /*
+                * Rounding down may make us wake up just short
+                * of the target, so we round up.
+                * The formula is ceiling(slp * hz/1000000).
+                * 32-bit arithmetic is enough for hz < 169.
+                * XXX see hzto() for how to avoid overflow if hz
+                * is large (divide by `tick' and/or arrange to
+                * use hzto() if hz is large).
+                */
+               slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
+               goto sleep;
        }
        if (rblen <= 0) {
                int carrier;
 
 sleep:
        }
        if (rblen <= 0) {
                int carrier;
 
 sleep:
+               if (tp->t_state & TS_ZOMBIE) {
+                       splx(s);
+                       return (0);     /* EOF */
+               }
                /*
                 * 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.
                 */
                /*
                 * 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.
                 */
-               carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
-               if (!carrier && tp->t_state&TS_ISOPEN) {
-                       splx(s);
-                       return (0);     /* EOF */
-               }
+               carrier = CAN_DO_IO(tp);
                if (flag & IO_NDELAY) {
                        splx(s);
                        return (EWOULDBLOCK);
                if (flag & IO_NDELAY) {
                        splx(s);
                        return (EWOULDBLOCK);
@@ -1483,7 +1506,7 @@ sleep:
                         */
                        timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp);
                }
                         */
                        timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp);
                }
-               error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+               error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,
                    carrier ? ttyin : ttopen, 0);
                if (slp) {
                        slp = 0;
                    carrier ? ttyin : ttopen, 0);
                if (slp) {
                        slp = 0;
@@ -1611,17 +1634,17 @@ ttycheckoutq(tp, wait)
                oldsig = curproc->p_sig;
        else
                oldsig = 0;
                oldsig = curproc->p_sig;
        else
                oldsig = 0;
-       if (RB_LEN(&tp->t_out) > hiwat + 200)
-               while (RB_LEN(&tp->t_out) > hiwat) {
+       if (RB_LEN(tp->t_out) > hiwat + 200)
+               while (RB_LEN(tp->t_out) > hiwat) {
                        ttstart(tp);
                        if (wait == 0 || (curproc && curproc->p_sig != oldsig)) {
                                splx(s);
                                return (0);
                        }
                        ttstart(tp);
                        if (wait == 0 || (curproc && curproc->p_sig != oldsig)) {
                                splx(s);
                                return (0);
                        }
-                       timeout((timeout_func_t)wakeup, (caddr_t)&tp->t_out,
+                       timeout((timeout_func_t)wakeup, (caddr_t)tp->t_out,
                                hz); /* XXX */
                        tp->t_state |= TS_ASLEEP;
                                hz); /* XXX */
                        tp->t_state |= TS_ASLEEP;
-                       tsleep((caddr_t)&tp->t_out, PZERO - 1, "ttchout", 0);
+                       tsleep((caddr_t)tp->t_out, PZERO - 1, "ttchout", 0);
                }
        splx(s);
        return (1);
                }
        splx(s);
        return (1);
@@ -1647,11 +1670,12 @@ ttwrite(tp, uio, flag)
        error = 0;
 loop:
        s = spltty();
        error = 0;
 loop:
        s = spltty();
-       if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
-               if (tp->t_state&TS_ISOPEN) {
-                       splx(s);
-                       return (EIO);
-               } else if (flag & IO_NDELAY) {
+       if (tp->t_state & TS_ZOMBIE) {
+               splx(s);
+               goto out;
+       }
+       if (!CAN_DO_IO(tp)) {
+               if (flag & IO_NDELAY) {
                        splx(s);
                        error = EWOULDBLOCK;
                        goto out;
                        splx(s);
                        error = EWOULDBLOCK;
                        goto out;
@@ -1659,7 +1683,7 @@ loop:
                        /*
                         * sleep awaiting carrier
                         */
                        /*
                         * sleep awaiting carrier
                         */
-                       error = ttysleep(tp, (caddr_t)&tp->t_raw, 
+                       error = ttysleep(tp, (caddr_t)tp->t_raw, 
                                        TTIPRI | PCATCH,ttopen, 0);
                        splx(s);
                        if (error)
                                        TTIPRI | PCATCH,ttopen, 0);
                        splx(s);
                        if (error)
@@ -1703,7 +1727,7 @@ loop:
                 * to fix this is messy because of all the gotos.
                 */
                s = spltty();
                 * to fix this is messy because of all the gotos.
                 */
                s = spltty();
-               if (RB_LEN(&tp->t_out) > hiwat) {
+               if (RB_LEN(tp->t_out) > hiwat) {
                        splx(s);
                        goto ovhiwat;
                }
                        splx(s);
                        goto ovhiwat;
                }
@@ -1754,7 +1778,7 @@ loop:
                                        cp++, cc--;
                                        s = spltty();
                                        if ((tp->t_lflag&FLUSHO) ||
                                        cp++, cc--;
                                        s = spltty();
                                        if ((tp->t_lflag&FLUSHO) ||
-                                           RB_LEN(&tp->t_out) > hiwat) {
+                                           RB_LEN(tp->t_out) > hiwat) {
                                                splx(s);
                                                goto ovhiwat;
                                        }
                                                splx(s);
                                                goto ovhiwat;
                                        }
@@ -1777,18 +1801,18 @@ loop:
 #else
                        i = ce;
                        s = spltty();
 #else
                        i = ce;
                        s = spltty();
-                       ce = imin(ce, RB_CONTIGPUT(&tp->t_out));
-                       bcopy(cp, tp->t_out.rb_tl, ce);
-                       tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
-                               tp->t_out.rb_tl + ce);
+                       ce = imin(ce, RB_CONTIGPUT(tp->t_out));
+                       bcopy(cp, tp->t_out->rb_tl, ce);
+                       tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+                               tp->t_out->rb_tl + ce);
                        i -= ce;
                        if (i > 0) {
                                int ii;
 
                        i -= ce;
                        if (i > 0) {
                                int ii;
 
-                               ii = imin(i, RB_CONTIGPUT(&tp->t_out));
-                               bcopy(cp + ce, tp->t_out.rb_tl, ii);
-                               tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
-                                       tp->t_out.rb_tl + ii);
+                               ii = imin(i, RB_CONTIGPUT(tp->t_out));
+                               bcopy(cp + ce, tp->t_out->rb_tl, ii);
+                               tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+                                       tp->t_out->rb_tl + ii);
                                i -= ii;
                                ce += ii;
                        }
                                i -= ii;
                                ce += ii;
                        }
@@ -1800,13 +1824,13 @@ loop:
                        if (i > 0) {
                                ttstart(tp);
                                s = spltty();
                        if (i > 0) {
                                ttstart(tp);
                                s = spltty();
-                               if (RB_CONTIGPUT(&tp->t_out) > 0) {
+                               if (RB_CONTIGPUT(tp->t_out) > 0) {
                                        splx(s);
                                        goto loop;      /* synchronous/fast */
                                }
                                /* out of space, wait a bit */
                                tp->t_state |= TS_ASLEEP;
                                        splx(s);
                                        goto loop;      /* synchronous/fast */
                                }
                                /* out of space, wait a bit */
                                tp->t_state |= TS_ASLEEP;
-                               if (error = ttysleep(tp, (caddr_t)&tp->t_out,
+                               if (error = ttysleep(tp, (caddr_t)tp->t_out,
                                            TTOPRI | PCATCH, ttybuf, 0)) {
                                        splx(s);
                                        break;
                                            TTOPRI | PCATCH, ttybuf, 0)) {
                                        splx(s);
                                        break;
@@ -1815,7 +1839,7 @@ loop:
                                goto loop;
                        }
                        s = spltty();
                                goto loop;
                        }
                        s = spltty();
-                       if (tp->t_lflag&FLUSHO || RB_LEN(&tp->t_out) > hiwat) {
+                       if (tp->t_lflag&FLUSHO || RB_LEN(tp->t_out) > hiwat) {
                                splx(s);
                                break;
                        }
                                splx(s);
                                break;
                        }
@@ -1840,7 +1864,7 @@ ovhiwat:
         * This can only occur if FLUSHO is set in t_lflag,
         * or if ttstart/oproc is synchronous (or very fast).
         */
         * This can only occur if FLUSHO is set in t_lflag,
         * or if ttstart/oproc is synchronous (or very fast).
         */
-       if (RB_LEN(&tp->t_out) <= hiwat) {
+       if (RB_LEN(tp->t_out) <= hiwat) {
                splx(s);
                goto loop;
        }
                splx(s);
                goto loop;
        }
@@ -1852,7 +1876,7 @@ ovhiwat:
                return (0);
        }
        tp->t_state |= TS_ASLEEP;
                return (0);
        }
        tp->t_state |= TS_ASLEEP;
-       error = ttysleep(tp, (caddr_t)&tp->t_out, TTOPRI | PCATCH, ttyout, 0);
+       error = ttysleep(tp, (caddr_t)tp->t_out, TTOPRI | PCATCH, ttyout, 0);
        splx(s);
        if (error)
                goto out;
        splx(s);
        if (error)
                goto out;
@@ -1903,7 +1927,7 @@ ttyrub(c, tp)
                case TAB: {
                        int c;
 
                case TAB: {
                        int c;
 
-                       if (tp->t_rocount < RB_LEN(&tp->t_raw)) {
+                       if (tp->t_rocount < RB_LEN(tp->t_raw)) {
                                ttyretype(tp);
                                return;
                        }
                                ttyretype(tp);
                                return;
                        }
@@ -1912,9 +1936,9 @@ ttyrub(c, tp)
                        tp->t_state |= TS_CNTTB;
                        tp->t_lflag |= FLUSHO;
                        tp->t_col = tp->t_rocol;
                        tp->t_state |= TS_CNTTB;
                        tp->t_lflag |= FLUSHO;
                        tp->t_col = tp->t_rocol;
-                       cp = tp->t_raw.rb_hd;
-                       for (c = nextc(&cp, &tp->t_raw); c ;
-                               c = nextc(&cp, &tp->t_raw))
+                       cp = tp->t_raw->rb_hd;
+                       for (c = nextc(&cp, tp->t_raw); c ;
+                               c = nextc(&cp, tp->t_raw))
                                ttyecho(c, tp);
                        tp->t_lflag &= ~FLUSHO;
                        tp->t_state &= ~TS_CNTTB;
                                ttyecho(c, tp);
                        tp->t_lflag &= ~FLUSHO;
                        tp->t_state &= ~TS_CNTTB;
@@ -1978,16 +2002,16 @@ ttyretype(tp)
        (void) ttyoutput('\n', tp);
 
        s = spltty();
        (void) ttyoutput('\n', tp);
 
        s = spltty();
-       cp = tp->t_can.rb_hd;
-       for (c = nextc(&cp, &tp->t_can); c ; c = nextc(&cp, &tp->t_can))
+       cp = tp->t_can->rb_hd;
+       for (c = nextc(&cp, tp->t_can); c ; c = nextc(&cp, tp->t_can))
                ttyecho(c, tp);
                ttyecho(c, tp);
-       cp = tp->t_raw.rb_hd;
-       for (c = nextc(&cp, &tp->t_raw); c ; c = nextc(&cp, &tp->t_raw))
+       cp = tp->t_raw->rb_hd;
+       for (c = nextc(&cp, tp->t_raw); c ; c = nextc(&cp, tp->t_raw))
                ttyecho(c, tp);
        tp->t_state &= ~TS_ERASE;
        splx(s);
 
                ttyecho(c, tp);
        tp->t_state &= ~TS_ERASE;
        splx(s);
 
-       tp->t_rocount = RB_LEN(&tp->t_raw);
+       tp->t_rocount = RB_LEN(tp->t_raw);
        tp->t_rocol = 0;
 }
 
        tp->t_rocol = 0;
 }
 
@@ -2048,7 +2072,7 @@ ttwakeup(tp)
        }
        if (tp->t_state & TS_ASYNC)
                pgsignal(tp->t_pgrp, SIGIO, 1); 
        }
        if (tp->t_state & TS_ASYNC)
                pgsignal(tp->t_pgrp, SIGIO, 1); 
-       wakeup((caddr_t)&tp->t_raw);
+       wakeup((caddr_t)tp->t_raw);
 }
 
 /*
 }
 
 /*
@@ -2098,14 +2122,14 @@ ttyinfo(tp)
 {
        register struct proc *p, *pick;
        struct timeval utime, stime;
 {
        register struct proc *p, *pick;
        struct timeval utime, stime;
-       int tmp;
+       int loadtmp, tmp = 0;
 
        if (ttycheckoutq(tp,0) == 0) 
                return;
 
        /* Print load average. */
 
        if (ttycheckoutq(tp,0) == 0) 
                return;
 
        /* Print load average. */
-       tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
-       ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
+       loadtmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
+       ttyprintf(tp, "load: %d.%02d ", loadtmp / 100, loadtmp % 100);
 
        if (tp->t_session == NULL)
                ttyprintf(tp, "not a controlling terminal\n");
 
        if (tp->t_session == NULL)
                ttyprintf(tp, "not a controlling terminal\n");
@@ -2114,14 +2138,38 @@ ttyinfo(tp)
        else if ((p = tp->t_pgrp->pg_mem) == NULL)
                ttyprintf(tp, "empty foreground process group\n");
        else {
        else if ((p = tp->t_pgrp->pg_mem) == NULL)
                ttyprintf(tp, "empty foreground process group\n");
        else {
+               int kspace;
+               int s;
+               pid_t pid;
+               char wmesg[WMESGLEN+1];
+               char comm[MAXCOMLEN+1];
                /* Pick interesting process. */
                for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
                        if (proc_compare(pick, p))
                                pick = p;
 
                /* Pick interesting process. */
                for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
                        if (proc_compare(pick, p))
                                pick = p;
 
-               ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
+               if( pick == NULL) {
+                       ttyprintf(tp, "process went away\n");
+                       goto finish;
+               }
+
+#define        pgtok(a)        (((a) * NBPG) / 1024)
+
+               if( (pick->p_flag & SLOAD) && (pick->p_vmspace)) 
+                       kspace = pgtok(pick->p_vmspace->vm_pmap.pm_stats.resident_count);
+               else
+                       kspace = 0;
+               strncpy(wmesg, ((pick->p_flag & SLOAD) == 0 ? "swapped":
                    pick->p_stat == SRUN ? "running" :
                    pick->p_stat == SRUN ? "running" :
-                   pick->p_wmesg ? pick->p_wmesg : "iowait");
+                   pick->p_wmesg ? pick->p_wmesg : "iowait"), WMESGLEN);
+               wmesg[WMESGLEN] = 0;
+
+               strncpy(comm, pick->p_comm ? pick->p_comm : "", MAXCOMLEN);
+               comm[MAXCOMLEN] = 0;
+
+               loadtmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
+
+               pid = pick->p_pid;
 
                /*
                 * Lock out clock if process is running; get user/system
 
                /*
                 * Lock out clock if process is running; get user/system
@@ -2134,6 +2182,8 @@ ttyinfo(tp)
                if (curproc == pick)
                        splx(tmp);
 
                if (curproc == pick)
                        splx(tmp);
 
+               ttyprintf(tp, " cmd: %s %d [%s] ", comm, pid, wmesg);
+
                /* Print user time. */
                ttyprintf(tp, "%d.%02du ",
                    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
                /* Print user time. */
                ttyprintf(tp, "%d.%02du ",
                    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
@@ -2142,12 +2192,10 @@ ttyinfo(tp)
                ttyprintf(tp, "%d.%02ds ",
                    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
 
                ttyprintf(tp, "%d.%02ds ",
                    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
 
-#define        pgtok(a)        (((a) * NBPG) / 1024)
                /* Print percentage cpu, resident set size. */
                /* Print percentage cpu, resident set size. */
-               tmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
-               ttyprintf(tp, "%d%% %dk\n",
-                  tmp / 100, pgtok(pick->p_vmspace->vm_pmap.pm_stats.resident_count));
+               ttyprintf(tp, "%d%% %dk\n", loadtmp / 100, kspace);
        }
        }
+finish:
        tp->t_rocount = 0;      /* so pending input will be retyped if BS */
 }
 
        tp->t_rocount = 0;      /* so pending input will be retyped if BS */
 }
 
@@ -2237,7 +2285,7 @@ tputchar(c, tp)
 {
        register s = spltty();
 
 {
        register s = spltty();
 
-       if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
+       if (CAN_DO_IO(tp)) {
                if (c == '\n')
                        (void) ttyoutput('\r', tp);
                (void) ttyoutput(c, tp);
                if (c == '\n')
                        (void) ttyoutput('\r', tp);
                (void) ttyoutput(c, tp);
@@ -2272,3 +2320,57 @@ ttysleep(tp, chan, pri, wmesg, timo)
                return (ERESTART);
        return (0);
 }
                return (ERESTART);
        return (0);
 }
+
+
+/*
+ * Allocate a tty structure and its associated buffers.
+ */
+struct tty *
+ttymalloc(itp)
+       struct tty *itp;
+{
+       struct tty *tp;
+
+#ifndef broken
+       /*
+        * Note that the itp input is not necessary when we can dealloc
+        * the struct tty.
+        */
+       if(itp == NULL) {
+               MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
+               bzero(tp, sizeof *tp);
+       } else {
+               tp = itp;
+       }
+#endif
+       if(tp->t_raw == NULL) {
+               MALLOC(tp->t_raw, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+               bzero(tp->t_raw, sizeof *tp->t_raw);
+       }
+       if(tp->t_can == NULL) {
+               MALLOC(tp->t_can, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+               bzero(tp->t_can, sizeof *tp->t_can);
+       }
+       if(tp->t_out == NULL) {
+               MALLOC(tp->t_out, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+               bzero(tp->t_out, sizeof *tp->t_out);
+       }
+       return(tp);
+}
+
+/*
+ * Free a tty structure and its buffers.
+ */
+void
+ttyfree(tp)
+struct tty *tp;
+{
+       FREE(tp->t_raw, M_TTYS);
+       FREE(tp->t_can, M_TTYS);
+       FREE(tp->t_out, M_TTYS);
+       tp->t_raw = tp->t_can = tp->t_out = NULL;
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+       /* also set tp to NULL when this isn't broken anymore */
+       FREE(tp, M_TTYS);
+#endif
+}