xref: /csrg-svn/sys/kern/tty_pty.c (revision 17096)
1*17096Sbloom /*	tty_pty.c	6.6	84/08/29	*/
22283Stoy 
32281Stoy /*
42281Stoy  * Pseudo-teletype Driver
52281Stoy  * (Actually two drivers, requiring two entries in 'cdevsw')
62281Stoy  */
72314Stoy #include "pty.h"
82314Stoy 
93206Swnj #if NPTY > 0
10*17096Sbloom #include "param.h"
11*17096Sbloom #include "systm.h"
12*17096Sbloom #include "ioctl.h"
13*17096Sbloom #include "tty.h"
14*17096Sbloom #include "dir.h"
15*17096Sbloom #include "user.h"
16*17096Sbloom #include "conf.h"
17*17096Sbloom #include "file.h"
18*17096Sbloom #include "proc.h"
19*17096Sbloom #include "uio.h"
20*17096Sbloom #include "kernel.h"
216239Sroot 
227475Ssam #if NPTY == 1
235408Swnj #undef	NPTY
246239Sroot #define	NPTY	32		/* crude XXX */
257475Ssam #endif
262281Stoy 
2716788Ssam #define BUFSIZ 100		/* Chunk size iomoved to/from user */
284484Swnj 
292281Stoy /*
304484Swnj  * pts == /dev/tty[pP]?
314484Swnj  * ptc == /dev/ptp[pP]?
322281Stoy  */
334484Swnj struct	tty pt_tty[NPTY];
344484Swnj struct	pt_ioctl {
355427Swnj 	int	pt_flags;
365427Swnj 	int	pt_gensym;
375427Swnj 	struct	proc *pt_selr, *pt_selw;
385427Swnj 	int	pt_send;
394484Swnj } pt_ioctl[NPTY];
402281Stoy 
415427Swnj #define	PF_RCOLL	0x01
425427Swnj #define	PF_WCOLL	0x02
435427Swnj #define	PF_NBIO		0x04
445427Swnj #define	PF_PKT		0x08		/* packet mode */
455574Swnj #define	PF_STOPPED	0x10		/* user told stopped */
465894Swnj #define	PF_REMOTE	0x20		/* remote and flow controlled input */
476119Swnj #define	PF_NOSTOP	0x40
482281Stoy 
492281Stoy /*ARGSUSED*/
502281Stoy ptsopen(dev, flag)
515396Sroot 	dev_t dev;
524484Swnj {
532281Stoy 	register struct tty *tp;
542281Stoy 
558563Sroot 	if (minor(dev) >= NPTY)
568563Sroot 		return (ENXIO);
572281Stoy 	tp = &pt_tty[minor(dev)];
585408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
592427Swnj 		ttychars(tp);		/* Set up default chars */
6012642Ssam 		tp->t_ispeed = tp->t_ospeed = EXTB;
612427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
628563Sroot 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
638563Sroot 		return (EBUSY);
644484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
655408Swnj 		tp->t_state |= TS_CARR_ON;
665408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
675408Swnj 		tp->t_state |= TS_WOPEN;
682281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
692281Stoy 	}
708563Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
712281Stoy }
722281Stoy 
732281Stoy ptsclose(dev)
745396Sroot 	dev_t dev;
755408Swnj {
762281Stoy 	register struct tty *tp;
772281Stoy 
782281Stoy 	tp = &pt_tty[minor(dev)];
792281Stoy 	(*linesw[tp->t_line].l_close)(tp);
806299Swnj 	ttyclose(tp);
8116788Ssam 	ptcwakeup(tp);
822281Stoy }
832281Stoy 
847823Sroot ptsread(dev, uio)
855396Sroot 	dev_t dev;
867823Sroot 	struct uio *uio;
874484Swnj {
885894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
895894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
908521Sroot 	int error = 0;
912281Stoy 
925894Swnj again:
935894Swnj 	if (pti->pt_flags & PF_REMOTE) {
945894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
9515144Skarels #define bit(a) (1<<(a-1))
9615144Skarels 			if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
9715144Skarels 			    (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
985894Swnj 	/*
995894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
1005894Swnj 	*/
1015894Swnj 			    u.u_procp->p_flag&SVFORK)
1028521Sroot 				return (EIO);
1035894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
1045894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1055408Swnj 		}
10615144Skarels #undef	bit
1075894Swnj 		if (tp->t_rawq.c_cc == 0) {
1088521Sroot 			if (tp->t_state & TS_NBIO)
1098521Sroot 				return (EWOULDBLOCK);
1105894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1115894Swnj 			goto again;
1125894Swnj 		}
1137823Sroot 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
1147823Sroot 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
1158521Sroot 				error = EFAULT;
1167823Sroot 				break;
1177823Sroot 			}
1185894Swnj 		if (tp->t_rawq.c_cc == 1)
1195894Swnj 			(void) getc(&tp->t_rawq);
1205894Swnj 		if (tp->t_rawq.c_cc)
1218521Sroot 			return (error);
1225894Swnj 	} else
1235894Swnj 		if (tp->t_oproc)
1248521Sroot 			error = (*linesw[tp->t_line].l_read)(tp, uio);
1255894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
1265894Swnj 	if (pti->pt_selw) {
1275894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
1285894Swnj 		pti->pt_selw = 0;
1295894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1302281Stoy 	}
1318521Sroot 	return (error);
1322281Stoy }
1332281Stoy 
1345408Swnj /*
1355408Swnj  * Write to pseudo-tty.
1365408Swnj  * Wakeups of controlling tty will happen
1375408Swnj  * indirectly, when tty driver calls ptsstart.
1385408Swnj  */
1397823Sroot ptswrite(dev, uio)
1405396Sroot 	dev_t dev;
1417823Sroot 	struct uio *uio;
1424484Swnj {
1432281Stoy 	register struct tty *tp;
1442281Stoy 
1452281Stoy 	tp = &pt_tty[minor(dev)];
1468521Sroot 	if (tp->t_oproc == 0)
1478521Sroot 		return (EIO);
1488521Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
1492281Stoy }
1502281Stoy 
1515408Swnj /*
1525408Swnj  * Start output on pseudo-tty.
1535408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1545408Swnj  */
1552281Stoy ptsstart(tp)
1564484Swnj 	struct tty *tp;
1574484Swnj {
1585574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1594484Swnj 
1605408Swnj 	if (tp->t_state & TS_TTSTOP)
1612281Stoy 		return;
1625574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1635574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1645574Swnj 		pti->pt_send = TIOCPKT_START;
1655574Swnj 	}
1665430Swnj 	ptcwakeup(tp);
1675430Swnj }
1685430Swnj 
1695430Swnj ptcwakeup(tp)
1705430Swnj 	struct tty *tp;
1715430Swnj {
1725430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1735430Swnj 
1745427Swnj 	if (pti->pt_selr) {
1755427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1765427Swnj 		pti->pt_selr = 0;
1775427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1784484Swnj 	}
1792281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1802281Stoy }
1812281Stoy 
1822281Stoy /*ARGSUSED*/
1832281Stoy ptcopen(dev, flag)
1844484Swnj 	dev_t dev;
1854484Swnj 	int flag;
1864484Swnj {
1872281Stoy 	register struct tty *tp;
1885427Swnj 	struct pt_ioctl *pti;
1892281Stoy 
1908563Sroot 	if (minor(dev) >= NPTY)
1918563Sroot 		return (ENXIO);
1922281Stoy 	tp = &pt_tty[minor(dev)];
1938563Sroot 	if (tp->t_oproc)
1948563Sroot 		return (EIO);
1954484Swnj 	tp->t_oproc = ptsstart;
1965408Swnj 	if (tp->t_state & TS_WOPEN)
1972281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1985408Swnj 	tp->t_state |= TS_CARR_ON;
1995427Swnj 	pti = &pt_ioctl[minor(dev)];
2005427Swnj 	pti->pt_flags = 0;
2015427Swnj 	pti->pt_send = 0;
2028563Sroot 	return (0);
2032281Stoy }
2042281Stoy 
2052281Stoy ptcclose(dev)
2064484Swnj 	dev_t dev;
2074484Swnj {
2082281Stoy 	register struct tty *tp;
2092281Stoy 
2102281Stoy 	tp = &pt_tty[minor(dev)];
2115408Swnj 	if (tp->t_state & TS_ISOPEN)
2122281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2135408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
21412753Ssam 	ttyflush(tp, FREAD|FWRITE);
2154484Swnj 	tp->t_oproc = 0;		/* mark closed */
2162281Stoy }
2172281Stoy 
2187823Sroot ptcread(dev, uio)
2195427Swnj 	dev_t dev;
2207823Sroot 	struct uio *uio;
2214484Swnj {
2228521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
2235427Swnj 	struct pt_ioctl *pti;
22416788Ssam 	char buf[BUFSIZ];
22516788Ssam 	int error = 0, cc;
2262281Stoy 
2275408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2288590Sroot 		return (EIO);
2295427Swnj 	pti = &pt_ioctl[minor(dev)];
2305427Swnj 	if (pti->pt_flags & PF_PKT) {
2315427Swnj 		if (pti->pt_send) {
2328521Sroot 			error = ureadc(pti->pt_send, uio);
2338521Sroot 			if (error)
2348521Sroot 				return (error);
2355427Swnj 			pti->pt_send = 0;
2368521Sroot 			return (0);
2375427Swnj 		}
2388521Sroot 		error = ureadc(0, uio);
2395427Swnj 	}
2405411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
24116788Ssam 		if ((tp->t_state&TS_CARR_ON) == 0)
24216788Ssam 			return (EIO);
2438521Sroot 		if (pti->pt_flags&PF_NBIO)
2448521Sroot 			return (EWOULDBLOCK);
2452281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2465411Swnj 	}
24716788Ssam 	while (uio->uio_resid > 0 && error == 0) {
24816788Ssam 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
24916788Ssam 		if (cc <= 0)
2507823Sroot 			break;
25116788Ssam 		error = uiomove(buf, cc, UIO_READ, uio);
25216788Ssam 	}
2535408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2545408Swnj 		if (tp->t_state&TS_ASLEEP) {
2555408Swnj 			tp->t_state &= ~TS_ASLEEP;
2565408Swnj 			wakeup((caddr_t)&tp->t_outq);
2575408Swnj 		}
2585408Swnj 		if (tp->t_wsel) {
2595408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2605408Swnj 			tp->t_wsel = 0;
2615408Swnj 			tp->t_state &= ~TS_WCOLL;
2625408Swnj 		}
2632281Stoy 	}
2648521Sroot 	return (error);
2652281Stoy }
2662281Stoy 
2675427Swnj ptsstop(tp, flush)
2685427Swnj 	register struct tty *tp;
2695427Swnj 	int flush;
2705427Swnj {
2715427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2725427Swnj 
2735574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2745574Swnj 	if (flush == 0) {
2755574Swnj 		flush = TIOCPKT_STOP;
2765574Swnj 		pti->pt_flags |= PF_STOPPED;
2775574Swnj 	} else {
2785574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2795574Swnj 	}
2806119Swnj 	pti->pt_send |= flush;
2815430Swnj 	ptcwakeup(tp);
2825427Swnj }
2835427Swnj 
2845408Swnj ptcselect(dev, rw)
2854484Swnj 	dev_t dev;
2865408Swnj 	int rw;
2874484Swnj {
2884484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2895894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2904484Swnj 	struct proc *p;
2915430Swnj 	int s;
2924484Swnj 
2935408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2944484Swnj 		return (1);
2955430Swnj 	s = spl5();
2965408Swnj 	switch (rw) {
2975408Swnj 
2985408Swnj 	case FREAD:
2995430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
3005430Swnj 			splx(s);
3015408Swnj 			return (1);
3025430Swnj 		}
3035427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
3045427Swnj 			pti->pt_flags |= PF_RCOLL;
3055408Swnj 		else
3065427Swnj 			pti->pt_selr = u.u_procp;
3075430Swnj 		break;
3085408Swnj 
3095408Swnj 	case FWRITE:
3105894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
3115430Swnj 			splx(s);
3125408Swnj 			return (1);
3135430Swnj 		}
3145427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
3155427Swnj 			pti->pt_flags |= PF_WCOLL;
3165408Swnj 		else
3175427Swnj 			pti->pt_selw = u.u_procp;
3185430Swnj 		break;
3195408Swnj 	}
3205430Swnj 	splx(s);
3215430Swnj 	return (0);
3225396Sroot }
3234484Swnj 
3247823Sroot ptcwrite(dev, uio)
3255408Swnj 	dev_t dev;
3267823Sroot 	struct uio *uio;
3274484Swnj {
3288521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
3292281Stoy 	register char *cp, *ce;
3302281Stoy 	register int cc;
3312281Stoy 	char locbuf[BUFSIZ];
3325408Swnj 	int cnt = 0;
3335894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3348521Sroot 	int error = 0;
3352281Stoy 
3365408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
3378521Sroot 		return (EIO);
3385894Swnj 	do {
3397823Sroot 		register struct iovec *iov;
3407823Sroot 
3417823Sroot 		if (uio->uio_iovcnt == 0)
3427823Sroot 			break;
3437823Sroot 		iov = uio->uio_iov;
3447823Sroot 		if (iov->iov_len == 0) {
34516788Ssam 			while (pti->pt_flags&PF_REMOTE && tp->t_rawq.c_cc != 0)
34616788Ssam 				sleep((caddr_t)&tp->t_rawq.c_cf, TTIPRI);
34716788Ssam 			if (pti->pt_flags&PF_REMOTE) {
34816788Ssam 				(void) putc(0, &tp->t_rawq);
34916788Ssam 				wakeup((caddr_t)&tp->t_rawq);
35016788Ssam 			}
3517823Sroot 			uio->uio_iovcnt--;
3527823Sroot 			uio->uio_iov++;
3537823Sroot 			if (uio->uio_iovcnt < 0)
3547823Sroot 				panic("ptcwrite");
3557823Sroot 			continue;
3567823Sroot 		}
3577823Sroot 		cc = MIN(iov->iov_len, BUFSIZ);
3582281Stoy 		cp = locbuf;
3598521Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
3608521Sroot 		if (error)
3612281Stoy 			break;
3622281Stoy 		ce = cp + cc;
3635894Swnj again:
3645894Swnj 		if (pti->pt_flags & PF_REMOTE) {
3655894Swnj 			if (tp->t_rawq.c_cc) {
3665894Swnj 				if (pti->pt_flags & PF_NBIO) {
3677823Sroot 					iov->iov_base -= ce - cp;
3687823Sroot 					iov->iov_len += ce - cp;
3697823Sroot 					uio->uio_resid += ce - cp;
3707823Sroot 					uio->uio_offset -= ce - cp;
3718521Sroot 					return (EWOULDBLOCK);
3725894Swnj 				}
3735894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3745894Swnj 				goto again;
3755894Swnj 			}
3766158Ssam 			(void) b_to_q(cp, cc, &tp->t_rawq);
3776158Ssam 			(void) putc(0, &tp->t_rawq);
3785894Swnj 			wakeup((caddr_t)&tp->t_rawq);
3798521Sroot 			return (0);
3805894Swnj 		}
3814484Swnj 		while (cp < ce) {
38216056Skarels 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
38316056Skarels 			    (tp->t_canq.c_cc > 0)) {
3842281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3855408Swnj 				if (tp->t_state & TS_NBIO) {
3867823Sroot 					iov->iov_base -= ce - cp;
3877823Sroot 					iov->iov_len += ce - cp;
3887823Sroot 					uio->uio_resid += ce - cp;
3897823Sroot 					uio->uio_offset -= ce - cp;
3905408Swnj 					if (cnt == 0)
3918521Sroot 						return (EWOULDBLOCK);
3928521Sroot 					return (0);
3935408Swnj 				}
3942281Stoy 				/* Better than just flushing it! */
3952281Stoy 				/* Wait for something to be read */
3962281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3975894Swnj 				goto again;
3982281Stoy 			}
3994141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
4005408Swnj 			cnt++;
4012281Stoy 		}
4027823Sroot 	} while (uio->uio_resid);
4038521Sroot 	return (error);
4042281Stoy }
4052281Stoy 
4062281Stoy /*ARGSUSED*/
4077626Ssam ptyioctl(dev, cmd, data, flag)
4087626Ssam 	caddr_t data;
4094484Swnj 	dev_t dev;
4104484Swnj {
4116119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
4126119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
4138563Sroot 	int error;
4142281Stoy 
4154484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4167626Ssam 	if (cdevsw[major(dev)].d_open == ptcopen)
4177626Ssam 		switch (cmd) {
4187626Ssam 
4197626Ssam 		case TIOCPKT:
4207626Ssam 			if (*(int *)data)
4215427Swnj 				pti->pt_flags |= PF_PKT;
4225427Swnj 			else
4235427Swnj 				pti->pt_flags &= ~PF_PKT;
4248563Sroot 			return (0);
4257626Ssam 
4267626Ssam 		case TIOCREMOTE:
4277626Ssam 			if (*(int *)data)
4285894Swnj 				pti->pt_flags |= PF_REMOTE;
4295894Swnj 			else
4305894Swnj 				pti->pt_flags &= ~PF_REMOTE;
43112753Ssam 			ttyflush(tp, FREAD|FWRITE);
4328563Sroot 			return (0);
4337626Ssam 
4347626Ssam 		case FIONBIO:
4357626Ssam 			if (*(int *)data)
4365427Swnj 				pti->pt_flags |= PF_NBIO;
4375411Swnj 			else
4385427Swnj 				pti->pt_flags &= ~PF_NBIO;
4398563Sroot 			return (0);
4407626Ssam 
4417626Ssam 		case TIOCSETP:
4427626Ssam 			while (getc(&tp->t_outq) >= 0)
4437626Ssam 				;
4447626Ssam 			break;
4455411Swnj 		}
4468563Sroot 	error = ttioctl(tp, cmd, data, dev);
4478563Sroot 	if (error < 0)
4488563Sroot 		error = ENOTTY;
4499561Ssam 	{ int stop = (tp->t_stopc == ('s'&037) &&
4509561Ssam 		      tp->t_startc == ('q'&037));
4516119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4526119Swnj 		if (stop) {
4536119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4546119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4556119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4566119Swnj 			ptcwakeup(tp);
4576119Swnj 		}
4586119Swnj 	} else {
4596119Swnj 		if (stop == 0) {
4606119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4616119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4626119Swnj 			pti->pt_flags |= PF_NOSTOP;
4636119Swnj 			ptcwakeup(tp);
4646119Swnj 		}
4656119Swnj 	}
4666119Swnj 	}
4678563Sroot 	return (error);
4682281Stoy }
4692313Stoy #endif
470