xref: /netbsd-src/sys/kern/tty_pty.c (revision d20841bb642898112fe68f0ad3f7b26dddf56f07)
1 /*	$NetBSD: tty_pty.c,v 1.72 2003/08/07 16:31:56 agc Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
32  */
33 
34 /*
35  * Pseudo-teletype Driver
36  * (Actually two drivers, requiring two entries in 'cdevsw')
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: tty_pty.c,v 1.72 2003/08/07 16:31:56 agc Exp $");
41 
42 #include "opt_compat_sunos.h"
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/ioctl.h>
47 #include <sys/proc.h>
48 #include <sys/tty.h>
49 #include <sys/file.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52 #include <sys/vnode.h>
53 #include <sys/signalvar.h>
54 #include <sys/uio.h>
55 #include <sys/conf.h>
56 #include <sys/poll.h>
57 #include <sys/malloc.h>
58 
59 #define	DEFAULT_NPTYS		16	/* default number of initial ptys */
60 #define DEFAULT_MAXPTYS		992	/* default maximum number of ptys */
61 
62 /* Macros to clear/set/test flags. */
63 #define	SET(t, f)	(t) |= (f)
64 #define	CLR(t, f)	(t) &= ~((unsigned)(f))
65 #define	ISSET(t, f)	((t) & (f))
66 
67 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
68 
69 /*
70  * pts == /dev/tty[pqrs]?
71  * ptc == /dev/pty[pqrs]?
72  */
73 struct	pt_softc {
74 	struct	tty *pt_tty;
75 	int	pt_flags;
76 	struct	selinfo pt_selr, pt_selw;
77 	u_char	pt_send;
78 	u_char	pt_ucntl;
79 };
80 
81 static struct pt_softc **pt_softc = NULL;	/* pty array */
82 static int npty = 0;			/* for pstat -t */
83 static int maxptys = DEFAULT_MAXPTYS;	/* maximum number of ptys (sysctable) */
84 static struct simplelock pt_softc_mutex = SIMPLELOCK_INITIALIZER;
85 
86 #define	PF_PKT		0x08		/* packet mode */
87 #define	PF_STOPPED	0x10		/* user told stopped */
88 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
89 #define	PF_NOSTOP	0x40
90 #define PF_UCNTL	0x80		/* user control mode */
91 
92 void	ptyattach __P((int));
93 void	ptcwakeup __P((struct tty *, int));
94 void	ptsstart __P((struct tty *));
95 int	pty_maxptys __P((int, int));
96 
97 static struct pt_softc **ptyarralloc __P((int));
98 static int check_pty(int);
99 
100 dev_type_open(ptcopen);
101 dev_type_close(ptcclose);
102 dev_type_read(ptcread);
103 dev_type_write(ptcwrite);
104 dev_type_poll(ptcpoll);
105 dev_type_kqfilter(ptckqfilter);
106 
107 dev_type_open(ptsopen);
108 dev_type_close(ptsclose);
109 dev_type_read(ptsread);
110 dev_type_write(ptswrite);
111 dev_type_stop(ptsstop);
112 dev_type_poll(ptspoll);
113 
114 dev_type_ioctl(ptyioctl);
115 dev_type_tty(ptytty);
116 
117 const struct cdevsw ptc_cdevsw = {
118 	ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
119 	nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
120 };
121 
122 const struct cdevsw pts_cdevsw = {
123 	ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
124 	ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
125 };
126 
127 #if defined(pmax)
128 const struct cdevsw ptc_ultrix_cdevsw = {
129 	ptcopen, ptcclose, ptcread, ptcwrite, ptyioctl,
130 	nullstop, ptytty, ptcpoll, nommap, ptckqfilter, D_TTY
131 };
132 
133 const struct cdevsw pts_ultrix_cdevsw = {
134 	ptsopen, ptsclose, ptsread, ptswrite, ptyioctl,
135 	ptsstop, ptytty, ptspoll, nommap, ttykqfilter, D_TTY
136 };
137 #endif /* defined(pmax) */
138 
139 /*
140  * Allocate and zero array of nelem elements.
141  */
142 static struct pt_softc **
143 ptyarralloc(nelem)
144 	int nelem;
145 {
146 	struct pt_softc **pt;
147 	nelem += 10;
148 	pt = malloc(nelem * sizeof *pt, M_DEVBUF, M_WAITOK | M_ZERO);
149 	return pt;
150 }
151 
152 /*
153  * Check if the minor is correct and ensure necessary structures
154  * are properly allocated.
155  */
156 static int
157 check_pty(int ptn)
158 {
159 	struct pt_softc *pti;
160 
161 	if (ptn >= npty) {
162 		struct pt_softc **newpt, **oldpt;
163 		int newnpty;
164 
165 		/* check if the requested pty can be granted */
166 		if (ptn >= maxptys) {
167 	    limit_reached:
168 			tablefull("pty", "increase kern.maxptys");
169 			return (ENXIO);
170 		}
171 
172 		/* Allocate a larger pty array */
173 		for (newnpty = npty; newnpty <= ptn;)
174 			newnpty *= 2;
175 		if (newnpty > maxptys)
176 			newnpty = maxptys;
177 		newpt = ptyarralloc(newnpty);
178 
179 		/*
180 		 * Now grab the pty array mutex - we need to ensure
181 		 * that the pty array is consistent while copying it's
182 		 * content to newly allocated, larger space; we also
183 		 * need to be safe against pty_maxptys().
184 		 */
185 		simple_lock(&pt_softc_mutex);
186 
187 		if (newnpty >= maxptys) {
188 			/* limit cut away beneath us... */
189 			newnpty = maxptys;
190 			if (ptn >= newnpty) {
191 				simple_unlock(&pt_softc_mutex);
192 				free(newpt, M_DEVBUF);
193 				goto limit_reached;
194 			}
195 		}
196 
197 		/*
198 		 * If the pty array was not enlarged while we were waiting
199 		 * for mutex, copy current contents of pt_softc[] to newly
200 		 * allocated array and start using the new bigger array.
201 		 */
202 		if (newnpty > npty) {
203 			memcpy(newpt, pt_softc, npty*sizeof(struct pt_softc *));
204 			oldpt = pt_softc;
205 			pt_softc = newpt;
206 			npty = newnpty;
207 		} else {
208 			/* was enlarged when waited for lock, free new space */
209 			oldpt = newpt;
210 		}
211 
212 		simple_unlock(&pt_softc_mutex);
213 		free(oldpt, M_DEVBUF);
214 	}
215 
216 	/*
217 	 * If the entry is not yet allocated, allocate one. The mutex is
218 	 * needed so that the state of pt_softc[] array is consistant
219 	 * in case it has been lengthened above.
220 	 */
221 	if (!pt_softc[ptn]) {
222 		MALLOC(pti, struct pt_softc *, sizeof(struct pt_softc),
223 			M_DEVBUF, M_WAITOK);
224 		memset(pti, 0, sizeof(struct pt_softc));
225 
226 	 	pti->pt_tty = ttymalloc();
227 
228 		simple_lock(&pt_softc_mutex);
229 
230 		/*
231 		 * Check the entry again - it might have been
232 		 * added while we were waiting for mutex.
233 		 */
234 		if (!pt_softc[ptn]) {
235 			tty_attach(pti->pt_tty);
236 			pt_softc[ptn] = pti;
237 		} else {
238 			ttyfree(pti->pt_tty);
239 			free(pti, M_DEVBUF);
240 		}
241 
242 		simple_unlock(&pt_softc_mutex);
243 	}
244 
245 	return (0);
246 }
247 
248 /*
249  * Set maxpty in thread-safe way. Returns 0 in case of error, otherwise
250  * new value of maxptys.
251  */
252 int
253 pty_maxptys(newmax, set)
254 	int newmax, set;
255 {
256 	if (!set)
257 		return (maxptys);
258 
259 	/*
260 	 * We have to grab the pt_softc lock, so that we would pick correct
261 	 * value of npty (might be modified in check_pty()).
262 	 */
263 	simple_lock(&pt_softc_mutex);
264 
265 	/*
266 	 * The value cannot be set to value lower than the highest pty
267 	 * number ever allocated.
268 	 */
269 	if (newmax >= npty)
270 		maxptys = newmax;
271 	else
272 		newmax = 0;
273 
274 	simple_unlock(&pt_softc_mutex);
275 
276 	return newmax;
277 }
278 
279 /*
280  * Establish n (or default if n is 1) ptys in the system.
281  */
282 void
283 ptyattach(n)
284 	int n;
285 {
286 	/* maybe should allow 0 => none? */
287 	if (n <= 1)
288 		n = DEFAULT_NPTYS;
289 	pt_softc = ptyarralloc(n);
290 	npty = n;
291 }
292 
293 /*ARGSUSED*/
294 int
295 ptsopen(dev, flag, devtype, p)
296 	dev_t dev;
297 	int flag, devtype;
298 	struct proc *p;
299 {
300 	struct pt_softc *pti;
301 	struct tty *tp;
302 	int error;
303 	int ptn = minor(dev);
304 
305 	if ((error = check_pty(ptn)))
306 		return (error);
307 
308 	pti = pt_softc[ptn];
309 	tp = pti->pt_tty;
310 
311 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
312 		ttychars(tp);		/* Set up default chars */
313 		tp->t_iflag = TTYDEF_IFLAG;
314 		tp->t_oflag = TTYDEF_OFLAG;
315 		tp->t_lflag = TTYDEF_LFLAG;
316 		tp->t_cflag = TTYDEF_CFLAG;
317 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
318 		ttsetwater(tp);		/* would be done in xxparam() */
319 	} else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
320 		return (EBUSY);
321 	if (tp->t_oproc)			/* Ctrlr still around. */
322 		SET(tp->t_state, TS_CARR_ON);
323 
324 	if (!ISSET(flag, O_NONBLOCK)) {
325 		TTY_LOCK(tp);
326 		while (!ISSET(tp->t_state, TS_CARR_ON)) {
327 			tp->t_wopen++;
328 			error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
329 			    ttopen, 0);
330 			tp->t_wopen--;
331 			if (error) {
332 				TTY_UNLOCK(tp);
333 				return (error);
334 			}
335 		}
336 		TTY_UNLOCK(tp);
337 	}
338 	error = (*tp->t_linesw->l_open)(dev, tp);
339 	ptcwakeup(tp, FREAD|FWRITE);
340 	return (error);
341 }
342 
343 int
344 ptsclose(dev, flag, mode, p)
345 	dev_t dev;
346 	int flag, mode;
347 	struct proc *p;
348 {
349 	struct pt_softc *pti = pt_softc[minor(dev)];
350 	struct tty *tp = pti->pt_tty;
351 	int error;
352 
353 	error = (*tp->t_linesw->l_close)(tp, flag);
354 	error |= ttyclose(tp);
355 	ptcwakeup(tp, FREAD|FWRITE);
356 	return (error);
357 }
358 
359 int
360 ptsread(dev, uio, flag)
361 	dev_t dev;
362 	struct uio *uio;
363 	int flag;
364 {
365 	struct proc *p = curproc;
366 	struct pt_softc *pti = pt_softc[minor(dev)];
367 	struct tty *tp = pti->pt_tty;
368 	int error = 0;
369 	int cc;
370 
371 again:
372 	if (pti->pt_flags & PF_REMOTE) {
373 		while (isbackground(p, tp)) {
374 			if (sigismasked(p, SIGTTIN) ||
375 			    p->p_pgrp->pg_jobc == 0 ||
376 			    p->p_flag & P_PPWAIT)
377 				return (EIO);
378 			pgsignal(p->p_pgrp, SIGTTIN, 1);
379 			TTY_LOCK(tp);
380 			error = ttysleep(tp, (caddr_t)&lbolt,
381 					 TTIPRI | PCATCH | PNORELOCK, ttybg, 0);
382 			if (error)
383 				return (error);
384 		}
385 		TTY_LOCK(tp);
386 		if (tp->t_canq.c_cc == 0) {
387 			if (flag & IO_NDELAY) {
388 				TTY_UNLOCK(tp);
389 				return (EWOULDBLOCK);
390 			}
391 			error = ttysleep(tp, (caddr_t)&tp->t_canq,
392 					 TTIPRI | PCATCH | PNORELOCK, ttyin, 0);
393 			if (error)
394 				return (error);
395 			goto again;
396 		}
397 		while(error == 0 && tp->t_canq.c_cc > 1 && uio->uio_resid > 0) {
398 			TTY_UNLOCK(tp);
399 			error = ureadc(getc(&tp->t_canq), uio);
400 			TTY_LOCK(tp);
401 			/* Re-check terminal state here? */
402 		}
403 		if (tp->t_canq.c_cc == 1)
404 			(void) getc(&tp->t_canq);
405 		cc = tp->t_canq.c_cc;
406 		TTY_UNLOCK(tp);
407 		if (cc)
408 			return (error);
409 	} else
410 		if (tp->t_oproc)
411 			error = (*tp->t_linesw->l_read)(tp, uio, flag);
412 	ptcwakeup(tp, FWRITE);
413 	return (error);
414 }
415 
416 /*
417  * Write to pseudo-tty.
418  * Wakeups of controlling tty will happen
419  * indirectly, when tty driver calls ptsstart.
420  */
421 int
422 ptswrite(dev, uio, flag)
423 	dev_t dev;
424 	struct uio *uio;
425 	int flag;
426 {
427 	struct pt_softc *pti = pt_softc[minor(dev)];
428 	struct tty *tp = pti->pt_tty;
429 
430 	if (tp->t_oproc == 0)
431 		return (EIO);
432 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
433 }
434 
435 /*
436  * Poll pseudo-tty.
437  */
438 int
439 ptspoll(dev, events, p)
440 	dev_t dev;
441 	int events;
442 	struct proc *p;
443 {
444 	struct pt_softc *pti = pt_softc[minor(dev)];
445 	struct tty *tp = pti->pt_tty;
446 
447 	if (tp->t_oproc == 0)
448 		return (EIO);
449 
450 	return ((*tp->t_linesw->l_poll)(tp, events, p));
451 }
452 
453 /*
454  * Start output on pseudo-tty.
455  * Wake up process polling or sleeping for input from controlling tty.
456  * Called with tty slock held.
457  */
458 void
459 ptsstart(tp)
460 	struct tty *tp;
461 {
462 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
463 
464 	if (ISSET(tp->t_state, TS_TTSTOP))
465 		return;
466 	if (pti->pt_flags & PF_STOPPED) {
467 		pti->pt_flags &= ~PF_STOPPED;
468 		pti->pt_send = TIOCPKT_START;
469 	}
470 
471 	selnotify(&pti->pt_selr, 0);
472 	wakeup((caddr_t)&tp->t_outq.c_cf);
473 }
474 
475 /*
476  * Stop output.
477  * Called with tty slock held.
478  */
479 void
480 ptsstop(tp, flush)
481 	struct tty *tp;
482 	int flush;
483 {
484 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
485 
486 	/* note: FLUSHREAD and FLUSHWRITE already ok */
487 	if (flush == 0) {
488 		flush = TIOCPKT_STOP;
489 		pti->pt_flags |= PF_STOPPED;
490 	} else
491 		pti->pt_flags &= ~PF_STOPPED;
492 	pti->pt_send |= flush;
493 
494 	/* change of perspective */
495 	if (flush & FREAD) {
496 		selnotify(&pti->pt_selw, 0);
497 		wakeup((caddr_t)&tp->t_rawq.c_cf);
498 	}
499 	if (flush & FWRITE) {
500 		selnotify(&pti->pt_selr, 0);
501 		wakeup((caddr_t)&tp->t_outq.c_cf);
502 	}
503 }
504 
505 void
506 ptcwakeup(tp, flag)
507 	struct tty *tp;
508 	int flag;
509 {
510 	struct pt_softc *pti = pt_softc[minor(tp->t_dev)];
511 
512 	TTY_LOCK(tp);
513 	if (flag & FREAD) {
514 		selnotify(&pti->pt_selr, 0);
515 		wakeup((caddr_t)&tp->t_outq.c_cf);
516 	}
517 	if (flag & FWRITE) {
518 		selnotify(&pti->pt_selw, 0);
519 		wakeup((caddr_t)&tp->t_rawq.c_cf);
520 	}
521 	TTY_UNLOCK(tp);
522 }
523 
524 /*ARGSUSED*/
525 int
526 ptcopen(dev, flag, devtype, p)
527 	dev_t dev;
528 	int flag, devtype;
529 	struct proc *p;
530 {
531 	struct pt_softc *pti;
532 	struct tty *tp;
533 	int error;
534 	int ptn = minor(dev);
535 
536 	if ((error = check_pty(ptn)))
537 		return (error);
538 
539 	pti = pt_softc[ptn];
540 	tp = pti->pt_tty;
541 
542 	TTY_LOCK(tp);
543 	if (tp->t_oproc) {
544 		TTY_UNLOCK(tp);
545 		return (EIO);
546 	}
547 	tp->t_oproc = ptsstart;
548 	TTY_UNLOCK(tp);
549 	(void)(*tp->t_linesw->l_modem)(tp, 1);
550 	CLR(tp->t_lflag, EXTPROC);
551 	pti->pt_flags = 0;
552 	pti->pt_send = 0;
553 	pti->pt_ucntl = 0;
554 	return (0);
555 }
556 
557 /*ARGSUSED*/
558 int
559 ptcclose(dev, flag, devtype, p)
560 	dev_t dev;
561 	int flag, devtype;
562 	struct proc *p;
563 {
564 	struct pt_softc *pti = pt_softc[minor(dev)];
565 	struct tty *tp = pti->pt_tty;
566 
567 	(void)(*tp->t_linesw->l_modem)(tp, 0);
568 	CLR(tp->t_state, TS_CARR_ON);
569 	TTY_LOCK(tp);
570 	tp->t_oproc = 0;		/* mark closed */
571 	TTY_UNLOCK(tp);
572 	return (0);
573 }
574 
575 int
576 ptcread(dev, uio, flag)
577 	dev_t dev;
578 	struct uio *uio;
579 	int flag;
580 {
581 	struct pt_softc *pti = pt_softc[minor(dev)];
582 	struct tty *tp = pti->pt_tty;
583 	u_char buf[BUFSIZ];
584 	int error = 0, cc;
585 
586 	/*
587 	 * We want to block until the slave
588 	 * is open, and there's something to read;
589 	 * but if we lost the slave or we're NBIO,
590 	 * then return the appropriate error instead.
591 	 */
592 	TTY_LOCK(tp);
593 	for (;;) {
594 		if (ISSET(tp->t_state, TS_ISOPEN)) {
595 			if (pti->pt_flags & PF_PKT && pti->pt_send) {
596 				TTY_UNLOCK(tp);
597 				error = ureadc((int)pti->pt_send, uio);
598 				if (error)
599 					return (error);
600 				/*
601 				 * Since we don't have the tty locked, there's
602 				 * a risk of messing up `t_termios'. This is
603 				 * relevant only if the tty got closed and then
604 				 * opened again while we were out uiomoving.
605 				 */
606 				if (pti->pt_send & TIOCPKT_IOCTL) {
607 					cc = min(uio->uio_resid,
608 						sizeof(tp->t_termios));
609 					uiomove((caddr_t) &tp->t_termios,
610 						cc, uio);
611 				}
612 				pti->pt_send = 0;
613 				return (0);
614 			}
615 			if (pti->pt_flags & PF_UCNTL && pti->pt_ucntl) {
616 				TTY_UNLOCK(tp);
617 				error = ureadc((int)pti->pt_ucntl, uio);
618 				if (error)
619 					return (error);
620 				pti->pt_ucntl = 0;
621 				return (0);
622 			}
623 			if (tp->t_outq.c_cc && !ISSET(tp->t_state, TS_TTSTOP))
624 				break;
625 		}
626 		if (!ISSET(tp->t_state, TS_CARR_ON)) {
627 			error = 0;	/* EOF */
628 			goto out;
629 		}
630 		if (flag & IO_NDELAY) {
631 			error = EWOULDBLOCK;
632 			goto out;
633 		}
634 		error = ltsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
635 				ttyin, 0, &tp->t_slock);
636 		if (error)
637 			goto out;
638 	}
639 
640 	if (pti->pt_flags & (PF_PKT|PF_UCNTL)) {
641 		TTY_UNLOCK(tp);
642 		error = ureadc(0, uio);
643 		TTY_LOCK(tp);
644 		if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
645 			error = EIO;
646 	}
647 	while (uio->uio_resid > 0 && error == 0) {
648 		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
649 		if (cc <= 0)
650 			break;
651 		TTY_UNLOCK(tp);
652 		error = uiomove(buf, cc, uio);
653 		TTY_LOCK(tp);
654 		if (error == 0 && !ISSET(tp->t_state, TS_ISOPEN))
655 			error = EIO;
656 	}
657 
658 	if (tp->t_outq.c_cc <= tp->t_lowat) {
659 		if (ISSET(tp->t_state, TS_ASLEEP)) {
660 			CLR(tp->t_state, TS_ASLEEP);
661 			wakeup((caddr_t)&tp->t_outq);
662 		}
663 		selnotify(&tp->t_wsel, 0);
664 	}
665 out:
666 	TTY_UNLOCK(tp);
667 	return (error);
668 }
669 
670 
671 int
672 ptcwrite(dev, uio, flag)
673 	dev_t dev;
674 	struct uio *uio;
675 	int flag;
676 {
677 	struct pt_softc *pti = pt_softc[minor(dev)];
678 	struct tty *tp = pti->pt_tty;
679 	u_char *cp = NULL;
680 	int cc = 0;
681 	u_char locbuf[BUFSIZ];
682 	int cnt = 0;
683 	int error = 0;
684 
685 again:
686 	TTY_LOCK(tp);
687 	if (!ISSET(tp->t_state, TS_ISOPEN))
688 		goto block;
689 	if (pti->pt_flags & PF_REMOTE) {
690 		if (tp->t_canq.c_cc)
691 			goto block;
692 		while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
693 			if (cc == 0) {
694 				cc = min(uio->uio_resid, BUFSIZ);
695 				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
696 				cp = locbuf;
697 				TTY_UNLOCK(tp);
698 				error = uiomove((caddr_t)cp, cc, uio);
699 				if (error)
700 					return (error);
701 				TTY_LOCK(tp);
702 				/* check again for safety */
703 				if (!ISSET(tp->t_state, TS_ISOPEN)) {
704 					error = EIO;
705 					goto out;
706 				}
707 			}
708 			if (cc)
709 				(void) b_to_q(cp, cc, &tp->t_canq);
710 			cc = 0;
711 		}
712 		(void) putc(0, &tp->t_canq);
713 		ttwakeup(tp);
714 		wakeup((caddr_t)&tp->t_canq);
715 		error = 0;
716 		goto out;
717 	}
718 	while (uio->uio_resid > 0) {
719 		if (cc == 0) {
720 			cc = min(uio->uio_resid, BUFSIZ);
721 			cp = locbuf;
722 			TTY_UNLOCK(tp);
723 			error = uiomove((caddr_t)cp, cc, uio);
724 			if (error)
725 				return (error);
726 			TTY_LOCK(tp);
727 			/* check again for safety */
728 			if (!ISSET(tp->t_state, TS_ISOPEN)) {
729 				error = EIO;
730 				goto out;
731 			}
732 		}
733 		while (cc > 0) {
734 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
735 			   (tp->t_canq.c_cc > 0 || !ISSET(tp->t_lflag, ICANON))) {
736 				wakeup((caddr_t)&tp->t_rawq);
737 				goto block;
738 			}
739 			/* XXX - should change l_rint to be called with lock
740 			 *	 see also tty.c:ttyinput_wlock()
741 			 */
742 			TTY_UNLOCK(tp);
743 			(*tp->t_linesw->l_rint)(*cp++, tp);
744 			TTY_LOCK(tp);
745 			cnt++;
746 			cc--;
747 		}
748 		cc = 0;
749 	}
750 	error = 0;
751 	goto out;
752 
753 block:
754 	/*
755 	 * Come here to wait for slave to open, for space
756 	 * in outq, or space in rawq.
757 	 */
758 	if (!ISSET(tp->t_state, TS_CARR_ON)) {
759 		error = EIO;
760 		goto out;
761 	}
762 	if (flag & IO_NDELAY) {
763 		/* adjust for data copied in but not written */
764 		uio->uio_resid += cc;
765 		error = cnt == 0 ? EWOULDBLOCK : 0;
766 		goto out;
767 	}
768 	error = ltsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH | PNORELOCK,
769 		       ttyout, 0, &tp->t_slock);
770 	if (error) {
771 		/* adjust for data copied in but not written */
772 		uio->uio_resid += cc;
773 		return (error);
774 	}
775 	goto again;
776 
777 out:
778 	TTY_UNLOCK(tp);
779 	return (error);
780 }
781 
782 int
783 ptcpoll(dev, events, p)
784 	dev_t dev;
785 	int events;
786 	struct proc *p;
787 {
788 	struct pt_softc *pti = pt_softc[minor(dev)];
789 	struct tty *tp = pti->pt_tty;
790 	int revents = 0;
791 	int s = splsoftclock();
792 
793 	if (events & (POLLIN | POLLRDNORM))
794 		if (ISSET(tp->t_state, TS_ISOPEN) &&
795 		    ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
796 		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
797 		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
798 			revents |= events & (POLLIN | POLLRDNORM);
799 
800 	if (events & (POLLOUT | POLLWRNORM))
801 		if (ISSET(tp->t_state, TS_ISOPEN) &&
802 		    ((pti->pt_flags & PF_REMOTE) ?
803 		     (tp->t_canq.c_cc == 0) :
804 		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
805 		      (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))))
806 			revents |= events & (POLLOUT | POLLWRNORM);
807 
808 	if (events & POLLHUP)
809 		if (!ISSET(tp->t_state, TS_CARR_ON))
810 			revents |= POLLHUP;
811 
812 	if (revents == 0) {
813 		if (events & (POLLIN | POLLHUP | POLLRDNORM))
814 			selrecord(p, &pti->pt_selr);
815 
816 		if (events & (POLLOUT | POLLWRNORM))
817 			selrecord(p, &pti->pt_selw);
818 	}
819 
820 	splx(s);
821 	return (revents);
822 }
823 
824 static void
825 filt_ptcrdetach(struct knote *kn)
826 {
827 	struct pt_softc *pti;
828 	int		s;
829 
830 	pti = kn->kn_hook;
831 	s = spltty();
832 	SLIST_REMOVE(&pti->pt_selr.sel_klist, kn, knote, kn_selnext);
833 	splx(s);
834 }
835 
836 static int
837 filt_ptcread(struct knote *kn, long hint)
838 {
839 	struct pt_softc *pti;
840 	struct tty	*tp;
841 	int canread;
842 
843 	pti = kn->kn_hook;
844 	tp = pti->pt_tty;
845 
846 	canread = (ISSET(tp->t_state, TS_ISOPEN) &&
847 		    ((tp->t_outq.c_cc > 0 && !ISSET(tp->t_state, TS_TTSTOP)) ||
848 		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
849 		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)));
850 
851 	if (canread) {
852 		/*
853 		 * c_cc is number of characters after output post-processing;
854 		 * the amount of data actually read(2) depends on
855 		 * setting of input flags for the terminal.
856 		 */
857 		kn->kn_data = tp->t_outq.c_cc;
858 		if (((pti->pt_flags & PF_PKT) && pti->pt_send) ||
859 		    ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))
860 			kn->kn_data++;
861 	}
862 
863 	return (canread);
864 }
865 
866 static void
867 filt_ptcwdetach(struct knote *kn)
868 {
869 	struct pt_softc *pti;
870 	int		s;
871 
872 	pti = kn->kn_hook;
873 	s = spltty();
874 	SLIST_REMOVE(&pti->pt_selw.sel_klist, kn, knote, kn_selnext);
875 	splx(s);
876 }
877 
878 static int
879 filt_ptcwrite(struct knote *kn, long hint)
880 {
881 	struct pt_softc *pti;
882 	struct tty	*tp;
883 	int canwrite;
884 	int nwrite;
885 
886 	pti = kn->kn_hook;
887 	tp = pti->pt_tty;
888 
889 	canwrite = (ISSET(tp->t_state, TS_ISOPEN) &&
890 		    ((pti->pt_flags & PF_REMOTE) ?
891 		     (tp->t_canq.c_cc == 0) :
892 		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) ||
893 		      (tp->t_canq.c_cc == 0 && ISSET(tp->t_lflag, ICANON)))));
894 
895 	if (canwrite) {
896 		if (pti->pt_flags & PF_REMOTE)
897 			nwrite = tp->t_canq.c_cn;
898 		else {
899 			/* this is guaranteed to be > 0 due to above check */
900 			nwrite = tp->t_canq.c_cn
901 				- (tp->t_rawq.c_cc + tp->t_canq.c_cc);
902 		}
903 		kn->kn_data = nwrite;
904 	}
905 
906 	return (canwrite);
907 }
908 
909 static const struct filterops ptcread_filtops =
910 	{ 1, NULL, filt_ptcrdetach, filt_ptcread };
911 static const struct filterops ptcwrite_filtops =
912 	{ 1, NULL, filt_ptcwdetach, filt_ptcwrite };
913 
914 int
915 ptckqfilter(dev_t dev, struct knote *kn)
916 {
917 	struct pt_softc *pti = pt_softc[minor(dev)];
918 	struct klist	*klist;
919 	int		s;
920 
921 	switch (kn->kn_filter) {
922 	case EVFILT_READ:
923 		klist = &pti->pt_selr.sel_klist;
924 		kn->kn_fop = &ptcread_filtops;
925 		break;
926 	case EVFILT_WRITE:
927 		klist = &pti->pt_selw.sel_klist;
928 		kn->kn_fop = &ptcwrite_filtops;
929 		break;
930 	default:
931 		return (1);
932 	}
933 
934 	kn->kn_hook = pti;
935 
936 	s = spltty();
937 	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
938 	splx(s);
939 
940 	return (0);
941 }
942 
943 struct tty *
944 ptytty(dev)
945 	dev_t dev;
946 {
947 	struct pt_softc *pti = pt_softc[minor(dev)];
948 	struct tty *tp = pti->pt_tty;
949 
950 	return (tp);
951 }
952 
953 /*ARGSUSED*/
954 int
955 ptyioctl(dev, cmd, data, flag, p)
956 	dev_t dev;
957 	u_long cmd;
958 	caddr_t data;
959 	int flag;
960 	struct proc *p;
961 {
962 	struct pt_softc *pti = pt_softc[minor(dev)];
963 	struct tty *tp = pti->pt_tty;
964 	const struct cdevsw *cdev;
965 	u_char *cc = tp->t_cc;
966 	int stop, error, sig;
967 
968 	cdev = cdevsw_lookup(dev);
969 	/*
970 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
971 	 * ttywflush(tp) will hang if there are characters in the outq.
972 	 */
973 	if (cmd == TIOCEXT) {
974 		/*
975 		 * When the EXTPROC bit is being toggled, we need
976 		 * to send an TIOCPKT_IOCTL if the packet driver
977 		 * is turned on.
978 		 */
979 		if (*(int *)data) {
980 			if (pti->pt_flags & PF_PKT) {
981 				pti->pt_send |= TIOCPKT_IOCTL;
982 				ptcwakeup(tp, FREAD);
983 			}
984 			SET(tp->t_lflag, EXTPROC);
985 		} else {
986 			if (ISSET(tp->t_lflag, EXTPROC) &&
987 			    (pti->pt_flags & PF_PKT)) {
988 				pti->pt_send |= TIOCPKT_IOCTL;
989 				ptcwakeup(tp, FREAD);
990 			}
991 			CLR(tp->t_lflag, EXTPROC);
992 		}
993 		return(0);
994 	}
995 
996 	if (cdev != NULL && cdev->d_open == ptcopen)
997 		switch (cmd) {
998 
999 		case TIOCGPGRP:
1000 			/*
1001 			 * We avoid calling ttioctl on the controller since,
1002 			 * in that case, tp must be the controlling terminal.
1003 			 */
1004 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
1005 			return (0);
1006 
1007 		case TIOCPKT:
1008 			if (*(int *)data) {
1009 				if (pti->pt_flags & PF_UCNTL)
1010 					return (EINVAL);
1011 				pti->pt_flags |= PF_PKT;
1012 			} else
1013 				pti->pt_flags &= ~PF_PKT;
1014 			return (0);
1015 
1016 		case TIOCUCNTL:
1017 			if (*(int *)data) {
1018 				if (pti->pt_flags & PF_PKT)
1019 					return (EINVAL);
1020 				pti->pt_flags |= PF_UCNTL;
1021 			} else
1022 				pti->pt_flags &= ~PF_UCNTL;
1023 			return (0);
1024 
1025 		case TIOCREMOTE:
1026 			if (*(int *)data)
1027 				pti->pt_flags |= PF_REMOTE;
1028 			else
1029 				pti->pt_flags &= ~PF_REMOTE;
1030 			TTY_LOCK(tp);
1031 			ttyflush(tp, FREAD|FWRITE);
1032 			TTY_UNLOCK(tp);
1033 			return (0);
1034 
1035 #ifdef COMPAT_OLDTTY
1036 		case TIOCSETP:
1037 		case TIOCSETN:
1038 #endif
1039 		case TIOCSETD:
1040 		case TIOCSETA:
1041 		case TIOCSETAW:
1042 		case TIOCSETAF:
1043 			TTY_LOCK(tp);
1044 			ndflush(&tp->t_outq, tp->t_outq.c_cc);
1045 			TTY_UNLOCK(tp);
1046 			break;
1047 
1048 		case TIOCSIG:
1049 			sig = (int)(long)*(caddr_t *)data;
1050 			if (sig <= 0 || sig >= NSIG)
1051 				return (EINVAL);
1052 			TTY_LOCK(tp);
1053 			if (!ISSET(tp->t_lflag, NOFLSH))
1054 				ttyflush(tp, FREAD|FWRITE);
1055 			if ((sig == SIGINFO) &&
1056 			    (!ISSET(tp->t_lflag, NOKERNINFO)))
1057 				ttyinfo(tp);
1058 			TTY_UNLOCK(tp);
1059 			pgsignal(tp->t_pgrp, sig, 1);
1060 			return(0);
1061 		}
1062 
1063 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
1064 	if (error == EPASSTHROUGH)
1065 		 error = ttioctl(tp, cmd, data, flag, p);
1066 	if (error == EPASSTHROUGH) {
1067 		if (pti->pt_flags & PF_UCNTL &&
1068 		    (cmd & ~0xff) == UIOCCMD(0)) {
1069 			if (cmd & 0xff) {
1070 				pti->pt_ucntl = (u_char)cmd;
1071 				ptcwakeup(tp, FREAD);
1072 			}
1073 			return (0);
1074 		}
1075 	}
1076 	/*
1077 	 * If external processing and packet mode send ioctl packet.
1078 	 */
1079 	if (ISSET(tp->t_lflag, EXTPROC) && (pti->pt_flags & PF_PKT)) {
1080 		switch(cmd) {
1081 		case TIOCSETA:
1082 		case TIOCSETAW:
1083 		case TIOCSETAF:
1084 #ifdef COMPAT_OLDTTY
1085 		case TIOCSETP:
1086 		case TIOCSETN:
1087 		case TIOCSETC:
1088 		case TIOCSLTC:
1089 		case TIOCLBIS:
1090 		case TIOCLBIC:
1091 		case TIOCLSET:
1092 #endif
1093 			pti->pt_send |= TIOCPKT_IOCTL;
1094 			ptcwakeup(tp, FREAD);
1095 		default:
1096 			break;
1097 		}
1098 	}
1099 	stop = ISSET(tp->t_iflag, IXON) && CCEQ(cc[VSTOP], CTRL('s'))
1100 		&& CCEQ(cc[VSTART], CTRL('q'));
1101 	if (pti->pt_flags & PF_NOSTOP) {
1102 		if (stop) {
1103 			pti->pt_send &= ~TIOCPKT_NOSTOP;
1104 			pti->pt_send |= TIOCPKT_DOSTOP;
1105 			pti->pt_flags &= ~PF_NOSTOP;
1106 			ptcwakeup(tp, FREAD);
1107 		}
1108 	} else {
1109 		if (!stop) {
1110 			pti->pt_send &= ~TIOCPKT_DOSTOP;
1111 			pti->pt_send |= TIOCPKT_NOSTOP;
1112 			pti->pt_flags |= PF_NOSTOP;
1113 			ptcwakeup(tp, FREAD);
1114 		}
1115 	}
1116 	return (error);
1117 }
1118