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