xref: /csrg-svn/sys/kern/tty_pty.c (revision 38007)
1 /*
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)tty_pty.c	7.7 (Berkeley) 05/15/89
18  */
19 
20 /*
21  * Pseudo-teletype Driver
22  * (Actually two drivers, requiring two entries in 'cdevsw')
23  */
24 #include "pty.h"
25 
26 #if NPTY > 0
27 #include "param.h"
28 #include "systm.h"
29 #include "ioctl.h"
30 #include "tty.h"
31 #include "user.h"
32 #include "conf.h"
33 #include "file.h"
34 #include "proc.h"
35 #include "uio.h"
36 #include "kernel.h"
37 #include "vnode.h"
38 
39 #if NPTY == 1
40 #undef NPTY
41 #define	NPTY	32		/* crude XXX */
42 #endif
43 
44 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
45 
46 /*
47  * pts == /dev/tty[pqrs]?
48  * ptc == /dev/pty[pqrs]?
49  */
50 struct	tty pt_tty[NPTY];
51 struct	pt_ioctl {
52 	int	pt_flags;
53 	struct	proc *pt_selr, *pt_selw;
54 	u_char	pt_send;
55 	u_char	pt_ucntl;
56 } pt_ioctl[NPTY];
57 int	npty = NPTY;		/* for pstat -t */
58 
59 int ptydebug = 0;
60 
61 #define	PF_RCOLL	0x01
62 #define	PF_WCOLL	0x02
63 #define	PF_NBIO		0x04
64 #define	PF_PKT		0x08		/* packet mode */
65 #define	PF_STOPPED	0x10		/* user told stopped */
66 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
67 #define	PF_NOSTOP	0x40
68 #define PF_UCNTL	0x80		/* user control mode */
69 
70 /*ARGSUSED*/
71 ptsopen(dev, flag)
72 	dev_t dev;
73 {
74 	register struct tty *tp;
75 	int error;
76 
77 #ifdef lint
78 	npty = npty;
79 #endif
80 	if (minor(dev) >= NPTY)
81 		return (ENXIO);
82 	tp = &pt_tty[minor(dev)];
83 	if ((tp->t_state & TS_ISOPEN) == 0) {
84 		ttychars(tp);		/* Set up default chars */
85 		tp->t_iflag = TTYDEF_IFLAG;
86 		tp->t_oflag = TTYDEF_OFLAG;
87 		tp->t_lflag = TTYDEF_LFLAG;
88 		tp->t_cflag = TTYDEF_CFLAG;
89 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
90 		ttsetwater(tp);		/* would be done in xxparam() */
91 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
92 		return (EBUSY);
93 	if (tp->t_oproc)			/* Ctrlr still around. */
94 		tp->t_state |= TS_CARR_ON;
95 	while ((tp->t_state & TS_CARR_ON) == 0) {
96 		tp->t_state |= TS_WOPEN;
97 		if (flag&FNDELAY)
98 			break;
99 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
100 	}
101 	error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
102 	ptcwakeup(tp, FREAD|FWRITE);
103 	return (error);
104 }
105 
106 ptsclose(dev)
107 	dev_t dev;
108 {
109 	register struct tty *tp;
110 
111 	tp = &pt_tty[minor(dev)];
112 	(*linesw[tp->t_line].l_close)(tp);
113 	ttyclose(tp);
114 	ptcwakeup(tp, FREAD|FWRITE);
115 }
116 
117 ptsread(dev, uio, flag)
118 	dev_t dev;
119 	struct uio *uio;
120 {
121 	register struct tty *tp = &pt_tty[minor(dev)];
122 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
123 	int error = 0;
124 
125 again:
126 	if (pti->pt_flags & PF_REMOTE) {
127 		while (tp == u.u_ttyp &&
128 		       u.u_procp->p_pgrp->pg_id != tp->t_pgid){
129 			if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
130 			    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
131 			    !u.u_procp->p_pgrp->pg_jobc ||
132 			    u.u_procp->p_flag&SVFORK)
133 				return (EIO);
134 			pgsignal(u.u_procp->p_pgrp, SIGTTIN);
135 			sleep((caddr_t)&lbolt, TTIPRI);
136 		}
137 		if (tp->t_canq.c_cc == 0) {
138 			if (flag & IO_NDELAY)
139 				return (EWOULDBLOCK);
140 			sleep((caddr_t)&tp->t_canq, TTIPRI);
141 			goto again;
142 		}
143 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
144 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
145 				error = EFAULT;
146 				break;
147 			}
148 		if (tp->t_canq.c_cc == 1)
149 			(void) getc(&tp->t_canq);
150 		if (tp->t_canq.c_cc)
151 			return (error);
152 	} else
153 		if (tp->t_oproc)
154 			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
155 	ptcwakeup(tp, FWRITE);
156 	return (error);
157 }
158 
159 /*
160  * Write to pseudo-tty.
161  * Wakeups of controlling tty will happen
162  * indirectly, when tty driver calls ptsstart.
163  */
164 ptswrite(dev, uio, flag)
165 	dev_t dev;
166 	struct uio *uio;
167 {
168 	register struct tty *tp;
169 
170 	tp = &pt_tty[minor(dev)];
171 	if (tp->t_oproc == 0)
172 		return (EIO);
173 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
174 }
175 
176 /*
177  * Start output on pseudo-tty.
178  * Wake up process selecting or sleeping for input from controlling tty.
179  */
180 ptsstart(tp)
181 	struct tty *tp;
182 {
183 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
184 
185 	if (tp->t_state & TS_TTSTOP)
186 		return;
187 	if (pti->pt_flags & PF_STOPPED) {
188 		pti->pt_flags &= ~PF_STOPPED;
189 		pti->pt_send = TIOCPKT_START;
190 	}
191 	ptcwakeup(tp, FREAD);
192 }
193 
194 ptcwakeup(tp, flag)
195 	struct tty *tp;
196 {
197 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
198 
199 	if (flag & FREAD) {
200 		if (pti->pt_selr) {
201 			selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
202 			pti->pt_selr = 0;
203 			pti->pt_flags &= ~PF_RCOLL;
204 		}
205 		wakeup((caddr_t)&tp->t_outq.c_cf);
206 	}
207 	if (flag & FWRITE) {
208 		if (pti->pt_selw) {
209 			selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
210 			pti->pt_selw = 0;
211 			pti->pt_flags &= ~PF_WCOLL;
212 		}
213 if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid);
214 		wakeup((caddr_t)&tp->t_rawq.c_cf);
215 	}
216 }
217 
218 /*ARGSUSED*/
219 ptcopen(dev, flag)
220 	dev_t dev;
221 	int flag;
222 {
223 	register struct tty *tp;
224 	struct pt_ioctl *pti;
225 
226 	if (minor(dev) >= NPTY)
227 		return (ENXIO);
228 	tp = &pt_tty[minor(dev)];
229 	if (tp->t_oproc)
230 		return (EIO);
231 	tp->t_oproc = ptsstart;
232 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
233 	pti = &pt_ioctl[minor(dev)];
234 	pti->pt_flags = 0;
235 	pti->pt_send = 0;
236 	pti->pt_ucntl = 0;
237 	return (0);
238 }
239 
240 ptcclose(dev)
241 	dev_t dev;
242 {
243 	register struct tty *tp;
244 
245 	tp = &pt_tty[minor(dev)];
246 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
247 	tp->t_state &= ~TS_CARR_ON;
248 	tp->t_oproc = 0;		/* mark closed */
249 }
250 
251 ptcread(dev, uio, flag)
252 	dev_t dev;
253 	struct uio *uio;
254 {
255 	register struct tty *tp = &pt_tty[minor(dev)];
256 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
257 	char buf[BUFSIZ];
258 	int error = 0, cc;
259 
260 	/*
261 	 * We want to block until the slave
262 	 * is open, and there's something to read;
263 	 * but if we lost the slave or we're NBIO,
264 	 * then return the appropriate error instead.
265 	 */
266 	for (;;) {
267 		if (tp->t_state&TS_ISOPEN) {
268 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
269 				error = ureadc((int)pti->pt_send, uio);
270 				if (error)
271 					return (error);
272 				pti->pt_send = 0;
273 				return (0);
274 			}
275 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
276 				error = ureadc((int)pti->pt_ucntl, uio);
277 				if (error)
278 					return (error);
279 				pti->pt_ucntl = 0;
280 				return (0);
281 			}
282 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
283 				break;
284 		}
285 		if ((tp->t_state&TS_CARR_ON) == 0)
286 			return (0);	/* EOF */
287 		if (flag & IO_NDELAY)
288 			return (EWOULDBLOCK);
289 if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid);
290 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
291 	}
292 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
293 		error = ureadc(0, uio);
294 	while (uio->uio_resid > 0 && error == 0) {
295 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
296 		if (cc <= 0)
297 			break;
298 		error = uiomove(buf, cc, uio);
299 	}
300 	if (tp->t_outq.c_cc <= tp->t_lowat) {
301 		if (tp->t_state&TS_ASLEEP) {
302 			tp->t_state &= ~TS_ASLEEP;
303 			wakeup((caddr_t)&tp->t_outq);
304 		}
305 		if (tp->t_wsel) {
306 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
307 			tp->t_wsel = 0;
308 			tp->t_state &= ~TS_WCOLL;
309 		}
310 	}
311 	return (error);
312 }
313 
314 ptsstop(tp, flush)
315 	register struct tty *tp;
316 	int flush;
317 {
318 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
319 	int flag;
320 
321 	/* note: FLUSHREAD and FLUSHWRITE already ok */
322 	if (flush == 0) {
323 		flush = TIOCPKT_STOP;
324 		pti->pt_flags |= PF_STOPPED;
325 	} else
326 		pti->pt_flags &= ~PF_STOPPED;
327 	pti->pt_send |= flush;
328 	/* change of perspective */
329 	flag = 0;
330 	if (flush & FREAD)
331 		flag |= FWRITE;
332 	if (flush & FWRITE)
333 		flag |= FREAD;
334 	ptcwakeup(tp, flag);
335 }
336 
337 ptcselect(dev, rw)
338 	dev_t dev;
339 	int rw;
340 {
341 	register struct tty *tp = &pt_tty[minor(dev)];
342 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
343 	struct proc *p;
344 	int s;
345 
346 	if ((tp->t_state&TS_CARR_ON) == 0)
347 		return (1);
348 	switch (rw) {
349 
350 	case FREAD:
351 		/*
352 		 * Need to block timeouts (ttrstart).
353 		 */
354 		s = spltty();
355 		if ((tp->t_state&TS_ISOPEN) &&
356 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
357 			splx(s);
358 			return (1);
359 		}
360 		splx(s);
361 		/* FALLTHROUGH */
362 
363 	case 0:					/* exceptional */
364 		if ((tp->t_state&TS_ISOPEN) &&
365 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
366 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
367 			return (1);
368 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
369 			pti->pt_flags |= PF_RCOLL;
370 		else
371 			pti->pt_selr = u.u_procp;
372 		break;
373 
374 
375 	case FWRITE:
376 		if (tp->t_state&TS_ISOPEN) {
377 			if (pti->pt_flags & PF_REMOTE) {
378 			    if (tp->t_canq.c_cc == 0)
379 				return (1);
380 			} else {
381 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
382 				    return (1);
383 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
384 				    return (1);
385 			}
386 		}
387 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
388 			pti->pt_flags |= PF_WCOLL;
389 		else
390 			pti->pt_selw = u.u_procp;
391 		break;
392 
393 	}
394 	return (0);
395 }
396 
397 ptcwrite(dev, uio, flag)
398 	dev_t dev;
399 	register struct uio *uio;
400 {
401 	register struct tty *tp = &pt_tty[minor(dev)];
402 	register struct iovec *iov;
403 	register char *cp;
404 	register int cc = 0;
405 	char locbuf[BUFSIZ];
406 	int cnt = 0;
407 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
408 	int error = 0;
409 
410 again:
411 	if ((tp->t_state&TS_ISOPEN) == 0)
412 		goto block;
413 	if (pti->pt_flags & PF_REMOTE) {
414 		if (tp->t_canq.c_cc)
415 			goto block;
416 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
417 			iov = uio->uio_iov;
418 			if (iov->iov_len == 0) {
419 				uio->uio_iovcnt--;
420 				uio->uio_iov++;
421 				continue;
422 			}
423 			if (cc == 0) {
424 				cc = MIN(iov->iov_len, BUFSIZ);
425 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
426 				cp = locbuf;
427 				error = uiomove(cp, cc, uio);
428 				if (error)
429 					return (error);
430 				/* check again for safety */
431 				if ((tp->t_state&TS_ISOPEN) == 0)
432 					return (EIO);
433 			}
434 			if (cc)
435 				(void) b_to_q(cp, cc, &tp->t_canq);
436 			cc = 0;
437 		}
438 		(void) putc(0, &tp->t_canq);
439 		ttwakeup(tp);
440 		wakeup((caddr_t)&tp->t_canq);
441 		return (0);
442 	}
443 	while (uio->uio_iovcnt > 0) {
444 		iov = uio->uio_iov;
445 		if (cc == 0) {
446 			if (iov->iov_len == 0) {
447 				uio->uio_iovcnt--;
448 				uio->uio_iov++;
449 				continue;
450 			}
451 			cc = MIN(iov->iov_len, BUFSIZ);
452 			cp = locbuf;
453 			error = uiomove(cp, cc, uio);
454 			if (error)
455 				return (error);
456 			/* check again for safety */
457 			if ((tp->t_state&TS_ISOPEN) == 0)
458 				return (EIO);
459 		}
460 		while (cc > 0) {
461 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
462 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
463 				wakeup((caddr_t)&tp->t_rawq);
464 				goto block;
465 			}
466 			(*linesw[tp->t_line].l_rint)(*cp++&0377, tp);
467 			cnt++;
468 			cc--;
469 		}
470 		cc = 0;
471 	}
472 	return (0);
473 block:
474 	/*
475 	 * Come here to wait for slave to open, for space
476 	 * in outq, or space in rawq.
477 	 */
478 	if ((tp->t_state&TS_CARR_ON) == 0)
479 		return (EIO);
480 	if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) {
481 		iov->iov_base -= cc;
482 		iov->iov_len += cc;
483 		uio->uio_resid += cc;
484 		uio->uio_offset -= cc;
485 		if (cnt == 0)
486 			return (EWOULDBLOCK);
487 		return (0);
488 	}
489 if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid);
490 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
491 	goto again;
492 }
493 
494 /*ARGSUSED*/
495 ptyioctl(dev, cmd, data, flag)
496 	caddr_t data;
497 	dev_t dev;
498 {
499 	register struct tty *tp = &pt_tty[minor(dev)];
500 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
501 	register u_char *cc = tp->t_cc;
502 	int stop, error;
503 	extern ttyinput();
504 
505 	/*
506 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
507 	 * ttywflush(tp) will hang if there are characters in the outq.
508 	 */
509 	if (cdevsw[major(dev)].d_open == ptcopen)
510 		switch (cmd) {
511 
512 		case TIOCPKT:
513 			if (*(int *)data) {
514 				if (pti->pt_flags & PF_UCNTL)
515 					return (EINVAL);
516 				pti->pt_flags |= PF_PKT;
517 			} else
518 				pti->pt_flags &= ~PF_PKT;
519 			return (0);
520 
521 		case TIOCUCNTL:
522 			if (*(int *)data) {
523 				if (pti->pt_flags & PF_PKT)
524 					return (EINVAL);
525 				pti->pt_flags |= PF_UCNTL;
526 			} else
527 				pti->pt_flags &= ~PF_UCNTL;
528 			return (0);
529 
530 		case TIOCREMOTE:
531 			if (*(int *)data)
532 				pti->pt_flags |= PF_REMOTE;
533 			else
534 				pti->pt_flags &= ~PF_REMOTE;
535 			ttyflush(tp, FREAD|FWRITE);
536 			return (0);
537 
538 		case FIONBIO:
539 			if (*(int *)data)
540 				pti->pt_flags |= PF_NBIO;
541 			else
542 				pti->pt_flags &= ~PF_NBIO;
543 			return (0);
544 
545 		case TIOCSETP:
546 		case TIOCSETN:
547 		case TIOCSETD:
548 		case TIOCSETA:
549 		case TIOCSETAW:
550 		case TIOCSETAF:
551 		case TIOCSETAS:
552 		case TIOCSETAWS:
553 		case TIOCSETAFS:
554 			while (getc(&tp->t_outq) >= 0)
555 				;
556 			break;
557 		}
558 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
559 	if (error < 0)
560 		 error = ttioctl(tp, cmd, data, flag);
561 	/*
562 	 * Since we use the tty queues internally,
563 	 * pty's can't be switched to disciplines which overwrite
564 	 * the queues.  We can't tell anything about the discipline
565 	 * from here...
566 	 */
567 	if (linesw[tp->t_line].l_rint != ttyinput) {
568 		(*linesw[tp->t_line].l_close)(tp);
569 		tp->t_line = 0;
570 		(void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
571 		error = ENOTTY;
572 	}
573 	if (error < 0) {
574 		if (pti->pt_flags & PF_UCNTL &&
575 		    (cmd & ~0xff) == UIOCCMD(0)) {
576 			if (cmd & 0xff) {
577 				pti->pt_ucntl = (u_char)cmd;
578 				ptcwakeup(tp, FREAD);
579 			}
580 			return (0);
581 		}
582 		error = ENOTTY;
583 	}
584 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
585 		&& CCEQ(cc[VSTART], CTRL('q'));
586 	if (pti->pt_flags & PF_NOSTOP) {
587 		if (stop) {
588 			pti->pt_send &= ~TIOCPKT_NOSTOP;
589 			pti->pt_send |= TIOCPKT_DOSTOP;
590 			pti->pt_flags &= ~PF_NOSTOP;
591 			ptcwakeup(tp, FREAD);
592 		}
593 	} else {
594 		if (!stop) {
595 			pti->pt_send &= ~TIOCPKT_DOSTOP;
596 			pti->pt_send |= TIOCPKT_NOSTOP;
597 			pti->pt_flags |= PF_NOSTOP;
598 			ptcwakeup(tp, FREAD);
599 		}
600 	}
601 	return (error);
602 }
603 #endif
604