pty.c revision 130585
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 291541Srgrimes * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 301541Srgrimes */ 311541Srgrimes 321541Srgrimes#include <sys/cdefs.h> 331541Srgrimes__FBSDID("$FreeBSD: head/sys/kern/tty_pty.c 130585 2004-06-16 09:47:26Z phk $"); 3412731Sbde 351541Srgrimes/* 361541Srgrimes * Pseudo-teletype Driver 371541Srgrimes * (Actually two drivers, requiring two entries in 'cdevsw') 381541Srgrimes */ 391541Srgrimes#include "opt_compat.h" 401541Srgrimes#include "opt_tty.h" 411541Srgrimes#include <sys/param.h> 421541Srgrimes#include <sys/systm.h> 431541Srgrimes#include <sys/lock.h> 441541Srgrimes#include <sys/mutex.h> 451541Srgrimes#include <sys/sx.h> 461541Srgrimes#if defined(COMPAT_43) 471541Srgrimes#include <sys/ioctl_compat.h> 481541Srgrimes#endif 491541Srgrimes#include <sys/proc.h> 501541Srgrimes#include <sys/tty.h> 511541Srgrimes#include <sys/conf.h> 521541Srgrimes#include <sys/fcntl.h> 533308Sphk#include <sys/poll.h> 541541Srgrimes#include <sys/kernel.h> 5512517Sjulian#include <sys/vnode.h> 5612517Sjulian#include <sys/signalvar.h> 5712517Sjulian#include <sys/malloc.h> 5812517Sjulian 5911789Sbdestatic MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); 6011789Sbde 6111789Sbdestatic void ptsstart(struct tty *tp); 6211789Sbdestatic void ptsstop(struct tty *tp, int rw); 6312675Sjulianstatic void ptcwakeup(struct tty *tp, int flag); 6412675Sjulianstatic struct cdev *ptyinit(struct cdev *cdev); 6512675Sjulian 6612675Sjulianstatic d_open_t ptsopen; 6712675Sjulianstatic d_close_t ptsclose; 6812675Sjulianstatic d_read_t ptsread; 6912731Sbdestatic d_write_t ptswrite; 7012675Sjulianstatic d_ioctl_t ptyioctl; 7112675Sjulianstatic d_open_t ptcopen; 7212675Sjulianstatic d_close_t ptcclose; 7312675Sjulianstatic d_read_t ptcread; 7412675Sjulianstatic d_write_t ptcwrite; 7512675Sjulianstatic d_poll_t ptcpoll; 7612675Sjulian 7712675Sjulian#define CDEV_MAJOR_S 5 7812675Sjulianstatic struct cdevsw pts_cdevsw = { 7912678Sphk .d_version = D_VERSION, 8012675Sjulian .d_open = ptsopen, 8112675Sjulian .d_close = ptsclose, 8212675Sjulian .d_read = ptsread, 8312675Sjulian .d_write = ptswrite, 8412678Sphk .d_ioctl = ptyioctl, 8512675Sjulian .d_name = "pts", 8612675Sjulian .d_maj = CDEV_MAJOR_S, 8712675Sjulian .d_flags = D_TTY | D_NEEDGIANT, 8812675Sjulian}; 8912675Sjulian 901541Srgrimes#define CDEV_MAJOR_C 6 911541Srgrimesstatic struct cdevsw ptc_cdevsw = { 921541Srgrimes .d_version = D_VERSION, 931541Srgrimes .d_open = ptcopen, 941541Srgrimes .d_close = ptcclose, 951541Srgrimes .d_read = ptcread, 961541Srgrimes .d_write = ptcwrite, 971541Srgrimes .d_ioctl = ptyioctl, 9812564Sjulian .d_poll = ptcpoll, 9912564Sjulian .d_name = "ptc", 1001541Srgrimes .d_maj = CDEV_MAJOR_C, 1011541Srgrimes .d_flags = D_TTY | D_NEEDGIANT, 1021541Srgrimes}; 1031541Srgrimes 1041541Srgrimes#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 1051541Srgrimes 1061541Srgrimesstruct ptsc { 1071541Srgrimes int pt_flags; 1081541Srgrimes struct selinfo pt_selr, pt_selw; 1091541Srgrimes u_char pt_send; 1101541Srgrimes u_char pt_ucntl; 1111541Srgrimes struct tty *pt_tty; 1121541Srgrimes struct cdev *devs, *devc; 1131541Srgrimes struct prison *pt_prison; 1141541Srgrimes}; 1151541Srgrimes 1161541Srgrimes#define PF_PKT 0x08 /* packet mode */ 1171541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 1181541Srgrimes#define PF_REMOTE 0x20 /* remote and flow controlled input */ 1191541Srgrimes#define PF_NOSTOP 0x40 1201541Srgrimes#define PF_UCNTL 0x80 /* user control mode */ 1211541Srgrimes 1221541Srgrimes#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf) 1231541Srgrimes#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) 1241541Srgrimes#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) 1251541Srgrimes 1261541Srgrimesstatic char *names = "pqrsPQRS"; 1271541Srgrimes/* 1281541Srgrimes * This function creates and initializes a pts/ptc pair 1291541Srgrimes * 1301541Srgrimes * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 1311541Srgrimes * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 1321541Srgrimes * 1331541Srgrimes * XXX: define and add mapping of upper minor bits to allow more 1341541Srgrimes * than 256 ptys. 1351541Srgrimes */ 1361541Srgrimesstatic struct cdev * 1371541Srgrimesptyinit(struct cdev *devc) 1381541Srgrimes{ 1391541Srgrimes struct cdev *devs; 1401541Srgrimes struct ptsc *pt; 1411541Srgrimes int n; 1421541Srgrimes 1431541Srgrimes n = minor(devc); 14412675Sjulian /* For now we only map the lower 8 bits of the minor */ 1451541Srgrimes if (n & ~0xff) 1461541Srgrimes return (NODEV); 1471541Srgrimes 1481541Srgrimes devc->si_flags &= ~SI_CHEAPCLONE; 1491541Srgrimes 1501541Srgrimes pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); 1511541Srgrimes pt->devs = devs = make_dev(&pts_cdevsw, n, 1521541Srgrimes UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); 1531541Srgrimes pt->devc = devc; 1541541Srgrimes 1551541Srgrimes pt->pt_tty = ttymalloc(pt->pt_tty); 1561541Srgrimes devs->si_drv1 = devc->si_drv1 = pt; 1571541Srgrimes devs->si_tty = devc->si_tty = pt->pt_tty; 1581541Srgrimes pt->pt_tty->t_dev = devs; 1591541Srgrimes return (devc); 1601541Srgrimes} 1611541Srgrimes 1621541Srgrimes/*ARGSUSED*/ 1631541Srgrimesstatic int 1641541Srgrimesptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) 1651541Srgrimes{ 1661541Srgrimes struct tty *tp; 1679824Sbde int error; 1681541Srgrimes struct ptsc *pt; 1691541Srgrimes 1701541Srgrimes if (!dev->si_drv1) 1719639Sbde return(ENXIO); 1729624Sbde pt = dev->si_drv1; 1733308Sphk tp = dev->si_tty; 1741541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 1751541Srgrimes ttychars(tp); /* Set up default chars */ 1761541Srgrimes tp->t_iflag = TTYDEF_IFLAG; 1777724Sache tp->t_oflag = TTYDEF_OFLAG; 1787724Sache tp->t_lflag = TTYDEF_LFLAG; 1791541Srgrimes tp->t_cflag = TTYDEF_CFLAG; 1801541Srgrimes tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 1811541Srgrimes } else if (tp->t_state & TS_XCLUDE && suser(td)) 18212675Sjulian return (EBUSY); 1831541Srgrimes else if (pt->pt_prison != td->td_ucred->cr_prison) 1841541Srgrimes return (EBUSY); 1851541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 1861541Srgrimes (void)ttyld_modem(tp, 1); 1871541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1881541Srgrimes if (flag&FNONBLOCK) 1891541Srgrimes break; 1901541Srgrimes error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1911541Srgrimes "ptsopn", 0); 1921541Srgrimes if (error) 1937730Sache return (error); 1947724Sache } 1951541Srgrimes error = ttyld_open(tp, dev); 1961541Srgrimes if (error == 0) 1971541Srgrimes ptcwakeup(tp, FREAD|FWRITE); 19812675Sjulian return (error); 1991541Srgrimes} 2001541Srgrimes 2011541Srgrimesstatic int 2021541Srgrimesptsclose(struct cdev *dev, int flag, int mode, struct thread *td) 2031541Srgrimes{ 2041541Srgrimes struct tty *tp; 2051541Srgrimes int err; 2061541Srgrimes 2071541Srgrimes tp = dev->si_tty; 2081541Srgrimes err = ttyld_close(tp, flag); 2091541Srgrimes (void) ttyclose(tp); 2101541Srgrimes return (err); 2111541Srgrimes} 2121541Srgrimes 2131541Srgrimesstatic int 2141541Srgrimesptsread(struct cdev *dev, struct uio *uio, int flag) 2151541Srgrimes{ 2161541Srgrimes struct thread *td = curthread; 2171541Srgrimes struct proc *p = td->td_proc; 2189624Sbde struct tty *tp = dev->si_tty; 2199624Sbde struct ptsc *pt = dev->si_drv1; 2203308Sphk struct pgrp *pg; 2211541Srgrimes int error = 0; 2221541Srgrimes 2231541Srgrimesagain: 2241541Srgrimes if (pt->pt_flags & PF_REMOTE) { 2251541Srgrimes while (isbackground(p, tp)) { 2269639Sbde sx_slock(&proctree_lock); 2279624Sbde PROC_LOCK(p); 2283308Sphk if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) || 2291541Srgrimes SIGISMEMBER(td->td_sigmask, SIGTTIN) || 2301541Srgrimes p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT) { 2311541Srgrimes PROC_UNLOCK(p); 2321541Srgrimes sx_sunlock(&proctree_lock); 2331541Srgrimes return (EIO); 2341541Srgrimes } 2351541Srgrimes pg = p->p_pgrp; 2361541Srgrimes PROC_UNLOCK(p); 2371541Srgrimes PGRP_LOCK(pg); 2381541Srgrimes sx_sunlock(&proctree_lock); 2391541Srgrimes pgsignal(pg, SIGTTIN, 1); 2401541Srgrimes PGRP_UNLOCK(pg); 2411541Srgrimes error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg", 2421541Srgrimes 0); 2431541Srgrimes if (error) 2441541Srgrimes return (error); 2451541Srgrimes } 2461541Srgrimes if (tp->t_canq.c_cc == 0) { 2471541Srgrimes if (flag & IO_NDELAY) 2481541Srgrimes return (EWOULDBLOCK); 2491541Srgrimes error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, 2501541Srgrimes "ptsin", 0); 2511541Srgrimes if (error) 2521541Srgrimes return (error); 25312675Sjulian goto again; 2541541Srgrimes } 2551541Srgrimes while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 2561541Srgrimes if (ureadc(getc(&tp->t_canq), uio) < 0) { 2571541Srgrimes error = EFAULT; 2581541Srgrimes break; 2591541Srgrimes } 2601541Srgrimes if (tp->t_canq.c_cc == 1) 2611541Srgrimes (void) getc(&tp->t_canq); 2621541Srgrimes if (tp->t_canq.c_cc) 2631541Srgrimes return (error); 2641541Srgrimes } else 2651541Srgrimes if (tp->t_oproc) 2661541Srgrimes error = ttyld_read(tp, uio, flag); 2671541Srgrimes ptcwakeup(tp, FWRITE); 2681541Srgrimes return (error); 2691541Srgrimes} 2701541Srgrimes 2711541Srgrimes/* 2721541Srgrimes * Write to pseudo-tty. 2731541Srgrimes * Wakeups of controlling tty will happen 2741541Srgrimes * indirectly, when tty driver calls ptsstart. 2751541Srgrimes */ 2761541Srgrimesstatic int 2771541Srgrimesptswrite(struct cdev *dev, struct uio *uio, int flag) 2781541Srgrimes{ 2791541Srgrimes struct tty *tp; 2801541Srgrimes 2811541Srgrimes tp = dev->si_tty; 2821541Srgrimes if (tp->t_oproc == 0) 2831541Srgrimes return (EIO); 2841541Srgrimes return (ttyld_write(tp, uio, flag)); 2851541Srgrimes} 2861549Srgrimes 2871541Srgrimes/* 2881541Srgrimes * Start output on pseudo-tty. 2891541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2901541Srgrimes */ 2911541Srgrimesstatic void 2921541Srgrimesptsstart(struct tty *tp) 2931541Srgrimes{ 2941541Srgrimes struct ptsc *pt = tp->t_dev->si_drv1; 2959639Sbde 2961541Srgrimes if (tp->t_state & TS_TTSTOP) 2971541Srgrimes return; 2981541Srgrimes if (pt->pt_flags & PF_STOPPED) { 2999639Sbde pt->pt_flags &= ~PF_STOPPED; 3001541Srgrimes pt->pt_send = TIOCPKT_START; 3011541Srgrimes } 3021541Srgrimes ptcwakeup(tp, FREAD); 30312675Sjulian} 3041541Srgrimes 3051541Srgrimesstatic void 3061541Srgrimesptcwakeup(struct tty *tp, int flag) 3071541Srgrimes{ 3081541Srgrimes struct ptsc *pt = tp->t_dev->si_drv1; 3091541Srgrimes 3101541Srgrimes if (flag & FREAD) { 3111541Srgrimes selwakeuppri(&pt->pt_selr, TTIPRI); 3121541Srgrimes wakeup(TSA_PTC_READ(tp)); 3131541Srgrimes } 3141541Srgrimes if (flag & FWRITE) { 3151541Srgrimes selwakeuppri(&pt->pt_selw, TTOPRI); 3161541Srgrimes wakeup(TSA_PTC_WRITE(tp)); 3171541Srgrimes } 3181541Srgrimes} 3191541Srgrimes 3201541Srgrimesstatic int 3211541Srgrimesptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) 3221541Srgrimes{ 3231541Srgrimes struct tty *tp; 3241541Srgrimes struct ptsc *pt; 3251541Srgrimes 3261541Srgrimes if (!dev->si_drv1) 3271541Srgrimes ptyinit(dev); 3281541Srgrimes if (!dev->si_drv1) 3291541Srgrimes return(ENXIO); 33012675Sjulian tp = dev->si_tty; 33110624Sbde if (tp->t_oproc) 3321541Srgrimes return (EIO); 33310624Sbde tp->t_timeout = -1; 33410624Sbde tp->t_oproc = ptsstart; 33510624Sbde tp->t_stop = ptsstop; 3361541Srgrimes (void)ttyld_modem(tp, 1); 3371541Srgrimes tp->t_lflag &= ~EXTPROC; 3381541Srgrimes pt = dev->si_drv1; 3391541Srgrimes pt->pt_prison = td->td_ucred->cr_prison; 3401541Srgrimes pt->pt_flags = 0; 3419824Sbde pt->pt_send = 0; 3429824Sbde pt->pt_ucntl = 0; 3439824Sbde return (0); 3449824Sbde} 3459824Sbde 3469824Sbdestatic int 3479824Sbdeptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) 3489824Sbde{ 3499824Sbde struct tty *tp; 3509850Sbde 3519850Sbde tp = dev->si_tty; 3529850Sbde (void)ttyld_modem(tp, 0); 3539850Sbde 3549850Sbde /* 3559824Sbde * XXX MDMBUF makes no sense for ptys but would inhibit the above 3561541Srgrimes * l_modem(). CLOCAL makes sense but isn't supported. Special 3571541Srgrimes * l_modem()s that ignore carrier drop make no sense for ptys but 3581541Srgrimes * may be in use because other parts of the line discipline make 3591541Srgrimes * sense for ptys. Recover by doing everything that a normal 36012675Sjulian * ttymodem() would have done except for sending a SIGHUP. 3611541Srgrimes */ 3621541Srgrimes if (tp->t_state & TS_ISOPEN) { 3631541Srgrimes tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 3641541Srgrimes tp->t_state |= TS_ZOMBIE; 3651541Srgrimes ttyflush(tp, FREAD | FWRITE); 3661541Srgrimes } 3671541Srgrimes 3681541Srgrimes tp->t_oproc = 0; /* mark closed */ 3691541Srgrimes return (0); 3701541Srgrimes} 3711541Srgrimes 3721541Srgrimesstatic int 3731541Srgrimesptcread(struct cdev *dev, struct uio *uio, int flag) 3741541Srgrimes{ 3751541Srgrimes struct tty *tp = dev->si_tty; 3761541Srgrimes struct ptsc *pt = dev->si_drv1; 3771541Srgrimes char buf[BUFSIZ]; 3781541Srgrimes int error = 0, cc; 3791541Srgrimes 3801541Srgrimes /* 3811541Srgrimes * We want to block until the slave 3821541Srgrimes * is open, and there's something to read; 3831541Srgrimes * but if we lost the slave or we're NBIO, 3841541Srgrimes * then return the appropriate error instead. 3851541Srgrimes */ 3862807Sbde for (;;) { 3872807Sbde if (tp->t_state&TS_ISOPEN) { 3881541Srgrimes if (pt->pt_flags&PF_PKT && pt->pt_send) { 3891541Srgrimes error = ureadc((int)pt->pt_send, uio); 3901541Srgrimes if (error) 3911541Srgrimes return (error); 3921541Srgrimes if (pt->pt_send & TIOCPKT_IOCTL) { 3931541Srgrimes cc = min(uio->uio_resid, 3941541Srgrimes sizeof(tp->t_termios)); 3951541Srgrimes uiomove(&tp->t_termios, cc, uio); 3961541Srgrimes } 3971541Srgrimes pt->pt_send = 0; 3981541Srgrimes return (0); 3991541Srgrimes } 4001541Srgrimes if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { 4011541Srgrimes error = ureadc((int)pt->pt_ucntl, uio); 4029824Sbde if (error) 4031541Srgrimes return (error); 4041541Srgrimes pt->pt_ucntl = 0; 4051541Srgrimes return (0); 4069639Sbde } 4073308Sphk if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 4081541Srgrimes break; 4091541Srgrimes } 4101541Srgrimes if ((tp->t_state & TS_CONNECTED) == 0) 4111541Srgrimes return (0); /* EOF */ 4121541Srgrimes if (flag & IO_NDELAY) 4131541Srgrimes return (EWOULDBLOCK); 4141541Srgrimes error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 4151541Srgrimes if (error) 4161541Srgrimes return (error); 4171541Srgrimes } 4189626Sbde if (pt->pt_flags & (PF_PKT|PF_UCNTL)) 4191541Srgrimes error = ureadc(0, uio); 4201541Srgrimes while (uio->uio_resid > 0 && error == 0) { 4211541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 42212675Sjulian if (cc <= 0) 4231541Srgrimes break; 4241541Srgrimes error = uiomove(buf, cc, uio); 4251541Srgrimes } 4261541Srgrimes ttwwakeup(tp); 4271541Srgrimes return (error); 4281541Srgrimes} 4291541Srgrimes 4301541Srgrimesstatic void 4311541Srgrimesptsstop(struct tty *tp, int flush) 4321541Srgrimes{ 4331541Srgrimes struct ptsc *pt = tp->t_dev->si_drv1; 4341541Srgrimes int flag; 4351541Srgrimes 4361541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 4371541Srgrimes if (flush == 0) { 4381541Srgrimes flush = TIOCPKT_STOP; 4391541Srgrimes pt->pt_flags |= PF_STOPPED; 4401541Srgrimes } else 4411541Srgrimes pt->pt_flags &= ~PF_STOPPED; 4421541Srgrimes pt->pt_send |= flush; 4431541Srgrimes /* change of perspective */ 4441541Srgrimes flag = 0; 4451541Srgrimes if (flush & FREAD) 44612675Sjulian flag |= FWRITE; 4471541Srgrimes if (flush & FWRITE) 4481541Srgrimes flag |= FREAD; 4491541Srgrimes ptcwakeup(tp, flag); 4501541Srgrimes} 4511541Srgrimes 4521541Srgrimesstatic int 4531541Srgrimesptcpoll(struct cdev *dev, int events, struct thread *td) 4541541Srgrimes{ 4551541Srgrimes struct tty *tp = dev->si_tty; 4569824Sbde struct ptsc *pt = dev->si_drv1; 4571541Srgrimes int revents = 0; 4581541Srgrimes int s; 4591541Srgrimes 4601541Srgrimes if ((tp->t_state & TS_CONNECTED) == 0) 4611541Srgrimes return (events & 4621541Srgrimes (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); 4631541Srgrimes 4641541Srgrimes /* 4651541Srgrimes * Need to block timeouts (ttrstart). 4661541Srgrimes */ 4671541Srgrimes s = spltty(); 4681541Srgrimes 4691541Srgrimes if (events & (POLLIN | POLLRDNORM)) 4701541Srgrimes if ((tp->t_state & TS_ISOPEN) && 4711541Srgrimes ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || 4721541Srgrimes ((pt->pt_flags & PF_PKT) && pt->pt_send) || 4731541Srgrimes ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) 4741541Srgrimes revents |= events & (POLLIN | POLLRDNORM); 4753308Sphk 4763308Sphk if (events & (POLLOUT | POLLWRNORM)) 4771541Srgrimes if (tp->t_state & TS_ISOPEN && 4781541Srgrimes ((pt->pt_flags & PF_REMOTE) ? 4791541Srgrimes (tp->t_canq.c_cc == 0) : 4801541Srgrimes ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || 4811541Srgrimes (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) 4821541Srgrimes revents |= events & (POLLOUT | POLLWRNORM); 4831541Srgrimes 4841541Srgrimes if (events & POLLHUP) 4851541Srgrimes if ((tp->t_state & TS_CARR_ON) == 0) 4861541Srgrimes revents |= POLLHUP; 4871541Srgrimes 4881541Srgrimes if (revents == 0) { 4891541Srgrimes if (events & (POLLIN | POLLRDNORM)) 4901541Srgrimes selrecord(td, &pt->pt_selr); 4911541Srgrimes 4921541Srgrimes if (events & (POLLOUT | POLLWRNORM)) 4931541Srgrimes selrecord(td, &pt->pt_selw); 4941541Srgrimes } 4951541Srgrimes splx(s); 4961541Srgrimes 4971541Srgrimes return (revents); 4981541Srgrimes} 4991541Srgrimes 5001541Srgrimesstatic int 50112675Sjulianptcwrite(struct cdev *dev, struct uio *uio, int flag) 5021541Srgrimes{ 5031541Srgrimes struct tty *tp = dev->si_tty; 5041541Srgrimes u_char *cp = 0; 5051541Srgrimes int cc = 0; 5061541Srgrimes u_char locbuf[BUFSIZ]; 5071541Srgrimes int cnt = 0; 5081549Srgrimes struct ptsc *pt = dev->si_drv1; 5091541Srgrimes int error = 0; 5101541Srgrimes 5111541Srgrimesagain: 5121541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 5131541Srgrimes goto block; 5141541Srgrimes if (pt->pt_flags & PF_REMOTE) { 5151541Srgrimes if (tp->t_canq.c_cc) 5161541Srgrimes goto block; 5171541Srgrimes while ((uio->uio_resid > 0 || cc > 0) && 5181541Srgrimes tp->t_canq.c_cc < TTYHOG - 1) { 5191541Srgrimes if (cc == 0) { 5201541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 52111789Sbde cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); 52211789Sbde cp = locbuf; 5231541Srgrimes error = uiomove(cp, cc, uio); 5241541Srgrimes if (error) 5251541Srgrimes return (error); 5261541Srgrimes /* check again for safety */ 5271541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 5281541Srgrimes /* adjust as usual */ 5291541Srgrimes uio->uio_resid += cc; 5301541Srgrimes return (EIO); 53111789Sbde } 53211789Sbde } 53311789Sbde if (cc > 0) { 5341541Srgrimes cc = b_to_q((char *)cp, cc, &tp->t_canq); 53511789Sbde /* 5361541Srgrimes * XXX we don't guarantee that the canq size 5371541Srgrimes * is >= TTYHOG, so the above b_to_q() may 53811789Sbde * leave some bytes uncopied. However, space 5391541Srgrimes * is guaranteed for the null terminator if 54011789Sbde * we don't fail here since (TTYHOG - 1) is 54111789Sbde * not a multiple of CBSIZE. 5421541Srgrimes */ 5431541Srgrimes if (cc > 0) 5449639Sbde break; 5451541Srgrimes } 5461541Srgrimes } 54711789Sbde /* adjust for data copied in but not written */ 5481541Srgrimes uio->uio_resid += cc; 5491541Srgrimes (void) putc(0, &tp->t_canq); 5501541Srgrimes ttwakeup(tp); 5511541Srgrimes wakeup(TSA_PTS_READ(tp)); 5521541Srgrimes return (0); 5531541Srgrimes } 5541541Srgrimes while (uio->uio_resid > 0 || cc > 0) { 55511789Sbde if (cc == 0) { 55611789Sbde cc = min(uio->uio_resid, BUFSIZ); 55711789Sbde cp = locbuf; 5581541Srgrimes error = uiomove(cp, cc, uio); 55911789Sbde if (error) 5601541Srgrimes return (error); 5611541Srgrimes /* check again for safety */ 5621541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 5631541Srgrimes /* adjust for data copied in but not written */ 5649824Sbde uio->uio_resid += cc; 5651541Srgrimes return (EIO); 5661541Srgrimes } 5671541Srgrimes } 5681541Srgrimes while (cc > 0) { 5691541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 5701541Srgrimes (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 5711541Srgrimes wakeup(TSA_HUP_OR_INPUT(tp)); 5721541Srgrimes goto block; 5731541Srgrimes } 5741541Srgrimes ttyld_rint(tp, *cp++); 5751541Srgrimes cnt++; 5761541Srgrimes cc--; 5771541Srgrimes } 5781541Srgrimes cc = 0; 57911789Sbde } 58011789Sbde return (0); 58111789Sbdeblock: 5821541Srgrimes /* 58311789Sbde * Come here to wait for slave to open, for space 5841541Srgrimes * in outq, or space in rawq, or an empty canq. 5851541Srgrimes */ 5861541Srgrimes if ((tp->t_state & TS_CONNECTED) == 0) { 5871541Srgrimes /* adjust for data copied in but not written */ 5881541Srgrimes uio->uio_resid += cc; 5891541Srgrimes return (EIO); 5901541Srgrimes } 5919639Sbde if (flag & IO_NDELAY) { 5923308Sphk /* adjust for data copied in but not written */ 5931541Srgrimes uio->uio_resid += cc; 5941541Srgrimes if (cnt == 0) 5951541Srgrimes return (EWOULDBLOCK); 5961541Srgrimes return (0); 5971541Srgrimes } 5981541Srgrimes error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 5991541Srgrimes if (error) { 60012675Sjulian /* adjust for data copied in but not written */ 6016712Spst uio->uio_resid += cc; 6026712Spst return (error); 6036712Spst } 6046712Spst goto again; 6056712Spst} 6066712Spst 6076712Spst/*ARGSUSED*/ 6086712Spststatic int 6096712Spstptyioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 6101541Srgrimes{ 61112675Sjulian struct tty *tp = dev->si_tty; 6121541Srgrimes struct ptsc *pt = dev->si_drv1; 6131541Srgrimes u_char *cc = tp->t_cc; 6141541Srgrimes int stop, error; 6151541Srgrimes 6161541Srgrimes if (devsw(dev)->d_open == ptcopen) { 6171541Srgrimes switch (cmd) { 6181541Srgrimes 6191541Srgrimes case TIOCGPGRP: 6201541Srgrimes /* 6211541Srgrimes * We avoid calling ttioctl on the controller since, 6221541Srgrimes * in that case, tp must be the controlling terminal. 6231541Srgrimes */ 6241541Srgrimes *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 6251541Srgrimes return (0); 6261541Srgrimes 6271541Srgrimes case TIOCPKT: 6281541Srgrimes if (*(int *)data) { 6291541Srgrimes if (pt->pt_flags & PF_UCNTL) 6301541Srgrimes return (EINVAL); 6311541Srgrimes pt->pt_flags |= PF_PKT; 6321541Srgrimes } else 6331541Srgrimes pt->pt_flags &= ~PF_PKT; 6341541Srgrimes return (0); 6351541Srgrimes 6361541Srgrimes case TIOCUCNTL: 6371541Srgrimes if (*(int *)data) { 6381541Srgrimes if (pt->pt_flags & PF_PKT) 6391541Srgrimes return (EINVAL); 6401541Srgrimes pt->pt_flags |= PF_UCNTL; 6411541Srgrimes } else 6421541Srgrimes pt->pt_flags &= ~PF_UCNTL; 6431541Srgrimes return (0); 6441541Srgrimes 6451541Srgrimes case TIOCREMOTE: 6461541Srgrimes if (*(int *)data) 6471541Srgrimes pt->pt_flags |= PF_REMOTE; 6481541Srgrimes else 6491541Srgrimes pt->pt_flags &= ~PF_REMOTE; 6501541Srgrimes ttyflush(tp, FREAD|FWRITE); 6511541Srgrimes return (0); 6521541Srgrimes } 6531541Srgrimes 6541541Srgrimes /* 6551541Srgrimes * The rest of the ioctls shouldn't be called until 6561541Srgrimes * the slave is open. 6571541Srgrimes */ 6581541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) 6591541Srgrimes return (EAGAIN); 6601541Srgrimes 6611541Srgrimes switch (cmd) { 6621541Srgrimes#ifdef COMPAT_43 6631541Srgrimes case TIOCSETP: 6641541Srgrimes case TIOCSETN: 6651541Srgrimes#endif 6661541Srgrimes case TIOCSETD: 6671541Srgrimes case TIOCSETA: 6681541Srgrimes case TIOCSETAW: 6691541Srgrimes case TIOCSETAF: 6701541Srgrimes /* 6711541Srgrimes * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 6721541Srgrimes * ttywflush(tp) will hang if there are characters in 6731541Srgrimes * the outq. 6741541Srgrimes */ 6751541Srgrimes ndflush(&tp->t_outq, tp->t_outq.c_cc); 6761541Srgrimes break; 6771541Srgrimes 6781541Srgrimes case TIOCSIG: 6791541Srgrimes if (*(unsigned int *)data >= NSIG || 6801541Srgrimes *(unsigned int *)data == 0) 6811541Srgrimes return(EINVAL); 6821541Srgrimes if ((tp->t_lflag&NOFLSH) == 0) 6831541Srgrimes ttyflush(tp, FREAD|FWRITE); 6841541Srgrimes if (tp->t_pgrp != NULL) { 6851541Srgrimes PGRP_LOCK(tp->t_pgrp); 6861541Srgrimes pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 6871541Srgrimes PGRP_UNLOCK(tp->t_pgrp); 6888876Srgrimes } 6891541Srgrimes if ((*(unsigned int *)data == SIGINFO) && 6901541Srgrimes ((tp->t_lflag&NOKERNINFO) == 0)) 6911541Srgrimes ttyinfo(tp); 6921541Srgrimes return(0); 6931541Srgrimes } 6949858Sache } 6951541Srgrimes if (cmd == TIOCEXT) { 6961541Srgrimes /* 6971541Srgrimes * When the EXTPROC bit is being toggled, we need 6981541Srgrimes * to send an TIOCPKT_IOCTL if the packet driver 6991541Srgrimes * is turned on. 7001541Srgrimes */ 7011541Srgrimes if (*(int *)data) { 7021541Srgrimes if (pt->pt_flags & PF_PKT) { 7031541Srgrimes pt->pt_send |= TIOCPKT_IOCTL; 7041541Srgrimes ptcwakeup(tp, FREAD); 7051541Srgrimes } 7061541Srgrimes tp->t_lflag |= EXTPROC; 7071541Srgrimes } else { 7081541Srgrimes if ((tp->t_lflag & EXTPROC) && 7091541Srgrimes (pt->pt_flags & PF_PKT)) { 7101541Srgrimes pt->pt_send |= TIOCPKT_IOCTL; 7111541Srgrimes ptcwakeup(tp, FREAD); 7121541Srgrimes } 7131541Srgrimes tp->t_lflag &= ~EXTPROC; 7141541Srgrimes } 7151541Srgrimes return(0); 7161541Srgrimes } 7171541Srgrimes error = ttyioctl(dev, cmd, data, flag, td); 7181541Srgrimes if (error == ENOTTY) { 7191541Srgrimes if (pt->pt_flags & PF_UCNTL && 7201541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 7211541Srgrimes if (cmd & 0xff) { 7221541Srgrimes pt->pt_ucntl = (u_char)cmd; 7231541Srgrimes ptcwakeup(tp, FREAD); 7241541Srgrimes } 7251541Srgrimes return (0); 7261541Srgrimes } 7271541Srgrimes error = ENOTTY; 7281541Srgrimes } 7291541Srgrimes /* 7301541Srgrimes * If external processing and packet mode send ioctl packet. 7311541Srgrimes */ 7321541Srgrimes if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) { 7331541Srgrimes switch(cmd) { 7341541Srgrimes case TIOCSETA: 7351541Srgrimes case TIOCSETAW: 7361541Srgrimes case TIOCSETAF: 7371541Srgrimes#ifdef COMPAT_43 7381541Srgrimes case TIOCSETP: 7391541Srgrimes case TIOCSETN: 7401541Srgrimes#endif 7411541Srgrimes#if defined(COMPAT_43) 7421541Srgrimes case TIOCSETC: 7431541Srgrimes case TIOCSLTC: 7441541Srgrimes case TIOCLBIS: 7451541Srgrimes case TIOCLBIC: 7461541Srgrimes case TIOCLSET: 7471541Srgrimes#endif 7488876Srgrimes pt->pt_send |= TIOCPKT_IOCTL; 7491541Srgrimes ptcwakeup(tp, FREAD); 7501541Srgrimes break; 7511541Srgrimes default: 7521541Srgrimes break; 7531541Srgrimes } 7541541Srgrimes } 7551541Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 7561541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 7571541Srgrimes if (pt->pt_flags & PF_NOSTOP) { 7581541Srgrimes if (stop) { 7591541Srgrimes pt->pt_send &= ~TIOCPKT_NOSTOP; 7601541Srgrimes pt->pt_send |= TIOCPKT_DOSTOP; 7611541Srgrimes pt->pt_flags &= ~PF_NOSTOP; 7621541Srgrimes ptcwakeup(tp, FREAD); 7631541Srgrimes } 7641541Srgrimes } else { 7651541Srgrimes if (!stop) { 7661541Srgrimes pt->pt_send &= ~TIOCPKT_DOSTOP; 76712517Sjulian pt->pt_send |= TIOCPKT_NOSTOP; 76812517Sjulian pt->pt_flags |= PF_NOSTOP; 76912675Sjulian ptcwakeup(tp, FREAD); 77012675Sjulian } 77112675Sjulian } 77212675Sjulian return (error); 77312675Sjulian} 77412675Sjulian 77512675Sjulianstatic void 77612517Sjulianpty_clone(void *arg, char *name, int namelen, struct cdev **dev) 77712675Sjulian{ 77812675Sjulian int u; 77912517Sjulian 78012517Sjulian if (*dev != NODEV) 78112567Sjulian return; 78212675Sjulian if (bcmp(name, "pty", 3) != 0) 78312517Sjulian return; 78412517Sjulian if (name[5] != '\0') 78512517Sjulian return; 78612517Sjulian switch (name[3]) { 78712675Sjulian case 'p': u = 0; break; 78812675Sjulian case 'q': u = 32; break; 78912675Sjulian case 'r': u = 64; break; 79012675Sjulian case 's': u = 96; break; 79112517Sjulian case 'P': u = 128; break; 79212517Sjulian case 'Q': u = 160; break; 79312517Sjulian case 'R': u = 192; break; 79412517Sjulian case 'S': u = 224; break; 79512517Sjulian default: return; 79612517Sjulian } 79712517Sjulian if (name[4] >= '0' && name[4] <= '9') 79812521Sjulian u += name[4] - '0'; 79912675Sjulian else if (name[4] >= 'a' && name[4] <= 'v') 80012517Sjulian u += name[4] - 'a' + 10; 80112564Sjulian else 80212564Sjulian return; 80312675Sjulian *dev = make_dev(&ptc_cdevsw, u, 80412675Sjulian UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); 80512675Sjulian (*dev)->si_flags |= SI_CHEAPCLONE; 80612675Sjulian return; 80712675Sjulian} 80812675Sjulian 80912675Sjulianstatic void 81012675Sjulianptc_drvinit(void *unused) 81112521Sjulian{ 81212521Sjulian 81312517Sjulian EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 81412517Sjulian} 81512517Sjulian 81612517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) 81712517Sjulian