xref: /csrg-svn/sys/kern/tty_pty.c (revision 25390)
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.15 (Berkeley) 11/04/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 			    u.u_procp->p_flag&SVFORK)
113 				return (EIO);
114 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
115 			sleep((caddr_t)&lbolt, TTIPRI);
116 		}
117 		if (tp->t_canq.c_cc == 0) {
118 			if (tp->t_state & TS_NBIO)
119 				return (EWOULDBLOCK);
120 			sleep((caddr_t)&tp->t_canq, TTIPRI);
121 			goto again;
122 		}
123 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
124 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
125 				error = EFAULT;
126 				break;
127 			}
128 		if (tp->t_canq.c_cc == 1)
129 			(void) getc(&tp->t_canq);
130 		if (tp->t_canq.c_cc)
131 			return (error);
132 	} else
133 		if (tp->t_oproc)
134 			error = (*linesw[tp->t_line].l_read)(tp, uio);
135 	ptcwakeup(tp, FWRITE);
136 	return (error);
137 }
138 
139 /*
140  * Write to pseudo-tty.
141  * Wakeups of controlling tty will happen
142  * indirectly, when tty driver calls ptsstart.
143  */
144 ptswrite(dev, uio)
145 	dev_t dev;
146 	struct uio *uio;
147 {
148 	register struct tty *tp;
149 
150 	tp = &pt_tty[minor(dev)];
151 	if (tp->t_oproc == 0)
152 		return (EIO);
153 	return ((*linesw[tp->t_line].l_write)(tp, uio));
154 }
155 
156 /*
157  * Start output on pseudo-tty.
158  * Wake up process selecting or sleeping for input from controlling tty.
159  */
160 ptsstart(tp)
161 	struct tty *tp;
162 {
163 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
164 
165 	if (tp->t_state & TS_TTSTOP)
166 		return;
167 	if (pti->pt_flags & PF_STOPPED) {
168 		pti->pt_flags &= ~PF_STOPPED;
169 		pti->pt_send = TIOCPKT_START;
170 	}
171 	ptcwakeup(tp, FREAD);
172 }
173 
174 ptcwakeup(tp, flag)
175 	struct tty *tp;
176 {
177 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
178 
179 	if (flag & FREAD) {
180 		if (pti->pt_selr) {
181 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
182 			pti->pt_selr = 0;
183 			pti->pt_flags &= ~PF_RCOLL;
184 		}
185 		wakeup((caddr_t)&tp->t_outq.c_cf);
186 	}
187 	if (flag & FWRITE) {
188 		if (pti->pt_selw) {
189 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
190 			pti->pt_selw = 0;
191 			pti->pt_flags &= ~PF_WCOLL;
192 		}
193 		wakeup((caddr_t)&tp->t_rawq.c_cf);
194 	}
195 }
196 
197 /*ARGSUSED*/
198 ptcopen(dev, flag)
199 	dev_t dev;
200 	int flag;
201 {
202 	register struct tty *tp;
203 	struct pt_ioctl *pti;
204 
205 	if (minor(dev) >= NPTY)
206 		return (ENXIO);
207 	tp = &pt_tty[minor(dev)];
208 	if (tp->t_oproc)
209 		return (EIO);
210 	tp->t_oproc = ptsstart;
211 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
212 	tp->t_state |= TS_CARR_ON;
213 	pti = &pt_ioctl[minor(dev)];
214 	pti->pt_flags = 0;
215 	pti->pt_send = 0;
216 	pti->pt_ucntl = 0;
217 	return (0);
218 }
219 
220 ptcclose(dev)
221 	dev_t dev;
222 {
223 	register struct tty *tp;
224 
225 	tp = &pt_tty[minor(dev)];
226 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
227 	tp->t_oproc = 0;		/* mark closed */
228 }
229 
230 ptcread(dev, uio)
231 	dev_t dev;
232 	struct uio *uio;
233 {
234 	register struct tty *tp = &pt_tty[minor(dev)];
235 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
236 	char buf[BUFSIZ];
237 	int error = 0, cc;
238 
239 	/*
240 	 * We want to block until the slave
241 	 * is open, and there's something to read;
242 	 * but if we lost the slave or we're NBIO,
243 	 * then return the appropriate error instead.
244 	 */
245 	for (;;) {
246 		if (tp->t_state&TS_ISOPEN) {
247 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
248 				error = ureadc(pti->pt_send, uio);
249 				if (error)
250 					return (error);
251 				pti->pt_send = 0;
252 				return (0);
253 			}
254 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
255 				error = ureadc(pti->pt_ucntl, uio);
256 				if (error)
257 					return (error);
258 				pti->pt_ucntl = 0;
259 				return (0);
260 			}
261 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
262 				break;
263 		}
264 		if ((tp->t_state&TS_CARR_ON) == 0)
265 			return (EIO);
266 		if (pti->pt_flags&PF_NBIO)
267 			return (EWOULDBLOCK);
268 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
269 	}
270 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
271 		error = ureadc(0, uio);
272 	while (uio->uio_resid > 0 && error == 0) {
273 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
274 		if (cc <= 0)
275 			break;
276 		error = uiomove(buf, cc, UIO_READ, uio);
277 	}
278 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
279 		if (tp->t_state&TS_ASLEEP) {
280 			tp->t_state &= ~TS_ASLEEP;
281 			wakeup((caddr_t)&tp->t_outq);
282 		}
283 		if (tp->t_wsel) {
284 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
285 			tp->t_wsel = 0;
286 			tp->t_state &= ~TS_WCOLL;
287 		}
288 	}
289 	return (error);
290 }
291 
292 ptsstop(tp, flush)
293 	register struct tty *tp;
294 	int flush;
295 {
296 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
297 	int flag;
298 
299 	/* note: FLUSHREAD and FLUSHWRITE already ok */
300 	if (flush == 0) {
301 		flush = TIOCPKT_STOP;
302 		pti->pt_flags |= PF_STOPPED;
303 	} else
304 		pti->pt_flags &= ~PF_STOPPED;
305 	pti->pt_send |= flush;
306 	/* change of perspective */
307 	flag = 0;
308 	if (flush & FREAD)
309 		flag |= FWRITE;
310 	if (flush & FWRITE)
311 		flag |= FREAD;
312 	ptcwakeup(tp, flag);
313 }
314 
315 ptcselect(dev, rw)
316 	dev_t dev;
317 	int rw;
318 {
319 	register struct tty *tp = &pt_tty[minor(dev)];
320 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
321 	struct proc *p;
322 	int s;
323 
324 	if ((tp->t_state&TS_CARR_ON) == 0)
325 		return (1);
326 	s = spl5();
327 	switch (rw) {
328 
329 	case FREAD:
330 		if ((tp->t_state&TS_ISOPEN) &&
331 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
332 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl ||
333 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) {
334 			splx(s);
335 			return (1);
336 		}
337 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
338 			pti->pt_flags |= PF_RCOLL;
339 		else
340 			pti->pt_selr = u.u_procp;
341 		break;
342 
343 	case FWRITE:
344 		if ((tp->t_state&TS_ISOPEN) &&
345 		    ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) {
346 			splx(s);
347 			return (1);
348 		}
349 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
350 			pti->pt_flags |= PF_WCOLL;
351 		else
352 			pti->pt_selw = u.u_procp;
353 		break;
354 	}
355 	splx(s);
356 	return (0);
357 }
358 
359 ptcwrite(dev, uio)
360 	dev_t dev;
361 	register struct uio *uio;
362 {
363 	register struct tty *tp = &pt_tty[minor(dev)];
364 	register struct iovec *iov;
365 	register char *cp;
366 	register int cc = 0;
367 	char locbuf[BUFSIZ];
368 	int cnt = 0;
369 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
370 	int error = 0;
371 
372 again:
373 	if ((tp->t_state&TS_ISOPEN) == 0)
374 		goto block;
375 	if (pti->pt_flags & PF_REMOTE) {
376 		if (tp->t_canq.c_cc)
377 			goto block;
378 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
379 			iov = uio->uio_iov;
380 			if (iov->iov_len == 0) {
381 				uio->uio_iovcnt--;
382 				uio->uio_iov++;
383 				continue;
384 			}
385 			if (cc == 0) {
386 				cc = MIN(iov->iov_len, BUFSIZ);
387 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
388 				cp = locbuf;
389 				error = uiomove(cp, cc, UIO_WRITE, uio);
390 				if (error)
391 					return (error);
392 				/* check again for safety */
393 				if ((tp->t_state&TS_ISOPEN) == 0)
394 					return (EIO);
395 			}
396 			if (cc)
397 				(void) b_to_q(cp, cc, &tp->t_canq);
398 			cc = 0;
399 		}
400 		(void) putc(0, &tp->t_canq);
401 		ttwakeup(tp);
402 		wakeup((caddr_t)&tp->t_canq);
403 		return (0);
404 	}
405 	while (uio->uio_iovcnt > 0) {
406 		iov = uio->uio_iov;
407 		if (cc == 0) {
408 			if (iov->iov_len == 0) {
409 				uio->uio_iovcnt--;
410 				uio->uio_iov++;
411 				continue;
412 			}
413 			cc = MIN(iov->iov_len, BUFSIZ);
414 			cp = locbuf;
415 			error = uiomove(cp, cc, UIO_WRITE, uio);
416 			if (error)
417 				return (error);
418 			/* check again for safety */
419 			if ((tp->t_state&TS_ISOPEN) == 0)
420 				return (EIO);
421 		}
422 		while (cc > 0) {
423 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
424 			    (tp->t_canq.c_cc > 0)) {
425 				wakeup((caddr_t)&tp->t_rawq);
426 				goto block;
427 			}
428 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
429 			cnt++;
430 			cc--;
431 		}
432 		cc = 0;
433 	}
434 	return (0);
435 block:
436 	/*
437 	 * Come here to wait for slave to open, for space
438 	 * in outq, or space in rawq.
439 	 */
440 	if ((tp->t_state&TS_CARR_ON) == 0)
441 		return (EIO);
442 	if (pti->pt_flags & PF_NBIO) {
443 		iov->iov_base -= cc;
444 		iov->iov_len += cc;
445 		uio->uio_resid += cc;
446 		uio->uio_offset -= cc;
447 		if (cnt == 0)
448 			return (EWOULDBLOCK);
449 		return (0);
450 	}
451 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
452 	goto again;
453 }
454 
455 /*ARGSUSED*/
456 ptyioctl(dev, cmd, data, flag)
457 	caddr_t data;
458 	dev_t dev;
459 {
460 	register struct tty *tp = &pt_tty[minor(dev)];
461 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
462 	int stop, error;
463 	extern ttyinput();
464 
465 	/*
466 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
467 	 * ttywflush(tp) will hang if there are characters in the outq.
468 	 */
469 	if (cdevsw[major(dev)].d_open == ptcopen)
470 		switch (cmd) {
471 
472 		case TIOCPKT:
473 			if (*(int *)data) {
474 				if (pti->pt_flags & PF_UCNTL)
475 					return (EINVAL);
476 				pti->pt_flags |= PF_PKT;
477 			} else
478 				pti->pt_flags &= ~PF_PKT;
479 			return (0);
480 
481 		case TIOCUCNTL:
482 			if (*(int *)data) {
483 				if (pti->pt_flags & PF_PKT)
484 					return (EINVAL);
485 				pti->pt_flags |= PF_UCNTL;
486 			} else
487 				pti->pt_flags &= ~PF_UCNTL;
488 			return (0);
489 
490 		case TIOCREMOTE:
491 			if (*(int *)data)
492 				pti->pt_flags |= PF_REMOTE;
493 			else
494 				pti->pt_flags &= ~PF_REMOTE;
495 			ttyflush(tp, FREAD|FWRITE);
496 			return (0);
497 
498 		case FIONBIO:
499 			if (*(int *)data)
500 				pti->pt_flags |= PF_NBIO;
501 			else
502 				pti->pt_flags &= ~PF_NBIO;
503 			return (0);
504 
505 		case TIOCSETP:
506 		case TIOCSETN:
507 		case TIOCSETD:
508 			while (getc(&tp->t_outq) >= 0)
509 				;
510 			break;
511 		}
512 	error = ttioctl(tp, cmd, data, flag);
513 	/*
514 	 * Since we use the tty queues internally,
515 	 * pty's can't be switched to disciplines which overwrite
516 	 * the queues.  We can't tell anything about the discipline
517 	 * from here...
518 	 */
519 	if (linesw[tp->t_line].l_rint != ttyinput) {
520 		(*linesw[tp->t_line].l_close)(tp);
521 		tp->t_line = 0;
522 		(void)(*linesw[tp->t_line].l_open)(dev, tp);
523 		error = ENOTTY;
524 	}
525 	if (error < 0) {
526 		if (pti->pt_flags & PF_UCNTL &&
527 		    (cmd & ~0xff) == _IO(u,0)) {
528 			if (cmd & 0xff) {
529 				pti->pt_ucntl = (u_char)cmd;
530 				ptcwakeup(tp, FREAD);
531 			}
532 			return (0);
533 		}
534 		error = ENOTTY;
535 	}
536 	stop = (tp->t_flags & RAW) == 0 &&
537 	    tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
538 	if (pti->pt_flags & PF_NOSTOP) {
539 		if (stop) {
540 			pti->pt_send &= TIOCPKT_NOSTOP;
541 			pti->pt_send |= TIOCPKT_DOSTOP;
542 			pti->pt_flags &= ~PF_NOSTOP;
543 			ptcwakeup(tp, FREAD);
544 		}
545 	} else {
546 		if (!stop) {
547 			pti->pt_send &= ~TIOCPKT_DOSTOP;
548 			pti->pt_send |= TIOCPKT_NOSTOP;
549 			pti->pt_flags |= PF_NOSTOP;
550 			ptcwakeup(tp, FREAD);
551 		}
552 	}
553 	return (error);
554 }
555 #endif
556