tty.c revision 116182
1139743Simp/*-
239213Sgibbs * Copyright (c) 1982, 1986, 1990, 1991, 1993
3111206Sken *	The Regents of the University of California.  All rights reserved.
439213Sgibbs * (c) UNIX System Laboratories, Inc.
539213Sgibbs * All or some portions of this file are derived from material licensed
639213Sgibbs * to the University of California by American Telephone and Telegraph
739213Sgibbs * Co. or Unix System Laboratories, Inc. and are reproduced herein with
839213Sgibbs * the permission of UNIX System Laboratories, Inc.
939213Sgibbs *
1039213Sgibbs * Copyright (c) 2002 Networks Associates Technologies, Inc.
1139213Sgibbs * All rights reserved.
1239213Sgibbs *
1339213Sgibbs * Portions of this software were developed for the FreeBSD Project by
1439213Sgibbs * ThinkSec AS and NAI Labs, the Security Research Division of Network
1539213Sgibbs * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
1639213Sgibbs * ("CBOSS"), as part of the DARPA CHATS research program.
1739213Sgibbs *
1839213Sgibbs * Redistribution and use in source and binary forms, with or without
1939213Sgibbs * modification, are permitted provided that the following conditions
2039213Sgibbs * are met:
2139213Sgibbs * 1. Redistributions of source code must retain the above copyright
2239213Sgibbs *    notice, this list of conditions and the following disclaimer.
2339213Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
2439213Sgibbs *    notice, this list of conditions and the following disclaimer in the
2539213Sgibbs *    documentation and/or other materials provided with the distribution.
2639213Sgibbs * 3. All advertising materials mentioning features or use of this software
27116162Sobrien *    must display the following acknowledgement:
28139743Simp *	This product includes software developed by the University of
2939213Sgibbs *	California, Berkeley and its contributors.
3039213Sgibbs * 4. Neither the name of the University nor the names of its contributors
3139213Sgibbs *    may be used to endorse or promote products derived from this software
3239213Sgibbs *    without specific prior written permission.
3339213Sgibbs *
3439213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3539213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3639213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3739213Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3839213Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3939213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4039213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4139213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4239213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4339213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4439213Sgibbs * SUCH DAMAGE.
4539213Sgibbs *
4639213Sgibbs *	@(#)tty.c	8.8 (Berkeley) 1/21/94
4739213Sgibbs */
48116162Sobrien
49116162Sobrien/*-
50116162Sobrien * TODO:
5140020Sken *	o Fix races for sending the start char in ttyflush().
5239213Sgibbs *	o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
5339213Sgibbs *	  With luck, there will be MIN chars before select() returns().
5439213Sgibbs *	o Handle CLOCAL consistently for ptys.  Perhaps disallow setting it.
5539213Sgibbs *	o Don't allow input in TS_ZOMBIE case.  It would be visible through
5660041Sphk *	  FIONREAD.
5751836Sphk *	o Do the new sio locking stuff here and use it to avoid special
5851836Sphk *	  case for EXTPROC?
5939213Sgibbs *	o Lock PENDIN too?
6039213Sgibbs *	o Move EXTPROC and/or PENDIN to t_state?
61105421Snjl *	o Wrap most of ttioctl in spltty/splx.
6260422Sken *	o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
6339213Sgibbs *	o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
6439213Sgibbs *	o Don't allow certain termios flags to affect disciplines other
65119708Sken *	  than TTYDISC.  Cancel their effects before switch disciplines
66120599Sphk *	  and ignore them if they are set while we are in another
6739213Sgibbs *	  discipline.
6839213Sgibbs *	o Now that historical speed conversions are handled here, don't
6939213Sgibbs *	  do them in drivers.
7039213Sgibbs *	o Check for TS_CARR_ON being set while everything is closed and not
7139213Sgibbs *	  waiting for carrier.  TS_CARR_ON isn't cleared if nothing is open,
7239213Sgibbs *	  so it would live until the next open even if carrier drops.
73168752Sscottl *	o Restore TS_WOPEN since it is useful in pstat.  It must be cleared
7439213Sgibbs *	  only when _all_ openers leave open().
7539213Sgibbs */
7639213Sgibbs
7739213Sgibbs#include <sys/cdefs.h>
7839213Sgibbs__FBSDID("$FreeBSD: head/sys/kern/tty.c 116182 2003-06-11 00:56:59Z obrien $");
7939213Sgibbs
8039213Sgibbs#include "opt_compat.h"
8139213Sgibbs#include "opt_tty.h"
8239213Sgibbs
8339213Sgibbs#include <sys/param.h>
8439213Sgibbs#include <sys/systm.h>
8539213Sgibbs#include <sys/filio.h>
8639213Sgibbs#include <sys/lock.h>
87111206Sken#include <sys/mutex.h>
88111206Sken#include <sys/namei.h>
89111206Sken#include <sys/sx.h>
90111206Sken#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
91111206Sken#include <sys/ioctl_compat.h>
92111206Sken#endif
9339213Sgibbs#include <sys/proc.h>
9439213Sgibbs#define	TTYDEFCHARS
9539213Sgibbs#include <sys/tty.h>
96120884Sthomas#undef	TTYDEFCHARS
97120884Sthomas#include <sys/fcntl.h>
98120884Sthomas#include <sys/conf.h>
99120884Sthomas#include <sys/poll.h>
100120884Sthomas#include <sys/kernel.h>
101120884Sthomas#include <sys/vnode.h>
102120884Sthomas#include <sys/signalvar.h>
103120884Sthomas#include <sys/resourcevar.h>
104120884Sthomas#include <sys/malloc.h>
105120884Sthomas#include <sys/filedesc.h>
106120884Sthomas#include <sys/sysctl.h>
107168752Sscottl
108168752Sscottl#include <vm/vm.h>
10939213Sgibbs#include <vm/pmap.h>
11039213Sgibbs#include <vm/vm_map.h>
11139213Sgibbs
11239213SgibbsMALLOC_DEFINE(M_TTYS, "ttys", "tty data structures");
11339213Sgibbs
11439213Sgibbslong tk_cancc;
11539213Sgibbslong tk_nin;
11639213Sgibbslong tk_nout;
11739213Sgibbslong tk_rawcc;
11839213Sgibbs
11939213Sgibbsstatic int	proc_compare(struct proc *p1, struct proc *p2);
12039213Sgibbsstatic int	ttnread(struct tty *tp);
12139213Sgibbsstatic void	ttyecho(int c, struct tty *tp);
12239213Sgibbsstatic int	ttyoutput(int c, struct tty *tp);
12339213Sgibbsstatic void	ttypend(struct tty *tp);
12439213Sgibbsstatic void	ttyretype(struct tty *tp);
12539213Sgibbsstatic void	ttyrub(int c, struct tty *tp);
12639213Sgibbsstatic void	ttyrubo(struct tty *tp, int cnt);
12739213Sgibbsstatic void	ttyunblock(struct tty *tp);
12839213Sgibbsstatic int	ttywflush(struct tty *tp);
129111206Skenstatic int	filt_ttyread(struct knote *kn, long hint);
130111206Skenstatic void	filt_ttyrdetach(struct knote *kn);
131111206Skenstatic int	filt_ttywrite(struct knote *kn, long hint);
132111206Skenstatic void	filt_ttywdetach(struct knote *kn);
133111206Sken
134111206Sken/*
135111206Sken * Table with character classes and parity. The 8th bit indicates parity,
136111206Sken * the 7th bit indicates the character is an alphameric or underscore (for
137111206Sken * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
138111206Sken * are 0 then the character needs no special processing on output; classes
13939213Sgibbs * other than 0 might be translated or (not currently) require delays.
14039213Sgibbs */
14139213Sgibbs#define	E	0x00	/* Even parity. */
14239213Sgibbs#define	O	0x80	/* Odd parity. */
14339213Sgibbs#define	PARITY(c)	(char_type[c] & O)
14439213Sgibbs
14539213Sgibbs#define	ALPHA	0x40	/* Alpha or underscore. */
14639213Sgibbs#define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
14746581Sken
14859249Sphk#define	CCLASSMASK	0x3f
14960938Sjake#define	CCLASS(c)	(char_type[c] & CCLASSMASK)
15039213Sgibbs
15139213Sgibbs#define	BS	BACKSPACE
15239213Sgibbs#define	CC	CONTROL
15360938Sjake#define	CR	RETURN
15439213Sgibbs#define	NA	ORDINARY | ALPHA
15539213Sgibbs#define	NL	NEWLINE
15639213Sgibbs#define	NO	ORDINARY
157111206Sken#define	TB	TAB
158112262Sphk#define	VT	VTAB
159119708Sken
160111206Skenstatic u_char const char_type[] = {
161111206Sken	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
162111206Sken	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
163111206Sken	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
164125975Sphk	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
16539213Sgibbs	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
16639213Sgibbs	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
167111206Sken	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
168111206Sken	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
169111206Sken	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
170111206Sken	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
171111206Sken	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
172111206Sken	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
173111206Sken	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
174111206Sken	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
175111206Sken	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
176111206Sken	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
17739213Sgibbs	/*
17839213Sgibbs	 * Meta chars; should be settable per character set;
17939213Sgibbs	 * for now, treat them all as normal characters.
18039213Sgibbs	 */
18139213Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
18239213Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
183111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
184111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
185111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
186111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
187111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
18839213Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
189111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
190111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
191111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
192111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
193111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
194111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
195111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
196111206Sken	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
197111206Sken};
198111206Sken#undef	BS
19939213Sgibbs#undef	CC
20039213Sgibbs#undef	CR
20139213Sgibbs#undef	NA
20239213Sgibbs#undef	NL
20339213Sgibbs#undef	NO
20439213Sgibbs#undef	TB
20539213Sgibbs#undef	VT
20639213Sgibbs
20754451Sken/* Macros to clear/set/test flags. */
20839213Sgibbs#define	SET(t, f)	(t) |= (f)
20940262Sken#define	CLR(t, f)	(t) &= ~(f)
21040262Sken#define	ISSET(t, f)	((t) & (f))
21167752Sken
21267752Sken#undef MAX_INPUT		/* XXX wrong in <sys/syslimits.h> */
21367752Sken#define	MAX_INPUT	TTYHOG	/* XXX limit is usually larger for !ICANON */
21467752Sken
21540262Sken/*
21640262Sken * list of struct tty where pstat(8) can pick it up with sysctl
21739213Sgibbs */
21839213Sgibbsstatic SLIST_HEAD(, tty) tty_list;
21939213Sgibbs
220120599Sphkstatic int  drainwait = 5*60;
221120599SphkSYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait,
222120599Sphk	0, "Output drain timeout in seconds");
223120599Sphk
22439213Sgibbs/*
22539213Sgibbs * Initial open of tty, or (re)entry to standard tty line discipline.
22639213Sgibbs */
22739213Sgibbsint
22839213Sgibbsttyopen(dev_t device, struct tty *tp)
22940603Sken{
23039213Sgibbs	int s;
23139213Sgibbs
232111206Sken	s = spltty();
23339213Sgibbs	tp->t_dev = device;
23439213Sgibbs	if (!ISSET(tp->t_state, TS_ISOPEN)) {
23539213Sgibbs		SET(tp->t_state, TS_ISOPEN);
23639213Sgibbs		if (ISSET(tp->t_cflag, CLOCAL))
23739213Sgibbs			SET(tp->t_state, TS_CONNECTED);
23839213Sgibbs		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
23939213Sgibbs	}
24039213Sgibbs	/* XXX don't hang forever on output */
24139213Sgibbs	if (tp->t_timeout < 0)
242111206Sken		tp->t_timeout = drainwait*hz;
24339213Sgibbs	ttsetwater(tp);
24439213Sgibbs	splx(s);
24539213Sgibbs	return (0);
246111206Sken}
247111206Sken
248111206Sken/*
249111206Sken * Handle close() on a tty line: flush and set to initial state,
250111206Sken * bumping generation number so that pending read/write calls
251111206Sken * can detect recycling of the tty.
25239213Sgibbs * XXX our caller should have done `spltty(); l_close(); ttyclose();'
25339213Sgibbs * and l_close() should have flushed, but we repeat the spltty() and
25439213Sgibbs * the flush in case there are buggy callers.
255111206Sken */
256111206Skenint
25739213Sgibbsttyclose(struct tty *tp)
258111206Sken{
25939213Sgibbs	int s;
260111206Sken
26139213Sgibbs	funsetown(&tp->t_sigio);
26239213Sgibbs	s = spltty();
26339213Sgibbs	if (constty == tp)
26439213Sgibbs		constty = NULL;
26539213Sgibbs
26639213Sgibbs	ttyflush(tp, FREAD | FWRITE);
26739213Sgibbs	clist_free_cblocks(&tp->t_canq);
26839213Sgibbs	clist_free_cblocks(&tp->t_outq);
26939213Sgibbs	clist_free_cblocks(&tp->t_rawq);
27039213Sgibbs
27139213Sgibbs	tp->t_gen++;
27239213Sgibbs	tp->t_line = TTYDISC;
27339213Sgibbs	tp->t_pgrp = NULL;
27439213Sgibbs	tp->t_session = NULL;
27539213Sgibbs	tp->t_state = 0;
27639213Sgibbs	splx(s);
277111206Sken	return (0);
278105421Snjl}
279105421Snjl
28060422Sken#define	FLUSHQ(q) {							\
28160422Sken	if ((q)->c_cc)							\
28260422Sken		ndflush(q, (q)->c_cc);					\
28360422Sken}
28460422Sken
28560422Sken/* Is 'c' a line delimiter ("break" character)? */
28639213Sgibbs#define	TTBREAKC(c, lflag)							\
28739213Sgibbs	((c) == '\n' || (((c) == cc[VEOF] ||				\
28839213Sgibbs	  (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) &&	\
28939213Sgibbs	 (c) != _POSIX_VDISABLE))
29039213Sgibbs
29139213Sgibbs/*
29239213Sgibbs * Process input of a single character received on a tty.
29372119Speter */
29439213Sgibbsint
29539213Sgibbsttyinput(int c, struct tty *tp)
29646747Sken{
29739213Sgibbs	tcflag_t iflag, lflag;
29839213Sgibbs	cc_t *cc;
29946747Sken	int i, err;
30039213Sgibbs
30139213Sgibbs	/*
30239213Sgibbs	 * If input is pending take it first.
30339213Sgibbs	 */
30439213Sgibbs	lflag = tp->t_lflag;
30539213Sgibbs	if (ISSET(lflag, PENDIN))
30639213Sgibbs		ttypend(tp);
30739213Sgibbs	/*
30839213Sgibbs	 * Gather stats.
309111206Sken	 */
31039213Sgibbs	if (ISSET(lflag, ICANON)) {
31139213Sgibbs		++tk_cancc;
312111206Sken		++tp->t_cancc;
31339213Sgibbs	} else {
31439213Sgibbs		++tk_rawcc;
31539213Sgibbs		++tp->t_rawcc;
31639213Sgibbs	}
31739213Sgibbs	++tk_nin;
31839213Sgibbs
31939213Sgibbs	/*
32039213Sgibbs	 * Block further input iff:
321168752Sscottl	 * current input > threshold AND input is available to user program
322168752Sscottl	 * AND input flow control is enabled and not yet invoked.
32346581Sken	 * The 3 is slop for PARMRK.
32460938Sjake	 */
32560938Sjake	iflag = tp->t_iflag;
32639213Sgibbs	if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 &&
32739213Sgibbs	    (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
328168752Sscottl	    (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
32960938Sjake	    !ISSET(tp->t_state, TS_TBLOCK))
330168752Sscottl		ttyblock(tp);
33139213Sgibbs
332169562Sscottl	/* Handle exceptional conditions (break, parity, framing). */
333169562Sscottl	cc = tp->t_cc;
334104880Sphk	err = (ISSET(c, TTY_ERRORMASK));
33539213Sgibbs	if (err) {
33639213Sgibbs		CLR(c, TTY_ERRORMASK);
33739213Sgibbs		if (ISSET(err, TTY_BI)) {
33839213Sgibbs			if (ISSET(iflag, IGNBRK))
339168752Sscottl				return (0);
340168752Sscottl			if (ISSET(iflag, BRKINT)) {
341168752Sscottl				ttyflush(tp, FREAD | FWRITE);
34239213Sgibbs				if (tp->t_pgrp != NULL) {
34339213Sgibbs					PGRP_LOCK(tp->t_pgrp);
34439213Sgibbs					pgsignal(tp->t_pgrp, SIGINT, 1);
34539213Sgibbs					PGRP_UNLOCK(tp->t_pgrp);
346169605Sscottl				}
34739213Sgibbs				goto endcase;
34839213Sgibbs			}
34939213Sgibbs			if (ISSET(iflag, PARMRK))
35039213Sgibbs				goto parmrk;
35139213Sgibbs		} else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
35239213Sgibbs			|| ISSET(err, TTY_FE)) {
35339213Sgibbs			if (ISSET(iflag, IGNPAR))
35439213Sgibbs				return (0);
35540603Sken			else if (ISSET(iflag, PARMRK)) {
35640603Skenparmrk:
35740603Sken				if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
35840603Sken				    MAX_INPUT - 3)
35940603Sken					goto input_overflow;
36040603Sken				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
36140603Sken				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
36240603Sken				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
36340603Sken				goto endcase;
364169605Sscottl			} else
36540603Sken				c = 0;
36640603Sken		}
36740603Sken	}
36840603Sken
36940603Sken	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
37040603Sken		CLR(c, 0x80);
37140603Sken	if (!ISSET(lflag, EXTPROC)) {
37240603Sken		/*
373112946Sphk		 * Check for literal nexting very first
37440603Sken		 */
37540603Sken		if (ISSET(tp->t_state, TS_LNCH)) {
37640603Sken			SET(c, TTY_QUOTE);
37740603Sken			CLR(tp->t_state, TS_LNCH);
37840603Sken		}
37940603Sken		/*
38040603Sken		 * Scan for special characters.  This code
38140603Sken		 * is really just a big case statement with
38240603Sken		 * non-constant cases.  The bottom of the
38340603Sken		 * case statement is labeled ``endcase'', so goto
384152565Sjdp		 * it after a case match, or similar.
385164906Smjacob		 */
38640603Sken
38740603Sken		/*
38840603Sken		 * Control chars which aren't controlled
38939213Sgibbs		 * by ICANON, ISIG, or IXON.
39039213Sgibbs		 */
39139213Sgibbs		if (ISSET(lflag, IEXTEN)) {
39239213Sgibbs			if (CCEQ(cc[VLNEXT], c)) {
39339213Sgibbs				if (ISSET(lflag, ECHO)) {
39439213Sgibbs					if (ISSET(lflag, ECHOE)) {
395164906Smjacob						(void)ttyoutput('^', tp);
39640603Sken						(void)ttyoutput('\b', tp);
397120884Sthomas					} else
398120884Sthomas						ttyecho(c, tp);
399164906Smjacob				}
400112668Sken				SET(tp->t_state, TS_LNCH);
401112668Sken				goto endcase;
40239213Sgibbs			}
40339213Sgibbs			if (CCEQ(cc[VDISCARD], c)) {
40439213Sgibbs				if (ISSET(lflag, FLUSHO))
40539213Sgibbs					CLR(tp->t_lflag, FLUSHO);
40639213Sgibbs				else {
40739213Sgibbs					ttyflush(tp, FWRITE);
40839213Sgibbs					ttyecho(c, tp);
40939213Sgibbs					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
41039213Sgibbs						ttyretype(tp);
41139213Sgibbs					SET(tp->t_lflag, FLUSHO);
41239213Sgibbs				}
41339213Sgibbs				goto startoutput;
41439213Sgibbs			}
41539213Sgibbs		}
41639213Sgibbs		/*
41739213Sgibbs		 * Signals.
41839213Sgibbs		 */
41939213Sgibbs		if (ISSET(lflag, ISIG)) {
42039213Sgibbs			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
42139213Sgibbs				if (!ISSET(lflag, NOFLSH))
42239213Sgibbs					ttyflush(tp, FREAD | FWRITE);
42339213Sgibbs				ttyecho(c, tp);
42439213Sgibbs				if (tp->t_pgrp != NULL) {
42539213Sgibbs					PGRP_LOCK(tp->t_pgrp);
42639213Sgibbs					pgsignal(tp->t_pgrp,
42739213Sgibbs					    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
42839213Sgibbs					PGRP_UNLOCK(tp->t_pgrp);
42939213Sgibbs				}
43039213Sgibbs				goto endcase;
431168752Sscottl			}
43239213Sgibbs			if (CCEQ(cc[VSUSP], c)) {
43339213Sgibbs				if (!ISSET(lflag, NOFLSH))
43439213Sgibbs					ttyflush(tp, FREAD);
43539213Sgibbs				ttyecho(c, tp);
43639213Sgibbs				if (tp->t_pgrp != NULL) {
43739213Sgibbs					PGRP_LOCK(tp->t_pgrp);
43839213Sgibbs					pgsignal(tp->t_pgrp, SIGTSTP, 1);
43939213Sgibbs					PGRP_UNLOCK(tp->t_pgrp);
44039213Sgibbs				}
44139213Sgibbs				goto endcase;
44239213Sgibbs			}
44339213Sgibbs		}
44439213Sgibbs		/*
44539213Sgibbs		 * Handle start/stop characters.
44639213Sgibbs		 */
44739213Sgibbs		if (ISSET(iflag, IXON)) {
44839213Sgibbs			if (CCEQ(cc[VSTOP], c)) {
44939213Sgibbs				if (!ISSET(tp->t_state, TS_TTSTOP)) {
45039213Sgibbs					SET(tp->t_state, TS_TTSTOP);
45139213Sgibbs					(*tp->t_stop)(tp, 0);
452168752Sscottl					return (0);
45339213Sgibbs				}
45439213Sgibbs				if (!CCEQ(cc[VSTART], c))
45539213Sgibbs					return (0);
45639213Sgibbs				/*
457168752Sscottl				 * if VSTART == VSTOP then toggle
45839213Sgibbs				 */
45939213Sgibbs				goto endcase;
46039213Sgibbs			}
461168752Sscottl			if (CCEQ(cc[VSTART], c))
46260938Sjake				goto restartoutput;
46339213Sgibbs		}
464168752Sscottl		/*
465168752Sscottl		 * IGNCR, ICRNL, & INLCR
466164906Smjacob		 */
46739213Sgibbs		if (c == '\r') {
46839213Sgibbs			if (ISSET(iflag, IGNCR))
469168786Sscottl				return (0);
470125975Sphk			else if (ISSET(iflag, ICRNL))
471168786Sscottl				c = '\n';
47240603Sken		} else if (c == '\n' && ISSET(iflag, INLCR))
47339213Sgibbs			c = '\r';
47439213Sgibbs	}
47539213Sgibbs	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
47639213Sgibbs		/*
47739213Sgibbs		 * From here on down canonical mode character
47839213Sgibbs		 * processing takes place.
47939213Sgibbs		 */
48039213Sgibbs		/*
48139213Sgibbs		 * erase or erase2 (^H / ^?)
48239213Sgibbs		 */
48339213Sgibbs		if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) {
48439213Sgibbs			if (tp->t_rawq.c_cc)
48539213Sgibbs				ttyrub(unputc(&tp->t_rawq), tp);
48639213Sgibbs			goto endcase;
48739213Sgibbs		}
48839213Sgibbs		/*
48979177Smjacob		 * kill (^U)
49079177Smjacob		 */
49139213Sgibbs		if (CCEQ(cc[VKILL], c)) {
49256148Smjacob			if (ISSET(lflag, ECHOKE) &&
49356148Smjacob			    tp->t_rawq.c_cc == tp->t_rocount &&
49439213Sgibbs			    !ISSET(lflag, ECHOPRT))
49539213Sgibbs				while (tp->t_rawq.c_cc)
49639213Sgibbs					ttyrub(unputc(&tp->t_rawq), tp);
49739213Sgibbs			else {
49839213Sgibbs				ttyecho(c, tp);
49939213Sgibbs				if (ISSET(lflag, ECHOK) ||
50039213Sgibbs				    ISSET(lflag, ECHOKE))
50140603Sken					ttyecho('\n', tp);
50240603Sken				FLUSHQ(&tp->t_rawq);
50340603Sken				tp->t_rocount = 0;
50440603Sken			}
50540603Sken			CLR(tp->t_state, TS_LOCAL);
50639213Sgibbs			goto endcase;
50739213Sgibbs		}
50839213Sgibbs		/*
50939213Sgibbs		 * word erase (^W)
51039213Sgibbs		 */
51139213Sgibbs		if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
51239213Sgibbs			int ctype;
51339213Sgibbs
51439213Sgibbs			/*
51539213Sgibbs			 * erase whitespace
51639213Sgibbs			 */
51739213Sgibbs			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
51839213Sgibbs				ttyrub(c, tp);
51939213Sgibbs			if (c == -1)
52039213Sgibbs				goto endcase;
52139213Sgibbs			/*
52239213Sgibbs			 * erase last char of word and remember the
52339213Sgibbs			 * next chars type (for ALTWERASE)
52439213Sgibbs			 */
52539213Sgibbs			ttyrub(c, tp);
52671999Sphk			c = unputc(&tp->t_rawq);
52739213Sgibbs			if (c == -1)
52847413Sgibbs				goto endcase;
52939213Sgibbs			if (c == ' ' || c == '\t') {
53039213Sgibbs				(void)putc(c, &tp->t_rawq);
53147413Sgibbs				goto endcase;
53239213Sgibbs			}
53339213Sgibbs			ctype = ISALPHA(c);
53439213Sgibbs			/*
53539213Sgibbs			 * erase rest of word
536119708Sken			 */
537119708Sken			do {
538119708Sken				ttyrub(c, tp);
539119708Sken				c = unputc(&tp->t_rawq);
540119708Sken				if (c == -1)
541119708Sken					goto endcase;
542119708Sken			} while (c != ' ' && c != '\t' &&
543119708Sken			    (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
544168752Sscottl			(void)putc(c, &tp->t_rawq);
545168752Sscottl			goto endcase;
546168752Sscottl		}
547119708Sken		/*
548119708Sken		 * reprint line (^R)
549119708Sken		 */
550119708Sken		if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
551119708Sken			ttyretype(tp);
552119708Sken			goto endcase;
553119708Sken		}
554120884Sthomas		/*
555119708Sken		 * ^T - kernel info and generate SIGINFO
556119708Sken		 */
557119708Sken		if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
558119708Sken			if (ISSET(lflag, ISIG) && tp->t_pgrp != NULL) {
559119708Sken				PGRP_LOCK(tp->t_pgrp);
560119708Sken				pgsignal(tp->t_pgrp, SIGINFO, 1);
561160345Sdelphij				PGRP_UNLOCK(tp->t_pgrp);
562168752Sscottl			}
563119708Sken			if (!ISSET(lflag, NOKERNINFO))
564119708Sken				ttyinfo(tp);
565119708Sken			goto endcase;
566119708Sken		}
567119708Sken	}
568119708Sken	/*
569119708Sken	 * Check for input buffer overflow
570119708Sken	 */
571119708Sken	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
572119708Skeninput_overflow:
573119708Sken		if (ISSET(iflag, IMAXBEL)) {
574119708Sken			if (tp->t_outq.c_cc < tp->t_ohiwat)
575119708Sken				(void)ttyoutput(CTRL('g'), tp);
576168752Sscottl		}
577119708Sken		goto endcase;
578119708Sken	}
579111206Sken
580111206Sken	if (   c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
581111206Sken	     && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
582111206Sken		(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
583111206Sken
584111206Sken	/*
585111206Sken	 * Put data char in q for user and
586111206Sken	 * wakeup on seeing a line delimiter.
587111206Sken	 */
588111206Sken	if (putc(c, &tp->t_rawq) >= 0) {
589111206Sken		if (!ISSET(lflag, ICANON)) {
590111206Sken			ttwakeup(tp);
591111206Sken			ttyecho(c, tp);
592111206Sken			goto endcase;
593111206Sken		}
594111206Sken		if (TTBREAKC(c, lflag)) {
595111206Sken			tp->t_rocount = 0;
596111206Sken			catq(&tp->t_rawq, &tp->t_canq);
597111206Sken			ttwakeup(tp);
598111206Sken		} else if (tp->t_rocount++ == 0)
599111206Sken			tp->t_rocol = tp->t_column;
600111206Sken		if (ISSET(tp->t_state, TS_ERASE)) {
601111206Sken			/*
602111206Sken			 * end of prterase \.../
603111206Sken			 */
604111206Sken			CLR(tp->t_state, TS_ERASE);
605111206Sken			(void)ttyoutput('/', tp);
606111206Sken		}
607111206Sken		i = tp->t_column;
608111206Sken		ttyecho(c, tp);
609111206Sken		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
610111206Sken			/*
611111206Sken			 * Place the cursor over the '^' of the ^D.
612111206Sken			 */
613111206Sken			i = imin(2, tp->t_column - i);
614111206Sken			while (i > 0) {
615111206Sken				(void)ttyoutput('\b', tp);
61639213Sgibbs				i--;
61739213Sgibbs			}
61839213Sgibbs		}
61939213Sgibbs	}
620118105Snjlendcase:
62139213Sgibbs	/*
622119708Sken	 * IXANY means allow any character to restart output.
62339213Sgibbs	 */
62439213Sgibbs	if (ISSET(tp->t_state, TS_TTSTOP) &&
62539213Sgibbs	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
62639213Sgibbs		return (0);
62739213Sgibbsrestartoutput:
62839213Sgibbs	CLR(tp->t_lflag, FLUSHO);
62939213Sgibbs	CLR(tp->t_state, TS_TTSTOP);
63039213Sgibbsstartoutput:
63139213Sgibbs	return (ttstart(tp));
63239213Sgibbs}
63339213Sgibbs
63439213Sgibbs/*
63539213Sgibbs * Output a single character on a tty, doing output processing
63639213Sgibbs * as needed (expanding tabs, newline processing, etc.).
63739213Sgibbs * Returns < 0 if succeeds, otherwise returns char to resend.
63839213Sgibbs * Must be recursive.
63939213Sgibbs */
64039213Sgibbsstatic int
64139213Sgibbsttyoutput(int c, struct tty *tp)
64239213Sgibbs{
64339213Sgibbs	tcflag_t oflag;
64439213Sgibbs	int col, s;
645111206Sken
64639213Sgibbs	oflag = tp->t_oflag;
64759249Sphk	if (!ISSET(oflag, OPOST)) {
64839213Sgibbs		if (ISSET(tp->t_lflag, FLUSHO))
64939213Sgibbs			return (-1);
65039213Sgibbs		if (putc(c, &tp->t_outq))
65139213Sgibbs			return (c);
65239213Sgibbs		tk_nout++;
65339213Sgibbs		tp->t_outcc++;
65439213Sgibbs		return (-1);
65539213Sgibbs	}
65639213Sgibbs	/*
65739213Sgibbs	 * Do tab expansion if OXTABS is set.  Special case if we external
65839213Sgibbs	 * processing, we don't do the tab expansion because we'll probably
65939213Sgibbs	 * get it wrong.  If tab expansion needs to be done, let it happen
66039213Sgibbs	 * externally.
66139213Sgibbs	 */
66239213Sgibbs	CLR(c, ~TTY_CHARMASK);
66339213Sgibbs	if (c == '\t' &&
66439213Sgibbs	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
66539213Sgibbs		c = 8 - (tp->t_column & 7);
66639213Sgibbs		if (!ISSET(tp->t_lflag, FLUSHO)) {
66739213Sgibbs			s = spltty();		/* Don't interrupt tabs. */
66839213Sgibbs			c -= b_to_q("        ", c, &tp->t_outq);
669118105Snjl			tk_nout += c;
670118105Snjl			tp->t_outcc += c;
671118105Snjl			splx(s);
672118105Snjl		}
673118105Snjl		tp->t_column += c;
674118105Snjl		return (c ? -1 : '\t');
675118105Snjl	}
676119708Sken	if (c == CEOT && ISSET(oflag, ONOEOT))
677111206Sken		return (-1);
678111206Sken
679111206Sken	/*
680111206Sken	 * Newline translation: if ONLCR is set,
681111206Sken	 * translate newline into "\r\n".
682111206Sken	 */
683111206Sken	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
68439213Sgibbs		tk_nout++;
685111206Sken		tp->t_outcc++;
686111206Sken		if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
687111206Sken			return (c);
688111206Sken	}
689111206Sken	/* If OCRNL is set, translate "\r" into "\n". */
690111206Sken	else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
691111206Sken		c = '\n';
692111206Sken	/* If ONOCR is set, don't transmit CRs when on column 0. */
693111206Sken	else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0)
694111206Sken		return (-1);
695111206Sken
696111206Sken	tk_nout++;
697111206Sken	tp->t_outcc++;
69839213Sgibbs	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
69939213Sgibbs		return (c);
70039213Sgibbs
70139213Sgibbs	col = tp->t_column;
70239213Sgibbs	switch (CCLASS(c)) {
70356148Smjacob	case BACKSPACE:
70439213Sgibbs		if (col > 0)
70539213Sgibbs			--col;
70639213Sgibbs		break;
70739213Sgibbs	case CONTROL:
70839213Sgibbs		break;
709168752Sscottl	case NEWLINE:
710125975Sphk		if (ISSET(tp->t_oflag, ONLCR | ONLRET))
711125975Sphk			col = 0;
71239213Sgibbs		break;
71339213Sgibbs	case RETURN:
71443819Sken		col = 0;
71543819Sken		break;
716125975Sphk	case ORDINARY:
717125975Sphk		++col;
718125975Sphk		break;
719125975Sphk	case TAB:
720125975Sphk		col = (col + 8) & ~7;
721125975Sphk		break;
722125975Sphk	}
723168752Sscottl	tp->t_column = col;
724125975Sphk	return (-1);
725168752Sscottl}
72639213Sgibbs
72739213Sgibbs/*
72839213Sgibbs * Ioctls for all tty devices.  Called after line-discipline specific ioctl
72939213Sgibbs * has been called to do discipline-specific functions and/or reject any
73039213Sgibbs * of these ioctl commands.
731169605Sscottl */
732169605Sscottl/* ARGSUSED */
73339213Sgibbsint
73439213Sgibbsttioctl(struct tty *tp, u_long cmd, void *data, int flag)
73539213Sgibbs{
73639213Sgibbs	struct proc *p;
73739213Sgibbs	struct thread *td;
73839213Sgibbs	struct pgrp *pgrp;
73939213Sgibbs	int s, error;
74039213Sgibbs
74139213Sgibbs	td = curthread;			/* XXX */
74239213Sgibbs	p = td->td_proc;
74339213Sgibbs
74439213Sgibbs	/* If the ioctl involves modification, hang if in the background. */
74539213Sgibbs	switch (cmd) {
74639213Sgibbs	case  TIOCCBRK:
74739213Sgibbs	case  TIOCCONS:
74839213Sgibbs	case  TIOCDRAIN:
74939213Sgibbs	case  TIOCEXCL:
75039213Sgibbs	case  TIOCFLUSH:
75139213Sgibbs#ifdef TIOCHPCL
75239213Sgibbs	case  TIOCHPCL:
75339213Sgibbs#endif
75439213Sgibbs	case  TIOCNXCL:
75539213Sgibbs	case  TIOCSBRK:
75639213Sgibbs	case  TIOCSCTTY:
75739213Sgibbs	case  TIOCSDRAINWAIT:
75839213Sgibbs	case  TIOCSETA:
759168752Sscottl	case  TIOCSETAF:
76039213Sgibbs	case  TIOCSETAW:
76139213Sgibbs	case  TIOCSETD:
76239213Sgibbs	case  TIOCSPGRP:
76339213Sgibbs	case  TIOCSTART:
76439213Sgibbs	case  TIOCSTAT:
76539213Sgibbs	case  TIOCSTI:
76639213Sgibbs	case  TIOCSTOP:
76739213Sgibbs	case  TIOCSWINSZ:
76839213Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
76939213Sgibbs	case  TIOCLBIC:
770168752Sscottl	case  TIOCLBIS:
77139213Sgibbs	case  TIOCLSET:
77239213Sgibbs	case  TIOCSETC:
77339213Sgibbs	case OTIOCSETD:
77439213Sgibbs	case  TIOCSETN:
77539213Sgibbs	case  TIOCSETP:
77639213Sgibbs	case  TIOCSLTC:
77739213Sgibbs#endif
77839213Sgibbs		sx_slock(&proctree_lock);
77939213Sgibbs		PROC_LOCK(p);
78039213Sgibbs		while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) &&
78139213Sgibbs		    !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) &&
78239213Sgibbs		    !SIGISMEMBER(td->td_sigmask, SIGTTOU)) {
78339213Sgibbs			pgrp = p->p_pgrp;
78439213Sgibbs			PROC_UNLOCK(p);
78539213Sgibbs			if (pgrp->pg_jobc == 0) {
78639213Sgibbs				sx_sunlock(&proctree_lock);
78739213Sgibbs				return (EIO);
78839213Sgibbs			}
78939213Sgibbs			PGRP_LOCK(pgrp);
79039213Sgibbs			sx_sunlock(&proctree_lock);
79139213Sgibbs			pgsignal(pgrp, SIGTTOU, 1);
79239213Sgibbs			PGRP_UNLOCK(pgrp);
79339213Sgibbs			error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1",
79439213Sgibbs					 0);
79539213Sgibbs			if (error)
79639213Sgibbs				return (error);
79739213Sgibbs			sx_slock(&proctree_lock);
79839213Sgibbs			PROC_LOCK(p);
79939213Sgibbs		}
80039213Sgibbs		PROC_UNLOCK(p);
80139213Sgibbs		sx_sunlock(&proctree_lock);
80239213Sgibbs		break;
80339213Sgibbs	}
80439213Sgibbs
80539213Sgibbs	switch (cmd) {			/* Process the ioctl. */
80639213Sgibbs	case FIOASYNC:			/* set/clear async i/o */
80739213Sgibbs		s = spltty();
80839213Sgibbs		if (*(int *)data)
80939213Sgibbs			SET(tp->t_state, TS_ASYNC);
81039213Sgibbs		else
81139213Sgibbs			CLR(tp->t_state, TS_ASYNC);
81239213Sgibbs		splx(s);
81339213Sgibbs		break;
81439213Sgibbs	case FIONBIO:			/* set/clear non-blocking i/o */
81539213Sgibbs		break;			/* XXX: delete. */
81639213Sgibbs	case FIONREAD:			/* get # bytes to read */
81767928Sken		s = spltty();
81839213Sgibbs		*(int *)data = ttnread(tp);
81939213Sgibbs		splx(s);
82039213Sgibbs		break;
82139213Sgibbs
82239213Sgibbs	case FIOSETOWN:
82339213Sgibbs		/*
82439213Sgibbs		 * Policy -- Don't allow FIOSETOWN on someone else's
82539213Sgibbs		 *           controlling tty
82639213Sgibbs		 */
82739213Sgibbs		if (tp->t_session != NULL && !isctty(p, tp))
82839213Sgibbs			return (ENOTTY);
82939213Sgibbs
83039213Sgibbs		error = fsetown(*(int *)data, &tp->t_sigio);
83139213Sgibbs		if (error)
83239213Sgibbs			return (error);
83339213Sgibbs		break;
83439213Sgibbs	case FIOGETOWN:
83539213Sgibbs		if (tp->t_session != NULL && !isctty(p, tp))
83639213Sgibbs			return (ENOTTY);
83739213Sgibbs		*(int *)data = fgetown(&tp->t_sigio);
83839213Sgibbs		break;
83939213Sgibbs
84039213Sgibbs	case TIOCEXCL:			/* set exclusive use of tty */
84139213Sgibbs		s = spltty();
84239213Sgibbs		SET(tp->t_state, TS_XCLUDE);
84339213Sgibbs		splx(s);
84439213Sgibbs		break;
84539213Sgibbs	case TIOCFLUSH: {		/* flush buffers */
84639213Sgibbs		int flags = *(int *)data;
84739213Sgibbs
84839213Sgibbs		if (flags == 0)
84939213Sgibbs			flags = FREAD | FWRITE;
85039213Sgibbs		else
85139213Sgibbs			flags &= FREAD | FWRITE;
85239213Sgibbs		ttyflush(tp, flags);
85339213Sgibbs		break;
85439213Sgibbs	}
85539213Sgibbs	case TIOCCONS:			/* become virtual console */
85639213Sgibbs		if (*(int *)data) {
85739213Sgibbs			struct nameidata nid;
85839213Sgibbs
85939213Sgibbs			if (constty && constty != tp &&
86039213Sgibbs			    ISSET(constty->t_state, TS_CONNECTED))
86139213Sgibbs				return (EBUSY);
86239213Sgibbs
86339213Sgibbs			/* Ensure user can open the real console. */
86439213Sgibbs			NDINIT(&nid, LOOKUP, LOCKLEAF | FOLLOW, UIO_SYSSPACE,
86539213Sgibbs			    "/dev/console", td);
86639213Sgibbs			if ((error = namei(&nid)) != 0)
86739213Sgibbs				return (error);
86839213Sgibbs			NDFREE(&nid, NDF_ONLY_PNBUF);
86939213Sgibbs			error = VOP_ACCESS(nid.ni_vp, VREAD, td->td_ucred, td);
87039213Sgibbs			vput(nid.ni_vp);
87139213Sgibbs			if (error)
87239213Sgibbs				return (error);
87339213Sgibbs
87439213Sgibbs			constty = tp;
87539213Sgibbs		} else if (tp == constty)
87639213Sgibbs			constty = NULL;
87739213Sgibbs		break;
87839213Sgibbs	case TIOCDRAIN:			/* wait till output drained */
87939213Sgibbs		error = ttywait(tp);
88039213Sgibbs		if (error)
88139213Sgibbs			return (error);
88239213Sgibbs		break;
88339213Sgibbs	case TIOCGETA: {		/* get termios struct */
884168752Sscottl		struct termios *t = (struct termios *)data;
885168752Sscottl
886168752Sscottl		bcopy(&tp->t_termios, t, sizeof(struct termios));
887168752Sscottl		break;
888168752Sscottl	}
889168752Sscottl	case TIOCGETD:			/* get line discipline */
890168752Sscottl		*(int *)data = tp->t_line;
89139213Sgibbs		break;
89239213Sgibbs	case TIOCGWINSZ:		/* get window size */
893168752Sscottl		*(struct winsize *)data = tp->t_winsize;
89439213Sgibbs		break;
89539213Sgibbs	case TIOCGPGRP:			/* get pgrp of tty */
89639213Sgibbs		if (!isctty(p, tp))
89739213Sgibbs			return (ENOTTY);
89839213Sgibbs		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
89939213Sgibbs		break;
90039213Sgibbs#ifdef TIOCHPCL
90139213Sgibbs	case TIOCHPCL:			/* hang up on last close */
90239213Sgibbs		s = spltty();
90339213Sgibbs		SET(tp->t_cflag, HUPCL);
90439213Sgibbs		splx(s);
90539213Sgibbs		break;
90639213Sgibbs#endif
90739213Sgibbs	case TIOCNXCL:			/* reset exclusive use of tty */
90839213Sgibbs		s = spltty();
90939213Sgibbs		CLR(tp->t_state, TS_XCLUDE);
91039213Sgibbs		splx(s);
91139213Sgibbs		break;
91239213Sgibbs	case TIOCOUTQ:			/* output queue size */
91339213Sgibbs		*(int *)data = tp->t_outq.c_cc;
91439213Sgibbs		break;
91539213Sgibbs	case TIOCSETA:			/* set termios struct */
91639213Sgibbs	case TIOCSETAW:			/* drain output, set */
91739213Sgibbs	case TIOCSETAF: {		/* drn out, fls in, set */
91839213Sgibbs		struct termios *t = (struct termios *)data;
91939213Sgibbs
92039213Sgibbs		if (t->c_ispeed == 0)
92139213Sgibbs			t->c_ispeed = t->c_ospeed;
92239213Sgibbs		if (t->c_ispeed == 0)
92339213Sgibbs			t->c_ispeed = tp->t_ospeed;
92439213Sgibbs		if (t->c_ispeed == 0)
92539213Sgibbs			return (EINVAL);
92639213Sgibbs		s = spltty();
92739213Sgibbs		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
92839213Sgibbs			error = ttywait(tp);
92939213Sgibbs			if (error) {
93067928Sken				splx(s);
93139213Sgibbs				return (error);
93239213Sgibbs			}
93339213Sgibbs			if (cmd == TIOCSETAF)
93439213Sgibbs				ttyflush(tp, FREAD);
93539213Sgibbs		}
93639213Sgibbs		if (!ISSET(t->c_cflag, CIGNORE)) {
93739213Sgibbs			/*
93839213Sgibbs			 * Set device hardware.
93939213Sgibbs			 */
94039213Sgibbs			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
94139213Sgibbs				splx(s);
94239213Sgibbs				return (error);
94339213Sgibbs			}
94439213Sgibbs			if (ISSET(t->c_cflag, CLOCAL) &&
94539213Sgibbs			    !ISSET(tp->t_cflag, CLOCAL)) {
94639213Sgibbs				/*
94739213Sgibbs				 * XXX disconnections would be too hard to
94839213Sgibbs				 * get rid of without this kludge.  The only
94939213Sgibbs				 * way to get rid of controlling terminals
95039213Sgibbs				 * is to exit from the session leader.
95139213Sgibbs				 */
95239213Sgibbs				CLR(tp->t_state, TS_ZOMBIE);
95339213Sgibbs
95439213Sgibbs				wakeup(TSA_CARR_ON(tp));
955168752Sscottl				ttwakeup(tp);
956168752Sscottl				ttwwakeup(tp);
957168752Sscottl			}
958168752Sscottl			if ((ISSET(tp->t_state, TS_CARR_ON) ||
959168752Sscottl			     ISSET(t->c_cflag, CLOCAL)) &&
96039213Sgibbs			    !ISSET(tp->t_state, TS_ZOMBIE))
96139213Sgibbs				SET(tp->t_state, TS_CONNECTED);
96239213Sgibbs			else
96339213Sgibbs				CLR(tp->t_state, TS_CONNECTED);
96439213Sgibbs			tp->t_cflag = t->c_cflag;
96539213Sgibbs			tp->t_ispeed = t->c_ispeed;
96639213Sgibbs			if (t->c_ospeed != 0)
96739213Sgibbs				tp->t_ospeed = t->c_ospeed;
96839213Sgibbs			ttsetwater(tp);
96939213Sgibbs		}
970120599Sphk		if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
97139213Sgibbs		    cmd != TIOCSETAF) {
97239213Sgibbs			if (ISSET(t->c_lflag, ICANON))
97339213Sgibbs				SET(tp->t_lflag, PENDIN);
974101940Snjl			else {
97539213Sgibbs				/*
976120599Sphk				 * XXX we really shouldn't allow toggling
97739213Sgibbs				 * ICANON while we're in a non-termios line
97839213Sgibbs				 * discipline.  Now we have to worry about
97939213Sgibbs				 * panicing for a null queue.
98039213Sgibbs				 */
98139213Sgibbs				if (tp->t_canq.c_cbreserved > 0 &&
982168752Sscottl				    tp->t_rawq.c_cbreserved > 0) {
983168752Sscottl					catq(&tp->t_rawq, &tp->t_canq);
984168752Sscottl					/*
985168752Sscottl					 * XXX the queue limits may be
986168752Sscottl					 * different, so the old queue
98740603Sken					 * swapping method no longer works.
988168752Sscottl					 */
989168752Sscottl					catq(&tp->t_canq, &tp->t_rawq);
99039213Sgibbs				}
99140603Sken				CLR(tp->t_lflag, PENDIN);
99239213Sgibbs			}
993168752Sscottl			ttwakeup(tp);
994168752Sscottl		}
995168752Sscottl		tp->t_iflag = t->c_iflag;
99639213Sgibbs		tp->t_oflag = t->c_oflag;
99741297Sken		/*
99839213Sgibbs		 * Make the EXTPROC bit read only.
999168752Sscottl		 */
1000168752Sscottl		if (ISSET(tp->t_lflag, EXTPROC))
1001168752Sscottl			SET(t->c_lflag, EXTPROC);
1002168752Sscottl		else
1003168752Sscottl			CLR(t->c_lflag, EXTPROC);
100441297Sken		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
100540020Sken		if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
1006111206Sken		    t->c_cc[VTIME] != tp->t_cc[VTIME])
1007111206Sken			ttwakeup(tp);
1008111206Sken		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
100951836Sphk		splx(s);
1010111206Sken		break;
101140020Sken	}
1012168752Sscottl	case TIOCSETD: {		/* set line discipline */
1013168752Sscottl		int t = *(int *)data;
101439213Sgibbs		dev_t device = tp->t_dev;
101539213Sgibbs
1016168752Sscottl		if ((u_int)t >= nlinesw)
101739213Sgibbs			return (ENXIO);
101839213Sgibbs		if (t != tp->t_line) {
101939213Sgibbs			s = spltty();
1020120599Sphk			(*linesw[tp->t_line].l_close)(tp, flag);
102139213Sgibbs			error = (*linesw[t].l_open)(device, tp);
102239213Sgibbs			if (error) {
102339213Sgibbs				(void)(*linesw[tp->t_line].l_open)(device, tp);
102439213Sgibbs				splx(s);
1025120599Sphk				return (error);
102639213Sgibbs			}
102739213Sgibbs			tp->t_line = t;
102839213Sgibbs			splx(s);
102939213Sgibbs		}
103039213Sgibbs		break;
1031168752Sscottl	}
1032168752Sscottl	case TIOCSTART:			/* start output, like ^Q */
103339213Sgibbs		s = spltty();
103439213Sgibbs		if (ISSET(tp->t_state, TS_TTSTOP) ||
103539213Sgibbs		    ISSET(tp->t_lflag, FLUSHO)) {
103639213Sgibbs			CLR(tp->t_lflag, FLUSHO);
103739213Sgibbs			CLR(tp->t_state, TS_TTSTOP);
103839213Sgibbs			ttstart(tp);
1039111206Sken		}
104039213Sgibbs		splx(s);
1041125975Sphk		break;
104239213Sgibbs	case TIOCSTI:			/* simulate terminal input */
1043111206Sken		if ((flag & FREAD) == 0 && suser(td))
1044111206Sken			return (EPERM);
1045111206Sken		if (!isctty(p, tp) && suser(td))
1046168752Sscottl			return (EACCES);
1047111206Sken		s = spltty();
1048168752Sscottl		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
104939213Sgibbs		splx(s);
105039213Sgibbs		break;
105139213Sgibbs	case TIOCSTOP:			/* stop output, like ^S */
105239213Sgibbs		s = spltty();
105339213Sgibbs		if (!ISSET(tp->t_state, TS_TTSTOP)) {
105439213Sgibbs			SET(tp->t_state, TS_TTSTOP);
105539213Sgibbs			(*tp->t_stop)(tp, 0);
105639213Sgibbs		}
105739213Sgibbs		splx(s);
105839213Sgibbs		break;
105939213Sgibbs	case TIOCSCTTY:			/* become controlling tty */
106039213Sgibbs		/* Session ctty vnode pointer set in vnode layer. */
106139213Sgibbs		sx_slock(&proctree_lock);
106239213Sgibbs		if (!SESS_LEADER(p) ||
106339213Sgibbs		    ((p->p_session->s_ttyvp || tp->t_session) &&
106439213Sgibbs		     (tp->t_session != p->p_session))) {
106539213Sgibbs			sx_sunlock(&proctree_lock);
106639213Sgibbs			return (EPERM);
106739213Sgibbs		}
106839213Sgibbs		tp->t_session = p->p_session;
106959249Sphk		tp->t_pgrp = p->p_pgrp;
1070112262Sphk		SESS_LOCK(p->p_session);
107139213Sgibbs		p->p_session->s_ttyp = tp;
107239213Sgibbs		SESS_UNLOCK(p->p_session);
107339213Sgibbs		PROC_LOCK(p);
107439213Sgibbs		p->p_flag |= P_CONTROLT;
107539213Sgibbs		PROC_UNLOCK(p);
107639213Sgibbs		sx_sunlock(&proctree_lock);
107739213Sgibbs		break;
107839213Sgibbs	case TIOCSPGRP: {		/* set pgrp of tty */
107939213Sgibbs		sx_slock(&proctree_lock);
108039213Sgibbs		pgrp = pgfind(*(int *)data);
108139213Sgibbs		if (!isctty(p, tp)) {
108239213Sgibbs			if (pgrp != NULL)
108339213Sgibbs				PGRP_UNLOCK(pgrp);
108439213Sgibbs			sx_sunlock(&proctree_lock);
108539213Sgibbs			return (ENOTTY);
108639213Sgibbs		}
108739213Sgibbs		if (pgrp == NULL) {
108839213Sgibbs			sx_sunlock(&proctree_lock);
108939213Sgibbs			return (EPERM);
109039213Sgibbs		}
109139213Sgibbs		PGRP_UNLOCK(pgrp);
109239213Sgibbs		if (pgrp->pg_session != p->p_session) {
109339213Sgibbs			sx_sunlock(&proctree_lock);
109439213Sgibbs			return (EPERM);
109539213Sgibbs		}
109639213Sgibbs		sx_sunlock(&proctree_lock);
109739213Sgibbs		tp->t_pgrp = pgrp;
109839213Sgibbs		break;
109939213Sgibbs	}
110039213Sgibbs	case TIOCSTAT:			/* simulate control-T */
110145442Sgibbs		s = spltty();
110239213Sgibbs		ttyinfo(tp);
110339213Sgibbs		splx(s);
110439213Sgibbs		break;
110539213Sgibbs	case TIOCSWINSZ:		/* set window size */
110639213Sgibbs		if (bcmp((caddr_t)&tp->t_winsize, data,
110739213Sgibbs		    sizeof (struct winsize))) {
110839213Sgibbs			tp->t_winsize = *(struct winsize *)data;
110939213Sgibbs			if (tp->t_pgrp != NULL) {
111039213Sgibbs				PGRP_LOCK(tp->t_pgrp);
111139213Sgibbs				pgsignal(tp->t_pgrp, SIGWINCH, 1);
111239213Sgibbs				PGRP_UNLOCK(tp->t_pgrp);
111346581Sken			}
111446581Sken		}
111539213Sgibbs		break;
111639213Sgibbs	case TIOCSDRAINWAIT:
111739213Sgibbs		error = suser(td);
111839213Sgibbs		if (error)
111939213Sgibbs			return (error);
112039213Sgibbs		tp->t_timeout = *(int *)data * hz;
112139213Sgibbs		wakeup(TSA_OCOMPLETE(tp));
112239213Sgibbs		wakeup(TSA_OLOWAT(tp));
112339213Sgibbs		break;
112439213Sgibbs	case TIOCGDRAINWAIT:
112539213Sgibbs		*(int *)data = tp->t_timeout / hz;
112639213Sgibbs		break;
112739213Sgibbs	default:
112839213Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
112939213Sgibbs		return (ttcompat(tp, cmd, data, flag));
113039213Sgibbs#else
113139213Sgibbs		return (ENOIOCTL);
113239213Sgibbs#endif
113339213Sgibbs	}
113439213Sgibbs	return (0);
113539213Sgibbs}
113639213Sgibbs
113739213Sgibbsint
113839213Sgibbsttypoll(dev_t dev, int events, struct thread *td)
113939213Sgibbs{
114039213Sgibbs	int s;
114139213Sgibbs	int revents = 0;
114239213Sgibbs	struct tty *tp;
114339213Sgibbs
114439213Sgibbs	tp = dev->si_tty;
114539213Sgibbs	if (tp == NULL)	/* XXX used to return ENXIO, but that means true! */
114639213Sgibbs		return ((events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM))
114739213Sgibbs			| POLLHUP);
114839213Sgibbs
114939213Sgibbs	s = spltty();
115039213Sgibbs	if (events & (POLLIN | POLLRDNORM)) {
115139213Sgibbs		if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))
115239213Sgibbs			revents |= events & (POLLIN | POLLRDNORM);
115339213Sgibbs		else
115439213Sgibbs			selrecord(td, &tp->t_rsel);
115539213Sgibbs	}
115639213Sgibbs	if (events & (POLLOUT | POLLWRNORM)) {
1157168752Sscottl		if ((tp->t_outq.c_cc <= tp->t_olowat &&
1158168752Sscottl		     ISSET(tp->t_state, TS_CONNECTED))
1159168752Sscottl		    || ISSET(tp->t_state, TS_ZOMBIE))
1160168752Sscottl			revents |= events & (POLLOUT | POLLWRNORM);
1161168752Sscottl		else
1162168752Sscottl			selrecord(td, &tp->t_wsel);
1163168752Sscottl	}
1164168752Sscottl	splx(s);
1165112262Sphk	return (revents);
116639213Sgibbs}
116739213Sgibbs
1168112262Sphkstatic struct filterops ttyread_filtops =
116939213Sgibbs	{ 1, NULL, filt_ttyrdetach, filt_ttyread };
1170168752Sscottlstatic struct filterops ttywrite_filtops =
1171168752Sscottl	{ 1, NULL, filt_ttywdetach, filt_ttywrite };
1172168752Sscottl
117339213Sgibbsint
117439213Sgibbsttykqfilter(dev_t dev, struct knote *kn)
117539213Sgibbs{
117639213Sgibbs	struct tty *tp = dev->si_tty;
117739213Sgibbs	struct klist *klist;
117839213Sgibbs	int s;
117939213Sgibbs
118039213Sgibbs	switch (kn->kn_filter) {
118139213Sgibbs	case EVFILT_READ:
118239213Sgibbs		klist = &tp->t_rsel.si_note;
118359249Sphk		kn->kn_fop = &ttyread_filtops;
118439213Sgibbs		break;
118539213Sgibbs	case EVFILT_WRITE:
118645442Sgibbs		klist = &tp->t_wsel.si_note;
118739213Sgibbs		kn->kn_fop = &ttywrite_filtops;
118839213Sgibbs		break;
118939213Sgibbs	default:
119039213Sgibbs		return (1);
119139213Sgibbs	}
119245845Sgibbs
119339213Sgibbs	kn->kn_hook = (caddr_t)dev;
119439213Sgibbs
119539213Sgibbs	s = spltty();
119639213Sgibbs	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
119739213Sgibbs	splx(s);
119839213Sgibbs
119939213Sgibbs	return (0);
120039213Sgibbs}
120139213Sgibbs
120239213Sgibbsstatic void
120339213Sgibbsfilt_ttyrdetach(struct knote *kn)
120439213Sgibbs{
120539213Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
120639213Sgibbs	int s = spltty();
120739213Sgibbs
1208168752Sscottl	SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
120939213Sgibbs	splx(s);
121039213Sgibbs}
121139213Sgibbs
121239213Sgibbsstatic int
1213168752Sscottlfilt_ttyread(struct knote *kn, long hint)
121439213Sgibbs{
121539213Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
121639213Sgibbs
121739213Sgibbs	kn->kn_data = ttnread(tp);
121839213Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE)) {
121939213Sgibbs		kn->kn_flags |= EV_EOF;
122039213Sgibbs		return (1);
122139213Sgibbs	}
122239213Sgibbs	return (kn->kn_data > 0);
122339213Sgibbs}
122439213Sgibbs
122539213Sgibbsstatic void
122639213Sgibbsfilt_ttywdetach(struct knote *kn)
122739213Sgibbs{
122839213Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
122939213Sgibbs	int s = spltty();
123039213Sgibbs
123139213Sgibbs	SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
123239213Sgibbs	splx(s);
123339213Sgibbs}
123439213Sgibbs
123539213Sgibbsstatic int
123639213Sgibbsfilt_ttywrite(struct knote *kn, long hint)
123739213Sgibbs{
123839213Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
123939213Sgibbs
124039213Sgibbs	kn->kn_data = tp->t_outq.c_cc;
124139213Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE))
124239213Sgibbs		return (1);
124339213Sgibbs	return (kn->kn_data <= tp->t_olowat &&
124439213Sgibbs	    ISSET(tp->t_state, TS_CONNECTED));
124539213Sgibbs}
124639213Sgibbs
124739213Sgibbs/*
124839213Sgibbs * Must be called at spltty().
124939213Sgibbs */
125039213Sgibbsstatic int
125139213Sgibbsttnread(struct tty *tp)
125239213Sgibbs{
125339213Sgibbs	int nread;
125439213Sgibbs
125539213Sgibbs	if (ISSET(tp->t_lflag, PENDIN))
125639213Sgibbs		ttypend(tp);
125739213Sgibbs	nread = tp->t_canq.c_cc;
125839213Sgibbs	if (!ISSET(tp->t_lflag, ICANON)) {
125939213Sgibbs		nread += tp->t_rawq.c_cc;
126059249Sphk		if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
1261112262Sphk			nread = 0;
126239213Sgibbs	}
126339213Sgibbs	return (nread);
126439213Sgibbs}
126539213Sgibbs
126639213Sgibbs/*
126739213Sgibbs * Wait for output to drain.
126839213Sgibbs */
126939213Sgibbsint
127039213Sgibbsttywait(struct tty *tp)
127139213Sgibbs{
127239213Sgibbs	int error, s;
127339213Sgibbs
1274168752Sscottl	error = 0;
1275168752Sscottl	s = spltty();
1276168752Sscottl	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
127739213Sgibbs	       ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
127839213Sgibbs		(*tp->t_oproc)(tp);
127939213Sgibbs		if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
128039213Sgibbs		    ISSET(tp->t_state, TS_CONNECTED)) {
128139213Sgibbs			SET(tp->t_state, TS_SO_OCOMPLETE);
128239213Sgibbs			error = ttysleep(tp, TSA_OCOMPLETE(tp),
1283168752Sscottl					 TTOPRI | PCATCH, "ttywai",
1284168752Sscottl					 tp->t_timeout);
1285168752Sscottl			if (error) {
128639213Sgibbs				if (error == EWOULDBLOCK)
128739213Sgibbs					error = EIO;
128839213Sgibbs				break;
128939213Sgibbs			}
129039213Sgibbs		} else
129139213Sgibbs			break;
129239213Sgibbs	}
129339213Sgibbs	if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
129439213Sgibbs		error = EIO;
129539213Sgibbs	splx(s);
129639213Sgibbs	return (error);
129739213Sgibbs}
129839213Sgibbs
129939213Sgibbs/*
130039213Sgibbs * Flush if successfully wait.
130139213Sgibbs */
130239213Sgibbsstatic int
130339213Sgibbsttywflush(struct tty *tp)
130439213Sgibbs{
130539213Sgibbs	int error;
130639213Sgibbs
130739213Sgibbs	if ((error = ttywait(tp)) == 0)
130839213Sgibbs		ttyflush(tp, FREAD);
130939213Sgibbs	return (error);
131039213Sgibbs}
131139213Sgibbs
131239213Sgibbs/*
131339213Sgibbs * Flush tty read and/or write queues, notifying anyone waiting.
1314125975Sphk */
131539213Sgibbsvoid
131639213Sgibbsttyflush(struct tty *tp, int rw)
131739213Sgibbs{
131839213Sgibbs	int s;
131939213Sgibbs
132039213Sgibbs	s = spltty();
132139213Sgibbs#if 0
132242017Seivindagain:
132339213Sgibbs#endif
132439213Sgibbs	if (rw & FWRITE) {
132539213Sgibbs		FLUSHQ(&tp->t_outq);
132639213Sgibbs		CLR(tp->t_state, TS_TTSTOP);
132739213Sgibbs	}
132839213Sgibbs	(*tp->t_stop)(tp, rw);
132939213Sgibbs	if (rw & FREAD) {
133039213Sgibbs		FLUSHQ(&tp->t_canq);
133139213Sgibbs		FLUSHQ(&tp->t_rawq);
133239213Sgibbs		CLR(tp->t_lflag, PENDIN);
133339213Sgibbs		tp->t_rocount = 0;
133446581Sken		tp->t_rocol = 0;
133539213Sgibbs		CLR(tp->t_state, TS_LOCAL);
133639213Sgibbs		ttwakeup(tp);
133739213Sgibbs		if (ISSET(tp->t_state, TS_TBLOCK)) {
133839213Sgibbs			if (rw & FWRITE)
133939213Sgibbs				FLUSHQ(&tp->t_outq);
134039213Sgibbs			ttyunblock(tp);
134145442Sgibbs
134239213Sgibbs			/*
134339213Sgibbs			 * Don't let leave any state that might clobber the
134439213Sgibbs			 * next line discipline (although we should do more
134546581Sken			 * to send the START char).  Not clearing the state
134646581Sken			 * may have caused the "putc to a clist with no
134746581Sken			 * reserved cblocks" panic/printf.
134846581Sken			 */
134939213Sgibbs			CLR(tp->t_state, TS_TBLOCK);
135039213Sgibbs
135139213Sgibbs#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
1352168752Sscottl			if (ISSET(tp->t_iflag, IXOFF)) {
1353168752Sscottl				/*
135439213Sgibbs				 * XXX wait a bit in the hope that the stop
135539213Sgibbs				 * character (if any) will go out.  Waiting
135639213Sgibbs				 * isn't good since it allows races.  This
135739213Sgibbs				 * will be fixed when the stop character is
135839213Sgibbs				 * put in a special queue.  Don't bother with
135939213Sgibbs				 * the checks in ttywait() since the timeout
136039213Sgibbs				 * will save us.
136139213Sgibbs				 */
136239213Sgibbs				SET(tp->t_state, TS_SO_OCOMPLETE);
136339213Sgibbs				ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI,
136439213Sgibbs					 "ttyfls", hz / 10);
136539213Sgibbs				/*
136659249Sphk				 * Don't try sending the stop character again.
136739213Sgibbs				 */
136839213Sgibbs				CLR(tp->t_state, TS_TBLOCK);
136939213Sgibbs				goto again;
137039213Sgibbs			}
1371120599Sphk#endif
137239213Sgibbs		}
137376362Sphk	}
137476362Sphk	if (rw & FWRITE) {
137539213Sgibbs		FLUSHQ(&tp->t_outq);
137639213Sgibbs		ttwwakeup(tp);
1377168752Sscottl	}
137839213Sgibbs	splx(s);
137939213Sgibbs}
138039213Sgibbs
138139213Sgibbs/*
138239213Sgibbs * Copy in the default termios characters.
138339213Sgibbs */
138439213Sgibbsvoid
138539213Sgibbstermioschars(struct termios *t)
1386168752Sscottl{
138776362Sphk
138876362Sphk	bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
138939213Sgibbs}
139039213Sgibbs
1391111206Sken/*
1392111206Sken * Old interface.
1393111206Sken */
1394111206Skenvoid
1395111206Skenttychars(struct tty *tp)
1396111206Sken{
1397111206Sken
1398111206Sken	termioschars(&tp->t_termios);
1399111206Sken}
1400168752Sscottl
1401111206Sken/*
1402111206Sken * Handle input high water.  Send stop character for the IXOFF case.  Turn
1403111206Sken * on our input flow control bit and propagate the changes to the driver.
1404111206Sken * XXX the stop character should be put in a special high priority queue.
1405111206Sken */
140639213Sgibbsvoid
140739213Sgibbsttyblock(struct tty *tp)
140839213Sgibbs{
1409112946Sphk
141039213Sgibbs	SET(tp->t_state, TS_TBLOCK);
141139213Sgibbs	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
141239213Sgibbs	    putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
141339213Sgibbs		CLR(tp->t_state, TS_TBLOCK);	/* try again later */
141439213Sgibbs	ttstart(tp);
141539213Sgibbs}
141639213Sgibbs
141739213Sgibbs/*
141839213Sgibbs * Handle input low water.  Send start character for the IXOFF case.  Turn
141939213Sgibbs * off our input flow control bit and propagate the changes to the driver.
1420168752Sscottl * XXX the start character should be put in a special high priority queue.
142139213Sgibbs */
142239213Sgibbsstatic void
142339213Sgibbsttyunblock(struct tty *tp)
142439213Sgibbs{
142539213Sgibbs
142639213Sgibbs	CLR(tp->t_state, TS_TBLOCK);
142739213Sgibbs	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
142859249Sphk	    putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
142939213Sgibbs		SET(tp->t_state, TS_TBLOCK);	/* try again later */
143039213Sgibbs	ttstart(tp);
143139213Sgibbs}
143239213Sgibbs
143339213Sgibbs#ifdef notyet
143439213Sgibbs/* Not used by any current (i386) drivers. */
143539213Sgibbs/*
143639213Sgibbs * Restart after an inter-char delay.
143739213Sgibbs */
143839213Sgibbsvoid
143959249Sphkttrstrt(void *tp_arg)
144039213Sgibbs{
144139213Sgibbs	struct tty *tp;
144239213Sgibbs	int s;
144339213Sgibbs
144439213Sgibbs	KASSERT(tp_arg != NULL, ("ttrstrt"));
144539213Sgibbs
144639213Sgibbs	tp = tp_arg;
144739213Sgibbs	s = spltty();
144839213Sgibbs
144939213Sgibbs	CLR(tp->t_state, TS_TIMEOUT);
145059249Sphk	ttstart(tp);
145139213Sgibbs
1452125975Sphk	splx(s);
145339213Sgibbs}
145439213Sgibbs#endif
145539213Sgibbs
145639213Sgibbsint
145791062Sphkttstart(struct tty *tp)
145859249Sphk{
145939213Sgibbs
146039213Sgibbs	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
1461121209Sphk		(*tp->t_oproc)(tp);
1462121209Sphk	return (0);
146359249Sphk}
146459249Sphk
146559249Sphk/*
146639213Sgibbs * "close" a line discipline
146739213Sgibbs */
146839213Sgibbsint
146939213Sgibbsttylclose(struct tty *tp, int flag)
147039213Sgibbs{
147139213Sgibbs
147239213Sgibbs	if (flag & FNONBLOCK || ttywflush(tp))
1473112262Sphk		ttyflush(tp, FREAD | FWRITE);
147439213Sgibbs	return (0);
147539213Sgibbs}
147639213Sgibbs
147739213Sgibbs/*
147839213Sgibbs * Handle modem control transition on a tty.
147939213Sgibbs * Flag indicates new state of carrier.
148039213Sgibbs * Returns 0 if the line should be turned off, otherwise 1.
148139213Sgibbs */
148259249Sphkint
148339213Sgibbsttymodem(struct tty *tp, int flag)
148439213Sgibbs{
148539213Sgibbs
148639213Sgibbs	if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
148739213Sgibbs		/*
148839213Sgibbs		 * MDMBUF: do flow control according to carrier flag
148939213Sgibbs		 * XXX TS_CAR_OFLOW doesn't do anything yet.  TS_TTSTOP
149039213Sgibbs		 * works if IXON and IXANY are clear.
149139213Sgibbs		 */
149239213Sgibbs		if (flag) {
149339213Sgibbs			CLR(tp->t_state, TS_CAR_OFLOW);
149439213Sgibbs			CLR(tp->t_state, TS_TTSTOP);
149539213Sgibbs			ttstart(tp);
1496169562Sscottl		} else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
149739213Sgibbs			SET(tp->t_state, TS_CAR_OFLOW);
149839213Sgibbs			SET(tp->t_state, TS_TTSTOP);
1499164906Smjacob			(*tp->t_stop)(tp, 0);
1500164906Smjacob		}
150139213Sgibbs	} else if (flag == 0) {
150239213Sgibbs		/*
150339213Sgibbs		 * Lost carrier.
150439213Sgibbs		 */
150539213Sgibbs		CLR(tp->t_state, TS_CARR_ON);
150639213Sgibbs		if (ISSET(tp->t_state, TS_ISOPEN) &&
150739213Sgibbs		    !ISSET(tp->t_cflag, CLOCAL)) {
150839213Sgibbs			SET(tp->t_state, TS_ZOMBIE);
150939213Sgibbs			CLR(tp->t_state, TS_CONNECTED);
151039213Sgibbs			if (tp->t_session) {
151139213Sgibbs				sx_slock(&proctree_lock);
151239213Sgibbs				if (tp->t_session->s_leader) {
151339213Sgibbs					struct proc *p;
151439213Sgibbs
151539213Sgibbs					p = tp->t_session->s_leader;
151639213Sgibbs					PROC_LOCK(p);
151739213Sgibbs					psignal(p, SIGHUP);
151839213Sgibbs					PROC_UNLOCK(p);
151939213Sgibbs				}
152039213Sgibbs				sx_sunlock(&proctree_lock);
152139213Sgibbs			}
152239213Sgibbs			ttyflush(tp, FREAD | FWRITE);
152339213Sgibbs			return (0);
152439213Sgibbs		}
152539213Sgibbs	} else {
152639213Sgibbs		/*
152739213Sgibbs		 * Carrier now on.
152839213Sgibbs		 */
152939213Sgibbs		SET(tp->t_state, TS_CARR_ON);
153039213Sgibbs		if (!ISSET(tp->t_state, TS_ZOMBIE))
153139213Sgibbs			SET(tp->t_state, TS_CONNECTED);
153239213Sgibbs		wakeup(TSA_CARR_ON(tp));
153339213Sgibbs		ttwakeup(tp);
153459249Sphk		ttwwakeup(tp);
153539213Sgibbs	}
153639213Sgibbs	return (1);
153759249Sphk}
153839213Sgibbs
153939213Sgibbs/*
154039213Sgibbs * Reinput pending characters after state switch
154139213Sgibbs * call at spltty().
154239213Sgibbs */
154339213Sgibbsstatic void
154439213Sgibbsttypend(struct tty *tp)
154539213Sgibbs{
154639213Sgibbs	struct clist tq;
154746747Sken	int c;
154874840Sken
154974840Sken	CLR(tp->t_lflag, PENDIN);
155039213Sgibbs	SET(tp->t_state, TS_TYPEN);
155139213Sgibbs	/*
155239213Sgibbs	 * XXX this assumes too much about clist internals.  It may even
155339213Sgibbs	 * fail if the cblock slush pool is empty.  We can't allocate more
155439213Sgibbs	 * cblocks here because we are called from an interrupt handler
155539213Sgibbs	 * and clist_alloc_cblocks() can wait.
155639213Sgibbs	 */
155739213Sgibbs	tq = tp->t_rawq;
155839213Sgibbs	bzero(&tp->t_rawq, sizeof tp->t_rawq);
1559164906Smjacob	tp->t_rawq.c_cbmax = tq.c_cbmax;
1560164906Smjacob	tp->t_rawq.c_cbreserved = tq.c_cbreserved;
1561112946Sphk	while ((c = getc(&tq)) >= 0)
156259249Sphk		ttyinput(c, tp);
156359249Sphk	CLR(tp->t_state, TS_TYPEN);
156459249Sphk}
156539213Sgibbs
156639213Sgibbs/*
156739213Sgibbs * Process a read call on a tty device.
156839213Sgibbs */
156939213Sgibbsint
157039213Sgibbsttread(struct tty *tp, struct uio *uio, int flag)
157139213Sgibbs{
157259249Sphk	struct clist *qp;
157359249Sphk	int c;
157459249Sphk	tcflag_t lflag;
1575104456Sphk	cc_t *cc = tp->t_cc;
1576104456Sphk	struct thread *td;
1577104456Sphk	struct proc *p;
1578104456Sphk	int s, first, error = 0;
1579104456Sphk	int has_stime = 0, last_cc = 0;
158059249Sphk	long slp = 0;		/* XXX this should be renamed `timo'. */
158139213Sgibbs	struct timeval stime;
158239213Sgibbs	struct pgrp *pg;
158339213Sgibbs
158439213Sgibbs	td = curthread;
1585112262Sphk	p = td->td_proc;
158639213Sgibbsloop:
158739213Sgibbs	s = spltty();
158839213Sgibbs	lflag = tp->t_lflag;
158939213Sgibbs	/*
1590157806Smaxim	 * take pending input first
159139213Sgibbs	 */
159239213Sgibbs	if (ISSET(lflag, PENDIN)) {
159339213Sgibbs		ttypend(tp);
159439213Sgibbs		splx(s);	/* reduce latency */
159539213Sgibbs		s = spltty();
159639213Sgibbs		lflag = tp->t_lflag;	/* XXX ttypend() clobbers it */
159739213Sgibbs	}
159839213Sgibbs
159939213Sgibbs	/*
160039213Sgibbs	 * Hang process if it's in the background.
160139213Sgibbs	 */
160239213Sgibbs	if (isbackground(p, tp)) {
160339213Sgibbs		splx(s);
160439213Sgibbs		sx_slock(&proctree_lock);
160539213Sgibbs		PROC_LOCK(p);
160639213Sgibbs		if (SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTIN) ||
160739213Sgibbs		    SIGISMEMBER(td->td_sigmask, SIGTTIN) ||
160839213Sgibbs		    (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0) {
160939213Sgibbs			PROC_UNLOCK(p);
161039213Sgibbs			sx_sunlock(&proctree_lock);
161139213Sgibbs			return (EIO);
161239213Sgibbs		}
161339213Sgibbs		pg = p->p_pgrp;
161439213Sgibbs		PROC_UNLOCK(p);
161539213Sgibbs		PGRP_LOCK(pg);
161639213Sgibbs		sx_sunlock(&proctree_lock);
161739213Sgibbs		pgsignal(pg, SIGTTIN, 1);
161839213Sgibbs		PGRP_UNLOCK(pg);
161939213Sgibbs		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0);
162039213Sgibbs		if (error)
162139213Sgibbs			return (error);
162239213Sgibbs		goto loop;
162339213Sgibbs	}
162439213Sgibbs
162541514Sarchie	if (ISSET(tp->t_state, TS_ZOMBIE)) {
162640020Sken		splx(s);
162740020Sken		return (0);	/* EOF */
162839213Sgibbs	}
162939213Sgibbs
163039213Sgibbs	/*
163139213Sgibbs	 * If canonical, use the canonical queue,
163239213Sgibbs	 * else use the raw queue.
163339213Sgibbs	 *
163439213Sgibbs	 * (should get rid of clists...)
163574840Sken	 */
163674840Sken	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
163739213Sgibbs
163839213Sgibbs	if (flag & IO_NDELAY) {
163939213Sgibbs		if (qp->c_cc > 0)
164039213Sgibbs			goto read;
164139213Sgibbs		if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
164239213Sgibbs			splx(s);
164339213Sgibbs			return (0);
164439213Sgibbs		}
164539213Sgibbs		splx(s);
164639213Sgibbs		return (EWOULDBLOCK);
164739213Sgibbs	}
164839213Sgibbs	if (!ISSET(lflag, ICANON)) {
164939213Sgibbs		int m = cc[VMIN];
165039213Sgibbs		long t = cc[VTIME];
165139213Sgibbs		struct timeval timecopy;
165239213Sgibbs
165339213Sgibbs		/*
165439213Sgibbs		 * Check each of the four combinations.
165539213Sgibbs		 * (m > 0 && t == 0) is the normal read case.
165639213Sgibbs		 * It should be fairly efficient, so we check that and its
165739213Sgibbs		 * companion case (m == 0 && t == 0) first.
165839213Sgibbs		 * For the other two cases, we compute the target sleep time
165939213Sgibbs		 * into slp.
166039213Sgibbs		 */
166139213Sgibbs		if (t == 0) {
166239213Sgibbs			if (qp->c_cc < m)
166339213Sgibbs				goto sleep;
166439213Sgibbs			if (qp->c_cc > 0)
166539213Sgibbs				goto read;
166639213Sgibbs
166739213Sgibbs			/* m, t and qp->c_cc are all 0.  0 is enough input. */
166839213Sgibbs			splx(s);
166939213Sgibbs			return (0);
167039213Sgibbs		}
167139213Sgibbs		t *= 100000;		/* time in us */
167239213Sgibbs#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
167339213Sgibbs			 ((t1).tv_usec - (t2).tv_usec))
167439213Sgibbs		if (m > 0) {
167539213Sgibbs			if (qp->c_cc <= 0)
167639213Sgibbs				goto sleep;
167739213Sgibbs			if (qp->c_cc >= m)
167839213Sgibbs				goto read;
167939213Sgibbs			getmicrotime(&timecopy);
168039213Sgibbs			if (!has_stime) {
168146581Sken				/* first character, start timer */
168246581Sken				has_stime = 1;
168346581Sken				stime = timecopy;
168446581Sken				slp = t;
168539213Sgibbs			} else if (qp->c_cc > last_cc) {
168646581Sken				/* got a character, restart timer */
168774840Sken				stime = timecopy;
168874840Sken				slp = t;
168974840Sken			} else {
169074840Sken				/* nothing, check expiration */
169174840Sken				slp = t - diff(timecopy, stime);
169274840Sken				if (slp <= 0)
169374840Sken					goto read;
169474840Sken			}
169541514Sarchie			last_cc = qp->c_cc;
169641514Sarchie		} else {	/* m == 0 */
169739213Sgibbs			if (qp->c_cc > 0)
169839213Sgibbs				goto read;
169974840Sken			getmicrotime(&timecopy);
170074840Sken			if (!has_stime) {
170182850Sken				has_stime = 1;
170282850Sken				stime = timecopy;
170382850Sken				slp = t;
170482850Sken			} else {
170582850Sken				slp = t - diff(timecopy, stime);
170682850Sken				if (slp <= 0) {
170782850Sken					/* Timed out, but 0 is enough input. */
170882850Sken					splx(s);
170982850Sken					return (0);
171082850Sken				}
171174840Sken			}
171239213Sgibbs		}
171339213Sgibbs#undef diff
171439213Sgibbs		/*
171539213Sgibbs		 * Rounding down may make us wake up just short
171639213Sgibbs		 * of the target, so we round up.
171739213Sgibbs		 * The formula is ceiling(slp * hz/1000000).
171839213Sgibbs		 * 32-bit arithmetic is enough for hz < 169.
171939213Sgibbs		 * XXX see tvtohz() for how to avoid overflow if hz
172039213Sgibbs		 * is large (divide by `tick' and/or arrange to
172139213Sgibbs		 * use tvtohz() if hz is large).
172239213Sgibbs		 */
172339213Sgibbs		slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
172439213Sgibbs		goto sleep;
172539213Sgibbs	}
172639213Sgibbs	if (qp->c_cc <= 0) {
172739213Sgibbssleep:
172839213Sgibbs		/*
172940020Sken		 * There is no input, or not enough input and we can block.
173040020Sken		 */
173140020Sken		error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
173240020Sken				 ISSET(tp->t_state, TS_CONNECTED) ?
1733164906Smjacob				 "ttyin" : "ttyhup", (int)slp);
1734164906Smjacob		splx(s);
1735164906Smjacob		if (error == EWOULDBLOCK)
173640020Sken			error = 0;
1737164906Smjacob		else if (error)
1738164906Smjacob			return (error);
173939213Sgibbs		/*
174040603Sken		 * XXX what happens if another process eats some input
174139213Sgibbs		 * while we are asleep (not just here)?  It would be
174239213Sgibbs		 * safest to detect changes and reset our state variables
174340020Sken		 * (has_stime and last_cc).
174440020Sken		 */
174539213Sgibbs		slp = 0;
174640603Sken		goto loop;
174739213Sgibbs	}
174840603Skenread:
174939213Sgibbs	splx(s);
175039213Sgibbs	/*
175140020Sken	 * Input present, check for input mapping and processing.
175239213Sgibbs	 */
175339213Sgibbs	first = 1;
175439213Sgibbs	if (ISSET(lflag, ICANON | ISIG))
1755169562Sscottl		goto slowcase;
175642378Smjacob	for (;;) {
175739213Sgibbs		char ibuf[IBUFSIZ];
175842378Smjacob		int icc;
175942378Smjacob
1760119708Sken		icc = imin(uio->uio_resid, IBUFSIZ);
1761119708Sken		icc = q_to_b(qp, ibuf, icc);
1762119708Sken		if (icc <= 0) {
1763119708Sken			if (first)
1764119708Sken				goto loop;
176542378Smjacob			break;
176640020Sken		}
176742378Smjacob		error = uiomove(ibuf, icc, uio);
176842378Smjacob		/*
176942378Smjacob		 * XXX if there was an error then we should ungetc() the
177042378Smjacob		 * unmoved chars and reduce icc here.
177142378Smjacob		 */
177242378Smjacob		if (error)
177342378Smjacob			break;
177442378Smjacob		if (uio->uio_resid == 0)
177542378Smjacob			break;
1776168752Sscottl		first = 0;
177742378Smjacob	}
177839213Sgibbs	goto out;
177939213Sgibbsslowcase:
178039213Sgibbs	for (;;) {
178139213Sgibbs		c = getc(qp);
178239213Sgibbs		if (c < 0) {
178339213Sgibbs			if (first)
178439213Sgibbs				goto loop;
178539213Sgibbs			break;
178639213Sgibbs		}
178739213Sgibbs		/*
178842378Smjacob		 * delayed suspend (^Y)
178942378Smjacob		 */
179039213Sgibbs		if (CCEQ(cc[VDSUSP], c) &&
179139213Sgibbs		    ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
179239213Sgibbs			if (tp->t_pgrp != NULL) {
179339213Sgibbs				PGRP_LOCK(tp->t_pgrp);
1794111206Sken				pgsignal(tp->t_pgrp, SIGTSTP, 1);
1795111206Sken				PGRP_UNLOCK(tp->t_pgrp);
1796111206Sken			}
1797111206Sken			if (first) {
1798111206Sken				error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
1799111206Sken						 "ttybg3", 0);
1800111206Sken				if (error)
1801111206Sken					break;
1802111206Sken				goto loop;
1803111206Sken			}
1804111206Sken			break;
1805111206Sken		}
1806111206Sken		/*
1807111206Sken		 * Interpret EOF only in canonical mode.
1808111206Sken		 */
180939213Sgibbs		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
1810111206Sken			break;
1811111206Sken		/*
1812111206Sken		 * Give user character.
1813111206Sken		 */
1814111206Sken		error = ureadc(c, uio);
1815111206Sken		if (error)
1816111206Sken			/* XXX should ungetc(c, qp). */
1817111206Sken			break;
1818111206Sken		if (uio->uio_resid == 0)
1819111206Sken			break;
1820111206Sken		/*
1821111206Sken		 * In canonical mode check for a "break character"
1822111206Sken		 * marking the end of a "line of input".
1823111206Sken		 */
1824120599Sphk		if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
182539213Sgibbs			break;
182639213Sgibbs		first = 0;
182739213Sgibbs	}
182839213Sgibbs
1829168752Sscottlout:
183039213Sgibbs	/*
1831120599Sphk	 * Look to unblock input now that (presumably)
183239213Sgibbs	 * the input queue has gone down.
183339213Sgibbs	 */
183439213Sgibbs	s = spltty();
1835168752Sscottl	if (ISSET(tp->t_state, TS_TBLOCK) &&
183639213Sgibbs	    tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat)
183739213Sgibbs		ttyunblock(tp);
183839213Sgibbs	splx(s);
183939213Sgibbs
184039213Sgibbs	return (error);
184140020Sken}
184239213Sgibbs
1843168752Sscottl/*
1844168752Sscottl * Check the output queue on tp for space for a kernel message (from uprintf
1845168752Sscottl * or tprintf).  Allow some space over the normal hiwater mark so we don't
1846168752Sscottl * lose messages due to normal flow control, but don't let the tty run amok.
1847168752Sscottl * Sleeps here are not interruptible, but we return prematurely if new signals
184839213Sgibbs * arrive.
1849111206Sken */
1850111206Skenint
1851111206Skenttycheckoutq(struct tty *tp, int wait)
1852144135Sken{
1853144135Sken	int hiwat, s;
1854144135Sken	sigset_t oldmask;
1855144135Sken	struct thread *td;
1856144135Sken	struct proc *p;
1857111206Sken
1858111206Sken	td = curthread;
1859111206Sken	p = td->td_proc;
1860144135Sken	hiwat = tp->t_ohiwat;
1861144135Sken	SIGEMPTYSET(oldmask);
1862111206Sken	s = spltty();
1863111206Sken	if (wait) {
1864168752Sscottl		PROC_LOCK(p);
1865168752Sscottl		oldmask = td->td_siglist;
1866168752Sscottl		PROC_UNLOCK(p);
1867168752Sscottl	}
1868168752Sscottl	if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100)
1869168752Sscottl		while (tp->t_outq.c_cc > hiwat) {
1870168752Sscottl			ttstart(tp);
187140020Sken			if (tp->t_outq.c_cc <= hiwat)
1872141031Ssobomax				break;
187339213Sgibbs			if (!wait) {
187439213Sgibbs				splx(s);
187539213Sgibbs				return (0);
187639213Sgibbs			}
187739213Sgibbs			PROC_LOCK(p);
187839213Sgibbs			if (!SIGSETEQ(td->td_siglist, oldmask)) {
1879111206Sken				PROC_UNLOCK(p);
1880111206Sken				splx(s);
188139213Sgibbs				return (0);
1882111206Sken			}
1883169562Sscottl			PROC_UNLOCK(p);
1884111206Sken			SET(tp->t_state, TS_SO_OLOWAT);
188539213Sgibbs			tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz);
1886168752Sscottl		}
188739213Sgibbs	splx(s);
188839213Sgibbs	return (1);
188939213Sgibbs}
1890111206Sken
189139213Sgibbs/*
1892169562Sscottl * Process a write call on a tty device.
1893168752Sscottl */
189439213Sgibbsint
189539213Sgibbsttwrite(struct tty *tp, struct uio *uio, int flag)
1896111206Sken{
1897111206Sken	char *cp = NULL;
1898111206Sken	int cc, ce;
1899111206Sken	struct thread *td;
1900111206Sken	struct proc *p;
1901169562Sscottl	int i, hiwat, cnt, error, s;
1902168752Sscottl	char obuf[OBUFSIZ];
1903168752Sscottl
190439213Sgibbs	hiwat = tp->t_ohiwat;
1905168752Sscottl	cnt = uio->uio_resid;
1906111206Sken	error = 0;
1907111206Sken	cc = 0;
1908111206Sken	td = curthread;
1909111206Sken	p = td->td_proc;
1910111206Skenloop:
1911111206Sken	s = spltty();
1912111206Sken	if (ISSET(tp->t_state, TS_ZOMBIE)) {
1913111206Sken		splx(s);
1914111206Sken		if (uio->uio_resid == cnt)
1915111206Sken			error = EIO;
1916111206Sken		goto out;
1917111206Sken	}
1918111206Sken	if (!ISSET(tp->t_state, TS_CONNECTED)) {
1919111206Sken		if (flag & IO_NDELAY) {
1920111206Sken			splx(s);
1921111206Sken			error = EWOULDBLOCK;
1922111206Sken			goto out;
1923111206Sken		}
1924111206Sken		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
1925111206Sken				 "ttydcd", 0);
1926111206Sken		splx(s);
1927111206Sken		if (error)
1928111206Sken			goto out;
1929111206Sken		goto loop;
1930111206Sken	}
1931111206Sken	splx(s);
1932111206Sken	/*
1933111206Sken	 * Hang the process if it's in the background.
1934111206Sken	 */
1935111206Sken	sx_slock(&proctree_lock);
1936111206Sken	PROC_LOCK(p);
1937111206Sken	if (isbackground(p, tp) &&
1938111206Sken	    ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) &&
1939111206Sken	    !SIGISMEMBER(p->p_sigacts->ps_sigignore, SIGTTOU) &&
1940111206Sken	    !SIGISMEMBER(td->td_sigmask, SIGTTOU)) {
1941111206Sken		if (p->p_pgrp->pg_jobc == 0) {
1942111206Sken			PROC_UNLOCK(p);
1943111206Sken			sx_sunlock(&proctree_lock);
1944111206Sken			error = EIO;
1945111206Sken			goto out;
1946111206Sken		}
1947111206Sken		PROC_UNLOCK(p);
1948111206Sken		PGRP_LOCK(p->p_pgrp);
1949111206Sken		sx_sunlock(&proctree_lock);
1950111206Sken		pgsignal(p->p_pgrp, SIGTTOU, 1);
1951111206Sken		PGRP_UNLOCK(p->p_pgrp);
1952111206Sken		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0);
1953111206Sken		if (error)
1954111206Sken			goto out;
1955111206Sken		goto loop;
1956111206Sken	} else {
1957111206Sken		PROC_UNLOCK(p);
1958111206Sken		sx_sunlock(&proctree_lock);
1959111206Sken	}
1960111206Sken	/*
1961111206Sken	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
1962111206Sken	 * output translation.  Keep track of high water mark, sleep on
1963111206Sken	 * overflow awaiting device aid in acquiring new space.
1964111206Sken	 */
1965111206Sken	while (uio->uio_resid > 0 || cc > 0) {
196639213Sgibbs		if (ISSET(tp->t_lflag, FLUSHO)) {
1967168752Sscottl			uio->uio_resid = 0;
196839213Sgibbs			return (0);
196939213Sgibbs		}
197039213Sgibbs		if (tp->t_outq.c_cc > hiwat)
197139213Sgibbs			goto ovhiwat;
197239213Sgibbs		/*
197339213Sgibbs		 * Grab a hunk of data from the user, unless we have some
1974111206Sken		 * leftover from last time.
1975111206Sken		 */
197639213Sgibbs		if (cc == 0) {
1977111206Sken			cc = imin(uio->uio_resid, OBUFSIZ);
1978169562Sscottl			cp = obuf;
1979111206Sken			error = uiomove(cp, cc, uio);
198039213Sgibbs			if (error) {
1981168752Sscottl				cc = 0;
198239213Sgibbs				break;
198339213Sgibbs			}
198439213Sgibbs		}
1985111206Sken		/*
198639213Sgibbs		 * If nothing fancy need be done, grab those characters we
1987169562Sscottl		 * can handle without any of ttyoutput's processing and
1988168752Sscottl		 * just transfer them to the output q.  For those chars
198939213Sgibbs		 * which require special processing (as indicated by the
199039213Sgibbs		 * bits in char_type), call ttyoutput.  After processing
1991111206Sken		 * a hunk of data, look for FLUSHO so ^O's will take effect
1992111206Sken		 * immediately.
1993111206Sken		 */
1994111206Sken		while (cc > 0) {
1995111206Sken			if (!ISSET(tp->t_oflag, OPOST))
1996169562Sscottl				ce = cc;
1997168752Sscottl			else {
1998168752Sscottl				ce = cc - scanc((u_int)cc, (u_char *)cp,
199939213Sgibbs						char_type, CCLASSMASK);
2000168752Sscottl				/*
200139213Sgibbs				 * If ce is zero, then we're processing
200239213Sgibbs				 * a special character through ttyoutput.
200339213Sgibbs				 */
200439213Sgibbs				if (ce == 0) {
200539213Sgibbs					tp->t_rocount = 0;
200639213Sgibbs					if (ttyoutput(*cp, tp) >= 0) {
200739213Sgibbs						/* No Clists, wait a bit. */
2008168752Sscottl						ttstart(tp);
200939213Sgibbs						if (flag & IO_NDELAY) {
201039213Sgibbs							error = EWOULDBLOCK;
201139213Sgibbs							goto out;
201239213Sgibbs						}
201339213Sgibbs						error = ttysleep(tp, &lbolt,
201439213Sgibbs								 TTOPRI|PCATCH,
2015111206Sken								 "ttybf1", 0);
2016111206Sken						if (error)
201739213Sgibbs							goto out;
2018111206Sken						goto loop;
2019169562Sscottl					}
2020111206Sken					cp++;
202139213Sgibbs					cc--;
2022168752Sscottl					if (ISSET(tp->t_lflag, FLUSHO) ||
2023168752Sscottl					    tp->t_outq.c_cc > hiwat)
2024168752Sscottl						goto ovhiwat;
2025168752Sscottl					continue;
2026168752Sscottl				}
2027111206Sken			}
202839213Sgibbs			/*
2029169562Sscottl			 * A bunch of normal characters have been found.
2030168752Sscottl			 * Transfer them en masse to the output queue and
203139213Sgibbs			 * continue processing at the top of the loop.
203239213Sgibbs			 * If there are any further characters in this
2033111206Sken			 * <= OBUFSIZ chunk, the first should be a character
2034111206Sken			 * requiring special handling by ttyoutput.
2035111206Sken			 */
2036111206Sken			tp->t_rocount = 0;
2037111206Sken			i = b_to_q(cp, ce, &tp->t_outq);
2038169562Sscottl			ce -= i;
2039168752Sscottl			tp->t_column += ce;
2040168752Sscottl			cp += ce, cc -= ce, tk_nout += ce;
204139213Sgibbs			tp->t_outcc += ce;
2042168752Sscottl			if (i > 0) {
204339213Sgibbs				/* No Clists, wait a bit. */
2044168752Sscottl				ttstart(tp);
204539213Sgibbs				if (flag & IO_NDELAY) {
204639213Sgibbs					error = EWOULDBLOCK;
2047141031Ssobomax					goto out;
2048141031Ssobomax				}
2049141031Ssobomax				error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
205039213Sgibbs						 "ttybf2", 0);
205139213Sgibbs				if (error)
205239213Sgibbs					goto out;
205339213Sgibbs				goto loop;
205439213Sgibbs			}
205539213Sgibbs			if (ISSET(tp->t_lflag, FLUSHO) ||
205639213Sgibbs			    tp->t_outq.c_cc > hiwat)
2057168752Sscottl				break;
2058169562Sscottl		}
2059168752Sscottl		ttstart(tp);
2060168752Sscottl	}
206139213Sgibbsout:
206239213Sgibbs	/*
206339213Sgibbs	 * If cc is nonzero, we leave the uio structure inconsistent, as the
206439213Sgibbs	 * offset and iov pointers have moved forward, but it doesn't matter
206539213Sgibbs	 * (the call will either return short or restart with a new uio).
206639213Sgibbs	 */
206739213Sgibbs	uio->uio_resid += cc;
206839213Sgibbs	return (error);
206939213Sgibbs
207039213Sgibbsovhiwat:
2071169562Sscottl	ttstart(tp);
2072168752Sscottl	s = spltty();
207339213Sgibbs	/*
207439213Sgibbs	 * This can only occur if FLUSHO is set in t_lflag,
207539213Sgibbs	 * or if ttstart/oproc is synchronous (or very fast).
207639213Sgibbs	 */
207739213Sgibbs	if (tp->t_outq.c_cc <= hiwat) {
207839213Sgibbs		splx(s);
207939213Sgibbs		goto loop;
208039213Sgibbs	}
208139213Sgibbs	if (flag & IO_NDELAY) {
208239213Sgibbs		splx(s);
2083169562Sscottl		uio->uio_resid += cc;
2084168752Sscottl		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
208539213Sgibbs	}
208639213Sgibbs	SET(tp->t_state, TS_SO_OLOWAT);
208739213Sgibbs	error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",
208839213Sgibbs			 tp->t_timeout);
208939213Sgibbs	splx(s);
209039213Sgibbs	if (error == EWOULDBLOCK)
209139213Sgibbs		error = EIO;
209239213Sgibbs	if (error)
2093168752Sscottl		goto out;
2094141031Ssobomax	goto loop;
2095141031Ssobomax}
2096141031Ssobomax
2097141031Ssobomax/*
2098141031Ssobomax * Rubout one character from the rawq of tp
2099141031Ssobomax * as cleanly as possible.
210039213Sgibbs */
2101169562Sscottlstatic void
210239213Sgibbsttyrub(int c, struct tty *tp)
210339213Sgibbs{
210439213Sgibbs	char *cp;
210539213Sgibbs	int savecol;
210639213Sgibbs	int tabc, s;
210739213Sgibbs
210839213Sgibbs	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
2109169562Sscottl		return;
2110168752Sscottl	CLR(tp->t_lflag, FLUSHO);
2111168752Sscottl	if (ISSET(tp->t_lflag, ECHOE)) {
2112168752Sscottl		if (tp->t_rocount == 0) {
211339213Sgibbs			/*
211439213Sgibbs			 * Screwed by ttwrite; retype
211539213Sgibbs			 */
2116111206Sken			ttyretype(tp);
2117111206Sken			return;
211839213Sgibbs		}
2119169562Sscottl		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
2120168752Sscottl			ttyrubo(tp, 2);
212139213Sgibbs		else {
212239213Sgibbs			CLR(c, ~TTY_CHARMASK);
212339213Sgibbs			switch (CCLASS(c)) {
212439213Sgibbs			case ORDINARY:
212539213Sgibbs				ttyrubo(tp, 1);
212639213Sgibbs				break;
212739213Sgibbs			case BACKSPACE:
212839213Sgibbs			case CONTROL:
212939213Sgibbs			case NEWLINE:
213039213Sgibbs			case RETURN:
213190868Smike			case VTAB:
213239213Sgibbs				if (ISSET(tp->t_lflag, ECHOCTL))
2133169562Sscottl					ttyrubo(tp, 2);
2134168752Sscottl				break;
213539213Sgibbs			case TAB:
213639213Sgibbs				if (tp->t_rocount < tp->t_rawq.c_cc) {
213739213Sgibbs					ttyretype(tp);
213839213Sgibbs					return;
2139111206Sken				}
2140111206Sken				s = spltty();
214139213Sgibbs				savecol = tp->t_column;
214239213Sgibbs				SET(tp->t_state, TS_CNTTB);
214339213Sgibbs				SET(tp->t_lflag, FLUSHO);
214439213Sgibbs				tp->t_column = tp->t_rocol;
214539213Sgibbs				cp = tp->t_rawq.c_cf;
214639213Sgibbs				if (cp)
2147169562Sscottl					tabc = *cp;	/* XXX FIX NEXTC */
2148169562Sscottl				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
2149168752Sscottl					ttyecho(tabc, tp);
2150168752Sscottl				CLR(tp->t_lflag, FLUSHO);
215139213Sgibbs				CLR(tp->t_state, TS_CNTTB);
215239213Sgibbs				splx(s);
215339213Sgibbs
215439213Sgibbs				/* savecol will now be length of the tab. */
215539213Sgibbs				savecol -= tp->t_column;
215639213Sgibbs				tp->t_column += savecol;
215739213Sgibbs				if (savecol > 8)
215839213Sgibbs					savecol = 8;	/* overflow screw */
215939213Sgibbs				while (--savecol >= 0)
216039213Sgibbs					(void)ttyoutput('\b', tp);
2161169562Sscottl				break;
2162169562Sscottl			default:			/* XXX */
2163168752Sscottl#define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
216439213Sgibbs				(void)printf(PANICSTR, c, CCLASS(c));
216539213Sgibbs#ifdef notdef
216639213Sgibbs				panic(PANICSTR, c, CCLASS(c));
216739213Sgibbs#endif
2168111206Sken			}
2169111206Sken		}
217039213Sgibbs	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
2171169562Sscottl		if (!ISSET(tp->t_state, TS_ERASE)) {
2172169562Sscottl			SET(tp->t_state, TS_ERASE);
2173168752Sscottl			(void)ttyoutput('\\', tp);
217439213Sgibbs		}
217539213Sgibbs		ttyecho(c, tp);
217639213Sgibbs	} else {
217739213Sgibbs		ttyecho(tp->t_cc[VERASE], tp);
217839213Sgibbs		/*
217939213Sgibbs		 * This code may be executed not only when an ERASE key
218039213Sgibbs		 * is pressed, but also when ^U (KILL) or ^W (WERASE) are.
218139213Sgibbs		 * So, I didn't think it was worthwhile to pass the extra
218239213Sgibbs		 * information (which would need an extra parameter,
218339213Sgibbs		 * changing every call) needed to distinguish the ERASE2
218439213Sgibbs		 * case from the ERASE.
218539213Sgibbs		 */
218639213Sgibbs	}
218739213Sgibbs	--tp->t_rocount;
218839213Sgibbs}
218939213Sgibbs
219039213Sgibbs/*
219139213Sgibbs * Back over cnt characters, erasing them.
219239213Sgibbs */
219339213Sgibbsstatic void
2194169562Sscottlttyrubo(struct tty *tp, int cnt)
2195169562Sscottl{
2196168752Sscottl
219739213Sgibbs	while (cnt-- > 0) {
219839213Sgibbs		(void)ttyoutput('\b', tp);
219939213Sgibbs		(void)ttyoutput(' ', tp);
220039213Sgibbs		(void)ttyoutput('\b', tp);
220139213Sgibbs	}
220239213Sgibbs}
220339213Sgibbs
220439213Sgibbs/*
220539213Sgibbs * ttyretype --
220639213Sgibbs *	Reprint the rawq line.  Note, it is assumed that c_cc has already
220739213Sgibbs *	been checked.
220839213Sgibbs */
220939213Sgibbsstatic void
221039213Sgibbsttyretype(struct tty *tp)
221139213Sgibbs{
221239213Sgibbs	char *cp;
221339213Sgibbs	int s, c;
221439213Sgibbs
221539213Sgibbs	/* Echo the reprint character. */
2216169562Sscottl	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
2217169562Sscottl		ttyecho(tp->t_cc[VREPRINT], tp);
2218168752Sscottl
221939213Sgibbs	(void)ttyoutput('\n', tp);
222039213Sgibbs
222139213Sgibbs	/*
222239213Sgibbs	 * XXX
222339213Sgibbs	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
222439213Sgibbs	 * BIT OF FIRST CHAR.
222539213Sgibbs	 */
2226111206Sken	s = spltty();
2227111206Sken	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
2228111206Sken	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
222939213Sgibbs		ttyecho(c, tp);
2230169562Sscottl	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
2231169562Sscottl	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
2232168752Sscottl		ttyecho(c, tp);
223339213Sgibbs	CLR(tp->t_state, TS_ERASE);
223439213Sgibbs	splx(s);
223539213Sgibbs
223639213Sgibbs	tp->t_rocount = tp->t_rawq.c_cc;
223739213Sgibbs	tp->t_rocol = 0;
223839213Sgibbs}
223939213Sgibbs
224039213Sgibbs/*
224139213Sgibbs * Echo a typed character to the terminal.
224239213Sgibbs */
2243111206Skenstatic void
2244111206Skenttyecho(int c, struct tty *tp)
2245111206Sken{
224639213Sgibbs
2247169562Sscottl	if (!ISSET(tp->t_state, TS_CNTTB))
2248169562Sscottl		CLR(tp->t_lflag, FLUSHO);
2249168752Sscottl	if ((!ISSET(tp->t_lflag, ECHO) &&
225039213Sgibbs	     (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
225139213Sgibbs	    ISSET(tp->t_lflag, EXTPROC))
225239213Sgibbs		return;
225339213Sgibbs	if (ISSET(tp->t_lflag, ECHOCTL) &&
225439213Sgibbs	    ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
225539213Sgibbs	    ISSET(c, TTY_CHARMASK) == 0177)) {
225639213Sgibbs		(void)ttyoutput('^', tp);
225739213Sgibbs		CLR(c, ~TTY_CHARMASK);
225839213Sgibbs		if (c == 0177)
225939213Sgibbs			c = '?';
226039213Sgibbs		else
226139213Sgibbs			c += 'A' - 1;
2262168752Sscottl	}
226339213Sgibbs	(void)ttyoutput(c, tp);
2264169562Sscottl}
2265169562Sscottl
226639213Sgibbs/*
226739213Sgibbs * Wake up any readers on a tty.
226839213Sgibbs */
226939213Sgibbsvoid
2270111206Skenttwakeup(struct tty *tp)
227139213Sgibbs{
227239213Sgibbs
227339213Sgibbs	if (SEL_WAITING(&tp->t_rsel))
227439213Sgibbs		selwakeup(&tp->t_rsel);
227539213Sgibbs	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2276169562Sscottl		pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
2277168752Sscottl	wakeup(TSA_HUP_OR_INPUT(tp));
2278168752Sscottl	KNOTE(&tp->t_rsel.si_note, 0);
227939213Sgibbs}
228039213Sgibbs
228139213Sgibbs/*
228239213Sgibbs * Wake up any writers on a tty.
228339213Sgibbs */
228439213Sgibbsvoid
228539213Sgibbsttwwakeup(struct tty *tp)
2286169562Sscottl{
228739213Sgibbs
2288168752Sscottl	if (SEL_WAITING(&tp->t_wsel) && tp->t_outq.c_cc <= tp->t_olowat)
228939213Sgibbs		selwakeup(&tp->t_wsel);
229039213Sgibbs	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
229139213Sgibbs		pgsigio(&tp->t_sigio, SIGIO, (tp->t_session != NULL));
229239213Sgibbs	if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
2293111206Sken	    TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
2294111206Sken		CLR(tp->t_state, TS_SO_OCOMPLETE);
229539213Sgibbs		wakeup(TSA_OCOMPLETE(tp));
2296169562Sscottl	}
2297168752Sscottl	if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
229839213Sgibbs	    tp->t_outq.c_cc <= tp->t_olowat) {
229939213Sgibbs		CLR(tp->t_state, TS_SO_OLOWAT);
230039213Sgibbs		wakeup(TSA_OLOWAT(tp));
230139213Sgibbs	}
230239213Sgibbs	KNOTE(&tp->t_wsel.si_note, 0);
230339213Sgibbs}
230439213Sgibbs
230539213Sgibbs/*
230639213Sgibbs * Look up a code for a specified speed in a conversion table;
230739213Sgibbs * used by drivers to map software speed values to hardware parameters.
230839213Sgibbs */
230939213Sgibbsint
231039213Sgibbsttspeedtab(int speed, struct speedtab *table)
231139213Sgibbs{
231239213Sgibbs
231339213Sgibbs	for ( ; table->sp_speed != -1; table++)
231439213Sgibbs		if (table->sp_speed == speed)
231539213Sgibbs			return (table->sp_code);
231639213Sgibbs	return (-1);
231739213Sgibbs}
2318169562Sscottl
231939213Sgibbs/*
2320168752Sscottl * Set input and output watermarks and buffer sizes.  For input, the
232139213Sgibbs * high watermark is about one second's worth of input above empty, the
232239213Sgibbs * low watermark is slightly below high water, and the buffer size is a
232339213Sgibbs * driver-dependent amount above high water.  For output, the watermarks
232439213Sgibbs * are near the ends of the buffer, with about 1 second's worth of input
2325111206Sken * between them.  All this only applies to the standard line discipline.
2326111206Sken */
232739213Sgibbsvoid
2328169562Sscottlttsetwater(struct tty *tp)
2329168752Sscottl{
233039213Sgibbs	int cps, ttmaxhiwat, x;
233139213Sgibbs
233239213Sgibbs	/* Input. */
233339213Sgibbs	clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
233439213Sgibbs	switch (tp->t_ispeedwat) {
233539213Sgibbs	case (speed_t)-1:
233639213Sgibbs		cps = tp->t_ispeed / 10;
2337169562Sscottl		break;
2338168752Sscottl	case 0:
233939213Sgibbs		/*
234039213Sgibbs		 * This case is for old drivers that don't know about
234139213Sgibbs		 * t_ispeedwat.  Arrange for them to get the old buffer
234239213Sgibbs		 * sizes and watermarks.
2343111206Sken		 */
2344111206Sken		cps = TTYHOG - 2 * 256;
2345111206Sken		tp->t_ififosize = 2 * 256;
234639213Sgibbs		break;
2347168752Sscottl	default:
2348169562Sscottl		cps = tp->t_ispeedwat / 10;
2349168752Sscottl		break;
2350168752Sscottl	}
2351168752Sscottl	tp->t_ihiwat = cps;
235239213Sgibbs	tp->t_ilowat = 7 * cps / 8;
235339213Sgibbs	x = cps + tp->t_ififosize;
235439213Sgibbs	clist_alloc_cblocks(&tp->t_rawq, x, x);
2355111206Sken
235639213Sgibbs	/* Output. */
2357169562Sscottl	switch (tp->t_ospeedwat) {
2358168752Sscottl	case (speed_t)-1:
235939213Sgibbs		cps = tp->t_ospeed / 10;
236039213Sgibbs		ttmaxhiwat = 2 * TTMAXHIWAT;
2361111206Sken		break;
2362111206Sken	case 0:
2363111206Sken		cps = tp->t_ospeed / 10;
236439213Sgibbs		ttmaxhiwat = TTMAXHIWAT;
2365111206Sken		break;
236639213Sgibbs	default:
2367111206Sken		cps = tp->t_ospeedwat / 10;
2368111206Sken		ttmaxhiwat = 8 * TTMAXHIWAT;
2369111206Sken		break;
2370169562Sscottl	}
2371168752Sscottl#define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
237239213Sgibbs	tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
237339213Sgibbs	x += cps;
237439213Sgibbs	x = CLAMP(x, ttmaxhiwat, TTMINHIWAT);	/* XXX clamps are too magic */
237539213Sgibbs	tp->t_ohiwat = roundup(x, CBSIZE);	/* XXX for compat */
237639213Sgibbs	x = imax(tp->t_ohiwat, TTMAXHIWAT);	/* XXX for compat/safety */
2377111206Sken	x += OBUFSIZ + 100;
2378111206Sken	clist_alloc_cblocks(&tp->t_outq, x, x);
237939213Sgibbs#undef	CLAMP
2380168752Sscottl}
2381169562Sscottl
2382168752Sscottl/*
2383168752Sscottl * Report on state of foreground process group.
2384168752Sscottl */
238539213Sgibbsvoid
238639213Sgibbsttyinfo(struct tty *tp)
238739213Sgibbs{
2388111206Sken	struct proc *p, *pick;
238939213Sgibbs	struct timeval utime, stime;
2390169562Sscottl	const char *stmp, *sprefix;
2391168752Sscottl	long ltmp;
239239213Sgibbs	int tmp;
239339213Sgibbs	struct thread *td;
2394111206Sken
2395111206Sken	if (ttycheckoutq(tp,0) == 0)
239639213Sgibbs		return;
2397111206Sken
239839213Sgibbs	/* Print load average. */
2399111206Sken	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
2400111206Sken	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
2401111206Sken
2402169562Sscottl	if (tp->t_session == NULL)
2403168752Sscottl		ttyprintf(tp, "not a controlling terminal\n");
240439213Sgibbs	else if (tp->t_pgrp == NULL)
240539213Sgibbs		ttyprintf(tp, "no foreground process group\n");
240639213Sgibbs	else {
240739213Sgibbs		PGRP_LOCK(tp->t_pgrp);
240839213Sgibbs		if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) {
2409111206Sken			PGRP_UNLOCK(tp->t_pgrp);
2410111206Sken			ttyprintf(tp, "empty foreground process group\n");
241139213Sgibbs		} else {
2412168752Sscottl			mtx_lock_spin(&sched_lock);
2413169562Sscottl
2414168752Sscottl			/* Pick interesting process. */
2415168752Sscottl			for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist))
2416168752Sscottl				if (proc_compare(pick, p))
241739213Sgibbs					pick = p;
241839213Sgibbs			PGRP_UNLOCK(tp->t_pgrp);
241939213Sgibbs
2420111206Sken			td = FIRST_THREAD_IN_PROC(pick);
242139213Sgibbs			sprefix = "";
2422169562Sscottl			if (pick->p_flag & P_THREADED) {
2423168752Sscottl				stmp = "KSE" ;  /* XXXKSE */
242439213Sgibbs			} else {
242539213Sgibbs				if (td) {
2426111206Sken					if (TD_ON_RUNQ(td) ||
2427111206Sken					    (TD_IS_RUNNING(td))) {
2428111206Sken						stmp = "running";
2429111206Sken					} else if (TD_ON_LOCK(td)) {
243039213Sgibbs						stmp = td->td_lockname;
2431111206Sken						sprefix = "*";
2432111206Sken					} else if (td->td_wmesg) {
243339213Sgibbs						stmp = td->td_wmesg;
2434111206Sken					} else {
2435111206Sken						stmp = "iowait";
2436111206Sken					}
2437168752Sscottl				} else {
2438169562Sscottl					stmp = "threadless";
243939213Sgibbs					panic("ttyinfo: no thread!?");
244039213Sgibbs				}
244139213Sgibbs			}
244239213Sgibbs			calcru(pick, &utime, &stime, NULL);
2443111206Sken			if (pick->p_state == PRS_NEW ||
2444111206Sken			    pick->p_state == PRS_ZOMBIE) {
244539213Sgibbs				ltmp = 0;
2446168752Sscottl			} else {
2447169562Sscottl				ltmp = pgtok(
2448168752Sscottl				    vmspace_resident_count(pick->p_vmspace));
2449168752Sscottl			}
2450168752Sscottl			mtx_unlock_spin(&sched_lock);
245139213Sgibbs
245239213Sgibbs			ttyprintf(tp, " cmd: %s %d [%s%s] ", pick->p_comm,
245339213Sgibbs			    pick->p_pid, sprefix, stmp);
2454111206Sken
245539213Sgibbs			/* Print user time. */
2456169562Sscottl			ttyprintf(tp, "%ld.%02ldu ",
2457168752Sscottl			    utime.tv_sec, utime.tv_usec / 10000);
245839213Sgibbs
245939213Sgibbs			/* Print system time. */
2460111206Sken			ttyprintf(tp, "%ld.%02lds ",
2461111206Sken			    (long)stime.tv_sec, stime.tv_usec / 10000);
2462111206Sken
246339213Sgibbs			/* Print percentage cpu, resident set size. */
2464111206Sken			ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp);
246539213Sgibbs
2466111206Sken		}
2467111206Sken	}
2468111206Sken	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
2469168752Sscottl}
2470169562Sscottl
247139213Sgibbs/*
247239213Sgibbs * Returns 1 if p2 is "better" than p1
247339213Sgibbs *
247439213Sgibbs * The algorithm for picking the "interesting" process is thus:
2475111206Sken *
2476111206Sken *	1) Only foreground processes are eligible - implied.
247739213Sgibbs *	2) Runnable processes are favored over anything else.  The runner
2478168752Sscottl *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
2479169562Sscottl *	   broken by picking the highest pid.
2480168752Sscottl *	3) The sleeper with the shortest sleep time is next.  With ties,
2481168752Sscottl *	   we pick out just "short-term" sleepers (P_SINTR == 0).
2482168752Sscottl *	4) Further ties are broken by picking the highest pid.
248339213Sgibbs */
248439213Sgibbs#define ISRUN(p, val)						\
248539213Sgibbsdo {								\
2486111206Sken	struct thread *td;					\
248739213Sgibbs	val = 0;						\
2488169562Sscottl	FOREACH_THREAD_IN_PROC(p, td) {				\
2489168752Sscottl		if (TD_ON_RUNQ(td) ||				\
249039213Sgibbs		    TD_IS_RUNNING(td)) {			\
249139213Sgibbs			val = 1;				\
2492111206Sken			break;					\
2493111206Sken		}						\
2494111206Sken	}							\
249539213Sgibbs} while (0)
2496111206Sken
249739213Sgibbs#define TESTAB(a, b)    ((a)<<1 | (b))
2498111206Sken#define ONLYA   2
2499111206Sken#define ONLYB   1
2500111206Sken#define BOTH    3
2501169562Sscottl
2502168752Sscottlstatic int
250339213Sgibbsproc_compare(struct proc *p1, struct proc *p2)
250439213Sgibbs{
250539213Sgibbs
250639213Sgibbs	int esta, estb;
2507111206Sken	struct ksegrp *kg;
2508111206Sken	mtx_assert(&sched_lock, MA_OWNED);
250939213Sgibbs	if (p1 == NULL)
2510168752Sscottl		return (1);
2511169562Sscottl
2512168752Sscottl	ISRUN(p1, esta);
2513168752Sscottl	ISRUN(p2, estb);
2514168752Sscottl
251539213Sgibbs	/*
251639213Sgibbs	 * see if at least one of them is runnable
251739213Sgibbs	 */
2518111206Sken	switch (TESTAB(esta, estb)) {
251939213Sgibbs	case ONLYA:
2520169562Sscottl		return (0);
2521168752Sscottl	case ONLYB:
252239213Sgibbs		return (1);
252339213Sgibbs	case BOTH:
2524111206Sken		/*
2525111206Sken		 * tie - favor one with highest recent cpu utilization
2526111206Sken		 */
2527111206Sken		esta = estb = 0;
2528111206Sken		FOREACH_KSEGRP_IN_PROC(p1,kg) {
2529111206Sken			esta += kg->kg_estcpu;
2530111206Sken		}
2531169562Sscottl		FOREACH_KSEGRP_IN_PROC(p2,kg) {
2532168752Sscottl			estb += kg->kg_estcpu;
253339213Sgibbs		}
253439213Sgibbs		if (estb > esta)
253539213Sgibbs			return (1);
253639213Sgibbs		if (esta > estb)
2537111206Sken			return (0);
2538111206Sken		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
253939213Sgibbs	}
2540168752Sscottl	/*
2541169562Sscottl	 * weed out zombies
2542168752Sscottl	 */
2543168752Sscottl	switch (TESTAB(p1->p_state == PRS_ZOMBIE, p2->p_state == PRS_ZOMBIE)) {
2544168752Sscottl	case ONLYA:
254539213Sgibbs		return (1);
254639213Sgibbs	case ONLYB:
254739213Sgibbs		return (0);
2548111206Sken	case BOTH:
254939213Sgibbs		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2550169562Sscottl	}
2551168752Sscottl
255239213Sgibbs#if 0 /* XXXKSE */
255339213Sgibbs	/*
2554111206Sken	 * pick the one with the smallest sleep time
2555111206Sken	 */
2556111206Sken	if (p2->p_slptime > p1->p_slptime)
2557111206Sken		return (0);
2558111206Sken	if (p1->p_slptime > p2->p_slptime)
2559111206Sken		return (1);
2560111206Sken	/*
2561169562Sscottl	 * favor one sleeping in a non-interruptible sleep
2562168752Sscottl	 */
256339213Sgibbs	if (p1->p_sflag & PS_SINTR && (p2->p_sflag & PS_SINTR) == 0)
256439213Sgibbs		return (1);
256539213Sgibbs	if (p2->p_sflag & PS_SINTR && (p1->p_sflag & PS_SINTR) == 0)
256639213Sgibbs		return (0);
2567111206Sken#endif
2568111206Sken	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
256939213Sgibbs}
2570111206Sken
2571169562Sscottl/*
2572111206Sken * Output char to tty; console putchar style.
2573111206Sken */
2574168752Sscottlint
2575168752Sscottltputchar(int c, struct tty *tp)
2576168752Sscottl{
2577168752Sscottl	int s;
2578111206Sken
257939213Sgibbs	s = spltty();
2580169562Sscottl	if (!ISSET(tp->t_state, TS_CONNECTED)) {
2581168752Sscottl		splx(s);
258239213Sgibbs		return (-1);
258339213Sgibbs	}
2584111206Sken	if (c == '\n')
2585111206Sken		(void)ttyoutput('\r', tp);
2586111206Sken	(void)ttyoutput(c, tp);
2587111206Sken	ttstart(tp);
2588111206Sken	splx(s);
2589111206Sken	return (0);
2590111206Sken}
2591169562Sscottl
2592168752Sscottl/*
259339213Sgibbs * Sleep on chan, returning ERESTART if tty changed while we napped and
259439213Sgibbs * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep.  If
259539213Sgibbs * the tty is revoked, restarting a pending call will redo validation done
2596168752Sscottl * at the start of the call.
259739213Sgibbs */
2598168752Sscottlint
259939213Sgibbsttysleep(struct tty *tp, void *chan, int pri, char *wmesg, int timo)
260039213Sgibbs{
2601168752Sscottl	int error;
260239213Sgibbs	int gen;
2603168752Sscottl
260439213Sgibbs	gen = tp->t_gen;
260539213Sgibbs	error = tsleep(chan, pri, wmesg, timo);
2606168752Sscottl	if (error)
2607111206Sken		return (error);
2608168752Sscottl	return (tp->t_gen == gen ? 0 : ERESTART);
260939213Sgibbs}
2610111206Sken
2611168752Sscottl/*
2612111206Sken * Allocate a tty struct.  Clists in the struct will be allocated by
2613168752Sscottl * ttyopen().
2614111206Sken */
261539213Sgibbsstruct tty *
2616168752Sscottlttymalloc(struct tty *tp)
261739213Sgibbs{
2618168752Sscottl
261939213Sgibbs	if (tp)
262039213Sgibbs		return(tp);
2621168752Sscottl	tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO);
262239213Sgibbs	ttyregister(tp);
2623168752Sscottl	return (tp);
262439213Sgibbs}
262539213Sgibbs
2626168752Sscottl#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */
262739213Sgibbs/*
2628168752Sscottl * Free a tty struct.  Clists in the struct should have been freed by
262939213Sgibbs * ttyclose().
263039213Sgibbs */
2631168752Sscottlvoid
263239213Sgibbsttyfree(struct tty *tp)
2633168752Sscottl{
263439213Sgibbs	free(tp, M_TTYS);
263539213Sgibbs}
263639213Sgibbs#endif /* 0 */
263739213Sgibbs
263839213Sgibbsvoid
263939213Sgibbsttyregister(struct tty *tp)
264039213Sgibbs{
264139213Sgibbs	tp->t_timeout = -1;
264239213Sgibbs	SLIST_INSERT_HEAD(&tty_list, tp, t_list);
264339213Sgibbs}
264439213Sgibbs
264539213Sgibbsstatic int
264639213Sgibbssysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
2647105421Snjl{
2648168752Sscottl	struct tty *tp;
2649105421Snjl	struct xtty xt;
2650168752Sscottl	int error;
2651105421Snjl
2652105421Snjl	SLIST_FOREACH(tp, &tty_list, t_list) {
2653168752Sscottl		bzero(&xt, sizeof xt);
2654105421Snjl		xt.xt_size = sizeof xt;
2655168752Sscottl#define XT_COPY(field) xt.xt_##field = tp->t_##field
2656105421Snjl		xt.xt_rawcc = tp->t_rawq.c_cc;
265760422Sken		xt.xt_cancc = tp->t_canq.c_cc;
265860422Sken		xt.xt_outcc = tp->t_outq.c_cc;
265960422Sken		XT_COPY(line);
266060422Sken		if (tp->t_dev)
266160422Sken			xt.xt_dev = dev2udev(tp->t_dev);
266260422Sken		XT_COPY(state);
2663168752Sscottl		XT_COPY(flags);
266460422Sken		XT_COPY(timeout);
266560422Sken		if (tp->t_pgrp)
266660422Sken			xt.xt_pgid = tp->t_pgrp->pg_id;
266760422Sken		if (tp->t_session)
2668168752Sscottl			xt.xt_sid = tp->t_session->s_sid;
266960422Sken		XT_COPY(termios);
2670104456Sphk		XT_COPY(winsize);
267160422Sken		XT_COPY(column);
267260422Sken		XT_COPY(rocount);
267360422Sken		XT_COPY(rocol);
267460422Sken		XT_COPY(ififosize);
267560422Sken		XT_COPY(ihiwat);
2676168752Sscottl		XT_COPY(ilowat);
267760422Sken		XT_COPY(ispeedwat);
2678168752Sscottl		XT_COPY(ohiwat);
267960422Sken		XT_COPY(olowat);
268060422Sken		XT_COPY(ospeedwat);
268160422Sken#undef XT_COPY
268239213Sgibbs		error = SYSCTL_OUT(req, &xt, sizeof xt);
2683168752Sscottl		if (error)
268439213Sgibbs			return (error);
2685168752Sscottl	}
268639213Sgibbs	return (0);
268739213Sgibbs}
268839213Sgibbs
2689168752SscottlSYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD,
2690168752Sscottl	0, 0, sysctl_kern_ttys, "S,xtty", "All ttys");
2691168752SscottlSYSCTL_LONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD,
269239213Sgibbs	&tk_nin, 0, "Total TTY in characters");
2693104456SphkSYSCTL_LONG(_kern, OID_AUTO, tty_nout, CTLFLAG_RD,
2694104456Sphk	&tk_nout, 0, "Total TTY out characters");
2695104456Sphk
2696168752Sscottlvoid
269739213Sgibbsnottystop(struct tty *tp, int rw)
269839213Sgibbs{
269939213Sgibbs
270039213Sgibbs	return;
270139213Sgibbs}
270239213Sgibbs
270339213Sgibbsint
270439213Sgibbsttyread(dev_t dev, struct uio *uio, int flag)
270539213Sgibbs{
270639213Sgibbs	struct tty *tp;
270739213Sgibbs
270839213Sgibbs	tp = dev->si_tty;
270939213Sgibbs	if (tp == NULL)
271039213Sgibbs		return (ENODEV);
271139213Sgibbs	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
271239213Sgibbs}
271339213Sgibbs
271439213Sgibbsint
271539213Sgibbsttywrite(dev_t dev, struct uio *uio, int flag)
271639213Sgibbs{
271739213Sgibbs	struct tty *tp;
271839213Sgibbs
271939213Sgibbs	tp = dev->si_tty;
272039213Sgibbs	if (tp == NULL)
272139213Sgibbs		return (ENODEV);
272239213Sgibbs	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
272339213Sgibbs}
272439213Sgibbs