pty.c revision 135298
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 135298 2004-09-16 12:07:25Z 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> 571541Srgrimes#include <sys/vnode.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; 7212675Sjulianstatic d_ioctl_t ptyioctl; 7312675Sjulianstatic d_open_t ptcopen; 7412675Sjulianstatic d_close_t ptcclose; 7512675Sjulianstatic d_read_t ptcread; 7612675Sjulianstatic d_write_t ptcwrite; 7729354Speterstatic d_poll_t ptcpoll; 7812675Sjulian 7938485Sbde#define CDEV_MAJOR_S 5 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, 86111815Sphk .d_ioctl = ptyioctl, 87111815Sphk .d_name = "pts", 88111815Sphk .d_maj = CDEV_MAJOR_S, 89126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 9038485Sbde}; 9112675Sjulian 9238485Sbde#define CDEV_MAJOR_C 6 9347625Sphkstatic struct cdevsw ptc_cdevsw = { 94126080Sphk .d_version = D_VERSION, 95111815Sphk .d_open = ptcopen, 96111815Sphk .d_close = ptcclose, 97111815Sphk .d_read = ptcread, 98111815Sphk .d_write = ptcwrite, 99111815Sphk .d_ioctl = ptyioctl, 100111815Sphk .d_poll = ptcpoll, 101111815Sphk .d_name = "ptc", 102111815Sphk .d_maj = CDEV_MAJOR_C, 103126080Sphk .d_flags = D_TTY | D_NEEDGIANT, 10438485Sbde}; 10512675Sjulian 1061541Srgrimes#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 1071541Srgrimes 108130263Sphkstruct ptsc { 1091541Srgrimes int pt_flags; 1101541Srgrimes struct selinfo pt_selr, pt_selw; 1111541Srgrimes u_char pt_send; 1121541Srgrimes u_char pt_ucntl; 113130054Sphk struct tty *pt_tty; 114130585Sphk struct cdev *devs, *devc; 11557070Srwatson struct prison *pt_prison; 11649536Sphk}; 1171541Srgrimes 1181541Srgrimes#define PF_PKT 0x08 /* packet mode */ 1191541Srgrimes#define PF_STOPPED 0x10 /* user told stopped */ 1201541Srgrimes#define PF_NOSTOP 0x40 1211541Srgrimes#define PF_UCNTL 0x80 /* user control mode */ 1221541Srgrimes 123130259Sphk#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf) 124130259Sphk#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) 125130259Sphk#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) 126130259Sphk 12777176Sphkstatic char *names = "pqrsPQRS"; 1281541Srgrimes/* 12949536Sphk * This function creates and initializes a pts/ptc pair 1301541Srgrimes * 13149536Sphk * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 13249536Sphk * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv] 13349536Sphk * 134111742Sdes * XXX: define and add mapping of upper minor bits to allow more 13549536Sphk * than 256 ptys. 1361541Srgrimes */ 137130585Sphkstatic struct cdev * 138130585Sphkptyinit(struct cdev *devc) 1391541Srgrimes{ 140130585Sphk struct cdev *devs; 141130263Sphk struct ptsc *pt; 14277176Sphk int n; 1431541Srgrimes 14477176Sphk n = minor(devc); 14549536Sphk /* For now we only map the lower 8 bits of the minor */ 14649536Sphk if (n & ~0xff) 147130640Sphk return (NULL); 14849536Sphk 14978405Sbrian devc->si_flags &= ~SI_CHEAPCLONE; 15078405Sbrian 151111119Simp pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); 15250092Sjulian pt->devs = devs = make_dev(&pts_cdevsw, n, 15366067Sphk UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); 15477176Sphk pt->devc = devc; 15549536Sphk 156130054Sphk pt->pt_tty = ttymalloc(pt->pt_tty); 157135298Sphk pt->pt_tty->t_sc = pt; 15849536Sphk devs->si_drv1 = devc->si_drv1 = pt; 159130054Sphk devs->si_tty = devc->si_tty = pt->pt_tty; 160130054Sphk pt->pt_tty->t_dev = devs; 16164880Sphk return (devc); 16216322Sgpalmer} 1631541Srgrimes 1641541Srgrimes/*ARGSUSED*/ 16512675Sjulianstatic int 166130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) 1671541Srgrimes{ 168111742Sdes struct tty *tp; 1691541Srgrimes int error; 170130263Sphk struct ptsc *pt; 1711541Srgrimes 17249536Sphk if (!dev->si_drv1) 173111742Sdes return(ENXIO); 174130263Sphk pt = dev->si_drv1; 17550652Sphk tp = dev->si_tty; 1761541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 1771541Srgrimes ttychars(tp); /* Set up default chars */ 1781541Srgrimes tp->t_iflag = TTYDEF_IFLAG; 1791541Srgrimes tp->t_oflag = TTYDEF_OFLAG; 1801541Srgrimes tp->t_lflag = TTYDEF_LFLAG; 1811541Srgrimes tp->t_cflag = TTYDEF_CFLAG; 1821541Srgrimes tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 183125839Srwatson } else if (tp->t_state & TS_XCLUDE && suser(td)) 1841541Srgrimes return (EBUSY); 185130263Sphk else if (pt->pt_prison != td->td_ucred->cr_prison) 18657070Srwatson return (EBUSY); 1871541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 188130077Sphk (void)ttyld_modem(tp, 1); 1891541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1901541Srgrimes if (flag&FNONBLOCK) 1911541Srgrimes break; 1929639Sbde error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1939624Sbde "ptsopn", 0); 1943308Sphk if (error) 1951541Srgrimes return (error); 1961541Srgrimes } 197130077Sphk error = ttyld_open(tp, dev); 1987724Sache if (error == 0) 1997724Sache ptcwakeup(tp, FREAD|FWRITE); 2001541Srgrimes return (error); 2011541Srgrimes} 2021541Srgrimes 20312675Sjulianstatic int 204130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td) 2051541Srgrimes{ 206111742Sdes struct tty *tp; 2071541Srgrimes int err; 2081541Srgrimes 20950652Sphk tp = dev->si_tty; 210130077Sphk err = ttyld_close(tp, flag); 211132226Sphk (void) tty_close(tp); 2121541Srgrimes return (err); 2131541Srgrimes} 2141541Srgrimes 21512675Sjulianstatic int 216130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag) 2171541Srgrimes{ 218111742Sdes struct tty *tp = dev->si_tty; 2191541Srgrimes int error = 0; 2201541Srgrimes 221131114Sphk if (tp->t_oproc) 222131114Sphk error = ttyld_read(tp, uio, flag); 2231541Srgrimes ptcwakeup(tp, FWRITE); 2241541Srgrimes return (error); 2251541Srgrimes} 2261541Srgrimes 2271541Srgrimes/* 2281541Srgrimes * Write to pseudo-tty. 2291541Srgrimes * Wakeups of controlling tty will happen 2301541Srgrimes * indirectly, when tty driver calls ptsstart. 2311541Srgrimes */ 23212675Sjulianstatic int 233130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag) 2341541Srgrimes{ 235111742Sdes struct tty *tp; 2361541Srgrimes 23750652Sphk tp = dev->si_tty; 2381541Srgrimes if (tp->t_oproc == 0) 2391541Srgrimes return (EIO); 240130077Sphk return (ttyld_write(tp, uio, flag)); 2411541Srgrimes} 2421541Srgrimes 2431541Srgrimes/* 2441541Srgrimes * Start output on pseudo-tty. 2451541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2461541Srgrimes */ 24712819Sphkstatic void 248130262Sphkptsstart(struct tty *tp) 2491541Srgrimes{ 250135298Sphk struct ptsc *pt = tp->t_sc; 2511541Srgrimes 2521541Srgrimes if (tp->t_state & TS_TTSTOP) 2531541Srgrimes return; 254130263Sphk if (pt->pt_flags & PF_STOPPED) { 255130263Sphk pt->pt_flags &= ~PF_STOPPED; 256130263Sphk pt->pt_send = TIOCPKT_START; 2571541Srgrimes } 2581541Srgrimes ptcwakeup(tp, FREAD); 2591541Srgrimes} 2601541Srgrimes 26112819Sphkstatic void 262130262Sphkptcwakeup(struct tty *tp, int flag) 2631541Srgrimes{ 264135298Sphk struct ptsc *pt = tp->t_sc; 2651541Srgrimes 2661541Srgrimes if (flag & FREAD) { 267130263Sphk selwakeuppri(&pt->pt_selr, TTIPRI); 2689639Sbde wakeup(TSA_PTC_READ(tp)); 2691541Srgrimes } 2701541Srgrimes if (flag & FWRITE) { 271130263Sphk selwakeuppri(&pt->pt_selw, TTOPRI); 2729639Sbde wakeup(TSA_PTC_WRITE(tp)); 2731541Srgrimes } 2741541Srgrimes} 2751541Srgrimes 27612675Sjulianstatic int 277130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) 2781541Srgrimes{ 279111742Sdes struct tty *tp; 280130263Sphk struct ptsc *pt; 2811541Srgrimes 28249536Sphk if (!dev->si_drv1) 28377176Sphk ptyinit(dev); 28449536Sphk if (!dev->si_drv1) 285111742Sdes return(ENXIO); 28650652Sphk tp = dev->si_tty; 2871541Srgrimes if (tp->t_oproc) 2881541Srgrimes return (EIO); 28959818Sache tp->t_timeout = -1; 2901541Srgrimes tp->t_oproc = ptsstart; 29151654Sphk tp->t_stop = ptsstop; 292130077Sphk (void)ttyld_modem(tp, 1); 2931541Srgrimes tp->t_lflag &= ~EXTPROC; 294130263Sphk pt = dev->si_drv1; 295130263Sphk pt->pt_prison = td->td_ucred->cr_prison; 296130263Sphk pt->pt_flags = 0; 297130263Sphk pt->pt_send = 0; 298130263Sphk pt->pt_ucntl = 0; 2991541Srgrimes return (0); 3001541Srgrimes} 3011541Srgrimes 30212675Sjulianstatic int 303130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) 3041541Srgrimes{ 305111742Sdes struct tty *tp; 3061541Srgrimes 30750652Sphk tp = dev->si_tty; 308130077Sphk (void)ttyld_modem(tp, 0); 3099824Sbde 3109824Sbde /* 3119824Sbde * XXX MDMBUF makes no sense for ptys but would inhibit the above 3129824Sbde * l_modem(). CLOCAL makes sense but isn't supported. Special 3139824Sbde * l_modem()s that ignore carrier drop make no sense for ptys but 3149824Sbde * may be in use because other parts of the line discipline make 3159824Sbde * sense for ptys. Recover by doing everything that a normal 3169824Sbde * ttymodem() would have done except for sending a SIGHUP. 3179824Sbde */ 3189850Sbde if (tp->t_state & TS_ISOPEN) { 3199850Sbde tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 3209850Sbde tp->t_state |= TS_ZOMBIE; 3219850Sbde ttyflush(tp, FREAD | FWRITE); 3229850Sbde } 3239824Sbde 3241541Srgrimes tp->t_oproc = 0; /* mark closed */ 3251541Srgrimes return (0); 3261541Srgrimes} 3271541Srgrimes 32812675Sjulianstatic int 329130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag) 3301541Srgrimes{ 331111742Sdes struct tty *tp = dev->si_tty; 332130263Sphk struct ptsc *pt = dev->si_drv1; 3331541Srgrimes char buf[BUFSIZ]; 3341541Srgrimes int error = 0, cc; 3351541Srgrimes 3361541Srgrimes /* 3371541Srgrimes * We want to block until the slave 3381541Srgrimes * is open, and there's something to read; 3391541Srgrimes * but if we lost the slave or we're NBIO, 3401541Srgrimes * then return the appropriate error instead. 3411541Srgrimes */ 3421541Srgrimes for (;;) { 3431541Srgrimes if (tp->t_state&TS_ISOPEN) { 344130263Sphk if (pt->pt_flags&PF_PKT && pt->pt_send) { 345130263Sphk error = ureadc((int)pt->pt_send, uio); 3461541Srgrimes if (error) 3471541Srgrimes return (error); 348130263Sphk if (pt->pt_send & TIOCPKT_IOCTL) { 3491541Srgrimes cc = min(uio->uio_resid, 3501541Srgrimes sizeof(tp->t_termios)); 351111741Sdes uiomove(&tp->t_termios, cc, uio); 3521541Srgrimes } 353130263Sphk pt->pt_send = 0; 3541541Srgrimes return (0); 3551541Srgrimes } 356130263Sphk if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { 357130263Sphk error = ureadc((int)pt->pt_ucntl, uio); 3581541Srgrimes if (error) 3591541Srgrimes return (error); 360130263Sphk pt->pt_ucntl = 0; 3611541Srgrimes return (0); 3621541Srgrimes } 3631541Srgrimes if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 3641541Srgrimes break; 3651541Srgrimes } 3669824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 3671541Srgrimes return (0); /* EOF */ 3681541Srgrimes if (flag & IO_NDELAY) 3691541Srgrimes return (EWOULDBLOCK); 3709639Sbde error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 3713308Sphk if (error) 3721541Srgrimes return (error); 3731541Srgrimes } 374130263Sphk if (pt->pt_flags & (PF_PKT|PF_UCNTL)) 3751541Srgrimes error = ureadc(0, uio); 3761541Srgrimes while (uio->uio_resid > 0 && error == 0) { 3771541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 3781541Srgrimes if (cc <= 0) 3791541Srgrimes break; 3801541Srgrimes error = uiomove(buf, cc, uio); 3811541Srgrimes } 3829626Sbde ttwwakeup(tp); 3831541Srgrimes return (error); 3841541Srgrimes} 3851541Srgrimes 38612675Sjulianstatic void 387130262Sphkptsstop(struct tty *tp, int flush) 3881541Srgrimes{ 389135298Sphk struct ptsc *pt = tp->t_sc; 3901541Srgrimes int flag; 3911541Srgrimes 3921541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 3931541Srgrimes if (flush == 0) { 3941541Srgrimes flush = TIOCPKT_STOP; 395130263Sphk pt->pt_flags |= PF_STOPPED; 3961541Srgrimes } else 397130263Sphk pt->pt_flags &= ~PF_STOPPED; 398130263Sphk pt->pt_send |= flush; 3991541Srgrimes /* change of perspective */ 4001541Srgrimes flag = 0; 4011541Srgrimes if (flush & FREAD) 4021541Srgrimes flag |= FWRITE; 4031541Srgrimes if (flush & FWRITE) 4041541Srgrimes flag |= FREAD; 4051541Srgrimes ptcwakeup(tp, flag); 4061541Srgrimes} 4071541Srgrimes 40812675Sjulianstatic int 409130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td) 4101541Srgrimes{ 411111742Sdes struct tty *tp = dev->si_tty; 412130263Sphk struct ptsc *pt = dev->si_drv1; 41329354Speter int revents = 0; 4141541Srgrimes int s; 4151541Srgrimes 4169824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 417120513Sphk return (events & 418120513Sphk (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); 4191541Srgrimes 42029354Speter /* 42129354Speter * Need to block timeouts (ttrstart). 42229354Speter */ 42329354Speter s = spltty(); 4241541Srgrimes 42529354Speter if (events & (POLLIN | POLLRDNORM)) 42629354Speter if ((tp->t_state & TS_ISOPEN) && 42729354Speter ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || 428130263Sphk ((pt->pt_flags & PF_PKT) && pt->pt_send) || 429130263Sphk ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) 43029354Speter revents |= events & (POLLIN | POLLRDNORM); 4311541Srgrimes 43229354Speter if (events & (POLLOUT | POLLWRNORM)) 43329354Speter if (tp->t_state & TS_ISOPEN && 434131114Sphk (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || 43590831Sdillon (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) 43629354Speter revents |= events & (POLLOUT | POLLWRNORM); 4371541Srgrimes 43829354Speter if (events & POLLHUP) 43929354Speter if ((tp->t_state & TS_CARR_ON) == 0) 44029354Speter revents |= POLLHUP; 4411541Srgrimes 44229354Speter if (revents == 0) { 44329354Speter if (events & (POLLIN | POLLRDNORM)) 444130263Sphk selrecord(td, &pt->pt_selr); 44529354Speter 446111742Sdes if (events & (POLLOUT | POLLWRNORM)) 447130263Sphk selrecord(td, &pt->pt_selw); 4481541Srgrimes } 44929354Speter splx(s); 45029354Speter 45129354Speter return (revents); 4521541Srgrimes} 4531541Srgrimes 45412675Sjulianstatic int 455130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag) 4561541Srgrimes{ 457111742Sdes struct tty *tp = dev->si_tty; 458111742Sdes u_char *cp = 0; 459111742Sdes int cc = 0; 4601541Srgrimes u_char locbuf[BUFSIZ]; 4611541Srgrimes int cnt = 0; 4621541Srgrimes int error = 0; 4631541Srgrimes 4641541Srgrimesagain: 4651541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4661541Srgrimes goto block; 46711789Sbde while (uio->uio_resid > 0 || cc > 0) { 4681541Srgrimes if (cc == 0) { 4691541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 4701541Srgrimes cp = locbuf; 471111741Sdes error = uiomove(cp, cc, uio); 4721541Srgrimes if (error) 4731541Srgrimes return (error); 4741541Srgrimes /* check again for safety */ 47511789Sbde if ((tp->t_state & TS_ISOPEN) == 0) { 47611789Sbde /* adjust for data copied in but not written */ 47711789Sbde uio->uio_resid += cc; 4781541Srgrimes return (EIO); 47911789Sbde } 4801541Srgrimes } 4811541Srgrimes while (cc > 0) { 4821541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 48390831Sdillon (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 4849824Sbde wakeup(TSA_HUP_OR_INPUT(tp)); 4851541Srgrimes goto block; 4861541Srgrimes } 487130077Sphk ttyld_rint(tp, *cp++); 4881541Srgrimes cnt++; 4891541Srgrimes cc--; 4901541Srgrimes } 4911541Srgrimes cc = 0; 4921541Srgrimes } 4931541Srgrimes return (0); 4941541Srgrimesblock: 4951541Srgrimes /* 4961541Srgrimes * Come here to wait for slave to open, for space 49715199Sbde * in outq, or space in rawq, or an empty canq. 4981541Srgrimes */ 49911789Sbde if ((tp->t_state & TS_CONNECTED) == 0) { 50011789Sbde /* adjust for data copied in but not written */ 50111789Sbde uio->uio_resid += cc; 5021541Srgrimes return (EIO); 50311789Sbde } 5041541Srgrimes if (flag & IO_NDELAY) { 5051541Srgrimes /* adjust for data copied in but not written */ 5061541Srgrimes uio->uio_resid += cc; 5071541Srgrimes if (cnt == 0) 5081541Srgrimes return (EWOULDBLOCK); 5091541Srgrimes return (0); 5101541Srgrimes } 5119639Sbde error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 5123308Sphk if (error) { 5131541Srgrimes /* adjust for data copied in but not written */ 5141541Srgrimes uio->uio_resid += cc; 5151541Srgrimes return (error); 5161541Srgrimes } 5171541Srgrimes goto again; 5181541Srgrimes} 5191541Srgrimes 5201541Srgrimes/*ARGSUSED*/ 52112675Sjulianstatic int 522130585Sphkptyioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 5231541Srgrimes{ 524111742Sdes struct tty *tp = dev->si_tty; 525130263Sphk struct ptsc *pt = dev->si_drv1; 526111742Sdes u_char *cc = tp->t_cc; 5271541Srgrimes int stop, error; 5281541Srgrimes 52947301Sluoqi if (devsw(dev)->d_open == ptcopen) { 5301541Srgrimes switch (cmd) { 5311541Srgrimes 5321541Srgrimes case TIOCGPGRP: 5331541Srgrimes /* 53433826Sbde * We avoid calling ttioctl on the controller since, 5351541Srgrimes * in that case, tp must be the controlling terminal. 5361541Srgrimes */ 5371541Srgrimes *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 5381541Srgrimes return (0); 5391541Srgrimes 5401541Srgrimes case TIOCPKT: 5411541Srgrimes if (*(int *)data) { 542130263Sphk if (pt->pt_flags & PF_UCNTL) 5431541Srgrimes return (EINVAL); 544130263Sphk pt->pt_flags |= PF_PKT; 5451541Srgrimes } else 546130263Sphk pt->pt_flags &= ~PF_PKT; 5471541Srgrimes return (0); 5481541Srgrimes 5491541Srgrimes case TIOCUCNTL: 5501541Srgrimes if (*(int *)data) { 551130263Sphk if (pt->pt_flags & PF_PKT) 5521541Srgrimes return (EINVAL); 553130263Sphk pt->pt_flags |= PF_UCNTL; 5541541Srgrimes } else 555130263Sphk pt->pt_flags &= ~PF_UCNTL; 5561541Srgrimes return (0); 55747203Sluoqi } 5581541Srgrimes 55947203Sluoqi /* 560111742Sdes * The rest of the ioctls shouldn't be called until 56147301Sluoqi * the slave is open. 56247203Sluoqi */ 56347203Sluoqi if ((tp->t_state & TS_ISOPEN) == 0) 56447301Sluoqi return (EAGAIN); 56547203Sluoqi 56647203Sluoqi switch (cmd) { 567130892Sphk#ifndef BURN_BRIDGES 5681541Srgrimes#ifdef COMPAT_43 5698876Srgrimes case TIOCSETP: 5701541Srgrimes case TIOCSETN: 5711541Srgrimes#endif 572130892Sphk#endif 5731541Srgrimes case TIOCSETD: 5741541Srgrimes case TIOCSETA: 5751541Srgrimes case TIOCSETAW: 5769858Sache case TIOCSETAF: 57747301Sluoqi /* 57847301Sluoqi * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 57947301Sluoqi * ttywflush(tp) will hang if there are characters in 58047301Sluoqi * the outq. 58147301Sluoqi */ 5821541Srgrimes ndflush(&tp->t_outq, tp->t_outq.c_cc); 5831541Srgrimes break; 5841541Srgrimes 5851541Srgrimes case TIOCSIG: 58627770Sjmg if (*(unsigned int *)data >= NSIG || 58727770Sjmg *(unsigned int *)data == 0) 5881541Srgrimes return(EINVAL); 5891541Srgrimes if ((tp->t_lflag&NOFLSH) == 0) 5901541Srgrimes ttyflush(tp, FREAD|FWRITE); 59191140Stanimura if (tp->t_pgrp != NULL) { 59291140Stanimura PGRP_LOCK(tp->t_pgrp); 59391140Stanimura pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 59491140Stanimura PGRP_UNLOCK(tp->t_pgrp); 59591140Stanimura } 5961541Srgrimes if ((*(unsigned int *)data == SIGINFO) && 5971541Srgrimes ((tp->t_lflag&NOKERNINFO) == 0)) 5981541Srgrimes ttyinfo(tp); 5991541Srgrimes return(0); 6001541Srgrimes } 60147203Sluoqi } 60247301Sluoqi if (cmd == TIOCEXT) { 60347301Sluoqi /* 60447301Sluoqi * When the EXTPROC bit is being toggled, we need 60547301Sluoqi * to send an TIOCPKT_IOCTL if the packet driver 60647301Sluoqi * is turned on. 60747301Sluoqi */ 60847301Sluoqi if (*(int *)data) { 609130263Sphk if (pt->pt_flags & PF_PKT) { 610130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61147301Sluoqi ptcwakeup(tp, FREAD); 61247301Sluoqi } 61347301Sluoqi tp->t_lflag |= EXTPROC; 61447301Sluoqi } else { 61547301Sluoqi if ((tp->t_lflag & EXTPROC) && 616130263Sphk (pt->pt_flags & PF_PKT)) { 617130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61847301Sluoqi ptcwakeup(tp, FREAD); 61947301Sluoqi } 62047301Sluoqi tp->t_lflag &= ~EXTPROC; 62147301Sluoqi } 62247301Sluoqi return(0); 62347301Sluoqi } 624130054Sphk error = ttyioctl(dev, cmd, data, flag, td); 625130054Sphk if (error == ENOTTY) { 626130263Sphk if (pt->pt_flags & PF_UCNTL && 6271541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 6281541Srgrimes if (cmd & 0xff) { 629130263Sphk pt->pt_ucntl = (u_char)cmd; 6301541Srgrimes ptcwakeup(tp, FREAD); 6311541Srgrimes } 6321541Srgrimes return (0); 6331541Srgrimes } 6341541Srgrimes error = ENOTTY; 6351541Srgrimes } 6361541Srgrimes /* 6371541Srgrimes * If external processing and packet mode send ioctl packet. 6381541Srgrimes */ 639130263Sphk if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) { 6401541Srgrimes switch(cmd) { 6411541Srgrimes case TIOCSETA: 6421541Srgrimes case TIOCSETAW: 6431541Srgrimes case TIOCSETAF: 644130892Sphk#ifndef BURN_BRIDGES 6451541Srgrimes#ifdef COMPAT_43 6461541Srgrimes case TIOCSETP: 6471541Srgrimes case TIOCSETN: 6481541Srgrimes case TIOCSETC: 6491541Srgrimes case TIOCSLTC: 6501541Srgrimes case TIOCLBIS: 6511541Srgrimes case TIOCLBIC: 6521541Srgrimes case TIOCLSET: 6531541Srgrimes#endif 654130892Sphk#endif 655130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 6561541Srgrimes ptcwakeup(tp, FREAD); 657115463Sphk break; 6581541Srgrimes default: 6591541Srgrimes break; 6601541Srgrimes } 6611541Srgrimes } 6628876Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 6631541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 664130263Sphk if (pt->pt_flags & PF_NOSTOP) { 6651541Srgrimes if (stop) { 666130263Sphk pt->pt_send &= ~TIOCPKT_NOSTOP; 667130263Sphk pt->pt_send |= TIOCPKT_DOSTOP; 668130263Sphk pt->pt_flags &= ~PF_NOSTOP; 6691541Srgrimes ptcwakeup(tp, FREAD); 6701541Srgrimes } 6711541Srgrimes } else { 6721541Srgrimes if (!stop) { 673130263Sphk pt->pt_send &= ~TIOCPKT_DOSTOP; 674130263Sphk pt->pt_send |= TIOCPKT_NOSTOP; 675130263Sphk pt->pt_flags |= PF_NOSTOP; 6761541Srgrimes ptcwakeup(tp, FREAD); 6771541Srgrimes } 6781541Srgrimes } 6791541Srgrimes return (error); 6801541Srgrimes} 68112517Sjulian 68212675Sjulianstatic void 683130585Sphkpty_clone(void *arg, char *name, int namelen, struct cdev **dev) 68464880Sphk{ 68564880Sphk int u; 68664880Sphk 687130640Sphk if (*dev != NULL) 68864880Sphk return; 68964880Sphk if (bcmp(name, "pty", 3) != 0) 69064880Sphk return; 69164880Sphk if (name[5] != '\0') 69264880Sphk return; 69364880Sphk switch (name[3]) { 69464880Sphk case 'p': u = 0; break; 69564880Sphk case 'q': u = 32; break; 69664880Sphk case 'r': u = 64; break; 69764880Sphk case 's': u = 96; break; 69864880Sphk case 'P': u = 128; break; 69964880Sphk case 'Q': u = 160; break; 70064880Sphk case 'R': u = 192; break; 70164880Sphk case 'S': u = 224; break; 70264880Sphk default: return; 70364880Sphk } 70464880Sphk if (name[4] >= '0' && name[4] <= '9') 70564880Sphk u += name[4] - '0'; 70664880Sphk else if (name[4] >= 'a' && name[4] <= 'v') 70764880Sphk u += name[4] - 'a' + 10; 70864880Sphk else 70964880Sphk return; 71077176Sphk *dev = make_dev(&ptc_cdevsw, u, 71177176Sphk UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); 71277176Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 71364880Sphk return; 71464880Sphk} 71564880Sphk 71664880Sphkstatic void 717130262Sphkptc_drvinit(void *unused) 71812517Sjulian{ 719108363Sphk 72065374Sphk EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 72112517Sjulian} 72212517Sjulian 72312517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) 724