pty.c revision 139205
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 * 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 139205 2004-12-22 17:37:14Z phk $"); 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); 66130585Sphkstatic struct cdev *ptyinit(struct cdev *cdev); 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 8038485Sbde#define CDEV_MAJOR_S 5 8147625Sphkstatic struct cdevsw pts_cdevsw = { 82126080Sphk .d_version = D_VERSION, 83111815Sphk .d_open = ptsopen, 84111815Sphk .d_close = ptsclose, 85111815Sphk .d_read = ptsread, 86111815Sphk .d_write = ptswrite, 87135622Sphk .d_ioctl = ptsioctl, 88111815Sphk .d_name = "pts", 89111815Sphk .d_maj = CDEV_MAJOR_S, 90126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 9138485Sbde}; 9212675Sjulian 9338485Sbde#define CDEV_MAJOR_C 6 9447625Sphkstatic struct cdevsw ptc_cdevsw = { 95126080Sphk .d_version = D_VERSION, 96111815Sphk .d_open = ptcopen, 97111815Sphk .d_close = ptcclose, 98111815Sphk .d_read = ptcread, 99111815Sphk .d_write = ptcwrite, 100135622Sphk .d_ioctl = ptcioctl, 101111815Sphk .d_poll = ptcpoll, 102111815Sphk .d_name = "ptc", 103111815Sphk .d_maj = CDEV_MAJOR_C, 104126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 10538485Sbde}; 10612675Sjulian 1071541Srgrimes#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 1081541Srgrimes 109130263Sphkstruct ptsc { 1101541Srgrimes int pt_flags; 1111541Srgrimes struct selinfo pt_selr, pt_selw; 1121541Srgrimes u_char pt_send; 1131541Srgrimes u_char pt_ucntl; 114130054Sphk struct tty *pt_tty; 115130585Sphk struct cdev *devs, *devc; 11657070Srwatson struct prison *pt_prison; 11749536Sphk}; 1181541Srgrimes 1191541Srgrimes#define PF_PKT 0x08 /* packet mode */ 1201541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 1211541Srgrimes#define PF_NOSTOP 0x40 1221541Srgrimes#define PF_UCNTL 0x80 /* user control mode */ 1231541Srgrimes 124130259Sphk#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf) 125130259Sphk#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) 126130259Sphk#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) 127130259Sphk 12877176Sphkstatic char *names = "pqrsPQRS"; 1291541Srgrimes/* 13049536Sphk * This function creates and initializes a pts/ptc pair 1311541Srgrimes * 13249536Sphk * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 13349536Sphk * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 13449536Sphk * 135111742Sdes * XXX: define and add mapping of upper minor bits to allow more 13649536Sphk * than 256 ptys. 1371541Srgrimes */ 138130585Sphkstatic struct cdev * 139130585Sphkptyinit(struct cdev *devc) 1401541Srgrimes{ 141130585Sphk struct cdev *devs; 142130263Sphk struct ptsc *pt; 14377176Sphk int n; 1441541Srgrimes 14577176Sphk n = minor(devc); 14649536Sphk /* For now we only map the lower 8 bits of the minor */ 14749536Sphk if (n & ~0xff) 148130640Sphk return (NULL); 14949536Sphk 15078405Sbrian devc->si_flags &= ~SI_CHEAPCLONE; 15178405Sbrian 152111119Simp pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); 15350092Sjulian pt->devs = devs = make_dev(&pts_cdevsw, n, 15466067Sphk UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); 15577176Sphk pt->devc = devc; 15649536Sphk 157130054Sphk pt->pt_tty = ttymalloc(pt->pt_tty); 158135298Sphk pt->pt_tty->t_sc = pt; 15949536Sphk devs->si_drv1 = devc->si_drv1 = pt; 160130054Sphk devs->si_tty = devc->si_tty = pt->pt_tty; 161130054Sphk pt->pt_tty->t_dev = devs; 16264880Sphk return (devc); 16316322Sgpalmer} 1641541Srgrimes 1651541Srgrimes/*ARGSUSED*/ 16612675Sjulianstatic int 167130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) 1681541Srgrimes{ 169111742Sdes struct tty *tp; 1701541Srgrimes int error; 171130263Sphk struct ptsc *pt; 1721541Srgrimes 17349536Sphk if (!dev->si_drv1) 174111742Sdes return(ENXIO); 175130263Sphk pt = dev->si_drv1; 17650652Sphk tp = dev->si_tty; 1771541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 178136680Sphk ttyinitmode(tp, 1, 0); 179125839Srwatson } else if (tp->t_state & TS_XCLUDE && suser(td)) 1801541Srgrimes return (EBUSY); 181130263Sphk else if (pt->pt_prison != td->td_ucred->cr_prison) 18257070Srwatson return (EBUSY); 1831541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 184130077Sphk (void)ttyld_modem(tp, 1); 1851541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1861541Srgrimes if (flag&FNONBLOCK) 1871541Srgrimes break; 1889639Sbde error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1899624Sbde "ptsopn", 0); 1903308Sphk if (error) 1911541Srgrimes return (error); 1921541Srgrimes } 193130077Sphk error = ttyld_open(tp, dev); 1947724Sache if (error == 0) 1957724Sache ptcwakeup(tp, FREAD|FWRITE); 1961541Srgrimes return (error); 1971541Srgrimes} 1981541Srgrimes 19912675Sjulianstatic int 200130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td) 2011541Srgrimes{ 202111742Sdes struct tty *tp; 2031541Srgrimes int err; 2041541Srgrimes 20550652Sphk tp = dev->si_tty; 206130077Sphk err = ttyld_close(tp, flag); 207132226Sphk (void) tty_close(tp); 2081541Srgrimes return (err); 2091541Srgrimes} 2101541Srgrimes 21112675Sjulianstatic int 212130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag) 2131541Srgrimes{ 214111742Sdes struct tty *tp = dev->si_tty; 2151541Srgrimes int error = 0; 2161541Srgrimes 217131114Sphk if (tp->t_oproc) 218131114Sphk error = ttyld_read(tp, uio, flag); 2191541Srgrimes ptcwakeup(tp, FWRITE); 2201541Srgrimes return (error); 2211541Srgrimes} 2221541Srgrimes 2231541Srgrimes/* 2241541Srgrimes * Write to pseudo-tty. 2251541Srgrimes * Wakeups of controlling tty will happen 2261541Srgrimes * indirectly, when tty driver calls ptsstart. 2271541Srgrimes */ 22812675Sjulianstatic int 229130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag) 2301541Srgrimes{ 231111742Sdes struct tty *tp; 2321541Srgrimes 23350652Sphk tp = dev->si_tty; 2341541Srgrimes if (tp->t_oproc == 0) 2351541Srgrimes return (EIO); 236130077Sphk return (ttyld_write(tp, uio, flag)); 2371541Srgrimes} 2381541Srgrimes 2391541Srgrimes/* 2401541Srgrimes * Start output on pseudo-tty. 2411541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2421541Srgrimes */ 24312819Sphkstatic void 244130262Sphkptsstart(struct tty *tp) 2451541Srgrimes{ 246135298Sphk struct ptsc *pt = tp->t_sc; 2471541Srgrimes 2481541Srgrimes if (tp->t_state & TS_TTSTOP) 2491541Srgrimes return; 250130263Sphk if (pt->pt_flags & PF_STOPPED) { 251130263Sphk pt->pt_flags &= ~PF_STOPPED; 252130263Sphk pt->pt_send = TIOCPKT_START; 2531541Srgrimes } 2541541Srgrimes ptcwakeup(tp, FREAD); 2551541Srgrimes} 2561541Srgrimes 25712819Sphkstatic void 258130262Sphkptcwakeup(struct tty *tp, int flag) 2591541Srgrimes{ 260135298Sphk struct ptsc *pt = tp->t_sc; 2611541Srgrimes 2621541Srgrimes if (flag & FREAD) { 263130263Sphk selwakeuppri(&pt->pt_selr, TTIPRI); 2649639Sbde wakeup(TSA_PTC_READ(tp)); 2651541Srgrimes } 2661541Srgrimes if (flag & FWRITE) { 267130263Sphk selwakeuppri(&pt->pt_selw, TTOPRI); 2689639Sbde wakeup(TSA_PTC_WRITE(tp)); 2691541Srgrimes } 2701541Srgrimes} 2711541Srgrimes 27212675Sjulianstatic int 273130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) 2741541Srgrimes{ 275111742Sdes struct tty *tp; 276130263Sphk struct ptsc *pt; 2771541Srgrimes 27849536Sphk if (!dev->si_drv1) 27977176Sphk ptyinit(dev); 28049536Sphk if (!dev->si_drv1) 281111742Sdes return(ENXIO); 28250652Sphk tp = dev->si_tty; 2831541Srgrimes if (tp->t_oproc) 2841541Srgrimes return (EIO); 28559818Sache tp->t_timeout = -1; 2861541Srgrimes tp->t_oproc = ptsstart; 28751654Sphk tp->t_stop = ptsstop; 288130077Sphk (void)ttyld_modem(tp, 1); 2891541Srgrimes tp->t_lflag &= ~EXTPROC; 290130263Sphk pt = dev->si_drv1; 291130263Sphk pt->pt_prison = td->td_ucred->cr_prison; 292130263Sphk pt->pt_flags = 0; 293130263Sphk pt->pt_send = 0; 294130263Sphk pt->pt_ucntl = 0; 2951541Srgrimes return (0); 2961541Srgrimes} 2971541Srgrimes 29812675Sjulianstatic int 299130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) 3001541Srgrimes{ 301111742Sdes struct tty *tp; 3021541Srgrimes 30350652Sphk tp = dev->si_tty; 304130077Sphk (void)ttyld_modem(tp, 0); 3059824Sbde 3069824Sbde /* 3079824Sbde * XXX MDMBUF makes no sense for ptys but would inhibit the above 3089824Sbde * l_modem(). CLOCAL makes sense but isn't supported. Special 3099824Sbde * l_modem()s that ignore carrier drop make no sense for ptys but 3109824Sbde * may be in use because other parts of the line discipline make 3119824Sbde * sense for ptys. Recover by doing everything that a normal 3129824Sbde * ttymodem() would have done except for sending a SIGHUP. 3139824Sbde */ 3149850Sbde if (tp->t_state & TS_ISOPEN) { 3159850Sbde tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 3169850Sbde tp->t_state |= TS_ZOMBIE; 3179850Sbde ttyflush(tp, FREAD | FWRITE); 3189850Sbde } 3199824Sbde 3201541Srgrimes tp->t_oproc = 0; /* mark closed */ 3211541Srgrimes return (0); 3221541Srgrimes} 3231541Srgrimes 32412675Sjulianstatic int 325130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag) 3261541Srgrimes{ 327111742Sdes struct tty *tp = dev->si_tty; 328130263Sphk struct ptsc *pt = dev->si_drv1; 3291541Srgrimes char buf[BUFSIZ]; 3301541Srgrimes int error = 0, cc; 3311541Srgrimes 3321541Srgrimes /* 3331541Srgrimes * We want to block until the slave 3341541Srgrimes * is open, and there's something to read; 3351541Srgrimes * but if we lost the slave or we're NBIO, 3361541Srgrimes * then return the appropriate error instead. 3371541Srgrimes */ 3381541Srgrimes for (;;) { 3391541Srgrimes if (tp->t_state&TS_ISOPEN) { 340130263Sphk if (pt->pt_flags&PF_PKT && pt->pt_send) { 341130263Sphk error = ureadc((int)pt->pt_send, uio); 3421541Srgrimes if (error) 3431541Srgrimes return (error); 344130263Sphk if (pt->pt_send & TIOCPKT_IOCTL) { 3451541Srgrimes cc = min(uio->uio_resid, 3461541Srgrimes sizeof(tp->t_termios)); 347111741Sdes uiomove(&tp->t_termios, cc, uio); 3481541Srgrimes } 349130263Sphk pt->pt_send = 0; 3501541Srgrimes return (0); 3511541Srgrimes } 352130263Sphk if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { 353130263Sphk error = ureadc((int)pt->pt_ucntl, uio); 3541541Srgrimes if (error) 3551541Srgrimes return (error); 356130263Sphk pt->pt_ucntl = 0; 3571541Srgrimes return (0); 3581541Srgrimes } 3591541Srgrimes if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 3601541Srgrimes break; 3611541Srgrimes } 3629824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 3631541Srgrimes return (0); /* EOF */ 364139205Sphk if (flag & O_NONBLOCK) 3651541Srgrimes return (EWOULDBLOCK); 3669639Sbde error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 3673308Sphk if (error) 3681541Srgrimes return (error); 3691541Srgrimes } 370130263Sphk if (pt->pt_flags & (PF_PKT|PF_UCNTL)) 3711541Srgrimes error = ureadc(0, uio); 3721541Srgrimes while (uio->uio_resid > 0 && error == 0) { 3731541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 3741541Srgrimes if (cc <= 0) 3751541Srgrimes break; 3761541Srgrimes error = uiomove(buf, cc, uio); 3771541Srgrimes } 3789626Sbde ttwwakeup(tp); 3791541Srgrimes return (error); 3801541Srgrimes} 3811541Srgrimes 38212675Sjulianstatic void 383130262Sphkptsstop(struct tty *tp, int flush) 3841541Srgrimes{ 385135298Sphk struct ptsc *pt = tp->t_sc; 3861541Srgrimes int flag; 3871541Srgrimes 3881541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 3891541Srgrimes if (flush == 0) { 3901541Srgrimes flush = TIOCPKT_STOP; 391130263Sphk pt->pt_flags |= PF_STOPPED; 3921541Srgrimes } else 393130263Sphk pt->pt_flags &= ~PF_STOPPED; 394130263Sphk pt->pt_send |= flush; 3951541Srgrimes /* change of perspective */ 3961541Srgrimes flag = 0; 3971541Srgrimes if (flush & FREAD) 3981541Srgrimes flag |= FWRITE; 3991541Srgrimes if (flush & FWRITE) 4001541Srgrimes flag |= FREAD; 4011541Srgrimes ptcwakeup(tp, flag); 4021541Srgrimes} 4031541Srgrimes 40412675Sjulianstatic int 405130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td) 4061541Srgrimes{ 407111742Sdes struct tty *tp = dev->si_tty; 408130263Sphk struct ptsc *pt = dev->si_drv1; 40929354Speter int revents = 0; 4101541Srgrimes int s; 4111541Srgrimes 4129824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 413120513Sphk return (events & 414120513Sphk (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); 4151541Srgrimes 41629354Speter /* 41729354Speter * Need to block timeouts (ttrstart). 41829354Speter */ 41929354Speter s = spltty(); 4201541Srgrimes 42129354Speter if (events & (POLLIN | POLLRDNORM)) 42229354Speter if ((tp->t_state & TS_ISOPEN) && 42329354Speter ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || 424130263Sphk ((pt->pt_flags & PF_PKT) && pt->pt_send) || 425130263Sphk ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) 42629354Speter revents |= events & (POLLIN | POLLRDNORM); 4271541Srgrimes 42829354Speter if (events & (POLLOUT | POLLWRNORM)) 42929354Speter if (tp->t_state & TS_ISOPEN && 430131114Sphk (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || 43190831Sdillon (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) 43229354Speter revents |= events & (POLLOUT | POLLWRNORM); 4331541Srgrimes 43429354Speter if (events & POLLHUP) 43529354Speter if ((tp->t_state & TS_CARR_ON) == 0) 43629354Speter revents |= POLLHUP; 4371541Srgrimes 43829354Speter if (revents == 0) { 43929354Speter if (events & (POLLIN | POLLRDNORM)) 440130263Sphk selrecord(td, &pt->pt_selr); 44129354Speter 442111742Sdes if (events & (POLLOUT | POLLWRNORM)) 443130263Sphk selrecord(td, &pt->pt_selw); 4441541Srgrimes } 44529354Speter splx(s); 44629354Speter 44729354Speter return (revents); 4481541Srgrimes} 4491541Srgrimes 45012675Sjulianstatic int 451130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag) 4521541Srgrimes{ 453111742Sdes struct tty *tp = dev->si_tty; 454111742Sdes u_char *cp = 0; 455111742Sdes int cc = 0; 4561541Srgrimes u_char locbuf[BUFSIZ]; 4571541Srgrimes int cnt = 0; 4581541Srgrimes int error = 0; 4591541Srgrimes 4601541Srgrimesagain: 4611541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4621541Srgrimes goto block; 46311789Sbde while (uio->uio_resid > 0 || cc > 0) { 4641541Srgrimes if (cc == 0) { 4651541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 4661541Srgrimes cp = locbuf; 467111741Sdes error = uiomove(cp, cc, uio); 4681541Srgrimes if (error) 4691541Srgrimes return (error); 4701541Srgrimes /* check again for safety */ 47111789Sbde if ((tp->t_state & TS_ISOPEN) == 0) { 47211789Sbde /* adjust for data copied in but not written */ 47311789Sbde uio->uio_resid += cc; 4741541Srgrimes return (EIO); 47511789Sbde } 4761541Srgrimes } 4771541Srgrimes while (cc > 0) { 4781541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 47990831Sdillon (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 4809824Sbde wakeup(TSA_HUP_OR_INPUT(tp)); 4811541Srgrimes goto block; 4821541Srgrimes } 483130077Sphk ttyld_rint(tp, *cp++); 4841541Srgrimes cnt++; 4851541Srgrimes cc--; 4861541Srgrimes } 4871541Srgrimes cc = 0; 4881541Srgrimes } 4891541Srgrimes return (0); 4901541Srgrimesblock: 4911541Srgrimes /* 4921541Srgrimes * Come here to wait for slave to open, for space 49315199Sbde * in outq, or space in rawq, or an empty canq. 4941541Srgrimes */ 49511789Sbde if ((tp->t_state & TS_CONNECTED) == 0) { 49611789Sbde /* adjust for data copied in but not written */ 49711789Sbde uio->uio_resid += cc; 4981541Srgrimes return (EIO); 49911789Sbde } 500139205Sphk if (flag & O_NONBLOCK) { 5011541Srgrimes /* adjust for data copied in but not written */ 5021541Srgrimes uio->uio_resid += cc; 5031541Srgrimes if (cnt == 0) 5041541Srgrimes return (EWOULDBLOCK); 5051541Srgrimes return (0); 5061541Srgrimes } 5079639Sbde error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 5083308Sphk if (error) { 5091541Srgrimes /* adjust for data copied in but not written */ 5101541Srgrimes uio->uio_resid += cc; 5111541Srgrimes return (error); 5121541Srgrimes } 5131541Srgrimes goto again; 5141541Srgrimes} 5151541Srgrimes 5161541Srgrimes/*ARGSUSED*/ 51712675Sjulianstatic int 518135622Sphkptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 5191541Srgrimes{ 520111742Sdes struct tty *tp = dev->si_tty; 521130263Sphk struct ptsc *pt = dev->si_drv1; 5221541Srgrimes 523135622Sphk switch (cmd) { 5241541Srgrimes 525135622Sphk case TIOCGPGRP: 526135622Sphk /* 527135622Sphk * We avoid calling ttioctl on the controller since, 528135622Sphk * in that case, tp must be the controlling terminal. 529135622Sphk */ 530135622Sphk *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 531135622Sphk return (0); 5321541Srgrimes 533135622Sphk case TIOCPKT: 534135622Sphk if (*(int *)data) { 535135622Sphk if (pt->pt_flags & PF_UCNTL) 536135622Sphk return (EINVAL); 537135622Sphk pt->pt_flags |= PF_PKT; 538135622Sphk } else 539135622Sphk pt->pt_flags &= ~PF_PKT; 540135622Sphk return (0); 5411541Srgrimes 542135622Sphk case TIOCUCNTL: 543135622Sphk if (*(int *)data) { 544135622Sphk if (pt->pt_flags & PF_PKT) 545135622Sphk return (EINVAL); 546135622Sphk pt->pt_flags |= PF_UCNTL; 547135622Sphk } else 548135622Sphk pt->pt_flags &= ~PF_UCNTL; 549135622Sphk return (0); 550135622Sphk } 5511541Srgrimes 552135622Sphk /* 553135622Sphk * The rest of the ioctls shouldn't be called until 554135622Sphk * the slave is open. 555135622Sphk */ 556135622Sphk if ((tp->t_state & TS_ISOPEN) == 0) 557135622Sphk return (EAGAIN); 55847203Sluoqi 559135622Sphk switch (cmd) { 560130892Sphk#ifndef BURN_BRIDGES 5611541Srgrimes#ifdef COMPAT_43 562135622Sphk case TIOCSETP: 563135622Sphk case TIOCSETN: 5641541Srgrimes#endif 565130892Sphk#endif 566135622Sphk case TIOCSETD: 567135622Sphk case TIOCSETA: 568135622Sphk case TIOCSETAW: 569135622Sphk case TIOCSETAF: 570135622Sphk /* 571135622Sphk * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 572135622Sphk * ttywflush(tp) will hang if there are characters in 573135622Sphk * the outq. 574135622Sphk */ 575135622Sphk ndflush(&tp->t_outq, tp->t_outq.c_cc); 576135622Sphk break; 5771541Srgrimes 578135622Sphk case TIOCSIG: 579135622Sphk if (*(unsigned int *)data >= NSIG || 580135622Sphk *(unsigned int *)data == 0) 581135622Sphk return(EINVAL); 582135622Sphk if ((tp->t_lflag&NOFLSH) == 0) 583135622Sphk ttyflush(tp, FREAD|FWRITE); 584135622Sphk if (tp->t_pgrp != NULL) { 585135622Sphk PGRP_LOCK(tp->t_pgrp); 586135622Sphk pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 587135622Sphk PGRP_UNLOCK(tp->t_pgrp); 5881541Srgrimes } 589135622Sphk if ((*(unsigned int *)data == SIGINFO) && 590135622Sphk ((tp->t_lflag&NOKERNINFO) == 0)) 591135622Sphk ttyinfo(tp); 592135622Sphk return(0); 59347203Sluoqi } 594135622Sphk 595135622Sphk return (ptsioctl(dev, cmd, data, flag, td)); 596135622Sphk} 597135622Sphk 598135622Sphk/*ARGSUSED*/ 599135622Sphkstatic int 600135622Sphkptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 601135622Sphk{ 602135622Sphk struct tty *tp = dev->si_tty; 603135622Sphk struct ptsc *pt = dev->si_drv1; 604135622Sphk u_char *cc = tp->t_cc; 605135622Sphk int stop, error; 606135622Sphk 60747301Sluoqi if (cmd == TIOCEXT) { 60847301Sluoqi /* 60947301Sluoqi * When the EXTPROC bit is being toggled, we need 61047301Sluoqi * to send an TIOCPKT_IOCTL if the packet driver 61147301Sluoqi * is turned on. 61247301Sluoqi */ 61347301Sluoqi if (*(int *)data) { 614130263Sphk if (pt->pt_flags & PF_PKT) { 615130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61647301Sluoqi ptcwakeup(tp, FREAD); 61747301Sluoqi } 61847301Sluoqi tp->t_lflag |= EXTPROC; 61947301Sluoqi } else { 62047301Sluoqi if ((tp->t_lflag & EXTPROC) && 621130263Sphk (pt->pt_flags & PF_PKT)) { 622130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 62347301Sluoqi ptcwakeup(tp, FREAD); 62447301Sluoqi } 62547301Sluoqi tp->t_lflag &= ~EXTPROC; 62647301Sluoqi } 62747301Sluoqi return(0); 62847301Sluoqi } 629130054Sphk error = ttyioctl(dev, cmd, data, flag, td); 630130054Sphk if (error == ENOTTY) { 631130263Sphk if (pt->pt_flags & PF_UCNTL && 6321541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 6331541Srgrimes if (cmd & 0xff) { 634130263Sphk pt->pt_ucntl = (u_char)cmd; 6351541Srgrimes ptcwakeup(tp, FREAD); 6361541Srgrimes } 6371541Srgrimes return (0); 6381541Srgrimes } 6391541Srgrimes error = ENOTTY; 6401541Srgrimes } 6411541Srgrimes /* 6421541Srgrimes * If external processing and packet mode send ioctl packet. 6431541Srgrimes */ 644130263Sphk if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) { 6451541Srgrimes switch(cmd) { 6461541Srgrimes case TIOCSETA: 6471541Srgrimes case TIOCSETAW: 6481541Srgrimes case TIOCSETAF: 649130892Sphk#ifndef BURN_BRIDGES 6501541Srgrimes#ifdef COMPAT_43 6511541Srgrimes case TIOCSETP: 6521541Srgrimes case TIOCSETN: 6531541Srgrimes case TIOCSETC: 6541541Srgrimes case TIOCSLTC: 6551541Srgrimes case TIOCLBIS: 6561541Srgrimes case TIOCLBIC: 6571541Srgrimes case TIOCLSET: 6581541Srgrimes#endif 659130892Sphk#endif 660130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 6611541Srgrimes ptcwakeup(tp, FREAD); 662115463Sphk break; 6631541Srgrimes default: 6641541Srgrimes break; 6651541Srgrimes } 6661541Srgrimes } 6678876Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 6681541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 669130263Sphk if (pt->pt_flags & PF_NOSTOP) { 6701541Srgrimes if (stop) { 671130263Sphk pt->pt_send &= ~TIOCPKT_NOSTOP; 672130263Sphk pt->pt_send |= TIOCPKT_DOSTOP; 673130263Sphk pt->pt_flags &= ~PF_NOSTOP; 6741541Srgrimes ptcwakeup(tp, FREAD); 6751541Srgrimes } 6761541Srgrimes } else { 6771541Srgrimes if (!stop) { 678130263Sphk pt->pt_send &= ~TIOCPKT_DOSTOP; 679130263Sphk pt->pt_send |= TIOCPKT_NOSTOP; 680130263Sphk pt->pt_flags |= PF_NOSTOP; 6811541Srgrimes ptcwakeup(tp, FREAD); 6821541Srgrimes } 6831541Srgrimes } 6841541Srgrimes return (error); 6851541Srgrimes} 68612517Sjulian 68712675Sjulianstatic void 688130585Sphkpty_clone(void *arg, char *name, int namelen, struct cdev **dev) 68964880Sphk{ 69064880Sphk int u; 69164880Sphk 692130640Sphk if (*dev != NULL) 69364880Sphk return; 69464880Sphk if (bcmp(name, "pty", 3) != 0) 69564880Sphk return; 69664880Sphk if (name[5] != '\0') 69764880Sphk return; 69864880Sphk switch (name[3]) { 69964880Sphk case 'p': u = 0; break; 70064880Sphk case 'q': u = 32; break; 70164880Sphk case 'r': u = 64; break; 70264880Sphk case 's': u = 96; break; 70364880Sphk case 'P': u = 128; break; 70464880Sphk case 'Q': u = 160; break; 70564880Sphk case 'R': u = 192; break; 70664880Sphk case 'S': u = 224; break; 70764880Sphk default: return; 70864880Sphk } 70964880Sphk if (name[4] >= '0' && name[4] <= '9') 71064880Sphk u += name[4] - '0'; 71164880Sphk else if (name[4] >= 'a' && name[4] <= 'v') 71264880Sphk u += name[4] - 'a' + 10; 71364880Sphk else 71464880Sphk return; 71577176Sphk *dev = make_dev(&ptc_cdevsw, u, 71677176Sphk UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); 71777176Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 71864880Sphk return; 71964880Sphk} 72064880Sphk 72164880Sphkstatic void 722130262Sphkptc_drvinit(void *unused) 72312517Sjulian{ 724108363Sphk 72565374Sphk EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 72612517Sjulian} 72712517Sjulian 72812517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) 729