X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/45372428f61e3510eeb7a1306c5e95425eefa20e..668cc26dbe8e6ce075ead3e3cc4590d239277fe0:/usr/src/sys/kern/tty_pty.c diff --git a/usr/src/sys/kern/tty_pty.c b/usr/src/sys/kern/tty_pty.c index a7b5af91aa..f16c43820d 100644 --- a/usr/src/sys/kern/tty_pty.c +++ b/usr/src/sys/kern/tty_pty.c @@ -1,10 +1,12 @@ -# +/* tty_pty.c 4.19 82/03/13 */ + /* * Pseudo-teletype Driver * (Actually two drivers, requiring two entries in 'cdevsw') - * - * Overhauled, and ported to VAX/VMUNIX (V7) Bruce Borden, July 80 */ +#include "pty.h" + +#if NPTY > 0 #include "../h/param.h" #include "../h/systm.h" #include "../h/tty.h" @@ -12,58 +14,64 @@ #include "../h/user.h" #include "../h/conf.h" #include "../h/buf.h" +#include "../h/file.h" +#include "../h/proc.h" +#undef NPTY + +#define NPTY 16 + +#define BUFSIZ 100 /* Chunk size iomoved from user */ -#define NPTY 16 /* Number of pseudo-teletypes */ -#define BUFSIZ 100 /* Chunk size iomoved from user */ -#define ALLDELAYS (NLDELAY|TBDELAY|XTABS|CRDELAY|VTDELAY) /* - * A pseudo-teletype is a special device which is not unlike a pipe. - * It is used to communicate between two processes. However, it allows - * one to simulate a teletype, including mode setting, interrupt, and - * multiple end of files (all not possible on a pipe). There are - * really two drivers here. One is the device which looks like a TTY - * and can be thought of as the slave device, and hence its routines - * are prefixed with 'pts' (PTY Slave). The other driver can be - * thought of as the controlling device, and its routines are prefixed - * by 'ptc' (PTY Controller). To type on the simulated keyboard of the - * PTY, one does a 'write' to the controlling device. To get the - * simulated printout from the PTY, one does a 'read' on the controlling - * device. Normally, the controlling device is called 'ptyx' and the - * slave device is called 'ttyx' (to make programs like 'who' happy). + * pts == /dev/tty[pP]? + * ptc == /dev/ptp[pP]? */ +struct tty pt_tty[NPTY]; +struct pt_ioctl { + int pt_flags; + int pt_gensym; + struct proc *pt_selr, *pt_selw; + int pt_send; +} pt_ioctl[NPTY]; -struct tty pt_tty[NPTY]; /* TTY headers for PTYs */ +#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 /*ARGSUSED*/ ptsopen(dev, flag) -dev_t dev; -{ /* Open for PTY Slave */ + dev_t dev; +{ register struct tty *tp; - if(minor(dev) >= NPTY) { + if (minor(dev) >= NPTY) { u.u_error = ENXIO; return; } tp = &pt_tty[minor(dev)]; - if((tp->t_state & ISOPEN) == 0) { - ttychars(tp); /* Set up default chars */ - tp->t_flags = 0; /* No features (nor raw mode) */ - } else if(tp->t_state&XCLUDE && u.u_uid != 0) { + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); /* Set up default chars */ + tp->t_flags = 0; /* No features (nor raw mode) */ + } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { u.u_error = EBUSY; return; } - if(tp->t_oproc) /* Ctrlr still around. */ - tp->t_state |= CARR_ON; - while((tp->t_state & CARR_ON) == 0) { - tp->t_state |= WOPEN; + if (tp->t_oproc) /* Ctrlr still around. */ + tp->t_state |= TS_CARR_ON; + while ((tp->t_state & TS_CARR_ON) == 0) { + tp->t_state |= TS_WOPEN; sleep((caddr_t)&tp->t_rawq, TTIPRI); } (*linesw[tp->t_line].l_open)(dev, tp); } ptsclose(dev) -dev_t dev; -{ /* Close slave part of PTY */ + dev_t dev; +{ register struct tty *tp; tp = &pt_tty[minor(dev)]; @@ -71,157 +79,356 @@ dev_t dev; } ptsread(dev) -dev_t dev; -{ /* Read from PTY, i.e. from data written by controlling device */ - register struct tty *tp; + dev_t dev; +{ + 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) { - (*linesw[tp->t_line].l_read)(tp); - /* Wakeup other half if sleeping */ - wakeup((caddr_t)&tp->t_rawq.c_cf); +again: + if (pti->pt_flags & PF_REMOTE) { + while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { + if (u.u_signal[SIGTTIN] == SIG_IGN || + u.u_signal[SIGTTIN] == SIG_HOLD || + /* + (u.u_procp->p_flag&SDETACH) || + */ + u.u_procp->p_flag&SVFORK) + return; + gsignal(u.u_procp->p_pgrp, SIGTTIN); + sleep((caddr_t)&lbolt, TTIPRI); + } + if (tp->t_rawq.c_cc == 0) { + if (tp->t_state & TS_NBIO) { + u.u_error = EWOULDBLOCK; + return; + } + sleep((caddr_t)&tp->t_rawq, TTIPRI); + goto again; + } + while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0) + ; + if (tp->t_rawq.c_cc == 1) + (void) getc(&tp->t_rawq); + if (tp->t_rawq.c_cc) + return; + } else + if (tp->t_oproc) + (*linesw[tp->t_line].l_read)(tp); + wakeup((caddr_t)&tp->t_rawq.c_cf); + if (pti->pt_selw) { + selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); + pti->pt_selw = 0; + pti->pt_flags &= ~PF_WCOLL; } } +/* + * Write to pseudo-tty. + * Wakeups of controlling tty will happen + * indirectly, when tty driver calls ptsstart. + */ ptswrite(dev) -dev_t dev; -{ /* Write on PTY, i.e. to be read from - controlling device */ + dev_t dev; +{ register struct tty *tp; tp = &pt_tty[minor(dev)]; - /* Wait for controlling device to be opened */ - if(tp->t_oproc) + if (tp->t_oproc) (*linesw[tp->t_line].l_write)(tp); } +/* + * Start output on pseudo-tty. + * Wake up process selecting or sleeping for input from controlling tty. + */ ptsstart(tp) -struct tty *tp; -{ /* Called by 'ttstart' to output a character. - Merely wakes up controlling half, which - does actual work */ - if(tp->t_state & TTSTOP) + struct tty *tp; +{ + register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + + if (tp->t_state & TS_TTSTOP) return; + if (pti->pt_flags & PF_STOPPED) { + pti->pt_flags &= ~PF_STOPPED; + pti->pt_send = TIOCPKT_START; + } + ptcwakeup(tp); +} + +ptcwakeup(tp) + struct tty *tp; +{ + struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + + if (pti->pt_selr) { + selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); + pti->pt_selr = 0; + pti->pt_flags &= ~PF_RCOLL; + } wakeup((caddr_t)&tp->t_outq.c_cf); } /*ARGSUSED*/ ptcopen(dev, flag) -dev_t dev; -{ /* Open for PTY Controller */ + dev_t dev; + int flag; +{ register struct tty *tp; + struct pt_ioctl *pti; - if(minor(dev) >= NPTY) { + if (minor(dev) >= NPTY) { u.u_error = ENXIO; return; } tp = &pt_tty[minor(dev)]; - if(tp->t_oproc) { + if (tp->t_oproc) { u.u_error = EIO; return; } - tp->t_oproc = ptsstart; /* Set address of start routine */ - tp->t_iproc = 0; - if(tp->t_state & WOPEN) + tp->t_oproc = ptsstart; + if (tp->t_state & TS_WOPEN) wakeup((caddr_t)&tp->t_rawq); - tp->t_state |= CARR_ON; + tp->t_state |= TS_CARR_ON; + pti = &pt_ioctl[minor(dev)]; + pti->pt_flags = 0; + pti->pt_send = 0; } ptcclose(dev) -dev_t dev; -{ /* Close controlling part of PTY */ + dev_t dev; +{ register struct tty *tp; tp = &pt_tty[minor(dev)]; - if(tp->t_state & ISOPEN) + if (tp->t_state & TS_ISOPEN) gsignal(tp->t_pgrp, SIGHUP); - tp->t_state &= ~CARR_ON; /* Virtual carrier is gone */ - flushtty(tp); /* Clean things up */ - tp->t_oproc = 0; /* Mark as closed */ + tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ + flushtty(tp, FREAD|FWRITE); + tp->t_oproc = 0; /* mark closed */ } ptcread(dev) -dev_t dev; -{ /* Read from PTY's output buffer */ + dev_t dev; +{ register struct tty *tp; + struct pt_ioctl *pti; tp = &pt_tty[minor(dev)]; - if((tp->t_state&(CARR_ON|ISOPEN)) == 0) + if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) return; - while(tp->t_outq.c_cc == 0 || /* Wait for something to arrive */ - (tp->t_state&TTSTOP)) /* (Woken by ptsstart) */ + pti = &pt_ioctl[minor(dev)]; + if (pti->pt_flags & PF_PKT) { + if (pti->pt_send) { + (void) passc(pti->pt_send); + pti->pt_send = 0; + return; + } + (void) passc(0); + } + while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { + if (pti->pt_flags&PF_NBIO) { + u.u_error = EWOULDBLOCK; + return; + } sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); - while(tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0); - if(tp->t_outq.c_cc <= TTLOWAT(tp) && (tp->t_state&ASLEEP)) { - tp->t_state &= ~ASLEEP; - if(tp->t_chan) - mcstart(tp->t_chan, (caddr_t)&tp->t_outq); - else + } + while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) + ; + 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; + } + } +} + +ptsstop(tp, flush) + register struct tty *tp; + int flush; +{ + struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + + /* note: FLUSHREAD and FLUSHWRITE already ok */ + if (flush == 0) { + flush = TIOCPKT_STOP; + pti->pt_flags |= PF_STOPPED; + } else { + pti->pt_flags &= ~PF_STOPPED; } + pti->pt_send |= flush; + ptcwakeup(tp); +} + +ptcselect(dev, rw) + dev_t dev; + int rw; +{ + register struct tty *tp = &pt_tty[minor(dev)]; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + struct proc *p; + int s; + + if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) + return (1); + s = spl5(); + switch (rw) { + + case FREAD: + if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { + splx(s); + return (1); + } + if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) + pti->pt_flags |= PF_RCOLL; + else + pti->pt_selr = u.u_procp; + break; + + case FWRITE: + if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { + splx(s); + return (1); + } + if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) + pti->pt_flags |= PF_WCOLL; + else + pti->pt_selw = u.u_procp; + break; + } + splx(s); + return (0); } ptcwrite(dev) -dev_t dev; -{ /* Stuff characters into PTY's input buffer */ + dev_t dev; +{ register struct tty *tp; register char *cp, *ce; register int cc; char locbuf[BUFSIZ]; + int cnt = 0; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; tp = &pt_tty[minor(dev)]; - if((tp->t_state&(CARR_ON|ISOPEN)) == 0) + if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) return; - while(u.u_count) { + do { cc = MIN(u.u_count, BUFSIZ); cp = locbuf; iomove(cp, (unsigned)cc, B_WRITE); - if(u.u_error) + if (u.u_error) break; ce = cp + cc; - while(cp < ce) { - while(tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { +again: + if (pti->pt_flags & PF_REMOTE) { + if (tp->t_rawq.c_cc) { + if (pti->pt_flags & PF_NBIO) { + u.u_count += ce - cp; + u.u_error = EWOULDBLOCK; + return; + } + sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); + goto again; + } + (void) b_to_q(cp, cc, &tp->t_rawq); + (void) putc(0, &tp->t_rawq); + wakeup((caddr_t)&tp->t_rawq); + return; + } + while (cp < ce) { + while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { wakeup((caddr_t)&tp->t_rawq); + if (tp->t_state & TS_NBIO) { + u.u_count += ce - cp; + if (cnt == 0) + u.u_error = EWOULDBLOCK; + return; + } /* Better than just flushing it! */ /* Wait for something to be read */ sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); + goto again; } - ttyinput(*cp++, tp); + (*linesw[tp->t_line].l_rint)(*cp++, tp); + cnt++; } - } + } while (u.u_count); } -/* Note: Both slave and controlling device have the same routine for */ -/* 'ioctl' (but note check for controller - 4/12/78:mob)*/ /*ARGSUSED*/ ptyioctl(dev, cmd, addr, flag) -caddr_t addr; -dev_t dev; -{ /* Read and write status bits */ - register struct tty *tp; - register int tbd; -#ifdef BLAND - register int nld; -#endif + caddr_t addr; + dev_t dev; +{ + register struct tty *tp = &pt_tty[minor(dev)]; + register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; - tp = &pt_tty[minor(dev)]; - /* if controller stty then must flush to prevent a hang */ - if(cdevsw[major(dev)].d_open == ptcopen && cmd == TIOCSETP) - while(getc(&tp->t_outq) >= 0); - if(ttioctl(tp, cmd, addr, dev)) { - if(cmd == TIOCSETP || cmd == TIOCSETN) { -#ifdef BLAND - nld = tp->t_flags & NLDELAY; -#endif - tbd = tp->t_flags & TBDELAY; - tp->t_flags &= ~ALLDELAYS; - if(tbd == TBDELAY) /* Wants tab expansion */ - tp->t_flags |= tbd; -#ifdef BLAND - if(nld == NLDELAY) /* Allow ANN ARBOR mode. */ - tp->t_flags |= nld; -#endif + /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ + if (cdevsw[major(dev)].d_open == ptcopen) { + if (cmd == TIOCPKT) { + int packet; + if (copyin((caddr_t)addr, (caddr_t)&packet, sizeof (packet))) { + u.u_error = EFAULT; + return; + } + if (packet) + pti->pt_flags |= PF_PKT; + else + pti->pt_flags &= ~PF_PKT; + return; } - } else + if (cmd == TIOCREMOTE) { + int remote; + if (copyin((caddr_t)addr, (caddr_t)&remote, sizeof (remote))) { + u.u_error = EFAULT; + return; + } + if (remote) + pti->pt_flags |= PF_REMOTE; + else + pti->pt_flags &= ~PF_REMOTE; + flushtty(tp, FREAD|FWRITE); + return; + } + if (cmd == FIONBIO) { + int nbio; + if (copyin((caddr_t)addr, (caddr_t)&nbio, sizeof (nbio))) { + u.u_error = EFAULT; + return; + } + if (nbio) + pti->pt_flags |= PF_NBIO; + else + pti->pt_flags &= ~PF_NBIO; + return; + } + if (cmd == TIOCSETP) + while (getc(&tp->t_outq) >= 0); + } + if (ttioctl(tp, cmd, addr, dev) == 0) u.u_error = ENOTTY; + { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && + tp->t_un.t_chr.t_startc == ('q'&037)); + if (pti->pt_flags & PF_NOSTOP) { + if (stop) { + pti->pt_send &= TIOCPKT_NOSTOP; + pti->pt_send |= TIOCPKT_DOSTOP; + pti->pt_flags &= ~PF_NOSTOP; + ptcwakeup(tp); + } + } else { + if (stop == 0) { + pti->pt_send &= ~TIOCPKT_DOSTOP; + pti->pt_send |= TIOCPKT_NOSTOP; + pti->pt_flags |= PF_NOSTOP; + ptcwakeup(tp); + } + } + } } +#endif