pty.c revision 173456
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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	@(#)tty_pty.c	8.4 (Berkeley) 2/20/95
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/kern/tty_pty.c 173456 2007-11-08 15:51:52Z jhb $");
34
35/*
36 * Pseudo-teletype Driver
37 * (Actually two drivers, requiring two entries in 'cdevsw')
38 */
39#include "opt_compat.h"
40#include "opt_tty.h"
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/libkern.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/sx.h>
47#if defined(COMPAT_43TTY)
48#include <sys/ioctl_compat.h>
49#endif
50#include <sys/priv.h>
51#include <sys/proc.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/uio.h>
58#include <sys/signalvar.h>
59#include <sys/malloc.h>
60
61static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
62
63static void ptsstart(struct tty *tp);
64static void ptsstop(struct tty *tp, int rw);
65static void ptcwakeup(struct tty *tp, int flag);
66static struct cdev *ptyinit(struct cdev *cdev, struct thread *td);
67
68static	d_open_t	ptsopen;
69static	d_close_t	ptsclose;
70static	d_read_t	ptsread;
71static	d_write_t	ptswrite;
72static	d_ioctl_t	ptsioctl;
73static	d_open_t	ptcopen;
74static	d_close_t	ptcclose;
75static	d_read_t	ptcread;
76static	d_ioctl_t	ptcioctl;
77static	d_write_t	ptcwrite;
78static	d_poll_t	ptcpoll;
79
80static struct cdevsw pts_cdevsw = {
81	.d_version =	D_VERSION,
82	.d_open =	ptsopen,
83	.d_close =	ptsclose,
84	.d_read =	ptsread,
85	.d_write =	ptswrite,
86	.d_ioctl =	ptsioctl,
87	.d_name =	"pts",
88	.d_flags =	D_TTY | D_NEEDGIANT,
89};
90
91static struct cdevsw ptc_cdevsw = {
92	.d_version =	D_VERSION,
93	.d_open =	ptcopen,
94	.d_close =	ptcclose,
95	.d_read =	ptcread,
96	.d_write =	ptcwrite,
97	.d_ioctl =	ptcioctl,
98	.d_poll =	ptcpoll,
99	.d_name =	"ptc",
100	.d_flags =	D_TTY | D_NEEDGIANT,
101};
102
103#define BUFSIZ 100		/* Chunk size iomoved to/from user */
104
105struct	ptsc {
106	int	pt_flags;
107	struct	selinfo pt_selr, pt_selw;
108	u_char	pt_send;
109	u_char	pt_ucntl;
110	struct tty *pt_tty;
111	struct cdev *devs, *devc;
112	int	pt_devs_open, pt_devc_open;
113	struct	prison *pt_prison;
114};
115
116#define	PF_PKT		0x08		/* packet mode */
117#define	PF_STOPPED	0x10		/* user told stopped */
118#define	PF_NOSTOP	0x40
119#define PF_UCNTL	0x80		/* user control mode */
120
121#define	TSA_PTC_READ(tp)	((void *)&(tp)->t_outq.c_cf)
122#define	TSA_PTC_WRITE(tp)	((void *)&(tp)->t_rawq.c_cl)
123#define	TSA_PTS_READ(tp)	((void *)&(tp)->t_canq)
124
125static char *names = "pqrsPQRS";
126/*
127 * This function creates and initializes a pts/ptc pair
128 *
129 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
130 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
131 */
132static struct cdev *
133ptyinit(struct cdev *devc, struct thread *td)
134{
135	struct ptsc *pt;
136	int n;
137
138	n = minor2unit(minor(devc));
139
140	/* We only allow for up to 32 ptys per char in "names". */
141	if (n >= 32 * strlen(names))
142		return (NULL);
143
144	devc->si_flags &= ~SI_CHEAPCLONE;
145
146	/*
147	 * Initially do not create a slave endpoint.
148	 */
149	pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
150	pt->devc = devc;
151
152	pt->pt_tty = ttyalloc();
153	pt->pt_tty->t_sc = pt;
154	devc->si_drv1 = pt;
155	devc->si_tty = pt->pt_tty;
156	return (devc);
157}
158
159static void
160pty_create_slave(struct ucred *cred, struct ptsc *pt, int n)
161{
162
163	pt->devs = make_dev_cred(&pts_cdevsw, n, cred, UID_ROOT, GID_WHEEL,
164	    0666, "tty%c%r", names[n / 32], n % 32);
165	pt->devs->si_drv1 = pt;
166	pt->devs->si_tty = pt->pt_tty;
167	pt->pt_tty->t_dev = pt->devs;
168}
169
170static void
171pty_destroy_slave(struct ptsc *pt)
172{
173
174	if (pt->pt_tty->t_refcnt > 1)
175		return;
176	pt->pt_tty->t_dev = NULL;
177	ttyrel(pt->pt_tty);
178	pt->pt_tty = NULL;
179	destroy_dev(pt->devs);
180	pt->devs = NULL;
181}
182
183static void
184pty_maybe_destroy_slave(struct ptsc *pt)
185{
186
187	/*
188	 * vfs bugs and complications near revoke() make
189	 * it currently impossible to destroy struct cdev
190	 */
191	if (0 && pt->pt_devc_open == 0 && pt->pt_devs_open == 0)
192		pty_destroy_slave(pt);
193}
194
195/*ARGSUSED*/
196static	int
197ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td)
198{
199	struct tty *tp;
200	int error;
201	struct ptsc *pt;
202
203	if (!dev->si_drv1)
204		return(ENXIO);
205	pt = dev->si_drv1;
206	tp = dev->si_tty;
207
208	if ((tp->t_state & TS_ISOPEN) == 0) {
209		ttyinitmode(tp, 1, 0);
210	} else if (tp->t_state & TS_XCLUDE && priv_check(td,
211	    PRIV_TTY_EXCLUSIVE))
212		return (EBUSY);
213	else if (pt->pt_prison != td->td_ucred->cr_prison &&
214	    priv_check(td, PRIV_TTY_PRISON))
215		return (EBUSY);
216	if (tp->t_oproc)			/* Ctrlr still around. */
217		(void)ttyld_modem(tp, 1);
218	while ((tp->t_state & TS_CARR_ON) == 0) {
219		if (flag&FNONBLOCK)
220			break;
221		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
222				 "ptsopn", 0);
223		if (error)
224			return (error);
225	}
226	error = ttyld_open(tp, dev);
227	if (error == 0) {
228		ptcwakeup(tp, FREAD|FWRITE);
229		pt->pt_devs_open = 1;
230	} else
231		pty_maybe_destroy_slave(pt);
232	return (error);
233}
234
235static	int
236ptsclose(struct cdev *dev, int flag, int mode, struct thread *td)
237{
238	struct ptsc *pti;
239	struct tty *tp;
240	int err;
241
242	tp = dev->si_tty;
243	pti = dev->si_drv1;
244
245	KASSERT(dev == pti->devs, ("ptsclose: dev != pti->devs"));
246
247	err = ttyld_close(tp, flag);
248	(void) tty_close(tp);
249
250	pti->pt_devs_open = 0;
251	pty_maybe_destroy_slave(pti);
252
253	return (err);
254}
255
256static	int
257ptsread(struct cdev *dev, struct uio *uio, int flag)
258{
259	struct tty *tp = dev->si_tty;
260	int error = 0;
261
262	if (tp->t_oproc)
263		error = ttyld_read(tp, uio, flag);
264	ptcwakeup(tp, FWRITE);
265	return (error);
266}
267
268/*
269 * Write to pseudo-tty.
270 * Wakeups of controlling tty will happen
271 * indirectly, when tty driver calls ptsstart.
272 */
273static	int
274ptswrite(struct cdev *dev, struct uio *uio, int flag)
275{
276	struct tty *tp;
277
278	tp = dev->si_tty;
279	if (tp->t_oproc == 0)
280		return (EIO);
281	return (ttyld_write(tp, uio, flag));
282}
283
284/*
285 * Start output on pseudo-tty.
286 * Wake up process selecting or sleeping for input from controlling tty.
287 */
288static void
289ptsstart(struct tty *tp)
290{
291	struct ptsc *pt = tp->t_sc;
292
293	if (tp->t_state & TS_TTSTOP)
294		return;
295	if (pt->pt_flags & PF_STOPPED) {
296		pt->pt_flags &= ~PF_STOPPED;
297		pt->pt_send = TIOCPKT_START;
298	}
299	ptcwakeup(tp, FREAD);
300}
301
302static void
303ptcwakeup(struct tty *tp, int flag)
304{
305	struct ptsc *pt = tp->t_sc;
306
307	if (flag & FREAD) {
308		selwakeuppri(&pt->pt_selr, TTIPRI);
309		wakeup(TSA_PTC_READ(tp));
310	}
311	if (flag & FWRITE) {
312		selwakeuppri(&pt->pt_selw, TTOPRI);
313		wakeup(TSA_PTC_WRITE(tp));
314	}
315}
316
317static	int
318ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td)
319{
320	struct tty *tp;
321	struct ptsc *pt;
322
323	if (!dev->si_drv1)
324		ptyinit(dev, td);
325	if (!dev->si_drv1)
326		return(ENXIO);
327
328	pt = dev->si_drv1;
329	/*
330	 * In case we have destroyed the struct tty at the last connect time,
331	 * we need to recreate it.
332	 */
333	if (pt->pt_tty == NULL) {
334		pt->pt_tty = ttyalloc();
335		pt->pt_tty->t_sc = pt;
336		dev->si_tty = pt->pt_tty;
337	}
338	tp = dev->si_tty;
339
340	if (tp->t_oproc)
341		return (EIO);
342	tp->t_timeout = -1;
343	tp->t_oproc = ptsstart;
344	tp->t_stop = ptsstop;
345	(void)ttyld_modem(tp, 1);
346	tp->t_lflag &= ~EXTPROC;
347	pt->pt_prison = td->td_ucred->cr_prison;
348	pt->pt_flags = 0;
349	pt->pt_send = 0;
350	pt->pt_ucntl = 0;
351
352	if (!pt->devs)
353		pty_create_slave(td->td_ucred, pt, minor(dev));
354	pt->pt_devc_open = 1;
355
356	return (0);
357}
358
359static	int
360ptcclose(struct cdev *dev, int flags, int fmt, struct thread *td)
361{
362	struct ptsc *pti = dev->si_drv1;
363	struct tty *tp;
364
365	tp = dev->si_tty;
366	(void)ttyld_modem(tp, 0);
367
368	/*
369	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
370	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
371	 * l_modem()s that ignore carrier drop make no sense for ptys but
372	 * may be in use because other parts of the line discipline make
373	 * sense for ptys.  Recover by doing everything that a normal
374	 * ttymodem() would have done except for sending a SIGHUP.
375	 */
376	if (tp->t_state & TS_ISOPEN) {
377		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
378		tp->t_state |= TS_ZOMBIE;
379		ttyflush(tp, FREAD | FWRITE);
380	}
381
382	tp->t_oproc = 0;		/* mark closed */
383	pti->pt_devc_open = 0;
384	pty_maybe_destroy_slave(pti);
385	return (0);
386}
387
388static	int
389ptcread(struct cdev *dev, struct uio *uio, int flag)
390{
391	struct tty *tp = dev->si_tty;
392	struct ptsc *pt = dev->si_drv1;
393	char buf[BUFSIZ];
394	int error = 0, cc;
395
396	/*
397	 * We want to block until the slave
398	 * is open, and there's something to read;
399	 * but if we lost the slave or we're NBIO,
400	 * then return the appropriate error instead.
401	 */
402	for (;;) {
403		if (tp->t_state&TS_ISOPEN) {
404			if (pt->pt_flags&PF_PKT && pt->pt_send) {
405				error = ureadc((int)pt->pt_send, uio);
406				if (error)
407					return (error);
408				if (pt->pt_send & TIOCPKT_IOCTL) {
409					cc = min(uio->uio_resid,
410						sizeof(tp->t_termios));
411					uiomove(&tp->t_termios, cc, uio);
412				}
413				pt->pt_send = 0;
414				return (0);
415			}
416			if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) {
417				error = ureadc((int)pt->pt_ucntl, uio);
418				if (error)
419					return (error);
420				pt->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 (flag & O_NONBLOCK)
429			return (EWOULDBLOCK);
430		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
431		if (error)
432			return (error);
433	}
434	if (pt->pt_flags & (PF_PKT|PF_UCNTL))
435		error = ureadc(0, uio);
436	while (uio->uio_resid > 0 && error == 0) {
437		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
438		if (cc <= 0)
439			break;
440		error = uiomove(buf, cc, uio);
441	}
442	ttwwakeup(tp);
443	return (error);
444}
445
446static	void
447ptsstop(struct tty *tp, int flush)
448{
449	struct ptsc *pt = tp->t_sc;
450	int flag;
451
452	/* note: FLUSHREAD and FLUSHWRITE already ok */
453	if (flush == 0) {
454		flush = TIOCPKT_STOP;
455		pt->pt_flags |= PF_STOPPED;
456	} else
457		pt->pt_flags &= ~PF_STOPPED;
458	pt->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
468static	int
469ptcpoll(struct cdev *dev, int events, struct thread *td)
470{
471	struct tty *tp = dev->si_tty;
472	struct ptsc *pt = dev->si_drv1;
473	int revents = 0;
474	int s;
475
476	if ((tp->t_state & TS_CONNECTED) == 0)
477		return (events &
478		   (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
479
480	/*
481	 * Need to block timeouts (ttrstart).
482	 */
483	s = spltty();
484
485	if (events & (POLLIN | POLLRDNORM))
486		if ((tp->t_state & TS_ISOPEN) &&
487		    ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
488		     ((pt->pt_flags & PF_PKT) && pt->pt_send) ||
489		     ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl)))
490			revents |= events & (POLLIN | POLLRDNORM);
491
492	if (events & (POLLOUT | POLLWRNORM))
493		if (tp->t_state & TS_ISOPEN &&
494		    (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
495		      (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
496			revents |= events & (POLLOUT | POLLWRNORM);
497
498	if (events & POLLHUP)
499		if ((tp->t_state & TS_CARR_ON) == 0)
500			revents |= POLLHUP;
501
502	if (revents == 0) {
503		if (events & (POLLIN | POLLRDNORM))
504			selrecord(td, &pt->pt_selr);
505
506		if (events & (POLLOUT | POLLWRNORM))
507			selrecord(td, &pt->pt_selw);
508	}
509	splx(s);
510
511	return (revents);
512}
513
514static	int
515ptcwrite(struct cdev *dev, struct uio *uio, int flag)
516{
517	struct tty *tp = dev->si_tty;
518	u_char *cp = 0;
519	int cc = 0;
520	u_char locbuf[BUFSIZ];
521	int cnt = 0;
522	int error = 0;
523
524again:
525	if ((tp->t_state&TS_ISOPEN) == 0)
526		goto block;
527	while (uio->uio_resid > 0 || cc > 0) {
528		if (cc == 0) {
529			cc = min(uio->uio_resid, BUFSIZ);
530			cp = locbuf;
531			error = uiomove(cp, cc, uio);
532			if (error)
533				return (error);
534			/* check again for safety */
535			if ((tp->t_state & TS_ISOPEN) == 0) {
536				/* adjust for data copied in but not written */
537				uio->uio_resid += cc;
538				return (EIO);
539			}
540		}
541		while (cc > 0) {
542			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
543			   (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
544				wakeup(TSA_HUP_OR_INPUT(tp));
545				goto block;
546			}
547			ttyld_rint(tp, *cp++);
548			cnt++;
549			cc--;
550		}
551		cc = 0;
552	}
553	return (0);
554block:
555	/*
556	 * Come here to wait for slave to open, for space
557	 * in outq, or space in rawq, or an empty canq.
558	 */
559	if ((tp->t_state & TS_CONNECTED) == 0) {
560		/* adjust for data copied in but not written */
561		uio->uio_resid += cc;
562		return (EIO);
563	}
564	if (flag & O_NONBLOCK) {
565		/* adjust for data copied in but not written */
566		uio->uio_resid += cc;
567		if (cnt == 0)
568			return (EWOULDBLOCK);
569		return (0);
570	}
571	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
572	if (error) {
573		/* adjust for data copied in but not written */
574		uio->uio_resid += cc;
575		return (error);
576	}
577	goto again;
578}
579
580/*ARGSUSED*/
581static	int
582ptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
583{
584	struct tty *tp = dev->si_tty;
585	struct ptsc *pt = dev->si_drv1;
586#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
587    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
588	int ival;
589#endif
590
591	switch (cmd) {
592
593	case TIOCGPGRP:
594		/*
595		 * We avoid calling ttioctl on the controller since,
596		 * in that case, tp must be the controlling terminal.
597		 */
598		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
599		return (0);
600
601	case TIOCPKT:
602		if (*(int *)data) {
603			if (pt->pt_flags & PF_UCNTL)
604				return (EINVAL);
605			pt->pt_flags |= PF_PKT;
606		} else
607			pt->pt_flags &= ~PF_PKT;
608		return (0);
609
610	case TIOCUCNTL:
611		if (*(int *)data) {
612			if (pt->pt_flags & PF_PKT)
613				return (EINVAL);
614			pt->pt_flags |= PF_UCNTL;
615		} else
616			pt->pt_flags &= ~PF_UCNTL;
617		return (0);
618	}
619
620	/*
621	 * The rest of the ioctls shouldn't be called until
622	 * the slave is open.
623	 */
624	if ((tp->t_state & TS_ISOPEN) == 0)
625		return (EAGAIN);
626
627	switch (cmd) {
628#ifdef COMPAT_43TTY
629	case TIOCSETP:
630	case TIOCSETN:
631#endif
632	case TIOCSETD:
633	case TIOCSETA:
634	case TIOCSETAW:
635	case TIOCSETAF:
636		/*
637		 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
638		 * ttywflush(tp) will hang if there are characters in
639		 * the outq.
640		 */
641		ndflush(&tp->t_outq, tp->t_outq.c_cc);
642		break;
643
644#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
645    defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
646	case _IO('t', 95):
647		ival = IOCPARM_IVAL(data);
648		data = (caddr_t)&ival;
649		/* FALLTHROUGH */
650#endif
651	case TIOCSIG:
652		if (*(unsigned int *)data >= NSIG ||
653		    *(unsigned int *)data == 0)
654			return(EINVAL);
655		if ((tp->t_lflag&NOFLSH) == 0)
656			ttyflush(tp, FREAD|FWRITE);
657		if (tp->t_pgrp != NULL) {
658			PGRP_LOCK(tp->t_pgrp);
659			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
660			PGRP_UNLOCK(tp->t_pgrp);
661		}
662		if ((*(unsigned int *)data == SIGINFO) &&
663		    ((tp->t_lflag&NOKERNINFO) == 0))
664			ttyinfo(tp);
665		return(0);
666	}
667
668	return (ptsioctl(dev, cmd, data, flag, td));
669}
670
671/*ARGSUSED*/
672static	int
673ptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
674{
675	struct tty *tp = dev->si_tty;
676	struct ptsc *pt = dev->si_drv1;
677	u_char *cc = tp->t_cc;
678	int stop, error;
679
680	if (cmd == TIOCEXT) {
681		/*
682		 * When the EXTPROC bit is being toggled, we need
683		 * to send an TIOCPKT_IOCTL if the packet driver
684		 * is turned on.
685		 */
686		if (*(int *)data) {
687			if (pt->pt_flags & PF_PKT) {
688				pt->pt_send |= TIOCPKT_IOCTL;
689				ptcwakeup(tp, FREAD);
690			}
691			tp->t_lflag |= EXTPROC;
692		} else {
693			if ((tp->t_lflag & EXTPROC) &&
694			    (pt->pt_flags & PF_PKT)) {
695				pt->pt_send |= TIOCPKT_IOCTL;
696				ptcwakeup(tp, FREAD);
697			}
698			tp->t_lflag &= ~EXTPROC;
699		}
700		return(0);
701	}
702	error = ttyioctl(dev, cmd, data, flag, td);
703	if (error == ENOTTY) {
704		if (pt->pt_flags & PF_UCNTL &&
705		    (cmd & ~0xff) == UIOCCMD(0)) {
706			if (cmd & 0xff) {
707				pt->pt_ucntl = (u_char)cmd;
708				ptcwakeup(tp, FREAD);
709			}
710			return (0);
711		}
712		error = ENOTTY;
713	}
714	/*
715	 * If external processing and packet mode send ioctl packet.
716	 */
717	if ((tp->t_lflag&EXTPROC) && (pt->pt_flags & PF_PKT)) {
718		switch(cmd) {
719		case TIOCSETA:
720		case TIOCSETAW:
721		case TIOCSETAF:
722#ifdef COMPAT_43TTY
723		case TIOCSETP:
724		case TIOCSETN:
725		case TIOCSETC:
726		case TIOCSLTC:
727		case TIOCLBIS:
728		case TIOCLBIC:
729		case TIOCLSET:
730#endif
731			pt->pt_send |= TIOCPKT_IOCTL;
732			ptcwakeup(tp, FREAD);
733			break;
734		default:
735			break;
736		}
737	}
738	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
739		&& CCEQ(cc[VSTART], CTRL('q'));
740	if (pt->pt_flags & PF_NOSTOP) {
741		if (stop) {
742			pt->pt_send &= ~TIOCPKT_NOSTOP;
743			pt->pt_send |= TIOCPKT_DOSTOP;
744			pt->pt_flags &= ~PF_NOSTOP;
745			ptcwakeup(tp, FREAD);
746		}
747	} else {
748		if (!stop) {
749			pt->pt_send &= ~TIOCPKT_DOSTOP;
750			pt->pt_send |= TIOCPKT_NOSTOP;
751			pt->pt_flags |= PF_NOSTOP;
752			ptcwakeup(tp, FREAD);
753		}
754	}
755	return (error);
756}
757
758static void
759pty_clone(void *arg, struct ucred *cr, char *name, int namelen,
760    struct cdev **dev)
761{
762	char *cp;
763	int u;
764
765	if (*dev != NULL)
766		return;
767	if (bcmp(name, "pty", 3) != 0)
768		return;
769	if (name[5] != '\0' || name[3] == '\0')
770		return;
771	cp = index(names, name[3]);
772	if (cp == NULL)
773		return;
774	u = (cp - names) * 32;
775	if (name[4] >= '0' && name[4] <= '9')
776		u += name[4] - '0';
777	else if (name[4] >= 'a' && name[4] <= 'v')
778		u += name[4] - 'a' + 10;
779	else
780		return;
781	*dev = make_dev_credf(MAKEDEV_REF, &ptc_cdevsw, unit2minor(u), cr,
782	    UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32);
783	(*dev)->si_flags |= SI_CHEAPCLONE;
784	return;
785}
786
787static void
788ptc_drvinit(void *unused)
789{
790
791	EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000);
792}
793
794SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL)
795