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