xref: /netbsd-src/sys/kern/tty_pty.c (revision 38023541164cff097d5fadec63134189b1453b8c)
1 /*
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	from: @(#)tty_pty.c	7.21 (Berkeley) 5/30/91
34  *	$Id: tty_pty.c,v 1.15 1993/11/15 09:17:05 deraadt Exp $
35  */
36 
37 /*
38  * Pseudo-teletype Driver
39  * (Actually two drivers, requiring two entries in 'cdevsw')
40  */
41 #include "pty.h"
42 
43 #if NPTY > 0
44 #include "param.h"
45 #include "systm.h"
46 #include "ioctl.h"
47 #include "select.h"
48 #include "tty.h"
49 #include "conf.h"
50 #include "file.h"
51 #include "proc.h"
52 #include "uio.h"
53 #include "kernel.h"
54 #include "vnode.h"
55 
56 #if NPTY == 1
57 #undef NPTY
58 #define	NPTY	32		/* crude XXX */
59 #endif
60 
61 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
62 
63 /*
64  * pts == /dev/tty[pqrs]?
65  * ptc == /dev/pty[pqrs]?
66  */
67 struct	tty *pt_tty[NPTY];
68 struct	pt_ioctl {
69 	int	pt_flags;
70 	struct selinfo pt_selr, pt_selw;
71 	u_char	pt_send;
72 	u_char	pt_ucntl;
73 } pt_ioctl[NPTY];
74 int	npty = NPTY;		/* for pstat -t */
75 
76 #define	PF_COPEN	0x01		/* master open */
77 #define	PF_SOPEN	0x02		/* slave open */
78 #define	PF_PKT		0x08		/* packet mode */
79 #define	PF_STOPPED	0x10		/* user told stopped */
80 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
81 #define	PF_NOSTOP	0x40
82 #define PF_UCNTL	0x80		/* user control mode */
83 
84 void ptcwakeup __P((struct tty *tp, int flag));
85 
86 void
87 ptyattach(n)
88 	int n;
89 {
90 }
91 
92 /*ARGSUSED*/
93 int
94 ptsopen(dev, flag, devtype, p)
95 	dev_t dev;
96 	int flag, devtype;
97 	struct proc *p;
98 {
99 	register struct tty *tp;
100 	int error;
101 
102 #ifdef lint
103 	npty = npty;
104 #endif
105 	if (minor(dev) >= NPTY)
106 		return (ENXIO);
107 	if(!pt_tty[minor(dev)]) {
108 		tp = pt_tty[minor(dev)] = ttymalloc();
109 	} else
110 		tp = pt_tty[minor(dev)];
111 	if ((tp->t_state & TS_ISOPEN) == 0) {
112 		tp->t_state |= TS_WOPEN;
113 		ttychars(tp);		/* Set up default chars */
114 		tp->t_iflag = TTYDEF_IFLAG;
115 		tp->t_oflag = TTYDEF_OFLAG;
116 		tp->t_lflag = TTYDEF_LFLAG;
117 		tp->t_cflag = TTYDEF_CFLAG;
118 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
119 		ttsetwater(tp);		/* would be done in xxparam() */
120 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
121 		return (EBUSY);
122 	if (tp->t_oproc)			/* Ctrlr still around. */
123 		tp->t_state |= TS_CARR_ON;
124 	while ((tp->t_state & TS_CARR_ON) == 0) {
125 		tp->t_state |= TS_WOPEN;
126 		if (flag&FNONBLOCK)
127 			break;
128 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
129 		    ttopen, 0))
130 			return (error);
131 	}
132 	if (error = (*linesw[tp->t_line].l_open)(dev, tp))
133 		return (error);
134 	pt_ioctl[minor(dev)].pt_flags |= PF_SOPEN;
135 	ptcwakeup(tp, FREAD|FWRITE);
136 	return (0);
137 }
138 
139 int
140 ptsclose(dev, flag, mode, p)
141 	dev_t dev;
142 	int flag, mode;
143 	struct proc *p;
144 {
145 	register struct tty *tp;
146 
147 	tp = pt_tty[minor(dev)];
148 	(*linesw[tp->t_line].l_close)(tp, flag);
149 	ttyclose(tp);
150 	ptcwakeup(tp, FREAD|FWRITE);
151 	pt_ioctl[minor(dev)].pt_flags &= ~PF_SOPEN;
152 #ifdef broken /* session holds a ref to the tty; can't deallocate */
153 	if ((pt_ioctl[minor(dev)].pt_flags & PF_COPEN) == 0) {
154 		ttyfree(tp);
155 		pt_tty[minor(dev)] = (struct tty *)NULL;
156 	}
157 #endif
158 	return(0);
159 }
160 
161 int
162 ptsread(dev, uio, flag)
163 	dev_t dev;
164 	struct uio *uio;
165 	int flag;
166 {
167 	struct proc *p = curproc;
168 	register struct tty *tp = pt_tty[minor(dev)];
169 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
170 	int error = 0;
171 
172 again:
173 	if (pti->pt_flags & PF_REMOTE) {
174 		while (isbackground(p, tp)) {
175 			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
176 			    (p->p_sigmask & sigmask(SIGTTIN)) ||
177 			    p->p_pgrp->pg_jobc == 0 ||
178 			    p->p_flag&SPPWAIT)
179 				return (EIO);
180 			pgsignal(p->p_pgrp, SIGTTIN, 1);
181 			if (error = ttysleep(tp, (caddr_t)&lbolt,
182 			    TTIPRI | PCATCH, ttybg, 0))
183 				return (error);
184 		}
185 		if (tp->t_canq.c_cc == 0) {
186 			if (flag & IO_NDELAY)
187 				return (EWOULDBLOCK);
188 			if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
189 			    TTIPRI | PCATCH, ttyin, 0))
190 				return (error);
191 			goto again;
192 		}
193 		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
194 			if (ureadc(getc(&tp->t_canq), uio) < 0) {
195 				error = EFAULT;
196 				break;
197 			}
198 		if (tp->t_canq.c_cc == 1)
199 			(void) getc(&tp->t_canq);
200 		if (tp->t_canq.c_cc)
201 			return (error);
202 	} else
203 		if (tp->t_oproc)
204 			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
205 	ptcwakeup(tp, FWRITE);
206 	return (error);
207 }
208 
209 /*
210  * Write to pseudo-tty.
211  * Wakeups of controlling tty will happen
212  * indirectly, when tty driver calls ptsstart.
213  */
214 int
215 ptswrite(dev, uio, flag)
216 	dev_t dev;
217 	struct uio *uio;
218 	int flag;
219 {
220 	register struct tty *tp;
221 
222 	tp = pt_tty[minor(dev)];
223 	if (tp->t_oproc == 0)
224 		return (EIO);
225 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
226 }
227 
228 /*
229  * Start output on pseudo-tty.
230  * Wake up process selecting or sleeping for input from controlling tty.
231  */
232 void
233 ptsstart(tp)
234 	struct tty *tp;
235 {
236 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
237 
238 	if (tp->t_state & TS_TTSTOP)
239 		return;
240 	if (pti->pt_flags & PF_STOPPED) {
241 		pti->pt_flags &= ~PF_STOPPED;
242 		pti->pt_send = TIOCPKT_START;
243 	}
244 	ptcwakeup(tp, FREAD);
245 	return;
246 }
247 
248 void
249 ptcwakeup(tp, flag)
250 	struct tty *tp;
251 	int flag;
252 {
253 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
254 
255 	if (flag & FREAD) {
256 		selwakeup(&pti->pt_selr);
257 		wakeup((caddr_t)&tp->t_outq.c_cl);
258 	}
259 	if (flag & FWRITE) {
260 		selwakeup(&pti->pt_selw);
261 		wakeup((caddr_t)&tp->t_rawq.c_cf);
262 	}
263 }
264 
265 /*ARGSUSED*/
266 #ifdef __STDC__
267 int
268 ptcopen(dev_t dev, int flag, int devtype, struct proc *p)
269 #else
270 int
271 ptcopen(dev, flag, devtype, p)
272 	dev_t dev;
273 	int flag, devtype;
274 	struct proc *p;
275 #endif
276 {
277 	register struct tty *tp;
278 	struct pt_ioctl *pti;
279 
280 	if (minor(dev) >= NPTY)
281 		return (ENXIO);
282 	if(!pt_tty[minor(dev)]) {
283 		tp = pt_tty[minor(dev)] = ttymalloc();
284 	} else
285 		tp = pt_tty[minor(dev)];
286 	if (tp->t_oproc)
287 		return (EIO);
288 	tp->t_oproc = ptsstart;
289 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
290 	tp->t_lflag &= ~EXTPROC;
291 	pti = &pt_ioctl[minor(dev)];
292 	pti->pt_flags &= PF_SOPEN;
293 	pti->pt_flags |= PF_COPEN;
294 	pti->pt_send = 0;
295 	pti->pt_ucntl = 0;
296 	return (0);
297 }
298 
299 extern struct tty *constty;	/* -hv- 06.Oct.92*/
300 
301 int
302 ptcclose(dev)
303 	dev_t dev;
304 {
305 	register struct tty *tp;
306 
307 	tp = pt_tty[minor(dev)];
308 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
309 	tp->t_state &= ~TS_CARR_ON;
310 	tp->t_oproc = 0;		/* mark closed */
311 
312 /* XXX -hv- 6.Oct.92 this prevents the "hanging console bug" with X11 */
313 	if (constty==tp)
314 		constty = 0;
315 
316 	pt_ioctl[minor(dev)].pt_flags &= ~PF_COPEN;
317 #ifdef broken
318 	if ((pt_ioctl[minor(dev)].pt_flags & PF_SOPEN) == 0) {
319 		ttyfree(tp);
320 		pt_tty[minor(dev)] = (struct tty *)NULL;
321 	}
322 #endif
323 	return (0);
324 }
325 
326 int
327 ptcread(dev, uio, flag)
328 	dev_t dev;
329 	struct uio *uio;
330 	int flag;
331 {
332 	register struct tty *tp = pt_tty[minor(dev)];
333 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
334 	u_char buf[BUFSIZ];
335 	int error = 0, cc;
336 
337 	/*
338 	 * We want to block until the slave
339 	 * is open, and there's something to read;
340 	 * but if we lost the slave or we're NBIO,
341 	 * then return the appropriate error instead.
342 	 */
343 	for (;;) {
344 		if (tp->t_state&TS_ISOPEN) {
345 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
346 				error = ureadc((int)pti->pt_send, uio);
347 				if (error)
348 					return (error);
349 				if (pti->pt_send & TIOCPKT_IOCTL) {
350 					cc = MIN(uio->uio_resid,
351 						sizeof(tp->t_termios));
352 					uiomove((caddr_t)&tp->t_termios, cc,
353 						uio);
354 				}
355 				pti->pt_send = 0;
356 				return (0);
357 			}
358 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
359 				error = ureadc((int)pti->pt_ucntl, uio);
360 				if (error)
361 					return (error);
362 				pti->pt_ucntl = 0;
363 				return (0);
364 			}
365 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
366 				break;
367 		}
368 		if ((tp->t_state&TS_CARR_ON) == 0)
369 			return (0);	/* EOF */
370 		if (flag & IO_NDELAY)
371 			return (EWOULDBLOCK);
372 		if (error = tsleep((caddr_t)&tp->t_outq.c_cl, TTIPRI | PCATCH,
373 		    ttyin, 0))
374 			return (error);
375 	}
376 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
377 		error = ureadc(0, uio);
378 	while (uio->uio_resid > 0 && error == 0) {
379 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
380 		if (cc <= 0)
381 			break;
382 		error = uiomove(buf, cc, uio);
383 	}
384 	if (tp->t_outq.c_cc <= tp->t_lowat) {
385 		if (tp->t_state&TS_ASLEEP) {
386 			tp->t_state &= ~TS_ASLEEP;
387 			wakeup((caddr_t)&tp->t_outq);
388 		}
389 		selwakeup(&tp->t_wsel);
390 	}
391 	return (error);
392 }
393 
394 void
395 ptsstop(tp, flush)
396 	register struct tty *tp;
397 	int flush;
398 {
399 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
400 	int flag;
401 
402 	/* note: FLUSHREAD and FLUSHWRITE already ok */
403 	if (flush == 0) {
404 		flush = TIOCPKT_STOP;
405 		pti->pt_flags |= PF_STOPPED;
406 	} else
407 		pti->pt_flags &= ~PF_STOPPED;
408 	pti->pt_send |= flush;
409 	/* change of perspective */
410 	flag = 0;
411 	if (flush & FREAD)
412 		flag |= FWRITE;
413 	if (flush & FWRITE)
414 		flag |= FREAD;
415 	ptcwakeup(tp, flag);
416 }
417 
418 int
419 ptcselect(dev, rw, p)
420 	dev_t dev;
421 	int rw;
422 	struct proc *p;
423 {
424 	register struct tty *tp = pt_tty[minor(dev)];
425 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
426 	int s;
427 
428 	if ((tp->t_state&TS_CARR_ON) == 0)
429 		return (1);
430 	switch (rw) {
431 
432 	case FREAD:
433 		/*
434 		 * Need to block timeouts (ttrstart).
435 		 */
436 		s = spltty();
437 		if ((tp->t_state&TS_ISOPEN) &&
438 		     tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
439 			splx(s);
440 			return (1);
441 		}
442 		splx(s);
443 		/* FALLTHROUGH */
444 
445 	case 0:					/* exceptional */
446 		if ((tp->t_state&TS_ISOPEN) &&
447 		    (pti->pt_flags&PF_PKT && pti->pt_send ||
448 		     pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
449 			return (1);
450 		selrecord(p, &pti->pt_selr);
451 		break;
452 
453 
454 	case FWRITE:
455 		if (tp->t_state&TS_ISOPEN) {
456 			if (pti->pt_flags & PF_REMOTE) {
457 			    if (tp->t_canq.c_cc == 0)
458 				return (1);
459 			} else {
460 			    if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
461 				    return (1);
462 			    if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
463 				    return (1);
464 			}
465 		}
466 		selrecord(p, &pti->pt_selw);
467 		break;
468 
469 	}
470 	return (0);
471 }
472 
473 int
474 ptcwrite(dev, uio, flag)
475 	dev_t dev;
476 	register struct uio *uio;
477 	int flag;
478 {
479 	register struct tty *tp = pt_tty[minor(dev)];
480 	register u_char *cp;
481 	register int cc = 0;
482 	u_char locbuf[BUFSIZ];
483 	int cnt = 0;
484 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
485 	int error = 0;
486 
487 again:
488 	if ((tp->t_state&TS_ISOPEN) == 0)
489 		goto block;
490 	if (pti->pt_flags & PF_REMOTE) {
491 		if (tp->t_canq.c_cc)
492 			goto block;
493 		while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
494 			if (cc == 0) {
495 				cc = min(uio->uio_resid, BUFSIZ);
496 				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
497 				cp = locbuf;
498 				error = uiomove((caddr_t)cp, cc, uio);
499 				if (error)
500 					return (error);
501 				/* check again for safety */
502 				if ((tp->t_state&TS_ISOPEN) == 0)
503 					return (EIO);
504 			}
505 			if (cc)
506 				(void) b_to_q(cp, cc, &tp->t_canq);
507 			cc = 0;
508 		}
509 		(void) putc(0, &tp->t_canq);
510 		ttwakeup(tp);
511 		wakeup((caddr_t)&tp->t_canq);
512 		return (0);
513 	}
514 	while (uio->uio_resid > 0) {
515 		if (cc == 0) {
516 			cc = min(uio->uio_resid, BUFSIZ);
517 			cp = locbuf;
518 			error = uiomove((caddr_t)cp, cc, uio);
519 			if (error)
520 				return (error);
521 			/* check again for safety */
522 			if ((tp->t_state&TS_ISOPEN) == 0)
523 				return (EIO);
524 		}
525 		while (cc > 0) {
526 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
527 			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
528 				wakeup((caddr_t)&tp->t_rawq);
529 				goto block;
530 			}
531 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
532 			cnt++;
533 			cc--;
534 		}
535 		cc = 0;
536 	}
537 	return (0);
538 block:
539 	/*
540 	 * Come here to wait for slave to open, for space
541 	 * in outq, or space in rawq.
542 	 */
543 	if ((tp->t_state&TS_CARR_ON) == 0)
544 		return (EIO);
545 	if (flag & IO_NDELAY) {
546 		/* adjust for data copied in but not written */
547 		uio->uio_resid += cc;
548 		if (cnt == 0)
549 			return (EWOULDBLOCK);
550 		return (0);
551 	}
552 	if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
553 	    ttyout, 0)) {
554 		/* adjust for data copied in but not written */
555 		uio->uio_resid += cc;
556 		return (error);
557 	}
558 	goto again;
559 }
560 
561 /*ARGSUSED*/
562 int
563 ptyioctl(dev, cmd, data, flag)
564 	caddr_t data;
565 	int cmd, flag;
566 	dev_t dev;
567 {
568 	register struct tty *tp = pt_tty[minor(dev)];
569 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
570 	register u_char *cc = tp->t_cc;
571 	int stop, error;
572 
573 	/*
574 	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
575 	 * ttywflush(tp) will hang if there are characters in the outq.
576 	 */
577 	if (cmd == TIOCEXT) {
578 		/*
579 		 * When the EXTPROC bit is being toggled, we need
580 		 * to send an TIOCPKT_IOCTL if the packet driver
581 		 * is turned on.
582 		 */
583 		if (*(int *)data) {
584 			if (pti->pt_flags & PF_PKT) {
585 				pti->pt_send |= TIOCPKT_IOCTL;
586 				ptcwakeup(tp, FREAD);
587 			}
588 			tp->t_lflag |= EXTPROC;
589 		} else {
590 			if ((tp->t_state & EXTPROC) &&
591 			    (pti->pt_flags & PF_PKT)) {
592 				pti->pt_send |= TIOCPKT_IOCTL;
593 				ptcwakeup(tp, FREAD);
594 			}
595 			tp->t_lflag &= ~EXTPROC;
596 		}
597 		return(0);
598 	} else
599 	if (cdevsw[major(dev)].d_open == ptcopen)
600 		switch (cmd) {
601 
602 		case TIOCGPGRP:
603 			/*
604 			 * We aviod calling ttioctl on the controller since,
605 			 * in that case, tp must be the controlling terminal.
606 			 */
607 			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
608 			return (0);
609 
610 		case TIOCPKT:
611 			if (*(int *)data) {
612 				if (pti->pt_flags & PF_UCNTL)
613 					return (EINVAL);
614 				pti->pt_flags |= PF_PKT;
615 			} else
616 				pti->pt_flags &= ~PF_PKT;
617 			return (0);
618 
619 		case TIOCUCNTL:
620 			if (*(int *)data) {
621 				if (pti->pt_flags & PF_PKT)
622 					return (EINVAL);
623 				pti->pt_flags |= PF_UCNTL;
624 			} else
625 				pti->pt_flags &= ~PF_UCNTL;
626 			return (0);
627 
628 		case TIOCREMOTE:
629 			if (*(int *)data)
630 				pti->pt_flags |= PF_REMOTE;
631 			else
632 				pti->pt_flags &= ~PF_REMOTE;
633 			ttyflush(tp, FREAD|FWRITE);
634 			return (0);
635 
636 #ifdef COMPAT_43
637 	/* wkt */
638 		case TIOCSETP:
639 		case TIOCSETN:
640 #endif
641 		case TIOCSETD:
642 		case TIOCSETA:
643 		case TIOCSETAW:
644 		case TIOCSETAF:
645 			flushq(&tp->t_outq);
646 			break;
647 
648 		case TIOCSIG:
649 			if (*(unsigned int *)data >= NSIG)
650 				return(EINVAL);
651 			if ((tp->t_lflag&NOFLSH) == 0)
652 				ttyflush(tp, FREAD|FWRITE);
653 			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
654 			if ((*(unsigned int *)data == SIGINFO) &&
655 			    ((tp->t_lflag&NOKERNINFO) == 0))
656 				ttyinfo(tp);
657 			return(0);
658 		}
659 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
660 	if (error < 0)
661 		 error = ttioctl(tp, cmd, data, flag);
662 	/*
663 	 * Since we use the tty queues internally,
664 	 * pty's can't be switched to disciplines which overwrite
665 	 * the queues.  We can't tell anything about the discipline
666 	 * from here...
667 	 */
668 	if (linesw[tp->t_line].l_rint != ttyinput) {
669 		(*linesw[tp->t_line].l_close)(tp, flag);
670 		tp->t_line = TTYDISC;
671 		(void)(*linesw[tp->t_line].l_open)(dev, tp);
672 		error = ENOTTY;
673 	}
674 	if (error < 0) {
675 		if (pti->pt_flags & PF_UCNTL &&
676 		    (cmd & ~0xff) == UIOCCMD(0)) {
677 			if (cmd & 0xff) {
678 				pti->pt_ucntl = (u_char)cmd;
679 				ptcwakeup(tp, FREAD);
680 			}
681 			return (0);
682 		}
683 		error = ENOTTY;
684 	}
685 	/*
686 	 * If external processing and packet mode send ioctl packet.
687 	 */
688 	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
689 		switch(cmd) {
690 		case TIOCSETA:
691 		case TIOCSETAW:
692 		case TIOCSETAF:
693 #ifdef	COMPAT_43
694 	/* wkt */
695 		case TIOCSETP:
696 		case TIOCSETN:
697 		case TIOCSETC:
698 		case TIOCSLTC:
699 		case TIOCLBIS:
700 		case TIOCLBIC:
701 		case TIOCLSET:
702 #endif
703 			pti->pt_send |= TIOCPKT_IOCTL;
704 		default:
705 			break;
706 		}
707 	}
708 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
709 		&& CCEQ(cc[VSTART], CTRL('q'));
710 	if (pti->pt_flags & PF_NOSTOP) {
711 		if (stop) {
712 			pti->pt_send &= ~TIOCPKT_NOSTOP;
713 			pti->pt_send |= TIOCPKT_DOSTOP;
714 			pti->pt_flags &= ~PF_NOSTOP;
715 			ptcwakeup(tp, FREAD);
716 		}
717 	} else {
718 		if (!stop) {
719 			pti->pt_send &= ~TIOCPKT_DOSTOP;
720 			pti->pt_send |= TIOCPKT_NOSTOP;
721 			pti->pt_flags |= PF_NOSTOP;
722 			ptcwakeup(tp, FREAD);
723 		}
724 	}
725 	return (error);
726 }
727 #endif
728