pty.c revision 11789
1258945Sroberto/*
2258945Sroberto * Copyright (c) 1982, 1986, 1989, 1993
3258945Sroberto *	The Regents of the University of California.  All rights reserved.
4258945Sroberto *
5258945Sroberto * Redistribution and use in source and binary forms, with or without
6258945Sroberto * modification, are permitted provided that the following conditions
7258945Sroberto * are met:
8258945Sroberto * 1. Redistributions of source code must retain the above copyright
9258945Sroberto *    notice, this list of conditions and the following disclaimer.
10258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright
11258945Sroberto *    notice, this list of conditions and the following disclaimer in the
12258945Sroberto *    documentation and/or other materials provided with the distribution.
13258945Sroberto * 3. All advertising materials mentioning features or use of this software
14258945Sroberto *    must display the following acknowledgement:
15258945Sroberto *	This product includes software developed by the University of
16258945Sroberto *	California, Berkeley and its contributors.
17258945Sroberto * 4. Neither the name of the University nor the names of its contributors
18258945Sroberto *    may be used to endorse or promote products derived from this software
19258945Sroberto *    without specific prior written permission.
20258945Sroberto *
21258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24258945Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31258945Sroberto * SUCH DAMAGE.
32258945Sroberto *
33258945Sroberto *	@(#)tty_pty.c	8.2 (Berkeley) 9/23/93
34258945Sroberto * $Id: tty_pty.c,v 1.21 1995/09/19 12:26:47 bde Exp $
35258945Sroberto */
36258945Sroberto
37258945Sroberto/*
38258945Sroberto * Pseudo-teletype Driver
39258945Sroberto * (Actually two drivers, requiring two entries in 'cdevsw')
40258945Sroberto */
41258945Sroberto#include "pty.h"		/* XXX */
42258945Sroberto
43258945Sroberto#include <sys/param.h>
44258945Sroberto#include <sys/systm.h>
45258945Sroberto#include <sys/ioctl.h>
46258945Sroberto#include <sys/proc.h>
47258945Sroberto#include <sys/tty.h>
48258945Sroberto#include <sys/conf.h>
49258945Sroberto#include <sys/file.h>
50258945Sroberto#include <sys/uio.h>
51258945Sroberto#include <sys/kernel.h>
52258945Sroberto#include <sys/vnode.h>
53258945Sroberto#include <sys/signalvar.h>
54258945Sroberto
55258945Srobertovoid ptyattach __P((int n));
56258945Srobertovoid ptsstart __P((struct tty *tp));
57258945Srobertovoid ptcwakeup __P((struct tty *tp, int flag));
58258945Sroberto
59258945Sroberto#if NPTY == 1
60258945Sroberto#undef NPTY
61258945Sroberto#define	NPTY	32		/* crude XXX */
62258945Sroberto#endif
63258945Sroberto
64258945Sroberto#define BUFSIZ 100		/* Chunk size iomoved to/from user */
65258945Sroberto
66258945Sroberto/*
67258945Sroberto * pts == /dev/tty[pqrs]?
68258945Sroberto * ptc == /dev/pty[pqrs]?
69258945Sroberto */
70258945Srobertostruct	tty pt_tty[NPTY];	/* XXX */
71258945Srobertostruct	pt_ioctl {
72258945Sroberto	int	pt_flags;
73258945Sroberto	struct	selinfo pt_selr, pt_selw;
74258945Sroberto	u_char	pt_send;
75258945Sroberto	u_char	pt_ucntl;
76258945Sroberto} pt_ioctl[NPTY];		/* XXX */
77258945Srobertoint	npty = NPTY;		/* for pstat -t */
78258945Sroberto
79258945Sroberto#define	PF_PKT		0x08		/* packet mode */
80258945Sroberto#define	PF_STOPPED	0x10		/* user told stopped */
81258945Sroberto#define	PF_REMOTE	0x20		/* remote and flow controlled input */
82258945Sroberto#define	PF_NOSTOP	0x40
83258945Sroberto#define PF_UCNTL	0x80		/* user control mode */
84258945Sroberto
85258945Srobertovoid	ptsstop		__P((struct tty *, int));
86258945Srobertovoid	ptcwakeup	__P((struct tty *, int));
87258945Sroberto
88258945Sroberto/*
89258945Sroberto * Establish n (or default if n is 1) ptys in the system.
90258945Sroberto *
91258945Sroberto * XXX cdevsw & pstat require the array `pty[]' to be an array
92258945Sroberto */
93258945Srobertovoid
94258945Srobertoptyattach(n)
95258945Sroberto	int n;
96258945Sroberto{
97258945Sroberto#ifdef notyet
98258945Sroberto	char *mem;
99258945Sroberto	register u_long ntb;
100258945Sroberto#define	DEFAULT_NPTY	32
101258945Sroberto
102258945Sroberto	/* maybe should allow 0 => none? */
103258945Sroberto	if (n <= 1)
104258945Sroberto		n = DEFAULT_NPTY;
105258945Sroberto	ntb = n * sizeof(struct tty);
106258945Sroberto	mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
107258945Sroberto	    M_DEVBUF, M_WAITOK);
108258945Sroberto	pt_tty = (struct tty *)mem;
109258945Sroberto	mem = (char *)ALIGN(mem + ntb);
110258945Sroberto	pt_ioctl = (struct pt_ioctl *)mem;
111258945Sroberto	npty = n;
112258945Sroberto#endif
113258945Sroberto}
114258945Sroberto
115258945Sroberto/*ARGSUSED*/
116258945Srobertoint
117258945Srobertoptsopen(dev, flag, devtype, p)
118258945Sroberto	dev_t dev;
119258945Sroberto	int flag, devtype;
120258945Sroberto	struct proc *p;
121258945Sroberto{
122258945Sroberto	register struct tty *tp;
123258945Sroberto	int error;
124258945Sroberto
125258945Sroberto	if (minor(dev) >= npty)
126258945Sroberto		return (ENXIO);
127258945Sroberto	tp = &pt_tty[minor(dev)];
128258945Sroberto	if ((tp->t_state & TS_ISOPEN) == 0) {
129258945Sroberto		ttychars(tp);		/* Set up default chars */
130258945Sroberto		tp->t_iflag = TTYDEF_IFLAG;
131258945Sroberto		tp->t_oflag = TTYDEF_OFLAG;
132258945Sroberto		tp->t_lflag = TTYDEF_LFLAG;
133258945Sroberto		tp->t_cflag = TTYDEF_CFLAG;
134258945Sroberto		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
135258945Sroberto		ttsetwater(tp);		/* would be done in xxparam() */
136258945Sroberto	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
137258945Sroberto		return (EBUSY);
138258945Sroberto	if (tp->t_oproc)			/* Ctrlr still around. */
139258945Sroberto		(void)(*linesw[tp->t_line].l_modem)(tp, 1);
140258945Sroberto	while ((tp->t_state & TS_CARR_ON) == 0) {
141258945Sroberto		if (flag&FNONBLOCK)
142258945Sroberto			break;
143258945Sroberto		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
144258945Sroberto				 "ptsopn", 0);
145258945Sroberto		if (error)
146258945Sroberto			return (error);
147258945Sroberto	}
148258945Sroberto	error = (*linesw[tp->t_line].l_open)(dev, tp);
149258945Sroberto	if (error == 0)
150258945Sroberto		ptcwakeup(tp, FREAD|FWRITE);
151258945Sroberto	return (error);
152258945Sroberto}
153258945Sroberto
154258945Srobertoint
155258945Srobertoptsclose(dev, flag, mode, p)
156258945Sroberto	dev_t dev;
157258945Sroberto	int flag, mode;
158258945Sroberto	struct proc *p;
159258945Sroberto{
160258945Sroberto	register struct tty *tp;
161258945Sroberto	int err;
162258945Sroberto
163258945Sroberto	tp = &pt_tty[minor(dev)];
164258945Sroberto	err = (*linesw[tp->t_line].l_close)(tp, flag);
165258945Sroberto	ptsstop(tp, FREAD|FWRITE);
166258945Sroberto	(void) ttyclose(tp);
167258945Sroberto	return (err);
168258945Sroberto}
169258945Sroberto
170258945Srobertoint
171258945Srobertoptsread(dev, uio, flag)
172258945Sroberto	dev_t dev;
173258945Sroberto	struct uio *uio;
174258945Sroberto	int flag;
175258945Sroberto{
176258945Sroberto	struct proc *p = curproc;
177258945Sroberto	register struct tty *tp = &pt_tty[minor(dev)];
178258945Sroberto	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
179258945Sroberto	int error = 0;
180258945Sroberto
181258945Srobertoagain:
182258945Sroberto	if (pti->pt_flags & PF_REMOTE) {
183258945Sroberto		while (isbackground(p, tp)) {
184258945Sroberto			if ((p->p_sigignore & sigmask(SIGTTIN)) ||
185258945Sroberto			    (p->p_sigmask & sigmask(SIGTTIN)) ||
186258945Sroberto			    p->p_pgrp->pg_jobc == 0 ||
187258945Sroberto			    p->p_flag & P_PPWAIT)
188258945Sroberto				return (EIO);
189258945Sroberto			pgsignal(p->p_pgrp, SIGTTIN, 1);
190258945Sroberto			error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ptsbg",
191258945Sroberto					 0);
192258945Sroberto			if (error)
193258945Sroberto				return (error);
194258945Sroberto		}
195258945Sroberto		if (tp->t_canq.c_cc == 0) {
196258945Sroberto			if (flag & IO_NDELAY)
197258945Sroberto				return (EWOULDBLOCK);
198258945Sroberto			error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
199258945Sroberto					 "ptsin", 0);
200258945Sroberto			if (error)
201258945Sroberto				return (error);
202258945Sroberto			goto again;
203258945Sroberto		}
204258945Sroberto		while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
205258945Sroberto			if (ureadc(getc(&tp->t_canq), uio) < 0) {
206258945Sroberto				error = EFAULT;
207258945Sroberto				break;
208258945Sroberto			}
209258945Sroberto		if (tp->t_canq.c_cc == 1)
210258945Sroberto			(void) getc(&tp->t_canq);
211258945Sroberto		if (tp->t_canq.c_cc)
212258945Sroberto			return (error);
213258945Sroberto	} else
214258945Sroberto		if (tp->t_oproc)
215258945Sroberto			error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
216258945Sroberto	ptcwakeup(tp, FWRITE);
217258945Sroberto	return (error);
218258945Sroberto}
219258945Sroberto
220258945Sroberto/*
221258945Sroberto * Write to pseudo-tty.
222258945Sroberto * Wakeups of controlling tty will happen
223258945Sroberto * indirectly, when tty driver calls ptsstart.
224258945Sroberto */
225258945Srobertoint
226258945Srobertoptswrite(dev, uio, flag)
227258945Sroberto	dev_t dev;
228258945Sroberto	struct uio *uio;
229258945Sroberto	int flag;
230258945Sroberto{
231258945Sroberto	register struct tty *tp;
232258945Sroberto
233258945Sroberto	tp = &pt_tty[minor(dev)];
234258945Sroberto	if (tp->t_oproc == 0)
235258945Sroberto		return (EIO);
236258945Sroberto	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
237258945Sroberto}
238258945Sroberto
239258945Sroberto/*
240258945Sroberto * Start output on pseudo-tty.
241258945Sroberto * Wake up process selecting or sleeping for input from controlling tty.
242258945Sroberto */
243258945Srobertovoid
244258945Srobertoptsstart(tp)
245258945Sroberto	struct tty *tp;
246258945Sroberto{
247258945Sroberto	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
248258945Sroberto
249258945Sroberto	if (tp->t_state & TS_TTSTOP)
250258945Sroberto		return;
251258945Sroberto	if (pti->pt_flags & PF_STOPPED) {
252258945Sroberto		pti->pt_flags &= ~PF_STOPPED;
253258945Sroberto		pti->pt_send = TIOCPKT_START;
254258945Sroberto	}
255258945Sroberto	ptcwakeup(tp, FREAD);
256258945Sroberto}
257258945Sroberto
258258945Srobertovoid
259ptcwakeup(tp, flag)
260	struct tty *tp;
261	int flag;
262{
263	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
264
265	if (flag & FREAD) {
266		selwakeup(&pti->pt_selr);
267		wakeup(TSA_PTC_READ(tp));
268	}
269	if (flag & FWRITE) {
270		selwakeup(&pti->pt_selw);
271		wakeup(TSA_PTC_WRITE(tp));
272	}
273}
274
275int
276ptcopen(dev, flag, devtype, p)
277	dev_t dev;
278	int flag, devtype;
279	struct proc *p;
280{
281	register struct tty *tp;
282	struct pt_ioctl *pti;
283
284	if (minor(dev) >= npty)
285		return (ENXIO);
286	tp = &pt_tty[minor(dev)];
287	if (tp->t_oproc)
288		return (EIO);
289	tp->t_oproc = ptsstart;
290#ifdef sun4c
291	tp->t_stop = ptsstop;
292#endif
293	(void)(*linesw[tp->t_line].l_modem)(tp, 1);
294	tp->t_lflag &= ~EXTPROC;
295	pti = &pt_ioctl[minor(dev)];
296	pti->pt_flags = 0;
297	pti->pt_send = 0;
298	pti->pt_ucntl = 0;
299	return (0);
300}
301
302int
303ptcclose(dev, flags, fmt, p)
304	dev_t dev;
305	int flags;
306	int fmt;
307	struct proc *p;
308{
309	register struct tty *tp;
310
311	tp = &pt_tty[minor(dev)];
312	(void)(*linesw[tp->t_line].l_modem)(tp, 0);
313
314	/*
315	 * XXX MDMBUF makes no sense for ptys but would inhibit the above
316	 * l_modem().  CLOCAL makes sense but isn't supported.   Special
317	 * l_modem()s that ignore carrier drop make no sense for ptys but
318	 * may be in use because other parts of the line discipline make
319	 * sense for ptys.  Recover by doing everything that a normal
320	 * ttymodem() would have done except for sending a SIGHUP.
321	 */
322	if (tp->t_state & TS_ISOPEN) {
323		tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
324		tp->t_state |= TS_ZOMBIE;
325		ttyflush(tp, FREAD | FWRITE);
326	}
327
328	tp->t_oproc = 0;		/* mark closed */
329	return (0);
330}
331
332int
333ptcread(dev, uio, flag)
334	dev_t dev;
335	struct uio *uio;
336	int flag;
337{
338	register struct tty *tp = &pt_tty[minor(dev)];
339	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
340	char buf[BUFSIZ];
341	int error = 0, cc;
342
343	/*
344	 * We want to block until the slave
345	 * is open, and there's something to read;
346	 * but if we lost the slave or we're NBIO,
347	 * then return the appropriate error instead.
348	 */
349	for (;;) {
350		if (tp->t_state&TS_ISOPEN) {
351			if (pti->pt_flags&PF_PKT && pti->pt_send) {
352				error = ureadc((int)pti->pt_send, uio);
353				if (error)
354					return (error);
355				if (pti->pt_send & TIOCPKT_IOCTL) {
356					cc = min(uio->uio_resid,
357						sizeof(tp->t_termios));
358					uiomove((caddr_t)&tp->t_termios, cc,
359						uio);
360				}
361				pti->pt_send = 0;
362				return (0);
363			}
364			if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
365				error = ureadc((int)pti->pt_ucntl, uio);
366				if (error)
367					return (error);
368				pti->pt_ucntl = 0;
369				return (0);
370			}
371			if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
372				break;
373		}
374		if ((tp->t_state & TS_CONNECTED) == 0)
375			return (0);	/* EOF */
376		if (flag & IO_NDELAY)
377			return (EWOULDBLOCK);
378		error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
379		if (error)
380			return (error);
381	}
382	if (pti->pt_flags & (PF_PKT|PF_UCNTL))
383		error = ureadc(0, uio);
384	while (uio->uio_resid > 0 && error == 0) {
385		cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
386		if (cc <= 0)
387			break;
388		error = uiomove(buf, cc, uio);
389	}
390	ttwwakeup(tp);
391	return (error);
392}
393
394void
395ptsstop(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
418int
419ptcselect(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_CONNECTED) == 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
473int
474ptcwrite(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 = 0;
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
487again:
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 || cc > 0) &&
494		       tp->t_canq.c_cc < TTYHOG - 1) {
495			if (cc == 0) {
496				cc = min(uio->uio_resid, BUFSIZ);
497				cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
498				cp = locbuf;
499				error = uiomove((caddr_t)cp, cc, uio);
500				if (error)
501					return (error);
502				/* check again for safety */
503				if ((tp->t_state & TS_ISOPEN) == 0) {
504					/* adjust as usual */
505					uio->uio_resid += cc;
506					return (EIO);
507				}
508			}
509			if (cc)
510				cc -= b_to_q((char *)cp, cc, &tp->t_canq);
511		}
512		/* adjust for data copied in but not written */
513		uio->uio_resid += cc;
514		(void) putc(0, &tp->t_canq);
515		ttwakeup(tp);
516		wakeup(TSA_PTS_READ(tp));
517		return (0);
518	}
519	while (uio->uio_resid > 0 || cc > 0) {
520		if (cc == 0) {
521			cc = min(uio->uio_resid, BUFSIZ);
522			cp = locbuf;
523			error = uiomove((caddr_t)cp, cc, uio);
524			if (error)
525				return (error);
526			/* check again for safety */
527			if ((tp->t_state & TS_ISOPEN) == 0) {
528				/* adjust for data copied in but not written */
529				uio->uio_resid += cc;
530				return (EIO);
531			}
532		}
533		while (cc > 0) {
534			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
535			   (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
536				wakeup(TSA_HUP_OR_INPUT(tp));
537				goto block;
538			}
539			(*linesw[tp->t_line].l_rint)(*cp++, tp);
540			cnt++;
541			cc--;
542		}
543		cc = 0;
544	}
545	return (0);
546block:
547	/*
548	 * Come here to wait for slave to open, for space
549	 * in outq, or space in rawq.
550	 */
551	if ((tp->t_state & TS_CONNECTED) == 0) {
552		/* adjust for data copied in but not written */
553		uio->uio_resid += cc;
554		return (EIO);
555	}
556	if (flag & IO_NDELAY) {
557		/* adjust for data copied in but not written */
558		uio->uio_resid += cc;
559		if (cnt == 0)
560			return (EWOULDBLOCK);
561		return (0);
562	}
563	error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
564	if (error) {
565		/* adjust for data copied in but not written */
566		uio->uio_resid += cc;
567		return (error);
568	}
569	goto again;
570}
571
572struct tty *
573ptydevtotty(dev)
574	dev_t		dev;
575{
576	if (minor(dev) >= npty)
577		return (NULL);
578
579	return &pt_tty[minor(dev)];
580}
581
582/*ARGSUSED*/
583int
584ptyioctl(dev, cmd, data, flag, p)
585	dev_t dev;
586	int cmd;
587	caddr_t data;
588	int flag;
589	struct proc *p;
590{
591	register struct tty *tp = &pt_tty[minor(dev)];
592	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
593	register u_char *cc = tp->t_cc;
594	int stop, error;
595
596	/*
597	 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
598	 * ttywflush(tp) will hang if there are characters in the outq.
599	 */
600	if (cmd == TIOCEXT) {
601		/*
602		 * When the EXTPROC bit is being toggled, we need
603		 * to send an TIOCPKT_IOCTL if the packet driver
604		 * is turned on.
605		 */
606		if (*(int *)data) {
607			if (pti->pt_flags & PF_PKT) {
608				pti->pt_send |= TIOCPKT_IOCTL;
609				ptcwakeup(tp, FREAD);
610			}
611			tp->t_lflag |= EXTPROC;
612		} else {
613			if ((tp->t_state & EXTPROC) &&
614			    (pti->pt_flags & PF_PKT)) {
615				pti->pt_send |= TIOCPKT_IOCTL;
616				ptcwakeup(tp, FREAD);
617			}
618			tp->t_lflag &= ~EXTPROC;
619		}
620		return(0);
621	} else
622	if (cdevsw[major(dev)].d_open == ptcopen)
623		switch (cmd) {
624
625		case TIOCGPGRP:
626			/*
627			 * We aviod calling ttioctl on the controller since,
628			 * in that case, tp must be the controlling terminal.
629			 */
630			*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
631			return (0);
632
633		case TIOCPKT:
634			if (*(int *)data) {
635				if (pti->pt_flags & PF_UCNTL)
636					return (EINVAL);
637				pti->pt_flags |= PF_PKT;
638			} else
639				pti->pt_flags &= ~PF_PKT;
640			return (0);
641
642		case TIOCUCNTL:
643			if (*(int *)data) {
644				if (pti->pt_flags & PF_PKT)
645					return (EINVAL);
646				pti->pt_flags |= PF_UCNTL;
647			} else
648				pti->pt_flags &= ~PF_UCNTL;
649			return (0);
650
651		case TIOCREMOTE:
652			if (*(int *)data)
653				pti->pt_flags |= PF_REMOTE;
654			else
655				pti->pt_flags &= ~PF_REMOTE;
656			ttyflush(tp, FREAD|FWRITE);
657			return (0);
658
659#ifdef COMPAT_43
660		case TIOCSETP:
661		case TIOCSETN:
662#endif
663		case TIOCSETD:
664		case TIOCSETA:
665		case TIOCSETAW:
666		case TIOCSETAF:
667			ndflush(&tp->t_outq, tp->t_outq.c_cc);
668			break;
669
670		case TIOCSIG:
671			if (*(unsigned int *)data >= NSIG)
672				return(EINVAL);
673			if ((tp->t_lflag&NOFLSH) == 0)
674				ttyflush(tp, FREAD|FWRITE);
675			pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
676			if ((*(unsigned int *)data == SIGINFO) &&
677			    ((tp->t_lflag&NOKERNINFO) == 0))
678				ttyinfo(tp);
679			return(0);
680		}
681	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
682	if (error < 0)
683		 error = ttioctl(tp, cmd, data, flag);
684	if (error < 0) {
685		if (pti->pt_flags & PF_UCNTL &&
686		    (cmd & ~0xff) == UIOCCMD(0)) {
687			if (cmd & 0xff) {
688				pti->pt_ucntl = (u_char)cmd;
689				ptcwakeup(tp, FREAD);
690			}
691			return (0);
692		}
693		error = ENOTTY;
694	}
695	/*
696	 * If external processing and packet mode send ioctl packet.
697	 */
698	if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
699		switch(cmd) {
700		case TIOCSETA:
701		case TIOCSETAW:
702		case TIOCSETAF:
703#ifdef COMPAT_43
704		case TIOCSETP:
705		case TIOCSETN:
706#endif
707#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
708		case TIOCSETC:
709		case TIOCSLTC:
710		case TIOCLBIS:
711		case TIOCLBIC:
712		case TIOCLSET:
713#endif
714			pti->pt_send |= TIOCPKT_IOCTL;
715			ptcwakeup(tp, FREAD);
716		default:
717			break;
718		}
719	}
720	stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
721		&& CCEQ(cc[VSTART], CTRL('q'));
722	if (pti->pt_flags & PF_NOSTOP) {
723		if (stop) {
724			pti->pt_send &= ~TIOCPKT_NOSTOP;
725			pti->pt_send |= TIOCPKT_DOSTOP;
726			pti->pt_flags &= ~PF_NOSTOP;
727			ptcwakeup(tp, FREAD);
728		}
729	} else {
730		if (!stop) {
731			pti->pt_send &= ~TIOCPKT_DOSTOP;
732			pti->pt_send |= TIOCPKT_NOSTOP;
733			pti->pt_flags |= PF_NOSTOP;
734			ptcwakeup(tp, FREAD);
735		}
736	}
737	return (error);
738}
739