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