pty.c revision 9639
121308Sache/* 221308Sache * Copyright (c) 1982, 1986, 1989, 1993 321308Sache * The Regents of the University of California. All rights reserved. 421308Sache * 521308Sache * Redistribution and use in source and binary forms, with or without 621308Sache * modification, are permitted provided that the following conditions 721308Sache * are met: 821308Sache * 1. Redistributions of source code must retain the above copyright 921308Sache * notice, this list of conditions and the following disclaimer. 1058314Sache * 2. Redistributions in binary form must reproduce the above copyright 1121308Sache * notice, this list of conditions and the following disclaimer in the 1221308Sache * documentation and/or other materials provided with the distribution. 1321308Sache * 3. All advertising materials mentioning features or use of this software 1421308Sache * must display the following acknowledgement: 1521308Sache * This product includes software developed by the University of 1621308Sache * California, Berkeley and its contributors. 1721308Sache * 4. Neither the name of the University nor the names of its contributors 1821308Sache * may be used to endorse or promote products derived from this software 1921308Sache * without specific prior written permission. 2021308Sache * 2158314Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22119614Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2321308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2421308Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2521308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2621308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2721308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2821308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2921308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3021308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3121308Sache * SUCH DAMAGE. 3221308Sache * 3321308Sache * @(#)tty_pty.c 8.2 (Berkeley) 9/23/93 3421308Sache * $Id: tty_pty.c,v 1.14 1995/07/22 01:30:32 bde Exp $ 3521308Sache */ 3621308Sache 3721308Sache/* 3821308Sache * Pseudo-teletype Driver 3921308Sache * (Actually two drivers, requiring two entries in 'cdevsw') 4021308Sache */ 4121308Sache#include "pty.h" /* XXX */ 4221308Sache 4321308Sache#include <sys/param.h> 4421308Sache#include <sys/systm.h> 4521308Sache#include <sys/ioctl.h> 4621308Sache#include <sys/proc.h> 4721308Sache#include <sys/tty.h> 4821308Sache#include <sys/conf.h> 4921308Sache#include <sys/file.h> 5021308Sache#include <sys/uio.h> 5121308Sache#include <sys/kernel.h> 5221308Sache#include <sys/vnode.h> 5321308Sache#include <sys/signalvar.h> 5421308Sache 5526497Sache#if NPTY == 1 5626497Sache#undef NPTY 5726497Sache#define NPTY 32 /* crude XXX */ 5826497Sache#endif 5926497Sache 6021308Sache#define BUFSIZ 100 /* Chunk size iomoved to/from user */ 6121308Sache 6221308Sache/* 6321308Sache * pts == /dev/tty[pqrs]? 6421308Sache * ptc == /dev/pty[pqrs]? 6521308Sache */ 6658314Sachestruct tty pt_tty[NPTY]; /* XXX */ 6758314Sachestruct pt_ioctl { 68119614Sache int pt_flags; 6921308Sache struct selinfo pt_selr, pt_selw; 70119614Sache u_char pt_send; 71119614Sache u_char pt_ucntl; 72119614Sache} pt_ioctl[NPTY]; /* XXX */ 7321308Sacheint npty = NPTY; /* for pstat -t */ 7421308Sache 7521308Sache#define PF_PKT 0x08 /* packet mode */ 7621308Sache#define PF_STOPPED 0x10 /* user told stopped */ 7721308Sache#define PF_REMOTE 0x20 /* remote and flow controlled input */ 7821308Sache#define PF_NOSTOP 0x40 7921308Sache#define PF_UCNTL 0x80 /* user control mode */ 8021308Sache 8121308Sachevoid ptsstop __P((struct tty *, int)); 8221308Sachevoid ptcwakeup __P((struct tty *, int)); 8321308Sache 8421308Sache/* 8526497Sache * Establish n (or default if n is 1) ptys in the system. 8626497Sache * 8726497Sache * XXX cdevsw & pstat require the array `pty[]' to be an array 8826497Sache */ 8921308Sachevoid 9021308Sacheptyattach(n) 9121308Sache int n; 9275409Sache{ 9375409Sache#ifdef notyet 9475409Sache char *mem; 9575409Sache register u_long ntb; 9675409Sache#define DEFAULT_NPTY 32 9775409Sache 9821308Sache /* maybe should allow 0 => none? */ 9921308Sache if (n <= 1) 10075409Sache n = DEFAULT_NPTY; 10121308Sache ntb = n * sizeof(struct tty); 10221308Sache mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl), 10375409Sache M_DEVBUF, M_WAITOK); 10475409Sache pt_tty = (struct tty *)mem; 10575409Sache mem = (char *)ALIGN(mem + ntb); 10675409Sache pt_ioctl = (struct pt_ioctl *)mem; 10775409Sache npty = n; 10821308Sache#endif 10921308Sache} 11075409Sache 11175409Sache/*ARGSUSED*/ 11221308Sacheint 11321308Sacheptsopen(dev, flag, devtype, p) 11475409Sache dev_t dev; 11521308Sache int flag, devtype; 11621308Sache struct proc *p; 11721308Sache{ 11875409Sache register struct tty *tp; 11921308Sache int error; 12075409Sache 12175409Sache if (minor(dev) >= npty) 12221308Sache return (ENXIO); 12321308Sache tp = &pt_tty[minor(dev)]; 12421308Sache if ((tp->t_state & TS_ISOPEN) == 0) { 12521308Sache ttychars(tp); /* Set up default chars */ 12621308Sache tp->t_iflag = TTYDEF_IFLAG; 12721308Sache tp->t_oflag = TTYDEF_OFLAG; 12821308Sache tp->t_lflag = TTYDEF_LFLAG; 12921308Sache tp->t_cflag = TTYDEF_CFLAG; 13075409Sache tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 13175409Sache ttsetwater(tp); /* would be done in xxparam() */ 13275409Sache } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 13321308Sache return (EBUSY); 13421308Sache if (tp->t_oproc) /* Ctrlr still around. */ 13575409Sache tp->t_state |= TS_CARR_ON; 13675409Sache while ((tp->t_state & TS_CARR_ON) == 0) { 13775409Sache if (flag&FNONBLOCK) 13875409Sache break; 13921308Sache error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, 14021308Sache "ptsopn", 0); 14175409Sache if (error) 14275409Sache return (error); 14321308Sache } 14421308Sache error = (*linesw[tp->t_line].l_open)(dev, tp); 14575409Sache if (error == 0) 14675409Sache ptcwakeup(tp, FREAD|FWRITE); 147119614Sache return (error); 14821308Sache} 149119614Sache 150119614Sacheint 151119614Sacheptsclose(dev, flag, mode, p) 152119614Sache dev_t dev; 153119614Sache int flag, mode; 154119614Sache struct proc *p; 155119614Sache{ 156119614Sache register struct tty *tp; 157119614Sache int err; 15821308Sache 15975409Sache tp = &pt_tty[minor(dev)]; 16021308Sache err = (*linesw[tp->t_line].l_close)(tp, flag); 16121308Sache ptsstop(tp, FREAD|FWRITE); 16221308Sache (void) ttyclose(tp); 16321308Sache return (err); 16421308Sache} 16521308Sache 16621308Sacheint 16758314Sacheptsread(dev, uio, flag) 16858314Sache dev_t dev; 16958314Sache struct uio *uio; 17058314Sache int flag; 17158314Sache{ 17258314Sache struct proc *p = curproc; 17358314Sache register struct tty *tp = &pt_tty[minor(dev)]; 17458314Sache register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 17558314Sache int error = 0; 17658314Sache 17758314Sacheagain: 17858314Sache if (pti->pt_flags & PF_REMOTE) { 17958314Sache while (isbackground(p, tp)) { 18058314Sache if ((p->p_sigignore & sigmask(SIGTTIN)) || 18158314Sache (p->p_sigmask & sigmask(SIGTTIN)) || 18258314Sache p->p_pgrp->pg_jobc == 0 || 18321308Sache p->p_flag & P_PPWAIT) 18421308Sache return (EIO); 18521308Sache pgsignal(p->p_pgrp, SIGTTIN, 1); 18621308Sache error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg", 18721308Sache 0); 18821308Sache if (error) 18921308Sache return (error); 19021308Sache } 19121308Sache if (tp->t_canq.c_cc == 0) { 19221308Sache if (flag & IO_NDELAY) 19321308Sache return (EWOULDBLOCK); 19421308Sache error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH, 19521308Sache "ptsin", 0); 19621308Sache if (error) 19721308Sache return (error); 19821308Sache goto again; 19975409Sache } 20075409Sache while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 20121308Sache if (ureadc(getc(&tp->t_canq), uio) < 0) { 20221308Sache error = EFAULT; 20321308Sache break; 20426497Sache } 20575409Sache if (tp->t_canq.c_cc == 1) 20626497Sache (void) getc(&tp->t_canq); 20726497Sache if (tp->t_canq.c_cc) 20821308Sache return (error); 20921308Sache } else 21075409Sache if (tp->t_oproc) 21121308Sache error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 21275409Sache ptcwakeup(tp, FWRITE); 21375409Sache return (error); 21421308Sache} 21558314Sache 21675409Sache/* 21775409Sache * Write to pseudo-tty. 21858314Sache * Wakeups of controlling tty will happen 21921308Sache * indirectly, when tty driver calls ptsstart. 22021308Sache */ 22121308Sacheint 22221308Sacheptswrite(dev, uio, flag) 22375409Sache dev_t dev; 22421308Sache struct uio *uio; 22575409Sache int flag; 22675409Sache{ 22721308Sache register struct tty *tp; 22858314Sache 22975409Sache tp = &pt_tty[minor(dev)]; 23075409Sache if (tp->t_oproc == 0) 23158314Sache return (EIO); 23221308Sache return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 23321308Sache} 23421308Sache 23575409Sache/* 23675409Sache * Start output on pseudo-tty. 23721308Sache * Wake up process selecting or sleeping for input from controlling tty. 23875409Sache */ 23975409Sachevoid 24021308Sacheptsstart(tp) 24121308Sache struct tty *tp; 24221308Sache{ 24321308Sache register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 24475409Sache 24521308Sache if (tp->t_state & TS_TTSTOP) 24658314Sache return; 24775409Sache if (pti->pt_flags & PF_STOPPED) { 24821308Sache pti->pt_flags &= ~PF_STOPPED; 24975409Sache pti->pt_send = TIOCPKT_START; 25021308Sache } 25121308Sache ptcwakeup(tp, FREAD); 25221308Sache} 25321308Sache 25421308Sachevoid 25521308Sacheptcwakeup(tp, flag) 25675409Sache struct tty *tp; 25775409Sache int flag; 25821308Sache{ 25975409Sache struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 26075409Sache 26175409Sache if (flag & FREAD) { 26221308Sache selwakeup(&pti->pt_selr); 26375409Sache wakeup(TSA_PTC_READ(tp)); 26421308Sache } 26575409Sache if (flag & FWRITE) { 26621308Sache selwakeup(&pti->pt_selw); 26721308Sache wakeup(TSA_PTC_WRITE(tp)); 26847558Sache } 26975409Sache} 27075409Sache 27175409Sache/*ARGSUSED*/ 27275409Sache#ifdef __STDC__ 27375409Sacheint 27475409Sacheptcopen(dev_t dev, int flag, int devtype, struct proc *p) 27575409Sache#else 27675409Sacheint 27775409Sacheptcopen(dev, flag, devtype, p) 27875409Sache dev_t dev; 27975409Sache int flag, devtype; 28075409Sache struct proc *p; 28175409Sache#endif 28275409Sache{ 28375409Sache register struct tty *tp; 28475409Sache struct pt_ioctl *pti; 28575409Sache 28647558Sache if (minor(dev) >= npty) 28747558Sache return (ENXIO); 28847558Sache tp = &pt_tty[minor(dev)]; 28947558Sache if (tp->t_oproc) 29047558Sache return (EIO); 291119614Sache tp->t_oproc = ptsstart; 292119614Sache#ifdef sun4c 293119614Sache tp->t_stop = ptsstop; 294119614Sache#endif 29547558Sache (void)(*linesw[tp->t_line].l_modem)(tp, 1); 29647558Sache tp->t_lflag &= ~EXTPROC; 29747558Sache pti = &pt_ioctl[minor(dev)]; 29821308Sache pti->pt_flags = 0; 29975409Sache pti->pt_send = 0; 30021308Sache pti->pt_ucntl = 0; 30121308Sache return (0); 30221308Sache} 30321308Sache 30421308Sacheint 30521308Sacheptcclose(dev) 30621308Sache dev_t dev; 307119614Sache{ 30875409Sache register struct tty *tp; 30975409Sache 31075409Sache tp = &pt_tty[minor(dev)]; 31175409Sache (void)(*linesw[tp->t_line].l_modem)(tp, 0); 31275409Sache tp->t_state &= ~TS_CARR_ON; 31375409Sache tp->t_oproc = 0; /* mark closed */ 31475409Sache tp->t_session = 0; 31575409Sache return (0); 31675409Sache} 317119614Sache 318119614Sacheint 31975409Sacheptcread(dev, uio, flag) 320119614Sache dev_t dev; 32175409Sache struct uio *uio; 32275409Sache int flag; 32375409Sache{ 324119614Sache register struct tty *tp = &pt_tty[minor(dev)]; 32575409Sache struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 32675409Sache char buf[BUFSIZ]; 32775409Sache int error = 0, cc; 32875409Sache 32921308Sache /* 33075409Sache * We want to block until the slave 33121308Sache * is open, and there's something to read; 33275409Sache * but if we lost the slave or we're NBIO, 33375409Sache * then return the appropriate error instead. 33475409Sache */ 335119614Sache for (;;) { 336119614Sache if (tp->t_state&TS_ISOPEN) { 33721308Sache if (pti->pt_flags&PF_PKT && pti->pt_send) { 33821308Sache error = ureadc((int)pti->pt_send, uio); 33921308Sache if (error) 34021308Sache return (error); 34121308Sache if (pti->pt_send & TIOCPKT_IOCTL) { 34221308Sache cc = min(uio->uio_resid, 34321308Sache sizeof(tp->t_termios)); 34421308Sache uiomove((caddr_t)&tp->t_termios, cc, 34521308Sache uio); 34621308Sache } 34758314Sache pti->pt_send = 0; 34821308Sache return (0); 34921308Sache } 35021308Sache if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 351119614Sache error = ureadc((int)pti->pt_ucntl, uio); 352119614Sache if (error) 353119614Sache return (error); 35421308Sache pti->pt_ucntl = 0; 355119614Sache return (0); 35658314Sache } 35721308Sache if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 35821308Sache break; 35921308Sache } 36021308Sache if ((tp->t_state&TS_CARR_ON) == 0) 36121308Sache return (0); /* EOF */ 36275409Sache if (flag & IO_NDELAY) 36321308Sache return (EWOULDBLOCK); 36475409Sache error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); 36575409Sache if (error) 36658314Sache return (error); 36721308Sache } 36875409Sache if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 36975409Sache error = ureadc(0, uio); 37058314Sache while (uio->uio_resid > 0 && error == 0) { 37175409Sache cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); 37221308Sache if (cc <= 0) 37358314Sache break; 37458314Sache error = uiomove(buf, cc, uio); 37521308Sache } 37658314Sache ttwwakeup(tp); 37758314Sache return (error); 37858314Sache} 37958314Sache 38058314Sachevoid 38158314Sacheptsstop(tp, flush) 38258314Sache register struct tty *tp; 38358314Sache int flush; 38458314Sache{ 38558314Sache struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 386119614Sache int flag; 38721308Sache 38858314Sache /* note: FLUSHREAD and FLUSHWRITE already ok */ 389119614Sache if (flush == 0) { 39021308Sache flush = TIOCPKT_STOP; 39158314Sache pti->pt_flags |= PF_STOPPED; 39221308Sache } else 39358314Sache pti->pt_flags &= ~PF_STOPPED; 39458314Sache pti->pt_send |= flush; 39521308Sache /* change of perspective */ 39658314Sache flag = 0; 39721308Sache if (flush & FREAD) 39858314Sache flag |= FWRITE; 39958314Sache if (flush & FWRITE) 40058314Sache flag |= FREAD; 40158314Sache ptcwakeup(tp, flag); 40258314Sache} 40358314Sache 40458314Sacheint 40575409Sacheptcselect(dev, rw, p) 40675409Sache dev_t dev; 40758314Sache int rw; 40858314Sache struct proc *p; 40958314Sache{ 41058314Sache register struct tty *tp = &pt_tty[minor(dev)]; 41158314Sache struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 41275409Sache int s; 41358314Sache 41475409Sache if ((tp->t_state&TS_CARR_ON) == 0) 41575409Sache return (1); 41658314Sache switch (rw) { 41758314Sache 41858314Sache case FREAD: 41975409Sache /* 42075409Sache * Need to block timeouts (ttrstart). 42175409Sache */ 42275409Sache s = spltty(); 42375409Sache if ((tp->t_state&TS_ISOPEN) && 424119614Sache tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 425119614Sache splx(s); 42675409Sache return (1); 427119614Sache } 42821308Sache splx(s); 42921308Sache /* FALLTHROUGH */ 43021308Sache 43175409Sache case 0: /* exceptional */ 43258314Sache if ((tp->t_state&TS_ISOPEN) && 43358314Sache ((pti->pt_flags&PF_PKT && pti->pt_send) || 43475409Sache (pti->pt_flags&PF_UCNTL && pti->pt_ucntl))) 43558314Sache return (1); 43658314Sache selrecord(p, &pti->pt_selr); 43775409Sache break; 43875409Sache 43958314Sache 44021308Sache case FWRITE: 44121308Sache if (tp->t_state&TS_ISOPEN) { 44221308Sache if (pti->pt_flags & PF_REMOTE) { 44321308Sache if (tp->t_canq.c_cc == 0) 44421308Sache return (1); 44521308Sache } else { 44621308Sache if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 44775409Sache return (1); 44875409Sache if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 44975409Sache return (1); 45021308Sache } 45175409Sache } 45275409Sache selrecord(p, &pti->pt_selw); 45321308Sache break; 45421308Sache 45521308Sache } 45621308Sache return (0); 45721308Sache} 45821308Sache 45921308Sacheint 46021308Sacheptcwrite(dev, uio, flag) 46121308Sache dev_t dev; 46275409Sache register struct uio *uio; 46321308Sache int flag; 46421308Sache{ 46521308Sache register struct tty *tp = &pt_tty[minor(dev)]; 46621308Sache register u_char *cp = 0; 46721308Sache register int cc = 0; 46875409Sache u_char locbuf[BUFSIZ]; 46921308Sache int cnt = 0; 47021308Sache struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 47121308Sache int error = 0; 47221308Sache 473119614Sacheagain: 47421308Sache if ((tp->t_state&TS_ISOPEN) == 0) 475119614Sache goto block; 476119614Sache if (pti->pt_flags & PF_REMOTE) { 477119614Sache if (tp->t_canq.c_cc) 478119614Sache goto block; 47921308Sache while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 480119614Sache if (cc == 0) { 481119614Sache cc = min(uio->uio_resid, BUFSIZ); 482119614Sache cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); 483119614Sache cp = locbuf; 484119614Sache error = uiomove((caddr_t)cp, cc, uio); 485119614Sache if (error) 486119614Sache return (error); 487119614Sache /* check again for safety */ 488119614Sache if ((tp->t_state&TS_ISOPEN) == 0) 489119614Sache return (EIO); 490119614Sache } 491119614Sache if (cc) 492119614Sache (void) b_to_q((char *)cp, cc, &tp->t_canq); 49375409Sache cc = 0; 49475409Sache } 49575409Sache (void) putc(0, &tp->t_canq); 49675409Sache ttwakeup(tp); 49721308Sache wakeup(TSA_PTS_READ(tp)); 49875409Sache return (0); 499119614Sache } 50021308Sache while (uio->uio_resid > 0) { 50121308Sache if (cc == 0) { 50221308Sache cc = min(uio->uio_resid, BUFSIZ); 50321308Sache cp = locbuf; 50421308Sache error = uiomove((caddr_t)cp, cc, uio); 50521308Sache if (error) 50675409Sache return (error); 50721308Sache /* check again for safety */ 50821308Sache if ((tp->t_state&TS_ISOPEN) == 0) 50921308Sache return (EIO); 51021308Sache } 51121308Sache while (cc > 0) { 51221308Sache if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 51321308Sache (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 51421308Sache wakeup(TSA_CARR_ON(tp)); 51521308Sache goto block; 51621308Sache } 51721308Sache (*linesw[tp->t_line].l_rint)(*cp++, tp); 51821308Sache cnt++; 51921308Sache cc--; 52026497Sache } 52126497Sache cc = 0; 52226497Sache } 52326497Sache return (0); 52475409Sacheblock: 52526497Sache /* 52626497Sache * Come here to wait for slave to open, for space 52726497Sache * in outq, or space in rawq. 52826497Sache */ 52926497Sache if ((tp->t_state&TS_CARR_ON) == 0) 53021308Sache return (EIO); 53135486Sache if (flag & IO_NDELAY) { 53235486Sache /* adjust for data copied in but not written */ 53335486Sache uio->uio_resid += cc; 53435486Sache if (cnt == 0) 53535486Sache return (EWOULDBLOCK); 53635486Sache return (0); 53735486Sache } 53835486Sache error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); 53921308Sache if (error) { 54021308Sache /* adjust for data copied in but not written */ 54121308Sache uio->uio_resid += cc; 54221308Sache return (error); 54321308Sache } 54421308Sache goto again; 54535486Sache} 54658314Sache 54721308Sachestruct tty * 54821308Sacheptydevtotty(dev) 54921308Sache dev_t dev; 55075409Sache{ 55121308Sache if (minor(dev) >= npty) 55221308Sache return (NULL); 55321308Sache 55421308Sache return &pt_tty[minor(dev)]; 55521308Sache} 55621308Sache 55721308Sache/*ARGSUSED*/ 55821308Sacheint 55921308Sacheptyioctl(dev, cmd, data, flag, p) 56021308Sache dev_t dev; 56121308Sache int cmd; 56221308Sache caddr_t data; 56375409Sache int flag; 56421308Sache struct proc *p; 56575409Sache{ 56621308Sache register struct tty *tp = &pt_tty[minor(dev)]; 56721308Sache register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 56821308Sache register u_char *cc = tp->t_cc; 56921308Sache int stop, error; 57021308Sache 57121308Sache /* 57221308Sache * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 57321308Sache * ttywflush(tp) will hang if there are characters in the outq. 57475409Sache */ 57521308Sache if (cmd == TIOCEXT) { 57621308Sache /* 57775409Sache * When the EXTPROC bit is being toggled, we need 57875409Sache * to send an TIOCPKT_IOCTL if the packet driver 57921308Sache * is turned on. 58021308Sache */ 58121308Sache if (*(int *)data) { 58221308Sache if (pti->pt_flags & PF_PKT) { 58321308Sache pti->pt_send |= TIOCPKT_IOCTL; 58421308Sache ptcwakeup(tp, FREAD); 58521308Sache } 58675409Sache tp->t_lflag |= EXTPROC; 58721308Sache } else { 58821308Sache if ((tp->t_state & EXTPROC) && 58921308Sache (pti->pt_flags & PF_PKT)) { 59021308Sache pti->pt_send |= TIOCPKT_IOCTL; 59121308Sache ptcwakeup(tp, FREAD); 59221308Sache } 59321308Sache tp->t_lflag &= ~EXTPROC; 59421308Sache } 59521308Sache return(0); 59675409Sache } else 59721308Sache if (cdevsw[major(dev)].d_open == ptcopen) 59875409Sache switch (cmd) { 59921308Sache 60021308Sache case TIOCGPGRP: 60121308Sache /* 60221308Sache * We aviod calling ttioctl on the controller since, 60321308Sache * in that case, tp must be the controlling terminal. 60421308Sache */ 60521308Sache *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 60621308Sache return (0); 60721308Sache 60821308Sache case TIOCPKT: 60921308Sache if (*(int *)data) { 61021308Sache if (pti->pt_flags & PF_UCNTL) 61121308Sache return (EINVAL); 61221308Sache pti->pt_flags |= PF_PKT; 61321308Sache } else 61421308Sache pti->pt_flags &= ~PF_PKT; 61521308Sache return (0); 61621308Sache 61721308Sache case TIOCUCNTL: 61826497Sache if (*(int *)data) { 61921308Sache if (pti->pt_flags & PF_PKT) 62021308Sache return (EINVAL); 62158314Sache pti->pt_flags |= PF_UCNTL; 62275409Sache } else 62375409Sache pti->pt_flags &= ~PF_UCNTL; 62458314Sache return (0); 62521308Sache 62621308Sache case TIOCREMOTE: 62721308Sache if (*(int *)data) 62821308Sache pti->pt_flags |= PF_REMOTE; 62921308Sache else 63021308Sache pti->pt_flags &= ~PF_REMOTE; 63158314Sache ttyflush(tp, FREAD|FWRITE); 63275409Sache return (0); 63375409Sache 63475409Sache#ifdef COMPAT_43 63575409Sache case TIOCSETP: 63658314Sache case TIOCSETN: 63721308Sache#endif 638119614Sache case TIOCSETD: 639119614Sache case TIOCSETA: 640119614Sache case TIOCSETAW: 641119614Sache case TIOCSETAF: 642119614Sache ndflush(&tp->t_outq, tp->t_outq.c_cc); 643119614Sache break; 644119614Sache 645119614Sache case TIOCSIG: 646119614Sache if (*(unsigned int *)data >= NSIG) 647119614Sache return(EINVAL); 648119614Sache if ((tp->t_lflag&NOFLSH) == 0) 649119614Sache ttyflush(tp, FREAD|FWRITE); 650119614Sache pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); 651119614Sache if ((*(unsigned int *)data == SIGINFO) && 652119614Sache ((tp->t_lflag&NOKERNINFO) == 0)) 653119614Sache ttyinfo(tp); 654119614Sache return(0); 655119614Sache } 656119614Sache error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 657119614Sache if (error < 0) 658119614Sache error = ttioctl(tp, cmd, data, flag); 659119614Sache if (error < 0) { 660119614Sache if (pti->pt_flags & PF_UCNTL && 661119614Sache (cmd & ~0xff) == UIOCCMD(0)) { 662119614Sache if (cmd & 0xff) { 663119614Sache pti->pt_ucntl = (u_char)cmd; 664 ptcwakeup(tp, FREAD); 665 } 666 return (0); 667 } 668 error = ENOTTY; 669 } 670 /* 671 * If external processing and packet mode send ioctl packet. 672 */ 673 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 674 switch(cmd) { 675 case TIOCSETA: 676 case TIOCSETAW: 677 case TIOCSETAF: 678#ifdef COMPAT_43 679 case TIOCSETP: 680 case TIOCSETN: 681#endif 682#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 683 case TIOCSETC: 684 case TIOCSLTC: 685 case TIOCLBIS: 686 case TIOCLBIC: 687 case TIOCLSET: 688#endif 689 pti->pt_send |= TIOCPKT_IOCTL; 690 ptcwakeup(tp, FREAD); 691 default: 692 break; 693 } 694 } 695 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 696 && CCEQ(cc[VSTART], CTRL('q')); 697 if (pti->pt_flags & PF_NOSTOP) { 698 if (stop) { 699 pti->pt_send &= ~TIOCPKT_NOSTOP; 700 pti->pt_send |= TIOCPKT_DOSTOP; 701 pti->pt_flags &= ~PF_NOSTOP; 702 ptcwakeup(tp, FREAD); 703 } 704 } else { 705 if (!stop) { 706 pti->pt_send &= ~TIOCPKT_DOSTOP; 707 pti->pt_send |= TIOCPKT_NOSTOP; 708 pti->pt_flags |= PF_NOSTOP; 709 ptcwakeup(tp, FREAD); 710 } 711 } 712 return (error); 713} 714