xref: /csrg-svn/sys/kern/tty_pty.c (revision 39497)
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.8 (Berkeley) 11/09/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 	tp->t_session = 0;
250 }
251 
252 ptcread(dev, uio, flag)
253 	dev_t dev;
254 	struct uio *uio;
255 {
256 	register struct tty *tp = &pt_tty[minor(dev)];
257 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
258 	char buf[BUFSIZ];
259 	int error = 0, cc;
260 
261 	/*
262 	 * We want to block until the slave
263 	 * is open, and there's something to read;
264 	 * but if we lost the slave or we're NBIO,
265 	 * then return the appropriate error instead.
266 	 */
267 	for (;;) {
268 		if (tp->t_state&TS_ISOPEN) {
269 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
270 				error = ureadc((int)pti->pt_send, uio);
271 				if (error)
272 					return (error);
273 				pti->pt_send = 0;
274 				return (0);
275 			}
276 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
277 				error = ureadc((int)pti->pt_ucntl, uio);
278 				if (error)
279 					return (error);
280 				pti->pt_ucntl = 0;
281 				return (0);
282 			}
283 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
284 				break;
285 		}
286 		if ((tp->t_state&TS_CARR_ON) == 0)
287 			return (0);	/* EOF */
288 		if (flag & IO_NDELAY)
289 			return (EWOULDBLOCK);
290 if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid);
291 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
292 	}
293 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
294 		error = ureadc(0, uio);
295 	while (uio->uio_resid > 0 && error == 0) {
296 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
297 		if (cc <= 0)
298 			break;
299 		error = uiomove(buf, cc, uio);
300 	}
301 	if (tp->t_outq.c_cc <= tp->t_lowat) {
302 		if (tp->t_state&TS_ASLEEP) {
303 			tp->t_state &= ~TS_ASLEEP;
304 			wakeup((caddr_t)&tp->t_outq);
305 		}
306 		if (tp->t_wsel) {
307 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
308 			tp->t_wsel = 0;
309 			tp->t_state &= ~TS_WCOLL;
310 		}
311 	}
312 	return (error);
313 }
314 
315 ptsstop(tp, flush)
316 	register struct tty *tp;
317 	int flush;
318 {
319 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
320 	int flag;
321 
322 	/* note: FLUSHREAD and FLUSHWRITE already ok */
323 	if (flush == 0) {
324 		flush = TIOCPKT_STOP;
325 		pti->pt_flags |= PF_STOPPED;
326 	} else
327 		pti->pt_flags &= ~PF_STOPPED;
328 	pti->pt_send |= flush;
329 	/* change of perspective */
330 	flag = 0;
331 	if (flush & FREAD)
332 		flag |= FWRITE;
333 	if (flush & FWRITE)
334 		flag |= FREAD;
335 	ptcwakeup(tp, flag);
336 }
337 
338 ptcselect(dev, rw)
339 	dev_t dev;
340 	int rw;
341 {
342 	register struct tty *tp = &pt_tty[minor(dev)];
343 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
344 	struct proc *p;
345 	int s;
346 
347 	if ((tp->t_state&TS_CARR_ON) == 0)
348 		return (1);
349 	switch (rw) {
350 
351 	case FREAD:
352 		/*
353 		 * Need to block timeouts (ttrstart).
354 		 */
355 		s = spltty();
356 		if ((tp->t_state&TS_ISOPEN) &&
357 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
358 			splx(s);
359 			return (1);
360 		}
361 		splx(s);
362 		/* FALLTHROUGH */
363 
364 	case 0:					/* exceptional */
365 		if ((tp->t_state&TS_ISOPEN) &&
366 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
367 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
368 			return (1);
369 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
370 			pti->pt_flags |= PF_RCOLL;
371 		else
372 			pti->pt_selr = u.u_procp;
373 		break;
374 
375 
376 	case FWRITE:
377 		if (tp->t_state&TS_ISOPEN) {
378 			if (pti->pt_flags & PF_REMOTE) {
379 			    if (tp->t_canq.c_cc == 0)
380 				return (1);
381 			} else {
382 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
383 				    return (1);
384 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
385 				    return (1);
386 			}
387 		}
388 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
389 			pti->pt_flags |= PF_WCOLL;
390 		else
391 			pti->pt_selw = u.u_procp;
392 		break;
393 
394 	}
395 	return (0);
396 }
397 
398 ptcwrite(dev, uio, flag)
399 	dev_t dev;
400 	register struct uio *uio;
401 {
402 	register struct tty *tp = &pt_tty[minor(dev)];
403 	register struct iovec *iov;
404 	register char *cp;
405 	register int cc = 0;
406 	char locbuf[BUFSIZ];
407 	int cnt = 0;
408 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
409 	int error = 0;
410 
411 again:
412 	if ((tp->t_state&TS_ISOPEN) == 0)
413 		goto block;
414 	if (pti->pt_flags & PF_REMOTE) {
415 		if (tp->t_canq.c_cc)
416 			goto block;
417 		while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
418 			iov = uio->uio_iov;
419 			if (iov->iov_len == 0) {
420 				uio->uio_iovcnt--;
421 				uio->uio_iov++;
422 				continue;
423 			}
424 			if (cc == 0) {
425 				cc = MIN(iov->iov_len, BUFSIZ);
426 				cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
427 				cp = locbuf;
428 				error = uiomove(cp, cc, uio);
429 				if (error)
430 					return (error);
431 				/* check again for safety */
432 				if ((tp->t_state&TS_ISOPEN) == 0)
433 					return (EIO);
434 			}
435 			if (cc)
436 				(void) b_to_q(cp, cc, &tp->t_canq);
437 			cc = 0;
438 		}
439 		(void) putc(0, &tp->t_canq);
440 		ttwakeup(tp);
441 		wakeup((caddr_t)&tp->t_canq);
442 		return (0);
443 	}
444 	while (uio->uio_iovcnt > 0) {
445 		iov = uio->uio_iov;
446 		if (cc == 0) {
447 			if (iov->iov_len == 0) {
448 				uio->uio_iovcnt--;
449 				uio->uio_iov++;
450 				continue;
451 			}
452 			cc = MIN(iov->iov_len, BUFSIZ);
453 			cp = locbuf;
454 			error = uiomove(cp, cc, uio);
455 			if (error)
456 				return (error);
457 			/* check again for safety */
458 			if ((tp->t_state&TS_ISOPEN) == 0)
459 				return (EIO);
460 		}
461 		while (cc > 0) {
462 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
463 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
464 				wakeup((caddr_t)&tp->t_rawq);
465 				goto block;
466 			}
467 			(*linesw[tp->t_line].l_rint)(*cp++&0377, tp);
468 			cnt++;
469 			cc--;
470 		}
471 		cc = 0;
472 	}
473 	return (0);
474 block:
475 	/*
476 	 * Come here to wait for slave to open, for space
477 	 * in outq, or space in rawq.
478 	 */
479 	if ((tp->t_state&TS_CARR_ON) == 0)
480 		return (EIO);
481 	if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) {
482 		iov->iov_base -= cc;
483 		iov->iov_len += cc;
484 		uio->uio_resid += cc;
485 		uio->uio_offset -= cc;
486 		if (cnt == 0)
487 			return (EWOULDBLOCK);
488 		return (0);
489 	}
490 if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid);
491 	sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
492 	goto again;
493 }
494 
495 /*ARGSUSED*/
496 ptyioctl(dev, cmd, data, flag)
497 	caddr_t data;
498 	dev_t dev;
499 {
500 	register struct tty *tp = &pt_tty[minor(dev)];
501 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
502 	register u_char *cc = tp->t_cc;
503 	int stop, error;
504 	extern ttyinput();
505 
506 	/*
507 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
508 	 * ttywflush(tp) will hang if there are characters in the outq.
509 	 */
510 	if (cdevsw[major(dev)].d_open == ptcopen)
511 		switch (cmd) {
512 
513 		case TIOCPKT:
514 			if (*(int *)data) {
515 				if (pti->pt_flags & PF_UCNTL)
516 					return (EINVAL);
517 				pti->pt_flags |= PF_PKT;
518 			} else
519 				pti->pt_flags &= ~PF_PKT;
520 			return (0);
521 
522 		case TIOCUCNTL:
523 			if (*(int *)data) {
524 				if (pti->pt_flags & PF_PKT)
525 					return (EINVAL);
526 				pti->pt_flags |= PF_UCNTL;
527 			} else
528 				pti->pt_flags &= ~PF_UCNTL;
529 			return (0);
530 
531 		case TIOCREMOTE:
532 			if (*(int *)data)
533 				pti->pt_flags |= PF_REMOTE;
534 			else
535 				pti->pt_flags &= ~PF_REMOTE;
536 			ttyflush(tp, FREAD|FWRITE);
537 			return (0);
538 
539 		case FIONBIO:
540 			if (*(int *)data)
541 				pti->pt_flags |= PF_NBIO;
542 			else
543 				pti->pt_flags &= ~PF_NBIO;
544 			return (0);
545 
546 		case TIOCSETP:
547 		case TIOCSETN:
548 		case TIOCSETD:
549 		case TIOCSETA:
550 		case TIOCSETAW:
551 		case TIOCSETAF:
552 		case JUNK_TIOCSETAS:
553 		case JUNK_TIOCSETAWS:
554 		case JUNK_TIOCSETAFS:
555 			while (getc(&tp->t_outq) >= 0)
556 				;
557 			break;
558 		}
559 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
560 	if (error < 0)
561 		 error = ttioctl(tp, cmd, data, flag);
562 	/*
563 	 * Since we use the tty queues internally,
564 	 * pty's can't be switched to disciplines which overwrite
565 	 * the queues.  We can't tell anything about the discipline
566 	 * from here...
567 	 */
568 	if (linesw[tp->t_line].l_rint != ttyinput) {
569 		(*linesw[tp->t_line].l_close)(tp);
570 		tp->t_line = 0;
571 		(void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
572 		error = ENOTTY;
573 	}
574 	if (error < 0) {
575 		if (pti->pt_flags & PF_UCNTL &&
576 		    (cmd & ~0xff) == UIOCCMD(0)) {
577 			if (cmd & 0xff) {
578 				pti->pt_ucntl = (u_char)cmd;
579 				ptcwakeup(tp, FREAD);
580 			}
581 			return (0);
582 		}
583 		error = ENOTTY;
584 	}
585 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
586 		&& CCEQ(cc[VSTART], CTRL('q'));
587 	if (pti->pt_flags & PF_NOSTOP) {
588 		if (stop) {
589 			pti->pt_send &= ~TIOCPKT_NOSTOP;
590 			pti->pt_send |= TIOCPKT_DOSTOP;
591 			pti->pt_flags &= ~PF_NOSTOP;
592 			ptcwakeup(tp, FREAD);
593 		}
594 	} else {
595 		if (!stop) {
596 			pti->pt_send &= ~TIOCPKT_DOSTOP;
597 			pti->pt_send |= TIOCPKT_NOSTOP;
598 			pti->pt_flags |= PF_NOSTOP;
599 			ptcwakeup(tp, FREAD);
600 		}
601 	}
602 	return (error);
603 }
604 #endif
605