tty.c revision 73929
197883Sgibbs/*-
297883Sgibbs * Copyright (c) 1982, 1986, 1990, 1991, 1993
397883Sgibbs *	The Regents of the University of California.  All rights reserved.
4102684Sgibbs * (c) UNIX System Laboratories, Inc.
5102684Sgibbs * All or some portions of this file are derived from material licensed
697883Sgibbs * to the University of California by American Telephone and Telegraph
797883Sgibbs * Co. or Unix System Laboratories, Inc. and are reproduced herein with
897883Sgibbs * the permission of UNIX System Laboratories, Inc.
997883Sgibbs *
1097883Sgibbs * Redistribution and use in source and binary forms, with or without
1197883Sgibbs * modification, are permitted provided that the following conditions
1297883Sgibbs * are met:
1397883Sgibbs * 1. Redistributions of source code must retain the above copyright
1497883Sgibbs *    notice, this list of conditions and the following disclaimer.
1597883Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1697883Sgibbs *    notice, this list of conditions and the following disclaimer in the
1797883Sgibbs *    documentation and/or other materials provided with the distribution.
1897883Sgibbs * 3. All advertising materials mentioning features or use of this software
1997883Sgibbs *    must display the following acknowledgement:
2097883Sgibbs *	This product includes software developed by the University of
2197883Sgibbs *	California, Berkeley and its contributors.
2297883Sgibbs * 4. Neither the name of the University nor the names of its contributors
2397883Sgibbs *    may be used to endorse or promote products derived from this software
2497883Sgibbs *    without specific prior written permission.
2597883Sgibbs *
2697883Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2797883Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2897883Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2997883Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3097883Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3197883Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32111653Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3397883Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3497883Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3597883Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3697883Sgibbs * SUCH DAMAGE.
3797883Sgibbs *
3897883Sgibbs *	@(#)tty.c	8.8 (Berkeley) 1/21/94
3997883Sgibbs * $FreeBSD: head/sys/kern/tty.c 73929 2001-03-07 03:37:06Z jhb $
4097883Sgibbs */
4197883Sgibbs
4297883Sgibbs/*-
4397883Sgibbs * TODO:
4497883Sgibbs *	o Fix races for sending the start char in ttyflush().
4597883Sgibbs *	o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttyselect().
4697883Sgibbs *	  With luck, there will be MIN chars before select() returns().
4797883Sgibbs *	o Handle CLOCAL consistently for ptys.  Perhaps disallow setting it.
4897883Sgibbs *	o Don't allow input in TS_ZOMBIE case.  It would be visible through
4997883Sgibbs *	  FIONREAD.
5097883Sgibbs *	o Do the new sio locking stuff here and use it to avoid special
5197883Sgibbs *	  case for EXTPROC?
5297883Sgibbs *	o Lock PENDIN too?
5397883Sgibbs *	o Move EXTPROC and/or PENDIN to t_state?
5497883Sgibbs *	o Wrap most of ttioctl in spltty/splx.
5597883Sgibbs *	o Implement TIOCNOTTY or remove it from <sys/ioctl.h>.
5697883Sgibbs *	o Send STOP if IXOFF is toggled off while TS_TBLOCK is set.
5797883Sgibbs *	o Don't allow certain termios flags to affect disciplines other
5897883Sgibbs *	  than TTYDISC.  Cancel their effects before switch disciplines
5997883Sgibbs *	  and ignore them if they are set while we are in another
6097883Sgibbs *	  discipline.
6197883Sgibbs *	o Now that historical speed conversions are handled here, don't
6297883Sgibbs *	  do them in drivers.
6397883Sgibbs *	o Check for TS_CARR_ON being set while everything is closed and not
6497883Sgibbs *	  waiting for carrier.  TS_CARR_ON isn't cleared if nothing is open,
6597883Sgibbs *	  so it would live until the next open even if carrier drops.
6697883Sgibbs *	o Restore TS_WOPEN since it is useful in pstat.  It must be cleared
6797883Sgibbs *	  only when _all_ openers leave open().
6897883Sgibbs */
6997883Sgibbs
7097883Sgibbs#include "opt_snp.h"
7197883Sgibbs#include "opt_compat.h"
7297883Sgibbs#include "opt_uconsole.h"
7397883Sgibbs
7497883Sgibbs#include <sys/param.h>
7597883Sgibbs#include <sys/systm.h>
7697883Sgibbs#include <sys/filio.h>
7797883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
7897883Sgibbs#include <sys/ioctl_compat.h>
7997883Sgibbs#endif
8097883Sgibbs#include <sys/proc.h>
8197883Sgibbs#define	TTYDEFCHARS
8297883Sgibbs#include <sys/tty.h>
8397883Sgibbs#undef	TTYDEFCHARS
8497883Sgibbs#include <sys/fcntl.h>
8597883Sgibbs#include <sys/conf.h>
8697883Sgibbs#include <sys/dkstat.h>
8797883Sgibbs#include <sys/poll.h>
8897883Sgibbs#include <sys/kernel.h>
8997883Sgibbs#include <sys/vnode.h>
9097883Sgibbs#include <sys/signalvar.h>
9197883Sgibbs#include <sys/resourcevar.h>
9297883Sgibbs#include <sys/malloc.h>
9397883Sgibbs#include <sys/filedesc.h>
9497883Sgibbs#ifdef DEV_SNP
9597883Sgibbs#include <sys/snoop.h>
9697883Sgibbs#endif
9797883Sgibbs#include <sys/sysctl.h>
9897883Sgibbs
9997883Sgibbs#include <vm/vm.h>
10097883Sgibbs#include <sys/lock.h>
10197883Sgibbs#include <vm/pmap.h>
10297883Sgibbs#include <vm/vm_map.h>
10397883Sgibbs
10497883SgibbsMALLOC_DEFINE(M_TTYS, "ttys", "tty data structures");
10597883Sgibbs
10697883Sgibbsstatic int	proc_compare __P((struct proc *p1, struct proc *p2));
10797883Sgibbsstatic int	ttnread __P((struct tty *tp));
10897883Sgibbsstatic void	ttyecho __P((int c, struct tty *tp));
10997883Sgibbsstatic int	ttyoutput __P((int c, register struct tty *tp));
11097883Sgibbsstatic void	ttypend __P((struct tty *tp));
11197883Sgibbsstatic void	ttyretype __P((struct tty *tp));
11297883Sgibbsstatic void	ttyrub __P((int c, struct tty *tp));
11397883Sgibbsstatic void	ttyrubo __P((struct tty *tp, int cnt));
11497883Sgibbsstatic void	ttyunblock __P((struct tty *tp));
11597883Sgibbsstatic int	ttywflush __P((struct tty *tp));
11697883Sgibbsstatic int	filt_ttyread __P((struct knote *kn, long hint));
11797883Sgibbsstatic void 	filt_ttyrdetach __P((struct knote *kn));
11897883Sgibbsstatic int	filt_ttywrite __P((struct knote *kn, long hint));
11997883Sgibbsstatic void 	filt_ttywdetach __P((struct knote *kn));
12097883Sgibbs
12197883Sgibbs/*
12297883Sgibbs * Table with character classes and parity. The 8th bit indicates parity,
12397883Sgibbs * the 7th bit indicates the character is an alphameric or underscore (for
12497883Sgibbs * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
12597883Sgibbs * are 0 then the character needs no special processing on output; classes
12697883Sgibbs * other than 0 might be translated or (not currently) require delays.
12797883Sgibbs */
12897883Sgibbs#define	E	0x00	/* Even parity. */
12997883Sgibbs#define	O	0x80	/* Odd parity. */
13097883Sgibbs#define	PARITY(c)	(char_type[c] & O)
13197883Sgibbs
13297883Sgibbs#define	ALPHA	0x40	/* Alpha or underscore. */
13397883Sgibbs#define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
13497883Sgibbs
13597883Sgibbs#define	CCLASSMASK	0x3f
13697883Sgibbs#define	CCLASS(c)	(char_type[c] & CCLASSMASK)
13797883Sgibbs
13897883Sgibbs#define	BS	BACKSPACE
13997883Sgibbs#define	CC	CONTROL
14097883Sgibbs#define	CR	RETURN
14197883Sgibbs#define	NA	ORDINARY | ALPHA
14297883Sgibbs#define	NL	NEWLINE
14397883Sgibbs#define	NO	ORDINARY
14497883Sgibbs#define	TB	TAB
14597883Sgibbs#define	VT	VTAB
14697883Sgibbs
14797883Sgibbsstatic u_char const char_type[] = {
14897883Sgibbs	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
14997883Sgibbs	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
15097883Sgibbs	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
15197883Sgibbs	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
15297883Sgibbs	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
15397883Sgibbs	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
15497883Sgibbs	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
15597883Sgibbs	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
15697883Sgibbs	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
15797883Sgibbs	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
15897883Sgibbs	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
15997883Sgibbs	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
16097883Sgibbs	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
16197883Sgibbs	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
16297883Sgibbs	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
16397883Sgibbs	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
16497883Sgibbs	/*
16597883Sgibbs	 * Meta chars; should be settable per character set;
16697883Sgibbs	 * for now, treat them all as normal characters.
16797883Sgibbs	 */
16897883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
16997883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17097883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17197883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17297883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17397883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
174102684Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17597883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17697883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17797883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
17897883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
179102684Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
180102684Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
18197883Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
182102684Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
183102684Sgibbs	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
18497883Sgibbs};
18597883Sgibbs#undef	BS
18697883Sgibbs#undef	CC
18797883Sgibbs#undef	CR
18897883Sgibbs#undef	NA
18997883Sgibbs#undef	NL
19097883Sgibbs#undef	NO
19197883Sgibbs#undef	TB
19297883Sgibbs#undef	VT
19397883Sgibbs
19497883Sgibbs/* Macros to clear/set/test flags. */
19597883Sgibbs#define	SET(t, f)	(t) |= (f)
19697883Sgibbs#define	CLR(t, f)	(t) &= ~(f)
19797883Sgibbs#define	ISSET(t, f)	((t) & (f))
19897883Sgibbs
19997883Sgibbs#undef MAX_INPUT		/* XXX wrong in <sys/syslimits.h> */
20097883Sgibbs#define	MAX_INPUT	TTYHOG	/* XXX limit is usually larger for !ICANON */
20197883Sgibbs
20297883Sgibbs/*
20397883Sgibbs * list of struct tty where pstat(8) can pick it up with sysctl
20497883Sgibbs */
20597883Sgibbsstatic SLIST_HEAD(, tty) tty_list;
20697883Sgibbs
20797883Sgibbsstatic int  drainwait = 5*60;
20897883SgibbsSYSCTL_INT(_kern, OID_AUTO, drainwait, CTLFLAG_RW, &drainwait,
20997883Sgibbs	0, "Output drain timeout in seconds");
21097883Sgibbs
21197883Sgibbs/*
21297883Sgibbs * Initial open of tty, or (re)entry to standard tty line discipline.
21397883Sgibbs */
21497883Sgibbsint
21597883Sgibbsttyopen(device, tp)
21697883Sgibbs	dev_t device;
21797883Sgibbs	register struct tty *tp;
21897883Sgibbs{
21997883Sgibbs	int s;
22097883Sgibbs
22197883Sgibbs	s = spltty();
22297883Sgibbs	tp->t_dev = device;
22397883Sgibbs	if (!ISSET(tp->t_state, TS_ISOPEN)) {
22497883Sgibbs		SET(tp->t_state, TS_ISOPEN);
22597883Sgibbs		if (ISSET(tp->t_cflag, CLOCAL))
22697883Sgibbs			SET(tp->t_state, TS_CONNECTED);
22797883Sgibbs		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
22897883Sgibbs	}
22997883Sgibbs	/* XXX don't hang forever on output */
23097883Sgibbs	if (tp->t_timeout < 0)
23197883Sgibbs		tp->t_timeout = drainwait*hz;
23297883Sgibbs	ttsetwater(tp);
23397883Sgibbs	splx(s);
23497883Sgibbs	return (0);
23597883Sgibbs}
23697883Sgibbs
23797883Sgibbs/*
23897883Sgibbs * Handle close() on a tty line: flush and set to initial state,
23997883Sgibbs * bumping generation number so that pending read/write calls
24097883Sgibbs * can detect recycling of the tty.
24197883Sgibbs * XXX our caller should have done `spltty(); l_close(); ttyclose();'
24297883Sgibbs * and l_close() should have flushed, but we repeat the spltty() and
24397883Sgibbs * the flush in case there are buggy callers.
24497883Sgibbs */
24597883Sgibbsint
24697883Sgibbsttyclose(tp)
24797883Sgibbs	register struct tty *tp;
24897883Sgibbs{
24997883Sgibbs	int s;
25097883Sgibbs
25197883Sgibbs	funsetown(tp->t_sigio);
25297883Sgibbs	s = spltty();
25397883Sgibbs	if (constty == tp)
25497883Sgibbs		constty = NULL;
25597883Sgibbs
25697883Sgibbs	ttyflush(tp, FREAD | FWRITE);
25797883Sgibbs	clist_free_cblocks(&tp->t_canq);
25897883Sgibbs	clist_free_cblocks(&tp->t_outq);
25997883Sgibbs	clist_free_cblocks(&tp->t_rawq);
26097883Sgibbs
26197883Sgibbs#ifdef DEV_SNP
26297883Sgibbs	if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
26397883Sgibbs		snpdown((struct snoop *)tp->t_sc);
26497883Sgibbs#endif
26597883Sgibbs
26697883Sgibbs	tp->t_gen++;
26797883Sgibbs	tp->t_line = TTYDISC;
26897883Sgibbs	tp->t_pgrp = NULL;
26997883Sgibbs	tp->t_session = NULL;
27097883Sgibbs	tp->t_state = 0;
27197883Sgibbs	splx(s);
27297883Sgibbs	return (0);
27397883Sgibbs}
27497883Sgibbs
27597883Sgibbs#define	FLUSHQ(q) {							\
27697883Sgibbs	if ((q)->c_cc)							\
27797883Sgibbs		ndflush(q, (q)->c_cc);					\
27897883Sgibbs}
27997883Sgibbs
28097883Sgibbs/* Is 'c' a line delimiter ("break" character)? */
28197883Sgibbs#define	TTBREAKC(c, lflag)							\
28297883Sgibbs	((c) == '\n' || (((c) == cc[VEOF] ||				\
28397883Sgibbs	  (c) == cc[VEOL] || ((c) == cc[VEOL2] && lflag & IEXTEN)) &&	\
28497883Sgibbs	 (c) != _POSIX_VDISABLE))
28597883Sgibbs
28697883Sgibbs/*
28797883Sgibbs * Process input of a single character received on a tty.
28897883Sgibbs */
28997883Sgibbsint
29097883Sgibbsttyinput(c, tp)
29197883Sgibbs	register int c;
29297883Sgibbs	register struct tty *tp;
29397883Sgibbs{
29497883Sgibbs	register tcflag_t iflag, lflag;
29597883Sgibbs	register cc_t *cc;
29697883Sgibbs	int i, err;
29797883Sgibbs
29897883Sgibbs	/*
29997883Sgibbs	 * If input is pending take it first.
30097883Sgibbs	 */
30197883Sgibbs	lflag = tp->t_lflag;
30297883Sgibbs	if (ISSET(lflag, PENDIN))
30397883Sgibbs		ttypend(tp);
30497883Sgibbs	/*
30597883Sgibbs	 * Gather stats.
30697883Sgibbs	 */
30797883Sgibbs	if (ISSET(lflag, ICANON)) {
30897883Sgibbs		++tk_cancc;
30997883Sgibbs		++tp->t_cancc;
31097883Sgibbs	} else {
31197883Sgibbs		++tk_rawcc;
31297883Sgibbs		++tp->t_rawcc;
31397883Sgibbs	}
31497883Sgibbs	++tk_nin;
31597883Sgibbs
31697883Sgibbs	/*
31797883Sgibbs	 * Block further input iff:
31897883Sgibbs	 * current input > threshold AND input is available to user program
31997883Sgibbs	 * AND input flow control is enabled and not yet invoked.
32097883Sgibbs	 * The 3 is slop for PARMRK.
32197883Sgibbs	 */
32297883Sgibbs	iflag = tp->t_iflag;
32397883Sgibbs	if (tp->t_rawq.c_cc + tp->t_canq.c_cc > tp->t_ihiwat - 3 &&
32497883Sgibbs	    (!ISSET(lflag, ICANON) || tp->t_canq.c_cc != 0) &&
32597883Sgibbs	    (ISSET(tp->t_cflag, CRTS_IFLOW) || ISSET(iflag, IXOFF)) &&
32697883Sgibbs	    !ISSET(tp->t_state, TS_TBLOCK))
32797883Sgibbs		ttyblock(tp);
32897883Sgibbs
32997883Sgibbs	/* Handle exceptional conditions (break, parity, framing). */
33097883Sgibbs	cc = tp->t_cc;
33197883Sgibbs	err = (ISSET(c, TTY_ERRORMASK));
33297883Sgibbs	if (err) {
33397883Sgibbs		CLR(c, TTY_ERRORMASK);
33497883Sgibbs		if (ISSET(err, TTY_BI)) {
33597883Sgibbs			if (ISSET(iflag, IGNBRK))
33697883Sgibbs				return (0);
33797883Sgibbs			if (ISSET(iflag, BRKINT)) {
33897883Sgibbs				ttyflush(tp, FREAD | FWRITE);
33997883Sgibbs				pgsignal(tp->t_pgrp, SIGINT, 1);
34097883Sgibbs				goto endcase;
34197883Sgibbs			}
34297883Sgibbs			if (ISSET(iflag, PARMRK))
34397883Sgibbs				goto parmrk;
34497883Sgibbs		} else if ((ISSET(err, TTY_PE) && ISSET(iflag, INPCK))
34597883Sgibbs			|| ISSET(err, TTY_FE)) {
34697883Sgibbs			if (ISSET(iflag, IGNPAR))
34797883Sgibbs				return (0);
34897883Sgibbs			else if (ISSET(iflag, PARMRK)) {
34997883Sgibbsparmrk:
35097883Sgibbs				if (tp->t_rawq.c_cc + tp->t_canq.c_cc >
35197883Sgibbs				    MAX_INPUT - 3)
35297883Sgibbs					goto input_overflow;
35397883Sgibbs				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
35497883Sgibbs				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
35597883Sgibbs				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
35697883Sgibbs				goto endcase;
35797883Sgibbs			} else
35897883Sgibbs				c = 0;
35997883Sgibbs		}
36097883Sgibbs	}
36197883Sgibbs
36297883Sgibbs	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
36397883Sgibbs		CLR(c, 0x80);
36497883Sgibbs	if (!ISSET(lflag, EXTPROC)) {
36597883Sgibbs		/*
36697883Sgibbs		 * Check for literal nexting very first
36797883Sgibbs		 */
36897883Sgibbs		if (ISSET(tp->t_state, TS_LNCH)) {
36997883Sgibbs			SET(c, TTY_QUOTE);
37097883Sgibbs			CLR(tp->t_state, TS_LNCH);
37197883Sgibbs		}
37297883Sgibbs		/*
37397883Sgibbs		 * Scan for special characters.  This code
37497883Sgibbs		 * is really just a big case statement with
37597883Sgibbs		 * non-constant cases.  The bottom of the
37697883Sgibbs		 * case statement is labeled ``endcase'', so goto
37797883Sgibbs		 * it after a case match, or similar.
37897883Sgibbs		 */
37997883Sgibbs
38097883Sgibbs		/*
38197883Sgibbs		 * Control chars which aren't controlled
38297883Sgibbs		 * by ICANON, ISIG, or IXON.
38397883Sgibbs		 */
38497883Sgibbs		if (ISSET(lflag, IEXTEN)) {
38597883Sgibbs			if (CCEQ(cc[VLNEXT], c)) {
38697883Sgibbs				if (ISSET(lflag, ECHO)) {
38797883Sgibbs					if (ISSET(lflag, ECHOE)) {
38897883Sgibbs						(void)ttyoutput('^', tp);
38997883Sgibbs						(void)ttyoutput('\b', tp);
39097883Sgibbs					} else
39197883Sgibbs						ttyecho(c, tp);
39297883Sgibbs				}
39397883Sgibbs				SET(tp->t_state, TS_LNCH);
39497883Sgibbs				goto endcase;
39597883Sgibbs			}
39697883Sgibbs			if (CCEQ(cc[VDISCARD], c)) {
39797883Sgibbs				if (ISSET(lflag, FLUSHO))
39897883Sgibbs					CLR(tp->t_lflag, FLUSHO);
39997883Sgibbs				else {
40097883Sgibbs					ttyflush(tp, FWRITE);
40197883Sgibbs					ttyecho(c, tp);
40297883Sgibbs					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
40397883Sgibbs						ttyretype(tp);
40497883Sgibbs					SET(tp->t_lflag, FLUSHO);
40597883Sgibbs				}
40697883Sgibbs				goto startoutput;
40797883Sgibbs			}
40897883Sgibbs		}
40997883Sgibbs		/*
41097883Sgibbs		 * Signals.
411102684Sgibbs		 */
412102684Sgibbs		if (ISSET(lflag, ISIG)) {
413102684Sgibbs			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
41497883Sgibbs				if (!ISSET(lflag, NOFLSH))
41597883Sgibbs					ttyflush(tp, FREAD | FWRITE);
41697883Sgibbs				ttyecho(c, tp);
41797883Sgibbs				pgsignal(tp->t_pgrp,
41897883Sgibbs				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
41997883Sgibbs				goto endcase;
42097883Sgibbs			}
42197883Sgibbs			if (CCEQ(cc[VSUSP], c)) {
42297883Sgibbs				if (!ISSET(lflag, NOFLSH))
42397883Sgibbs					ttyflush(tp, FREAD);
42497883Sgibbs				ttyecho(c, tp);
42597883Sgibbs				pgsignal(tp->t_pgrp, SIGTSTP, 1);
42697883Sgibbs				goto endcase;
427102684Sgibbs			}
428102684Sgibbs		}
429102684Sgibbs		/*
430102684Sgibbs		 * Handle start/stop characters.
431102684Sgibbs		 */
432102684Sgibbs		if (ISSET(iflag, IXON)) {
433102684Sgibbs			if (CCEQ(cc[VSTOP], c)) {
434102684Sgibbs				if (!ISSET(tp->t_state, TS_TTSTOP)) {
435102684Sgibbs					SET(tp->t_state, TS_TTSTOP);
436102684Sgibbs					(*tp->t_stop)(tp, 0);
437102684Sgibbs					return (0);
43897883Sgibbs				}
43997883Sgibbs				if (!CCEQ(cc[VSTART], c))
44097883Sgibbs					return (0);
44197883Sgibbs				/*
44297883Sgibbs				 * if VSTART == VSTOP then toggle
44397883Sgibbs				 */
44497883Sgibbs				goto endcase;
44597883Sgibbs			}
44697883Sgibbs			if (CCEQ(cc[VSTART], c))
44797883Sgibbs				goto restartoutput;
44897883Sgibbs		}
44997883Sgibbs		/*
45097883Sgibbs		 * IGNCR, ICRNL, & INLCR
45197883Sgibbs		 */
45297883Sgibbs		if (c == '\r') {
45397883Sgibbs			if (ISSET(iflag, IGNCR))
45497883Sgibbs				return (0);
45597883Sgibbs			else if (ISSET(iflag, ICRNL))
45697883Sgibbs				c = '\n';
45797883Sgibbs		} else if (c == '\n' && ISSET(iflag, INLCR))
45897883Sgibbs			c = '\r';
45997883Sgibbs	}
46097883Sgibbs	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
46197883Sgibbs		/*
46297883Sgibbs		 * From here on down canonical mode character
46397883Sgibbs		 * processing takes place.
46497883Sgibbs		 */
46597883Sgibbs		/*
46697883Sgibbs		 * erase or erase2 (^H / ^?)
46797883Sgibbs		 */
468109588Sgibbs		if (CCEQ(cc[VERASE], c) || CCEQ(cc[VERASE2], c) ) {
46997883Sgibbs			if (tp->t_rawq.c_cc)
47097883Sgibbs				ttyrub(unputc(&tp->t_rawq), tp);
47197883Sgibbs			goto endcase;
47297883Sgibbs		}
47397883Sgibbs		/*
47497883Sgibbs		 * kill (^U)
47597883Sgibbs		 */
47697883Sgibbs		if (CCEQ(cc[VKILL], c)) {
47797883Sgibbs			if (ISSET(lflag, ECHOKE) &&
47897883Sgibbs			    tp->t_rawq.c_cc == tp->t_rocount &&
47997883Sgibbs			    !ISSET(lflag, ECHOPRT))
48097883Sgibbs				while (tp->t_rawq.c_cc)
48197883Sgibbs					ttyrub(unputc(&tp->t_rawq), tp);
48297883Sgibbs			else {
48397883Sgibbs				ttyecho(c, tp);
48497883Sgibbs				if (ISSET(lflag, ECHOK) ||
48597883Sgibbs				    ISSET(lflag, ECHOKE))
48697883Sgibbs					ttyecho('\n', tp);
48797883Sgibbs				FLUSHQ(&tp->t_rawq);
48897883Sgibbs				tp->t_rocount = 0;
48997883Sgibbs			}
49097883Sgibbs			CLR(tp->t_state, TS_LOCAL);
49197883Sgibbs			goto endcase;
492109588Sgibbs		}
49397883Sgibbs		/*
49497883Sgibbs		 * word erase (^W)
49597883Sgibbs		 */
49697883Sgibbs		if (CCEQ(cc[VWERASE], c) && ISSET(lflag, IEXTEN)) {
49797883Sgibbs			int ctype;
49897883Sgibbs
49997883Sgibbs			/*
50097883Sgibbs			 * erase whitespace
50197883Sgibbs			 */
50297883Sgibbs			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
50397883Sgibbs				ttyrub(c, tp);
50497883Sgibbs			if (c == -1)
50597883Sgibbs				goto endcase;
50697883Sgibbs			/*
50797883Sgibbs			 * erase last char of word and remember the
50897883Sgibbs			 * next chars type (for ALTWERASE)
50997883Sgibbs			 */
51097883Sgibbs			ttyrub(c, tp);
51197883Sgibbs			c = unputc(&tp->t_rawq);
51297883Sgibbs			if (c == -1)
51397883Sgibbs				goto endcase;
51497883Sgibbs			if (c == ' ' || c == '\t') {
51597883Sgibbs				(void)putc(c, &tp->t_rawq);
51697883Sgibbs				goto endcase;
51797883Sgibbs			}
51897883Sgibbs			ctype = ISALPHA(c);
51997883Sgibbs			/*
52097883Sgibbs			 * erase rest of word
52197883Sgibbs			 */
52297883Sgibbs			do {
52397883Sgibbs				ttyrub(c, tp);
52497883Sgibbs				c = unputc(&tp->t_rawq);
52597883Sgibbs				if (c == -1)
52697883Sgibbs					goto endcase;
52797883Sgibbs			} while (c != ' ' && c != '\t' &&
52897883Sgibbs			    (!ISSET(lflag, ALTWERASE) || ISALPHA(c) == ctype));
52997883Sgibbs			(void)putc(c, &tp->t_rawq);
53097883Sgibbs			goto endcase;
53197883Sgibbs		}
53297883Sgibbs		/*
53397883Sgibbs		 * reprint line (^R)
53497883Sgibbs		 */
53597883Sgibbs		if (CCEQ(cc[VREPRINT], c) && ISSET(lflag, IEXTEN)) {
53697883Sgibbs			ttyretype(tp);
53797883Sgibbs			goto endcase;
53897883Sgibbs		}
53997883Sgibbs		/*
54097883Sgibbs		 * ^T - kernel info and generate SIGINFO
54197883Sgibbs		 */
54297883Sgibbs		if (CCEQ(cc[VSTATUS], c) && ISSET(lflag, IEXTEN)) {
54397883Sgibbs			if (ISSET(lflag, ISIG))
54497883Sgibbs				pgsignal(tp->t_pgrp, SIGINFO, 1);
54597883Sgibbs			if (!ISSET(lflag, NOKERNINFO))
54697883Sgibbs				ttyinfo(tp);
54797883Sgibbs			goto endcase;
54897883Sgibbs		}
54997883Sgibbs	}
55097883Sgibbs	/*
55197883Sgibbs	 * Check for input buffer overflow
55297883Sgibbs	 */
55397883Sgibbs	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= MAX_INPUT) {
55497883Sgibbsinput_overflow:
55597883Sgibbs		if (ISSET(iflag, IMAXBEL)) {
55697883Sgibbs			if (tp->t_outq.c_cc < tp->t_ohiwat)
55797883Sgibbs				(void)ttyoutput(CTRL('g'), tp);
55897883Sgibbs		}
55997883Sgibbs		goto endcase;
56097883Sgibbs	}
56197883Sgibbs
56297883Sgibbs	if (   c == 0377 && ISSET(iflag, PARMRK) && !ISSET(iflag, ISTRIP)
56397883Sgibbs	     && ISSET(iflag, IGNBRK|IGNPAR) != (IGNBRK|IGNPAR))
56497883Sgibbs		(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
56597883Sgibbs
56697883Sgibbs	/*
56797883Sgibbs	 * Put data char in q for user and
56897883Sgibbs	 * wakeup on seeing a line delimiter.
56997883Sgibbs	 */
57097883Sgibbs	if (putc(c, &tp->t_rawq) >= 0) {
57197883Sgibbs		if (!ISSET(lflag, ICANON)) {
57297883Sgibbs			ttwakeup(tp);
57397883Sgibbs			ttyecho(c, tp);
57497883Sgibbs			goto endcase;
57597883Sgibbs		}
57697883Sgibbs		if (TTBREAKC(c, lflag)) {
57797883Sgibbs			tp->t_rocount = 0;
57897883Sgibbs			catq(&tp->t_rawq, &tp->t_canq);
57997883Sgibbs			ttwakeup(tp);
58097883Sgibbs		} else if (tp->t_rocount++ == 0)
58197883Sgibbs			tp->t_rocol = tp->t_column;
58297883Sgibbs		if (ISSET(tp->t_state, TS_ERASE)) {
58397883Sgibbs			/*
58497883Sgibbs			 * end of prterase \.../
58597883Sgibbs			 */
58697883Sgibbs			CLR(tp->t_state, TS_ERASE);
58797883Sgibbs			(void)ttyoutput('/', tp);
58897883Sgibbs		}
58997883Sgibbs		i = tp->t_column;
59097883Sgibbs		ttyecho(c, tp);
59197883Sgibbs		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
59297883Sgibbs			/*
59397883Sgibbs			 * Place the cursor over the '^' of the ^D.
59497883Sgibbs			 */
59597883Sgibbs			i = imin(2, tp->t_column - i);
59697883Sgibbs			while (i > 0) {
59797883Sgibbs				(void)ttyoutput('\b', tp);
59897883Sgibbs				i--;
59997883Sgibbs			}
60097883Sgibbs		}
60197883Sgibbs	}
60297883Sgibbsendcase:
60397883Sgibbs	/*
60497883Sgibbs	 * IXANY means allow any character to restart output.
60597883Sgibbs	 */
60697883Sgibbs	if (ISSET(tp->t_state, TS_TTSTOP) &&
60797883Sgibbs	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
60897883Sgibbs		return (0);
60997883Sgibbsrestartoutput:
61097883Sgibbs	CLR(tp->t_lflag, FLUSHO);
61197883Sgibbs	CLR(tp->t_state, TS_TTSTOP);
61297883Sgibbsstartoutput:
61397883Sgibbs	return (ttstart(tp));
61497883Sgibbs}
61597883Sgibbs
61697883Sgibbs/*
61797883Sgibbs * Output a single character on a tty, doing output processing
61897883Sgibbs * as needed (expanding tabs, newline processing, etc.).
61997883Sgibbs * Returns < 0 if succeeds, otherwise returns char to resend.
62097883Sgibbs * Must be recursive.
62197883Sgibbs */
62297883Sgibbsstatic int
62397883Sgibbsttyoutput(c, tp)
62497883Sgibbs	register int c;
62597883Sgibbs	register struct tty *tp;
62697883Sgibbs{
62797883Sgibbs	register tcflag_t oflag;
62897883Sgibbs	register int col, s;
62997883Sgibbs
63097883Sgibbs	oflag = tp->t_oflag;
63197883Sgibbs	if (!ISSET(oflag, OPOST)) {
63297883Sgibbs		if (ISSET(tp->t_lflag, FLUSHO))
63397883Sgibbs			return (-1);
63497883Sgibbs		if (putc(c, &tp->t_outq))
63597883Sgibbs			return (c);
63697883Sgibbs		tk_nout++;
63797883Sgibbs		tp->t_outcc++;
63897883Sgibbs		return (-1);
63997883Sgibbs	}
64097883Sgibbs	/*
64197883Sgibbs	 * Do tab expansion if OXTABS is set.  Special case if we external
64297883Sgibbs	 * processing, we don't do the tab expansion because we'll probably
64397883Sgibbs	 * get it wrong.  If tab expansion needs to be done, let it happen
64497883Sgibbs	 * externally.
64597883Sgibbs	 */
64697883Sgibbs	CLR(c, ~TTY_CHARMASK);
64797883Sgibbs	if (c == '\t' &&
64897883Sgibbs	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
64997883Sgibbs		c = 8 - (tp->t_column & 7);
65097883Sgibbs		if (!ISSET(tp->t_lflag, FLUSHO)) {
65197883Sgibbs			s = spltty();		/* Don't interrupt tabs. */
65297883Sgibbs			c -= b_to_q("        ", c, &tp->t_outq);
65397883Sgibbs			tk_nout += c;
65497883Sgibbs			tp->t_outcc += c;
65597883Sgibbs			splx(s);
65697883Sgibbs		}
65797883Sgibbs		tp->t_column += c;
65897883Sgibbs		return (c ? -1 : '\t');
65997883Sgibbs	}
66097883Sgibbs	if (c == CEOT && ISSET(oflag, ONOEOT))
66197883Sgibbs		return (-1);
66297883Sgibbs
66397883Sgibbs	/*
66497883Sgibbs	 * Newline translation: if ONLCR is set,
66597883Sgibbs	 * translate newline into "\r\n".
66697883Sgibbs	 */
66797883Sgibbs	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
66897883Sgibbs		tk_nout++;
66997883Sgibbs		tp->t_outcc++;
67097883Sgibbs		if (!ISSET(tp->t_lflag, FLUSHO) && putc('\r', &tp->t_outq))
67197883Sgibbs			return (c);
67297883Sgibbs	}
67397883Sgibbs	/* If OCRNL is set, translate "\r" into "\n". */
67497883Sgibbs	else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
67597883Sgibbs		c = '\n';
67697883Sgibbs	/* If ONOCR is set, don't transmit CRs when on column 0. */
67797883Sgibbs	else if (c == '\r' && ISSET(tp->t_oflag, ONOCR) && tp->t_column == 0)
67897883Sgibbs		return (-1);
67997883Sgibbs
68097883Sgibbs	tk_nout++;
68197883Sgibbs	tp->t_outcc++;
68297883Sgibbs	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
68397883Sgibbs		return (c);
68497883Sgibbs
68597883Sgibbs	col = tp->t_column;
68697883Sgibbs	switch (CCLASS(c)) {
68797883Sgibbs	case BACKSPACE:
68897883Sgibbs		if (col > 0)
68997883Sgibbs			--col;
69097883Sgibbs		break;
69197883Sgibbs	case CONTROL:
69297883Sgibbs		break;
69397883Sgibbs	case NEWLINE:
69497883Sgibbs		if (ISSET(tp->t_oflag, ONLCR | ONLRET))
69597883Sgibbs			col = 0;
69697883Sgibbs		break;
69797883Sgibbs	case RETURN:
69897883Sgibbs		col = 0;
69997883Sgibbs		break;
70097883Sgibbs	case ORDINARY:
70197883Sgibbs		++col;
70297883Sgibbs		break;
70397883Sgibbs	case TAB:
70497883Sgibbs		col = (col + 8) & ~7;
70597883Sgibbs		break;
70697883Sgibbs	}
70797883Sgibbs	tp->t_column = col;
70897883Sgibbs	return (-1);
70997883Sgibbs}
71097883Sgibbs
71197883Sgibbs/*
71297883Sgibbs * Ioctls for all tty devices.  Called after line-discipline specific ioctl
71397883Sgibbs * has been called to do discipline-specific functions and/or reject any
71497883Sgibbs * of these ioctl commands.
71597883Sgibbs */
71697883Sgibbs/* ARGSUSED */
71797883Sgibbsint
71897883Sgibbsttioctl(tp, cmd, data, flag)
71997883Sgibbs	register struct tty *tp;
72097883Sgibbs	u_long cmd;
72197883Sgibbs	int flag;
72297883Sgibbs	void *data;
72397883Sgibbs{
72497883Sgibbs	register struct proc *p;
72597883Sgibbs	int s, error;
72697883Sgibbs
72797883Sgibbs	p = curproc;			/* XXX */
72897883Sgibbs
72997883Sgibbs	/* If the ioctl involves modification, hang if in the background. */
73097883Sgibbs	switch (cmd) {
73197883Sgibbs	case  TIOCCBRK:
73297883Sgibbs	case  TIOCCONS:
73397883Sgibbs	case  TIOCDRAIN:
73497883Sgibbs	case  TIOCEXCL:
73597883Sgibbs	case  TIOCFLUSH:
73697883Sgibbs#ifdef TIOCHPCL
73797883Sgibbs	case  TIOCHPCL:
73897883Sgibbs#endif
73997883Sgibbs	case  TIOCNXCL:
74097883Sgibbs	case  TIOCSBRK:
74197883Sgibbs	case  TIOCSCTTY:
74297883Sgibbs	case  TIOCSDRAINWAIT:
74397883Sgibbs	case  TIOCSETA:
74497883Sgibbs	case  TIOCSETAF:
74597883Sgibbs	case  TIOCSETAW:
74697883Sgibbs	case  TIOCSETD:
74797883Sgibbs	case  TIOCSPGRP:
74897883Sgibbs	case  TIOCSTART:
74997883Sgibbs	case  TIOCSTAT:
75097883Sgibbs	case  TIOCSTI:
75197883Sgibbs	case  TIOCSTOP:
75297883Sgibbs	case  TIOCSWINSZ:
75397883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
75497883Sgibbs	case  TIOCLBIC:
75597883Sgibbs	case  TIOCLBIS:
75697883Sgibbs	case  TIOCLSET:
75797883Sgibbs	case  TIOCSETC:
75897883Sgibbs	case OTIOCSETD:
75997883Sgibbs	case  TIOCSETN:
76097883Sgibbs	case  TIOCSETP:
76197883Sgibbs	case  TIOCSLTC:
76297883Sgibbs#endif
76397883Sgibbs		while (isbackground(p, tp) && !(p->p_flag & P_PPWAIT) &&
76497883Sgibbs		    !SIGISMEMBER(p->p_sigignore, SIGTTOU) &&
76597883Sgibbs		    !SIGISMEMBER(p->p_sigmask, SIGTTOU)) {
76697883Sgibbs			if (p->p_pgrp->pg_jobc == 0)
76797883Sgibbs				return (EIO);
76897883Sgibbs			pgsignal(p->p_pgrp, SIGTTOU, 1);
76997883Sgibbs			error = ttysleep(tp, &lbolt, TTOPRI | PCATCH, "ttybg1",
77097883Sgibbs					 0);
77197883Sgibbs			if (error)
77297883Sgibbs				return (error);
77397883Sgibbs		}
77497883Sgibbs		break;
77597883Sgibbs	}
77697883Sgibbs
77797883Sgibbs	switch (cmd) {			/* Process the ioctl. */
77897883Sgibbs	case FIOASYNC:			/* set/clear async i/o */
77997883Sgibbs		s = spltty();
78097883Sgibbs		if (*(int *)data)
78197883Sgibbs			SET(tp->t_state, TS_ASYNC);
78297883Sgibbs		else
78397883Sgibbs			CLR(tp->t_state, TS_ASYNC);
78497883Sgibbs		splx(s);
78597883Sgibbs		break;
78697883Sgibbs	case FIONBIO:			/* set/clear non-blocking i/o */
78797883Sgibbs		break;			/* XXX: delete. */
78897883Sgibbs	case FIONREAD:			/* get # bytes to read */
78997883Sgibbs		s = spltty();
79097883Sgibbs		*(int *)data = ttnread(tp);
79197883Sgibbs		splx(s);
79297883Sgibbs		break;
79397883Sgibbs
79497883Sgibbs	case FIOSETOWN:
79597883Sgibbs		/*
79697883Sgibbs		 * Policy -- Don't allow FIOSETOWN on someone else's
79797883Sgibbs		 *           controlling tty
79897883Sgibbs		 */
79997883Sgibbs		if (tp->t_session != NULL && !isctty(p, tp))
80097883Sgibbs			return (ENOTTY);
80197883Sgibbs
80297883Sgibbs		error = fsetown(*(int *)data, &tp->t_sigio);
80397883Sgibbs		if (error)
80497883Sgibbs			return (error);
80597883Sgibbs		break;
80697883Sgibbs	case FIOGETOWN:
80797883Sgibbs		if (tp->t_session != NULL && !isctty(p, tp))
80897883Sgibbs			return (ENOTTY);
80997883Sgibbs		*(int *)data = fgetown(tp->t_sigio);
81097883Sgibbs		break;
81197883Sgibbs
81297883Sgibbs	case TIOCEXCL:			/* set exclusive use of tty */
81397883Sgibbs		s = spltty();
81497883Sgibbs		SET(tp->t_state, TS_XCLUDE);
81597883Sgibbs		splx(s);
81697883Sgibbs		break;
81797883Sgibbs	case TIOCFLUSH: {		/* flush buffers */
81897883Sgibbs		register int flags = *(int *)data;
81997883Sgibbs
82097883Sgibbs		if (flags == 0)
82197883Sgibbs			flags = FREAD | FWRITE;
82297883Sgibbs		else
82397883Sgibbs			flags &= FREAD | FWRITE;
82497883Sgibbs		ttyflush(tp, flags);
82597883Sgibbs		break;
82697883Sgibbs	}
82797883Sgibbs	case TIOCCONS:			/* become virtual console */
82897883Sgibbs		if (*(int *)data) {
829102684Sgibbs			if (constty && constty != tp &&
830102684Sgibbs			    ISSET(constty->t_state, TS_CONNECTED))
831102684Sgibbs				return (EBUSY);
83297883Sgibbs#ifndef	UCONSOLE
83397883Sgibbs			if ((error = suser(p)) != 0)
83497883Sgibbs				return (error);
83597883Sgibbs#endif
83697883Sgibbs			constty = tp;
83797883Sgibbs		} else if (tp == constty)
83897883Sgibbs			constty = NULL;
83997883Sgibbs		break;
84097883Sgibbs	case TIOCDRAIN:			/* wait till output drained */
84197883Sgibbs		error = ttywait(tp);
84297883Sgibbs		if (error)
843102684Sgibbs			return (error);
844102684Sgibbs		break;
845102684Sgibbs	case TIOCGETA: {		/* get termios struct */
846102684Sgibbs		struct termios *t = (struct termios *)data;
84797883Sgibbs
84897883Sgibbs		bcopy(&tp->t_termios, t, sizeof(struct termios));
84997883Sgibbs		break;
85097883Sgibbs	}
85197883Sgibbs	case TIOCGETD:			/* get line discipline */
85297883Sgibbs		*(int *)data = tp->t_line;
85397883Sgibbs		break;
85497883Sgibbs	case TIOCGWINSZ:		/* get window size */
85597883Sgibbs		*(struct winsize *)data = tp->t_winsize;
85697883Sgibbs		break;
85797883Sgibbs	case TIOCGPGRP:			/* get pgrp of tty */
85897883Sgibbs		if (!isctty(p, tp))
85997883Sgibbs			return (ENOTTY);
86097883Sgibbs		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
86197883Sgibbs		break;
86297883Sgibbs#ifdef TIOCHPCL
86397883Sgibbs	case TIOCHPCL:			/* hang up on last close */
86497883Sgibbs		s = spltty();
86597883Sgibbs		SET(tp->t_cflag, HUPCL);
86697883Sgibbs		splx(s);
86797883Sgibbs		break;
86897883Sgibbs#endif
86997883Sgibbs	case TIOCNXCL:			/* reset exclusive use of tty */
87097883Sgibbs		s = spltty();
87197883Sgibbs		CLR(tp->t_state, TS_XCLUDE);
87297883Sgibbs		splx(s);
87397883Sgibbs		break;
87497883Sgibbs	case TIOCOUTQ:			/* output queue size */
87597883Sgibbs		*(int *)data = tp->t_outq.c_cc;
87697883Sgibbs		break;
87797883Sgibbs	case TIOCSETA:			/* set termios struct */
87897883Sgibbs	case TIOCSETAW:			/* drain output, set */
87997883Sgibbs	case TIOCSETAF: {		/* drn out, fls in, set */
88097883Sgibbs		register struct termios *t = (struct termios *)data;
88197883Sgibbs
88297883Sgibbs		if (t->c_ispeed == 0)
88397883Sgibbs			t->c_ispeed = t->c_ospeed;
88497883Sgibbs		if (t->c_ispeed == 0)
88597883Sgibbs			t->c_ispeed = tp->t_ospeed;
88697883Sgibbs		if (t->c_ispeed == 0)
88797883Sgibbs			return (EINVAL);
88897883Sgibbs		s = spltty();
88997883Sgibbs		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
89097883Sgibbs			error = ttywait(tp);
89197883Sgibbs			if (error) {
89297883Sgibbs				splx(s);
89397883Sgibbs				return (error);
89497883Sgibbs			}
89597883Sgibbs			if (cmd == TIOCSETAF)
89697883Sgibbs				ttyflush(tp, FREAD);
89797883Sgibbs		}
89897883Sgibbs		if (!ISSET(t->c_cflag, CIGNORE)) {
89997883Sgibbs			/*
90097883Sgibbs			 * Set device hardware.
90197883Sgibbs			 */
90297883Sgibbs			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
90397883Sgibbs				splx(s);
90497883Sgibbs				return (error);
90597883Sgibbs			}
90697883Sgibbs			if (ISSET(t->c_cflag, CLOCAL) &&
90797883Sgibbs			    !ISSET(tp->t_cflag, CLOCAL)) {
90897883Sgibbs				/*
90997883Sgibbs				 * XXX disconnections would be too hard to
91097883Sgibbs				 * get rid of without this kludge.  The only
91197883Sgibbs				 * way to get rid of controlling terminals
91297883Sgibbs				 * is to exit from the session leader.
91397883Sgibbs				 */
91497883Sgibbs				CLR(tp->t_state, TS_ZOMBIE);
91597883Sgibbs
91697883Sgibbs				wakeup(TSA_CARR_ON(tp));
91797883Sgibbs				ttwakeup(tp);
91897883Sgibbs				ttwwakeup(tp);
91997883Sgibbs			}
92097883Sgibbs			if ((ISSET(tp->t_state, TS_CARR_ON) ||
92197883Sgibbs			     ISSET(t->c_cflag, CLOCAL)) &&
92297883Sgibbs			    !ISSET(tp->t_state, TS_ZOMBIE))
92397883Sgibbs				SET(tp->t_state, TS_CONNECTED);
92497883Sgibbs			else
92597883Sgibbs				CLR(tp->t_state, TS_CONNECTED);
92697883Sgibbs			tp->t_cflag = t->c_cflag;
92797883Sgibbs			tp->t_ispeed = t->c_ispeed;
92897883Sgibbs			if (t->c_ospeed != 0)
92997883Sgibbs				tp->t_ospeed = t->c_ospeed;
93097883Sgibbs			ttsetwater(tp);
93197883Sgibbs		}
93297883Sgibbs		if (ISSET(t->c_lflag, ICANON) != ISSET(tp->t_lflag, ICANON) &&
93397883Sgibbs		    cmd != TIOCSETAF) {
93497883Sgibbs			if (ISSET(t->c_lflag, ICANON))
93597883Sgibbs				SET(tp->t_lflag, PENDIN);
93697883Sgibbs			else {
93797883Sgibbs				/*
93897883Sgibbs				 * XXX we really shouldn't allow toggling
93997883Sgibbs				 * ICANON while we're in a non-termios line
94097883Sgibbs				 * discipline.  Now we have to worry about
94197883Sgibbs				 * panicing for a null queue.
94297883Sgibbs				 */
94397883Sgibbs				if (tp->t_canq.c_cbreserved > 0 &&
94497883Sgibbs				    tp->t_rawq.c_cbreserved > 0) {
94597883Sgibbs					catq(&tp->t_rawq, &tp->t_canq);
94697883Sgibbs					/*
94797883Sgibbs					 * XXX the queue limits may be
94897883Sgibbs					 * different, so the old queue
94997883Sgibbs					 * swapping method no longer works.
95097883Sgibbs					 */
95197883Sgibbs					catq(&tp->t_canq, &tp->t_rawq);
95297883Sgibbs				}
95397883Sgibbs				CLR(tp->t_lflag, PENDIN);
95497883Sgibbs			}
95597883Sgibbs			ttwakeup(tp);
95697883Sgibbs		}
95797883Sgibbs		tp->t_iflag = t->c_iflag;
95897883Sgibbs		tp->t_oflag = t->c_oflag;
95997883Sgibbs		/*
96097883Sgibbs		 * Make the EXTPROC bit read only.
96197883Sgibbs		 */
96297883Sgibbs		if (ISSET(tp->t_lflag, EXTPROC))
96397883Sgibbs			SET(t->c_lflag, EXTPROC);
96497883Sgibbs		else
96597883Sgibbs			CLR(t->c_lflag, EXTPROC);
96697883Sgibbs		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
96797883Sgibbs		if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
96897883Sgibbs		    t->c_cc[VTIME] != tp->t_cc[VTIME])
96997883Sgibbs			ttwakeup(tp);
97097883Sgibbs		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
97197883Sgibbs		splx(s);
97297883Sgibbs		break;
97397883Sgibbs	}
97497883Sgibbs	case TIOCSETD: {		/* set line discipline */
97597883Sgibbs		register int t = *(int *)data;
97697883Sgibbs		dev_t device = tp->t_dev;
97797883Sgibbs
97897883Sgibbs		if ((u_int)t >= nlinesw)
97997883Sgibbs			return (ENXIO);
98097883Sgibbs		if (t != tp->t_line) {
98197883Sgibbs			s = spltty();
98297883Sgibbs			(*linesw[tp->t_line].l_close)(tp, flag);
98397883Sgibbs			error = (*linesw[t].l_open)(device, tp);
98497883Sgibbs			if (error) {
98597883Sgibbs				(void)(*linesw[tp->t_line].l_open)(device, tp);
98697883Sgibbs				splx(s);
98797883Sgibbs				return (error);
98897883Sgibbs			}
98997883Sgibbs			tp->t_line = t;
99097883Sgibbs			splx(s);
99197883Sgibbs		}
99297883Sgibbs		break;
99397883Sgibbs	}
99497883Sgibbs	case TIOCSTART:			/* start output, like ^Q */
99597883Sgibbs		s = spltty();
99697883Sgibbs		if (ISSET(tp->t_state, TS_TTSTOP) ||
99797883Sgibbs		    ISSET(tp->t_lflag, FLUSHO)) {
99897883Sgibbs			CLR(tp->t_lflag, FLUSHO);
99997883Sgibbs			CLR(tp->t_state, TS_TTSTOP);
100097883Sgibbs			ttstart(tp);
100197883Sgibbs		}
100297883Sgibbs		splx(s);
100397883Sgibbs		break;
100497883Sgibbs	case TIOCSTI:			/* simulate terminal input */
100597883Sgibbs		if ((flag & FREAD) == 0 && suser(p))
100697883Sgibbs			return (EPERM);
100797883Sgibbs		if (!isctty(p, tp) && suser(p))
100897883Sgibbs			return (EACCES);
100997883Sgibbs		s = spltty();
101097883Sgibbs		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
101197883Sgibbs		splx(s);
101297883Sgibbs		break;
101397883Sgibbs	case TIOCSTOP:			/* stop output, like ^S */
101497883Sgibbs		s = spltty();
101597883Sgibbs		if (!ISSET(tp->t_state, TS_TTSTOP)) {
101697883Sgibbs			SET(tp->t_state, TS_TTSTOP);
101797883Sgibbs			(*tp->t_stop)(tp, 0);
101897883Sgibbs		}
101997883Sgibbs		splx(s);
102097883Sgibbs		break;
102197883Sgibbs	case TIOCSCTTY:			/* become controlling tty */
102297883Sgibbs		/* Session ctty vnode pointer set in vnode layer. */
102397883Sgibbs		if (!SESS_LEADER(p) ||
102497883Sgibbs		    ((p->p_session->s_ttyvp || tp->t_session) &&
102597883Sgibbs		    (tp->t_session != p->p_session)))
102697883Sgibbs			return (EPERM);
102797883Sgibbs		tp->t_session = p->p_session;
102897883Sgibbs		tp->t_pgrp = p->p_pgrp;
102997883Sgibbs		p->p_session->s_ttyp = tp;
103097883Sgibbs		p->p_flag |= P_CONTROLT;
103197883Sgibbs		break;
103297883Sgibbs	case TIOCSPGRP: {		/* set pgrp of tty */
103397883Sgibbs		register struct pgrp *pgrp = pgfind(*(int *)data);
103497883Sgibbs
103597883Sgibbs		if (!isctty(p, tp))
103697883Sgibbs			return (ENOTTY);
103797883Sgibbs		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
103897883Sgibbs			return (EPERM);
103997883Sgibbs		tp->t_pgrp = pgrp;
104097883Sgibbs		break;
104197883Sgibbs	}
104297883Sgibbs	case TIOCSTAT:			/* simulate control-T */
104397883Sgibbs		s = spltty();
104497883Sgibbs		ttyinfo(tp);
104597883Sgibbs		splx(s);
104697883Sgibbs		break;
104797883Sgibbs	case TIOCSWINSZ:		/* set window size */
104897883Sgibbs		if (bcmp((caddr_t)&tp->t_winsize, data,
104997883Sgibbs		    sizeof (struct winsize))) {
105097883Sgibbs			tp->t_winsize = *(struct winsize *)data;
105197883Sgibbs			pgsignal(tp->t_pgrp, SIGWINCH, 1);
105297883Sgibbs		}
105397883Sgibbs		break;
105497883Sgibbs	case TIOCSDRAINWAIT:
105597883Sgibbs		error = suser(p);
105697883Sgibbs		if (error)
105797883Sgibbs			return (error);
105897883Sgibbs		tp->t_timeout = *(int *)data * hz;
105997883Sgibbs		wakeup(TSA_OCOMPLETE(tp));
106097883Sgibbs		wakeup(TSA_OLOWAT(tp));
106197883Sgibbs		break;
106297883Sgibbs	case TIOCGDRAINWAIT:
106397883Sgibbs		*(int *)data = tp->t_timeout / hz;
106497883Sgibbs		break;
106597883Sgibbs	default:
106697883Sgibbs#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
106797883Sgibbs		return (ttcompat(tp, cmd, data, flag));
106897883Sgibbs#else
106997883Sgibbs		return (ENOIOCTL);
107097883Sgibbs#endif
107197883Sgibbs	}
107297883Sgibbs	return (0);
107397883Sgibbs}
107497883Sgibbs
107597883Sgibbsint
107697883Sgibbsttypoll(dev, events, p)
107797883Sgibbs	dev_t dev;
107897883Sgibbs	int events;
107997883Sgibbs	struct proc *p;
108097883Sgibbs{
108197883Sgibbs	int s;
108297883Sgibbs	int revents = 0;
108397883Sgibbs	struct tty *tp;
108497883Sgibbs
108597883Sgibbs	tp = dev->si_tty;
108697883Sgibbs	if (tp == NULL)	/* XXX used to return ENXIO, but that means true! */
108797883Sgibbs		return ((events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM))
108897883Sgibbs			| POLLHUP);
108997883Sgibbs
109097883Sgibbs	s = spltty();
109197883Sgibbs	if (events & (POLLIN | POLLRDNORM)) {
109297883Sgibbs		if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))
109397883Sgibbs			revents |= events & (POLLIN | POLLRDNORM);
109497883Sgibbs		else
109597883Sgibbs			selrecord(p, &tp->t_rsel);
109697883Sgibbs	}
109797883Sgibbs	if (events & (POLLOUT | POLLWRNORM)) {
109897883Sgibbs		if ((tp->t_outq.c_cc <= tp->t_olowat &&
109997883Sgibbs		     ISSET(tp->t_state, TS_CONNECTED))
110097883Sgibbs		    || ISSET(tp->t_state, TS_ZOMBIE))
110197883Sgibbs			revents |= events & (POLLOUT | POLLWRNORM);
110297883Sgibbs		else
110397883Sgibbs			selrecord(p, &tp->t_wsel);
110497883Sgibbs	}
110597883Sgibbs	splx(s);
110697883Sgibbs	return (revents);
110797883Sgibbs}
110897883Sgibbs
110997883Sgibbsstatic struct filterops ttyread_filtops =
111097883Sgibbs	{ 1, NULL, filt_ttyrdetach, filt_ttyread };
111197883Sgibbsstatic struct filterops ttywrite_filtops =
111297883Sgibbs	{ 1, NULL, filt_ttywdetach, filt_ttywrite };
111397883Sgibbs
111497883Sgibbsint
111597883Sgibbsttykqfilter(dev, kn)
111697883Sgibbs	dev_t dev;
1117109588Sgibbs	struct knote *kn;
111897883Sgibbs{
1119109588Sgibbs	struct tty *tp = dev->si_tty;
1120109588Sgibbs	struct klist *klist;
1121109588Sgibbs	int s;
112297883Sgibbs
112397883Sgibbs	switch (kn->kn_filter) {
112497883Sgibbs	case EVFILT_READ:
112597883Sgibbs		klist = &tp->t_rsel.si_note;
112697883Sgibbs		kn->kn_fop = &ttyread_filtops;
112797883Sgibbs		break;
112897883Sgibbs	case EVFILT_WRITE:
112997883Sgibbs		klist = &tp->t_wsel.si_note;
113097883Sgibbs		kn->kn_fop = &ttywrite_filtops;
113197883Sgibbs		break;
113297883Sgibbs	default:
113397883Sgibbs		return (1);
113497883Sgibbs	}
113597883Sgibbs
113697883Sgibbs	kn->kn_hook = (caddr_t)dev;
113797883Sgibbs
113897883Sgibbs	s = spltty();
113997883Sgibbs	SLIST_INSERT_HEAD(klist, kn, kn_selnext);
114097883Sgibbs	splx(s);
114197883Sgibbs
114297883Sgibbs	return (0);
114397883Sgibbs}
114497883Sgibbs
114597883Sgibbsstatic void
114697883Sgibbsfilt_ttyrdetach(struct knote *kn)
114797883Sgibbs{
114897883Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
114997883Sgibbs	int s = spltty();
115097883Sgibbs
115197883Sgibbs	SLIST_REMOVE(&tp->t_rsel.si_note, kn, knote, kn_selnext);
115297883Sgibbs	splx(s);
115397883Sgibbs}
115497883Sgibbs
115597883Sgibbsstatic int
115697883Sgibbsfilt_ttyread(struct knote *kn, long hint)
115797883Sgibbs{
115897883Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
115997883Sgibbs
116097883Sgibbs	kn->kn_data = ttnread(tp);
116197883Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE)) {
116297883Sgibbs		kn->kn_flags |= EV_EOF;
116397883Sgibbs		return (1);
116497883Sgibbs	}
116597883Sgibbs	return (kn->kn_data > 0);
116697883Sgibbs}
116797883Sgibbs
116897883Sgibbsstatic void
116997883Sgibbsfilt_ttywdetach(struct knote *kn)
117097883Sgibbs{
117197883Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
117297883Sgibbs	int s = spltty();
117397883Sgibbs
117497883Sgibbs	SLIST_REMOVE(&tp->t_wsel.si_note, kn, knote, kn_selnext);
117597883Sgibbs	splx(s);
117697883Sgibbs}
117797883Sgibbs
117897883Sgibbsstatic int
117997883Sgibbsfilt_ttywrite(kn, hint)
118097883Sgibbs	struct knote *kn;
118197883Sgibbs	long hint;
118297883Sgibbs{
118397883Sgibbs	struct tty *tp = ((dev_t)kn->kn_hook)->si_tty;
118497883Sgibbs
118597883Sgibbs	kn->kn_data = tp->t_outq.c_cc;
118697883Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE))
118797883Sgibbs		return (1);
118897883Sgibbs	return (kn->kn_data <= tp->t_olowat &&
118997883Sgibbs	    ISSET(tp->t_state, TS_CONNECTED));
119097883Sgibbs}
1191111653Sgibbs
1192111653Sgibbs/*
1193111653Sgibbs * Must be called at spltty().
1194111653Sgibbs */
1195111653Sgibbsstatic int
119697883Sgibbsttnread(tp)
119797883Sgibbs	struct tty *tp;
119897883Sgibbs{
119997883Sgibbs	int nread;
120097883Sgibbs
120197883Sgibbs	if (ISSET(tp->t_lflag, PENDIN))
120297883Sgibbs		ttypend(tp);
120397883Sgibbs	nread = tp->t_canq.c_cc;
120497883Sgibbs	if (!ISSET(tp->t_lflag, ICANON)) {
1205111653Sgibbs		nread += tp->t_rawq.c_cc;
120697883Sgibbs		if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
1207111653Sgibbs			nread = 0;
1208111653Sgibbs	}
1209111653Sgibbs	return (nread);
121097883Sgibbs}
121197883Sgibbs
121297883Sgibbs/*
121397883Sgibbs * Wait for output to drain.
121497883Sgibbs */
121597883Sgibbsint
121697883Sgibbsttywait(tp)
121797883Sgibbs	register struct tty *tp;
121897883Sgibbs{
121997883Sgibbs	int error, s;
122097883Sgibbs
122197883Sgibbs	error = 0;
122297883Sgibbs	s = spltty();
122397883Sgibbs	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
122497883Sgibbs	       ISSET(tp->t_state, TS_CONNECTED) && tp->t_oproc) {
122597883Sgibbs		(*tp->t_oproc)(tp);
122697883Sgibbs		if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
122797883Sgibbs		    ISSET(tp->t_state, TS_CONNECTED)) {
122897883Sgibbs			SET(tp->t_state, TS_SO_OCOMPLETE);
122997883Sgibbs			error = ttysleep(tp, TSA_OCOMPLETE(tp),
123097883Sgibbs					 TTOPRI | PCATCH, "ttywai",
123197883Sgibbs					 tp->t_timeout);
123297883Sgibbs			if (error) {
123397883Sgibbs				if (error == EWOULDBLOCK)
123497883Sgibbs					error = EIO;
123597883Sgibbs				break;
123697883Sgibbs			}
123797883Sgibbs		} else
123897883Sgibbs			break;
123997883Sgibbs	}
124097883Sgibbs	if (!error && (tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)))
124197883Sgibbs		error = EIO;
124297883Sgibbs	splx(s);
124397883Sgibbs	return (error);
124497883Sgibbs}
124597883Sgibbs
124697883Sgibbs/*
124797883Sgibbs * Flush if successfully wait.
124897883Sgibbs */
124997883Sgibbsstatic int
125097883Sgibbsttywflush(tp)
125197883Sgibbs	struct tty *tp;
125297883Sgibbs{
125397883Sgibbs	int error;
125497883Sgibbs
125597883Sgibbs	if ((error = ttywait(tp)) == 0)
125697883Sgibbs		ttyflush(tp, FREAD);
125797883Sgibbs	return (error);
125897883Sgibbs}
125997883Sgibbs
126097883Sgibbs/*
126197883Sgibbs * Flush tty read and/or write queues, notifying anyone waiting.
126297883Sgibbs */
126397883Sgibbsvoid
126497883Sgibbsttyflush(tp, rw)
126597883Sgibbs	register struct tty *tp;
126697883Sgibbs	int rw;
126797883Sgibbs{
1268113296Sjake	register int s;
1269113296Sjake
127097883Sgibbs	s = spltty();
127197883Sgibbs#if 0
127297883Sgibbsagain:
127397883Sgibbs#endif
127497883Sgibbs	if (rw & FWRITE) {
127597883Sgibbs		FLUSHQ(&tp->t_outq);
127697883Sgibbs		CLR(tp->t_state, TS_TTSTOP);
127797883Sgibbs	}
127897883Sgibbs	(*tp->t_stop)(tp, rw);
127997883Sgibbs	if (rw & FREAD) {
128097883Sgibbs		FLUSHQ(&tp->t_canq);
128197883Sgibbs		FLUSHQ(&tp->t_rawq);
128297883Sgibbs		CLR(tp->t_lflag, PENDIN);
128397883Sgibbs		tp->t_rocount = 0;
128497883Sgibbs		tp->t_rocol = 0;
128597883Sgibbs		CLR(tp->t_state, TS_LOCAL);
128697883Sgibbs		ttwakeup(tp);
128797883Sgibbs		if (ISSET(tp->t_state, TS_TBLOCK)) {
128897883Sgibbs			if (rw & FWRITE)
128997883Sgibbs				FLUSHQ(&tp->t_outq);
129097883Sgibbs			ttyunblock(tp);
129197883Sgibbs
129297883Sgibbs			/*
129397883Sgibbs			 * Don't let leave any state that might clobber the
129497883Sgibbs			 * next line discipline (although we should do more
129597883Sgibbs			 * to send the START char).  Not clearing the state
129697883Sgibbs			 * may have caused the "putc to a clist with no
129797883Sgibbs			 * reserved cblocks" panic/printf.
129897883Sgibbs			 */
129997883Sgibbs			CLR(tp->t_state, TS_TBLOCK);
130097883Sgibbs
130197883Sgibbs#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
130297883Sgibbs			if (ISSET(tp->t_iflag, IXOFF)) {
130397883Sgibbs				/*
130497883Sgibbs				 * XXX wait a bit in the hope that the stop
130597883Sgibbs				 * character (if any) will go out.  Waiting
130697883Sgibbs				 * isn't good since it allows races.  This
130797883Sgibbs				 * will be fixed when the stop character is
130897883Sgibbs				 * put in a special queue.  Don't bother with
130997883Sgibbs				 * the checks in ttywait() since the timeout
131097883Sgibbs				 * will save us.
131197883Sgibbs				 */
131297883Sgibbs				SET(tp->t_state, TS_SO_OCOMPLETE);
131397883Sgibbs				ttysleep(tp, TSA_OCOMPLETE(tp), TTOPRI,
131497883Sgibbs					 "ttyfls", hz / 10);
131597883Sgibbs				/*
131697883Sgibbs				 * Don't try sending the stop character again.
131797883Sgibbs				 */
131897883Sgibbs				CLR(tp->t_state, TS_TBLOCK);
131997883Sgibbs				goto again;
132097883Sgibbs			}
132197883Sgibbs#endif
132297883Sgibbs		}
132397883Sgibbs	}
132497883Sgibbs	if (rw & FWRITE) {
132597883Sgibbs		FLUSHQ(&tp->t_outq);
132697883Sgibbs		ttwwakeup(tp);
132797883Sgibbs	}
132897883Sgibbs	splx(s);
132997883Sgibbs}
133097883Sgibbs
133197883Sgibbs/*
133297883Sgibbs * Copy in the default termios characters.
133397883Sgibbs */
133497883Sgibbsvoid
133597883Sgibbstermioschars(t)
133697883Sgibbs	struct termios *t;
133797883Sgibbs{
133897883Sgibbs
133997883Sgibbs	bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
134097883Sgibbs}
134197883Sgibbs
134297883Sgibbs/*
134397883Sgibbs * Old interface.
134497883Sgibbs */
134597883Sgibbsvoid
134697883Sgibbsttychars(tp)
134797883Sgibbs	struct tty *tp;
134897883Sgibbs{
134997883Sgibbs
135097883Sgibbs	termioschars(&tp->t_termios);
135197883Sgibbs}
135297883Sgibbs
135397883Sgibbs/*
135497883Sgibbs * Handle input high water.  Send stop character for the IXOFF case.  Turn
135597883Sgibbs * on our input flow control bit and propagate the changes to the driver.
135697883Sgibbs * XXX the stop character should be put in a special high priority queue.
135797883Sgibbs */
135897883Sgibbsvoid
135997883Sgibbsttyblock(tp)
136097883Sgibbs	struct tty *tp;
136197883Sgibbs{
136297883Sgibbs
136397883Sgibbs	SET(tp->t_state, TS_TBLOCK);
136497883Sgibbs	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTOP] != _POSIX_VDISABLE &&
136597883Sgibbs	    putc(tp->t_cc[VSTOP], &tp->t_outq) != 0)
136697883Sgibbs		CLR(tp->t_state, TS_TBLOCK);	/* try again later */
136797883Sgibbs	ttstart(tp);
136897883Sgibbs}
136997883Sgibbs
137097883Sgibbs/*
137197883Sgibbs * Handle input low water.  Send start character for the IXOFF case.  Turn
137297883Sgibbs * off our input flow control bit and propagate the changes to the driver.
137397883Sgibbs * XXX the start character should be put in a special high priority queue.
137497883Sgibbs */
137597883Sgibbsstatic void
137697883Sgibbsttyunblock(tp)
137797883Sgibbs	struct tty *tp;
137897883Sgibbs{
137997883Sgibbs
138097883Sgibbs	CLR(tp->t_state, TS_TBLOCK);
138197883Sgibbs	if (ISSET(tp->t_iflag, IXOFF) && tp->t_cc[VSTART] != _POSIX_VDISABLE &&
138297883Sgibbs	    putc(tp->t_cc[VSTART], &tp->t_outq) != 0)
138397883Sgibbs		SET(tp->t_state, TS_TBLOCK);	/* try again later */
138497883Sgibbs	ttstart(tp);
138597883Sgibbs}
138697883Sgibbs
138797883Sgibbs#ifdef notyet
138897883Sgibbs/* Not used by any current (i386) drivers. */
138997883Sgibbs/*
139097883Sgibbs * Restart after an inter-char delay.
139197883Sgibbs */
139297883Sgibbsvoid
139397883Sgibbsttrstrt(tp_arg)
139497883Sgibbs	void *tp_arg;
139597883Sgibbs{
139697883Sgibbs	struct tty *tp;
139797883Sgibbs	int s;
139897883Sgibbs
139997883Sgibbs	KASSERT(tp_arg != NULL, ("ttrstrt"));
140097883Sgibbs
140197883Sgibbs	tp = tp_arg;
140297883Sgibbs	s = spltty();
140397883Sgibbs
140497883Sgibbs	CLR(tp->t_state, TS_TIMEOUT);
140597883Sgibbs	ttstart(tp);
140697883Sgibbs
140797883Sgibbs	splx(s);
140897883Sgibbs}
140997883Sgibbs#endif
141097883Sgibbs
141197883Sgibbsint
141297883Sgibbsttstart(tp)
141397883Sgibbs	struct tty *tp;
141497883Sgibbs{
141597883Sgibbs
141697883Sgibbs	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
141797883Sgibbs		(*tp->t_oproc)(tp);
141897883Sgibbs	return (0);
141997883Sgibbs}
142097883Sgibbs
142197883Sgibbs/*
142297883Sgibbs * "close" a line discipline
142397883Sgibbs */
142497883Sgibbsint
142597883Sgibbsttylclose(tp, flag)
142697883Sgibbs	struct tty *tp;
142797883Sgibbs	int flag;
142897883Sgibbs{
142997883Sgibbs
143097883Sgibbs	if (flag & FNONBLOCK || ttywflush(tp))
143197883Sgibbs		ttyflush(tp, FREAD | FWRITE);
143297883Sgibbs	return (0);
143397883Sgibbs}
143497883Sgibbs
143597883Sgibbs/*
143697883Sgibbs * Handle modem control transition on a tty.
143797883Sgibbs * Flag indicates new state of carrier.
143897883Sgibbs * Returns 0 if the line should be turned off, otherwise 1.
143997883Sgibbs */
144097883Sgibbsint
144197883Sgibbsttymodem(tp, flag)
144297883Sgibbs	register struct tty *tp;
144397883Sgibbs	int flag;
144497883Sgibbs{
144597883Sgibbs
144697883Sgibbs	if (ISSET(tp->t_state, TS_CARR_ON) && ISSET(tp->t_cflag, MDMBUF)) {
144797883Sgibbs		/*
144897883Sgibbs		 * MDMBUF: do flow control according to carrier flag
144997883Sgibbs		 * XXX TS_CAR_OFLOW doesn't do anything yet.  TS_TTSTOP
145097883Sgibbs		 * works if IXON and IXANY are clear.
145197883Sgibbs		 */
145297883Sgibbs		if (flag) {
145397883Sgibbs			CLR(tp->t_state, TS_CAR_OFLOW);
145497883Sgibbs			CLR(tp->t_state, TS_TTSTOP);
145597883Sgibbs			ttstart(tp);
145697883Sgibbs		} else if (!ISSET(tp->t_state, TS_CAR_OFLOW)) {
145797883Sgibbs			SET(tp->t_state, TS_CAR_OFLOW);
145897883Sgibbs			SET(tp->t_state, TS_TTSTOP);
145997883Sgibbs			(*tp->t_stop)(tp, 0);
146097883Sgibbs		}
146197883Sgibbs	} else if (flag == 0) {
146297883Sgibbs		/*
146397883Sgibbs		 * Lost carrier.
146497883Sgibbs		 */
146597883Sgibbs		CLR(tp->t_state, TS_CARR_ON);
146697883Sgibbs		if (ISSET(tp->t_state, TS_ISOPEN) &&
146797883Sgibbs		    !ISSET(tp->t_cflag, CLOCAL)) {
146897883Sgibbs			SET(tp->t_state, TS_ZOMBIE);
146997883Sgibbs			CLR(tp->t_state, TS_CONNECTED);
147097883Sgibbs			if (tp->t_session && tp->t_session->s_leader) {
147197883Sgibbs				struct proc *p;
147297883Sgibbs
147397883Sgibbs				p = tp->t_session->s_leader;
147497883Sgibbs				PROC_LOCK(p);
147597883Sgibbs				psignal(p, SIGHUP);
147697883Sgibbs				PROC_UNLOCK(p);
147797883Sgibbs			}
147897883Sgibbs			ttyflush(tp, FREAD | FWRITE);
147997883Sgibbs			return (0);
148097883Sgibbs		}
148197883Sgibbs	} else {
148297883Sgibbs		/*
148397883Sgibbs		 * Carrier now on.
148497883Sgibbs		 */
148597883Sgibbs		SET(tp->t_state, TS_CARR_ON);
148697883Sgibbs		if (!ISSET(tp->t_state, TS_ZOMBIE))
148797883Sgibbs			SET(tp->t_state, TS_CONNECTED);
148897883Sgibbs		wakeup(TSA_CARR_ON(tp));
148997883Sgibbs		ttwakeup(tp);
149097883Sgibbs		ttwwakeup(tp);
149197883Sgibbs	}
149297883Sgibbs	return (1);
149397883Sgibbs}
149497883Sgibbs
149597883Sgibbs/*
149697883Sgibbs * Reinput pending characters after state switch
149797883Sgibbs * call at spltty().
149897883Sgibbs */
149997883Sgibbsstatic void
150097883Sgibbsttypend(tp)
150197883Sgibbs	register struct tty *tp;
150297883Sgibbs{
150397883Sgibbs	struct clist tq;
150497883Sgibbs	register int c;
150597883Sgibbs
150697883Sgibbs	CLR(tp->t_lflag, PENDIN);
150797883Sgibbs	SET(tp->t_state, TS_TYPEN);
150897883Sgibbs	/*
150997883Sgibbs	 * XXX this assumes too much about clist internals.  It may even
151097883Sgibbs	 * fail if the cblock slush pool is empty.  We can't allocate more
151197883Sgibbs	 * cblocks here because we are called from an interrupt handler
151297883Sgibbs	 * and clist_alloc_cblocks() can wait.
151397883Sgibbs	 */
151497883Sgibbs	tq = tp->t_rawq;
151597883Sgibbs	bzero(&tp->t_rawq, sizeof tp->t_rawq);
151697883Sgibbs	tp->t_rawq.c_cbmax = tq.c_cbmax;
151797883Sgibbs	tp->t_rawq.c_cbreserved = tq.c_cbreserved;
151897883Sgibbs	while ((c = getc(&tq)) >= 0)
151997883Sgibbs		ttyinput(c, tp);
152097883Sgibbs	CLR(tp->t_state, TS_TYPEN);
152197883Sgibbs}
152297883Sgibbs
152397883Sgibbs/*
152497883Sgibbs * Process a read call on a tty device.
152597883Sgibbs */
152697883Sgibbsint
152797883Sgibbsttread(tp, uio, flag)
152897883Sgibbs	register struct tty *tp;
152997883Sgibbs	struct uio *uio;
153097883Sgibbs	int flag;
153197883Sgibbs{
153297883Sgibbs	register struct clist *qp;
153397883Sgibbs	register int c;
153497883Sgibbs	register tcflag_t lflag;
153597883Sgibbs	register cc_t *cc = tp->t_cc;
153697883Sgibbs	register struct proc *p = curproc;
153797883Sgibbs	int s, first, error = 0;
153897883Sgibbs	int has_stime = 0, last_cc = 0;
153997883Sgibbs	long slp = 0;		/* XXX this should be renamed `timo'. */
154097883Sgibbs	struct timeval stime;
154197883Sgibbs
154297883Sgibbsloop:
154397883Sgibbs	s = spltty();
154497883Sgibbs	lflag = tp->t_lflag;
154597883Sgibbs	/*
154697883Sgibbs	 * take pending input first
154797883Sgibbs	 */
154897883Sgibbs	if (ISSET(lflag, PENDIN)) {
154997883Sgibbs		ttypend(tp);
155097883Sgibbs		splx(s);	/* reduce latency */
155197883Sgibbs		s = spltty();
155297883Sgibbs		lflag = tp->t_lflag;	/* XXX ttypend() clobbers it */
155397883Sgibbs	}
155497883Sgibbs
155597883Sgibbs	/*
155697883Sgibbs	 * Hang process if it's in the background.
155797883Sgibbs	 */
155897883Sgibbs	if (isbackground(p, tp)) {
155997883Sgibbs		splx(s);
156097883Sgibbs		if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
156197883Sgibbs		    SIGISMEMBER(p->p_sigmask, SIGTTIN) ||
156297883Sgibbs		    (p->p_flag & P_PPWAIT) || p->p_pgrp->pg_jobc == 0)
156397883Sgibbs			return (EIO);
156497883Sgibbs		pgsignal(p->p_pgrp, SIGTTIN, 1);
156597883Sgibbs		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg2", 0);
156697883Sgibbs		if (error)
156797883Sgibbs			return (error);
156897883Sgibbs		goto loop;
156997883Sgibbs	}
157097883Sgibbs
157197883Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE)) {
157297883Sgibbs		splx(s);
157397883Sgibbs		return (0);	/* EOF */
157497883Sgibbs	}
157597883Sgibbs
157697883Sgibbs	/*
157797883Sgibbs	 * If canonical, use the canonical queue,
157897883Sgibbs	 * else use the raw queue.
157997883Sgibbs	 *
158097883Sgibbs	 * (should get rid of clists...)
158197883Sgibbs	 */
158297883Sgibbs	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
158397883Sgibbs
158497883Sgibbs	if (flag & IO_NDELAY) {
158597883Sgibbs		if (qp->c_cc > 0)
158697883Sgibbs			goto read;
158797883Sgibbs		if (!ISSET(lflag, ICANON) && cc[VMIN] == 0) {
158897883Sgibbs			splx(s);
158997883Sgibbs			return (0);
159097883Sgibbs		}
159197883Sgibbs		splx(s);
159297883Sgibbs		return (EWOULDBLOCK);
159397883Sgibbs	}
159497883Sgibbs	if (!ISSET(lflag, ICANON)) {
159597883Sgibbs		int m = cc[VMIN];
159697883Sgibbs		long t = cc[VTIME];
159797883Sgibbs		struct timeval timecopy;
159897883Sgibbs
159997883Sgibbs		/*
160097883Sgibbs		 * Check each of the four combinations.
160197883Sgibbs		 * (m > 0 && t == 0) is the normal read case.
160297883Sgibbs		 * It should be fairly efficient, so we check that and its
160397883Sgibbs		 * companion case (m == 0 && t == 0) first.
160497883Sgibbs		 * For the other two cases, we compute the target sleep time
160597883Sgibbs		 * into slp.
160697883Sgibbs		 */
160797883Sgibbs		if (t == 0) {
160897883Sgibbs			if (qp->c_cc < m)
160997883Sgibbs				goto sleep;
161097883Sgibbs			if (qp->c_cc > 0)
161197883Sgibbs				goto read;
161297883Sgibbs
161397883Sgibbs			/* m, t and qp->c_cc are all 0.  0 is enough input. */
161497883Sgibbs			splx(s);
161597883Sgibbs			return (0);
161697883Sgibbs		}
161797883Sgibbs		t *= 100000;		/* time in us */
161897883Sgibbs#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \
161997883Sgibbs			 ((t1).tv_usec - (t2).tv_usec))
162097883Sgibbs		if (m > 0) {
162197883Sgibbs			if (qp->c_cc <= 0)
162297883Sgibbs				goto sleep;
162397883Sgibbs			if (qp->c_cc >= m)
162497883Sgibbs				goto read;
162597883Sgibbs			getmicrotime(&timecopy);
162697883Sgibbs			if (!has_stime) {
162797883Sgibbs				/* first character, start timer */
162897883Sgibbs				has_stime = 1;
162997883Sgibbs				stime = timecopy;
163097883Sgibbs				slp = t;
163197883Sgibbs			} else if (qp->c_cc > last_cc) {
163297883Sgibbs				/* got a character, restart timer */
163397883Sgibbs				stime = timecopy;
163497883Sgibbs				slp = t;
163597883Sgibbs			} else {
163697883Sgibbs				/* nothing, check expiration */
163797883Sgibbs				slp = t - diff(timecopy, stime);
163897883Sgibbs				if (slp <= 0)
163997883Sgibbs					goto read;
164097883Sgibbs			}
164197883Sgibbs			last_cc = qp->c_cc;
164297883Sgibbs		} else {	/* m == 0 */
164397883Sgibbs			if (qp->c_cc > 0)
164497883Sgibbs				goto read;
164597883Sgibbs			getmicrotime(&timecopy);
164697883Sgibbs			if (!has_stime) {
164797883Sgibbs				has_stime = 1;
164897883Sgibbs				stime = timecopy;
164997883Sgibbs				slp = t;
165097883Sgibbs			} else {
165197883Sgibbs				slp = t - diff(timecopy, stime);
165297883Sgibbs				if (slp <= 0) {
165397883Sgibbs					/* Timed out, but 0 is enough input. */
165497883Sgibbs					splx(s);
165597883Sgibbs					return (0);
165697883Sgibbs				}
165797883Sgibbs			}
165897883Sgibbs		}
165997883Sgibbs#undef diff
166097883Sgibbs		/*
166197883Sgibbs		 * Rounding down may make us wake up just short
166297883Sgibbs		 * of the target, so we round up.
166397883Sgibbs		 * The formula is ceiling(slp * hz/1000000).
166497883Sgibbs		 * 32-bit arithmetic is enough for hz < 169.
166597883Sgibbs		 * XXX see tvtohz() for how to avoid overflow if hz
166697883Sgibbs		 * is large (divide by `tick' and/or arrange to
166797883Sgibbs		 * use tvtohz() if hz is large).
166897883Sgibbs		 */
166997883Sgibbs		slp = (long) (((u_long)slp * hz) + 999999) / 1000000;
167097883Sgibbs		goto sleep;
167197883Sgibbs	}
167297883Sgibbs	if (qp->c_cc <= 0) {
167397883Sgibbssleep:
167497883Sgibbs		/*
167597883Sgibbs		 * There is no input, or not enough input and we can block.
167697883Sgibbs		 */
167797883Sgibbs		error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
167897883Sgibbs				 ISSET(tp->t_state, TS_CONNECTED) ?
167997883Sgibbs				 "ttyin" : "ttyhup", (int)slp);
168097883Sgibbs		splx(s);
168197883Sgibbs		if (error == EWOULDBLOCK)
168297883Sgibbs			error = 0;
168397883Sgibbs		else if (error)
168497883Sgibbs			return (error);
168597883Sgibbs		/*
168697883Sgibbs		 * XXX what happens if another process eats some input
168797883Sgibbs		 * while we are asleep (not just here)?  It would be
168897883Sgibbs		 * safest to detect changes and reset our state variables
168997883Sgibbs		 * (has_stime and last_cc).
169097883Sgibbs		 */
169197883Sgibbs		slp = 0;
169297883Sgibbs		goto loop;
169397883Sgibbs	}
169497883Sgibbsread:
169597883Sgibbs	splx(s);
169697883Sgibbs	/*
169797883Sgibbs	 * Input present, check for input mapping and processing.
169897883Sgibbs	 */
169997883Sgibbs	first = 1;
170097883Sgibbs	if (ISSET(lflag, ICANON | ISIG))
170197883Sgibbs		goto slowcase;
170297883Sgibbs	for (;;) {
170397883Sgibbs		char ibuf[IBUFSIZ];
170497883Sgibbs		int icc;
170597883Sgibbs
170697883Sgibbs		icc = imin(uio->uio_resid, IBUFSIZ);
170797883Sgibbs		icc = q_to_b(qp, ibuf, icc);
170897883Sgibbs		if (icc <= 0) {
170997883Sgibbs			if (first)
171097883Sgibbs				goto loop;
171197883Sgibbs			break;
171297883Sgibbs		}
171397883Sgibbs		error = uiomove(ibuf, icc, uio);
171497883Sgibbs		/*
171597883Sgibbs		 * XXX if there was an error then we should ungetc() the
171697883Sgibbs		 * unmoved chars and reduce icc here.
171797883Sgibbs		 */
171897883Sgibbs#ifdef DEV_SNP
171997883Sgibbs		if (ISSET(tp->t_lflag, ECHO) &&
172097883Sgibbs		    ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
172197883Sgibbs			snpin((struct snoop *)tp->t_sc, ibuf, icc);
172297883Sgibbs#endif
172397883Sgibbs		if (error)
172497883Sgibbs			break;
172597883Sgibbs 		if (uio->uio_resid == 0)
172697883Sgibbs			break;
172797883Sgibbs		first = 0;
172897883Sgibbs	}
172997883Sgibbs	goto out;
173097883Sgibbsslowcase:
173197883Sgibbs	for (;;) {
173297883Sgibbs		c = getc(qp);
173397883Sgibbs		if (c < 0) {
173497883Sgibbs			if (first)
173597883Sgibbs				goto loop;
173697883Sgibbs			break;
173797883Sgibbs		}
173897883Sgibbs		/*
173997883Sgibbs		 * delayed suspend (^Y)
174097883Sgibbs		 */
174197883Sgibbs		if (CCEQ(cc[VDSUSP], c) &&
174297883Sgibbs		    ISSET(lflag, IEXTEN | ISIG) == (IEXTEN | ISIG)) {
174397883Sgibbs			pgsignal(tp->t_pgrp, SIGTSTP, 1);
174497883Sgibbs			if (first) {
174597883Sgibbs				error = ttysleep(tp, &lbolt, TTIPRI | PCATCH,
174697883Sgibbs						 "ttybg3", 0);
174797883Sgibbs				if (error)
174897883Sgibbs					break;
174997883Sgibbs				goto loop;
175097883Sgibbs			}
175197883Sgibbs			break;
175297883Sgibbs		}
175397883Sgibbs		/*
175497883Sgibbs		 * Interpret EOF only in canonical mode.
175597883Sgibbs		 */
175697883Sgibbs		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
175797883Sgibbs			break;
175897883Sgibbs		/*
175997883Sgibbs		 * Give user character.
176097883Sgibbs		 */
176197883Sgibbs 		error = ureadc(c, uio);
176297883Sgibbs		if (error)
176397883Sgibbs			/* XXX should ungetc(c, qp). */
176497883Sgibbs			break;
176597883Sgibbs#ifdef DEV_SNP
176697883Sgibbs		/*
176797883Sgibbs		 * Only snoop directly on input in echo mode.  Non-echoed
176897883Sgibbs		 * input will be snooped later iff the application echoes it.
176997883Sgibbs		 */
177097883Sgibbs		if (ISSET(tp->t_lflag, ECHO) &&
177197883Sgibbs		    ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
177297883Sgibbs			snpinc((struct snoop *)tp->t_sc, (char)c);
177397883Sgibbs#endif
177497883Sgibbs 		if (uio->uio_resid == 0)
177597883Sgibbs			break;
177697883Sgibbs		/*
177797883Sgibbs		 * In canonical mode check for a "break character"
177897883Sgibbs		 * marking the end of a "line of input".
177997883Sgibbs		 */
178097883Sgibbs		if (ISSET(lflag, ICANON) && TTBREAKC(c, lflag))
178197883Sgibbs			break;
178297883Sgibbs		first = 0;
178397883Sgibbs	}
178497883Sgibbs
178597883Sgibbsout:
178697883Sgibbs	/*
178797883Sgibbs	 * Look to unblock input now that (presumably)
178897883Sgibbs	 * the input queue has gone down.
178997883Sgibbs	 */
179097883Sgibbs	s = spltty();
179197883Sgibbs	if (ISSET(tp->t_state, TS_TBLOCK) &&
179297883Sgibbs	    tp->t_rawq.c_cc + tp->t_canq.c_cc <= tp->t_ilowat)
179397883Sgibbs		ttyunblock(tp);
179497883Sgibbs	splx(s);
179597883Sgibbs
179697883Sgibbs	return (error);
179797883Sgibbs}
179897883Sgibbs
179997883Sgibbs/*
180097883Sgibbs * Check the output queue on tp for space for a kernel message (from uprintf
180197883Sgibbs * or tprintf).  Allow some space over the normal hiwater mark so we don't
180297883Sgibbs * lose messages due to normal flow control, but don't let the tty run amok.
180397883Sgibbs * Sleeps here are not interruptible, but we return prematurely if new signals
180497883Sgibbs * arrive.
180597883Sgibbs */
180697883Sgibbsint
180797883Sgibbsttycheckoutq(tp, wait)
180897883Sgibbs	register struct tty *tp;
180997883Sgibbs	int wait;
181097883Sgibbs{
181197883Sgibbs	int hiwat, s;
181297883Sgibbs	sigset_t oldmask;
181397883Sgibbs
181497883Sgibbs	hiwat = tp->t_ohiwat;
181597883Sgibbs	SIGEMPTYSET(oldmask);
181697883Sgibbs	s = spltty();
181797883Sgibbs	if (wait)
181897883Sgibbs		oldmask = curproc->p_siglist;
181997883Sgibbs	if (tp->t_outq.c_cc > hiwat + OBUFSIZ + 100)
182097883Sgibbs		while (tp->t_outq.c_cc > hiwat) {
182197883Sgibbs			ttstart(tp);
182297883Sgibbs			if (tp->t_outq.c_cc <= hiwat)
182397883Sgibbs				break;
182497883Sgibbs			if (!(wait && SIGSETEQ(curproc->p_siglist, oldmask))) {
182597883Sgibbs				splx(s);
182697883Sgibbs				return (0);
182797883Sgibbs			}
182897883Sgibbs			SET(tp->t_state, TS_SO_OLOWAT);
182997883Sgibbs			tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz);
183097883Sgibbs		}
183197883Sgibbs	splx(s);
183297883Sgibbs	return (1);
183397883Sgibbs}
183497883Sgibbs
183597883Sgibbs/*
183697883Sgibbs * Process a write call on a tty device.
183797883Sgibbs */
183897883Sgibbsint
183997883Sgibbsttwrite(tp, uio, flag)
184097883Sgibbs	register struct tty *tp;
184197883Sgibbs	register struct uio *uio;
184297883Sgibbs	int flag;
184397883Sgibbs{
184497883Sgibbs	register char *cp = NULL;
184597883Sgibbs	register int cc, ce;
184697883Sgibbs	register struct proc *p;
184797883Sgibbs	int i, hiwat, cnt, error, s;
184897883Sgibbs	char obuf[OBUFSIZ];
184997883Sgibbs
185097883Sgibbs	hiwat = tp->t_ohiwat;
185197883Sgibbs	cnt = uio->uio_resid;
185297883Sgibbs	error = 0;
185397883Sgibbs	cc = 0;
185497883Sgibbsloop:
185597883Sgibbs	s = spltty();
185697883Sgibbs	if (ISSET(tp->t_state, TS_ZOMBIE)) {
185797883Sgibbs		splx(s);
185897883Sgibbs		if (uio->uio_resid == cnt)
185997883Sgibbs			error = EIO;
186097883Sgibbs		goto out;
186197883Sgibbs	}
186297883Sgibbs	if (!ISSET(tp->t_state, TS_CONNECTED)) {
186397883Sgibbs		if (flag & IO_NDELAY) {
186497883Sgibbs			splx(s);
186597883Sgibbs			error = EWOULDBLOCK;
186697883Sgibbs			goto out;
186797883Sgibbs		}
186897883Sgibbs		error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
186997883Sgibbs				 "ttydcd", 0);
187097883Sgibbs		splx(s);
187197883Sgibbs		if (error)
187297883Sgibbs			goto out;
187397883Sgibbs		goto loop;
187497883Sgibbs	}
187597883Sgibbs	splx(s);
187697883Sgibbs	/*
187797883Sgibbs	 * Hang the process if it's in the background.
187897883Sgibbs	 */
187997883Sgibbs	p = curproc;
188097883Sgibbs	if (isbackground(p, tp) &&
188197883Sgibbs	    ISSET(tp->t_lflag, TOSTOP) && !(p->p_flag & P_PPWAIT) &&
188297883Sgibbs	    !SIGISMEMBER(p->p_sigignore, SIGTTOU) &&
188397883Sgibbs	    !SIGISMEMBER(p->p_sigmask, SIGTTOU)) {
188497883Sgibbs		if (p->p_pgrp->pg_jobc == 0) {
188597883Sgibbs			error = EIO;
188697883Sgibbs			goto out;
188797883Sgibbs		}
188897883Sgibbs		pgsignal(p->p_pgrp, SIGTTOU, 1);
188997883Sgibbs		error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, "ttybg4", 0);
189097883Sgibbs		if (error)
189197883Sgibbs			goto out;
189297883Sgibbs		goto loop;
189397883Sgibbs	}
189497883Sgibbs	/*
189597883Sgibbs	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
189697883Sgibbs	 * output translation.  Keep track of high water mark, sleep on
189797883Sgibbs	 * overflow awaiting device aid in acquiring new space.
189897883Sgibbs	 */
189997883Sgibbs	while (uio->uio_resid > 0 || cc > 0) {
190097883Sgibbs		if (ISSET(tp->t_lflag, FLUSHO)) {
190197883Sgibbs			uio->uio_resid = 0;
190297883Sgibbs			return (0);
190397883Sgibbs		}
190497883Sgibbs		if (tp->t_outq.c_cc > hiwat)
190597883Sgibbs			goto ovhiwat;
190697883Sgibbs		/*
190797883Sgibbs		 * Grab a hunk of data from the user, unless we have some
190897883Sgibbs		 * leftover from last time.
190997883Sgibbs		 */
191097883Sgibbs		if (cc == 0) {
191197883Sgibbs			cc = imin(uio->uio_resid, OBUFSIZ);
191297883Sgibbs			cp = obuf;
191397883Sgibbs			error = uiomove(cp, cc, uio);
191497883Sgibbs			if (error) {
191597883Sgibbs				cc = 0;
191697883Sgibbs				break;
191797883Sgibbs			}
191897883Sgibbs#ifdef DEV_SNP
191997883Sgibbs			if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)
192097883Sgibbs				snpin((struct snoop *)tp->t_sc, cp, cc);
192197883Sgibbs#endif
192297883Sgibbs		}
192397883Sgibbs		/*
192497883Sgibbs		 * If nothing fancy need be done, grab those characters we
192597883Sgibbs		 * can handle without any of ttyoutput's processing and
192697883Sgibbs		 * just transfer them to the output q.  For those chars
192797883Sgibbs		 * which require special processing (as indicated by the
192897883Sgibbs		 * bits in char_type), call ttyoutput.  After processing
192997883Sgibbs		 * a hunk of data, look for FLUSHO so ^O's will take effect
193097883Sgibbs		 * immediately.
193197883Sgibbs		 */
193297883Sgibbs		while (cc > 0) {
193397883Sgibbs			if (!ISSET(tp->t_oflag, OPOST))
193497883Sgibbs				ce = cc;
193597883Sgibbs			else {
193697883Sgibbs				ce = cc - scanc((u_int)cc, (u_char *)cp,
193797883Sgibbs						char_type, CCLASSMASK);
193897883Sgibbs				/*
193997883Sgibbs				 * If ce is zero, then we're processing
194097883Sgibbs				 * a special character through ttyoutput.
194197883Sgibbs				 */
194297883Sgibbs				if (ce == 0) {
194397883Sgibbs					tp->t_rocount = 0;
1944107368Sscottl					if (ttyoutput(*cp, tp) >= 0) {
194597883Sgibbs						/* No Clists, wait a bit. */
194697883Sgibbs						ttstart(tp);
194797883Sgibbs						if (flag & IO_NDELAY) {
194897883Sgibbs							error = EWOULDBLOCK;
194997883Sgibbs							goto out;
195097883Sgibbs						}
195197883Sgibbs						error = ttysleep(tp, &lbolt,
195297883Sgibbs								 TTOPRI|PCATCH,
195397883Sgibbs								 "ttybf1", 0);
195497883Sgibbs						if (error)
195597883Sgibbs							goto out;
195697883Sgibbs						goto loop;
195797883Sgibbs					}
195897883Sgibbs					cp++;
195997883Sgibbs					cc--;
196097883Sgibbs					if (ISSET(tp->t_lflag, FLUSHO) ||
196197883Sgibbs					    tp->t_outq.c_cc > hiwat)
196297883Sgibbs						goto ovhiwat;
196397883Sgibbs					continue;
196497883Sgibbs				}
196597883Sgibbs			}
196697883Sgibbs			/*
196797883Sgibbs			 * A bunch of normal characters have been found.
196897883Sgibbs			 * Transfer them en masse to the output queue and
196997883Sgibbs			 * continue processing at the top of the loop.
197097883Sgibbs			 * If there are any further characters in this
197197883Sgibbs			 * <= OBUFSIZ chunk, the first should be a character
197297883Sgibbs			 * requiring special handling by ttyoutput.
197397883Sgibbs			 */
197497883Sgibbs			tp->t_rocount = 0;
197597883Sgibbs			i = b_to_q(cp, ce, &tp->t_outq);
197697883Sgibbs			ce -= i;
197797883Sgibbs			tp->t_column += ce;
197897883Sgibbs			cp += ce, cc -= ce, tk_nout += ce;
197997883Sgibbs			tp->t_outcc += ce;
198097883Sgibbs			if (i > 0) {
198197883Sgibbs				/* No Clists, wait a bit. */
198297883Sgibbs				ttstart(tp);
198397883Sgibbs				if (flag & IO_NDELAY) {
198497883Sgibbs					error = EWOULDBLOCK;
198597883Sgibbs					goto out;
198697883Sgibbs				}
198797883Sgibbs				error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,
198897883Sgibbs						 "ttybf2", 0);
198997883Sgibbs				if (error)
199097883Sgibbs					goto out;
199197883Sgibbs				goto loop;
199297883Sgibbs			}
199397883Sgibbs			if (ISSET(tp->t_lflag, FLUSHO) ||
199497883Sgibbs			    tp->t_outq.c_cc > hiwat)
199597883Sgibbs				break;
199697883Sgibbs		}
199797883Sgibbs		ttstart(tp);
199897883Sgibbs	}
199997883Sgibbsout:
200097883Sgibbs	/*
200197883Sgibbs	 * If cc is nonzero, we leave the uio structure inconsistent, as the
200297883Sgibbs	 * offset and iov pointers have moved forward, but it doesn't matter
2003107368Sscottl	 * (the call will either return short or restart with a new uio).
2004107368Sscottl	 */
2005107368Sscottl	uio->uio_resid += cc;
200697883Sgibbs	return (error);
200797883Sgibbs
200897883Sgibbsovhiwat:
200997883Sgibbs	ttstart(tp);
201097883Sgibbs	s = spltty();
201197883Sgibbs	/*
201297883Sgibbs	 * This can only occur if FLUSHO is set in t_lflag,
201397883Sgibbs	 * or if ttstart/oproc is synchronous (or very fast).
201497883Sgibbs	 */
201597883Sgibbs	if (tp->t_outq.c_cc <= hiwat) {
201697883Sgibbs		splx(s);
2017		goto loop;
2018	}
2019	if (flag & IO_NDELAY) {
2020		splx(s);
2021		uio->uio_resid += cc;
2022		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
2023	}
2024	SET(tp->t_state, TS_SO_OLOWAT);
2025	error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",
2026			 tp->t_timeout);
2027	splx(s);
2028	if (error == EWOULDBLOCK)
2029		error = EIO;
2030	if (error)
2031		goto out;
2032	goto loop;
2033}
2034
2035/*
2036 * Rubout one character from the rawq of tp
2037 * as cleanly as possible.
2038 */
2039static void
2040ttyrub(c, tp)
2041	register int c;
2042	register struct tty *tp;
2043{
2044	register char *cp;
2045	register int savecol;
2046	int tabc, s;
2047
2048	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
2049		return;
2050	CLR(tp->t_lflag, FLUSHO);
2051	if (ISSET(tp->t_lflag, ECHOE)) {
2052		if (tp->t_rocount == 0) {
2053			/*
2054			 * Screwed by ttwrite; retype
2055			 */
2056			ttyretype(tp);
2057			return;
2058		}
2059		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
2060			ttyrubo(tp, 2);
2061		else {
2062			CLR(c, ~TTY_CHARMASK);
2063			switch (CCLASS(c)) {
2064			case ORDINARY:
2065				ttyrubo(tp, 1);
2066				break;
2067			case BACKSPACE:
2068			case CONTROL:
2069			case NEWLINE:
2070			case RETURN:
2071			case VTAB:
2072				if (ISSET(tp->t_lflag, ECHOCTL))
2073					ttyrubo(tp, 2);
2074				break;
2075			case TAB:
2076				if (tp->t_rocount < tp->t_rawq.c_cc) {
2077					ttyretype(tp);
2078					return;
2079				}
2080				s = spltty();
2081				savecol = tp->t_column;
2082				SET(tp->t_state, TS_CNTTB);
2083				SET(tp->t_lflag, FLUSHO);
2084				tp->t_column = tp->t_rocol;
2085				cp = tp->t_rawq.c_cf;
2086				if (cp)
2087					tabc = *cp;	/* XXX FIX NEXTC */
2088				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
2089					ttyecho(tabc, tp);
2090				CLR(tp->t_lflag, FLUSHO);
2091				CLR(tp->t_state, TS_CNTTB);
2092				splx(s);
2093
2094				/* savecol will now be length of the tab. */
2095				savecol -= tp->t_column;
2096				tp->t_column += savecol;
2097				if (savecol > 8)
2098					savecol = 8;	/* overflow screw */
2099				while (--savecol >= 0)
2100					(void)ttyoutput('\b', tp);
2101				break;
2102			default:			/* XXX */
2103#define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
2104				(void)printf(PANICSTR, c, CCLASS(c));
2105#ifdef notdef
2106				panic(PANICSTR, c, CCLASS(c));
2107#endif
2108			}
2109		}
2110	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
2111		if (!ISSET(tp->t_state, TS_ERASE)) {
2112			SET(tp->t_state, TS_ERASE);
2113			(void)ttyoutput('\\', tp);
2114		}
2115		ttyecho(c, tp);
2116	} else {
2117		ttyecho(tp->t_cc[VERASE], tp);
2118		/*
2119		 * This code may be executed not only when an ERASE key
2120		 * is pressed, but also when ^U (KILL) or ^W (WERASE) are.
2121		 * So, I didn't think it was worthwhile to pass the extra
2122		 * information (which would need an extra parameter,
2123		 * changing every call) needed to distinguish the ERASE2
2124		 * case from the ERASE.
2125		 */
2126	}
2127	--tp->t_rocount;
2128}
2129
2130/*
2131 * Back over cnt characters, erasing them.
2132 */
2133static void
2134ttyrubo(tp, cnt)
2135	register struct tty *tp;
2136	int cnt;
2137{
2138
2139	while (cnt-- > 0) {
2140		(void)ttyoutput('\b', tp);
2141		(void)ttyoutput(' ', tp);
2142		(void)ttyoutput('\b', tp);
2143	}
2144}
2145
2146/*
2147 * ttyretype --
2148 *	Reprint the rawq line.  Note, it is assumed that c_cc has already
2149 *	been checked.
2150 */
2151static void
2152ttyretype(tp)
2153	register struct tty *tp;
2154{
2155	register char *cp;
2156	int s, c;
2157
2158	/* Echo the reprint character. */
2159	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
2160		ttyecho(tp->t_cc[VREPRINT], tp);
2161
2162	(void)ttyoutput('\n', tp);
2163
2164	/*
2165	 * XXX
2166	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
2167	 * BIT OF FIRST CHAR.
2168	 */
2169	s = spltty();
2170	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
2171	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
2172		ttyecho(c, tp);
2173	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
2174	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
2175		ttyecho(c, tp);
2176	CLR(tp->t_state, TS_ERASE);
2177	splx(s);
2178
2179	tp->t_rocount = tp->t_rawq.c_cc;
2180	tp->t_rocol = 0;
2181}
2182
2183/*
2184 * Echo a typed character to the terminal.
2185 */
2186static void
2187ttyecho(c, tp)
2188	register int c;
2189	register struct tty *tp;
2190{
2191
2192	if (!ISSET(tp->t_state, TS_CNTTB))
2193		CLR(tp->t_lflag, FLUSHO);
2194	if ((!ISSET(tp->t_lflag, ECHO) &&
2195	     (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||
2196	    ISSET(tp->t_lflag, EXTPROC))
2197		return;
2198	if (ISSET(tp->t_lflag, ECHOCTL) &&
2199	    ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||
2200	    ISSET(c, TTY_CHARMASK) == 0177)) {
2201		(void)ttyoutput('^', tp);
2202		CLR(c, ~TTY_CHARMASK);
2203		if (c == 0177)
2204			c = '?';
2205		else
2206			c += 'A' - 1;
2207	}
2208	(void)ttyoutput(c, tp);
2209}
2210
2211/*
2212 * Wake up any readers on a tty.
2213 */
2214void
2215ttwakeup(tp)
2216	register struct tty *tp;
2217{
2218
2219	if (tp->t_rsel.si_pid != 0)
2220		selwakeup(&tp->t_rsel);
2221	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2222		pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
2223	wakeup(TSA_HUP_OR_INPUT(tp));
2224	KNOTE(&tp->t_rsel.si_note, 0);
2225}
2226
2227/*
2228 * Wake up any writers on a tty.
2229 */
2230void
2231ttwwakeup(tp)
2232	register struct tty *tp;
2233{
2234
2235	if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_olowat)
2236		selwakeup(&tp->t_wsel);
2237	if (ISSET(tp->t_state, TS_ASYNC) && tp->t_sigio != NULL)
2238		pgsigio(tp->t_sigio, SIGIO, (tp->t_session != NULL));
2239	if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
2240	    TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
2241		CLR(tp->t_state, TS_SO_OCOMPLETE);
2242		wakeup(TSA_OCOMPLETE(tp));
2243	}
2244	if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
2245	    tp->t_outq.c_cc <= tp->t_olowat) {
2246		CLR(tp->t_state, TS_SO_OLOWAT);
2247		wakeup(TSA_OLOWAT(tp));
2248	}
2249	KNOTE(&tp->t_wsel.si_note, 0);
2250}
2251
2252/*
2253 * Look up a code for a specified speed in a conversion table;
2254 * used by drivers to map software speed values to hardware parameters.
2255 */
2256int
2257ttspeedtab(speed, table)
2258	int speed;
2259	register struct speedtab *table;
2260{
2261
2262	for ( ; table->sp_speed != -1; table++)
2263		if (table->sp_speed == speed)
2264			return (table->sp_code);
2265	return (-1);
2266}
2267
2268/*
2269 * Set input and output watermarks and buffer sizes.  For input, the
2270 * high watermark is about one second's worth of input above empty, the
2271 * low watermark is slightly below high water, and the buffer size is a
2272 * driver-dependent amount above high water.  For output, the watermarks
2273 * are near the ends of the buffer, with about 1 second's worth of input
2274 * between them.  All this only applies to the standard line discipline.
2275 */
2276void
2277ttsetwater(tp)
2278	struct tty *tp;
2279{
2280	register int cps, ttmaxhiwat, x;
2281
2282	/* Input. */
2283	clist_alloc_cblocks(&tp->t_canq, TTYHOG, 512);
2284	switch (tp->t_ispeedwat) {
2285	case (speed_t)-1:
2286		cps = tp->t_ispeed / 10;
2287		break;
2288	case 0:
2289		/*
2290		 * This case is for old drivers that don't know about
2291		 * t_ispeedwat.  Arrange for them to get the old buffer
2292		 * sizes and watermarks.
2293		 */
2294		cps = TTYHOG - 2 * 256;
2295		tp->t_ififosize = 2 * 256;
2296		break;
2297	default:
2298		cps = tp->t_ispeedwat / 10;
2299		break;
2300	}
2301	tp->t_ihiwat = cps;
2302	tp->t_ilowat = 7 * cps / 8;
2303	x = cps + tp->t_ififosize;
2304	clist_alloc_cblocks(&tp->t_rawq, x, x);
2305
2306	/* Output. */
2307	switch (tp->t_ospeedwat) {
2308	case (speed_t)-1:
2309		cps = tp->t_ospeed / 10;
2310		ttmaxhiwat = 2 * TTMAXHIWAT;
2311		break;
2312	case 0:
2313		cps = tp->t_ospeed / 10;
2314		ttmaxhiwat = TTMAXHIWAT;
2315		break;
2316	default:
2317		cps = tp->t_ospeedwat / 10;
2318		ttmaxhiwat = 8 * TTMAXHIWAT;
2319		break;
2320	}
2321#define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
2322	tp->t_olowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
2323	x += cps;
2324	x = CLAMP(x, ttmaxhiwat, TTMINHIWAT);	/* XXX clamps are too magic */
2325	tp->t_ohiwat = roundup(x, CBSIZE);	/* XXX for compat */
2326	x = imax(tp->t_ohiwat, TTMAXHIWAT);	/* XXX for compat/safety */
2327	x += OBUFSIZ + 100;
2328	clist_alloc_cblocks(&tp->t_outq, x, x);
2329#undef	CLAMP
2330}
2331
2332/*
2333 * Report on state of foreground process group.
2334 */
2335void
2336ttyinfo(tp)
2337	register struct tty *tp;
2338{
2339	register struct proc *p, *pick;
2340	struct timeval utime, stime;
2341	const char *stmp;
2342	long ltmp;
2343	int tmp;
2344
2345	if (ttycheckoutq(tp,0) == 0)
2346		return;
2347
2348	/* Print load average. */
2349	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
2350	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
2351
2352	if (tp->t_session == NULL)
2353		ttyprintf(tp, "not a controlling terminal\n");
2354	else if (tp->t_pgrp == NULL)
2355		ttyprintf(tp, "no foreground process group\n");
2356	else if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0)
2357		ttyprintf(tp, "empty foreground process group\n");
2358	else {
2359		mtx_lock_spin(&sched_lock);
2360
2361		/* Pick interesting process. */
2362		for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist))
2363			if (proc_compare(pick, p))
2364				pick = p;
2365
2366		stmp = pick->p_stat == SRUN ? "running" :
2367		    pick->p_wmesg ? pick->p_wmesg : "iowait";
2368		calcru(pick, &utime, &stime, NULL);
2369		ltmp = pick->p_stat == SIDL || pick->p_stat == SWAIT ||
2370		    pick->p_stat == SZOMB ? 0 :
2371		    pgtok(vmspace_resident_count(pick->p_vmspace));
2372		mtx_unlock_spin(&sched_lock);
2373
2374		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
2375		    stmp);
2376
2377		/* Print user time. */
2378		ttyprintf(tp, "%ld.%02ldu ",
2379		    utime.tv_sec, utime.tv_usec / 10000);
2380
2381		/* Print system time. */
2382		ttyprintf(tp, "%ld.%02lds ",
2383		    stime.tv_sec, stime.tv_usec / 10000);
2384
2385		/* Print percentage cpu, resident set size. */
2386		ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp);
2387	}
2388	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
2389}
2390
2391/*
2392 * Returns 1 if p2 is "better" than p1
2393 *
2394 * The algorithm for picking the "interesting" process is thus:
2395 *
2396 *	1) Only foreground processes are eligible - implied.
2397 *	2) Runnable processes are favored over anything else.  The runner
2398 *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
2399 *	   broken by picking the highest pid.
2400 *	3) The sleeper with the shortest sleep time is next.  With ties,
2401 *	   we pick out just "short-term" sleepers (P_SINTR == 0).
2402 *	4) Further ties are broken by picking the highest pid.
2403 */
2404#define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
2405#define TESTAB(a, b)    ((a)<<1 | (b))
2406#define ONLYA   2
2407#define ONLYB   1
2408#define BOTH    3
2409
2410static int
2411proc_compare(p1, p2)
2412	register struct proc *p1, *p2;
2413{
2414
2415	mtx_assert(&sched_lock, MA_OWNED);
2416	if (p1 == NULL)
2417		return (1);
2418
2419	/*
2420	 * see if at least one of them is runnable
2421	 */
2422	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
2423	case ONLYA:
2424		return (0);
2425	case ONLYB:
2426		return (1);
2427	case BOTH:
2428		/*
2429		 * tie - favor one with highest recent cpu utilization
2430		 */
2431		if (p2->p_estcpu > p1->p_estcpu)
2432			return (1);
2433		if (p1->p_estcpu > p2->p_estcpu)
2434			return (0);
2435		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
2436	}
2437	/*
2438 	 * weed out zombies
2439	 */
2440	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
2441	case ONLYA:
2442		return (1);
2443	case ONLYB:
2444		return (0);
2445	case BOTH:
2446		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
2447	}
2448
2449	/*
2450	 * pick the one with the smallest sleep time
2451	 */
2452	if (p2->p_slptime > p1->p_slptime)
2453		return (0);
2454	if (p1->p_slptime > p2->p_slptime)
2455		return (1);
2456	/*
2457	 * favor one sleeping in a non-interruptible sleep
2458	 */
2459	if (p1->p_sflag & PS_SINTR && (p2->p_sflag & PS_SINTR) == 0)
2460		return (1);
2461	if (p2->p_sflag & PS_SINTR && (p1->p_sflag & PS_SINTR) == 0)
2462		return (0);
2463	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
2464}
2465
2466/*
2467 * Output char to tty; console putchar style.
2468 */
2469int
2470tputchar(c, tp)
2471	int c;
2472	struct tty *tp;
2473{
2474	register int s;
2475
2476	s = spltty();
2477	if (!ISSET(tp->t_state, TS_CONNECTED)) {
2478		splx(s);
2479		return (-1);
2480	}
2481	if (c == '\n')
2482		(void)ttyoutput('\r', tp);
2483	(void)ttyoutput(c, tp);
2484	ttstart(tp);
2485	splx(s);
2486	return (0);
2487}
2488
2489/*
2490 * Sleep on chan, returning ERESTART if tty changed while we napped and
2491 * returning any errors (e.g. EINTR/EWOULDBLOCK) reported by tsleep.  If
2492 * the tty is revoked, restarting a pending call will redo validation done
2493 * at the start of the call.
2494 */
2495int
2496ttysleep(tp, chan, pri, wmesg, timo)
2497	struct tty *tp;
2498	void *chan;
2499	int pri, timo;
2500	char *wmesg;
2501{
2502	int error;
2503	int gen;
2504
2505	gen = tp->t_gen;
2506	error = tsleep(chan, pri, wmesg, timo);
2507	if (error)
2508		return (error);
2509	return (tp->t_gen == gen ? 0 : ERESTART);
2510}
2511
2512/*
2513 * Allocate a tty struct.  Clists in the struct will be allocated by
2514 * ttyopen().
2515 */
2516struct tty *
2517ttymalloc(tp)
2518	struct tty *tp;
2519{
2520
2521	if (tp)
2522		return(tp);
2523        tp = malloc(sizeof *tp, M_TTYS, M_WAITOK | M_ZERO);
2524	ttyregister(tp);
2525        return (tp);
2526}
2527
2528#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). */
2529/*
2530 * Free a tty struct.  Clists in the struct should have been freed by
2531 * ttyclose().
2532 */
2533void
2534ttyfree(tp)
2535	struct tty *tp;
2536{
2537        free(tp, M_TTYS);
2538}
2539#endif /* 0 */
2540
2541void
2542ttyregister(tp)
2543	struct tty *tp;
2544{
2545	tp->t_timeout = -1;
2546	SLIST_INSERT_HEAD(&tty_list, tp, t_list);
2547}
2548
2549static int
2550sysctl_kern_ttys(SYSCTL_HANDLER_ARGS)
2551{
2552	int error;
2553	struct tty *tp, t;
2554	SLIST_FOREACH(tp, &tty_list, t_list) {
2555		t = *tp;
2556		if (t.t_dev)
2557			t.t_dev = (dev_t)dev2udev(t.t_dev);
2558		error = SYSCTL_OUT(req, (caddr_t)&t, sizeof(t));
2559		if (error)
2560			return (error);
2561	}
2562	return (0);
2563}
2564
2565SYSCTL_PROC(_kern, OID_AUTO, ttys, CTLTYPE_OPAQUE|CTLFLAG_RD,
2566	0, 0, sysctl_kern_ttys, "S,tty", "All struct ttys");
2567
2568void
2569nottystop(tp, rw)
2570	struct tty *tp;
2571	int rw;
2572{
2573
2574	return;
2575}
2576
2577int
2578ttyread(dev, uio, flag)
2579	dev_t dev;
2580	struct uio *uio;
2581	int flag;
2582{
2583	struct tty *tp;
2584
2585	tp = dev->si_tty;
2586	if (tp == NULL)
2587		return (ENODEV);
2588	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
2589}
2590
2591int
2592ttywrite(dev, uio, flag)
2593	dev_t dev;
2594	struct uio *uio;
2595	int flag;
2596{
2597	struct tty *tp;
2598
2599	tp = dev->si_tty;
2600	if (tp == NULL)
2601		return (ENODEV);
2602	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
2603}
2604