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