X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/f21c8fb875600215ab51a3785a9b15e7647001f9..6a79e262ebff67defcc88ba77f6eea5894a6b695:/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 09c7bd676b..c6eaca1a13 100644 --- a/usr/src/sys/kern/tty_pty.c +++ b/usr/src/sys/kern/tty_pty.c @@ -1,4 +1,10 @@ -/* tty_pty.c 4.27 82/10/17 */ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + * + * @(#)tty_pty.c 7.3.1.1 (Berkeley) %G% + */ /* * Pseudo-teletype Driver @@ -7,55 +13,70 @@ #include "pty.h" #if NPTY > 0 -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/tty.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/conf.h" -#include "../h/file.h" -#include "../h/proc.h" -#include "../h/uio.h" -#include "../h/kernel.h" +#include "param.h" +#include "systm.h" +#include "ioctl.h" +#include "tty.h" +#include "dir.h" +#include "user.h" +#include "conf.h" +#include "file.h" +#include "proc.h" +#include "uio.h" +#include "kernel.h" +#include "tsleep.h" #if NPTY == 1 -#undef NPTY +#undef NPTY #define NPTY 32 /* crude XXX */ #endif -#define BUFSIZ 100 /* Chunk size iomoved from user */ +#define BUFSIZ 100 /* Chunk size iomoved to/from user */ /* - * pts == /dev/tty[pP]? - * ptc == /dev/ptp[pP]? + * pts == /dev/tty[pqrs]? + * ptc == /dev/pty[pqrs]? */ struct tty pt_tty[NPTY]; struct pt_ioctl { int pt_flags; - int pt_gensym; struct proc *pt_selr, *pt_selw; - int pt_send; + u_char pt_send; + u_char pt_ucntl; + struct clist pt_ioc; } pt_ioctl[NPTY]; - -#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 +int npty = NPTY; /* for pstat -t */ + +#define PF_RCOLL 0x0001 +#define PF_WCOLL 0x0002 +#define PF_NBIO 0x0004 +#define PF_PKT 0x0008 /* packet mode */ +#define PF_STOPPED 0x0010 /* user told stopped */ +#define PF_REMOTE 0x0020 /* remote and flow controlled input */ +#define PF_NOSTOP 0x0040 +#define PF_UCNTL 0x0080 /* user control mode */ +#define PF_TIOC 0x0100 /* transparent control mode */ +#define PF_LIOC 0x0200 /* transparent control locked */ +#define PF_WIOC 0x0400 /* waiting for PF_LIOC to clear */ +#define PF_BLOCK 0x0800 /* block writes to slave */ +#define PF_OWAIT 0x1000 /* waiting for PF_BLOCK to clear */ /*ARGSUSED*/ ptsopen(dev, flag) dev_t dev; { register struct tty *tp; + int error; +#ifdef lint + npty = npty; +#endif if (minor(dev) >= NPTY) return (ENXIO); tp = &pt_tty[minor(dev)]; if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); /* Set up default chars */ + tp->t_ispeed = tp->t_ospeed = EXTB; tp->t_flags = 0; /* No features (nor raw mode) */ } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) return (EBUSY); @@ -65,7 +86,9 @@ ptsopen(dev, flag) tp->t_state |= TS_WOPEN; sleep((caddr_t)&tp->t_rawq, TTIPRI); } - return ((*linesw[tp->t_line].l_open)(dev, tp)); + error = (*linesw[tp->t_line].l_open)(dev, tp); + ptcwakeup(tp, FREAD|FWRITE); + return (error); } ptsclose(dev) @@ -76,6 +99,8 @@ ptsclose(dev) tp = &pt_tty[minor(dev)]; (*linesw[tp->t_line].l_close)(tp); ttyclose(tp); + ptcwakeup(tp, FREAD|FWRITE); + return (0); } ptsread(dev, uio) @@ -89,40 +114,32 @@ ptsread(dev, uio) 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) || - */ + if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || + (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || u.u_procp->p_flag&SVFORK) return (EIO); gsignal(u.u_procp->p_pgrp, SIGTTIN); sleep((caddr_t)&lbolt, TTIPRI); } - if (tp->t_rawq.c_cc == 0) { + if (tp->t_canq.c_cc == 0) { if (tp->t_state & TS_NBIO) return (EWOULDBLOCK); - sleep((caddr_t)&tp->t_rawq, TTIPRI); + sleep((caddr_t)&tp->t_canq, TTIPRI); goto again; } - while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) - if (ureadc(getc(&tp->t_rawq), uio) < 0) { + while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) + if (ureadc(getc(&tp->t_canq), uio) < 0) { error = EFAULT; break; } - if (tp->t_rawq.c_cc == 1) - (void) getc(&tp->t_rawq); - if (tp->t_rawq.c_cc) + if (tp->t_canq.c_cc == 1) + (void) getc(&tp->t_canq); + if (tp->t_canq.c_cc) return (error); } else if (tp->t_oproc) error = (*linesw[tp->t_line].l_read)(tp, uio); - wakeup((caddr_t)&tp->t_rawq.c_cf); - if (pti->pt_selw) { - selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); - pti->pt_selw = 0; - pti->pt_flags &= ~PF_WCOLL; - } + ptcwakeup(tp, FWRITE); return (error); } @@ -135,11 +152,17 @@ ptswrite(dev, uio) dev_t dev; struct uio *uio; { - register struct tty *tp; + register struct tty *tp = &pt_tty[minor(dev)]; + register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; - tp = &pt_tty[minor(dev)]; if (tp->t_oproc == 0) return (EIO); + + while (pti->pt_flags & PF_BLOCK) { + pti->pt_flags |= PF_OWAIT; + sleep((caddr_t)pti + 1, TTOPRI); + } + return ((*linesw[tp->t_line].l_write)(tp, uio)); } @@ -158,20 +181,30 @@ ptsstart(tp) pti->pt_flags &= ~PF_STOPPED; pti->pt_send = TIOCPKT_START; } - ptcwakeup(tp); + ptcwakeup(tp, FREAD); } -ptcwakeup(tp) +ptcwakeup(tp, flag) 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; + if (flag & FREAD) { + 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); + } + if (flag & FWRITE) { + if (pti->pt_selw) { + selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); + pti->pt_selw = 0; + pti->pt_flags &= ~PF_WCOLL; + } + wakeup((caddr_t)&tp->t_rawq.c_cf); } - wakeup((caddr_t)&tp->t_outq.c_cf); } /*ARGSUSED*/ @@ -188,12 +221,11 @@ ptcopen(dev, flag) if (tp->t_oproc) return (EIO); tp->t_oproc = ptsstart; - if (tp->t_state & TS_WOPEN) - wakeup((caddr_t)&tp->t_rawq); - tp->t_state |= TS_CARR_ON; + (void)(*linesw[tp->t_line].l_modem)(tp, 1); pti = &pt_ioctl[minor(dev)]; pti->pt_flags = 0; pti->pt_send = 0; + pti->pt_ucntl = 0; return (0); } @@ -203,11 +235,10 @@ ptcclose(dev) register struct tty *tp; tp = &pt_tty[minor(dev)]; - if (tp->t_state & TS_ISOPEN) - gsignal(tp->t_pgrp, SIGHUP); - tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ - flushtty(tp, FREAD|FWRITE); + (void)(*linesw[tp->t_line].l_modem)(tp, 0); + tp->t_state &= ~TS_CARR_ON; tp->t_oproc = 0; /* mark closed */ + return (0); } ptcread(dev, uio) @@ -215,61 +246,102 @@ ptcread(dev, uio) struct uio *uio; { register struct tty *tp = &pt_tty[minor(dev)]; - struct pt_ioctl *pti; - int error = 0; + struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; + char buf[BUFSIZ]; + int error = 0, cc; - if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) - return; - pti = &pt_ioctl[minor(dev)]; - if (pti->pt_flags & PF_PKT) { - if (pti->pt_send) { - error = ureadc(pti->pt_send, uio); - if (error) + /* + * We want to block until the slave + * is open, and there's something to read; + * but if we lost the slave or we're NBIO, + * then return the appropriate error instead. + */ + for (;;) { + if (tp->t_state&TS_ISOPEN) { + if (pti->pt_flags&PF_PKT && pti->pt_send) { + error = ureadc((int)pti->pt_send, uio); + if (error) + return (error); + pti->pt_send = 0; + return (0); + } + if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { + error = ureadc((int)pti->pt_ucntl, uio); + if (error) + return (error); + pti->pt_ucntl = 0; + return (0); + } + if (pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc) { + if (uio->uio_resid < pti->pt_ioc.c_cc + 1) + return (E2BIG); + error = ureadc(TIOCPKT_TIOC, uio); + while (error == 0 && pti->pt_ioc.c_cc > 0) { + cc = q_to_b(&pti->pt_ioc, buf, + MIN(pti->pt_ioc.c_cc, BUFSIZ)); + if (cc <= 0) /* impossible? */ + break; + error = uiomove(buf, cc, UIO_READ, uio); + } return (error); - pti->pt_send = 0; - return (0); + } + if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) + break; } - error = ureadc(0, uio); - } - while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { + if ((tp->t_state&TS_CARR_ON) == 0) + return (EIO); if (pti->pt_flags&PF_NBIO) return (EWOULDBLOCK); sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); } - while (tp->t_outq.c_cc && uio->uio_resid > 0) - if (ureadc(getc(&tp->t_outq), uio) < 0) { - error = EFAULT; + if (pti->pt_flags & (PF_PKT|PF_UCNTL|PF_TIOC)) + error = ureadc(0, uio); + while (uio->uio_resid > 0 && error == 0) { + cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); + if (cc <= 0) break; - } - 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; - } + error = uiomove(buf, cc, UIO_READ, uio); } + if (tp->t_outq.c_cc <= TTLOWAT(tp) && !(pti->pt_flags & PF_BLOCK)) + ptswake(tp); return (error); } +ptswake(tp) + register struct tty *tp; +{ + if (tp->t_state&TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } +} + ptsstop(tp, flush) register struct tty *tp; int flush; { struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; + int flag; /* note: FLUSHREAD and FLUSHWRITE already ok */ if (flush == 0) { flush = TIOCPKT_STOP; pti->pt_flags |= PF_STOPPED; - } else { + } else pti->pt_flags &= ~PF_STOPPED; - } pti->pt_send |= flush; - ptcwakeup(tp); + /* change of perspective */ + flag = 0; + if (flush & FREAD) + flag |= FWRITE; + if (flush & FWRITE) + flag |= FREAD; + ptcwakeup(tp, flag); } ptcselect(dev, rw) @@ -281,110 +353,154 @@ ptcselect(dev, rw) struct proc *p; int s; - if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) + if ((tp->t_state&TS_CARR_ON) == 0) return (1); - s = spl5(); switch (rw) { case FREAD: - if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { + /* + * Need to block timeouts (ttrstart). + */ + s = spltty(); + if ((tp->t_state&TS_ISOPEN) && + tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { splx(s); return (1); } + splx(s); + /* FALLTHROUGH */ + + case 0: /* exceptional */ + if ((tp->t_state&TS_ISOPEN) && + (pti->pt_flags&PF_PKT && pti->pt_send || + pti->pt_flags&PF_TIOC && pti->pt_ioc.c_cc || + pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) + return (1); if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) pti->pt_flags |= PF_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 (tp->t_state&TS_ISOPEN) { + if (pti->pt_flags & PF_REMOTE) { + if (tp->t_canq.c_cc == 0) + return (1); + } else { + if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) + return (1); + if (tp->t_canq.c_cc == 0 && + (tp->t_flags & (RAW|CBREAK)) == 0) + 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, uio) dev_t dev; - struct uio *uio; + register struct uio *uio; { register struct tty *tp = &pt_tty[minor(dev)]; - register char *cp, *ce; - register int cc; + register struct iovec *iov; + register char *cp; + register int cc = 0; char locbuf[BUFSIZ]; int cnt = 0; struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; int error = 0; - if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) - return (EIO); - do { - register struct iovec *iov; - - if (uio->uio_iovcnt == 0) - break; - iov = uio->uio_iov; - if (iov->iov_len == 0) { - uio->uio_iovcnt--; - uio->uio_iov++; - if (uio->uio_iovcnt < 0) - panic("ptcwrite"); - continue; - } - cc = MIN(iov->iov_len, BUFSIZ); - cp = locbuf; - error = uiomove(cp, cc, UIO_WRITE, uio); - if (error) - break; - ce = cp + cc; again: - if (pti->pt_flags & PF_REMOTE) { - if (tp->t_rawq.c_cc) { - if (pti->pt_flags & PF_NBIO) { - iov->iov_base -= ce - cp; - iov->iov_len += ce - cp; - uio->uio_resid += ce - cp; - uio->uio_offset -= ce - cp; - return (EWOULDBLOCK); - } - sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); - goto again; + if ((tp->t_state&TS_ISOPEN) == 0) + goto block; + if (pti->pt_flags & PF_REMOTE) { + if (tp->t_canq.c_cc) + goto block; + while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iovcnt--; + uio->uio_iov++; + continue; } - (void) b_to_q(cp, cc, &tp->t_rawq); - (void) putc(0, &tp->t_rawq); - wakeup((caddr_t)&tp->t_rawq); - return (0); + if (cc == 0) { + cc = MIN(iov->iov_len, BUFSIZ); + cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); + cp = locbuf; + error = uiomove(cp, cc, UIO_WRITE, uio); + if (error) + return (error); + /* check again for safety */ + if ((tp->t_state&TS_ISOPEN) == 0) + return (EIO); + } + if (cc) + (void) b_to_q(cp, cc, &tp->t_canq); + cc = 0; + } + (void) putc(0, &tp->t_canq); + ttwakeup(tp); + wakeup((caddr_t)&tp->t_canq); + return (0); + } + while (uio->uio_iovcnt > 0) { + iov = uio->uio_iov; + if (cc == 0) { + if (iov->iov_len == 0) { + uio->uio_iovcnt--; + uio->uio_iov++; + continue; + } + cc = MIN(iov->iov_len, BUFSIZ); + cp = locbuf; + error = uiomove(cp, cc, UIO_WRITE, uio); + if (error) + return (error); + /* check again for safety */ + if ((tp->t_state&TS_ISOPEN) == 0) + return (EIO); } - while (cp < ce) { - while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { + while (cc > 0) { + if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && + (tp->t_canq.c_cc > 0 || + tp->t_flags & (RAW|CBREAK))) { wakeup((caddr_t)&tp->t_rawq); - if (tp->t_state & TS_NBIO) { - iov->iov_base -= ce - cp; - iov->iov_len += ce - cp; - uio->uio_resid += ce - cp; - uio->uio_offset -= ce - cp; - if (cnt == 0) - return (EWOULDBLOCK); - return (0); - } - /* Better than just flushing it! */ - /* Wait for something to be read */ - sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); - goto again; + goto block; } (*linesw[tp->t_line].l_rint)(*cp++, tp); cnt++; + cc--; } - } while (uio->uio_resid); - return (error); + cc = 0; + } + return (0); +block: + /* + * Come here to wait for slave to open, for space + * in outq, or space in rawq. + */ + if ((tp->t_state&TS_CARR_ON) == 0) + return (EIO); + if (pti->pt_flags & PF_NBIO) { + iov->iov_base -= cc; + iov->iov_len += cc; + uio->uio_resid += cc; + uio->uio_offset -= cc; + if (cnt == 0) + return (EWOULDBLOCK); + return (0); + } + sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); + goto again; } /*ARGSUSED*/ @@ -394,25 +510,71 @@ ptyioctl(dev, cmd, data, flag) { register struct tty *tp = &pt_tty[minor(dev)]; register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; - int error; + int stop, error; + extern ttyinput(); - /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ - if (cdevsw[major(dev)].d_open == ptcopen) + /* + * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. + * ttywflush(tp) will hang if there are characters in the outq. + */ + if (cdevsw[major(dev)].d_open == ptcopen) { + if ((cmd & 0xffff) == (TIOCIOANS(0) & 0xffff)) { + if (!(pti->pt_flags & PF_LIOC) || pti->pt_ioc.c_cc) + return (EINVAL); + (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc); + wakeup((caddr_t)&pti->pt_ioc); + return (0); + } switch (cmd) { case TIOCPKT: - if (*(int *)data) + if (*(int *)data) { + if (pti->pt_flags & PF_UCNTL) + return (EINVAL); pti->pt_flags |= PF_PKT; - else + } else pti->pt_flags &= ~PF_PKT; return (0); + case TIOCUCNTL: + if (*(int *)data) { + if (pti->pt_flags & PF_PKT) + return (EINVAL); + pti->pt_flags |= PF_UCNTL; + } else + pti->pt_flags &= ~PF_UCNTL; + return (0); + + case TIOCTIOC: + if (*(int *)data) { + if (pti->pt_flags & PF_UCNTL) + return (EINVAL); + pti->pt_flags |= PF_TIOC; + } else { + pti->pt_flags &= ~(PF_TIOC|PF_LIOC|PF_WIOC); + while (pti->pt_ioc.c_cc) + (void) getc(&pti->pt_ioc); + wakeup((caddr_t)&pti->pt_ioc); + } + return (0); + + case TIOCBLK: + if (*(int *)data) + pti->pt_flags |= PF_BLOCK; + else { + if (pti->pt_flags & PF_OWAIT) + wakeup((caddr_t)pti + 1); + pti->pt_flags &= ~(PF_BLOCK|PF_OWAIT); + ptswake(tp); + } + return (0); + case TIOCREMOTE: if (*(int *)data) pti->pt_flags |= PF_REMOTE; else pti->pt_flags &= ~PF_REMOTE; - flushtty(tp, FREAD|FWRITE); + ttyflush(tp, FREAD|FWRITE); return (0); case FIONBIO: @@ -422,32 +584,130 @@ ptyioctl(dev, cmd, data, flag) pti->pt_flags &= ~PF_NBIO; return (0); + case FIONREAD: + *(int *)data = tp->t_outq.c_cc; + return (0); + case TIOCSETP: + case TIOCSETN: + case TIOCSETD: while (getc(&tp->t_outq) >= 0) ; break; } - error = ttioctl(tp, cmd, data, dev); - if (error < 0) + } else if (pti->pt_flags & PF_TIOC) { + while (pti->pt_flags & PF_LIOC) { + pti->pt_flags |= PF_WIOC; + switch (tsleep((caddr_t)&pti->pt_flags,TTIPRI-1,5*hz)) { + case TS_OK: + continue; + case TS_SIG: + case TS_TIME: + return (EBUSY); + } + } + pti->pt_flags |= PF_LIOC | PF_BLOCK; + while (pti->pt_ioc.c_cc) + (void) getc(&pti->pt_ioc); + (void) b_to_q(&cmd, sizeof cmd, &pti->pt_ioc); + if (cmd & IOC_IN) + (void) b_to_q(data, IOCPARM_LEN(cmd), &pti->pt_ioc); + ptcwakeup(tp, FREAD); + switch (tsleep((caddr_t)&pti->pt_ioc, TTIPRI-1, 5*hz)) { + case TS_SIG: + case TS_TIME: + while (pti->pt_ioc.c_cc) + (void) getc(&pti->pt_ioc); + if (pti->pt_flags & PF_WIOC) + wakeup((caddr_t)&pti->pt_flags); + if (pti->pt_flags & PF_OWAIT) + wakeup((caddr_t)pti + 1); + pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); + ptswake(tp); + return (EBUSY); + case TS_OK: + break; + } + if (pti->pt_ioc.c_cc == 0) { + if (pti->pt_flags & PF_WIOC) + wakeup((caddr_t)&pti->pt_flags); + if (pti->pt_flags & PF_OWAIT) + wakeup((caddr_t)pti + 1); + pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); + ptswake(tp); + goto doioctl; + } + if (q_to_b(&pti->pt_ioc, &error, sizeof error) != sizeof error) + error = EINVAL; + if (error == 0 && cmd & IOC_OUT) { + if (IOCPARM_LEN(cmd) != pti->pt_ioc.c_cc) + error = EINVAL; + else + (void) q_to_b(&pti->pt_ioc, data, + pti->pt_ioc.c_cc); + } + while (pti->pt_ioc.c_cc) + (void) getc(&pti->pt_ioc); + if (pti->pt_flags & PF_WIOC) + wakeup((caddr_t)&pti->pt_flags); + if (pti->pt_flags & PF_OWAIT) + wakeup((caddr_t)pti + 1); + pti->pt_flags &= ~(PF_LIOC|PF_WIOC|PF_BLOCK|PF_OWAIT); + ptswake(tp); + return (error); + } + + doioctl: + error = ttioctl(tp, cmd, data, flag); + /* + * Since we use the tty queues internally, + * pty's can't be switched to disciplines which overwrite + * the queues. We can't tell anything about the discipline + * from here... + * + * Nb: this is not really good enough, the line disc open routine + * may have done anything at all, no guarantees that close + * will fix it. This also has the effect of losing the + * previous discipline, which an error on a TIOCSETD shouldn't + * do... Sometime it should be done via an explicit check + * for TIOCSETD, then check to see what linesw[new_number].l_rint + * really is. + */ + if (linesw[tp->t_line].l_rint != ttyinput) { + (*linesw[tp->t_line].l_close)(tp); + tp->t_line = 0; + (void)(*linesw[tp->t_line].l_open)(dev, tp); + error = ENOTTY; + } + + if (error < 0) { + if (pti->pt_flags & PF_UCNTL && + (cmd & ~0xff) == UIOCCMD(0)) { + if (cmd & 0xff) { + pti->pt_ucntl = (u_char)cmd; + ptcwakeup(tp, FREAD); + } + return (0); + } error = ENOTTY; - { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && - tp->t_un.t_chr.t_startc == ('q'&037)); + } + stop = (tp->t_flags & RAW) == 0 && + tp->t_stopc == CTRL('s') && tp->t_startc == CTRL('q'); if (pti->pt_flags & PF_NOSTOP) { if (stop) { - pti->pt_send &= TIOCPKT_NOSTOP; + pti->pt_send &= ~TIOCPKT_NOSTOP; pti->pt_send |= TIOCPKT_DOSTOP; pti->pt_flags &= ~PF_NOSTOP; - ptcwakeup(tp); + ptcwakeup(tp, FREAD); } } else { - if (stop == 0) { + if (!stop) { pti->pt_send &= ~TIOCPKT_DOSTOP; pti->pt_send |= TIOCPKT_NOSTOP; pti->pt_flags |= PF_NOSTOP; - ptcwakeup(tp); + ptcwakeup(tp, FREAD); } } - } return (error); } #endif