xref: /csrg-svn/sys/kern/tty_pty.c (revision 5894)
1*5894Swnj /*	tty_pty.c	4.17	82/02/18	*/
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"
162281Stoy #include "../h/buf.h"
172427Swnj #include "../h/file.h"
184484Swnj #include "../h/proc.h"
195408Swnj #undef	NPTY
202281Stoy 
214484Swnj #define NPTY 16
224484Swnj 
232427Swnj #define BUFSIZ 100		/* Chunk size iomoved from user */
244484Swnj 
252281Stoy /*
264484Swnj  * pts == /dev/tty[pP]?
274484Swnj  * ptc == /dev/ptp[pP]?
282281Stoy  */
294484Swnj struct	tty pt_tty[NPTY];
304484Swnj struct	pt_ioctl {
315427Swnj 	int	pt_flags;
325427Swnj 	int	pt_gensym;
335427Swnj 	struct	proc *pt_selr, *pt_selw;
345427Swnj 	int	pt_send;
354484Swnj } pt_ioctl[NPTY];
362281Stoy 
375427Swnj #define	PF_RCOLL	0x01
385427Swnj #define	PF_WCOLL	0x02
395427Swnj #define	PF_NBIO		0x04
405427Swnj #define	PF_PKT		0x08		/* packet mode */
415574Swnj #define	PF_STOPPED	0x10		/* user told stopped */
42*5894Swnj #define	PF_REMOTE	0x20		/* remote and flow controlled input */
432281Stoy 
442281Stoy /*ARGSUSED*/
452281Stoy ptsopen(dev, flag)
465396Sroot 	dev_t dev;
474484Swnj {
482281Stoy 	register struct tty *tp;
492281Stoy 
504484Swnj 	if (minor(dev) >= NPTY) {
512281Stoy 		u.u_error = ENXIO;
522281Stoy 		return;
532281Stoy 	}
542281Stoy 	tp = &pt_tty[minor(dev)];
555408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
562427Swnj 		ttychars(tp);		/* Set up default chars */
572427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
585408Swnj 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) {
592281Stoy 		u.u_error = EBUSY;
602281Stoy 		return;
612281Stoy 	}
624484Swnj 	if (tp->t_oproc)			/* Ctrlr still around. */
635408Swnj 		tp->t_state |= TS_CARR_ON;
645408Swnj 	while ((tp->t_state & TS_CARR_ON) == 0) {
655408Swnj 		tp->t_state |= TS_WOPEN;
662281Stoy 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
672281Stoy 	}
682281Stoy 	(*linesw[tp->t_line].l_open)(dev, tp);
692281Stoy }
702281Stoy 
712281Stoy ptsclose(dev)
725396Sroot 	dev_t dev;
735408Swnj {
742281Stoy 	register struct tty *tp;
752281Stoy 
762281Stoy 	tp = &pt_tty[minor(dev)];
772281Stoy 	(*linesw[tp->t_line].l_close)(tp);
782281Stoy }
792281Stoy 
802281Stoy ptsread(dev)
815396Sroot 	dev_t dev;
824484Swnj {
83*5894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
84*5894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
852281Stoy 
86*5894Swnj again:
87*5894Swnj 	if (pti->pt_flags & PF_REMOTE) {
88*5894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
89*5894Swnj 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
90*5894Swnj 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
91*5894Swnj 	/*
92*5894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
93*5894Swnj 	*/
94*5894Swnj 			    u.u_procp->p_flag&SVFORK)
95*5894Swnj 				return;
96*5894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
97*5894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
985408Swnj 		}
99*5894Swnj 		if (tp->t_rawq.c_cc == 0) {
100*5894Swnj 			if (tp->t_state & TS_NBIO) {
101*5894Swnj 				u.u_error = EWOULDBLOCK;
102*5894Swnj 				return;
103*5894Swnj 			}
104*5894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
105*5894Swnj 			goto again;
106*5894Swnj 		}
107*5894Swnj 		while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0)
108*5894Swnj 			;
109*5894Swnj 		if (tp->t_rawq.c_cc == 1)
110*5894Swnj 			(void) getc(&tp->t_rawq);
111*5894Swnj 		if (tp->t_rawq.c_cc)
112*5894Swnj 			return;
113*5894Swnj 	} else
114*5894Swnj 		if (tp->t_oproc)
115*5894Swnj 			(*linesw[tp->t_line].l_read)(tp);
116*5894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
117*5894Swnj 	if (pti->pt_selw) {
118*5894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
119*5894Swnj 		pti->pt_selw = 0;
120*5894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1212281Stoy 	}
1222281Stoy }
1232281Stoy 
1245408Swnj /*
1255408Swnj  * Write to pseudo-tty.
1265408Swnj  * Wakeups of controlling tty will happen
1275408Swnj  * indirectly, when tty driver calls ptsstart.
1285408Swnj  */
1292281Stoy ptswrite(dev)
1305396Sroot 	dev_t dev;
1314484Swnj {
1322281Stoy 	register struct tty *tp;
1332281Stoy 
1342281Stoy 	tp = &pt_tty[minor(dev)];
1354484Swnj 	if (tp->t_oproc)
1362281Stoy 		(*linesw[tp->t_line].l_write)(tp);
1372281Stoy }
1382281Stoy 
1395408Swnj /*
1405408Swnj  * Start output on pseudo-tty.
1415408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1425408Swnj  */
1432281Stoy ptsstart(tp)
1444484Swnj 	struct tty *tp;
1454484Swnj {
1465574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1474484Swnj 
1485408Swnj 	if (tp->t_state & TS_TTSTOP)
1492281Stoy 		return;
1505574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1515574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1525574Swnj 		pti->pt_send = TIOCPKT_START;
1535574Swnj 	}
1545430Swnj 	ptcwakeup(tp);
1555430Swnj }
1565430Swnj 
1575430Swnj ptcwakeup(tp)
1585430Swnj 	struct tty *tp;
1595430Swnj {
1605430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1615430Swnj 
1625427Swnj 	if (pti->pt_selr) {
1635427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1645427Swnj 		pti->pt_selr = 0;
1655427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1664484Swnj 	}
1672281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1682281Stoy }
1692281Stoy 
1702281Stoy /*ARGSUSED*/
1712281Stoy ptcopen(dev, flag)
1724484Swnj 	dev_t dev;
1734484Swnj 	int flag;
1744484Swnj {
1752281Stoy 	register struct tty *tp;
1765427Swnj 	struct pt_ioctl *pti;
1772281Stoy 
1784484Swnj 	if (minor(dev) >= NPTY) {
1792281Stoy 		u.u_error = ENXIO;
1802281Stoy 		return;
1812281Stoy 	}
1822281Stoy 	tp = &pt_tty[minor(dev)];
1834484Swnj 	if (tp->t_oproc) {
1842281Stoy 		u.u_error = EIO;
1852281Stoy 		return;
1862281Stoy 	}
1874484Swnj 	tp->t_oproc = ptsstart;
1885408Swnj 	if (tp->t_state & TS_WOPEN)
1892281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1905408Swnj 	tp->t_state |= TS_CARR_ON;
1915427Swnj 	pti = &pt_ioctl[minor(dev)];
1925427Swnj 	pti->pt_flags = 0;
1935427Swnj 	pti->pt_send = 0;
1942281Stoy }
1952281Stoy 
1962281Stoy ptcclose(dev)
1974484Swnj 	dev_t dev;
1984484Swnj {
1992281Stoy 	register struct tty *tp;
2002281Stoy 
2012281Stoy 	tp = &pt_tty[minor(dev)];
2025408Swnj 	if (tp->t_state & TS_ISOPEN)
2032281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2045408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
2054484Swnj 	flushtty(tp, FREAD|FWRITE);
2064484Swnj 	tp->t_oproc = 0;		/* mark closed */
2072281Stoy }
2082281Stoy 
2092281Stoy ptcread(dev)
2105427Swnj 	dev_t dev;
2114484Swnj {
2122281Stoy 	register struct tty *tp;
2135427Swnj 	struct pt_ioctl *pti;
2142281Stoy 
2152281Stoy 	tp = &pt_tty[minor(dev)];
2165408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2172281Stoy 		return;
2185427Swnj 	pti = &pt_ioctl[minor(dev)];
2195427Swnj 	if (pti->pt_flags & PF_PKT) {
2205427Swnj 		if (pti->pt_send) {
2215427Swnj 			passc(pti->pt_send);
2225427Swnj 			pti->pt_send = 0;
2235427Swnj 			return;
2245427Swnj 		}
2255427Swnj 		passc(0);
2265427Swnj 	}
2275411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
2285427Swnj 		if (pti->pt_flags&PF_NBIO) {
2295411Swnj 			u.u_error = EWOULDBLOCK;
2305411Swnj 			return;
2315411Swnj 		}
2322281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2335411Swnj 	}
2345408Swnj 	while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0)
2355408Swnj 		;
2365408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2375408Swnj 		if (tp->t_state&TS_ASLEEP) {
2385408Swnj 			tp->t_state &= ~TS_ASLEEP;
2395408Swnj 			wakeup((caddr_t)&tp->t_outq);
2405408Swnj 		}
2415408Swnj 		if (tp->t_wsel) {
2425408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2435408Swnj 			tp->t_wsel = 0;
2445408Swnj 			tp->t_state &= ~TS_WCOLL;
2455408Swnj 		}
2462281Stoy 	}
2472281Stoy }
2482281Stoy 
2495427Swnj ptsstop(tp, flush)
2505427Swnj 	register struct tty *tp;
2515427Swnj 	int flush;
2525427Swnj {
2535427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2545427Swnj 
2555574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2565574Swnj 	if (flush == 0) {
2575574Swnj 		flush = TIOCPKT_STOP;
2585574Swnj 		pti->pt_flags |= PF_STOPPED;
2595574Swnj 	} else {
2605574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2615574Swnj 	}
2625574Swnj 	pti->pt_send = flush;
2635430Swnj 	ptcwakeup(tp);
2645427Swnj }
2655427Swnj 
2665408Swnj ptcselect(dev, rw)
2674484Swnj 	dev_t dev;
2685408Swnj 	int rw;
2694484Swnj {
2704484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
271*5894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2724484Swnj 	struct proc *p;
2735430Swnj 	int s;
2744484Swnj 
2755408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2764484Swnj 		return (1);
2775430Swnj 	s = spl5();
2785408Swnj 	switch (rw) {
2795408Swnj 
2805408Swnj 	case FREAD:
2815430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2825430Swnj 			splx(s);
2835408Swnj 			return (1);
2845430Swnj 		}
2855427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
2865427Swnj 			pti->pt_flags |= PF_RCOLL;
2875408Swnj 		else
2885427Swnj 			pti->pt_selr = u.u_procp;
2895430Swnj 		break;
2905408Swnj 
2915408Swnj 	case FWRITE:
292*5894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
2935430Swnj 			splx(s);
2945408Swnj 			return (1);
2955430Swnj 		}
2965427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
2975427Swnj 			pti->pt_flags |= PF_WCOLL;
2985408Swnj 		else
2995427Swnj 			pti->pt_selw = u.u_procp;
3005430Swnj 		break;
3015408Swnj 	}
3025430Swnj 	splx(s);
3035430Swnj 	return (0);
3045396Sroot }
3054484Swnj 
3062281Stoy ptcwrite(dev)
3075408Swnj 	dev_t dev;
3084484Swnj {
3092281Stoy 	register struct tty *tp;
3102281Stoy 	register char *cp, *ce;
3112281Stoy 	register int cc;
3122281Stoy 	char locbuf[BUFSIZ];
3135408Swnj 	int cnt = 0;
314*5894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3152281Stoy 
3162281Stoy 	tp = &pt_tty[minor(dev)];
3175408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
3182281Stoy 		return;
319*5894Swnj 	do {
3202281Stoy 		cc = MIN(u.u_count, BUFSIZ);
3212281Stoy 		cp = locbuf;
3222281Stoy 		iomove(cp, (unsigned)cc, B_WRITE);
3234484Swnj 		if (u.u_error)
3242281Stoy 			break;
3252281Stoy 		ce = cp + cc;
326*5894Swnj again:
327*5894Swnj 		if (pti->pt_flags & PF_REMOTE) {
328*5894Swnj 			if (tp->t_rawq.c_cc) {
329*5894Swnj 				if (pti->pt_flags & PF_NBIO) {
330*5894Swnj 					u.u_count += ce - cp;
331*5894Swnj 					u.u_error = EWOULDBLOCK;
332*5894Swnj 					return;
333*5894Swnj 				}
334*5894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
335*5894Swnj 				goto again;
336*5894Swnj 			}
337*5894Swnj 			b_to_q(cp, cc, &tp->t_rawq);
338*5894Swnj 			putc(0, &tp->t_rawq);
339*5894Swnj 			wakeup((caddr_t)&tp->t_rawq);
340*5894Swnj 			return;
341*5894Swnj 		}
3424484Swnj 		while (cp < ce) {
3434484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3442281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3455408Swnj 				if (tp->t_state & TS_NBIO) {
3465408Swnj 					u.u_count += ce - cp;
3475408Swnj 					if (cnt == 0)
3485408Swnj 						u.u_error = EWOULDBLOCK;
3495408Swnj 					return;
3505408Swnj 				}
3512281Stoy 				/* Better than just flushing it! */
3522281Stoy 				/* Wait for something to be read */
3532281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
354*5894Swnj 				goto again;
3552281Stoy 			}
3564141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3575408Swnj 			cnt++;
3582281Stoy 		}
359*5894Swnj 	} while (u.u_count);
3602281Stoy }
3612281Stoy 
3622281Stoy /*ARGSUSED*/
3632281Stoy ptyioctl(dev, cmd, addr, flag)
3644484Swnj 	caddr_t addr;
3654484Swnj 	dev_t dev;
3664484Swnj {
3672281Stoy 	register struct tty *tp;
3682281Stoy 
3692281Stoy 	tp = &pt_tty[minor(dev)];
3704484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
3715411Swnj 	if (cdevsw[major(dev)].d_open == ptcopen) {
3725427Swnj 		register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3735427Swnj 		if (cmd == TIOCPKT) {
3745427Swnj 			int packet;
3755427Swnj 			if (copyin((caddr_t)addr, &packet, sizeof (packet))) {
3765427Swnj 				u.u_error = EFAULT;
3775427Swnj 				return;
3785427Swnj 			}
3795427Swnj 			if (packet)
3805427Swnj 				pti->pt_flags |= PF_PKT;
3815427Swnj 			else
3825427Swnj 				pti->pt_flags &= ~PF_PKT;
3835427Swnj 			return;
3845427Swnj 		}
385*5894Swnj 		if (cmd == TIOCREMOTE) {
386*5894Swnj 			int remote;
387*5894Swnj 			if (copyin((caddr_t)addr, &remote, sizeof (remote))) {
388*5894Swnj 				u.u_error = EFAULT;
389*5894Swnj 				return;
390*5894Swnj 			}
391*5894Swnj 			if (remote)
392*5894Swnj 				pti->pt_flags |= PF_REMOTE;
393*5894Swnj 			else
394*5894Swnj 				pti->pt_flags &= ~PF_REMOTE;
395*5894Swnj 			flushtty(tp, FREAD|FWRITE);
396*5894Swnj 			return;
397*5894Swnj 		}
3985411Swnj 		if (cmd == FIONBIO) {
3995411Swnj 			int nbio;
4005411Swnj 			if (copyin(addr, &nbio, sizeof (nbio))) {
4015411Swnj 				u.u_error = EFAULT;
4025411Swnj 				return;
4035411Swnj 			}
4045411Swnj 			if (nbio)
4055427Swnj 				pti->pt_flags |= PF_NBIO;
4065411Swnj 			else
4075427Swnj 				pti->pt_flags &= ~PF_NBIO;
4085411Swnj 			return;
4095411Swnj 		}
4105411Swnj 		if (cmd == TIOCSETP)
4115411Swnj 			while (getc(&tp->t_outq) >= 0);
4125411Swnj 	}
4134484Swnj 	if (ttioctl(tp, cmd, addr, dev) == 0)
4142281Stoy 		u.u_error = ENOTTY;
4152281Stoy }
4162313Stoy #endif
417