pty.c revision 132226
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 132226 2004-07-15 20:47:41Z 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); 15749536Sphk devs->si_drv1 = devc->si_drv1 = pt; 158130054Sphk devs->si_tty = devc->si_tty = pt->pt_tty; 159130054Sphk pt->pt_tty->t_dev = devs; 16064880Sphk return (devc); 16116322Sgpalmer} 1621541Srgrimes 1631541Srgrimes/*ARGSUSED*/ 16412675Sjulianstatic int 165130585Sphkptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) 1661541Srgrimes{ 167111742Sdes struct tty *tp; 1681541Srgrimes int error; 169130263Sphk struct ptsc *pt; 1701541Srgrimes 17149536Sphk if (!dev->si_drv1) 172111742Sdes return(ENXIO); 173130263Sphk pt = dev->si_drv1; 17450652Sphk tp = dev->si_tty; 1751541Srgrimes if ((tp->t_state & TS_ISOPEN) == 0) { 1761541Srgrimes ttychars(tp); /* Set up default chars */ 1771541Srgrimes tp->t_iflag = TTYDEF_IFLAG; 1781541Srgrimes tp->t_oflag = TTYDEF_OFLAG; 1791541Srgrimes tp->t_lflag = TTYDEF_LFLAG; 1801541Srgrimes tp->t_cflag = TTYDEF_CFLAG; 1811541Srgrimes tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 182125839Srwatson } else if (tp->t_state & TS_XCLUDE && suser(td)) 1831541Srgrimes return (EBUSY); 184130263Sphk else if (pt->pt_prison != td->td_ucred->cr_prison) 18557070Srwatson return (EBUSY); 1861541Srgrimes if (tp->t_oproc) /* Ctrlr still around. */ 187130077Sphk (void)ttyld_modem(tp, 1); 1881541Srgrimes while ((tp->t_state & TS_CARR_ON) == 0) { 1891541Srgrimes if (flag&FNONBLOCK) 1901541Srgrimes break; 1919639Sbde error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 1929624Sbde "ptsopn", 0); 1933308Sphk if (error) 1941541Srgrimes return (error); 1951541Srgrimes } 196130077Sphk error = ttyld_open(tp, dev); 1977724Sache if (error == 0) 1987724Sache ptcwakeup(tp, FREAD|FWRITE); 1991541Srgrimes return (error); 2001541Srgrimes} 2011541Srgrimes 20212675Sjulianstatic int 203130585Sphkptsclose(struct cdev *dev, int flag, int mode, struct thread *td) 2041541Srgrimes{ 205111742Sdes struct tty *tp; 2061541Srgrimes int err; 2071541Srgrimes 20850652Sphk tp = dev->si_tty; 209130077Sphk err = ttyld_close(tp, flag); 210132226Sphk (void) tty_close(tp); 2111541Srgrimes return (err); 2121541Srgrimes} 2131541Srgrimes 21412675Sjulianstatic int 215130585Sphkptsread(struct cdev *dev, struct uio *uio, int flag) 2161541Srgrimes{ 217111742Sdes struct tty *tp = dev->si_tty; 2181541Srgrimes int error = 0; 2191541Srgrimes 220131114Sphk if (tp->t_oproc) 221131114Sphk error = ttyld_read(tp, uio, flag); 2221541Srgrimes ptcwakeup(tp, FWRITE); 2231541Srgrimes return (error); 2241541Srgrimes} 2251541Srgrimes 2261541Srgrimes/* 2271541Srgrimes * Write to pseudo-tty. 2281541Srgrimes * Wakeups of controlling tty will happen 2291541Srgrimes * indirectly, when tty driver calls ptsstart. 2301541Srgrimes */ 23112675Sjulianstatic int 232130585Sphkptswrite(struct cdev *dev, struct uio *uio, int flag) 2331541Srgrimes{ 234111742Sdes struct tty *tp; 2351541Srgrimes 23650652Sphk tp = dev->si_tty; 2371541Srgrimes if (tp->t_oproc == 0) 2381541Srgrimes return (EIO); 239130077Sphk return (ttyld_write(tp, uio, flag)); 2401541Srgrimes} 2411541Srgrimes 2421541Srgrimes/* 2431541Srgrimes * Start output on pseudo-tty. 2441541Srgrimes * Wake up process selecting or sleeping for input from controlling tty. 2451541Srgrimes */ 24612819Sphkstatic void 247130262Sphkptsstart(struct tty *tp) 2481541Srgrimes{ 249130263Sphk struct ptsc *pt = tp->t_dev->si_drv1; 2501541Srgrimes 2511541Srgrimes if (tp->t_state & TS_TTSTOP) 2521541Srgrimes return; 253130263Sphk if (pt->pt_flags & PF_STOPPED) { 254130263Sphk pt->pt_flags &= ~PF_STOPPED; 255130263Sphk pt->pt_send = TIOCPKT_START; 2561541Srgrimes } 2571541Srgrimes ptcwakeup(tp, FREAD); 2581541Srgrimes} 2591541Srgrimes 26012819Sphkstatic void 261130262Sphkptcwakeup(struct tty *tp, int flag) 2621541Srgrimes{ 263130263Sphk struct ptsc *pt = tp->t_dev->si_drv1; 2641541Srgrimes 2651541Srgrimes if (flag & FREAD) { 266130263Sphk selwakeuppri(&pt->pt_selr, TTIPRI); 2679639Sbde wakeup(TSA_PTC_READ(tp)); 2681541Srgrimes } 2691541Srgrimes if (flag & FWRITE) { 270130263Sphk selwakeuppri(&pt->pt_selw, TTOPRI); 2719639Sbde wakeup(TSA_PTC_WRITE(tp)); 2721541Srgrimes } 2731541Srgrimes} 2741541Srgrimes 27512675Sjulianstatic int 276130585Sphkptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) 2771541Srgrimes{ 278111742Sdes struct tty *tp; 279130263Sphk struct ptsc *pt; 2801541Srgrimes 28149536Sphk if (!dev->si_drv1) 28277176Sphk ptyinit(dev); 28349536Sphk if (!dev->si_drv1) 284111742Sdes return(ENXIO); 28550652Sphk tp = dev->si_tty; 2861541Srgrimes if (tp->t_oproc) 2871541Srgrimes return (EIO); 28859818Sache tp->t_timeout = -1; 2891541Srgrimes tp->t_oproc = ptsstart; 29051654Sphk tp->t_stop = ptsstop; 291130077Sphk (void)ttyld_modem(tp, 1); 2921541Srgrimes tp->t_lflag &= ~EXTPROC; 293130263Sphk pt = dev->si_drv1; 294130263Sphk pt->pt_prison = td->td_ucred->cr_prison; 295130263Sphk pt->pt_flags = 0; 296130263Sphk pt->pt_send = 0; 297130263Sphk pt->pt_ucntl = 0; 2981541Srgrimes return (0); 2991541Srgrimes} 3001541Srgrimes 30112675Sjulianstatic int 302130585Sphkptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) 3031541Srgrimes{ 304111742Sdes struct tty *tp; 3051541Srgrimes 30650652Sphk tp = dev->si_tty; 307130077Sphk (void)ttyld_modem(tp, 0); 3089824Sbde 3099824Sbde /* 3109824Sbde * XXX MDMBUF makes no sense for ptys but would inhibit the above 3119824Sbde * l_modem(). CLOCAL makes sense but isn't supported. Special 3129824Sbde * l_modem()s that ignore carrier drop make no sense for ptys but 3139824Sbde * may be in use because other parts of the line discipline make 3149824Sbde * sense for ptys. Recover by doing everything that a normal 3159824Sbde * ttymodem() would have done except for sending a SIGHUP. 3169824Sbde */ 3179850Sbde if (tp->t_state & TS_ISOPEN) { 3189850Sbde tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); 3199850Sbde tp->t_state |= TS_ZOMBIE; 3209850Sbde ttyflush(tp, FREAD | FWRITE); 3219850Sbde } 3229824Sbde 3231541Srgrimes tp->t_oproc = 0; /* mark closed */ 3241541Srgrimes return (0); 3251541Srgrimes} 3261541Srgrimes 32712675Sjulianstatic int 328130585Sphkptcread(struct cdev *dev, struct uio *uio, int flag) 3291541Srgrimes{ 330111742Sdes struct tty *tp = dev->si_tty; 331130263Sphk struct ptsc *pt = dev->si_drv1; 3321541Srgrimes char buf[BUFSIZ]; 3331541Srgrimes int error = 0, cc; 3341541Srgrimes 3351541Srgrimes /* 3361541Srgrimes * We want to block until the slave 3371541Srgrimes * is open, and there's something to read; 3381541Srgrimes * but if we lost the slave or we're NBIO, 3391541Srgrimes * then return the appropriate error instead. 3401541Srgrimes */ 3411541Srgrimes for (;;) { 3421541Srgrimes if (tp->t_state&TS_ISOPEN) { 343130263Sphk if (pt->pt_flags&PF_PKT && pt->pt_send) { 344130263Sphk error = ureadc((int)pt->pt_send, uio); 3451541Srgrimes if (error) 3461541Srgrimes return (error); 347130263Sphk if (pt->pt_send & TIOCPKT_IOCTL) { 3481541Srgrimes cc = min(uio->uio_resid, 3491541Srgrimes sizeof(tp->t_termios)); 350111741Sdes uiomove(&tp->t_termios, cc, uio); 3511541Srgrimes } 352130263Sphk pt->pt_send = 0; 3531541Srgrimes return (0); 3541541Srgrimes } 355130263Sphk if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { 356130263Sphk error = ureadc((int)pt->pt_ucntl, uio); 3571541Srgrimes if (error) 3581541Srgrimes return (error); 359130263Sphk pt->pt_ucntl = 0; 3601541Srgrimes return (0); 3611541Srgrimes } 3621541Srgrimes if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 3631541Srgrimes break; 3641541Srgrimes } 3659824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 3661541Srgrimes return (0); /* EOF */ 3671541Srgrimes if (flag & IO_NDELAY) 3681541Srgrimes return (EWOULDBLOCK); 3699639Sbde error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 3703308Sphk if (error) 3711541Srgrimes return (error); 3721541Srgrimes } 373130263Sphk if (pt->pt_flags & (PF_PKT|PF_UCNTL)) 3741541Srgrimes error = ureadc(0, uio); 3751541Srgrimes while (uio->uio_resid > 0 && error == 0) { 3761541Srgrimes cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 3771541Srgrimes if (cc <= 0) 3781541Srgrimes break; 3791541Srgrimes error = uiomove(buf, cc, uio); 3801541Srgrimes } 3819626Sbde ttwwakeup(tp); 3821541Srgrimes return (error); 3831541Srgrimes} 3841541Srgrimes 38512675Sjulianstatic void 386130262Sphkptsstop(struct tty *tp, int flush) 3871541Srgrimes{ 388130263Sphk struct ptsc *pt = tp->t_dev->si_drv1; 3891541Srgrimes int flag; 3901541Srgrimes 3911541Srgrimes /* note: FLUSHREAD and FLUSHWRITE already ok */ 3921541Srgrimes if (flush == 0) { 3931541Srgrimes flush = TIOCPKT_STOP; 394130263Sphk pt->pt_flags |= PF_STOPPED; 3951541Srgrimes } else 396130263Sphk pt->pt_flags &= ~PF_STOPPED; 397130263Sphk pt->pt_send |= flush; 3981541Srgrimes /* change of perspective */ 3991541Srgrimes flag = 0; 4001541Srgrimes if (flush & FREAD) 4011541Srgrimes flag |= FWRITE; 4021541Srgrimes if (flush & FWRITE) 4031541Srgrimes flag |= FREAD; 4041541Srgrimes ptcwakeup(tp, flag); 4051541Srgrimes} 4061541Srgrimes 40712675Sjulianstatic int 408130585Sphkptcpoll(struct cdev *dev, int events, struct thread *td) 4091541Srgrimes{ 410111742Sdes struct tty *tp = dev->si_tty; 411130263Sphk struct ptsc *pt = dev->si_drv1; 41229354Speter int revents = 0; 4131541Srgrimes int s; 4141541Srgrimes 4159824Sbde if ((tp->t_state & TS_CONNECTED) == 0) 416120513Sphk return (events & 417120513Sphk (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); 4181541Srgrimes 41929354Speter /* 42029354Speter * Need to block timeouts (ttrstart). 42129354Speter */ 42229354Speter s = spltty(); 4231541Srgrimes 42429354Speter if (events & (POLLIN | POLLRDNORM)) 42529354Speter if ((tp->t_state & TS_ISOPEN) && 42629354Speter ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || 427130263Sphk ((pt->pt_flags & PF_PKT) && pt->pt_send) || 428130263Sphk ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) 42929354Speter revents |= events & (POLLIN | POLLRDNORM); 4301541Srgrimes 43129354Speter if (events & (POLLOUT | POLLWRNORM)) 43229354Speter if (tp->t_state & TS_ISOPEN && 433131114Sphk (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || 43490831Sdillon (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) 43529354Speter revents |= events & (POLLOUT | POLLWRNORM); 4361541Srgrimes 43729354Speter if (events & POLLHUP) 43829354Speter if ((tp->t_state & TS_CARR_ON) == 0) 43929354Speter revents |= POLLHUP; 4401541Srgrimes 44129354Speter if (revents == 0) { 44229354Speter if (events & (POLLIN | POLLRDNORM)) 443130263Sphk selrecord(td, &pt->pt_selr); 44429354Speter 445111742Sdes if (events & (POLLOUT | POLLWRNORM)) 446130263Sphk selrecord(td, &pt->pt_selw); 4471541Srgrimes } 44829354Speter splx(s); 44929354Speter 45029354Speter return (revents); 4511541Srgrimes} 4521541Srgrimes 45312675Sjulianstatic int 454130585Sphkptcwrite(struct cdev *dev, struct uio *uio, int flag) 4551541Srgrimes{ 456111742Sdes struct tty *tp = dev->si_tty; 457111742Sdes u_char *cp = 0; 458111742Sdes int cc = 0; 4591541Srgrimes u_char locbuf[BUFSIZ]; 4601541Srgrimes int cnt = 0; 4611541Srgrimes int error = 0; 4621541Srgrimes 4631541Srgrimesagain: 4641541Srgrimes if ((tp->t_state&TS_ISOPEN) == 0) 4651541Srgrimes goto block; 46611789Sbde while (uio->uio_resid > 0 || cc > 0) { 4671541Srgrimes if (cc == 0) { 4681541Srgrimes cc = min(uio->uio_resid, BUFSIZ); 4691541Srgrimes cp = locbuf; 470111741Sdes error = uiomove(cp, cc, uio); 4711541Srgrimes if (error) 4721541Srgrimes return (error); 4731541Srgrimes /* check again for safety */ 47411789Sbde if ((tp->t_state & TS_ISOPEN) == 0) { 47511789Sbde /* adjust for data copied in but not written */ 47611789Sbde uio->uio_resid += cc; 4771541Srgrimes return (EIO); 47811789Sbde } 4791541Srgrimes } 4801541Srgrimes while (cc > 0) { 4811541Srgrimes if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 48290831Sdillon (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { 4839824Sbde wakeup(TSA_HUP_OR_INPUT(tp)); 4841541Srgrimes goto block; 4851541Srgrimes } 486130077Sphk ttyld_rint(tp, *cp++); 4871541Srgrimes cnt++; 4881541Srgrimes cc--; 4891541Srgrimes } 4901541Srgrimes cc = 0; 4911541Srgrimes } 4921541Srgrimes return (0); 4931541Srgrimesblock: 4941541Srgrimes /* 4951541Srgrimes * Come here to wait for slave to open, for space 49615199Sbde * in outq, or space in rawq, or an empty canq. 4971541Srgrimes */ 49811789Sbde if ((tp->t_state & TS_CONNECTED) == 0) { 49911789Sbde /* adjust for data copied in but not written */ 50011789Sbde uio->uio_resid += cc; 5011541Srgrimes return (EIO); 50211789Sbde } 5031541Srgrimes if (flag & IO_NDELAY) { 5041541Srgrimes /* adjust for data copied in but not written */ 5051541Srgrimes uio->uio_resid += cc; 5061541Srgrimes if (cnt == 0) 5071541Srgrimes return (EWOULDBLOCK); 5081541Srgrimes return (0); 5091541Srgrimes } 5109639Sbde error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 5113308Sphk if (error) { 5121541Srgrimes /* adjust for data copied in but not written */ 5131541Srgrimes uio->uio_resid += cc; 5141541Srgrimes return (error); 5151541Srgrimes } 5161541Srgrimes goto again; 5171541Srgrimes} 5181541Srgrimes 5191541Srgrimes/*ARGSUSED*/ 52012675Sjulianstatic int 521130585Sphkptyioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 5221541Srgrimes{ 523111742Sdes struct tty *tp = dev->si_tty; 524130263Sphk struct ptsc *pt = dev->si_drv1; 525111742Sdes u_char *cc = tp->t_cc; 5261541Srgrimes int stop, error; 5271541Srgrimes 52847301Sluoqi if (devsw(dev)->d_open == ptcopen) { 5291541Srgrimes switch (cmd) { 5301541Srgrimes 5311541Srgrimes case TIOCGPGRP: 5321541Srgrimes /* 53333826Sbde * We avoid calling ttioctl on the controller since, 5341541Srgrimes * in that case, tp must be the controlling terminal. 5351541Srgrimes */ 5361541Srgrimes *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 5371541Srgrimes return (0); 5381541Srgrimes 5391541Srgrimes case TIOCPKT: 5401541Srgrimes if (*(int *)data) { 541130263Sphk if (pt->pt_flags & PF_UCNTL) 5421541Srgrimes return (EINVAL); 543130263Sphk pt->pt_flags |= PF_PKT; 5441541Srgrimes } else 545130263Sphk pt->pt_flags &= ~PF_PKT; 5461541Srgrimes return (0); 5471541Srgrimes 5481541Srgrimes case TIOCUCNTL: 5491541Srgrimes if (*(int *)data) { 550130263Sphk if (pt->pt_flags & PF_PKT) 5511541Srgrimes return (EINVAL); 552130263Sphk pt->pt_flags |= PF_UCNTL; 5531541Srgrimes } else 554130263Sphk pt->pt_flags &= ~PF_UCNTL; 5551541Srgrimes return (0); 55647203Sluoqi } 5571541Srgrimes 55847203Sluoqi /* 559111742Sdes * The rest of the ioctls shouldn't be called until 56047301Sluoqi * the slave is open. 56147203Sluoqi */ 56247203Sluoqi if ((tp->t_state & TS_ISOPEN) == 0) 56347301Sluoqi return (EAGAIN); 56447203Sluoqi 56547203Sluoqi switch (cmd) { 566130892Sphk#ifndef BURN_BRIDGES 5671541Srgrimes#ifdef COMPAT_43 5688876Srgrimes case TIOCSETP: 5691541Srgrimes case TIOCSETN: 5701541Srgrimes#endif 571130892Sphk#endif 5721541Srgrimes case TIOCSETD: 5731541Srgrimes case TIOCSETA: 5741541Srgrimes case TIOCSETAW: 5759858Sache case TIOCSETAF: 57647301Sluoqi /* 57747301Sluoqi * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 57847301Sluoqi * ttywflush(tp) will hang if there are characters in 57947301Sluoqi * the outq. 58047301Sluoqi */ 5811541Srgrimes ndflush(&tp->t_outq, tp->t_outq.c_cc); 5821541Srgrimes break; 5831541Srgrimes 5841541Srgrimes case TIOCSIG: 58527770Sjmg if (*(unsigned int *)data >= NSIG || 58627770Sjmg *(unsigned int *)data == 0) 5871541Srgrimes return(EINVAL); 5881541Srgrimes if ((tp->t_lflag&NOFLSH) == 0) 5891541Srgrimes ttyflush(tp, FREAD|FWRITE); 59091140Stanimura if (tp->t_pgrp != NULL) { 59191140Stanimura PGRP_LOCK(tp->t_pgrp); 59291140Stanimura pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 59391140Stanimura PGRP_UNLOCK(tp->t_pgrp); 59491140Stanimura } 5951541Srgrimes if ((*(unsigned int *)data == SIGINFO) && 5961541Srgrimes ((tp->t_lflag&NOKERNINFO) == 0)) 5971541Srgrimes ttyinfo(tp); 5981541Srgrimes return(0); 5991541Srgrimes } 60047203Sluoqi } 60147301Sluoqi if (cmd == TIOCEXT) { 60247301Sluoqi /* 60347301Sluoqi * When the EXTPROC bit is being toggled, we need 60447301Sluoqi * to send an TIOCPKT_IOCTL if the packet driver 60547301Sluoqi * is turned on. 60647301Sluoqi */ 60747301Sluoqi if (*(int *)data) { 608130263Sphk if (pt->pt_flags & PF_PKT) { 609130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61047301Sluoqi ptcwakeup(tp, FREAD); 61147301Sluoqi } 61247301Sluoqi tp->t_lflag |= EXTPROC; 61347301Sluoqi } else { 61447301Sluoqi if ((tp->t_lflag & EXTPROC) && 615130263Sphk (pt->pt_flags & PF_PKT)) { 616130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 61747301Sluoqi ptcwakeup(tp, FREAD); 61847301Sluoqi } 61947301Sluoqi tp->t_lflag &= ~EXTPROC; 62047301Sluoqi } 62147301Sluoqi return(0); 62247301Sluoqi } 623130054Sphk error = ttyioctl(dev, cmd, data, flag, td); 624130054Sphk if (error == ENOTTY) { 625130263Sphk if (pt->pt_flags & PF_UCNTL && 6261541Srgrimes (cmd & ~0xff) == UIOCCMD(0)) { 6271541Srgrimes if (cmd & 0xff) { 628130263Sphk pt->pt_ucntl = (u_char)cmd; 6291541Srgrimes ptcwakeup(tp, FREAD); 6301541Srgrimes } 6311541Srgrimes return (0); 6321541Srgrimes } 6331541Srgrimes error = ENOTTY; 6341541Srgrimes } 6351541Srgrimes /* 6361541Srgrimes * If external processing and packet mode send ioctl packet. 6371541Srgrimes */ 638130263Sphk if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) { 6391541Srgrimes switch(cmd) { 6401541Srgrimes case TIOCSETA: 6411541Srgrimes case TIOCSETAW: 6421541Srgrimes case TIOCSETAF: 643130892Sphk#ifndef BURN_BRIDGES 6441541Srgrimes#ifdef COMPAT_43 6451541Srgrimes case TIOCSETP: 6461541Srgrimes case TIOCSETN: 6471541Srgrimes case TIOCSETC: 6481541Srgrimes case TIOCSLTC: 6491541Srgrimes case TIOCLBIS: 6501541Srgrimes case TIOCLBIC: 6511541Srgrimes case TIOCLSET: 6521541Srgrimes#endif 653130892Sphk#endif 654130263Sphk pt->pt_send |= TIOCPKT_IOCTL; 6551541Srgrimes ptcwakeup(tp, FREAD); 656115463Sphk break; 6571541Srgrimes default: 6581541Srgrimes break; 6591541Srgrimes } 6601541Srgrimes } 6618876Srgrimes stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 6621541Srgrimes && CCEQ(cc[VSTART], CTRL('q')); 663130263Sphk if (pt->pt_flags & PF_NOSTOP) { 6641541Srgrimes if (stop) { 665130263Sphk pt->pt_send &= ~TIOCPKT_NOSTOP; 666130263Sphk pt->pt_send |= TIOCPKT_DOSTOP; 667130263Sphk pt->pt_flags &= ~PF_NOSTOP; 6681541Srgrimes ptcwakeup(tp, FREAD); 6691541Srgrimes } 6701541Srgrimes } else { 6711541Srgrimes if (!stop) { 672130263Sphk pt->pt_send &= ~TIOCPKT_DOSTOP; 673130263Sphk pt->pt_send |= TIOCPKT_NOSTOP; 674130263Sphk pt->pt_flags |= PF_NOSTOP; 6751541Srgrimes ptcwakeup(tp, FREAD); 6761541Srgrimes } 6771541Srgrimes } 6781541Srgrimes return (error); 6791541Srgrimes} 68012517Sjulian 68112675Sjulianstatic void 682130585Sphkpty_clone(void *arg, char *name, int namelen, struct cdev **dev) 68364880Sphk{ 68464880Sphk int u; 68564880Sphk 686130640Sphk if (*dev != NULL) 68764880Sphk return; 68864880Sphk if (bcmp(name, "pty", 3) != 0) 68964880Sphk return; 69064880Sphk if (name[5] != '\0') 69164880Sphk return; 69264880Sphk switch (name[3]) { 69364880Sphk case 'p': u = 0; break; 69464880Sphk case 'q': u = 32; break; 69564880Sphk case 'r': u = 64; break; 69664880Sphk case 's': u = 96; break; 69764880Sphk case 'P': u = 128; break; 69864880Sphk case 'Q': u = 160; break; 69964880Sphk case 'R': u = 192; break; 70064880Sphk case 'S': u = 224; break; 70164880Sphk default: return; 70264880Sphk } 70364880Sphk if (name[4] >= '0' && name[4] <= '9') 70464880Sphk u += name[4] - '0'; 70564880Sphk else if (name[4] >= 'a' && name[4] <= 'v') 70664880Sphk u += name[4] - 'a' + 10; 70764880Sphk else 70864880Sphk return; 70977176Sphk *dev = make_dev(&ptc_cdevsw, u, 71077176Sphk UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); 71177176Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 71264880Sphk return; 71364880Sphk} 71464880Sphk 71564880Sphkstatic void 716130262Sphkptc_drvinit(void *unused) 71712517Sjulian{ 718108363Sphk 71965374Sphk EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); 72012517Sjulian} 72112517Sjulian 72212517SjulianSYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL) 723