tty.c revision 116663
1202375Srdivacky/*-
2202375Srdivacky * Copyright (c) 1982, 1986, 1990, 1991, 1993
3202375Srdivacky *	The Regents of the University of California.  All rights reserved.
4202375Srdivacky * (c) UNIX System Laboratories, Inc.
5202375Srdivacky * All or some portions of this file are derived from material licensed
6202375Srdivacky * to the University of California by American Telephone and Telegraph
7202375Srdivacky * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8202375Srdivacky * the permission of UNIX System Laboratories, Inc.
9202375Srdivacky *
10202375Srdivacky * Copyright (c) 2002 Networks Associates Technologies, Inc.
11202375Srdivacky * All rights reserved.
12202375Srdivacky *
13202375Srdivacky * Portions of this software were developed for the FreeBSD Project by
14202375Srdivacky * ThinkSec AS and NAI Labs, the Security Research Division of Network
15288943Sdim * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
16288943Sdim * ("CBOSS"), as part of the DARPA CHATS research program.
17249423Sdim *
18276479Sdim * Redistribution and use in source and binary forms, with or without
19202375Srdivacky * modification, are permitted provided that the following conditions
20202375Srdivacky * are met:
21249423Sdim * 1. Redistributions of source code must retain the above copyright
22202375Srdivacky *    notice, this list of conditions and the following disclaimer.
23276479Sdim * 2. Redistributions in binary form must reproduce the above copyright
24276479Sdim *    notice, this list of conditions and the following disclaimer in the
25249423Sdim *    documentation and/or other materials provided with the distribution.
26202375Srdivacky * 3. All advertising materials mentioning features or use of this software
27202375Srdivacky *    must display the following acknowledgement:
28202375Srdivacky *	This product includes software developed by the University of
29249423Sdim *	California, Berkeley and its contributors.
30202375Srdivacky * 4. Neither the name of the University nor the names of its contributors
31202375Srdivacky *    may be used to endorse or promote products derived from this software
32202375Srdivacky *    without specific prior written permission.
33202375Srdivacky *
34202375Srdivacky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35202375Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36202375Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37202375Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38202375Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39218893Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40202375Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41202375Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42202375Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43202375Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44202375Srdivacky * SUCH DAMAGE.
45202375Srdivacky *
46280031Sdim *	@(#)tty.c	8.8 (Berkeley) 1/21/94
47202375Srdivacky */
48202375Srdivacky
49202375Srdivacky/*-
50202375Srdivacky * TODO:
51202375Srdivacky *	o Fix races for sending the start char in ttyflush().
52202375Srdivacky *	o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
53202375Srdivacky *	  With luck, there will be MIN chars before select() returns().
54202375Srdivacky *	o Handle CLOCAL consistently for ptys.  Perhaps disallow setting it.
55202375Srdivacky *	o Don't allow input in TS_ZOMBIE case.  It would be visible through
56202375Srdivacky *	  FIONREAD.
57202375Srdivacky *	o Do the new sio locking stuff here and use it to avoid special
58202375Srdivacky *	  case for EXTPROC?
59249423Sdim *	o Lock PENDIN too?
60288943Sdim *	o Move EXTPROC and/or PENDIN to t_state?
61288943Sdim *	o Wrap most of ttioctl in spltty/splx.
62276479Sdim *	o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
63202375Srdivacky *	o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
64202375Srdivacky *	o Don't allow certain termios flags to affect disciplines other
65202375Srdivacky *	  than TTYDISC.  Cancel their effects before switch disciplines
66202375Srdivacky *	  and ignore them if they are set while we are in another
67202375Srdivacky *	  discipline.
68202375Srdivacky *	o Now that historical speed conversions are handled here, don't
69202375Srdivacky *	  do them in drivers.
70202375Srdivacky *	o Check for TS_CARR_ON being set while everything is closed and not
71249423Sdim *	  waiting for carrier.  TS_CARR_ON isn't cleared if nothing is open,
72202375Srdivacky *	  so it would live until the next open even if carrier drops.
73202375Srdivacky *	o Restore TS_WOPEN since it is useful in pstat.  It must be cleared
74288943Sdim *	  only when _all_ openers leave open().
75288943Sdim */
76288943Sdim
77276479Sdim#include <sys/cdefs.h>
78202375Srdivacky__FBSDID("$FreeBSD: head/sys/kern/tty.c 116663 2003-06-22 02:54:33Z iedowse $");
79202375Srdivacky
80202375Srdivacky#include "opt_compat.h"
81202375Srdivacky#include "opt_tty.h"
82202375Srdivacky
83202375Srdivacky#include <sys/param.h>
84202375Srdivacky#include <sys/systm.h>
85202375Srdivacky#include <sys/filio.h>
86202375Srdivacky#include <sys/lock.h>
87202375Srdivacky#include <sys/mutex.h>
88202375Srdivacky#include <sys/namei.h>
89202375Srdivacky#include <sys/sx.h>
90202375Srdivacky#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
91202375Srdivacky#include <sys/ioctl_compat.h>
92202375Srdivacky#endif
93249423Sdim#include <sys/proc.h>
94202375Srdivacky#define	TTYDEFCHARS
95202375Srdivacky#include <sys/tty.h>
96202375Srdivacky#undef	TTYDEFCHARS
97202375Srdivacky#include <sys/fcntl.h>
98202375Srdivacky#include <sys/conf.h>
99202375Srdivacky#include <sys/poll.h>
100202375Srdivacky#include <sys/kernel.h>
101202375Srdivacky#include <sys/vnode.h>
102202375Srdivacky#include <sys/signalvar.h>
103202375Srdivacky#include <sys/resourcevar.h>
104202375Srdivacky#include <sys/malloc.h>
105202375Srdivacky#include <sys/filedesc.h>
106280031Sdim#include <sys/sysctl.h>
107280031Sdim
108276479Sdim#include <vm/vm.h>
109202375Srdivacky#include <vm/pmap.h>
110202375Srdivacky#include <vm/vm_map.h>
111226633Sdim
112288943SdimMALLOC_DEFINE(M_TTYS, "ttys", "tty data structures");
113288943Sdim
114288943Sdimlong tk_cancc;
115288943Sdimlong tk_nin;
116288943Sdimlong tk_nout;
117288943Sdimlong tk_rawcc;
118202375Srdivacky
119202375Srdivackystatic int	proc_compare(struct proc *p1, struct proc *p2);
120202375Srdivackystatic int	ttnread(struct tty *tp);
121202375Srdivackystatic void	ttyecho(int c, struct tty *tp);
122276479Sdimstatic int	ttyoutput(int c, struct tty *tp);
123202375Srdivackystatic void	ttypend(struct tty *tp);
124202375Srdivackystatic void	ttyretype(struct tty *tp);
125202375Srdivackystatic void	ttyrub(int c, struct tty *tp);
126218893Sdimstatic void	ttyrubo(struct tty *tp, int cnt);
127202375Srdivackystatic void	ttyunblock(struct tty *tp);
128276479Sdimstatic int	ttywflush(struct tty *tp);
129202375Srdivackystatic int	filt_ttyread(struct knote *kn, long hint);
130202375Srdivackystatic void	filt_ttyrdetach(struct knote *kn);
131218893Sdimstatic int	filt_ttywrite(struct knote *kn, long hint);
132218893Sdimstatic void	filt_ttywdetach(struct knote *kn);
133202375Srdivacky
134202375Srdivacky/*
135276479Sdim * Table with character classes and parity. The 8th bit indicates parity,
136202375Srdivacky * the 7th bit indicates the character is an alphameric or underscore (for
137202375Srdivacky * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
138249423Sdim * are 0 then the character needs no special processing on output; classes
139202375Srdivacky * other than 0 might be translated or (not currently) require delays.
140276479Sdim */
141249423Sdim#define	E	0x00	/* Even parity. */
142202375Srdivacky#define	O	0x80	/* Odd parity. */
143203954Srdivacky#define	PARITY(c)	(char_type[c] & O)
144202375Srdivacky
145202375Srdivacky#define	ALPHA	0x40	/* Alpha or underscore. */
146202375Srdivacky#define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
147280031Sdim
148276479Sdim#define	CCLASSMASK	0x3f
149202375Srdivacky#define	CCLASS(c)	(char_type[c] & CCLASSMASK)
150202375Srdivacky
151202375Srdivacky#define	BS	BACKSPACE
152202375Srdivacky#define	CC	CONTROL
153202375Srdivacky#define	CR	RETURN
154202375Srdivacky#define	NA	ORDINARY | ALPHA
155202375Srdivacky#define	NL	NEWLINE
156202375Srdivacky#define	NO	ORDINARY
157202375Srdivacky#define	TB	TAB
158202375Srdivacky#define	VT	VTAB
159202375Srdivacky
160202375Srdivackystatic u_char const char_type[] = {
161288943Sdim	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
162280031Sdim	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
163288943Sdim	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
164280031Sdim	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
165249423Sdim	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
166202375Srdivacky	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
167202375Srdivacky	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
168202375Srdivacky	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
169249423Sdim	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
170202375Srdivacky	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
171202375Srdivacky	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
172249423Sdim	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
173202375Srdivacky	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
174202375Srdivacky	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
175249423Sdim	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
176202375Srdivacky	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
177202375Srdivacky	/*
178202375Srdivacky	 * Meta chars; should be settable per character set;
179249423Sdim	 * for now, treat them all as normal characters.
180202375Srdivacky	 */
181202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
182202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
183249423Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
184202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
185288943Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
186280031Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
187288943Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
188280031Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
189249423Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
190202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
191202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
192202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
193249423Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
194202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
195202375Srdivacky	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
196249423Sdim	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
197202375Srdivacky};
198202375Srdivacky#undef	BS
199249423Sdim#undef	CC
200202375Srdivacky#undef	CR
201202375Srdivacky#undef	NA
202249423Sdim#undef	NL
203202375Srdivacky#undef	NO
204202375Srdivacky#undef	TB
205249423Sdim#undef	VT
206202375Srdivacky
207202375Srdivacky/* Macros to clear/set/test flags. */
208249423Sdim#define	SET(t, f)	(t) |= (f)
209249423Sdim#define	CLR(t, f)	(t) &= ~(f)
210249423Sdim#define	ISSET(t, f)	((t) & (f))
211249423Sdim
212288943Sdim#undef MAX_INPUT		/* XXX wrong in <sys/syslimits.h> */
213280031Sdim#define	MAX_INPUT	TTYHOG	/* XXX limit is usually larger for !ICANON */
214288943Sdim
215280031Sdim/*
216249423Sdim * list of struct tty where pstat(8) can pick it up with sysctl
217249423Sdim */
218249423Sdimstatic SLIST_HEAD(, tty) tty_list;
219249423Sdim
220249423Sdimstatic int  drainwait = 5*60;
221249423SdimSYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait,
222249423Sdim	0, "Output drain timeout in seconds");
223202375Srdivacky
224249423Sdim/*
225202375Srdivacky * Initial open of tty, or (re)entry to standard tty line discipline.
226280031Sdim */
227276479Sdimint
228202375Srdivackyttyopen(dev_t device, struct tty *tp)
229249423Sdim{
230202375Srdivacky	int s;
231202375Srdivacky
232202375Srdivacky	s = spltty();
233202375Srdivacky	tp->t_dev = device;
234202375Srdivacky	if (!ISSET(tp->t_state, TS_ISOPEN)) {
235202375Srdivacky		SET(tp->t_state, TS_ISOPEN);
236249423Sdim		if (ISSET(tp->t_cflag, CLOCAL))
237202375Srdivacky			SET(tp->t_state, TS_CONNECTED);
238202375Srdivacky		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
239280031Sdim	}
240202375Srdivacky	/* XXX don't hang forever on output */
241202375Srdivacky	if (tp->t_timeout < 0)
242202375Srdivacky		tp->t_timeout = drainwait*hz;
243288943Sdim	ttsetwater(tp);
244288943Sdim	splx(s);
245202375Srdivacky	return (0);
246288943Sdim}
247202375Srdivacky
248249423Sdim/*
249249423Sdim * Handle close() on a tty line: flush and set to initial state,
250202375Srdivacky * bumping generation number so that pending read/write calls
251280031Sdim * can detect recycling of the tty.
252280031Sdim * XXX our caller should have done `spltty(); l_close(); ttyclose();'
253280031Sdim * and l_close() should have flushed, but we repeat the spltty() and
254280031Sdim * the flush in case there are buggy callers.
255280031Sdim */
256280031Sdimint
257202375Srdivackyttyclose(struct tty *tp)
258202375Srdivacky{
259249423Sdim	int s;
260202375Srdivacky
261202375Srdivacky	funsetown(&tp->t_sigio);
262249423Sdim	s = spltty();
263202375Srdivacky	if (constty == tp)
264202375Srdivacky		constty_clear();
265249423Sdim
266202375Srdivacky	ttyflush(tp, FREAD | FWRITE);
267202375Srdivacky	clist_free_cblocks(&tp->t_canq);
268202375Srdivacky	clist_free_cblocks(&tp->t_outq);
269249423Sdim	clist_free_cblocks(&tp->t_rawq);
270202375Srdivacky
271202375Srdivacky	tp->t_gen++;
272202375Srdivacky	tp->t_line = TTYDISC;
273249423Sdim	tp->t_pgrp = NULL;
274202375Srdivacky	tp->t_session = NULL;
275203954Srdivacky	tp->t_state = 0;
276202375Srdivacky	splx(s);
277203954Srdivacky	return (0);
278202375Srdivacky}
279202375Srdivacky
280202375Srdivacky#define	FLUSHQ(q) {							\
281288943Sdim	if ((q)->c_cc)							\
282288943Sdim		ndflush(q, (q)->c_cc);					\
283249423Sdim}
284288943Sdim
285202375Srdivacky/* Is 'c' a line delimiter ("break" character)? */
286249423Sdim#define	TTBREAKC(c, lflag)							\
287249423Sdim	((c) == '\n' || (((c) == cc[VEOF] ||				\
288249423Sdim	  (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) &&	\
289280031Sdim	 (c) != _POSIX_VDISABLE))
290280031Sdim
291280031Sdim/*
292280031Sdim * Process input of a single character received on a tty.
293280031Sdim */
294280031Sdimint
295202375Srdivackyttyinput(int c, struct tty *tp)
296202375Srdivacky{
297249423Sdim	tcflag_t iflag, lflag;
298202375Srdivacky	cc_t *cc;
299202375Srdivacky	int i, err;
300249423Sdim
301202375Srdivacky	/*
302202375Srdivacky	 * If input is pending take it first.
303202375Srdivacky	 */
304202375Srdivacky	lflag = tp->t_lflag;
305202375Srdivacky	if (ISSET(lflag, PENDIN))
306249423Sdim		ttypend(tp);
307202375Srdivacky	/*
308202375Srdivacky	 * Gather stats.
309249423Sdim	 */
310202375Srdivacky	if (ISSET(lflag, ICANON)) {
311202375Srdivacky		++tk_cancc;
312249423Sdim		++tp->t_cancc;
313202375Srdivacky	} else {
314202375Srdivacky		++tk_rawcc;
315202375Srdivacky		++tp->t_rawcc;
316249423Sdim	}
317202375Srdivacky	++tk_nin;
318203954Srdivacky
319202375Srdivacky	/*
320203954Srdivacky	 * Block further input iff:
321202375Srdivacky	 * current input > threshold AND input is available to user program
322202375Srdivacky	 * AND input flow control is enabled and not yet invoked.
323288943Sdim	 * The 3 is slop for PARMRK.
324288943Sdim	 */
325288943Sdim	iflag = tp->t_iflag;
326288943Sdim	if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 &&
327202375Srdivacky	    (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
328249423Sdim	    (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
329249423Sdim	    !ISSET(tp->t_state, TS_TBLOCK))
330249423Sdim		ttyblock(tp);
331280031Sdim
332280031Sdim	/* Handle exceptional conditions (break, parity, framing). */
333280031Sdim	cc = tp->t_cc;
334280031Sdim	err = (ISSET(c, TTY_ERRORMASK));
335280031Sdim	if (err) {
336280031Sdim		CLR(c, TTY_ERRORMASK);
337280031Sdim		if (ISSET(err, TTY_BI)) {
338280031Sdim			if (ISSET(iflag, IGNBRK))
339280031Sdim				return (0);
340280031Sdim			if (ISSET(iflag, BRKINT)) {
341280031Sdim				ttyflush(tp, FREAD | FWRITE);
342280031Sdim				if (tp->t_pgrp != NULL) {
343202375Srdivacky					PGRP_LOCK(tp->t_pgrp);
344202375Srdivacky					pgsignal(tp->t_pgrp, SIGINT, 1);
345202375Srdivacky					PGRP_UNLOCK(tp->t_pgrp);
346202375Srdivacky				}
347202375Srdivacky				goto endcase;
348202375Srdivacky			}
349249423Sdim			if (ISSET(iflag, PARMRK))
350202375Srdivacky				goto parmrk;
351202375Srdivacky		} else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
352202375Srdivacky			|| ISSET(err, TTY_FE)) {
353202375Srdivacky			if (ISSET(iflag, IGNPAR))
354249423Sdim				return (0);
355202375Srdivacky			else if (ISSET(iflag, PARMRK)) {
356202375Srdivackyparmrk:
357223017Sdim				if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
358202375Srdivacky				    MAX_INPUT - 3)
359249423Sdim					goto input_overflow;
360202375Srdivacky				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
361202375Srdivacky				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
362202375Srdivacky				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
363202375Srdivacky				goto endcase;
364249423Sdim			} else
365202375Srdivacky				c = 0;
366202375Srdivacky		}
367202375Srdivacky	}
368202375Srdivacky
369226633Sdim	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
370223017Sdim		CLR(c, 0x80);
371202375Srdivacky	if (!ISSET(lflag, EXTPROC)) {
372202375Srdivacky		/*
373249423Sdim		 * Check for literal nexting very first
374202375Srdivacky		 */
375202375Srdivacky		if (ISSET(tp->t_state, TS_LNCH)) {
376202375Srdivacky			SET(c, TTY_QUOTE);
377202375Srdivacky			CLR(tp->t_state, TS_LNCH);
378249423Sdim		}
379202375Srdivacky		/*
380202375Srdivacky		 * Scan for special characters.  This code
381202375Srdivacky		 * is really just a big case statement with
382202375Srdivacky		 * non-constant cases.  The bottom of the
383202375Srdivacky		 * case statement is labeled ``endcase'', so goto
384202375Srdivacky		 * it after a case match, or similar.
385202375Srdivacky		 */
386202375Srdivacky
387202375Srdivacky		/*
388202375Srdivacky		 * Control chars which aren't controlled
389202375Srdivacky		 * by ICANON, ISIG, or IXON.
390202375Srdivacky		 */
391249423Sdim		if (ISSET(lflag, IEXTEN)) {
392202375Srdivacky			if (CCEQ(cc[VLNEXT], c)) {
393202375Srdivacky				if (ISSET(lflag, ECHO)) {
394226633Sdim					if (ISSET(lflag, ECHOE)) {
395223017Sdim						(void)ttyoutput('^', tp);
396249423Sdim						(void)ttyoutput('\b', tp);
397202375Srdivacky					} else
398202375Srdivacky						ttyecho(c, tp);
399226633Sdim				}
400223017Sdim				SET(tp->t_state, TS_LNCH);
401202375Srdivacky				goto endcase;
402203954Srdivacky			}
403203954Srdivacky			if (CCEQ(cc[VDISCARD], c)) {
404203954Srdivacky				if (ISSET(lflag, FLUSHO))
405203954Srdivacky					CLR(tp->t_lflag, FLUSHO);
406203954Srdivacky				else {
407202375Srdivacky					ttyflush(tp, FWRITE);
408202375Srdivacky					ttyecho(c, tp);
409202375Srdivacky					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
410288943Sdim						ttyretype(tp);
411288943Sdim					SET(tp->t_lflag, FLUSHO);
412288943Sdim				}
413296417Sdim				goto startoutput;
414288943Sdim			}
415296417Sdim		}
416288943Sdim		/*
417288943Sdim		 * Signals.
418288943Sdim		 */
419288943Sdim		if (ISSET(lflag, ISIG)) {
420202375Srdivacky			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
421249423Sdim				if (!ISSET(lflag, NOFLSH))
422249423Sdim					ttyflush(tp, FREAD | FWRITE);
423249423Sdim				ttyecho(c, tp);
424202375Srdivacky				if (tp->t_pgrp != NULL) {
425202375Srdivacky					PGRP_LOCK(tp->t_pgrp);
426202375Srdivacky					pgsignal(tp->t_pgrp,
427202375Srdivacky					    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
428249423Sdim					PGRP_UNLOCK(tp->t_pgrp);
429202375Srdivacky				}
430203954Srdivacky				goto endcase;
431203954Srdivacky			}
432202375Srdivacky			if (CCEQ(cc[VSUSP], c)) {
433202375Srdivacky				if (!ISSET(lflag, NOFLSH))
434202375Srdivacky					ttyflush(tp, FREAD);
435218893Sdim				ttyecho(c, tp);
436218893Sdim				if (tp->t_pgrp != NULL) {
437218893Sdim					PGRP_LOCK(tp->t_pgrp);
438288943Sdim					pgsignal(tp->t_pgrp, SIGTSTP, 1);
439288943Sdim					PGRP_UNLOCK(tp->t_pgrp);
440202375Srdivacky				}
441218893Sdim				goto endcase;
442218893Sdim			}
443218893Sdim		}
444249423Sdim		/*
445202375Srdivacky		 * Handle start/stop characters.
446202375Srdivacky		 */
447202375Srdivacky		if (ISSET(iflag, IXON)) {
448203954Srdivacky			if (CCEQ(cc[VSTOP], c)) {
449276479Sdim				if (!ISSET(tp->t_state, TS_TTSTOP)) {
450202375Srdivacky					SET(tp->t_state, TS_TTSTOP);
451226633Sdim					(*tp->t_stop)(tp, 0);
452226633Sdim					return (0);
453202375Srdivacky				}
454202375Srdivacky				if (!CCEQ(cc[VSTART], c))
455202375Srdivacky					return (0);
456276479Sdim				/*
457202375Srdivacky				 * if VSTART == VSTOP then toggle
458202375Srdivacky				 */
459276479Sdim				goto endcase;
460204642Srdivacky			}
461202375Srdivacky			if (CCEQ(cc[VSTART], c))
462276479Sdim				goto restartoutput;
463202375Srdivacky		}
464288943Sdim		/*
465288943Sdim		 * IGNCR, ICRNL, & INLCR
466202375Srdivacky		 */
467249423Sdim		if (c == '\r') {
468202375Srdivacky			if (ISSET(iflag, IGNCR))
469202375Srdivacky				return (0);
470202375Srdivacky			else if (ISSET(iflag, ICRNL))
471202375Srdivacky				c = '\n';
472249423Sdim		} else if (c == '\n' && ISSET(iflag, INLCR))
473218893Sdim			c = '\r';
474218893Sdim	}
475218893Sdim	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
476288943Sdim		/*
477288943Sdim		 * From here on down canonical mode character
478202375Srdivacky		 * processing takes place.
479218893Sdim		 */
480218893Sdim		/*
481218893Sdim		 * erase or erase2 (^H / ^?)
482249423Sdim		 */
483202375Srdivacky		if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) {
484203954Srdivacky			if (tp->t_rawq.c_cc)
485202375Srdivacky				ttyrub(unputc(&tp->t_rawq), tp);
486202375Srdivacky			goto endcase;
487202375Srdivacky		}
488202375Srdivacky		/*
489202375Srdivacky		 * kill (^U)
490249423Sdim		 */
491249423Sdim		if (CCEQ(cc[VKILL], c)) {
492202375Srdivacky			if (ISSET(lflag, ECHOKE) &&
493202375Srdivacky			    tp->t_rawq.c_cc == tp->t_rocount &&
494202375Srdivacky			    !ISSET(lflag, ECHOPRT))
495202375Srdivacky				while (tp->t_rawq.c_cc)
496202375Srdivacky					ttyrub(unputc(&tp->t_rawq), tp);
497202375Srdivacky			else {
498218893Sdim				ttyecho(c, tp);
499249423Sdim				if (ISSET(lflag, ECHOK) ||
500218893Sdim				    ISSET(lflag, ECHOKE))
501218893Sdim					ttyecho('\n', tp);
502218893Sdim				FLUSHQ(&tp->t_rawq);
503288943Sdim				tp->t_rocount = 0;
504288943Sdim			}
505202375Srdivacky			CLR(tp->t_state, TS_LOCAL);
506218893Sdim			goto endcase;
507218893Sdim		}
508218893Sdim		/*
509249423Sdim		 * word erase (^W)
510249423Sdim		 */
511202375Srdivacky		if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
512202375Srdivacky			int ctype;
513202375Srdivacky
514202375Srdivacky			/*
515202375Srdivacky			 * erase whitespace
516203954Srdivacky			 */
517202375Srdivacky			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
518202375Srdivacky				ttyrub(c, tp);
519223017Sdim			if (c == -1)
520203954Srdivacky				goto endcase;
521203954Srdivacky			/*
522202375Srdivacky			 * erase last char of word and remember the
523202375Srdivacky			 * next chars type (for ALTWERASE)
524202375Srdivacky			 */
525288943Sdim			ttyrub(c, tp);
526288943Sdim			c = unputc(&tp->t_rawq);
527288943Sdim			if (c == -1)
528288943Sdim				goto endcase;
529202375Srdivacky			if (c == ' ' || c == '\t') {
530288943Sdim				(void)putc(c, &tp->t_rawq);
531288943Sdim				goto endcase;
532202375Srdivacky			}
533202375Srdivacky			ctype = ISALPHA(c);
534202375Srdivacky			/*
535288943Sdim			 * erase rest of word
536288943Sdim			 */
537202375Srdivacky			do {
538288943Sdim				ttyrub(c, tp);
539288943Sdim				c = unputc(&tp->t_rawq);
540288943Sdim				if (c == -1)
541288943Sdim					goto endcase;
542288943Sdim			} while (c != ' ' && c != '\t' &&
543288943Sdim			    (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
544288943Sdim			(void)putc(c, &tp->t_rawq);
545202375Srdivacky			goto endcase;
546288943Sdim		}
547202375Srdivacky		/*
548234353Sdim		 * reprint line (^R)
549288943Sdim		 */
550202375Srdivacky		if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
551280031Sdim			ttyretype(tp);
552202375Srdivacky			goto endcase;
553288943Sdim		}
554202375Srdivacky		/*
555202375Srdivacky		 * ^T - kernel info and generate SIGINFO
556249423Sdim		 */
557249423Sdim		if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
558249423Sdim			if (ISSET(lflag, ISIG) && tp->t_pgrp != NULL) {
559249423Sdim				PGRP_LOCK(tp->t_pgrp);
560249423Sdim				pgsignal(tp->t_pgrp, SIGINFO, 1);
561249423Sdim				PGRP_UNLOCK(tp->t_pgrp);
562249423Sdim			}
563249423Sdim			if (!ISSET(lflag, NOKERNINFO))
564249423Sdim				ttyinfo(tp);
565249423Sdim			goto endcase;
566249423Sdim		}
567218893Sdim	}
568202375Srdivacky	/*
569249423Sdim	 * Check for input buffer overflow
570218893Sdim	 */
571218893Sdim	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
572218893Sdiminput_overflow:
573218893Sdim		if (ISSET(iflag, IMAXBEL)) {
574218893Sdim			if (tp->t_outq.c_cc < tp->t_ohiwat)
575218893Sdim				(void)ttyoutput(CTRL('g'), tp);
576249423Sdim		}
577288943Sdim		goto endcase;
578288943Sdim	}
579202375Srdivacky
580203954Srdivacky	if (   c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
581203954Srdivacky	     && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
582203954Srdivacky		(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
583202375Srdivacky
584202375Srdivacky	/*
585203954Srdivacky	 * Put data char in q for user and
586202375Srdivacky	 * wakeup on seeing a line delimiter.
587202375Srdivacky	 */
588202375Srdivacky	if (putc(c, &tp->t_rawq) >= 0) {
589202375Srdivacky		if (!ISSET(lflag, ICANON)) {
590202375Srdivacky			ttwakeup(tp);
591218893Sdim			ttyecho(c, tp);
592249423Sdim			goto endcase;
593202375Srdivacky		}
594202375Srdivacky		if (TTBREAKC(c, lflag)) {
595249423Sdim			tp->t_rocount = 0;
596218893Sdim			catq(&tp->t_rawq, &tp->t_canq);
597218893Sdim			ttwakeup(tp);
598218893Sdim		} else if (tp->t_rocount++ == 0)
599218893Sdim			tp->t_rocol = tp->t_column;
600249423Sdim		if (ISSET(tp->t_state, TS_ERASE)) {
601288943Sdim			/*
602288943Sdim			 * end of prterase \.../
603202375Srdivacky			 */
604203954Srdivacky			CLR(tp->t_state, TS_ERASE);
605203954Srdivacky			(void)ttyoutput('/', tp);
606203954Srdivacky		}
607202375Srdivacky		i = tp->t_column;
608202375Srdivacky		ttyecho(c, tp);
609202375Srdivacky		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
610203954Srdivacky			/*
611202375Srdivacky			 * Place the cursor over the '^' of the ^D.
612202375Srdivacky			 */
613202375Srdivacky			i = imin(2, tp->t_column - i);
614202375Srdivacky			while (i > 0) {
615202375Srdivacky				(void)ttyoutput('\b', tp);
616202375Srdivacky				i--;
617202375Srdivacky			}
618202375Srdivacky		}
619202375Srdivacky	}
620202375Srdivackyendcase:
621202375Srdivacky	/*
622202375Srdivacky	 * IXANY means allow any character to restart output.
623223017Sdim	 */
624249423Sdim	if (ISSET(tp->t_state, TS_TTSTOP) &&
625202375Srdivacky	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
626202375Srdivacky		return (0);
627202375Srdivackyrestartoutput:
628202375Srdivacky	CLR(tp->t_lflag, FLUSHO);
629202375Srdivacky	CLR(tp->t_state, TS_TTSTOP);
630249423Sdimstartoutput:
631202375Srdivacky	return (ttstart(tp));
632218893Sdim}
633249423Sdim
634202375Srdivacky/*
635202375Srdivacky * Output a single character on a tty, doing output processing
636202375Srdivacky * as needed (expanding tabs, newline processing, etc.).
637202375Srdivacky * Returns < 0 if succeeds, otherwise returns char to resend.
638202375Srdivacky * Must be recursive.
639218893Sdim */
640249423Sdimstatic int
641218893Sdimttyoutput(int c, struct tty *tp)
642218893Sdim{
643218893Sdim	tcflag_t oflag;
644218893Sdim	int col, s;
645249423Sdim
646288943Sdim	oflag = tp->t_oflag;
647288943Sdim	if (!ISSET(oflag, OPOST)) {
648202375Srdivacky		if (ISSET(tp->t_lflag, FLUSHO))
649203954Srdivacky			return (-1);
650202375Srdivacky		if (putc(c, &tp->t_outq))
651202375Srdivacky			return (c);
652203954Srdivacky		tk_nout++;
653203954Srdivacky		tp->t_outcc++;
654249423Sdim		return (-1);
655202375Srdivacky	}
656202375Srdivacky	/*
657202375Srdivacky	 * Do tab expansion if OXTABS is set.  Special case if we external
658249423Sdim	 * processing, we don't do the tab expansion because we'll probably
659249423Sdim	 * get it wrong.  If tab expansion needs to be done, let it happen
660202375Srdivacky	 * externally.
661202375Srdivacky	 */
662249423Sdim	CLR(c, ~TTY_CHARMASK);
663202375Srdivacky	if (c == '\t' &&
664202375Srdivacky	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
665234353Sdim		c = 8 - (tp->t_column & 7);
666234353Sdim		if (!ISSET(tp->t_lflag, FLUSHO)) {
667234353Sdim			s = spltty();		/* Don't interrupt tabs. */
668223017Sdim			c -= b_to_q("        ", c, &tp->t_outq);
669203954Srdivacky			tk_nout += c;
670203954Srdivacky			tp->t_outcc += c;
671202375Srdivacky			splx(s);
672202375Srdivacky		}
673202375Srdivacky		tp->t_column += c;
674202375Srdivacky		return (c ? -1 : '\t');
675202375Srdivacky	}
676221345Sdim	if (c == CEOT && ISSET(oflag, ONOEOT))
677221345Sdim		return (-1);
678221345Sdim
679221345Sdim	/*
680202375Srdivacky	 * Newline translation: if ONLCR is set,
681202375Srdivacky	 * translate newline into "\r\n".
682202375Srdivacky	 */
683202375Srdivacky	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
684202375Srdivacky		tk_nout++;
685202375Srdivacky		tp->t_outcc++;
686202375Srdivacky		if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
687288943Sdim			return (c);
688288943Sdim	}
689202375Srdivacky	/* If OCRNL is set, translate "\r" into "\n". */
690202375Srdivacky	else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
691203954Srdivacky		c = '\n';
692203954Srdivacky	/* If ONOCR is set, don't transmit CRs when on column 0. */
693203954Srdivacky	else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0)
694203954Srdivacky		return (-1);
695203954Srdivacky
696203954Srdivacky	tk_nout++;
697202375Srdivacky	tp->t_outcc++;
698203954Srdivacky	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
699202375Srdivacky		return (c);
700203954Srdivacky
701203954Srdivacky	col = tp->t_column;
702203954Srdivacky	switch (CCLASS(c)) {
703203954Srdivacky	case BACKSPACE:
704202375Srdivacky		if (col > 0)
705249423Sdim			--col;
706202375Srdivacky		break;
707202375Srdivacky	case CONTROL:
708221345Sdim		break;
709221345Sdim	case NEWLINE:
710221345Sdim		if (ISSET(tp->t_oflag, ONLCR | ONLRET))
711221345Sdim			col = 0;
712221345Sdim		break;
713288943Sdim	case RETURN:
714280031Sdim		col = 0;
715221345Sdim		break;
716221345Sdim	case ORDINARY:
717261991Sdim		++col;
718221345Sdim		break;
719202375Srdivacky	case TAB:
720202375Srdivacky		col = (col + 8) & ~7;
721202375Srdivacky		break;
722202375Srdivacky	}
723288943Sdim	tp->t_column = col;
724288943Sdim	return (-1);
725288943Sdim}
726288943Sdim
727202375Srdivacky/*
728202375Srdivacky * Ioctls for all tty devices.  Called after line-discipline specific ioctl
729202375Srdivacky * has been called to do discipline-specific functions and/or reject any
730202375Srdivacky * of these ioctl commands.
731202375Srdivacky */
732202375Srdivacky/* ARGSUSED */
733202375Srdivackyint
734202375Srdivackyttioctl(struct tty *tp, u_long cmd, void *data, int flag)
735202375Srdivacky{
736202375Srdivacky	struct proc *p;
737202375Srdivacky	struct thread *td;
738202375Srdivacky	struct pgrp *pgrp;
739202375Srdivacky	int s, error;
740202375Srdivacky
741202375Srdivacky	td = curthread;			/* XXX */
742202375Srdivacky	p = td->td_proc;
743202375Srdivacky
744249423Sdim	/* If the ioctl involves modification, hang if in the background. */
745202375Srdivacky	switch (cmd) {
746202375Srdivacky	case  TIOCCBRK:
747202375Srdivacky	case  TIOCCONS:
748202375Srdivacky	case  TIOCDRAIN:
749202375Srdivacky	case  TIOCEXCL:
750202375Srdivacky	case  TIOCFLUSH:
751202375Srdivacky#ifdef TIOCHPCL
752202375Srdivacky	case  TIOCHPCL:
753202375Srdivacky#endif
754249423Sdim	case  TIOCNXCL:
755202375Srdivacky	case  TIOCSBRK:
756202375Srdivacky	case  TIOCSCTTY:
757202375Srdivacky	case  TIOCSDRAINWAIT:
758202375Srdivacky	case  TIOCSETA:
759210299Sed	case  TIOCSETAF:
760202375Srdivacky	case  TIOCSETAW:
761202375Srdivacky	case  TIOCSETD:
762210299Sed	case  TIOCSPGRP:
763202375Srdivacky	case  TIOCSTART:
764202375Srdivacky	case  TIOCSTAT:
765223017Sdim	case  TIOCSTI:
766202375Srdivacky	case  TIOCSTOP:
767249423Sdim	case  TIOCSWINSZ:
768202375Srdivacky#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
769202375Srdivacky	case  TIOCLBIC:
770202375Srdivacky	case  TIOCLBIS:
771223017Sdim	case  TIOCLSET:
772223017Sdim	case  TIOCSETC:
773276479Sdim	case OTIOCSETD:
774202375Srdivacky	case  TIOCSETN:
775202375Srdivacky	case  TIOCSETP:
776280031Sdim	case  TIOCSLTC:
777202375Srdivacky#endif
778202375Srdivacky		sx_slock(&proctree_lock);
779249423Sdim		PROC_LOCK(p);
780202375Srdivacky		while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) &&
781202375Srdivacky		    !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) &&
782203954Srdivacky		    !SIGISMEMBER(td->td_sigmask, SIGTTOU)) {
783203954Srdivacky			pgrp = p->p_pgrp;
784276479Sdim			PROC_UNLOCK(p);
785202375Srdivacky			if (pgrp->pg_jobc == 0) {
786202375Srdivacky				sx_sunlock(&proctree_lock);
787249423Sdim				return (EIO);
788249423Sdim			}
789249423Sdim			PGRP_LOCK(pgrp);
790249423Sdim			sx_sunlock(&proctree_lock);
791249423Sdim			pgsignal(pgrp, SIGTTOU, 1);
792249423Sdim			PGRP_UNLOCK(pgrp);
793249423Sdim			error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1",
794249423Sdim					 0);
795249423Sdim			if (error)
796249423Sdim				return (error);
797249423Sdim			sx_slock(&proctree_lock);
798249423Sdim			PROC_LOCK(p);
799249423Sdim		}
800249423Sdim		PROC_UNLOCK(p);
801249423Sdim		sx_sunlock(&proctree_lock);
802249423Sdim		break;
803249423Sdim	}
804249423Sdim
805249423Sdim	switch (cmd) {			/* Process the ioctl. */
806202375Srdivacky	case FIOASYNC:			/* set/clear async i/o */
807255076Sdim		s = spltty();
808255076Sdim		if (*(int *)data)
809255076Sdim			SET(tp->t_state, TS_ASYNC);
810276479Sdim		else
811249423Sdim			CLR(tp->t_state, TS_ASYNC);
812255076Sdim		splx(s);
813255076Sdim		break;
814255076Sdim	case FIONBIO:			/* set/clear non-blocking i/o */
815255076Sdim		break;			/* XXX: delete. */
816276479Sdim	case FIONREAD:			/* get # bytes to read */
817255076Sdim		s = spltty();
818255076Sdim		*(int *)data = ttnread(tp);
819255076Sdim		splx(s);
820255076Sdim		break;
821249423Sdim
822249423Sdim	case FIOSETOWN:
823249423Sdim		/*
824249423Sdim		 * Policy -- Don't allow FIOSETOWN on someone else's
825255076Sdim		 *           controlling tty
826255076Sdim		 */
827249423Sdim		if (tp->t_session != NULL && !isctty(p, tp))
828249423Sdim			return (ENOTTY);
829249423Sdim
830249423Sdim		error = fsetown(*(int *)data, &tp->t_sigio);
831249423Sdim		if (error)
832249423Sdim			return (error);
833249423Sdim		break;
834249423Sdim	case FIOGETOWN:
835249423Sdim		if (tp->t_session != NULL && !isctty(p, tp))
836249423Sdim			return (ENOTTY);
837249423Sdim		*(int *)data = fgetown(&tp->t_sigio);
838249423Sdim		break;
839249423Sdim
840249423Sdim	case TIOCEXCL:			/* set exclusive use of tty */
841249423Sdim		s = spltty();
842249423Sdim		SET(tp->t_state, TS_XCLUDE);
843249423Sdim		splx(s);
844249423Sdim		break;
845276479Sdim	case TIOCFLUSH: {		/* flush buffers */
846249423Sdim		int flags = *(int *)data;
847249423Sdim
848249423Sdim		if (flags == 0)
849249423Sdim			flags = FREAD | FWRITE;
850249423Sdim		else
851249423Sdim			flags &= FREAD | FWRITE;
852249423Sdim		ttyflush(tp, flags);
853249423Sdim		break;
854249423Sdim	}
855249423Sdim	case TIOCCONS:			/* become virtual console */
856249423Sdim		if (*(int *)data) {
857249423Sdim			struct nameidata nid;
858249423Sdim
859249423Sdim			if (constty && constty != tp &&
860249423Sdim			    ISSET(constty->t_state, TS_CONNECTED))
861249423Sdim				return (EBUSY);
862249423Sdim
863249423Sdim			/* Ensure user can open the real console. */
864249423Sdim			NDINIT(&nid, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE,
865276479Sdim			    "/dev/console", td);
866249423Sdim			if ((error = namei(&nid)) != 0)
867249423Sdim				return (error);
868202375Srdivacky			NDFREE(&nid, NDF_ONLY_PNBUF);
869202375Srdivacky			error = VOP_ACCESS(nid.ni_vp, VREAD, td->td_ucred, td);
870202375Srdivacky			vput(nid.ni_vp);
871202375Srdivacky			if (error)
872202375Srdivacky				return (error);
873202375Srdivacky
874202375Srdivacky			constty_set(tp);
875202375Srdivacky		} else if (tp == constty)
876202375Srdivacky			constty_clear();
877203954Srdivacky		break;
878202375Srdivacky	case TIOCDRAIN:			/* wait till output drained */
879202375Srdivacky		error = ttywait(tp);
880202375Srdivacky		if (error)
881202375Srdivacky			return (error);
882202375Srdivacky		break;
883202375Srdivacky	case TIOCGETA: {		/* get termios struct */
884202375Srdivacky		struct termios *t = (struct termios *)data;
885202375Srdivacky
886276479Sdim		bcopy(&tp->t_termios, t, sizeof(struct termios));
887203954Srdivacky		break;
888249423Sdim	}
889203954Srdivacky	case TIOCGETD:			/* get line discipline */
890202375Srdivacky		*(int *)data = tp->t_line;
891202375Srdivacky		break;
892202375Srdivacky	case TIOCGWINSZ:		/* get window size */
893202375Srdivacky		*(struct winsize *)data = tp->t_winsize;
894202375Srdivacky		break;
895249423Sdim	case TIOCGPGRP:			/* get pgrp of tty */
896234353Sdim		if (!isctty(p, tp))
897234353Sdim			return (ENOTTY);
898234353Sdim		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
899234353Sdim		break;
900234353Sdim#ifdef TIOCHPCL
901276479Sdim	case TIOCHPCL:			/* hang up on last close */
902234353Sdim		s = spltty();
903226633Sdim		SET(tp->t_cflag, HUPCL);
904202375Srdivacky		splx(s);
905249423Sdim		break;
906234353Sdim#endif
907234353Sdim	case TIOCNXCL:			/* reset exclusive use of tty */
908202375Srdivacky		s = spltty();
909202375Srdivacky		CLR(tp->t_state, TS_XCLUDE);
910218893Sdim		splx(s);
911234353Sdim		break;
912234353Sdim	case TIOCOUTQ:			/* output queue size */
913249423Sdim		*(int *)data = tp->t_outq.c_cc;
914234353Sdim		break;
915276479Sdim	case TIOCSETA:			/* set termios struct */
916249423Sdim	case TIOCSETAW:			/* drain output, set */
917234353Sdim	case TIOCSETAF: {		/* drn out, fls in, set */
918202375Srdivacky		struct termios *t = (struct termios *)data;
919218893Sdim
920202375Srdivacky		if (t->c_ispeed == 0)
921234353Sdim			t->c_ispeed = t->c_ospeed;
922202375Srdivacky		if (t->c_ispeed == 0)
923234353Sdim			t->c_ispeed = tp->t_ospeed;
924249423Sdim		if (t->c_ispeed == 0)
925202375Srdivacky			return (EINVAL);
926234353Sdim		s = spltty();
927276479Sdim		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
928203954Srdivacky			error = ttywait(tp);
929249423Sdim			if (error) {
930202375Srdivacky				splx(s);
931202375Srdivacky				return (error);
932276479Sdim			}
933202375Srdivacky			if (cmd == TIOCSETAF)
934223017Sdim				ttyflush(tp, FREAD);
935202375Srdivacky		}
936202375Srdivacky		if (!ISSET(t->c_cflag, CIGNORE)) {
937202375Srdivacky			/*
938202375Srdivacky			 * Set device hardware.
939202375Srdivacky			 */
940202375Srdivacky			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
941202375Srdivacky				splx(s);
942202375Srdivacky				return (error);
943276479Sdim			}
944202375Srdivacky			if (ISSET(t->c_cflag, CLOCAL) &&
945202375Srdivacky			    !ISSET(tp->t_cflag, CLOCAL)) {
946202375Srdivacky				/*
947202375Srdivacky				 * XXX disconnections would be too hard to
948249423Sdim				 * get rid of without this kludge.  The only
949202375Srdivacky				 * way to get rid of controlling terminals
950276479Sdim				 * is to exit from the session leader.
951249423Sdim				 */
952202375Srdivacky				CLR(tp->t_state, TS_ZOMBIE);
953202375Srdivacky
954202375Srdivacky				wakeup(TSA_CARR_ON(tp));
955202375Srdivacky				ttwakeup(tp);
956202375Srdivacky				ttwwakeup(tp);
957249423Sdim			}
958202375Srdivacky			if ((ISSET(tp->t_state, TS_CARR_ON) ||
959202375Srdivacky			     ISSET(t->c_cflag, CLOCAL)) &&
960202375Srdivacky			    !ISSET(tp->t_state, TS_ZOMBIE))
961202375Srdivacky				SET(tp->t_state, TS_CONNECTED);
962276479Sdim			else
963202375Srdivacky				CLR(tp->t_state, TS_CONNECTED);
964202375Srdivacky			tp->t_cflag = t->c_cflag;
965202375Srdivacky			tp->t_ispeed = t->c_ispeed;
966288943Sdim			if (t->c_ospeed != 0)
967202375Srdivacky				tp->t_ospeed = t->c_ospeed;
968202375Srdivacky			ttsetwater(tp);
969202375Srdivacky		}
970249423Sdim		if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
971202375Srdivacky		    cmd != TIOCSETAF) {
972202375Srdivacky			if (ISSET(t->c_lflag, ICANON))
973202375Srdivacky				SET(tp->t_lflag, PENDIN);
974202375Srdivacky			else {
975202375Srdivacky				/*
976202375Srdivacky				 * XXX we really shouldn't allow toggling
977202375Srdivacky				 * ICANON while we're in a non-termios line
978249423Sdim				 * discipline.  Now we have to worry about
979202375Srdivacky				 * panicing for a null queue.
980202375Srdivacky				 */
981202375Srdivacky				if (tp->t_canq.c_cbreserved > 0 &&
982218893Sdim				    tp->t_rawq.c_cbreserved > 0) {
983202375Srdivacky					catq(&tp->t_rawq, &tp->t_canq);
984288943Sdim					/*
985202375Srdivacky					 * XXX the queue limits may be
986202375Srdivacky					 * different, so the old queue
987202375Srdivacky					 * swapping method no longer works.
988218893Sdim					 */
989202375Srdivacky					catq(&tp->t_canq, &tp->t_rawq);
990202375Srdivacky				}
991202375Srdivacky				CLR(tp->t_lflag, PENDIN);
992202375Srdivacky			}
993202375Srdivacky			ttwakeup(tp);
994202375Srdivacky		}
995202375Srdivacky		tp->t_iflag = t->c_iflag;
996202375Srdivacky		tp->t_oflag = t->c_oflag;
997202375Srdivacky		/*
998202375Srdivacky		 * Make the EXTPROC bit read only.
999202375Srdivacky		 */
1000202375Srdivacky		if (ISSET(tp->t_lflag, EXTPROC))
1001202375Srdivacky			SET(t->c_lflag, EXTPROC);
1002202375Srdivacky		else
1003218893Sdim			CLR(t->c_lflag, EXTPROC);
1004202375Srdivacky		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
1005218893Sdim		if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
1006202375Srdivacky		    t->c_cc[VTIME] != tp->t_cc[VTIME])
1007202375Srdivacky			ttwakeup(tp);
1008202375Srdivacky		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
1009202375Srdivacky		splx(s);
1010202375Srdivacky		break;
1011202375Srdivacky	}
1012288943Sdim	case TIOCSETD: {		/* set line discipline */
1013202375Srdivacky		int t = *(int *)data;
1014202375Srdivacky		dev_t device = tp->t_dev;
1015202375Srdivacky
1016202375Srdivacky		if ((u_int)t >= nlinesw)
1017288943Sdim			return (ENXIO);
1018202375Srdivacky		if (t != tp->t_line) {
1019202375Srdivacky			s = spltty();
1020202375Srdivacky			(*linesw[tp->t_line].l_close)(tp, flag);
1021202375Srdivacky			error = (*linesw[t].l_open)(device, tp);
1022202375Srdivacky			if (error) {
1023202375Srdivacky				(void)(*linesw[tp->t_line].l_open)(device, tp);
1024218893Sdim				splx(s);
1025226633Sdim				return (error);
1026226633Sdim			}
1027226633Sdim			tp->t_line = t;
1028202375Srdivacky			splx(s);
1029202375Srdivacky		}
1030202375Srdivacky		break;
1031218893Sdim	}
1032202375Srdivacky	case TIOCSTART:			/* start output, like ^Q */
1033202375Srdivacky		s = spltty();
1034202375Srdivacky		if (ISSET(tp->t_state, TS_TTSTOP) ||
1035202375Srdivacky		    ISSET(tp->t_lflag, FLUSHO)) {
1036218893Sdim			CLR(tp->t_lflag, FLUSHO);
1037202375Srdivacky			CLR(tp->t_state, TS_TTSTOP);
1038202375Srdivacky			ttstart(tp);
1039202375Srdivacky		}
1040202375Srdivacky		splx(s);
1041202375Srdivacky		break;
1042202375Srdivacky	case TIOCSTI:			/* simulate terminal input */
1043234353Sdim		if ((flag & FREAD) == 0 && suser(td))
1044202375Srdivacky			return (EPERM);
1045202375Srdivacky		if (!isctty(p, tp) && suser(td))
1046202375Srdivacky			return (EACCES);
1047202375Srdivacky		s = spltty();
1048202375Srdivacky		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
1049202375Srdivacky		splx(s);
1050202375Srdivacky		break;
1051202375Srdivacky	case TIOCSTOP:			/* stop output, like ^S */
1052202375Srdivacky		s = spltty();
1053202375Srdivacky		if (!ISSET(tp->t_state, TS_TTSTOP)) {
1054202375Srdivacky			SET(tp->t_state, TS_TTSTOP);
1055202375Srdivacky			(*tp->t_stop)(tp, 0);
1056239462Sdim		}
1057239462Sdim		splx(s);
1058239462Sdim		break;
1059239462Sdim	case TIOCSCTTY:			/* become controlling tty */
1060296417Sdim		/* Session ctty vnode pointer set in vnode layer. */
1061296417Sdim		sx_slock(&proctree_lock);
1062296417Sdim		if (!SESS_LEADER(p) ||
1063296417Sdim		    ((p->p_session->s_ttyvp || tp->t_session) &&
1064296417Sdim		     (tp->t_session != p->p_session))) {
1065296417Sdim			sx_sunlock(&proctree_lock);
1066296417Sdim			return (EPERM);
1067239462Sdim		}
1068239462Sdim		tp->t_session = p->p_session;
1069239462Sdim		tp->t_pgrp = p->p_pgrp;
1070239462Sdim		SESS_LOCK(p->p_session);
1071239462Sdim		p->p_session->s_ttyp = tp;
1072239462Sdim		SESS_UNLOCK(p->p_session);
1073288943Sdim		PROC_LOCK(p);
1074288943Sdim		p->p_flag |= P_CONTROLT;
1075239462Sdim		PROC_UNLOCK(p);
1076239462Sdim		sx_sunlock(&proctree_lock);
1077239462Sdim		break;
1078288943Sdim	case TIOCSPGRP: {		/* set pgrp of tty */
1079239462Sdim		sx_slock(&proctree_lock);
1080249423Sdim		pgrp = pgfind(*(int *)data);
1081239462Sdim		if (!isctty(p, tp)) {
1082239462Sdim			if (pgrp != NULL)
1083239462Sdim				PGRP_UNLOCK(pgrp);
1084239462Sdim			sx_sunlock(&proctree_lock);
1085202375Srdivacky			return (ENOTTY);
1086202375Srdivacky		}
1087226633Sdim		if (pgrp == NULL) {
1088202375Srdivacky			sx_sunlock(&proctree_lock);
1089202375Srdivacky			return (EPERM);
1090202375Srdivacky		}
1091296417Sdim		PGRP_UNLOCK(pgrp);
1092202375Srdivacky		if (pgrp->pg_session != p->p_session) {
1093202375Srdivacky			sx_sunlock(&proctree_lock);
1094202375Srdivacky			return (EPERM);
1095202375Srdivacky		}
1096202375Srdivacky		sx_sunlock(&proctree_lock);
1097202375Srdivacky		tp->t_pgrp = pgrp;
1098202375Srdivacky		break;
1099296417Sdim	}
1100296417Sdim	case TIOCSTAT:			/* simulate control-T */
1101296417Sdim		s = spltty();
1102296417Sdim		ttyinfo(tp);
1103296417Sdim		splx(s);
1104296417Sdim		break;
1105202375Srdivacky	case TIOCSWINSZ:		/* set window size */
1106296417Sdim		if (bcmp((caddr_t)&tp->t_winsize, data,
1107296417Sdim		    sizeof (struct winsize))) {
1108296417Sdim			tp->t_winsize = *(struct winsize *)data;
1109296417Sdim			if (tp->t_pgrp != NULL) {
1110296417Sdim				PGRP_LOCK(tp->t_pgrp);
1111296417Sdim				pgsignal(tp->t_pgrp, SIGWINCH, 1);
1112296417Sdim				PGRP_UNLOCK(tp->t_pgrp);
1113296417Sdim			}
1114296417Sdim		}
1115202375Srdivacky		break;
1116296417Sdim	case TIOCSDRAINWAIT:
1117202375Srdivacky		error = suser(td);
1118202375Srdivacky		if (error)
1119249423Sdim			return (error);
1120202375Srdivacky		tp->t_timeout = *(int *)data * hz;
1121202375Srdivacky		wakeup(TSA_OCOMPLETE(tp));
1122288943Sdim		wakeup(TSA_OLOWAT(tp));
1123202375Srdivacky		break;
1124202375Srdivacky	case TIOCGDRAINWAIT:
1125202375Srdivacky		*(int *)data = tp->t_timeout / hz;
1126202375Srdivacky		break;
1127249423Sdim	default:
1128296417Sdim#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1129296417Sdim		return (ttcompat(tp, cmd, data, flag));
1130296417Sdim#else
1131296417Sdim		return (ENOIOCTL);
1132296417Sdim#endif
1133296417Sdim	}
1134202375Srdivacky	return (0);
1135296417Sdim}
1136218893Sdim
1137296417Sdimint
1138296417Sdimttypoll(dev_t dev, int events, struct thread *td)
1139296417Sdim{
1140296417Sdim	int s;
1141296417Sdim	int revents = 0;
1142296417Sdim	struct tty *tp;
1143296417Sdim
1144296417Sdim	tp = dev->si_tty;
1145296417Sdim	if (tp == NULL)	/* XXX used to return ENXIO, but that means true! */
1146296417Sdim		return ((events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM))
1147202375Srdivacky			| POLLHUP);
1148202375Srdivacky
1149202375Srdivacky	s = spltty();
1150202375Srdivacky	if (events & (POLLIN | POLLRDNORM)) {
1151202375Srdivacky		if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))
1152202375Srdivacky			revents |= events & (POLLIN | POLLRDNORM);
1153202375Srdivacky		else
1154202375Srdivacky			selrecord(td, &tp->t_rsel);
1155202375Srdivacky	}
1156202375Srdivacky	if (events & (POLLOUT | POLLWRNORM)) {
1157202375Srdivacky		if ((tp->t_outq.c_cc <= tp->t_olowat &&
1158288943Sdim		     ISSET(tp->t_state, TS_CONNECTED))
1159288943Sdim		    || ISSET(tp->t_state, TS_ZOMBIE))
1160202375Srdivacky			revents |= events & (POLLOUT | POLLWRNORM);
1161202375Srdivacky		else
1162288943Sdim			selrecord(td, &tp->t_wsel);
1163202375Srdivacky	}
1164249423Sdim	splx(s);
1165202375Srdivacky	return (revents);
1166202375Srdivacky}
1167202375Srdivacky
1168202375Srdivackystatic struct filterops ttyread_filtops =
1169239462Sdim	{ 1, NULL, filt_ttyrdetach, filt_ttyread };
1170239462Sdimstatic struct filterops ttywrite_filtops =
1171288943Sdim	{ 1, NULL, filt_ttywdetach, filt_ttywrite };
1172288943Sdim
1173239462Sdimint
1174239462Sdimttykqfilter(dev_t dev, struct knote *kn)
1175249423Sdim{
1176202375Srdivacky	struct tty *tp = dev->si_tty;
1177202375Srdivacky	struct klist *klist;
1178202375Srdivacky	int s;
1179202375Srdivacky
1180202375Srdivacky	switch (kn->kn_filter) {
1181249423Sdim	case EVFILT_READ:
1182202375Srdivacky		klist = &tp->t_rsel.si_note;
1183202375Srdivacky		kn->kn_fop = &ttyread_filtops;
1184202375Srdivacky		break;
1185202375Srdivacky	case EVFILT_WRITE:
1186202375Srdivacky		klist = &tp->t_wsel.si_note;
1187202375Srdivacky		kn->kn_fop = &ttywrite_filtops;
1188202375Srdivacky		break;
1189202375Srdivacky	default:
1190202375Srdivacky		return (1);
1191202375Srdivacky	}
1192210299Sed
1193288943Sdim	kn->kn_hook = (caddr_t)dev;
1194210299Sed
1195210299Sed	s = spltty();
1196288943Sdim	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1197210299Sed	splx(s);
1198202375Srdivacky
1199202375Srdivacky	return (0);
1200202375Srdivacky}
1201202375Srdivacky
1202202375Srdivackystatic void
1203202375Srdivackyfilt_ttyrdetach(struct knote *kn)
1204202375Srdivacky{
1205202375Srdivacky	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
1206202375Srdivacky	int s = spltty();
1207202375Srdivacky
1208202375Srdivacky	SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
1209210299Sed	splx(s);
1210210299Sed}
1211202375Srdivacky
1212249423Sdimstatic int
1213202375Srdivackyfilt_ttyread(struct knote *kn, long hint)
1214223017Sdim{
1215202375Srdivacky	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
1216249423Sdim
1217202375Srdivacky	kn->kn_data = ttnread(tp);
1218202375Srdivacky	if (ISSET(tp->t_state, TS_ZOMBIE)) {
1219202375Srdivacky		kn->kn_flags |= EV_EOF;
1220202375Srdivacky		return (1);
1221223017Sdim	}
1222202375Srdivacky	return (kn->kn_data > 0);
1223202375Srdivacky}
1224202375Srdivacky
1225202375Srdivackystatic void
1226223017Sdimfilt_ttywdetach(struct knote *kn)
1227202375Srdivacky{
1228202375Srdivacky	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
1229202375Srdivacky	int s = spltty();
1230249423Sdim
1231202375Srdivacky	SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
1232202375Srdivacky	splx(s);
1233202375Srdivacky}
1234202375Srdivacky
1235202375Srdivackystatic int
1236223017Sdimfilt_ttywrite(struct knote *kn, long hint)
1237202375Srdivacky{
1238249423Sdim	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
1239202375Srdivacky
1240249423Sdim	kn->kn_data = tp->t_outq.c_cc;
1241202375Srdivacky	if (ISSET(tp->t_state, TS_ZOMBIE))
1242202375Srdivacky		return (1);
1243202375Srdivacky	return (kn->kn_data <= tp->t_olowat &&
1244202375Srdivacky	    ISSET(tp->t_state, TS_CONNECTED));
1245296417Sdim}
1246296417Sdim
1247296417Sdim/*
1248296417Sdim * Must be called at spltty().
1249296417Sdim */
1250296417Sdimstatic int
1251296417Sdimttnread(struct tty *tp)
1252296417Sdim{
1253296417Sdim	int nread;
1254202375Srdivacky
1255202375Srdivacky	if (ISSET(tp->t_lflag, PENDIN))
1256202375Srdivacky		ttypend(tp);
1257202375Srdivacky	nread = tp->t_canq.c_cc;
1258276479Sdim	if (!ISSET(tp->t_lflag, ICANON)) {
1259202375Srdivacky		nread += tp->t_rawq.c_cc;
1260		if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
1261			nread = 0;
1262	}
1263	return (nread);
1264}
1265
1266/*
1267 * Wait for output to drain.
1268 */
1269int
1270ttywait(struct tty *tp)
1271{
1272	int error, s;
1273
1274	error = 0;
1275	s = spltty();
1276	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1277	       ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
1278		(*tp->t_oproc)(tp);
1279		if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
1280		    ISSET(tp->t_state, TS_CONNECTED)) {
1281			SET(tp->t_state, TS_SO_OCOMPLETE);
1282			error = ttysleep(tp, TSA_OCOMPLETE(tp),
1283					 TTOPRI | PCATCH, "ttywai",
1284					 tp->t_timeout);
1285			if (error) {
1286				if (error == EWOULDBLOCK)
1287					error = EIO;
1288				break;
1289			}
1290		} else
1291			break;
1292	}
1293	if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
1294		error = EIO;
1295	splx(s);
1296	return (error);
1297}
1298
1299/*
1300 * Flush if successfully wait.
1301 */
1302static int
1303ttywflush(struct tty *tp)
1304{
1305	int error;
1306
1307	if ((error = ttywait(tp)) == 0)
1308		ttyflush(tp, FREAD);
1309	return (error);
1310}
1311
1312/*
1313 * Flush tty read and/or write queues, notifying anyone waiting.
1314 */
1315void
1316ttyflush(struct tty *tp, int rw)
1317{
1318	int s;
1319
1320	s = spltty();
1321#if 0
1322again:
1323#endif
1324	if (rw & FWRITE) {
1325		FLUSHQ(&tp->t_outq);
1326		CLR(tp->t_state, TS_TTSTOP);
1327	}
1328	(*tp->t_stop)(tp, rw);
1329	if (rw & FREAD) {
1330		FLUSHQ(&tp->t_canq);
1331		FLUSHQ(&tp->t_rawq);
1332		CLR(tp->t_lflag, PENDIN);
1333		tp->t_rocount = 0;
1334		tp->t_rocol = 0;
1335		CLR(tp->t_state, TS_LOCAL);
1336		ttwakeup(tp);
1337		if (ISSET(tp->t_state, TS_TBLOCK)) {
1338			if (rw & FWRITE)
1339				FLUSHQ(&tp->t_outq);
1340			ttyunblock(tp);
1341
1342			/*
1343			 * Don't let leave any state that might clobber the
1344			 * next line discipline (although we should do more
1345			 * to send the START char).  Not clearing the state
1346			 * may have caused the "putc to a clist with no
1347			 * reserved cblocks" panic/printf.
1348			 */
1349			CLR(tp->t_state, TS_TBLOCK);
1350
1351#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
1352			if (ISSET(tp->t_iflag, IXOFF)) {
1353				/*
1354				 * XXX wait a bit in the hope that the stop
1355				 * character (if any) will go out.  Waiting
1356				 * isn't good since it allows races.  This
1357				 * will be fixed when the stop character is
1358				 * put in a special queue.  Don't bother with
1359				 * the checks in ttywait() since the timeout
1360				 * will save us.
1361				 */
1362				SET(tp->t_state, TS_SO_OCOMPLETE);
1363				ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI,
1364					 "ttyfls", hz / 10);
1365				/*
1366				 * Don't try sending the stop character again.
1367				 */
1368				CLR(tp->t_state, TS_TBLOCK);
1369				goto again;
1370			}
1371#endif
1372		}
1373	}
1374	if (rw & FWRITE) {
1375		FLUSHQ(&tp->t_outq);
1376		ttwwakeup(tp);
1377	}
1378	splx(s);
1379}
1380
1381/*
1382 * Copy in the default termios characters.
1383 */
1384void
1385termioschars(struct termios *t)
1386{
1387
1388	bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
1389}
1390
1391/*
1392 * Old interface.
1393 */
1394void
1395ttychars(struct tty *tp)
1396{
1397
1398	termioschars(&tp->t_termios);
1399}
1400
1401/*
1402 * Handle input high water.  Send stop character for the IXOFF case.  Turn
1403 * on our input flow control bit and propagate the changes to the driver.
1404 * XXX the stop character should be put in a special high priority queue.
1405 */
1406void
1407ttyblock(struct tty *tp)
1408{
1409
1410	SET(tp->t_state, TS_TBLOCK);
1411	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
1412	    putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
1413		CLR(tp->t_state, TS_TBLOCK);	/* try again later */
1414	ttstart(tp);
1415}
1416
1417/*
1418 * Handle input low water.  Send start character for the IXOFF case.  Turn
1419 * off our input flow control bit and propagate the changes to the driver.
1420 * XXX the start character should be put in a special high priority queue.
1421 */
1422static void
1423ttyunblock(struct tty *tp)
1424{
1425
1426	CLR(tp->t_state, TS_TBLOCK);
1427	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
1428	    putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
1429		SET(tp->t_state, TS_TBLOCK);	/* try again later */
1430	ttstart(tp);
1431}
1432
1433#ifdef notyet
1434/* Not used by any current (i386) drivers. */
1435/*
1436 * Restart after an inter-char delay.
1437 */
1438void
1439ttrstrt(void *tp_arg)
1440{
1441	struct tty *tp;
1442	int s;
1443
1444	KASSERT(tp_arg != NULL, ("ttrstrt"));
1445
1446	tp = tp_arg;
1447	s = spltty();
1448
1449	CLR(tp->t_state, TS_TIMEOUT);
1450	ttstart(tp);
1451
1452	splx(s);
1453}
1454#endif
1455
1456int
1457ttstart(struct tty *tp)
1458{
1459
1460	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
1461		(*tp->t_oproc)(tp);
1462	return (0);
1463}
1464
1465/*
1466 * "close" a line discipline
1467 */
1468int
1469ttylclose(struct tty *tp, int flag)
1470{
1471
1472	if (flag & FNONBLOCK || ttywflush(tp))
1473		ttyflush(tp, FREAD | FWRITE);
1474	return (0);
1475}
1476
1477/*
1478 * Handle modem control transition on a tty.
1479 * Flag indicates new state of carrier.
1480 * Returns 0 if the line should be turned off, otherwise 1.
1481 */
1482int
1483ttymodem(struct tty *tp, int flag)
1484{
1485
1486	if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
1487		/*
1488		 * MDMBUF: do flow control according to carrier flag
1489		 * XXX TS_CAR_OFLOW doesn't do anything yet.  TS_TTSTOP
1490		 * works if IXON and IXANY are clear.
1491		 */
1492		if (flag) {
1493			CLR(tp->t_state, TS_CAR_OFLOW);
1494			CLR(tp->t_state, TS_TTSTOP);
1495			ttstart(tp);
1496		} else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
1497			SET(tp->t_state, TS_CAR_OFLOW);
1498			SET(tp->t_state, TS_TTSTOP);
1499			(*tp->t_stop)(tp, 0);
1500		}
1501	} else if (flag == 0) {
1502		/*
1503		 * Lost carrier.
1504		 */
1505		CLR(tp->t_state, TS_CARR_ON);
1506		if (ISSET(tp->t_state, TS_ISOPEN) &&
1507		    !ISSET(tp->t_cflag, CLOCAL)) {
1508			SET(tp->t_state, TS_ZOMBIE);
1509			CLR(tp->t_state, TS_CONNECTED);
1510			if (tp->t_session) {
1511				sx_slock(&proctree_lock);
1512				if (tp->t_session->s_leader) {
1513					struct proc *p;
1514
1515					p = tp->t_session->s_leader;
1516					PROC_LOCK(p);
1517					psignal(p, SIGHUP);
1518					PROC_UNLOCK(p);
1519				}
1520				sx_sunlock(&proctree_lock);
1521			}
1522			ttyflush(tp, FREAD | FWRITE);
1523			return (0);
1524		}
1525	} else {
1526		/*
1527		 * Carrier now on.
1528		 */
1529		SET(tp->t_state, TS_CARR_ON);
1530		if (!ISSET(tp->t_state, TS_ZOMBIE))
1531			SET(tp->t_state, TS_CONNECTED);
1532		wakeup(TSA_CARR_ON(tp));
1533		ttwakeup(tp);
1534		ttwwakeup(tp);
1535	}
1536	return (1);
1537}
1538
1539/*
1540 * Reinput pending characters after state switch
1541 * call at spltty().
1542 */
1543static void
1544ttypend(struct tty *tp)
1545{
1546	struct clist tq;
1547	int c;
1548
1549	CLR(tp->t_lflag, PENDIN);
1550	SET(tp->t_state, TS_TYPEN);
1551	/*
1552	 * XXX this assumes too much about clist internals.  It may even
1553	 * fail if the cblock slush pool is empty.  We can't allocate more
1554	 * cblocks here because we are called from an interrupt handler
1555	 * and clist_alloc_cblocks() can wait.
1556	 */
1557	tq = tp->t_rawq;
1558	bzero(&tp->t_rawq, sizeof tp->t_rawq);
1559	tp->t_rawq.c_cbmax = tq.c_cbmax;
1560	tp->t_rawq.c_cbreserved = tq.c_cbreserved;
1561	while ((c = getc(&tq)) >= 0)
1562		ttyinput(c, tp);
1563	CLR(tp->t_state, TS_TYPEN);
1564}
1565
1566/*
1567 * Process a read call on a tty device.
1568 */
1569int
1570ttread(struct tty *tp, struct uio *uio, int flag)
1571{
1572	struct clist *qp;
1573	int c;
1574	tcflag_t lflag;
1575	cc_t *cc = tp->t_cc;
1576	struct thread *td;
1577	struct proc *p;
1578	int s, first, error = 0;
1579	int has_stime = 0, last_cc = 0;
1580	long slp = 0;		/* XXX this should be renamed `timo'. */
1581	struct timeval stime;
1582	struct pgrp *pg;
1583
1584	td = curthread;
1585	p = td->td_proc;
1586loop:
1587	s = spltty();
1588	lflag = tp->t_lflag;
1589	/*
1590	 * take pending input first
1591	 */
1592	if (ISSET(lflag, PENDIN)) {
1593		ttypend(tp);
1594		splx(s);	/* reduce latency */
1595		s = spltty();
1596		lflag = tp->t_lflag;	/* XXX ttypend() clobbers it */
1597	}
1598
1599	/*
1600	 * Hang process if it's in the background.
1601	 */
1602	if (isbackground(p, tp)) {
1603		splx(s);
1604		sx_slock(&proctree_lock);
1605		PROC_LOCK(p);
1606		if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) ||
1607		    SIGISMEMBER(td->td_sigmask, SIGTTIN) ||
1608		    (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) {
1609			PROC_UNLOCK(p);
1610			sx_sunlock(&proctree_lock);
1611			return (EIO);
1612		}
1613		pg = p->p_pgrp;
1614		PROC_UNLOCK(p);
1615		PGRP_LOCK(pg);
1616		sx_sunlock(&proctree_lock);
1617		pgsignal(pg, SIGTTIN, 1);
1618		PGRP_UNLOCK(pg);
1619		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0);
1620		if (error)
1621			return (error);
1622		goto loop;
1623	}
1624
1625	if (ISSET(tp->t_state, TS_ZOMBIE)) {
1626		splx(s);
1627		return (0);	/* EOF */
1628	}
1629
1630	/*
1631	 * If canonical, use the canonical queue,
1632	 * else use the raw queue.
1633	 *
1634	 * (should get rid of clists...)
1635	 */
1636	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
1637
1638	if (flag & IO_NDELAY) {
1639		if (qp->c_cc > 0)
1640			goto read;
1641		if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
1642			splx(s);
1643			return (0);
1644		}
1645		splx(s);
1646		return (EWOULDBLOCK);
1647	}
1648	if (!ISSET(lflag, ICANON)) {
1649		int m = cc[VMIN];
1650		long t = cc[VTIME];
1651		struct timeval timecopy;
1652
1653		/*
1654		 * Check each of the four combinations.
1655		 * (m > 0 && t == 0) is the normal read case.
1656		 * It should be fairly efficient, so we check that and its
1657		 * companion case (m == 0 && t == 0) first.
1658		 * For the other two cases, we compute the target sleep time
1659		 * into slp.
1660		 */
1661		if (t == 0) {
1662			if (qp->c_cc < m)
1663				goto sleep;
1664			if (qp->c_cc > 0)
1665				goto read;
1666
1667			/* m, t and qp->c_cc are all 0.  0 is enough input. */
1668			splx(s);
1669			return (0);
1670		}
1671		t *= 100000;		/* time in us */
1672#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
1673			 ((t1).tv_usec - (t2).tv_usec))
1674		if (m > 0) {
1675			if (qp->c_cc <= 0)
1676				goto sleep;
1677			if (qp->c_cc >= m)
1678				goto read;
1679			getmicrotime(&timecopy);
1680			if (!has_stime) {
1681				/* first character, start timer */
1682				has_stime = 1;
1683				stime = timecopy;
1684				slp = t;
1685			} else if (qp->c_cc > last_cc) {
1686				/* got a character, restart timer */
1687				stime = timecopy;
1688				slp = t;
1689			} else {
1690				/* nothing, check expiration */
1691				slp = t - diff(timecopy, stime);
1692				if (slp <= 0)
1693					goto read;
1694			}
1695			last_cc = qp->c_cc;
1696		} else {	/* m == 0 */
1697			if (qp->c_cc > 0)
1698				goto read;
1699			getmicrotime(&timecopy);
1700			if (!has_stime) {
1701				has_stime = 1;
1702				stime = timecopy;
1703				slp = t;
1704			} else {
1705				slp = t - diff(timecopy, stime);
1706				if (slp <= 0) {
1707					/* Timed out, but 0 is enough input. */
1708					splx(s);
1709					return (0);
1710				}
1711			}
1712		}
1713#undef diff
1714		/*
1715		 * Rounding down may make us wake up just short
1716		 * of the target, so we round up.
1717		 * The formula is ceiling(slp * hz/1000000).
1718		 * 32-bit arithmetic is enough for hz < 169.
1719		 * XXX see tvtohz() for how to avoid overflow if hz
1720		 * is large (divide by `tick' and/or arrange to
1721		 * use tvtohz() if hz is large).
1722		 */
1723		slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
1724		goto sleep;
1725	}
1726	if (qp->c_cc <= 0) {
1727sleep:
1728		/*
1729		 * There is no input, or not enough input and we can block.
1730		 */
1731		error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
1732				 ISSET(tp->t_state, TS_CONNECTED) ?
1733				 "ttyin" : "ttyhup", (int)slp);
1734		splx(s);
1735		if (error == EWOULDBLOCK)
1736			error = 0;
1737		else if (error)
1738			return (error);
1739		/*
1740		 * XXX what happens if another process eats some input
1741		 * while we are asleep (not just here)?  It would be
1742		 * safest to detect changes and reset our state variables
1743		 * (has_stime and last_cc).
1744		 */
1745		slp = 0;
1746		goto loop;
1747	}
1748read:
1749	splx(s);
1750	/*
1751	 * Input present, check for input mapping and processing.
1752	 */
1753	first = 1;
1754	if (ISSET(lflag, ICANON | ISIG))
1755		goto slowcase;
1756	for (;;) {
1757		char ibuf[IBUFSIZ];
1758		int icc;
1759
1760		icc = imin(uio->uio_resid, IBUFSIZ);
1761		icc = q_to_b(qp, ibuf, icc);
1762		if (icc <= 0) {
1763			if (first)
1764				goto loop;
1765			break;
1766		}
1767		error = uiomove(ibuf, icc, uio);
1768		/*
1769		 * XXX if there was an error then we should ungetc() the
1770		 * unmoved chars and reduce icc here.
1771		 */
1772		if (error)
1773			break;
1774		if (uio->uio_resid == 0)
1775			break;
1776		first = 0;
1777	}
1778	goto out;
1779slowcase:
1780	for (;;) {
1781		c = getc(qp);
1782		if (c < 0) {
1783			if (first)
1784				goto loop;
1785			break;
1786		}
1787		/*
1788		 * delayed suspend (^Y)
1789		 */
1790		if (CCEQ(cc[VDSUSP], c) &&
1791		    ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
1792			if (tp->t_pgrp != NULL) {
1793				PGRP_LOCK(tp->t_pgrp);
1794				pgsignal(tp->t_pgrp, SIGTSTP, 1);
1795				PGRP_UNLOCK(tp->t_pgrp);
1796			}
1797			if (first) {
1798				error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
1799						 "ttybg3", 0);
1800				if (error)
1801					break;
1802				goto loop;
1803			}
1804			break;
1805		}
1806		/*
1807		 * Interpret EOF only in canonical mode.
1808		 */
1809		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
1810			break;
1811		/*
1812		 * Give user character.
1813		 */
1814		error = ureadc(c, uio);
1815		if (error)
1816			/* XXX should ungetc(c, qp). */
1817			break;
1818		if (uio->uio_resid == 0)
1819			break;
1820		/*
1821		 * In canonical mode check for a "break character"
1822		 * marking the end of a "line of input".
1823		 */
1824		if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
1825			break;
1826		first = 0;
1827	}
1828
1829out:
1830	/*
1831	 * Look to unblock input now that (presumably)
1832	 * the input queue has gone down.
1833	 */
1834	s = spltty();
1835	if (ISSET(tp->t_state, TS_TBLOCK) &&
1836	    tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat)
1837		ttyunblock(tp);
1838	splx(s);
1839
1840	return (error);
1841}
1842
1843/*
1844 * Check the output queue on tp for space for a kernel message (from uprintf
1845 * or tprintf).  Allow some space over the normal hiwater mark so we don't
1846 * lose messages due to normal flow control, but don't let the tty run amok.
1847 * Sleeps here are not interruptible, but we return prematurely if new signals
1848 * arrive.
1849 */
1850int
1851ttycheckoutq(struct tty *tp, int wait)
1852{
1853	int hiwat, s;
1854	sigset_t oldmask;
1855	struct thread *td;
1856	struct proc *p;
1857
1858	td = curthread;
1859	p = td->td_proc;
1860	hiwat = tp->t_ohiwat;
1861	SIGEMPTYSET(oldmask);
1862	s = spltty();
1863	if (wait) {
1864		PROC_LOCK(p);
1865		oldmask = td->td_siglist;
1866		PROC_UNLOCK(p);
1867	}
1868	if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100)
1869		while (tp->t_outq.c_cc > hiwat) {
1870			ttstart(tp);
1871			if (tp->t_outq.c_cc <= hiwat)
1872				break;
1873			if (!wait) {
1874				splx(s);
1875				return (0);
1876			}
1877			PROC_LOCK(p);
1878			if (!SIGSETEQ(td->td_siglist, oldmask)) {
1879				PROC_UNLOCK(p);
1880				splx(s);
1881				return (0);
1882			}
1883			PROC_UNLOCK(p);
1884			SET(tp->t_state, TS_SO_OLOWAT);
1885			tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz);
1886		}
1887	splx(s);
1888	return (1);
1889}
1890
1891/*
1892 * Process a write call on a tty device.
1893 */
1894int
1895ttwrite(struct tty *tp, struct uio *uio, int flag)
1896{
1897	char *cp = NULL;
1898	int cc, ce;
1899	struct thread *td;
1900	struct proc *p;
1901	int i, hiwat, cnt, error, s;
1902	char obuf[OBUFSIZ];
1903
1904	hiwat = tp->t_ohiwat;
1905	cnt = uio->uio_resid;
1906	error = 0;
1907	cc = 0;
1908	td = curthread;
1909	p = td->td_proc;
1910loop:
1911	s = spltty();
1912	if (ISSET(tp->t_state, TS_ZOMBIE)) {
1913		splx(s);
1914		if (uio->uio_resid == cnt)
1915			error = EIO;
1916		goto out;
1917	}
1918	if (!ISSET(tp->t_state, TS_CONNECTED)) {
1919		if (flag & IO_NDELAY) {
1920			splx(s);
1921			error = EWOULDBLOCK;
1922			goto out;
1923		}
1924		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
1925				 "ttydcd", 0);
1926		splx(s);
1927		if (error)
1928			goto out;
1929		goto loop;
1930	}
1931	splx(s);
1932	/*
1933	 * Hang the process if it's in the background.
1934	 */
1935	sx_slock(&proctree_lock);
1936	PROC_LOCK(p);
1937	if (isbackground(p, tp) &&
1938	    ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) &&
1939	    !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) &&
1940	    !SIGISMEMBER(td->td_sigmask, SIGTTOU)) {
1941		if (p->p_pgrp->pg_jobc == 0) {
1942			PROC_UNLOCK(p);
1943			sx_sunlock(&proctree_lock);
1944			error = EIO;
1945			goto out;
1946		}
1947		PROC_UNLOCK(p);
1948		PGRP_LOCK(p->p_pgrp);
1949		sx_sunlock(&proctree_lock);
1950		pgsignal(p->p_pgrp, SIGTTOU, 1);
1951		PGRP_UNLOCK(p->p_pgrp);
1952		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0);
1953		if (error)
1954			goto out;
1955		goto loop;
1956	} else {
1957		PROC_UNLOCK(p);
1958		sx_sunlock(&proctree_lock);
1959	}
1960	/*
1961	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
1962	 * output translation.  Keep track of high water mark, sleep on
1963	 * overflow awaiting device aid in acquiring new space.
1964	 */
1965	while (uio->uio_resid > 0 || cc > 0) {
1966		if (ISSET(tp->t_lflag, FLUSHO)) {
1967			uio->uio_resid = 0;
1968			return (0);
1969		}
1970		if (tp->t_outq.c_cc > hiwat)
1971			goto ovhiwat;
1972		/*
1973		 * Grab a hunk of data from the user, unless we have some
1974		 * leftover from last time.
1975		 */
1976		if (cc == 0) {
1977			cc = imin(uio->uio_resid, OBUFSIZ);
1978			cp = obuf;
1979			error = uiomove(cp, cc, uio);
1980			if (error) {
1981				cc = 0;
1982				break;
1983			}
1984		}
1985		/*
1986		 * If nothing fancy need be done, grab those characters we
1987		 * can handle without any of ttyoutput's processing and
1988		 * just transfer them to the output q.  For those chars
1989		 * which require special processing (as indicated by the
1990		 * bits in char_type), call ttyoutput.  After processing
1991		 * a hunk of data, look for FLUSHO so ^O's will take effect
1992		 * immediately.
1993		 */
1994		while (cc > 0) {
1995			if (!ISSET(tp->t_oflag, OPOST))
1996				ce = cc;
1997			else {
1998				ce = cc - scanc((u_int)cc, (u_char *)cp,
1999						char_type, CCLASSMASK);
2000				/*
2001				 * If ce is zero, then we're processing
2002				 * a special character through ttyoutput.
2003				 */
2004				if (ce == 0) {
2005					tp->t_rocount = 0;
2006					if (ttyoutput(*cp, tp) >= 0) {
2007						/* No Clists, wait a bit. */
2008						ttstart(tp);
2009						if (flag & IO_NDELAY) {
2010							error = EWOULDBLOCK;
2011							goto out;
2012						}
2013						error = ttysleep(tp, &lbolt,
2014								 TTOPRI|PCATCH,
2015								 "ttybf1", 0);
2016						if (error)
2017							goto out;
2018						goto loop;
2019					}
2020					cp++;
2021					cc--;
2022					if (ISSET(tp->t_lflag, FLUSHO) ||
2023					    tp->t_outq.c_cc > hiwat)
2024						goto ovhiwat;
2025					continue;
2026				}
2027			}
2028			/*
2029			 * A bunch of normal characters have been found.
2030			 * Transfer them en masse to the output queue and
2031			 * continue processing at the top of the loop.
2032			 * If there are any further characters in this
2033			 * <= OBUFSIZ chunk, the first should be a character
2034			 * requiring special handling by ttyoutput.
2035			 */
2036			tp->t_rocount = 0;
2037			i = b_to_q(cp, ce, &tp->t_outq);
2038			ce -= i;
2039			tp->t_column += ce;
2040			cp += ce, cc -= ce, tk_nout += ce;
2041			tp->t_outcc += ce;
2042			if (i > 0) {
2043				/* No Clists, wait a bit. */
2044				ttstart(tp);
2045				if (flag & IO_NDELAY) {
2046					error = EWOULDBLOCK;
2047					goto out;
2048				}
2049				error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
2050						 "ttybf2", 0);
2051				if (error)
2052					goto out;
2053				goto loop;
2054			}
2055			if (ISSET(tp->t_lflag, FLUSHO) ||
2056			    tp->t_outq.c_cc > hiwat)
2057				break;
2058		}
2059		ttstart(tp);
2060	}
2061out:
2062	/*
2063	 * If cc is nonzero, we leave the uio structure inconsistent, as the
2064	 * offset and iov pointers have moved forward, but it doesn't matter
2065	 * (the call will either return short or restart with a new uio).
2066	 */
2067	uio->uio_resid += cc;
2068	return (error);
2069
2070ovhiwat:
2071	ttstart(tp);
2072	s = spltty();
2073	/*
2074	 * This can only occur if FLUSHO is set in t_lflag,
2075	 * or if ttstart/oproc is synchronous (or very fast).
2076	 */
2077	if (tp->t_outq.c_cc <= hiwat) {
2078		splx(s);
2079		goto loop;
2080	}
2081	if (flag & IO_NDELAY) {
2082		splx(s);
2083		uio->uio_resid += cc;
2084		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
2085	}
2086	SET(tp->t_state, TS_SO_OLOWAT);
2087	error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",
2088			 tp->t_timeout);
2089	splx(s);
2090	if (error == EWOULDBLOCK)
2091		error = EIO;
2092	if (error)
2093		goto out;
2094	goto loop;
2095}
2096
2097/*
2098 * Rubout one character from the rawq of tp
2099 * as cleanly as possible.
2100 */
2101static void
2102ttyrub(int c, struct tty *tp)
2103{
2104	char *cp;
2105	int savecol;
2106	int tabc, s;
2107
2108	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
2109		return;
2110	CLR(tp->t_lflag, FLUSHO);
2111	if (ISSET(tp->t_lflag, ECHOE)) {
2112		if (tp->t_rocount == 0) {
2113			/*
2114			 * Screwed by ttwrite; retype
2115			 */
2116			ttyretype(tp);
2117			return;
2118		}
2119		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
2120			ttyrubo(tp, 2);
2121		else {
2122			CLR(c, ~TTY_CHARMASK);
2123			switch (CCLASS(c)) {
2124			case ORDINARY:
2125				ttyrubo(tp, 1);
2126				break;
2127			case BACKSPACE:
2128			case CONTROL:
2129			case NEWLINE:
2130			case RETURN:
2131			case VTAB:
2132				if (ISSET(tp->t_lflag, ECHOCTL))
2133					ttyrubo(tp, 2);
2134				break;
2135			case TAB:
2136				if (tp->t_rocount < tp->t_rawq.c_cc) {
2137					ttyretype(tp);
2138					return;
2139				}
2140				s = spltty();
2141				savecol = tp->t_column;
2142				SET(tp->t_state, TS_CNTTB);
2143				SET(tp->t_lflag, FLUSHO);
2144				tp->t_column = tp->t_rocol;
2145				cp = tp->t_rawq.c_cf;
2146				if (cp)
2147					tabc = *cp;	/* XXX FIX NEXTC */
2148				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
2149					ttyecho(tabc, tp);
2150				CLR(tp->t_lflag, FLUSHO);
2151				CLR(tp->t_state, TS_CNTTB);
2152				splx(s);
2153
2154				/* savecol will now be length of the tab. */
2155				savecol -= tp->t_column;
2156				tp->t_column += savecol;
2157				if (savecol > 8)
2158					savecol = 8;	/* overflow screw */
2159				while (--savecol >= 0)
2160					(void)ttyoutput('\b', tp);
2161				break;
2162			default:			/* XXX */
2163#define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
2164				(void)printf(PANICSTR, c, CCLASS(c));
2165#ifdef notdef
2166				panic(PANICSTR, c, CCLASS(c));
2167#endif
2168			}
2169		}
2170	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
2171		if (!ISSET(tp->t_state, TS_ERASE)) {
2172			SET(tp->t_state, TS_ERASE);
2173			(void)ttyoutput('\\', tp);
2174		}
2175		ttyecho(c, tp);
2176	} else {
2177		ttyecho(tp->t_cc[VERASE], tp);
2178		/*
2179		 * This code may be executed not only when an ERASE key
2180		 * is pressed, but also when ^U (KILL) or ^W (WERASE) are.
2181		 * So, I didn't think it was worthwhile to pass the extra
2182		 * information (which would need an extra parameter,
2183		 * changing every call) needed to distinguish the ERASE2
2184		 * case from the ERASE.
2185		 */
2186	}
2187	--tp->t_rocount;
2188}
2189
2190/*
2191 * Back over cnt characters, erasing them.
2192 */
2193static void
2194ttyrubo(struct tty *tp, int cnt)
2195{
2196
2197	while (cnt-- > 0) {
2198		(void)ttyoutput('\b', tp);
2199		(void)ttyoutput(' ', tp);
2200		(void)ttyoutput('\b', tp);
2201	}
2202}
2203
2204/*
2205 * ttyretype --
2206 *	Reprint the rawq line.  Note, it is assumed that c_cc has already
2207 *	been checked.
2208 */
2209static void
2210ttyretype(struct tty *tp)
2211{
2212	char *cp;
2213	int s, c;
2214
2215	/* Echo the reprint character. */
2216	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
2217		ttyecho(tp->t_cc[VREPRINT], tp);
2218
2219	(void)ttyoutput('\n', tp);
2220
2221	/*
2222	 * XXX
2223	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
2224	 * BIT OF FIRST CHAR.
2225	 */
2226	s = spltty();
2227	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
2228	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
2229		ttyecho(c, tp);
2230	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
2231	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
2232		ttyecho(c, tp);
2233	CLR(tp->t_state, TS_ERASE);
2234	splx(s);
2235
2236	tp->t_rocount = tp->t_rawq.c_cc;
2237	tp->t_rocol = 0;
2238}
2239
2240/*
2241 * Echo a typed character to the terminal.
2242 */
2243static void
2244ttyecho(int c, struct tty *tp)
2245{
2246
2247	if (!ISSET(tp->t_state, TS_CNTTB))
2248		CLR(tp->t_lflag, FLUSHO);
2249	if ((!ISSET(tp->t_lflag, ECHO) &&
2250	     (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
2251	    ISSET(tp->t_lflag, EXTPROC))
2252		return;
2253	if (ISSET(tp->t_lflag, ECHOCTL) &&
2254	    ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
2255	    ISSET(c, TTY_CHARMASK) == 0177)) {
2256		(void)ttyoutput('^', tp);
2257		CLR(c, ~TTY_CHARMASK);
2258		if (c == 0177)
2259			c = '?';
2260		else
2261			c += 'A' - 1;
2262	}
2263	(void)ttyoutput(c, tp);
2264}
2265
2266/*
2267 * Wake up any readers on a tty.
2268 */
2269void
2270ttwakeup(struct tty *tp)
2271{
2272
2273	if (SEL_WAITING(&tp->t_rsel))
2274		selwakeup(&tp->t_rsel);
2275	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2276		pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
2277	wakeup(TSA_HUP_OR_INPUT(tp));
2278	KNOTE(&tp->t_rsel.si_note, 0);
2279}
2280
2281/*
2282 * Wake up any writers on a tty.
2283 */
2284void
2285ttwwakeup(struct tty *tp)
2286{
2287
2288	if (SEL_WAITING(&tp->t_wsel) && tp->t_outq.c_cc <= tp->t_olowat)
2289		selwakeup(&tp->t_wsel);
2290	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2291		pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
2292	if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
2293	    TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
2294		CLR(tp->t_state, TS_SO_OCOMPLETE);
2295		wakeup(TSA_OCOMPLETE(tp));
2296	}
2297	if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
2298	    tp->t_outq.c_cc <= tp->t_olowat) {
2299		CLR(tp->t_state, TS_SO_OLOWAT);
2300		wakeup(TSA_OLOWAT(tp));
2301	}
2302	KNOTE(&tp->t_wsel.si_note, 0);
2303}
2304
2305/*
2306 * Look up a code for a specified speed in a conversion table;
2307 * used by drivers to map software speed values to hardware parameters.
2308 */
2309int
2310ttspeedtab(int speed, struct speedtab *table)
2311{
2312
2313	for ( ; table->sp_speed != -1; table++)
2314		if (table->sp_speed == speed)
2315			return (table->sp_code);
2316	return (-1);
2317}
2318
2319/*
2320 * Set input and output watermarks and buffer sizes.  For input, the
2321 * high watermark is about one second's worth of input above empty, the
2322 * low watermark is slightly below high water, and the buffer size is a
2323 * driver-dependent amount above high water.  For output, the watermarks
2324 * are near the ends of the buffer, with about 1 second's worth of input
2325 * between them.  All this only applies to the standard line discipline.
2326 */
2327void
2328ttsetwater(struct tty *tp)
2329{
2330	int cps, ttmaxhiwat, x;
2331
2332	/* Input. */
2333	clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
2334	switch (tp->t_ispeedwat) {
2335	case (speed_t)-1:
2336		cps = tp->t_ispeed / 10;
2337		break;
2338	case 0:
2339		/*
2340		 * This case is for old drivers that don't know about
2341		 * t_ispeedwat.  Arrange for them to get the old buffer
2342		 * sizes and watermarks.
2343		 */
2344		cps = TTYHOG - 2 * 256;
2345		tp->t_ififosize = 2 * 256;
2346		break;
2347	default:
2348		cps = tp->t_ispeedwat / 10;
2349		break;
2350	}
2351	tp->t_ihiwat = cps;
2352	tp->t_ilowat = 7 * cps / 8;
2353	x = cps + tp->t_ififosize;
2354	clist_alloc_cblocks(&tp->t_rawq, x, x);
2355
2356	/* Output. */
2357	switch (tp->t_ospeedwat) {
2358	case (speed_t)-1:
2359		cps = tp->t_ospeed / 10;
2360		ttmaxhiwat = 2 * TTMAXHIWAT;
2361		break;
2362	case 0:
2363		cps = tp->t_ospeed / 10;
2364		ttmaxhiwat = TTMAXHIWAT;
2365		break;
2366	default:
2367		cps = tp->t_ospeedwat / 10;
2368		ttmaxhiwat = 8 * TTMAXHIWAT;
2369		break;
2370	}
2371#define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
2372	tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
2373	x += cps;
2374	x = CLAMP(x, ttmaxhiwat, TTMINHIWAT);	/* XXX clamps are too magic */
2375	tp->t_ohiwat = roundup(x, CBSIZE);	/* XXX for compat */
2376	x = imax(tp->t_ohiwat, TTMAXHIWAT);	/* XXX for compat/safety */
2377	x += OBUFSIZ + 100;
2378	clist_alloc_cblocks(&tp->t_outq, x, x);
2379#undef	CLAMP
2380}
2381
2382/*
2383 * Report on state of foreground process group.
2384 */
2385void
2386ttyinfo(struct tty *tp)
2387{
2388	struct proc *p, *pick;
2389	struct timeval utime, stime;
2390	const char *stmp, *sprefix;
2391	long ltmp;
2392	int tmp;
2393	struct thread *td;
2394
2395	if (ttycheckoutq(tp,0) == 0)
2396		return;
2397
2398	/* Print load average. */
2399	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
2400	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
2401
2402	if (tp->t_session == NULL)
2403		ttyprintf(tp, "not a controlling terminal\n");
2404	else if (tp->t_pgrp == NULL)
2405		ttyprintf(tp, "no foreground process group\n");
2406	else {
2407		PGRP_LOCK(tp->t_pgrp);
2408		if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) {
2409			PGRP_UNLOCK(tp->t_pgrp);
2410			ttyprintf(tp, "empty foreground process group\n");
2411		} else {
2412			mtx_lock_spin(&sched_lock);
2413
2414			/* Pick interesting process. */
2415			for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist))
2416				if (proc_compare(pick, p))
2417					pick = p;
2418			PGRP_UNLOCK(tp->t_pgrp);
2419
2420			td = FIRST_THREAD_IN_PROC(pick);
2421			sprefix = "";
2422			if (pick->p_flag & P_SA) {
2423				stmp = "KSE" ;  /* XXXKSE */
2424			} else {
2425				if (td) {
2426					if (TD_ON_RUNQ(td) ||
2427					    (TD_IS_RUNNING(td))) {
2428						stmp = "running";
2429					} else if (TD_ON_LOCK(td)) {
2430						stmp = td->td_lockname;
2431						sprefix = "*";
2432					} else if (td->td_wmesg) {
2433						stmp = td->td_wmesg;
2434					} else {
2435						stmp = "iowait";
2436					}
2437				} else {
2438					stmp = "threadless";
2439					panic("ttyinfo: no thread!?");
2440				}
2441			}
2442			calcru(pick, &utime, &stime, NULL);
2443			if (pick->p_state == PRS_NEW ||
2444			    pick->p_state == PRS_ZOMBIE) {
2445				ltmp = 0;
2446			} else {
2447				ltmp = pgtok(
2448				    vmspace_resident_count(pick->p_vmspace));
2449			}
2450			mtx_unlock_spin(&sched_lock);
2451
2452			ttyprintf(tp, " cmd: %s %d [%s%s] ", pick->p_comm,
2453			    pick->p_pid, sprefix, stmp);
2454
2455			/* Print user time. */
2456			ttyprintf(tp, "%ld.%02ldu ",
2457			    utime.tv_sec, utime.tv_usec / 10000);
2458
2459			/* Print system time. */
2460			ttyprintf(tp, "%ld.%02lds ",
2461			    (long)stime.tv_sec, stime.tv_usec / 10000);
2462
2463			/* Print percentage cpu, resident set size. */
2464			ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp);
2465
2466		}
2467	}
2468	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
2469}
2470
2471/*
2472 * Returns 1 if p2 is "better" than p1
2473 *
2474 * The algorithm for picking the "interesting" process is thus:
2475 *
2476 *	1) Only foreground processes are eligible - implied.
2477 *	2) Runnable processes are favored over anything else.  The runner
2478 *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
2479 *	   broken by picking the highest pid.
2480 *	3) The sleeper with the shortest sleep time is next.  With ties,
2481 *	   we pick out just "short-term" sleepers (P_SINTR == 0).
2482 *	4) Further ties are broken by picking the highest pid.
2483 */
2484#define ISRUN(p, val)						\
2485do {								\
2486	struct thread *td;					\
2487	val = 0;						\
2488	FOREACH_THREAD_IN_PROC(p, td) {				\
2489		if (TD_ON_RUNQ(td) ||				\
2490		    TD_IS_RUNNING(td)) {			\
2491			val = 1;				\
2492			break;					\
2493		}						\
2494	}							\
2495} while (0)
2496
2497#define TESTAB(a, b)    ((a)<<1 | (b))
2498#define ONLYA   2
2499#define ONLYB   1
2500#define BOTH    3
2501
2502static int
2503proc_compare(struct proc *p1, struct proc *p2)
2504{
2505
2506	int esta, estb;
2507	struct ksegrp *kg;
2508	mtx_assert(&sched_lock, MA_OWNED);
2509	if (p1 == NULL)
2510		return (1);
2511
2512	ISRUN(p1, esta);
2513	ISRUN(p2, estb);
2514
2515	/*
2516	 * see if at least one of them is runnable
2517	 */
2518	switch (TESTAB(esta, estb)) {
2519	case ONLYA:
2520		return (0);
2521	case ONLYB:
2522		return (1);
2523	case BOTH:
2524		/*
2525		 * tie - favor one with highest recent cpu utilization
2526		 */
2527		esta = estb = 0;
2528		FOREACH_KSEGRP_IN_PROC(p1,kg) {
2529			esta += kg->kg_estcpu;
2530		}
2531		FOREACH_KSEGRP_IN_PROC(p2,kg) {
2532			estb += kg->kg_estcpu;
2533		}
2534		if (estb > esta)
2535			return (1);
2536		if (esta > estb)
2537			return (0);
2538		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
2539	}
2540	/*
2541	 * weed out zombies
2542	 */
2543	switch (TESTAB(p1->p_state == PRS_ZOMBIE, p2->p_state == PRS_ZOMBIE)) {
2544	case ONLYA:
2545		return (1);
2546	case ONLYB:
2547		return (0);
2548	case BOTH:
2549		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2550	}
2551
2552#if 0 /* XXXKSE */
2553	/*
2554	 * pick the one with the smallest sleep time
2555	 */
2556	if (p2->p_slptime > p1->p_slptime)
2557		return (0);
2558	if (p1->p_slptime > p2->p_slptime)
2559		return (1);
2560	/*
2561	 * favor one sleeping in a non-interruptible sleep
2562	 */
2563	if (p1->p_sflag & PS_SINTR && (p2->p_sflag & PS_SINTR) == 0)
2564		return (1);
2565	if (p2->p_sflag & PS_SINTR && (p1->p_sflag & PS_SINTR) == 0)
2566		return (0);
2567#endif
2568	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
2569}
2570
2571/*
2572 * Output char to tty; console putchar style.
2573 */
2574int
2575tputchar(int c, struct tty *tp)
2576{
2577	int s;
2578
2579	s = spltty();
2580	if (!ISSET(tp->t_state, TS_CONNECTED)) {
2581		splx(s);
2582		return (-1);
2583	}
2584	if (c == '\n')
2585		(void)ttyoutput('\r', tp);
2586	(void)ttyoutput(c, tp);
2587	ttstart(tp);
2588	splx(s);
2589	return (0);
2590}
2591
2592/*
2593 * Sleep on chan, returning ERESTART if tty changed while we napped and
2594 * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep.  If
2595 * the tty is revoked, restarting a pending call will redo validation done
2596 * at the start of the call.
2597 */
2598int
2599ttysleep(struct tty *tp, void *chan, int pri, char *wmesg, int timo)
2600{
2601	int error;
2602	int gen;
2603
2604	gen = tp->t_gen;
2605	error = tsleep(chan, pri, wmesg, timo);
2606	if (error)
2607		return (error);
2608	return (tp->t_gen == gen ? 0 : ERESTART);
2609}
2610
2611/*
2612 * Allocate a tty struct.  Clists in the struct will be allocated by
2613 * ttyopen().
2614 */
2615struct tty *
2616ttymalloc(struct tty *tp)
2617{
2618
2619	if (tp)
2620		return(tp);
2621	tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO);
2622	ttyregister(tp);
2623	return (tp);
2624}
2625
2626#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */
2627/*
2628 * Free a tty struct.  Clists in the struct should have been freed by
2629 * ttyclose().
2630 */
2631void
2632ttyfree(struct tty *tp)
2633{
2634	free(tp, M_TTYS);
2635}
2636#endif /* 0 */
2637
2638void
2639ttyregister(struct tty *tp)
2640{
2641	tp->t_timeout = -1;
2642	SLIST_INSERT_HEAD(&tty_list, tp, t_list);
2643}
2644
2645static int
2646sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
2647{
2648	struct tty *tp;
2649	struct xtty xt;
2650	int error;
2651
2652	SLIST_FOREACH(tp, &tty_list, t_list) {
2653		bzero(&xt, sizeof xt);
2654		xt.xt_size = sizeof xt;
2655#define XT_COPY(field) xt.xt_##field = tp->t_##field
2656		xt.xt_rawcc = tp->t_rawq.c_cc;
2657		xt.xt_cancc = tp->t_canq.c_cc;
2658		xt.xt_outcc = tp->t_outq.c_cc;
2659		XT_COPY(line);
2660		if (tp->t_dev)
2661			xt.xt_dev = dev2udev(tp->t_dev);
2662		XT_COPY(state);
2663		XT_COPY(flags);
2664		XT_COPY(timeout);
2665		if (tp->t_pgrp)
2666			xt.xt_pgid = tp->t_pgrp->pg_id;
2667		if (tp->t_session)
2668			xt.xt_sid = tp->t_session->s_sid;
2669		XT_COPY(termios);
2670		XT_COPY(winsize);
2671		XT_COPY(column);
2672		XT_COPY(rocount);
2673		XT_COPY(rocol);
2674		XT_COPY(ififosize);
2675		XT_COPY(ihiwat);
2676		XT_COPY(ilowat);
2677		XT_COPY(ispeedwat);
2678		XT_COPY(ohiwat);
2679		XT_COPY(olowat);
2680		XT_COPY(ospeedwat);
2681#undef XT_COPY
2682		error = SYSCTL_OUT(req, &xt, sizeof xt);
2683		if (error)
2684			return (error);
2685	}
2686	return (0);
2687}
2688
2689SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD,
2690	0, 0, sysctl_kern_ttys, "S,xtty", "All ttys");
2691SYSCTL_LONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD,
2692	&tk_nin, 0, "Total TTY in characters");
2693SYSCTL_LONG(_kern, OID_AUTO, tty_nout, CTLFLAG_RD,
2694	&tk_nout, 0, "Total TTY out characters");
2695
2696void
2697nottystop(struct tty *tp, int rw)
2698{
2699
2700	return;
2701}
2702
2703int
2704ttyread(dev_t dev, struct uio *uio, int flag)
2705{
2706	struct tty *tp;
2707
2708	tp = dev->si_tty;
2709	if (tp == NULL)
2710		return (ENODEV);
2711	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
2712}
2713
2714int
2715ttywrite(dev_t dev, struct uio *uio, int flag)
2716{
2717	struct tty *tp;
2718
2719	tp = dev->si_tty;
2720	if (tp == NULL)
2721		return (ENODEV);
2722	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
2723}
2724