xref: /dragonfly/sys/kern/tty_pty.c (revision b71f52a9)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  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  *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
34  * $FreeBSD: src/sys/kern/tty_pty.c,v 1.74.2.4 2002/02/20 19:58:13 dillon Exp $
35  * $DragonFly: src/sys/kern/tty_pty.c,v 1.21 2008/08/13 10:29:38 swildner Exp $
36  */
37 
38 /*
39  * Pseudo-teletype Driver
40  * (Actually two drivers, requiring two dev_ops structures)
41  */
42 #include "use_pty.h"		/* XXX */
43 #include "opt_compat.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
48 #include <sys/ioctl_compat.h>
49 #endif
50 #include <sys/proc.h>
51 #include <sys/priv.h>
52 #include <sys/tty.h>
53 #include <sys/conf.h>
54 #include <sys/fcntl.h>
55 #include <sys/poll.h>
56 #include <sys/kernel.h>
57 #include <sys/vnode.h>
58 #include <sys/signalvar.h>
59 #include <sys/malloc.h>
60 #include <sys/device.h>
61 #include <sys/thread2.h>
62 
63 MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
64 
65 static void ptsstart (struct tty *tp);
66 static void ptsstop (struct tty *tp, int rw);
67 static void ptcwakeup (struct tty *tp, int flag);
68 static void ptyinit (int n);
69 
70 static	d_open_t	ptsopen;
71 static	d_close_t	ptsclose;
72 static	d_read_t	ptsread;
73 static	d_write_t	ptswrite;
74 static	d_ioctl_t	ptyioctl;
75 static	d_open_t	ptcopen;
76 static	d_close_t	ptcclose;
77 static	d_read_t	ptcread;
78 static	d_write_t	ptcwrite;
79 static	d_poll_t	ptcpoll;
80 
81 #define	CDEV_MAJOR_S	5
82 static struct dev_ops pts_ops = {
83 	{ "pts", CDEV_MAJOR_S, D_TTY | D_KQFILTER },
84 	.d_open =	ptsopen,
85 	.d_close =	ptsclose,
86 	.d_read =	ptsread,
87 	.d_write =	ptswrite,
88 	.d_ioctl =	ptyioctl,
89 	.d_poll =	ttypoll,
90 	.d_kqfilter =	ttykqfilter,
91 	.d_revoke =	ttyrevoke
92 };
93 
94 #define	CDEV_MAJOR_C	6
95 static struct dev_ops ptc_ops = {
96 	{ "ptc", CDEV_MAJOR_C, D_TTY | D_KQFILTER | D_MASTER },
97 	.d_open =	ptcopen,
98 	.d_close =	ptcclose,
99 	.d_read =	ptcread,
100 	.d_write =	ptcwrite,
101 	.d_ioctl =	ptyioctl,
102 	.d_poll =	ptcpoll,
103 	.d_kqfilter =	ttykqfilter,
104 	.d_revoke =	ttyrevoke
105 };
106 
107 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
108 
109 struct	pt_ioctl {
110 	int	pt_flags;
111 	struct	selinfo pt_selr, pt_selw;
112 	u_char	pt_send;
113 	u_char	pt_ucntl;
114 	struct tty pt_tty;
115 	cdev_t	devs, devc;
116 	struct	prison *pt_prison;
117 };
118 
119 #define	PF_PKT		0x08		/* packet mode */
120 #define	PF_STOPPED	0x10		/* user told stopped */
121 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
122 #define	PF_NOSTOP	0x40
123 #define PF_UCNTL	0x80		/* user control mode */
124 
125 /*
126  * This function creates and initializes a pts/ptc pair
127  *
128  * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
129  * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
130  *
131  * XXX: define and add mapping of upper minor bits to allow more
132  *      than 256 ptys.
133  */
134 static void
135 ptyinit(int n)
136 {
137 	cdev_t devs, devc;
138 	char *names = "pqrsPQRS";
139 	struct pt_ioctl *pt;
140 
141 	/* For now we only map the lower 8 bits of the minor */
142 	if (n & ~0xff)
143 		return;
144 
145 	pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
146 	pt->devs = devs = make_dev(&pts_ops, n,
147 	    0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
148 	pt->devc = devc = make_dev(&ptc_ops, n,
149 	    0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
150 
151 	devs->si_drv1 = devc->si_drv1 = pt;
152 	devs->si_tty = devc->si_tty = &pt->pt_tty;
153 	pt->pt_tty.t_dev = devs;
154 	ttyregister(&pt->pt_tty);
155 }
156 
157 /*ARGSUSED*/
158 static	int
159 ptsopen(struct dev_open_args *ap)
160 {
161 	cdev_t dev = ap->a_head.a_dev;
162 	struct tty *tp;
163 	int error;
164 #if 0
165 	int minr;
166 	cdev_t nextdev;
167 #endif
168 	struct pt_ioctl *pti;
169 
170 #if 0
171 	minr = lminor(dev);
172 	/*
173 	 * REMOVED gross hack for devfs.  also note that makedev()
174 	 * no longer exists in this form and reference counting makes
175 	 * this a problem if we don't clean it out later.
176 	 */
177 	if (minr < 255) {
178 		nextdev = make_sub_dev(dev, minr + 1);
179 		if (!nextdev->si_drv1) {
180 			ptyinit(minr + 1);
181 		}
182 	}
183 #endif
184 	if (!dev->si_drv1)
185 		ptyinit(minor(dev));
186 	if (!dev->si_drv1)
187 		return(ENXIO);
188 	pti = dev->si_drv1;
189 	tp = dev->si_tty;
190 	if ((tp->t_state & TS_ISOPEN) == 0) {
191 		ttychars(tp);		/* Set up default chars */
192 		tp->t_iflag = TTYDEF_IFLAG;
193 		tp->t_oflag = TTYDEF_OFLAG;
194 		tp->t_lflag = TTYDEF_LFLAG;
195 		tp->t_cflag = TTYDEF_CFLAG;
196 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
197 	} else if ((tp->t_state & TS_XCLUDE) && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
198 		return (EBUSY);
199 	} else if (pti->pt_prison != ap->a_cred->cr_prison) {
200 		return (EBUSY);
201 	}
202 	if (tp->t_oproc)			/* Ctrlr still around. */
203 		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
204 	while ((tp->t_state & TS_CARR_ON) == 0) {
205 		if (ap->a_oflags & FNONBLOCK)
206 			break;
207 		error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0);
208 		if (error)
209 			return (error);
210 	}
211 	error = (*linesw[tp->t_line].l_open)(dev, tp);
212 	if (error == 0)
213 		ptcwakeup(tp, FREAD|FWRITE);
214 	return (error);
215 }
216 
217 static	int
218 ptsclose(struct dev_close_args *ap)
219 {
220 	cdev_t dev = ap->a_head.a_dev;
221 	struct tty *tp;
222 	int err;
223 
224 	tp = dev->si_tty;
225 	err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
226 	ptsstop(tp, FREAD|FWRITE);
227 	(void) ttyclose(tp);
228 	return (err);
229 }
230 
231 static	int
232 ptsread(struct dev_read_args *ap)
233 {
234 	cdev_t dev = ap->a_head.a_dev;
235 	struct proc *p = curproc;
236 	struct tty *tp = dev->si_tty;
237 	struct pt_ioctl *pti = dev->si_drv1;
238 	struct lwp *lp;
239 
240 	int error = 0;
241 
242 	lp = curthread->td_lwp;
243 
244 again:
245 	if (pti->pt_flags & PF_REMOTE) {
246 		while (isbackground(p, tp)) {
247 			if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
248 			    SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
249 			    p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT)
250 				return (EIO);
251 			pgsignal(p->p_pgrp, SIGTTIN, 1);
252 			error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0);
253 			if (error)
254 				return (error);
255 		}
256 		if (tp->t_canq.c_cc == 0) {
257 			if (ap->a_ioflag & IO_NDELAY)
258 				return (EWOULDBLOCK);
259 			error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH,
260 					 "ptsin", 0);
261 			if (error)
262 				return (error);
263 			goto again;
264 		}
265 		while (tp->t_canq.c_cc > 1 && ap->a_uio->uio_resid > 0)
266 			if (ureadc(clist_getc(&tp->t_canq), ap->a_uio) < 0) {
267 				error = EFAULT;
268 				break;
269 			}
270 		if (tp->t_canq.c_cc == 1)
271 			clist_getc(&tp->t_canq);
272 		if (tp->t_canq.c_cc)
273 			return (error);
274 	} else
275 		if (tp->t_oproc)
276 			error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
277 	ptcwakeup(tp, FWRITE);
278 	return (error);
279 }
280 
281 /*
282  * Write to pseudo-tty.
283  * Wakeups of controlling tty will happen
284  * indirectly, when tty driver calls ptsstart.
285  */
286 static	int
287 ptswrite(struct dev_write_args *ap)
288 {
289 	cdev_t dev = ap->a_head.a_dev;
290 	struct tty *tp;
291 
292 	tp = dev->si_tty;
293 	if (tp->t_oproc == 0)
294 		return (EIO);
295 	return ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
296 }
297 
298 /*
299  * Start output on pseudo-tty.
300  * Wake up process selecting or sleeping for input from controlling tty.
301  */
302 static void
303 ptsstart(struct tty *tp)
304 {
305 	struct pt_ioctl *pti = tp->t_dev->si_drv1;
306 
307 	if (tp->t_state & TS_TTSTOP)
308 		return;
309 	if (pti->pt_flags & PF_STOPPED) {
310 		pti->pt_flags &= ~PF_STOPPED;
311 		pti->pt_send = TIOCPKT_START;
312 	}
313 	ptcwakeup(tp, FREAD);
314 }
315 
316 static void
317 ptcwakeup(struct tty *tp, int flag)
318 {
319 	struct pt_ioctl *pti = tp->t_dev->si_drv1;
320 
321 	if (flag & FREAD) {
322 		selwakeup(&pti->pt_selr);
323 		wakeup(TSA_PTC_READ(tp));
324 	}
325 	if (flag & FWRITE) {
326 		selwakeup(&pti->pt_selw);
327 		wakeup(TSA_PTC_WRITE(tp));
328 	}
329 }
330 
331 static	int
332 ptcopen(struct dev_open_args *ap)
333 {
334 	cdev_t dev = ap->a_head.a_dev;
335 	struct tty *tp;
336 	struct pt_ioctl *pti;
337 
338 	if (!dev->si_drv1)
339 		ptyinit(minor(dev));
340 	if (!dev->si_drv1)
341 		return(ENXIO);
342 	tp = dev->si_tty;
343 	if (tp->t_oproc)
344 		return (EIO);
345 	tp->t_oproc = ptsstart;
346 	tp->t_stop = ptsstop;
347 	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
348 	tp->t_lflag &= ~EXTPROC;
349 	pti = dev->si_drv1;
350 	pti->pt_prison = ap->a_cred->cr_prison;
351 	pti->pt_flags = 0;
352 	pti->pt_send = 0;
353 	pti->pt_ucntl = 0;
354 	pti->devs->si_uid = ap->a_cred->cr_uid;
355 	return (0);
356 }
357 
358 static	int
359 ptcclose(struct dev_close_args *ap)
360 {
361 	cdev_t dev = ap->a_head.a_dev;
362 	struct tty *tp;
363 
364 	tp = dev->si_tty;
365 	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
366 
367 	/*
368 	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
369 	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
370 	 * l_modem()s that ignore carrier drop make no sense for ptys but
371 	 * may be in use because other parts of the line discipline make
372 	 * sense for ptys.  Recover by doing everything that a normal
373 	 * ttymodem() would have done except for sending a SIGHUP.
374 	 */
375 	if (tp->t_state & TS_ISOPEN) {
376 		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
377 		tp->t_state |= TS_ZOMBIE;
378 		ttyflush(tp, FREAD | FWRITE);
379 		tp->t_dev->si_uid = 0;
380 	}
381 
382 	tp->t_oproc = 0;		/* mark closed */
383 	return (0);
384 }
385 
386 static	int
387 ptcread(struct dev_read_args *ap)
388 {
389 	cdev_t dev = ap->a_head.a_dev;
390 	struct tty *tp = dev->si_tty;
391 	struct pt_ioctl *pti = dev->si_drv1;
392 	char buf[BUFSIZ];
393 	int error = 0, cc;
394 
395 	/*
396 	 * We want to block until the slave
397 	 * is open, and there's something to read;
398 	 * but if we lost the slave or we're NBIO,
399 	 * then return the appropriate error instead.
400 	 */
401 	for (;;) {
402 		if (tp->t_state&TS_ISOPEN) {
403 			if (pti->pt_flags&PF_PKT && pti->pt_send) {
404 				error = ureadc((int)pti->pt_send, ap->a_uio);
405 				if (error)
406 					return (error);
407 				if (pti->pt_send & TIOCPKT_IOCTL) {
408 					cc = min(ap->a_uio->uio_resid,
409 						sizeof(tp->t_termios));
410 					uiomove((caddr_t)&tp->t_termios, cc,
411 						ap->a_uio);
412 				}
413 				pti->pt_send = 0;
414 				return (0);
415 			}
416 			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
417 				error = ureadc((int)pti->pt_ucntl, ap->a_uio);
418 				if (error)
419 					return (error);
420 				pti->pt_ucntl = 0;
421 				return (0);
422 			}
423 			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
424 				break;
425 		}
426 		if ((tp->t_state & TS_CONNECTED) == 0)
427 			return (0);	/* EOF */
428 		if (ap->a_ioflag & IO_NDELAY)
429 			return (EWOULDBLOCK);
430 		error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0);
431 		if (error)
432 			return (error);
433 	}
434 	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
435 		error = ureadc(0, ap->a_uio);
436 	while (ap->a_uio->uio_resid > 0 && error == 0) {
437 		cc = q_to_b(&tp->t_outq, buf, min(ap->a_uio->uio_resid, BUFSIZ));
438 		if (cc <= 0)
439 			break;
440 		error = uiomove(buf, cc, ap->a_uio);
441 	}
442 	ttwwakeup(tp);
443 	return (error);
444 }
445 
446 static	void
447 ptsstop(struct tty *tp, int flush)
448 {
449 	struct pt_ioctl *pti = tp->t_dev->si_drv1;
450 	int flag;
451 
452 	/* note: FLUSHREAD and FLUSHWRITE already ok */
453 	if (flush == 0) {
454 		flush = TIOCPKT_STOP;
455 		pti->pt_flags |= PF_STOPPED;
456 	} else
457 		pti->pt_flags &= ~PF_STOPPED;
458 	pti->pt_send |= flush;
459 	/* change of perspective */
460 	flag = 0;
461 	if (flush & FREAD)
462 		flag |= FWRITE;
463 	if (flush & FWRITE)
464 		flag |= FREAD;
465 	ptcwakeup(tp, flag);
466 }
467 
468 static	int
469 ptcpoll(struct dev_poll_args *ap)
470 {
471 	cdev_t dev = ap->a_head.a_dev;
472 	struct tty *tp = dev->si_tty;
473 	struct pt_ioctl *pti = dev->si_drv1;
474 	int revents = 0;
475 
476 	if ((tp->t_state & TS_CONNECTED) == 0) {
477 		ap->a_events = seltrue(dev, ap->a_events) | POLLHUP;
478 		return(0);
479 	}
480 
481 	/*
482 	 * Need to block timeouts (ttrstart).
483 	 */
484 	crit_enter();
485 
486 	if (ap->a_events & (POLLIN | POLLRDNORM))
487 		if ((tp->t_state & TS_ISOPEN) &&
488 		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
489 		     ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
490 		     ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
491 			revents |= ap->a_events & (POLLIN | POLLRDNORM);
492 
493 	if (ap->a_events & (POLLOUT | POLLWRNORM))
494 		if (tp->t_state & TS_ISOPEN &&
495 		    ((pti->pt_flags & PF_REMOTE) ?
496 		     (tp->t_canq.c_cc == 0) :
497 		     ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
498 		      (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
499 			revents |= ap->a_events & (POLLOUT | POLLWRNORM);
500 
501 	if (ap->a_events & POLLHUP)
502 		if ((tp->t_state & TS_CARR_ON) == 0)
503 			revents |= POLLHUP;
504 
505 	if (revents == 0) {
506 		if (ap->a_events & (POLLIN | POLLRDNORM))
507 			selrecord(curthread, &pti->pt_selr);
508 
509 		if (ap->a_events & (POLLOUT | POLLWRNORM))
510 			selrecord(curthread, &pti->pt_selw);
511 	}
512 	crit_exit();
513 
514 	ap->a_events = revents;
515 	return (0);
516 }
517 
518 static	int
519 ptcwrite(struct dev_write_args *ap)
520 {
521 	cdev_t dev = ap->a_head.a_dev;
522 	struct tty *tp = dev->si_tty;
523 	u_char *cp = 0;
524 	int cc = 0;
525 	u_char locbuf[BUFSIZ];
526 	int cnt = 0;
527 	struct pt_ioctl *pti = dev->si_drv1;
528 	int error = 0;
529 
530 again:
531 	if ((tp->t_state&TS_ISOPEN) == 0)
532 		goto block;
533 	if (pti->pt_flags & PF_REMOTE) {
534 		if (tp->t_canq.c_cc)
535 			goto block;
536 		while ((ap->a_uio->uio_resid > 0 || cc > 0) &&
537 		       tp->t_canq.c_cc < TTYHOG - 1) {
538 			if (cc == 0) {
539 				cc = min(ap->a_uio->uio_resid, BUFSIZ);
540 				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
541 				cp = locbuf;
542 				error = uiomove((caddr_t)cp, cc, ap->a_uio);
543 				if (error)
544 					return (error);
545 				/* check again for safety */
546 				if ((tp->t_state & TS_ISOPEN) == 0) {
547 					/* adjust as usual */
548 					ap->a_uio->uio_resid += cc;
549 					return (EIO);
550 				}
551 			}
552 			if (cc > 0) {
553 				cc = b_to_q((char *)cp, cc, &tp->t_canq);
554 				/*
555 				 * XXX we don't guarantee that the canq size
556 				 * is >= TTYHOG, so the above b_to_q() may
557 				 * leave some bytes uncopied.  However, space
558 				 * is guaranteed for the null terminator if
559 				 * we don't fail here since (TTYHOG - 1) is
560 				 * not a multiple of CBSIZE.
561 				 */
562 				if (cc > 0)
563 					break;
564 			}
565 		}
566 		/* adjust for data copied in but not written */
567 		ap->a_uio->uio_resid += cc;
568 		clist_putc(0, &tp->t_canq);
569 		ttwakeup(tp);
570 		wakeup(TSA_PTS_READ(tp));
571 		return (0);
572 	}
573 	while (ap->a_uio->uio_resid > 0 || cc > 0) {
574 		if (cc == 0) {
575 			cc = min(ap->a_uio->uio_resid, BUFSIZ);
576 			cp = locbuf;
577 			error = uiomove((caddr_t)cp, cc, ap->a_uio);
578 			if (error)
579 				return (error);
580 			/* check again for safety */
581 			if ((tp->t_state & TS_ISOPEN) == 0) {
582 				/* adjust for data copied in but not written */
583 				ap->a_uio->uio_resid += cc;
584 				return (EIO);
585 			}
586 		}
587 		while (cc > 0) {
588 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
589 			   (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
590 				wakeup(TSA_HUP_OR_INPUT(tp));
591 				goto block;
592 			}
593 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
594 			cnt++;
595 			cc--;
596 		}
597 		cc = 0;
598 	}
599 	return (0);
600 block:
601 	/*
602 	 * Come here to wait for slave to open, for space
603 	 * in outq, or space in rawq, or an empty canq.
604 	 */
605 	if ((tp->t_state & TS_CONNECTED) == 0) {
606 		/* adjust for data copied in but not written */
607 		ap->a_uio->uio_resid += cc;
608 		return (EIO);
609 	}
610 	if (ap->a_ioflag & IO_NDELAY) {
611 		/* adjust for data copied in but not written */
612 		ap->a_uio->uio_resid += cc;
613 		if (cnt == 0)
614 			return (EWOULDBLOCK);
615 		return (0);
616 	}
617 	error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0);
618 	if (error) {
619 		/* adjust for data copied in but not written */
620 		ap->a_uio->uio_resid += cc;
621 		return (error);
622 	}
623 	goto again;
624 }
625 
626 /*ARGSUSED*/
627 static	int
628 ptyioctl(struct dev_ioctl_args *ap)
629 {
630 	cdev_t dev = ap->a_head.a_dev;
631 	struct tty *tp = dev->si_tty;
632 	struct pt_ioctl *pti = dev->si_drv1;
633 	u_char *cc = tp->t_cc;
634 	int stop, error;
635 
636 	if (dev_dflags(dev) & D_MASTER) {
637 		switch (ap->a_cmd) {
638 
639 		case TIOCGPGRP:
640 			/*
641 			 * We avoid calling ttioctl on the controller since,
642 			 * in that case, tp must be the controlling terminal.
643 			 */
644 			*(int *)ap->a_data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
645 			return (0);
646 
647 		case TIOCPKT:
648 			if (*(int *)ap->a_data) {
649 				if (pti->pt_flags & PF_UCNTL)
650 					return (EINVAL);
651 				pti->pt_flags |= PF_PKT;
652 			} else
653 				pti->pt_flags &= ~PF_PKT;
654 			return (0);
655 
656 		case TIOCUCNTL:
657 			if (*(int *)ap->a_data) {
658 				if (pti->pt_flags & PF_PKT)
659 					return (EINVAL);
660 				pti->pt_flags |= PF_UCNTL;
661 			} else
662 				pti->pt_flags &= ~PF_UCNTL;
663 			return (0);
664 
665 		case TIOCREMOTE:
666 			if (*(int *)ap->a_data)
667 				pti->pt_flags |= PF_REMOTE;
668 			else
669 				pti->pt_flags &= ~PF_REMOTE;
670 			ttyflush(tp, FREAD|FWRITE);
671 			return (0);
672 		}
673 
674 		/*
675 		 * The rest of the ioctls shouldn't be called until
676 		 * the slave is open.
677 		 */
678 		if ((tp->t_state & TS_ISOPEN) == 0)
679 			return (EAGAIN);
680 
681 		switch (ap->a_cmd) {
682 #ifdef COMPAT_43
683 		case TIOCSETP:
684 		case TIOCSETN:
685 #endif
686 		case TIOCSETD:
687 		case TIOCSETA:
688 		case TIOCSETAW:
689 		case TIOCSETAF:
690 			/*
691 			 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
692 			 * ttywflush(tp) will hang if there are characters in
693 			 * the outq.
694 			 */
695 			ndflush(&tp->t_outq, tp->t_outq.c_cc);
696 			break;
697 
698 		case TIOCSIG:
699 			if (*(unsigned int *)ap->a_data >= NSIG ||
700 			    *(unsigned int *)ap->a_data == 0)
701 				return(EINVAL);
702 			if ((tp->t_lflag&NOFLSH) == 0)
703 				ttyflush(tp, FREAD|FWRITE);
704 			pgsignal(tp->t_pgrp, *(unsigned int *)ap->a_data, 1);
705 			if ((*(unsigned int *)ap->a_data == SIGINFO) &&
706 			    ((tp->t_lflag&NOKERNINFO) == 0))
707 				ttyinfo(tp);
708 			return(0);
709 		}
710 	}
711 	if (ap->a_cmd == TIOCEXT) {
712 		/*
713 		 * When the EXTPROC bit is being toggled, we need
714 		 * to send an TIOCPKT_IOCTL if the packet driver
715 		 * is turned on.
716 		 */
717 		if (*(int *)ap->a_data) {
718 			if (pti->pt_flags & PF_PKT) {
719 				pti->pt_send |= TIOCPKT_IOCTL;
720 				ptcwakeup(tp, FREAD);
721 			}
722 			tp->t_lflag |= EXTPROC;
723 		} else {
724 			if ((tp->t_lflag & EXTPROC) &&
725 			    (pti->pt_flags & PF_PKT)) {
726 				pti->pt_send |= TIOCPKT_IOCTL;
727 				ptcwakeup(tp, FREAD);
728 			}
729 			tp->t_lflag &= ~EXTPROC;
730 		}
731 		return(0);
732 	}
733 	error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
734 					      ap->a_fflag, ap->a_cred);
735 	if (error == ENOIOCTL)
736 		 error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
737 	if (error == ENOIOCTL) {
738 		if (pti->pt_flags & PF_UCNTL &&
739 		    (ap->a_cmd & ~0xff) == UIOCCMD(0)) {
740 			if (ap->a_cmd & 0xff) {
741 				pti->pt_ucntl = (u_char)ap->a_cmd;
742 				ptcwakeup(tp, FREAD);
743 			}
744 			return (0);
745 		}
746 		error = ENOTTY;
747 	}
748 	/*
749 	 * If external processing and packet mode send ioctl packet.
750 	 */
751 	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
752 		switch(ap->a_cmd) {
753 		case TIOCSETA:
754 		case TIOCSETAW:
755 		case TIOCSETAF:
756 #ifdef COMPAT_43
757 		case TIOCSETP:
758 		case TIOCSETN:
759 #endif
760 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
761 		case TIOCSETC:
762 		case TIOCSLTC:
763 		case TIOCLBIS:
764 		case TIOCLBIC:
765 		case TIOCLSET:
766 #endif
767 			pti->pt_send |= TIOCPKT_IOCTL;
768 			ptcwakeup(tp, FREAD);
769 		default:
770 			break;
771 		}
772 	}
773 	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
774 		&& CCEQ(cc[VSTART], CTRL('q'));
775 	if (pti->pt_flags & PF_NOSTOP) {
776 		if (stop) {
777 			pti->pt_send &= ~TIOCPKT_NOSTOP;
778 			pti->pt_send |= TIOCPKT_DOSTOP;
779 			pti->pt_flags &= ~PF_NOSTOP;
780 			ptcwakeup(tp, FREAD);
781 		}
782 	} else {
783 		if (!stop) {
784 			pti->pt_send &= ~TIOCPKT_DOSTOP;
785 			pti->pt_send |= TIOCPKT_NOSTOP;
786 			pti->pt_flags |= PF_NOSTOP;
787 			ptcwakeup(tp, FREAD);
788 		}
789 	}
790 	return (error);
791 }
792 
793 
794 static void ptc_drvinit (void *unused);
795 
796 static void
797 ptc_drvinit(void *unused)
798 {
799 	dev_ops_add(&pts_ops, 0, 0);
800 	dev_ops_add(&ptc_ops, 0, 0);
801 	/* XXX: Gross hack for DEVFS */
802 	/* XXX: DEVFS is no more, should this be removed? */
803 	ptyinit(0);
804 }
805 
806 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
807