xref: /csrg-svn/sys/kern/tty_pty.c (revision 8563)
1*8563Sroot /*	tty_pty.c	4.27	82/10/17	*/
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 
54*8563Sroot 	if (minor(dev) >= NPTY)
55*8563Sroot 		return (ENXIO);
562281Stoy 	tp = &pt_tty[minor(dev)];
575408Swnj 	if ((tp->t_state & TS_ISOPEN) == 0) {
582427Swnj 		ttychars(tp);		/* Set up default chars */
592427Swnj 		tp->t_flags = 0;	/* No features (nor raw mode) */
60*8563Sroot 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
61*8563Sroot 		return (EBUSY);
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 	}
68*8563Sroot 	return ((*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);
786299Swnj 	ttyclose(tp);
792281Stoy }
802281Stoy 
817823Sroot ptsread(dev, uio)
825396Sroot 	dev_t dev;
837823Sroot 	struct uio *uio;
844484Swnj {
855894Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
865894Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
878521Sroot 	int error = 0;
882281Stoy 
895894Swnj again:
905894Swnj 	if (pti->pt_flags & PF_REMOTE) {
915894Swnj 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
925894Swnj 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
935894Swnj 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
945894Swnj 	/*
955894Swnj 			    (u.u_procp->p_flag&SDETACH) ||
965894Swnj 	*/
975894Swnj 			    u.u_procp->p_flag&SVFORK)
988521Sroot 				return (EIO);
995894Swnj 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
1005894Swnj 			sleep((caddr_t)&lbolt, TTIPRI);
1015408Swnj 		}
1025894Swnj 		if (tp->t_rawq.c_cc == 0) {
1038521Sroot 			if (tp->t_state & TS_NBIO)
1048521Sroot 				return (EWOULDBLOCK);
1055894Swnj 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
1065894Swnj 			goto again;
1075894Swnj 		}
1087823Sroot 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
1097823Sroot 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
1108521Sroot 				error = EFAULT;
1117823Sroot 				break;
1127823Sroot 			}
1135894Swnj 		if (tp->t_rawq.c_cc == 1)
1145894Swnj 			(void) getc(&tp->t_rawq);
1155894Swnj 		if (tp->t_rawq.c_cc)
1168521Sroot 			return (error);
1175894Swnj 	} else
1185894Swnj 		if (tp->t_oproc)
1198521Sroot 			error = (*linesw[tp->t_line].l_read)(tp, uio);
1205894Swnj 	wakeup((caddr_t)&tp->t_rawq.c_cf);
1215894Swnj 	if (pti->pt_selw) {
1225894Swnj 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
1235894Swnj 		pti->pt_selw = 0;
1245894Swnj 		pti->pt_flags &= ~PF_WCOLL;
1252281Stoy 	}
1268521Sroot 	return (error);
1272281Stoy }
1282281Stoy 
1295408Swnj /*
1305408Swnj  * Write to pseudo-tty.
1315408Swnj  * Wakeups of controlling tty will happen
1325408Swnj  * indirectly, when tty driver calls ptsstart.
1335408Swnj  */
1347823Sroot ptswrite(dev, uio)
1355396Sroot 	dev_t dev;
1367823Sroot 	struct uio *uio;
1374484Swnj {
1382281Stoy 	register struct tty *tp;
1392281Stoy 
1402281Stoy 	tp = &pt_tty[minor(dev)];
1418521Sroot 	if (tp->t_oproc == 0)
1428521Sroot 		return (EIO);
1438521Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
1442281Stoy }
1452281Stoy 
1465408Swnj /*
1475408Swnj  * Start output on pseudo-tty.
1485408Swnj  * Wake up process selecting or sleeping for input from controlling tty.
1495408Swnj  */
1502281Stoy ptsstart(tp)
1514484Swnj 	struct tty *tp;
1524484Swnj {
1535574Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1544484Swnj 
1555408Swnj 	if (tp->t_state & TS_TTSTOP)
1562281Stoy 		return;
1575574Swnj 	if (pti->pt_flags & PF_STOPPED) {
1585574Swnj 		pti->pt_flags &= ~PF_STOPPED;
1595574Swnj 		pti->pt_send = TIOCPKT_START;
1605574Swnj 	}
1615430Swnj 	ptcwakeup(tp);
1625430Swnj }
1635430Swnj 
1645430Swnj ptcwakeup(tp)
1655430Swnj 	struct tty *tp;
1665430Swnj {
1675430Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
1685430Swnj 
1695427Swnj 	if (pti->pt_selr) {
1705427Swnj 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
1715427Swnj 		pti->pt_selr = 0;
1725427Swnj 		pti->pt_flags &= ~PF_RCOLL;
1734484Swnj 	}
1742281Stoy 	wakeup((caddr_t)&tp->t_outq.c_cf);
1752281Stoy }
1762281Stoy 
1772281Stoy /*ARGSUSED*/
1782281Stoy ptcopen(dev, flag)
1794484Swnj 	dev_t dev;
1804484Swnj 	int flag;
1814484Swnj {
1822281Stoy 	register struct tty *tp;
1835427Swnj 	struct pt_ioctl *pti;
1842281Stoy 
185*8563Sroot 	if (minor(dev) >= NPTY)
186*8563Sroot 		return (ENXIO);
1872281Stoy 	tp = &pt_tty[minor(dev)];
188*8563Sroot 	if (tp->t_oproc)
189*8563Sroot 		return (EIO);
1904484Swnj 	tp->t_oproc = ptsstart;
1915408Swnj 	if (tp->t_state & TS_WOPEN)
1922281Stoy 		wakeup((caddr_t)&tp->t_rawq);
1935408Swnj 	tp->t_state |= TS_CARR_ON;
1945427Swnj 	pti = &pt_ioctl[minor(dev)];
1955427Swnj 	pti->pt_flags = 0;
1965427Swnj 	pti->pt_send = 0;
197*8563Sroot 	return (0);
1982281Stoy }
1992281Stoy 
2002281Stoy ptcclose(dev)
2014484Swnj 	dev_t dev;
2024484Swnj {
2032281Stoy 	register struct tty *tp;
2042281Stoy 
2052281Stoy 	tp = &pt_tty[minor(dev)];
2065408Swnj 	if (tp->t_state & TS_ISOPEN)
2072281Stoy 		gsignal(tp->t_pgrp, SIGHUP);
2085408Swnj 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
2094484Swnj 	flushtty(tp, FREAD|FWRITE);
2104484Swnj 	tp->t_oproc = 0;		/* mark closed */
2112281Stoy }
2122281Stoy 
2137823Sroot ptcread(dev, uio)
2145427Swnj 	dev_t dev;
2157823Sroot 	struct uio *uio;
2164484Swnj {
2178521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
2185427Swnj 	struct pt_ioctl *pti;
2198521Sroot 	int error = 0;
2202281Stoy 
2215408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2222281Stoy 		return;
2235427Swnj 	pti = &pt_ioctl[minor(dev)];
2245427Swnj 	if (pti->pt_flags & PF_PKT) {
2255427Swnj 		if (pti->pt_send) {
2268521Sroot 			error = ureadc(pti->pt_send, uio);
2278521Sroot 			if (error)
2288521Sroot 				return (error);
2295427Swnj 			pti->pt_send = 0;
2308521Sroot 			return (0);
2315427Swnj 		}
2328521Sroot 		error = ureadc(0, uio);
2335427Swnj 	}
2345411Swnj 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
2358521Sroot 		if (pti->pt_flags&PF_NBIO)
2368521Sroot 			return (EWOULDBLOCK);
2372281Stoy 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
2385411Swnj 	}
2397823Sroot 	while (tp->t_outq.c_cc && uio->uio_resid > 0)
2407823Sroot 		if (ureadc(getc(&tp->t_outq), uio) < 0) {
2418521Sroot 			error = EFAULT;
2427823Sroot 			break;
2437823Sroot 		}
2445408Swnj 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
2455408Swnj 		if (tp->t_state&TS_ASLEEP) {
2465408Swnj 			tp->t_state &= ~TS_ASLEEP;
2475408Swnj 			wakeup((caddr_t)&tp->t_outq);
2485408Swnj 		}
2495408Swnj 		if (tp->t_wsel) {
2505408Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
2515408Swnj 			tp->t_wsel = 0;
2525408Swnj 			tp->t_state &= ~TS_WCOLL;
2535408Swnj 		}
2542281Stoy 	}
2558521Sroot 	return (error);
2562281Stoy }
2572281Stoy 
2585427Swnj ptsstop(tp, flush)
2595427Swnj 	register struct tty *tp;
2605427Swnj 	int flush;
2615427Swnj {
2625427Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
2635427Swnj 
2645574Swnj 	/* note: FLUSHREAD and FLUSHWRITE already ok */
2655574Swnj 	if (flush == 0) {
2665574Swnj 		flush = TIOCPKT_STOP;
2675574Swnj 		pti->pt_flags |= PF_STOPPED;
2685574Swnj 	} else {
2695574Swnj 		pti->pt_flags &= ~PF_STOPPED;
2705574Swnj 	}
2716119Swnj 	pti->pt_send |= flush;
2725430Swnj 	ptcwakeup(tp);
2735427Swnj }
2745427Swnj 
2755408Swnj ptcselect(dev, rw)
2764484Swnj 	dev_t dev;
2775408Swnj 	int rw;
2784484Swnj {
2794484Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
2805894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2814484Swnj 	struct proc *p;
2825430Swnj 	int s;
2834484Swnj 
2845408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
2854484Swnj 		return (1);
2865430Swnj 	s = spl5();
2875408Swnj 	switch (rw) {
2885408Swnj 
2895408Swnj 	case FREAD:
2905430Swnj 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
2915430Swnj 			splx(s);
2925408Swnj 			return (1);
2935430Swnj 		}
2945427Swnj 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
2955427Swnj 			pti->pt_flags |= PF_RCOLL;
2965408Swnj 		else
2975427Swnj 			pti->pt_selr = u.u_procp;
2985430Swnj 		break;
2995408Swnj 
3005408Swnj 	case FWRITE:
3015894Swnj 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
3025430Swnj 			splx(s);
3035408Swnj 			return (1);
3045430Swnj 		}
3055427Swnj 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
3065427Swnj 			pti->pt_flags |= PF_WCOLL;
3075408Swnj 		else
3085427Swnj 			pti->pt_selw = u.u_procp;
3095430Swnj 		break;
3105408Swnj 	}
3115430Swnj 	splx(s);
3125430Swnj 	return (0);
3135396Sroot }
3144484Swnj 
3157823Sroot ptcwrite(dev, uio)
3165408Swnj 	dev_t dev;
3177823Sroot 	struct uio *uio;
3184484Swnj {
3198521Sroot 	register struct tty *tp = &pt_tty[minor(dev)];
3202281Stoy 	register char *cp, *ce;
3212281Stoy 	register int cc;
3222281Stoy 	char locbuf[BUFSIZ];
3235408Swnj 	int cnt = 0;
3245894Swnj 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
3258521Sroot 	int error = 0;
3262281Stoy 
3275408Swnj 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
3288521Sroot 		return (EIO);
3295894Swnj 	do {
3307823Sroot 		register struct iovec *iov;
3317823Sroot 
3327823Sroot 		if (uio->uio_iovcnt == 0)
3337823Sroot 			break;
3347823Sroot 		iov = uio->uio_iov;
3357823Sroot 		if (iov->iov_len == 0) {
3367823Sroot 			uio->uio_iovcnt--;
3377823Sroot 			uio->uio_iov++;
3387823Sroot 			if (uio->uio_iovcnt < 0)
3397823Sroot 				panic("ptcwrite");
3407823Sroot 			continue;
3417823Sroot 		}
3427823Sroot 		cc = MIN(iov->iov_len, BUFSIZ);
3432281Stoy 		cp = locbuf;
3448521Sroot 		error = uiomove(cp, cc, UIO_WRITE, uio);
3458521Sroot 		if (error)
3462281Stoy 			break;
3472281Stoy 		ce = cp + cc;
3485894Swnj again:
3495894Swnj 		if (pti->pt_flags & PF_REMOTE) {
3505894Swnj 			if (tp->t_rawq.c_cc) {
3515894Swnj 				if (pti->pt_flags & PF_NBIO) {
3527823Sroot 					iov->iov_base -= ce - cp;
3537823Sroot 					iov->iov_len += ce - cp;
3547823Sroot 					uio->uio_resid += ce - cp;
3557823Sroot 					uio->uio_offset -= ce - cp;
3568521Sroot 					return (EWOULDBLOCK);
3575894Swnj 				}
3585894Swnj 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3595894Swnj 				goto again;
3605894Swnj 			}
3616158Ssam 			(void) b_to_q(cp, cc, &tp->t_rawq);
3626158Ssam 			(void) putc(0, &tp->t_rawq);
3635894Swnj 			wakeup((caddr_t)&tp->t_rawq);
3648521Sroot 			return (0);
3655894Swnj 		}
3664484Swnj 		while (cp < ce) {
3674484Swnj 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
3682281Stoy 				wakeup((caddr_t)&tp->t_rawq);
3695408Swnj 				if (tp->t_state & TS_NBIO) {
3707823Sroot 					iov->iov_base -= ce - cp;
3717823Sroot 					iov->iov_len += ce - cp;
3727823Sroot 					uio->uio_resid += ce - cp;
3737823Sroot 					uio->uio_offset -= ce - cp;
3745408Swnj 					if (cnt == 0)
3758521Sroot 						return (EWOULDBLOCK);
3768521Sroot 					return (0);
3775408Swnj 				}
3782281Stoy 				/* Better than just flushing it! */
3792281Stoy 				/* Wait for something to be read */
3802281Stoy 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
3815894Swnj 				goto again;
3822281Stoy 			}
3834141Secc 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
3845408Swnj 			cnt++;
3852281Stoy 		}
3867823Sroot 	} while (uio->uio_resid);
3878521Sroot 	return (error);
3882281Stoy }
3892281Stoy 
3902281Stoy /*ARGSUSED*/
3917626Ssam ptyioctl(dev, cmd, data, flag)
3927626Ssam 	caddr_t data;
3934484Swnj 	dev_t dev;
3944484Swnj {
3956119Swnj 	register struct tty *tp = &pt_tty[minor(dev)];
3966119Swnj 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
397*8563Sroot 	int error;
3982281Stoy 
3994484Swnj 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4007626Ssam 	if (cdevsw[major(dev)].d_open == ptcopen)
4017626Ssam 		switch (cmd) {
4027626Ssam 
4037626Ssam 		case TIOCPKT:
4047626Ssam 			if (*(int *)data)
4055427Swnj 				pti->pt_flags |= PF_PKT;
4065427Swnj 			else
4075427Swnj 				pti->pt_flags &= ~PF_PKT;
408*8563Sroot 			return (0);
4097626Ssam 
4107626Ssam 		case TIOCREMOTE:
4117626Ssam 			if (*(int *)data)
4125894Swnj 				pti->pt_flags |= PF_REMOTE;
4135894Swnj 			else
4145894Swnj 				pti->pt_flags &= ~PF_REMOTE;
4155894Swnj 			flushtty(tp, FREAD|FWRITE);
416*8563Sroot 			return (0);
4177626Ssam 
4187626Ssam 		case FIONBIO:
4197626Ssam 			if (*(int *)data)
4205427Swnj 				pti->pt_flags |= PF_NBIO;
4215411Swnj 			else
4225427Swnj 				pti->pt_flags &= ~PF_NBIO;
423*8563Sroot 			return (0);
4247626Ssam 
4257626Ssam 		case TIOCSETP:
4267626Ssam 			while (getc(&tp->t_outq) >= 0)
4277626Ssam 				;
4287626Ssam 			break;
4295411Swnj 		}
430*8563Sroot 	error = ttioctl(tp, cmd, data, dev);
431*8563Sroot 	if (error < 0)
432*8563Sroot 		error = ENOTTY;
4336119Swnj 	{ int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) &&
4346119Swnj 		      tp->t_un.t_chr.t_startc == ('q'&037));
4356119Swnj 	if (pti->pt_flags & PF_NOSTOP) {
4366119Swnj 		if (stop) {
4376119Swnj 			pti->pt_send &= TIOCPKT_NOSTOP;
4386119Swnj 			pti->pt_send |= TIOCPKT_DOSTOP;
4396119Swnj 			pti->pt_flags &= ~PF_NOSTOP;
4406119Swnj 			ptcwakeup(tp);
4416119Swnj 		}
4426119Swnj 	} else {
4436119Swnj 		if (stop == 0) {
4446119Swnj 			pti->pt_send &= ~TIOCPKT_DOSTOP;
4456119Swnj 			pti->pt_send |= TIOCPKT_NOSTOP;
4466119Swnj 			pti->pt_flags |= PF_NOSTOP;
4476119Swnj 			ptcwakeup(tp);
4486119Swnj 		}
4496119Swnj 	}
4506119Swnj 	}
451*8563Sroot 	return (error);
4522281Stoy }
4532313Stoy #endif
454