pty.c revision 147982
1139804Simp/*- 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 * 2914511Shsu * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 301541Srgrimes */ 311541Srgrimes 32116182Sobrien#include <sys/cdefs.h> 33116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/tty_pty.c 147982 2005-07-14 10:22:09Z rwatson $"); 34116182Sobrien 351541Srgrimes/* 361541Srgrimes * Pseudo-teletype Driver 371541Srgrimes * (Actually two drivers, requiring two entries in 'cdevsw') 381541Srgrimes */ 3931778Seivind#include "opt_compat.h" 40111899Sdas#include "opt_tty.h" 411541Srgrimes#include <sys/param.h> 421541Srgrimes#include <sys/systm.h> 4391140Stanimura#include <sys/lock.h> 4491140Stanimura#include <sys/mutex.h> 4591140Stanimura#include <sys/sx.h> 46130892Sphk#ifndef BURN_BRIDGES 47130344Sphk#if defined(COMPAT_43) 4824207Sbde#include <sys/ioctl_compat.h> 4924207Sbde#endif 50130892Sphk#endif 511541Srgrimes#include <sys/proc.h> 521541Srgrimes#include <sys/tty.h> 531541Srgrimes#include <sys/conf.h> 5424131Sbde#include <sys/fcntl.h> 5529354Speter#include <sys/poll.h> 561541Srgrimes#include <sys/kernel.h> 57139205Sphk#include <sys/uio.h> 583308Sphk#include <sys/signalvar.h> 5949536Sphk#include <sys/malloc.h> 601541Srgrimes 6169774Sphkstatic MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); 6212517Sjulian 6392723Salfredstatic void ptsstart(struct tty *tp); 6492723Salfredstatic void ptsstop(struct tty *tp, int rw); 6592723Salfredstatic void ptcwakeup(struct tty *tp, int flag); 66147982Srwatsonstatic struct cdev *ptyinit(struct cdev *cdev, struct thread *td); 6711789Sbde 6812675Sjulianstatic d_open_t ptsopen; 6912675Sjulianstatic d_close_t ptsclose; 7012675Sjulianstatic d_read_t ptsread; 7112675Sjulianstatic d_write_t ptswrite; 72135622Sphkstatic d_ioctl_t ptsioctl; 7312675Sjulianstatic d_open_t ptcopen; 7412675Sjulianstatic d_close_t ptcclose; 7512675Sjulianstatic d_read_t ptcread; 76135622Sphkstatic d_ioctl_t ptcioctl; 7712675Sjulianstatic d_write_t ptcwrite; 7829354Speterstatic d_poll_t ptcpoll; 7912675Sjulian 8047625Sphkstatic struct cdevsw pts_cdevsw = { 81126080Sphk .d_version = D_VERSION, 82111815Sphk .d_open = ptsopen, 83111815Sphk .d_close = ptsclose, 84111815Sphk .d_read = ptsread, 85111815Sphk .d_write = ptswrite, 86135622Sphk .d_ioctl = ptsioctl, 87111815Sphk .d_name = "pts", 88126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 8938485Sbde}; 9012675Sjulian 9147625Sphkstatic struct cdevsw ptc_cdevsw = { 92126080Sphk .d_version = D_VERSION, 93111815Sphk .d_open = ptcopen, 94111815Sphk .d_close = ptcclose, 95111815Sphk .d_read = ptcread, 96111815Sphk .d_write = ptcwrite, 97135622Sphk .d_ioctl = ptcioctl, 98111815Sphk .d_poll = ptcpoll, 99111815Sphk .d_name = "ptc", 100126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 10138485Sbde}; 10212675Sjulian 1031541Srgrimes#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 1041541Srgrimes 105130263Sphkstruct ptsc { 1061541Srgrimes int pt_flags; 1071541Srgrimes struct selinfo pt_selr, pt_selw; 1081541Srgrimes u_char pt_send; 1091541Srgrimes u_char pt_ucntl; 110130054Sphk struct tty *pt_tty; 111130585Sphk struct cdev *devs, *devc; 11257070Srwatson struct prison *pt_prison; 11349536Sphk}; 1141541Srgrimes 1151541Srgrimes#define PF_PKT 0x08 /* packet mode */ 1161541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 1171541Srgrimes#define PF_NOSTOP 0x40 1181541Srgrimes#define PF_UCNTL 0x80 /* user control mode */ 1191541Srgrimes 120130259Sphk#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf) 121130259Sphk#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) 122130259Sphk#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) 123130259Sphk 12477176Sphkstatic char *names = "pqrsPQRS"; 1251541Srgrimes/* 12649536Sphk * This function creates and initializes a pts/ptc pair 1271541Srgrimes * 12849536Sphk * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 12949536Sphk * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 13049536Sphk * 131111742Sdes * XXX: define and add mapping of upper minor bits to allow more 13249536Sphk * than 256 ptys. 1331541Srgrimes */ 134130585Sphkstatic struct cdev * 135147982Srwatsonptyinit(struct cdev *devc, struct thread *td) 1361541Srgrimes{ 137130585Sphk struct cdev *devs; 138130263Sphk struct ptsc *pt; 13977176Sphk int n; 1401541Srgrimes 14177176Sphk n = minor(devc); 14249536Sphk /* For now we only map the lower 8 bits of the minor */ 14349536Sphk if (n & ~0xff) 144130640Sphk return (NULL); 14549536Sphk 14678405Sbrian devc->si_flags &= ~SI_CHEAPCLONE; 14778405Sbrian 148111119Simp pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); 149147982Srwatson pt->devs = devs = make_dev_cred(&pts_cdevsw, n, td->td_ucred, 15066067Sphk UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); 15177176Sphk pt->devc = devc; 15249536Sphk 153130054Sphk pt->pt_tty = ttymalloc(pt->pt_tty); 154135298Sphk pt->pt_tty->t_sc = pt; 15549536Sphk devs->si_drv1 = devc->si_drv1 = pt; 156130054Sphk devs->si_tty = devc->si_tty = pt->pt_tty; 157130054Sphk pt->pt_tty->t_dev = devs; 15864880Sphk return (devc); 15916322Sgpalmer} 1601541Srgrimes 1611541Srgrimes/*ARGSUSED*/ 16212675Sjulianstatic int 163130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) 1641541Srgrimes{ 165111742Sdes struct tty *tp; 1661541Srgrimes int error; 167130263Sphk struct ptsc *pt; 1681541Srgrimes 16949536Sphk if (!dev->si_drv1) 170111742Sdes return(ENXIO); 171130263Sphk pt = dev->si_drv1; 17250652Sphk tp = dev->si_tty; 1731541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 174136680Sphk ttyinitmode(tp, 1, 0); 175125839Srwatson } else if (tp->t_state & TS_XCLUDE && suser(td)) 1761541Srgrimes return (EBUSY); 177130263Sphk else if (pt->pt_prison != td->td_ucred->cr_prison) 17857070Srwatson return (EBUSY); 1791541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 180130077Sphk (void)ttyld_modem(tp, 1); 1811541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1821541Srgrimes if (flag&FNONBLOCK) 1831541Srgrimes break; 1849639Sbde error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1859624Sbde "ptsopn", 0); 1863308Sphk if (error) 1871541Srgrimes return (error); 1881541Srgrimes } 189130077Sphk error = ttyld_open(tp, dev); 1907724Sache if (error == 0) 1917724Sache ptcwakeup(tp, FREAD|FWRITE); 1921541Srgrimes return (error); 1931541Srgrimes} 1941541Srgrimes 19512675Sjulianstatic int 196130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td) 1971541Srgrimes{ 198111742Sdes struct tty *tp; 1991541Srgrimes int err; 2001541Srgrimes 20150652Sphk tp = dev->si_tty; 202130077Sphk err = ttyld_close(tp, flag); 203132226Sphk (void) tty_close(tp); 2041541Srgrimes return (err); 2051541Srgrimes} 2061541Srgrimes 20712675Sjulianstatic int 208130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag) 2091541Srgrimes{ 210111742Sdes struct tty *tp = dev->si_tty; 2111541Srgrimes int error = 0; 2121541Srgrimes 213131114Sphk if (tp->t_oproc) 214131114Sphk error = ttyld_read(tp, uio, flag); 2151541Srgrimes ptcwakeup(tp, FWRITE); 2161541Srgrimes return (error); 2171541Srgrimes} 2181541Srgrimes 2191541Srgrimes/* 2201541Srgrimes * Write to pseudo-tty. 2211541Srgrimes * Wakeups of controlling tty will happen 2221541Srgrimes * indirectly, when tty driver calls ptsstart. 2231541Srgrimes */ 22412675Sjulianstatic int 225130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag) 2261541Srgrimes{ 227111742Sdes struct tty *tp; 2281541Srgrimes 22950652Sphk tp = dev->si_tty; 2301541Srgrimes if (tp->t_oproc == 0) 2311541Srgrimes return (EIO); 232130077Sphk return (ttyld_write(tp, uio, flag)); 2331541Srgrimes} 2341541Srgrimes 2351541Srgrimes/* 2361541Srgrimes * Start output on pseudo-tty. 2371541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2381541Srgrimes */ 23912819Sphkstatic void 240130262Sphkptsstart(struct tty *tp) 2411541Srgrimes{ 242135298Sphk struct ptsc *pt = tp->t_sc; 2431541Srgrimes 2441541Srgrimes if (tp->t_state & TS_TTSTOP) 2451541Srgrimes return; 246130263Sphk if (pt->pt_flags & PF_STOPPED) { 247130263Sphk pt->pt_flags &= ~PF_STOPPED; 248130263Sphk pt->pt_send = TIOCPKT_START; 2491541Srgrimes } 2501541Srgrimes ptcwakeup(tp, FREAD); 2511541Srgrimes} 2521541Srgrimes 25312819Sphkstatic void 254130262Sphkptcwakeup(struct tty *tp, int flag) 2551541Srgrimes{ 256135298Sphk struct ptsc *pt = tp->t_sc; 2571541Srgrimes 2581541Srgrimes if (flag & FREAD) { 259130263Sphk selwakeuppri(&pt->pt_selr, TTIPRI); 2609639Sbde wakeup(TSA_PTC_READ(tp)); 2611541Srgrimes } 2621541Srgrimes if (flag & FWRITE) { 263130263Sphk selwakeuppri(&pt->pt_selw, TTOPRI); 2649639Sbde wakeup(TSA_PTC_WRITE(tp)); 2651541Srgrimes } 2661541Srgrimes} 2671541Srgrimes 26812675Sjulianstatic int 269130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) 2701541Srgrimes{ 271111742Sdes struct tty *tp; 272130263Sphk struct ptsc *pt; 2731541Srgrimes 27449536Sphk if (!dev->si_drv1) 275147982Srwatson ptyinit(dev, td); 27649536Sphk if (!dev->si_drv1) 277111742Sdes return(ENXIO); 27850652Sphk tp = dev->si_tty; 2791541Srgrimes if (tp->t_oproc) 2801541Srgrimes return (EIO); 28159818Sache tp->t_timeout = -1; 2821541Srgrimes tp->t_oproc = ptsstart; 28351654Sphk tp->t_stop = ptsstop; 284130077Sphk (void)ttyld_modem(tp, 1); 2851541Srgrimes tp->t_lflag &= ~EXTPROC; 286130263Sphk pt = dev->si_drv1; 287130263Sphk pt->pt_prison = td->td_ucred->cr_prison; 288130263Sphk pt->pt_flags = 0; 289130263Sphk pt->pt_send = 0; 290130263Sphk pt->pt_ucntl = 0; 2911541Srgrimes return (0); 2921541Srgrimes} 2931541Srgrimes 29412675Sjulianstatic int 295130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) 2961541Srgrimes{ 297111742Sdes struct tty *tp; 2981541Srgrimes 29950652Sphk tp = dev->si_tty; 300130077Sphk (void)ttyld_modem(tp, 0); 3019824Sbde 3029824Sbde /* 3039824Sbde * XXX MDMBUF makes no sense for ptys but would inhibit the above 3049824Sbde * l_modem(). CLOCAL makes sense but isn't supported. Special 3059824Sbde * l_modem()s that ignore carrier drop make no sense for ptys but 3069824Sbde * may be in use because other parts of the line discipline make 3079824Sbde * sense for ptys. Recover by doing everything that a normal 3089824Sbde * ttymodem() would have done except for sending a SIGHUP. 3099824Sbde */ 3109850Sbde if (tp->t_state & TS_ISOPEN) { 3119850Sbde tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 3129850Sbde tp->t_state |= TS_ZOMBIE; 3139850Sbde ttyflush(tp, FREAD | FWRITE); 3149850Sbde } 3159824Sbde 3161541Srgrimes tp->t_oproc = 0; /* mark closed */ 3171541Srgrimes return (0); 3181541Srgrimes} 3191541Srgrimes 32012675Sjulianstatic int 321130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag) 3221541Srgrimes{ 323111742Sdes struct tty *tp = dev->si_tty; 324130263Sphk struct ptsc *pt = dev->si_drv1; 3251541Srgrimes char buf[BUFSIZ]; 3261541Srgrimes int error = 0, cc; 3271541Srgrimes 3281541Srgrimes /* 3291541Srgrimes * We want to block until the slave 3301541Srgrimes * is open, and there's something to read; 3311541Srgrimes * but if we lost the slave or we're NBIO, 3321541Srgrimes * then return the appropriate error instead. 3331541Srgrimes */ 3341541Srgrimes for (;;) { 3351541Srgrimes if (tp->t_state&TS_ISOPEN) { 336130263Sphk if (pt->pt_flags&PF_PKT && pt->pt_send) { 337130263Sphk error = ureadc((int)pt->pt_send, uio); 3381541Srgrimes if (error) 3391541Srgrimes return (error); 340130263Sphk if (pt->pt_send & TIOCPKT_IOCTL) { 3411541Srgrimes cc = min(uio->uio_resid, 3421541Srgrimes sizeof(tp->t_termios)); 343111741Sdes uiomove(&tp->t_termios, cc, uio); 3441541Srgrimes } 345130263Sphk pt->pt_send = 0; 3461541Srgrimes return (0); 3471541Srgrimes } 348130263Sphk if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { 349130263Sphk error = ureadc((int)pt->pt_ucntl, uio); 3501541Srgrimes if (error) 3511541Srgrimes return (error); 352130263Sphk pt->pt_ucntl = 0; 3531541Srgrimes return (0); 3541541Srgrimes } 3551541Srgrimes if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 3561541Srgrimes break; 3571541Srgrimes } 3589824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 3591541Srgrimes return (0); /* EOF */ 360139205Sphk if (flag & O_NONBLOCK) 3611541Srgrimes return (EWOULDBLOCK); 3629639Sbde error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 3633308Sphk if (error) 3641541Srgrimes return (error); 3651541Srgrimes } 366130263Sphk if (pt->pt_flags & (PF_PKT|PF_UCNTL)) 3671541Srgrimes error = ureadc(0, uio); 3681541Srgrimes while (uio->uio_resid > 0 && error == 0) { 3691541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 3701541Srgrimes if (cc <= 0) 3711541Srgrimes break; 3721541Srgrimes error = uiomove(buf, cc, uio); 3731541Srgrimes } 3749626Sbde ttwwakeup(tp); 3751541Srgrimes return (error); 3761541Srgrimes} 3771541Srgrimes 37812675Sjulianstatic void 379130262Sphkptsstop(struct tty *tp, int flush) 3801541Srgrimes{ 381135298Sphk struct ptsc *pt = tp->t_sc; 3821541Srgrimes int flag; 3831541Srgrimes 3841541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 3851541Srgrimes if (flush == 0) { 3861541Srgrimes flush = TIOCPKT_STOP; 387130263Sphk pt->pt_flags |= PF_STOPPED; 3881541Srgrimes } else 389130263Sphk pt->pt_flags &= ~PF_STOPPED; 390130263Sphk pt->pt_send |= flush; 3911541Srgrimes /* change of perspective */ 3921541Srgrimes flag = 0; 3931541Srgrimes if (flush & FREAD) 3941541Srgrimes flag |= FWRITE; 3951541Srgrimes if (flush & FWRITE) 3961541Srgrimes flag |= FREAD; 3971541Srgrimes ptcwakeup(tp, flag); 3981541Srgrimes} 3991541Srgrimes 40012675Sjulianstatic int 401130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td) 4021541Srgrimes{ 403111742Sdes struct tty *tp = dev->si_tty; 404130263Sphk struct ptsc *pt = dev->si_drv1; 40529354Speter int revents = 0; 4061541Srgrimes int s; 4071541Srgrimes 4089824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 409120513Sphk return (events & 410120513Sphk (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); 4111541Srgrimes 41229354Speter /* 41329354Speter * Need to block timeouts (ttrstart). 41429354Speter */ 41529354Speter s = spltty(); 4161541Srgrimes 41729354Speter if (events & (POLLIN | POLLRDNORM)) 41829354Speter if ((tp->t_state & TS_ISOPEN) && 41929354Speter ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || 420130263Sphk ((pt->pt_flags & PF_PKT) && pt->pt_send) || 421130263Sphk ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) 42229354Speter revents |= events & (POLLIN | POLLRDNORM); 4231541Srgrimes 42429354Speter if (events & (POLLOUT | POLLWRNORM)) 42529354Speter if (tp->t_state & TS_ISOPEN && 426131114Sphk (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || 42790831Sdillon (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) 42829354Speter revents |= events & (POLLOUT | POLLWRNORM); 4291541Srgrimes 43029354Speter if (events & POLLHUP) 43129354Speter if ((tp->t_state & TS_CARR_ON) == 0) 43229354Speter revents |= POLLHUP; 4331541Srgrimes 43429354Speter if (revents == 0) { 43529354Speter if (events & (POLLIN | POLLRDNORM)) 436130263Sphk selrecord(td, &pt->pt_selr); 43729354Speter 438111742Sdes if (events & (POLLOUT | POLLWRNORM)) 439130263Sphk selrecord(td, &pt->pt_selw); 4401541Srgrimes } 44129354Speter splx(s); 44229354Speter 44329354Speter return (revents); 4441541Srgrimes} 4451541Srgrimes 44612675Sjulianstatic int 447130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag) 4481541Srgrimes{ 449111742Sdes struct tty *tp = dev->si_tty; 450111742Sdes u_char *cp = 0; 451111742Sdes int cc = 0; 4521541Srgrimes u_char locbuf[BUFSIZ]; 4531541Srgrimes int cnt = 0; 4541541Srgrimes int error = 0; 4551541Srgrimes 4561541Srgrimesagain: 4571541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4581541Srgrimes goto block; 45911789Sbde while (uio->uio_resid > 0 || cc > 0) { 4601541Srgrimes if (cc == 0) { 4611541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 4621541Srgrimes cp = locbuf; 463111741Sdes error = uiomove(cp, cc, uio); 4641541Srgrimes if (error) 4651541Srgrimes return (error); 4661541Srgrimes /* check again for safety */ 46711789Sbde if ((tp->t_state & TS_ISOPEN) == 0) { 46811789Sbde /* adjust for data copied in but not written */ 46911789Sbde uio->uio_resid += cc; 4701541Srgrimes return (EIO); 47111789Sbde } 4721541Srgrimes } 4731541Srgrimes while (cc > 0) { 4741541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 47590831Sdillon (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 4769824Sbde wakeup(TSA_HUP_OR_INPUT(tp)); 4771541Srgrimes goto block; 4781541Srgrimes } 479130077Sphk ttyld_rint(tp, *cp++); 4801541Srgrimes cnt++; 4811541Srgrimes cc--; 4821541Srgrimes } 4831541Srgrimes cc = 0; 4841541Srgrimes } 4851541Srgrimes return (0); 4861541Srgrimesblock: 4871541Srgrimes /* 4881541Srgrimes * Come here to wait for slave to open, for space 48915199Sbde * in outq, or space in rawq, or an empty canq. 4901541Srgrimes */ 49111789Sbde if ((tp->t_state & TS_CONNECTED) == 0) { 49211789Sbde /* adjust for data copied in but not written */ 49311789Sbde uio->uio_resid += cc; 4941541Srgrimes return (EIO); 49511789Sbde } 496139205Sphk if (flag & O_NONBLOCK) { 4971541Srgrimes /* adjust for data copied in but not written */ 4981541Srgrimes uio->uio_resid += cc; 4991541Srgrimes if (cnt == 0) 5001541Srgrimes return (EWOULDBLOCK); 5011541Srgrimes return (0); 5021541Srgrimes } 5039639Sbde error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 5043308Sphk if (error) { 5051541Srgrimes /* adjust for data copied in but not written */ 5061541Srgrimes uio->uio_resid += cc; 5071541Srgrimes return (error); 5081541Srgrimes } 5091541Srgrimes goto again; 5101541Srgrimes} 5111541Srgrimes 5121541Srgrimes/*ARGSUSED*/ 51312675Sjulianstatic int 514135622Sphkptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 5151541Srgrimes{ 516111742Sdes struct tty *tp = dev->si_tty; 517130263Sphk struct ptsc *pt = dev->si_drv1; 5181541Srgrimes 519135622Sphk switch (cmd) { 5201541Srgrimes 521135622Sphk case TIOCGPGRP: 522135622Sphk /* 523135622Sphk * We avoid calling ttioctl on the controller since, 524135622Sphk * in that case, tp must be the controlling terminal. 525135622Sphk */ 526135622Sphk *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 527135622Sphk return (0); 5281541Srgrimes 529135622Sphk case TIOCPKT: 530135622Sphk if (*(int *)data) { 531135622Sphk if (pt->pt_flags & PF_UCNTL) 532135622Sphk return (EINVAL); 533135622Sphk pt->pt_flags |= PF_PKT; 534135622Sphk } else 535135622Sphk pt->pt_flags &= ~PF_PKT; 536135622Sphk return (0); 5371541Srgrimes 538135622Sphk case TIOCUCNTL: 539135622Sphk if (*(int *)data) { 540135622Sphk if (pt->pt_flags & PF_PKT) 541135622Sphk return (EINVAL); 542135622Sphk pt->pt_flags |= PF_UCNTL; 543135622Sphk } else 544135622Sphk pt->pt_flags &= ~PF_UCNTL; 545135622Sphk return (0); 546135622Sphk } 5471541Srgrimes 548135622Sphk /* 549135622Sphk * The rest of the ioctls shouldn't be called until 550135622Sphk * the slave is open. 551135622Sphk */ 552135622Sphk if ((tp->t_state & TS_ISOPEN) == 0) 553135622Sphk return (EAGAIN); 55447203Sluoqi 555135622Sphk switch (cmd) { 556130892Sphk#ifndef BURN_BRIDGES 5571541Srgrimes#ifdef COMPAT_43 558135622Sphk case TIOCSETP: 559135622Sphk case TIOCSETN: 5601541Srgrimes#endif 561130892Sphk#endif 562135622Sphk case TIOCSETD: 563135622Sphk case TIOCSETA: 564135622Sphk case TIOCSETAW: 565135622Sphk case TIOCSETAF: 566135622Sphk /* 567135622Sphk * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 568135622Sphk * ttywflush(tp) will hang if there are characters in 569135622Sphk * the outq. 570135622Sphk */ 571135622Sphk ndflush(&tp->t_outq, tp->t_outq.c_cc); 572135622Sphk break; 5731541Srgrimes 574135622Sphk case TIOCSIG: 575135622Sphk if (*(unsigned int *)data >= NSIG || 576135622Sphk *(unsigned int *)data == 0) 577135622Sphk return(EINVAL); 578135622Sphk if ((tp->t_lflag&NOFLSH) == 0) 579135622Sphk ttyflush(tp, FREAD|FWRITE); 580135622Sphk if (tp->t_pgrp != NULL) { 581135622Sphk PGRP_LOCK(tp->t_pgrp); 582135622Sphk pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 583135622Sphk PGRP_UNLOCK(tp->t_pgrp); 5841541Srgrimes } 585135622Sphk if ((*(unsigned int *)data == SIGINFO) && 586135622Sphk ((tp->t_lflag&NOKERNINFO) == 0)) 587135622Sphk ttyinfo(tp); 588135622Sphk return(0); 58947203Sluoqi } 590135622Sphk 591135622Sphk return (ptsioctl(dev, cmd, data, flag, td)); 592135622Sphk} 593135622Sphk 594135622Sphk/*ARGSUSED*/ 595135622Sphkstatic int 596135622Sphkptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 597135622Sphk{ 598135622Sphk struct tty *tp = dev->si_tty; 599135622Sphk struct ptsc *pt = dev->si_drv1; 600135622Sphk u_char *cc = tp->t_cc; 601135622Sphk int stop, error; 602135622Sphk 60347301Sluoqi if (cmd == TIOCEXT) { 60447301Sluoqi /* 60547301Sluoqi * When the EXTPROC bit is being toggled, we need 60647301Sluoqi * to send an TIOCPKT_IOCTL if the packet driver 60747301Sluoqi * is turned on. 60847301Sluoqi */ 60947301Sluoqi if (*(int *)data) { 610130263Sphk if (pt->pt_flags & PF_PKT) { 611130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61247301Sluoqi ptcwakeup(tp, FREAD); 61347301Sluoqi } 61447301Sluoqi tp->t_lflag |= EXTPROC; 61547301Sluoqi } else { 61647301Sluoqi if ((tp->t_lflag & EXTPROC) && 617130263Sphk (pt->pt_flags & PF_PKT)) { 618130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61947301Sluoqi ptcwakeup(tp, FREAD); 62047301Sluoqi } 62147301Sluoqi tp->t_lflag &= ~EXTPROC; 62247301Sluoqi } 62347301Sluoqi return(0); 62447301Sluoqi } 625130054Sphk error = ttyioctl(dev, cmd, data, flag, td); 626130054Sphk if (error == ENOTTY) { 627130263Sphk if (pt->pt_flags & PF_UCNTL && 6281541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 6291541Srgrimes if (cmd & 0xff) { 630130263Sphk pt->pt_ucntl = (u_char)cmd; 6311541Srgrimes ptcwakeup(tp, FREAD); 6321541Srgrimes } 6331541Srgrimes return (0); 6341541Srgrimes } 6351541Srgrimes error = ENOTTY; 6361541Srgrimes } 6371541Srgrimes /* 6381541Srgrimes * If external processing and packet mode send ioctl packet. 6391541Srgrimes */ 640130263Sphk if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) { 6411541Srgrimes switch(cmd) { 6421541Srgrimes case TIOCSETA: 6431541Srgrimes case TIOCSETAW: 6441541Srgrimes case TIOCSETAF: 645130892Sphk#ifndef BURN_BRIDGES 6461541Srgrimes#ifdef COMPAT_43 6471541Srgrimes case TIOCSETP: 6481541Srgrimes case TIOCSETN: 6491541Srgrimes case TIOCSETC: 6501541Srgrimes case TIOCSLTC: 6511541Srgrimes case TIOCLBIS: 6521541Srgrimes case TIOCLBIC: 6531541Srgrimes case TIOCLSET: 6541541Srgrimes#endif 655130892Sphk#endif 656130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 6571541Srgrimes ptcwakeup(tp, FREAD); 658115463Sphk break; 6591541Srgrimes default: 6601541Srgrimes break; 6611541Srgrimes } 6621541Srgrimes } 6638876Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 6641541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 665130263Sphk if (pt->pt_flags & PF_NOSTOP) { 6661541Srgrimes if (stop) { 667130263Sphk pt->pt_send &= ~TIOCPKT_NOSTOP; 668130263Sphk pt->pt_send |= TIOCPKT_DOSTOP; 669130263Sphk pt->pt_flags &= ~PF_NOSTOP; 6701541Srgrimes ptcwakeup(tp, FREAD); 6711541Srgrimes } 6721541Srgrimes } else { 6731541Srgrimes if (!stop) { 674130263Sphk pt->pt_send &= ~TIOCPKT_DOSTOP; 675130263Sphk pt->pt_send |= TIOCPKT_NOSTOP; 676130263Sphk pt->pt_flags |= PF_NOSTOP; 6771541Srgrimes ptcwakeup(tp, FREAD); 6781541Srgrimes } 6791541Srgrimes } 6801541Srgrimes return (error); 6811541Srgrimes} 68212517Sjulian 68312675Sjulianstatic void 684147982Srwatsonpty_clone(void *arg, struct ucred *cr, char *name, int namelen, 685147982Srwatson struct cdev **dev) 68664880Sphk{ 68764880Sphk int u; 68864880Sphk 689130640Sphk if (*dev != NULL) 69064880Sphk return; 69164880Sphk if (bcmp(name, "pty", 3) != 0) 69264880Sphk return; 69364880Sphk if (name[5] != '\0') 69464880Sphk return; 69564880Sphk switch (name[3]) { 69664880Sphk case 'p': u = 0; break; 69764880Sphk case 'q': u = 32; break; 69864880Sphk case 'r': u = 64; break; 69964880Sphk case 's': u = 96; break; 70064880Sphk case 'P': u = 128; break; 70164880Sphk case 'Q': u = 160; break; 70264880Sphk case 'R': u = 192; break; 70364880Sphk case 'S': u = 224; break; 70464880Sphk default: return; 70564880Sphk } 70664880Sphk if (name[4] >= '0' && name[4] <= '9') 70764880Sphk u += name[4] - '0'; 70864880Sphk else if (name[4] >= 'a' && name[4] <= 'v') 70964880Sphk u += name[4] - 'a' + 10; 71064880Sphk else 71164880Sphk return; 712147982Srwatson *dev = make_dev_cred(&ptc_cdevsw, u, cr, 71377176Sphk UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); 714144389Sphk dev_ref(*dev); 71577176Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 71664880Sphk return; 71764880Sphk} 71864880Sphk 71964880Sphkstatic void 720130262Sphkptc_drvinit(void *unused) 72112517Sjulian{ 722108363Sphk 723147982Srwatson EVENTHANDLER_REGISTER(dev_clone_cred, pty_clone, 0, 1000); 72412517Sjulian} 72512517Sjulian 726142709SphkSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL) 727