xref: /original-bsd/sys/kern/tty_pty.c (revision f0fd5f8a)
1 /*	tty_pty.c	4.29	82/12/05	*/
2 
3 /*
4  * Pseudo-teletype Driver
5  * (Actually two drivers, requiring two entries in 'cdevsw')
6  */
7 #include "pty.h"
8 
9 #if NPTY > 0
10 #include "../h/param.h"
11 #include "../h/systm.h"
12 #include "../h/ioctl.h"
13 #include "../h/tty.h"
14 #include "../h/dir.h"
15 #include "../h/user.h"
16 #include "../h/conf.h"
17 #include "../h/file.h"
18 #include "../h/proc.h"
19 #include "../h/uio.h"
20 #include "../h/kernel.h"
21 
22 #if NPTY == 1
23 #undef	NPTY
24 #define	NPTY	32		/* crude XXX */
25 #endif
26 
27 #define BUFSIZ 100		/* Chunk size iomoved from user */
28 
29 /*
30  * pts == /dev/tty[pP]?
31  * ptc == /dev/ptp[pP]?
32  */
33 struct	tty pt_tty[NPTY];
34 struct	pt_ioctl {
35 	int	pt_flags;
36 	int	pt_gensym;
37 	struct	proc *pt_selr, *pt_selw;
38 	int	pt_send;
39 } pt_ioctl[NPTY];
40 
41 #define	PF_RCOLL	0x01
42 #define	PF_WCOLL	0x02
43 #define	PF_NBIO		0x04
44 #define	PF_PKT		0x08		/* packet mode */
45 #define	PF_STOPPED	0x10		/* user told stopped */
46 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
47 #define	PF_NOSTOP	0x40
48 
49 /*ARGSUSED*/
50 ptsopen(dev, flag)
51 	dev_t dev;
52 {
53 	register struct tty *tp;
54 
55 	if (minor(dev) >= NPTY)
56 		return (ENXIO);
57 	tp = &pt_tty[minor(dev)];
58 	if ((tp->t_state & TS_ISOPEN) == 0) {
59 		ttychars(tp);		/* Set up default chars */
60 		tp->t_flags = 0;	/* No features (nor raw mode) */
61 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
62 		return (EBUSY);
63 	if (tp->t_oproc)			/* Ctrlr still around. */
64 		tp->t_state |= TS_CARR_ON;
65 	while ((tp->t_state & TS_CARR_ON) == 0) {
66 		tp->t_state |= TS_WOPEN;
67 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
68 	}
69 	return ((*linesw[tp->t_line].l_open)(dev, tp));
70 }
71 
72 ptsclose(dev)
73 	dev_t dev;
74 {
75 	register struct tty *tp;
76 
77 	tp = &pt_tty[minor(dev)];
78 	(*linesw[tp->t_line].l_close)(tp);
79 	ttyclose(tp);
80 }
81 
82 ptsread(dev, uio)
83 	dev_t dev;
84 	struct uio *uio;
85 {
86 	register struct tty *tp = &pt_tty[minor(dev)];
87 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
88 	int error = 0;
89 
90 again:
91 	if (pti->pt_flags & PF_REMOTE) {
92 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
93 			if (u.u_signal[SIGTTIN] == SIG_IGN ||
94 			    u.u_signal[SIGTTIN] == SIG_HOLD ||
95 	/*
96 			    (u.u_procp->p_flag&SDETACH) ||
97 	*/
98 			    u.u_procp->p_flag&SVFORK)
99 				return (EIO);
100 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
101 			sleep((caddr_t)&lbolt, TTIPRI);
102 		}
103 		if (tp->t_rawq.c_cc == 0) {
104 			if (tp->t_state & TS_NBIO)
105 				return (EWOULDBLOCK);
106 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
107 			goto again;
108 		}
109 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
110 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
111 				error = EFAULT;
112 				break;
113 			}
114 		if (tp->t_rawq.c_cc == 1)
115 			(void) getc(&tp->t_rawq);
116 		if (tp->t_rawq.c_cc)
117 			return (error);
118 	} else
119 		if (tp->t_oproc)
120 			error = (*linesw[tp->t_line].l_read)(tp, uio);
121 	wakeup((caddr_t)&tp->t_rawq.c_cf);
122 	if (pti->pt_selw) {
123 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
124 		pti->pt_selw = 0;
125 		pti->pt_flags &= ~PF_WCOLL;
126 	}
127 	return (error);
128 }
129 
130 /*
131  * Write to pseudo-tty.
132  * Wakeups of controlling tty will happen
133  * indirectly, when tty driver calls ptsstart.
134  */
135 ptswrite(dev, uio)
136 	dev_t dev;
137 	struct uio *uio;
138 {
139 	register struct tty *tp;
140 
141 	tp = &pt_tty[minor(dev)];
142 	if (tp->t_oproc == 0)
143 		return (EIO);
144 	return ((*linesw[tp->t_line].l_write)(tp, uio));
145 }
146 
147 /*
148  * Start output on pseudo-tty.
149  * Wake up process selecting or sleeping for input from controlling tty.
150  */
151 ptsstart(tp)
152 	struct tty *tp;
153 {
154 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
155 
156 	if (tp->t_state & TS_TTSTOP)
157 		return;
158 	if (pti->pt_flags & PF_STOPPED) {
159 		pti->pt_flags &= ~PF_STOPPED;
160 		pti->pt_send = TIOCPKT_START;
161 	}
162 	ptcwakeup(tp);
163 }
164 
165 ptcwakeup(tp)
166 	struct tty *tp;
167 {
168 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
169 
170 	if (pti->pt_selr) {
171 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
172 		pti->pt_selr = 0;
173 		pti->pt_flags &= ~PF_RCOLL;
174 	}
175 	wakeup((caddr_t)&tp->t_outq.c_cf);
176 }
177 
178 /*ARGSUSED*/
179 ptcopen(dev, flag)
180 	dev_t dev;
181 	int flag;
182 {
183 	register struct tty *tp;
184 	struct pt_ioctl *pti;
185 
186 	if (minor(dev) >= NPTY)
187 		return (ENXIO);
188 	tp = &pt_tty[minor(dev)];
189 	if (tp->t_oproc)
190 		return (EIO);
191 	tp->t_oproc = ptsstart;
192 	if (tp->t_state & TS_WOPEN)
193 		wakeup((caddr_t)&tp->t_rawq);
194 	tp->t_state |= TS_CARR_ON;
195 	pti = &pt_ioctl[minor(dev)];
196 	pti->pt_flags = 0;
197 	pti->pt_send = 0;
198 	return (0);
199 }
200 
201 ptcclose(dev)
202 	dev_t dev;
203 {
204 	register struct tty *tp;
205 
206 	tp = &pt_tty[minor(dev)];
207 	if (tp->t_state & TS_ISOPEN)
208 		gsignal(tp->t_pgrp, SIGHUP);
209 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
210 	flushtty(tp, FREAD|FWRITE);
211 	tp->t_oproc = 0;		/* mark closed */
212 }
213 
214 ptcread(dev, uio)
215 	dev_t dev;
216 	struct uio *uio;
217 {
218 	register struct tty *tp = &pt_tty[minor(dev)];
219 	struct pt_ioctl *pti;
220 	int error = 0;
221 
222 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
223 		return (EIO);
224 	pti = &pt_ioctl[minor(dev)];
225 	if (pti->pt_flags & PF_PKT) {
226 		if (pti->pt_send) {
227 			error = ureadc(pti->pt_send, uio);
228 			if (error)
229 				return (error);
230 			pti->pt_send = 0;
231 			return (0);
232 		}
233 		error = ureadc(0, uio);
234 	}
235 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
236 		if (pti->pt_flags&PF_NBIO)
237 			return (EWOULDBLOCK);
238 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
239 	}
240 	while (tp->t_outq.c_cc && uio->uio_resid > 0)
241 		if (ureadc(getc(&tp->t_outq), uio) < 0) {
242 			error = EFAULT;
243 			break;
244 		}
245 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
246 		if (tp->t_state&TS_ASLEEP) {
247 			tp->t_state &= ~TS_ASLEEP;
248 			wakeup((caddr_t)&tp->t_outq);
249 		}
250 		if (tp->t_wsel) {
251 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
252 			tp->t_wsel = 0;
253 			tp->t_state &= ~TS_WCOLL;
254 		}
255 	}
256 	return (error);
257 }
258 
259 ptsstop(tp, flush)
260 	register struct tty *tp;
261 	int flush;
262 {
263 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
264 
265 	/* note: FLUSHREAD and FLUSHWRITE already ok */
266 	if (flush == 0) {
267 		flush = TIOCPKT_STOP;
268 		pti->pt_flags |= PF_STOPPED;
269 	} else {
270 		pti->pt_flags &= ~PF_STOPPED;
271 	}
272 	pti->pt_send |= flush;
273 	ptcwakeup(tp);
274 }
275 
276 ptcselect(dev, rw)
277 	dev_t dev;
278 	int rw;
279 {
280 	register struct tty *tp = &pt_tty[minor(dev)];
281 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
282 	struct proc *p;
283 	int s;
284 
285 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
286 		return (1);
287 	s = spl5();
288 	switch (rw) {
289 
290 	case FREAD:
291 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
292 			splx(s);
293 			return (1);
294 		}
295 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
296 			pti->pt_flags |= PF_RCOLL;
297 		else
298 			pti->pt_selr = u.u_procp;
299 		break;
300 
301 	case FWRITE:
302 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
303 			splx(s);
304 			return (1);
305 		}
306 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
307 			pti->pt_flags |= PF_WCOLL;
308 		else
309 			pti->pt_selw = u.u_procp;
310 		break;
311 	}
312 	splx(s);
313 	return (0);
314 }
315 
316 ptcwrite(dev, uio)
317 	dev_t dev;
318 	struct uio *uio;
319 {
320 	register struct tty *tp = &pt_tty[minor(dev)];
321 	register char *cp, *ce;
322 	register int cc;
323 	char locbuf[BUFSIZ];
324 	int cnt = 0;
325 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
326 	int error = 0;
327 
328 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
329 		return (EIO);
330 	do {
331 		register struct iovec *iov;
332 
333 		if (uio->uio_iovcnt == 0)
334 			break;
335 		iov = uio->uio_iov;
336 		if (iov->iov_len == 0) {
337 			uio->uio_iovcnt--;
338 			uio->uio_iov++;
339 			if (uio->uio_iovcnt < 0)
340 				panic("ptcwrite");
341 			continue;
342 		}
343 		cc = MIN(iov->iov_len, BUFSIZ);
344 		cp = locbuf;
345 		error = uiomove(cp, cc, UIO_WRITE, uio);
346 		if (error)
347 			break;
348 		ce = cp + cc;
349 again:
350 		if (pti->pt_flags & PF_REMOTE) {
351 			if (tp->t_rawq.c_cc) {
352 				if (pti->pt_flags & PF_NBIO) {
353 					iov->iov_base -= ce - cp;
354 					iov->iov_len += ce - cp;
355 					uio->uio_resid += ce - cp;
356 					uio->uio_offset -= ce - cp;
357 					return (EWOULDBLOCK);
358 				}
359 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
360 				goto again;
361 			}
362 			(void) b_to_q(cp, cc, &tp->t_rawq);
363 			(void) putc(0, &tp->t_rawq);
364 			wakeup((caddr_t)&tp->t_rawq);
365 			return (0);
366 		}
367 		while (cp < ce) {
368 			while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) {
369 				wakeup((caddr_t)&tp->t_rawq);
370 				if (tp->t_state & TS_NBIO) {
371 					iov->iov_base -= ce - cp;
372 					iov->iov_len += ce - cp;
373 					uio->uio_resid += ce - cp;
374 					uio->uio_offset -= ce - cp;
375 					if (cnt == 0)
376 						return (EWOULDBLOCK);
377 					return (0);
378 				}
379 				/* Better than just flushing it! */
380 				/* Wait for something to be read */
381 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
382 				goto again;
383 			}
384 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
385 			cnt++;
386 		}
387 	} while (uio->uio_resid);
388 	return (error);
389 }
390 
391 /*ARGSUSED*/
392 ptyioctl(dev, cmd, data, flag)
393 	caddr_t data;
394 	dev_t dev;
395 {
396 	register struct tty *tp = &pt_tty[minor(dev)];
397 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
398 	int error;
399 
400 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
401 	if (cdevsw[major(dev)].d_open == ptcopen)
402 		switch (cmd) {
403 
404 		case TIOCPKT:
405 			if (*(int *)data)
406 				pti->pt_flags |= PF_PKT;
407 			else
408 				pti->pt_flags &= ~PF_PKT;
409 			return (0);
410 
411 		case TIOCREMOTE:
412 			if (*(int *)data)
413 				pti->pt_flags |= PF_REMOTE;
414 			else
415 				pti->pt_flags &= ~PF_REMOTE;
416 			flushtty(tp, FREAD|FWRITE);
417 			return (0);
418 
419 		case FIONBIO:
420 			if (*(int *)data)
421 				pti->pt_flags |= PF_NBIO;
422 			else
423 				pti->pt_flags &= ~PF_NBIO;
424 			return (0);
425 
426 		case TIOCSETP:
427 			while (getc(&tp->t_outq) >= 0)
428 				;
429 			break;
430 		}
431 	error = ttioctl(tp, cmd, data, dev);
432 	if (error < 0)
433 		error = ENOTTY;
434 	{ int stop = (tp->t_stopc == ('s'&037) &&
435 		      tp->t_startc == ('q'&037));
436 	if (pti->pt_flags & PF_NOSTOP) {
437 		if (stop) {
438 			pti->pt_send &= TIOCPKT_NOSTOP;
439 			pti->pt_send |= TIOCPKT_DOSTOP;
440 			pti->pt_flags &= ~PF_NOSTOP;
441 			ptcwakeup(tp);
442 		}
443 	} else {
444 		if (stop == 0) {
445 			pti->pt_send &= ~TIOCPKT_DOSTOP;
446 			pti->pt_send |= TIOCPKT_NOSTOP;
447 			pti->pt_flags |= PF_NOSTOP;
448 			ptcwakeup(tp);
449 		}
450 	}
451 	}
452 	return (error);
453 }
454 #endif
455