xref: /csrg-svn/sys/kern/tty_pty.c (revision 22731)
1 /*	tty_pty.c	6.11	85/06/07	*/
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 "param.h"
11 #include "systm.h"
12 #include "ioctl.h"
13 #include "tty.h"
14 #include "dir.h"
15 #include "user.h"
16 #include "conf.h"
17 #include "file.h"
18 #include "proc.h"
19 #include "uio.h"
20 #include "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 to/from user */
28 
29 /*
30  * pts == /dev/tty[pqrs]?
31  * ptc == /dev/pty[pqrs]?
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 	u_char	pt_send;
39 	u_char	pt_ucntl;
40 } pt_ioctl[NPTY];
41 int	npty = NPTY;		/* for pstat -t */
42 
43 #define	PF_RCOLL	0x01
44 #define	PF_WCOLL	0x02
45 #define	PF_NBIO		0x04
46 #define	PF_PKT		0x08		/* packet mode */
47 #define	PF_STOPPED	0x10		/* user told stopped */
48 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
49 #define	PF_NOSTOP	0x40
50 #define PF_UCNTL	0x80		/* user control mode */
51 
52 /*ARGSUSED*/
53 ptsopen(dev, flag)
54 	dev_t dev;
55 {
56 	register struct tty *tp;
57 	int error;
58 
59 #ifdef lint
60 	npty = npty;
61 #endif
62 	if (minor(dev) >= NPTY)
63 		return (ENXIO);
64 	tp = &pt_tty[minor(dev)];
65 	if ((tp->t_state & TS_ISOPEN) == 0) {
66 		ttychars(tp);		/* Set up default chars */
67 		tp->t_ispeed = tp->t_ospeed = EXTB;
68 		tp->t_flags = 0;	/* No features (nor raw mode) */
69 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
70 		return (EBUSY);
71 	if (tp->t_oproc)			/* Ctrlr still around. */
72 		tp->t_state |= TS_CARR_ON;
73 	while ((tp->t_state & TS_CARR_ON) == 0) {
74 		tp->t_state |= TS_WOPEN;
75 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
76 	}
77 	error = (*linesw[tp->t_line].l_open)(dev, tp);
78 	ptcwakeup(tp, FREAD|FWRITE);
79 	return (error);
80 }
81 
82 ptsclose(dev)
83 	dev_t dev;
84 {
85 	register struct tty *tp;
86 
87 	tp = &pt_tty[minor(dev)];
88 	(*linesw[tp->t_line].l_close)(tp);
89 	ttyclose(tp);
90 	ptcwakeup(tp, FREAD|FWRITE);
91 }
92 
93 ptsread(dev, uio)
94 	dev_t dev;
95 	struct uio *uio;
96 {
97 	register struct tty *tp = &pt_tty[minor(dev)];
98 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
99 	int error = 0;
100 
101 again:
102 	if (pti->pt_flags & PF_REMOTE) {
103 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
104 			if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
105 			    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
106 	/*
107 			    (u.u_procp->p_flag&SDETACH) ||
108 	*/
109 			    u.u_procp->p_flag&SVFORK)
110 				return (EIO);
111 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
112 			sleep((caddr_t)&lbolt, TTIPRI);
113 		}
114 		if (tp->t_canq.c_cc == 0) {
115 			if (tp->t_state & TS_NBIO)
116 				return (EWOULDBLOCK);
117 			sleep((caddr_t)&tp->t_canq, TTIPRI);
118 			goto again;
119 		}
120 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
121 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
122 				error = EFAULT;
123 				break;
124 			}
125 		if (tp->t_canq.c_cc == 1)
126 			(void) getc(&tp->t_canq);
127 		if (tp->t_canq.c_cc)
128 			return (error);
129 	} else
130 		if (tp->t_oproc)
131 			error = (*linesw[tp->t_line].l_read)(tp, uio);
132 	ptcwakeup(tp, FWRITE);
133 	return (error);
134 }
135 
136 /*
137  * Write to pseudo-tty.
138  * Wakeups of controlling tty will happen
139  * indirectly, when tty driver calls ptsstart.
140  */
141 ptswrite(dev, uio)
142 	dev_t dev;
143 	struct uio *uio;
144 {
145 	register struct tty *tp;
146 
147 	tp = &pt_tty[minor(dev)];
148 	if (tp->t_oproc == 0)
149 		return (EIO);
150 	return ((*linesw[tp->t_line].l_write)(tp, uio));
151 }
152 
153 /*
154  * Start output on pseudo-tty.
155  * Wake up process selecting or sleeping for input from controlling tty.
156  */
157 ptsstart(tp)
158 	struct tty *tp;
159 {
160 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
161 
162 	if (tp->t_state & TS_TTSTOP)
163 		return;
164 	if (pti->pt_flags & PF_STOPPED) {
165 		pti->pt_flags &= ~PF_STOPPED;
166 		pti->pt_send = TIOCPKT_START;
167 	}
168 	ptcwakeup(tp, FREAD);
169 }
170 
171 ptcwakeup(tp, flag)
172 	struct tty *tp;
173 {
174 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
175 
176 	if (flag & FREAD) {
177 		if (pti->pt_selr) {
178 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
179 			pti->pt_selr = 0;
180 			pti->pt_flags &= ~PF_RCOLL;
181 		}
182 		wakeup((caddr_t)&tp->t_outq.c_cf);
183 	}
184 	if (flag & FWRITE) {
185 		if (pti->pt_selw) {
186 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
187 			pti->pt_selw = 0;
188 			pti->pt_flags &= ~PF_WCOLL;
189 		}
190 		wakeup((caddr_t)&tp->t_rawq.c_cf);
191 	}
192 }
193 
194 /*ARGSUSED*/
195 ptcopen(dev, flag)
196 	dev_t dev;
197 	int flag;
198 {
199 	register struct tty *tp;
200 	struct pt_ioctl *pti;
201 
202 	if (minor(dev) >= NPTY)
203 		return (ENXIO);
204 	tp = &pt_tty[minor(dev)];
205 	if (tp->t_oproc)
206 		return (EIO);
207 	tp->t_oproc = ptsstart;
208 	if (tp->t_state & TS_WOPEN)
209 		wakeup((caddr_t)&tp->t_rawq);
210 	tp->t_state |= TS_CARR_ON;
211 	pti = &pt_ioctl[minor(dev)];
212 	pti->pt_flags = 0;
213 	pti->pt_send = 0;
214 	pti->pt_ucntl = 0;
215 	return (0);
216 }
217 
218 ptcclose(dev)
219 	dev_t dev;
220 {
221 	register struct tty *tp;
222 
223 	tp = &pt_tty[minor(dev)];
224 	if (tp->t_state & TS_ISOPEN)
225 		gsignal(tp->t_pgrp, SIGHUP);
226 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
227 	ttyflush(tp, FREAD|FWRITE);
228 	tp->t_oproc = 0;		/* mark closed */
229 }
230 
231 ptcread(dev, uio)
232 	dev_t dev;
233 	struct uio *uio;
234 {
235 	register struct tty *tp = &pt_tty[minor(dev)];
236 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
237 	char buf[BUFSIZ];
238 	int error = 0, cc;
239 
240 	/*
241 	 * We want to block until the slave
242 	 * is open, and there's something to read;
243 	 * but if we lost the slave or we're NBIO,
244 	 * then return the appropriate error instead.
245 	 */
246 	for (;;) {
247 		if (tp->t_state&TS_ISOPEN) {
248 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
249 				error = ureadc(pti->pt_send, uio);
250 				if (error)
251 					return (error);
252 				pti->pt_send = 0;
253 				return (0);
254 			}
255 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
256 				error = ureadc(pti->pt_ucntl, uio);
257 				if (error)
258 					return (error);
259 				pti->pt_ucntl = 0;
260 				return (0);
261 			}
262 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
263 				break;
264 		}
265 		if ((tp->t_state&TS_CARR_ON) == 0)
266 			return (EIO);
267 		if (pti->pt_flags&PF_NBIO)
268 			return (EWOULDBLOCK);
269 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
270 	}
271 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
272 		error = ureadc(0, uio);
273 	while (uio->uio_resid > 0 && error == 0) {
274 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
275 		if (cc <= 0)
276 			break;
277 		error = uiomove(buf, cc, UIO_READ, uio);
278 	}
279 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
280 		if (tp->t_state&TS_ASLEEP) {
281 			tp->t_state &= ~TS_ASLEEP;
282 			wakeup((caddr_t)&tp->t_outq);
283 		}
284 		if (tp->t_wsel) {
285 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
286 			tp->t_wsel = 0;
287 			tp->t_state &= ~TS_WCOLL;
288 		}
289 	}
290 	return (error);
291 }
292 
293 ptsstop(tp, flush)
294 	register struct tty *tp;
295 	int flush;
296 {
297 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
298 	int flag;
299 
300 	/* note: FLUSHREAD and FLUSHWRITE already ok */
301 	if (flush == 0) {
302 		flush = TIOCPKT_STOP;
303 		pti->pt_flags |= PF_STOPPED;
304 	} else
305 		pti->pt_flags &= ~PF_STOPPED;
306 	pti->pt_send |= flush;
307 	/* change of perspective */
308 	flag = 0;
309 	if (flush & FREAD)
310 		flag |= FWRITE;
311 	if (flush & FWRITE)
312 		flag |= FREAD;
313 	ptcwakeup(tp, flush);
314 }
315 
316 ptcselect(dev, rw)
317 	dev_t dev;
318 	int rw;
319 {
320 	register struct tty *tp = &pt_tty[minor(dev)];
321 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
322 	struct proc *p;
323 	int s;
324 
325 	if ((tp->t_state&TS_CARR_ON) == 0)
326 		return (1);
327 	s = spl5();
328 	switch (rw) {
329 
330 	case FREAD:
331 		if ((tp->t_state&TS_ISOPEN) &&
332 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
333 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl ||
334 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) {
335 			splx(s);
336 			return (1);
337 		}
338 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
339 			pti->pt_flags |= PF_RCOLL;
340 		else
341 			pti->pt_selr = u.u_procp;
342 		break;
343 
344 	case FWRITE:
345 		if ((tp->t_state&TS_ISOPEN) &&
346 		    ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) {
347 			splx(s);
348 			return (1);
349 		}
350 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
351 			pti->pt_flags |= PF_WCOLL;
352 		else
353 			pti->pt_selw = u.u_procp;
354 		break;
355 	}
356 	splx(s);
357 	return (0);
358 }
359 
360 ptcwrite(dev, uio)
361 	dev_t dev;
362 	register struct uio *uio;
363 {
364 	register struct tty *tp = &pt_tty[minor(dev)];
365 	register struct iovec *iov;
366 	register char *cp;
367 	register int cc = 0;
368 	char locbuf[BUFSIZ];
369 	int cnt = 0;
370 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
371 	int error = 0;
372 
373 again:
374 	if ((tp->t_state&TS_ISOPEN) == 0)
375 		goto block;
376 	if (cnt == 0 && pti->pt_flags & PF_REMOTE) {
377 		if (uio->uio_iovcnt <= 0)
378 			return (0);
379 		if (tp->t_canq.c_cc)
380 			goto block;
381 		iov = uio->uio_iov;
382 		if (cc == 0 && iov->iov_len) {
383 			cc = MIN(iov->iov_len, BUFSIZ);
384 			cp = locbuf;
385 			error = uiomove(cp, cc, UIO_WRITE, uio);
386 			if (error)
387 				return (error);
388 			/* check again for safety */
389 			if ((tp->t_state&TS_ISOPEN) == 0)
390 				return (EIO);
391 			if (tp->t_canq.c_cc)
392 				goto block;
393 		}
394 		if (cc)
395 			(void) b_to_q(cp, cc, &tp->t_canq);
396 		(void) putc(0, &tp->t_canq);
397 		ttwakeup(tp);
398 		wakeup((caddr_t)&tp->t_canq);
399 		return (0);
400 	}
401 	while (uio->uio_iovcnt > 0) {
402 		iov = uio->uio_iov;
403 		if (cc == 0) {
404 			if (iov->iov_len == 0) {
405 				uio->uio_iovcnt--;
406 				uio->uio_iov++;
407 				continue;
408 			}
409 			cc = MIN(iov->iov_len, BUFSIZ);
410 			cp = locbuf;
411 			error = uiomove(cp, cc, UIO_WRITE, uio);
412 			if (error)
413 				return (error);
414 			/* check again for safety */
415 			if ((tp->t_state&TS_ISOPEN) == 0)
416 				return (EIO);
417 		}
418 		while (--cc >= 0) {
419 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
420 			cnt++;
421 		}
422 		cc = 0;
423 	}
424 	return (0);
425 block:
426 	/*
427 	 * Come here to wait for slave to open or for space
428 	 * in outq.
429 	 */
430 	if ((tp->t_state&TS_CARR_ON) == 0)
431 		return (EIO);
432 	if (pti->pt_flags & PF_NBIO) {
433 		if (cnt == 0)
434 			return (EWOULDBLOCK);
435 		iov->iov_base -= cc;
436 		iov->iov_len += cc;
437 		uio->uio_resid += cc;
438 		uio->uio_offset -= cc;
439 		return (0);
440 	}
441 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
442 	goto again;
443 }
444 
445 /*ARGSUSED*/
446 ptyioctl(dev, cmd, data, flag)
447 	caddr_t data;
448 	dev_t dev;
449 {
450 	register struct tty *tp = &pt_tty[minor(dev)];
451 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
452 	int stop, error;
453 
454 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
455 	if (cdevsw[major(dev)].d_open == ptcopen)
456 		switch (cmd) {
457 
458 		case TIOCPKT:
459 			if (*(int *)data) {
460 				if (pti->pt_flags & PF_UCNTL)
461 					return (EINVAL);
462 				pti->pt_flags |= PF_PKT;
463 			} else
464 				pti->pt_flags &= ~PF_PKT;
465 			return (0);
466 
467 		case TIOCUCNTL:
468 			if (*(int *)data) {
469 				if (pti->pt_flags & PF_PKT)
470 					return (EINVAL);
471 				pti->pt_flags |= PF_UCNTL;
472 			} else
473 				pti->pt_flags &= ~PF_UCNTL;
474 			return (0);
475 
476 		case TIOCREMOTE:
477 			if (*(int *)data)
478 				pti->pt_flags |= PF_REMOTE;
479 			else
480 				pti->pt_flags &= ~PF_REMOTE;
481 			ttyflush(tp, FREAD|FWRITE);
482 			return (0);
483 
484 		case FIONBIO:
485 			if (*(int *)data)
486 				pti->pt_flags |= PF_NBIO;
487 			else
488 				pti->pt_flags &= ~PF_NBIO;
489 			return (0);
490 
491 		case TIOCSETP:
492 			while (getc(&tp->t_outq) >= 0)
493 				;
494 			break;
495 		}
496 	error = ttioctl(tp, cmd, data, flag);
497 	if (error < 0) {
498 		if (pti->pt_flags & PF_UCNTL &&
499 		    (cmd & ~0xff) == _IO(u,0)) {
500 			if (cmd & 0xff) {
501 				pti->pt_ucntl = (u_char)cmd;
502 				ptcwakeup(tp, FREAD);
503 			}
504 			return (0);
505 		}
506 		error = ENOTTY;
507 	}
508 	stop = (tp->t_flags & RAW) == 0 &&
509 	    tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
510 	if (pti->pt_flags & PF_NOSTOP) {
511 		if (stop) {
512 			pti->pt_send &= TIOCPKT_NOSTOP;
513 			pti->pt_send |= TIOCPKT_DOSTOP;
514 			pti->pt_flags &= ~PF_NOSTOP;
515 			ptcwakeup(tp, FREAD);
516 		}
517 	} else {
518 		if (!stop) {
519 			pti->pt_send &= ~TIOCPKT_DOSTOP;
520 			pti->pt_send |= TIOCPKT_NOSTOP;
521 			pti->pt_flags |= PF_NOSTOP;
522 			ptcwakeup(tp, FREAD);
523 		}
524 	}
525 	return (error);
526 }
527 #endif
528