xref: /csrg-svn/sys/kern/tty_pty.c (revision 8521)
1*8521Sroot /*	tty_pty.c	4.26	82/10/13	*/
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
102281Stoy #include "../h/param.h"
112281Stoy #include "../h/systm.h"
122281Stoy #include "../h/tty.h"
132281Stoy #include "../h/dir.h"
142281Stoy #include "../h/user.h"
152281Stoy #include "../h/conf.h"
162427Swnj #include "../h/file.h"
174484Swnj #include "../h/proc.h"
187823Sroot #include "../h/uio.h"
198155Sroot #include "../h/kernel.h"
206239Sroot 
217475Ssam #if NPTY == 1
225408Swnj #undef	NPTY
236239Sroot #define	NPTY	32		/* crude XXX */
247475Ssam #endif
252281Stoy 
262427Swnj #define BUFSIZ 100		/* Chunk size iomoved from user */
274484Swnj 
282281Stoy /*
294484Swnj  * pts == /dev/tty[pP]?
304484Swnj  * ptc == /dev/ptp[pP]?
312281Stoy  */
324484Swnj struct	tty pt_tty[NPTY];
334484Swnj struct	pt_ioctl {
345427Swnj 	int	pt_flags;
355427Swnj 	int	pt_gensym;
365427Swnj 	struct	proc *pt_selr, *pt_selw;
375427Swnj 	int	pt_send;
384484Swnj } pt_ioctl[NPTY];
392281Stoy 
405427Swnj #define	PF_RCOLL	0x01
415427Swnj #define	PF_WCOLL	0x02
425427Swnj #define	PF_NBIO		0x04
435427Swnj #define	PF_PKT		0x08		/* packet mode */
445574Swnj #define	PF_STOPPED	0x10		/* user told stopped */
455894Swnj #define	PF_REMOTE	0x20		/* remote and flow controlled input */
466119Swnj #define	PF_NOSTOP	0x40
472281Stoy 
482281Stoy /*ARGSUSED*/
492281Stoy ptsopen(dev, flag)
505396Sroot 	dev_t dev;
514484Swnj {
522281Stoy 	register struct tty *tp;
532281Stoy 
544484Swnj 	if (minor(dev) >= NPTY) {
552281Stoy 		u.u_error = ENXIO;
562281Stoy 		return;
572281Stoy 	}
582281Stoy 	tp = &pt_tty[minor(dev)];
595408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
602427Swnj 		ttychars(tp);		/* Set up default chars */
612427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
625408Swnj 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
632281Stoy 		u.u_error = EBUSY;
642281Stoy 		return;
652281Stoy 	}
664484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
675408Swnj 		tp->t_state |= TS_CARR_ON;
685408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
695408Swnj 		tp->t_state |= TS_WOPEN;
702281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
712281Stoy 	}
722281Stoy 	(*linesw[tp->t_line].l_open)(dev, tp);
732281Stoy }
742281Stoy 
752281Stoy ptsclose(dev)
765396Sroot 	dev_t dev;
775408Swnj {
782281Stoy 	register struct tty *tp;
792281Stoy 
802281Stoy 	tp = &pt_tty[minor(dev)];
812281Stoy 	(*linesw[tp->t_line].l_close)(tp);
826299Swnj 	ttyclose(tp);
832281Stoy }
842281Stoy 
857823Sroot ptsread(dev, uio)
865396Sroot 	dev_t dev;
877823Sroot 	struct uio *uio;
884484Swnj {
895894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
905894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
91*8521Sroot 	int error = 0;
922281Stoy 
935894Swnj again:
945894Swnj 	if (pti->pt_flags & PF_REMOTE) {
955894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
965894Swnj 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
975894Swnj 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
985894Swnj 	/*
995894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
1005894Swnj 	*/
1015894Swnj 			    u.u_procp->p_flag&SVFORK)
102*8521Sroot 				return (EIO);
1035894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
1045894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1055408Swnj 		}
1065894Swnj 		if (tp->t_rawq.c_cc == 0) {
107*8521Sroot 			if (tp->t_state & TS_NBIO)
108*8521Sroot 				return (EWOULDBLOCK);
1095894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1105894Swnj 			goto again;
1115894Swnj 		}
1127823Sroot 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
1137823Sroot 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
114*8521Sroot 				error = EFAULT;
1157823Sroot 				break;
1167823Sroot 			}
1175894Swnj 		if (tp->t_rawq.c_cc == 1)
1185894Swnj 			(void) getc(&tp->t_rawq);
1195894Swnj 		if (tp->t_rawq.c_cc)
120*8521Sroot 			return (error);
1215894Swnj 	} else
1225894Swnj 		if (tp->t_oproc)
123*8521Sroot 			error = (*linesw[tp->t_line].l_read)(tp, uio);
1245894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
1255894Swnj 	if (pti->pt_selw) {
1265894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
1275894Swnj 		pti->pt_selw = 0;
1285894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1292281Stoy 	}
130*8521Sroot 	return (error);
1312281Stoy }
1322281Stoy 
1335408Swnj /*
1345408Swnj  * Write to pseudo-tty.
1355408Swnj  * Wakeups of controlling tty will happen
1365408Swnj  * indirectly, when tty driver calls ptsstart.
1375408Swnj  */
1387823Sroot ptswrite(dev, uio)
1395396Sroot 	dev_t dev;
1407823Sroot 	struct uio *uio;
1414484Swnj {
1422281Stoy 	register struct tty *tp;
1432281Stoy 
1442281Stoy 	tp = &pt_tty[minor(dev)];
145*8521Sroot 	if (tp->t_oproc == 0)
146*8521Sroot 		return (EIO);
147*8521Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
1482281Stoy }
1492281Stoy 
1505408Swnj /*
1515408Swnj  * Start output on pseudo-tty.
1525408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1535408Swnj  */
1542281Stoy ptsstart(tp)
1554484Swnj 	struct tty *tp;
1564484Swnj {
1575574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1584484Swnj 
1595408Swnj 	if (tp->t_state & TS_TTSTOP)
1602281Stoy 		return;
1615574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1625574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1635574Swnj 		pti->pt_send = TIOCPKT_START;
1645574Swnj 	}
1655430Swnj 	ptcwakeup(tp);
1665430Swnj }
1675430Swnj 
1685430Swnj ptcwakeup(tp)
1695430Swnj 	struct tty *tp;
1705430Swnj {
1715430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1725430Swnj 
1735427Swnj 	if (pti->pt_selr) {
1745427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1755427Swnj 		pti->pt_selr = 0;
1765427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1774484Swnj 	}
1782281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1792281Stoy }
1802281Stoy 
1812281Stoy /*ARGSUSED*/
1822281Stoy ptcopen(dev, flag)
1834484Swnj 	dev_t dev;
1844484Swnj 	int flag;
1854484Swnj {
1862281Stoy 	register struct tty *tp;
1875427Swnj 	struct pt_ioctl *pti;
1882281Stoy 
1894484Swnj 	if (minor(dev) >= NPTY) {
1902281Stoy 		u.u_error = ENXIO;
1912281Stoy 		return;
1922281Stoy 	}
1932281Stoy 	tp = &pt_tty[minor(dev)];
1944484Swnj 	if (tp->t_oproc) {
1952281Stoy 		u.u_error = EIO;
1962281Stoy 		return;
1972281Stoy 	}
1984484Swnj 	tp->t_oproc = ptsstart;
1995408Swnj 	if (tp->t_state & TS_WOPEN)
2002281Stoy 		wakeup((caddr_t)&tp->t_rawq);
2015408Swnj 	tp->t_state |= TS_CARR_ON;
2025427Swnj 	pti = &pt_ioctl[minor(dev)];
2035427Swnj 	pti->pt_flags = 0;
2045427Swnj 	pti->pt_send = 0;
2052281Stoy }
2062281Stoy 
2072281Stoy ptcclose(dev)
2084484Swnj 	dev_t dev;
2094484Swnj {
2102281Stoy 	register struct tty *tp;
2112281Stoy 
2122281Stoy 	tp = &pt_tty[minor(dev)];
2135408Swnj 	if (tp->t_state & TS_ISOPEN)
2142281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2155408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
2164484Swnj 	flushtty(tp, FREAD|FWRITE);
2174484Swnj 	tp->t_oproc = 0;		/* mark closed */
2182281Stoy }
2192281Stoy 
2207823Sroot ptcread(dev, uio)
2215427Swnj 	dev_t dev;
2227823Sroot 	struct uio *uio;
2234484Swnj {
224*8521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
2255427Swnj 	struct pt_ioctl *pti;
226*8521Sroot 	int error = 0;
2272281Stoy 
2285408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2292281Stoy 		return;
2305427Swnj 	pti = &pt_ioctl[minor(dev)];
2315427Swnj 	if (pti->pt_flags & PF_PKT) {
2325427Swnj 		if (pti->pt_send) {
233*8521Sroot 			error = ureadc(pti->pt_send, uio);
234*8521Sroot 			if (error)
235*8521Sroot 				return (error);
2365427Swnj 			pti->pt_send = 0;
237*8521Sroot 			return (0);
2385427Swnj 		}
239*8521Sroot 		error = ureadc(0, uio);
2405427Swnj 	}
2415411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
242*8521Sroot 		if (pti->pt_flags&PF_NBIO)
243*8521Sroot 			return (EWOULDBLOCK);
2442281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2455411Swnj 	}
2467823Sroot 	while (tp->t_outq.c_cc && uio->uio_resid > 0)
2477823Sroot 		if (ureadc(getc(&tp->t_outq), uio) < 0) {
248*8521Sroot 			error = EFAULT;
2497823Sroot 			break;
2507823Sroot 		}
2515408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2525408Swnj 		if (tp->t_state&TS_ASLEEP) {
2535408Swnj 			tp->t_state &= ~TS_ASLEEP;
2545408Swnj 			wakeup((caddr_t)&tp->t_outq);
2555408Swnj 		}
2565408Swnj 		if (tp->t_wsel) {
2575408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2585408Swnj 			tp->t_wsel = 0;
2595408Swnj 			tp->t_state &= ~TS_WCOLL;
2605408Swnj 		}
2612281Stoy 	}
262*8521Sroot 	return (error);
2632281Stoy }
2642281Stoy 
2655427Swnj ptsstop(tp, flush)
2665427Swnj 	register struct tty *tp;
2675427Swnj 	int flush;
2685427Swnj {
2695427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2705427Swnj 
2715574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2725574Swnj 	if (flush == 0) {
2735574Swnj 		flush = TIOCPKT_STOP;
2745574Swnj 		pti->pt_flags |= PF_STOPPED;
2755574Swnj 	} else {
2765574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2775574Swnj 	}
2786119Swnj 	pti->pt_send |= flush;
2795430Swnj 	ptcwakeup(tp);
2805427Swnj }
2815427Swnj 
2825408Swnj ptcselect(dev, rw)
2834484Swnj 	dev_t dev;
2845408Swnj 	int rw;
2854484Swnj {
2864484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2875894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2884484Swnj 	struct proc *p;
2895430Swnj 	int s;
2904484Swnj 
2915408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2924484Swnj 		return (1);
2935430Swnj 	s = spl5();
2945408Swnj 	switch (rw) {
2955408Swnj 
2965408Swnj 	case FREAD:
2975430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2985430Swnj 			splx(s);
2995408Swnj 			return (1);
3005430Swnj 		}
3015427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
3025427Swnj 			pti->pt_flags |= PF_RCOLL;
3035408Swnj 		else
3045427Swnj 			pti->pt_selr = u.u_procp;
3055430Swnj 		break;
3065408Swnj 
3075408Swnj 	case FWRITE:
3085894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
3095430Swnj 			splx(s);
3105408Swnj 			return (1);
3115430Swnj 		}
3125427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
3135427Swnj 			pti->pt_flags |= PF_WCOLL;
3145408Swnj 		else
3155427Swnj 			pti->pt_selw = u.u_procp;
3165430Swnj 		break;
3175408Swnj 	}
3185430Swnj 	splx(s);
3195430Swnj 	return (0);
3205396Sroot }
3214484Swnj 
3227823Sroot ptcwrite(dev, uio)
3235408Swnj 	dev_t dev;
3247823Sroot 	struct uio *uio;
3254484Swnj {
326*8521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
3272281Stoy 	register char *cp, *ce;
3282281Stoy 	register int cc;
3292281Stoy 	char locbuf[BUFSIZ];
3305408Swnj 	int cnt = 0;
3315894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
332*8521Sroot 	int error = 0;
3332281Stoy 
3345408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
335*8521Sroot 		return (EIO);
3365894Swnj 	do {
3377823Sroot 		register struct iovec *iov;
3387823Sroot 
3397823Sroot 		if (uio->uio_iovcnt == 0)
3407823Sroot 			break;
3417823Sroot 		iov = uio->uio_iov;
3427823Sroot 		if (iov->iov_len == 0) {
3437823Sroot 			uio->uio_iovcnt--;
3447823Sroot 			uio->uio_iov++;
3457823Sroot 			if (uio->uio_iovcnt < 0)
3467823Sroot 				panic("ptcwrite");
3477823Sroot 			continue;
3487823Sroot 		}
3497823Sroot 		cc = MIN(iov->iov_len, BUFSIZ);
3502281Stoy 		cp = locbuf;
351*8521Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
352*8521Sroot 		if (error)
3532281Stoy 			break;
3542281Stoy 		ce = cp + cc;
3555894Swnj again:
3565894Swnj 		if (pti->pt_flags & PF_REMOTE) {
3575894Swnj 			if (tp->t_rawq.c_cc) {
3585894Swnj 				if (pti->pt_flags & PF_NBIO) {
3597823Sroot 					iov->iov_base -= ce - cp;
3607823Sroot 					iov->iov_len += ce - cp;
3617823Sroot 					uio->uio_resid += ce - cp;
3627823Sroot 					uio->uio_offset -= ce - cp;
363*8521Sroot 					return (EWOULDBLOCK);
3645894Swnj 				}
3655894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3665894Swnj 				goto again;
3675894Swnj 			}
3686158Ssam 			(void) b_to_q(cp, cc, &tp->t_rawq);
3696158Ssam 			(void) putc(0, &tp->t_rawq);
3705894Swnj 			wakeup((caddr_t)&tp->t_rawq);
371*8521Sroot 			return (0);
3725894Swnj 		}
3734484Swnj 		while (cp < ce) {
3744484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3752281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3765408Swnj 				if (tp->t_state & TS_NBIO) {
3777823Sroot 					iov->iov_base -= ce - cp;
3787823Sroot 					iov->iov_len += ce - cp;
3797823Sroot 					uio->uio_resid += ce - cp;
3807823Sroot 					uio->uio_offset -= ce - cp;
3815408Swnj 					if (cnt == 0)
382*8521Sroot 						return (EWOULDBLOCK);
383*8521Sroot 					return (0);
3845408Swnj 				}
3852281Stoy 				/* Better than just flushing it! */
3862281Stoy 				/* Wait for something to be read */
3872281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3885894Swnj 				goto again;
3892281Stoy 			}
3904141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3915408Swnj 			cnt++;
3922281Stoy 		}
3937823Sroot 	} while (uio->uio_resid);
394*8521Sroot 	return (error);
3952281Stoy }
3962281Stoy 
3972281Stoy /*ARGSUSED*/
3987626Ssam ptyioctl(dev, cmd, data, flag)
3997626Ssam 	caddr_t data;
4004484Swnj 	dev_t dev;
4014484Swnj {
4026119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
4036119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
4042281Stoy 
4054484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4067626Ssam 	if (cdevsw[major(dev)].d_open == ptcopen)
4077626Ssam 		switch (cmd) {
4087626Ssam 
4097626Ssam 		case TIOCPKT:
4107626Ssam 			if (*(int *)data)
4115427Swnj 				pti->pt_flags |= PF_PKT;
4125427Swnj 			else
4135427Swnj 				pti->pt_flags &= ~PF_PKT;
4145427Swnj 			return;
4157626Ssam 
4167626Ssam 		case TIOCREMOTE:
4177626Ssam 			if (*(int *)data)
4185894Swnj 				pti->pt_flags |= PF_REMOTE;
4195894Swnj 			else
4205894Swnj 				pti->pt_flags &= ~PF_REMOTE;
4215894Swnj 			flushtty(tp, FREAD|FWRITE);
4225894Swnj 			return;
4237626Ssam 
4247626Ssam 		case FIONBIO:
4257626Ssam 			if (*(int *)data)
4265427Swnj 				pti->pt_flags |= PF_NBIO;
4275411Swnj 			else
4285427Swnj 				pti->pt_flags &= ~PF_NBIO;
4295411Swnj 			return;
4307626Ssam 
4317626Ssam 		case TIOCSETP:
4327626Ssam 			while (getc(&tp->t_outq) >= 0)
4337626Ssam 				;
4347626Ssam 			break;
4355411Swnj 		}
4367626Ssam 	if (ttioctl(tp, cmd, data, dev) == 0)
4372281Stoy 		u.u_error = ENOTTY;
4386119Swnj 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
4396119Swnj 		      tp->t_un.t_chr.t_startc == ('q'&037));
4406119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4416119Swnj 		if (stop) {
4426119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4436119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4446119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4456119Swnj 			ptcwakeup(tp);
4466119Swnj 		}
4476119Swnj 	} else {
4486119Swnj 		if (stop == 0) {
4496119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4506119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4516119Swnj 			pti->pt_flags |= PF_NOSTOP;
4526119Swnj 			ptcwakeup(tp);
4536119Swnj 		}
4546119Swnj 	}
4556119Swnj 	}
4562281Stoy }
4572313Stoy #endif
458