xref: /csrg-svn/sys/kern/tty_pty.c (revision 24522)
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.14 (Berkeley) 09/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 	/*
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_line)
231 		(*linesw[tp->t_line].l_close)(tp);
232 	if (tp->t_state & TS_ISOPEN)
233 		gsignal(tp->t_pgrp, SIGHUP);
234 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
235 	ttyflush(tp, FREAD|FWRITE);
236 	tp->t_oproc = 0;		/* mark closed */
237 }
238 
239 ptcread(dev, uio)
240 	dev_t dev;
241 	struct uio *uio;
242 {
243 	register struct tty *tp = &pt_tty[minor(dev)];
244 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
245 	char buf[BUFSIZ];
246 	int error = 0, cc;
247 
248 	/*
249 	 * We want to block until the slave
250 	 * is open, and there's something to read;
251 	 * but if we lost the slave or we're NBIO,
252 	 * then return the appropriate error instead.
253 	 */
254 	for (;;) {
255 		if (tp->t_state&TS_ISOPEN) {
256 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
257 				error = ureadc(pti->pt_send, uio);
258 				if (error)
259 					return (error);
260 				pti->pt_send = 0;
261 				return (0);
262 			}
263 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
264 				error = ureadc(pti->pt_ucntl, uio);
265 				if (error)
266 					return (error);
267 				pti->pt_ucntl = 0;
268 				return (0);
269 			}
270 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
271 				break;
272 		}
273 		if ((tp->t_state&TS_CARR_ON) == 0)
274 			return (EIO);
275 		if (pti->pt_flags&PF_NBIO)
276 			return (EWOULDBLOCK);
277 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
278 	}
279 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
280 		error = ureadc(0, uio);
281 	while (uio->uio_resid > 0 && error == 0) {
282 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
283 		if (cc <= 0)
284 			break;
285 		error = uiomove(buf, cc, UIO_READ, uio);
286 	}
287 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
288 		if (tp->t_state&TS_ASLEEP) {
289 			tp->t_state &= ~TS_ASLEEP;
290 			wakeup((caddr_t)&tp->t_outq);
291 		}
292 		if (tp->t_wsel) {
293 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
294 			tp->t_wsel = 0;
295 			tp->t_state &= ~TS_WCOLL;
296 		}
297 	}
298 	return (error);
299 }
300 
301 ptsstop(tp, flush)
302 	register struct tty *tp;
303 	int flush;
304 {
305 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
306 	int flag;
307 
308 	/* note: FLUSHREAD and FLUSHWRITE already ok */
309 	if (flush == 0) {
310 		flush = TIOCPKT_STOP;
311 		pti->pt_flags |= PF_STOPPED;
312 	} else
313 		pti->pt_flags &= ~PF_STOPPED;
314 	pti->pt_send |= flush;
315 	/* change of perspective */
316 	flag = 0;
317 	if (flush & FREAD)
318 		flag |= FWRITE;
319 	if (flush & FWRITE)
320 		flag |= FREAD;
321 	ptcwakeup(tp, flag);
322 }
323 
324 ptcselect(dev, rw)
325 	dev_t dev;
326 	int rw;
327 {
328 	register struct tty *tp = &pt_tty[minor(dev)];
329 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
330 	struct proc *p;
331 	int s;
332 
333 	if ((tp->t_state&TS_CARR_ON) == 0)
334 		return (1);
335 	s = spl5();
336 	switch (rw) {
337 
338 	case FREAD:
339 		if ((tp->t_state&TS_ISOPEN) &&
340 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
341 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl ||
342 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) {
343 			splx(s);
344 			return (1);
345 		}
346 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
347 			pti->pt_flags |= PF_RCOLL;
348 		else
349 			pti->pt_selr = u.u_procp;
350 		break;
351 
352 	case FWRITE:
353 		if ((tp->t_state&TS_ISOPEN) &&
354 		    ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) {
355 			splx(s);
356 			return (1);
357 		}
358 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
359 			pti->pt_flags |= PF_WCOLL;
360 		else
361 			pti->pt_selw = u.u_procp;
362 		break;
363 	}
364 	splx(s);
365 	return (0);
366 }
367 
368 ptcwrite(dev, uio)
369 	dev_t dev;
370 	register struct uio *uio;
371 {
372 	register struct tty *tp = &pt_tty[minor(dev)];
373 	register struct iovec *iov;
374 	register char *cp;
375 	register int cc = 0;
376 	char locbuf[BUFSIZ];
377 	int cnt = 0;
378 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
379 	int error = 0;
380 
381 again:
382 	if ((tp->t_state&TS_ISOPEN) == 0)
383 		goto block;
384 	if (pti->pt_flags & PF_REMOTE) {
385 		if (tp->t_canq.c_cc)
386 			goto block;
387 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
388 			iov = uio->uio_iov;
389 			if (iov->iov_len == 0) {
390 				uio->uio_iovcnt--;
391 				uio->uio_iov++;
392 				continue;
393 			}
394 			if (cc == 0) {
395 				cc = MIN(iov->iov_len, BUFSIZ);
396 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
397 				cp = locbuf;
398 				error = uiomove(cp, cc, UIO_WRITE, uio);
399 				if (error)
400 					return (error);
401 				/* check again for safety */
402 				if ((tp->t_state&TS_ISOPEN) == 0)
403 					return (EIO);
404 			}
405 			if (cc)
406 				(void) b_to_q(cp, cc, &tp->t_canq);
407 			cc = 0;
408 		}
409 		(void) putc(0, &tp->t_canq);
410 		ttwakeup(tp);
411 		wakeup((caddr_t)&tp->t_canq);
412 		return (0);
413 	}
414 	while (uio->uio_iovcnt > 0) {
415 		iov = uio->uio_iov;
416 		if (cc == 0) {
417 			if (iov->iov_len == 0) {
418 				uio->uio_iovcnt--;
419 				uio->uio_iov++;
420 				continue;
421 			}
422 			cc = MIN(iov->iov_len, BUFSIZ);
423 			cp = locbuf;
424 			error = uiomove(cp, cc, UIO_WRITE, uio);
425 			if (error)
426 				return (error);
427 			/* check again for safety */
428 			if ((tp->t_state&TS_ISOPEN) == 0)
429 				return (EIO);
430 		}
431 		while (cc > 0) {
432 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
433 			    (tp->t_canq.c_cc > 0)) {
434 				wakeup((caddr_t)&tp->t_rawq);
435 				goto block;
436 			}
437 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
438 			cnt++;
439 			cc--;
440 		}
441 		cc = 0;
442 	}
443 	return (0);
444 block:
445 	/*
446 	 * Come here to wait for slave to open, for space
447 	 * in outq, or space in rawq.
448 	 */
449 	if ((tp->t_state&TS_CARR_ON) == 0)
450 		return (EIO);
451 	if (pti->pt_flags & PF_NBIO) {
452 		iov->iov_base -= cc;
453 		iov->iov_len += cc;
454 		uio->uio_resid += cc;
455 		uio->uio_offset -= cc;
456 		if (cnt == 0)
457 			return (EWOULDBLOCK);
458 		return (0);
459 	}
460 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
461 	goto again;
462 }
463 
464 /*ARGSUSED*/
465 ptyioctl(dev, cmd, data, flag)
466 	caddr_t data;
467 	dev_t dev;
468 {
469 	register struct tty *tp = &pt_tty[minor(dev)];
470 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
471 	int stop, error;
472 
473 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
474 	if (cdevsw[major(dev)].d_open == ptcopen)
475 		switch (cmd) {
476 
477 		case TIOCPKT:
478 			if (*(int *)data) {
479 				if (pti->pt_flags & PF_UCNTL)
480 					return (EINVAL);
481 				pti->pt_flags |= PF_PKT;
482 			} else
483 				pti->pt_flags &= ~PF_PKT;
484 			return (0);
485 
486 		case TIOCUCNTL:
487 			if (*(int *)data) {
488 				if (pti->pt_flags & PF_PKT)
489 					return (EINVAL);
490 				pti->pt_flags |= PF_UCNTL;
491 			} else
492 				pti->pt_flags &= ~PF_UCNTL;
493 			return (0);
494 
495 		case TIOCREMOTE:
496 			if (*(int *)data)
497 				pti->pt_flags |= PF_REMOTE;
498 			else
499 				pti->pt_flags &= ~PF_REMOTE;
500 			ttyflush(tp, FREAD|FWRITE);
501 			return (0);
502 
503 		case FIONBIO:
504 			if (*(int *)data)
505 				pti->pt_flags |= PF_NBIO;
506 			else
507 				pti->pt_flags &= ~PF_NBIO;
508 			return (0);
509 
510 		case TIOCSETP:
511 			while (getc(&tp->t_outq) >= 0)
512 				;
513 			break;
514 		}
515 	error = ttioctl(tp, cmd, data, flag);
516 	if (error < 0) {
517 		if (pti->pt_flags & PF_UCNTL &&
518 		    (cmd & ~0xff) == _IO(u,0)) {
519 			if (cmd & 0xff) {
520 				pti->pt_ucntl = (u_char)cmd;
521 				ptcwakeup(tp, FREAD);
522 			}
523 			return (0);
524 		}
525 		error = ENOTTY;
526 	}
527 	stop = (tp->t_flags & RAW) == 0 &&
528 	    tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
529 	if (pti->pt_flags & PF_NOSTOP) {
530 		if (stop) {
531 			pti->pt_send &= TIOCPKT_NOSTOP;
532 			pti->pt_send |= TIOCPKT_DOSTOP;
533 			pti->pt_flags &= ~PF_NOSTOP;
534 			ptcwakeup(tp, FREAD);
535 		}
536 	} else {
537 		if (!stop) {
538 			pti->pt_send &= ~TIOCPKT_DOSTOP;
539 			pti->pt_send |= TIOCPKT_NOSTOP;
540 			pti->pt_flags |= PF_NOSTOP;
541 			ptcwakeup(tp, FREAD);
542 		}
543 	}
544 	return (error);
545 }
546 #endif
547