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