xref: /csrg-svn/sys/kern/tty.c (revision 68171)
149594Sbostic /*-
263178Sbostic  * Copyright (c) 1982, 1986, 1990, 1991, 1993
363178Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923387Smckusick  *
1049594Sbostic  * %sccs.include.redist.c%
1149594Sbostic  *
12*68171Scgd  *	@(#)tty.c	8.13 (Berkeley) 01/09/95
1323387Smckusick  */
1439Sbill 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/ioctl.h>
1856517Sbostic #include <sys/proc.h>
1964416Sbostic #define	TTYDEFCHARS
2056517Sbostic #include <sys/tty.h>
2164416Sbostic #undef	TTYDEFCHARS
2256517Sbostic #include <sys/file.h>
2356517Sbostic #include <sys/conf.h>
2456517Sbostic #include <sys/dkstat.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/kernel.h>
2756517Sbostic #include <sys/vnode.h>
2856517Sbostic #include <sys/syslog.h>
2939Sbill 
3056517Sbostic #include <vm/vm.h>
3137525Smckusick 
3264416Sbostic static int	proc_compare __P((struct proc *p1, struct proc *p2));
3364416Sbostic static int	ttnread __P((struct tty *));
3464416Sbostic static void	ttyblock __P((struct tty *tp));
3564416Sbostic static void	ttyecho __P((int, struct tty *tp));
3664416Sbostic static void	ttyrubo __P((struct tty *, int));
3749907Sbostic 
3864416Sbostic /* Symbolic sleep message strings. */
3964416Sbostic char ttclos[]	= "ttycls";
4064416Sbostic char ttopen[]	= "ttyopn";
4164416Sbostic char ttybg[]	= "ttybg";
4264416Sbostic char ttybuf[]	= "ttybuf";
4364416Sbostic char ttyin[]	= "ttyin";
4464416Sbostic char ttyout[]	= "ttyout";
4540712Skarels 
467436Skre /*
4764416Sbostic  * Table with character classes and parity. The 8th bit indicates parity,
4864416Sbostic  * the 7th bit indicates the character is an alphameric or underscore (for
4964416Sbostic  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
5064416Sbostic  * are 0 then the character needs no special processing on output; classes
5164416Sbostic  * other than 0 might be translated or (not currently) require delays.
527436Skre  */
5364416Sbostic #define	E	0x00	/* Even parity. */
5464416Sbostic #define	O	0x80	/* Odd parity. */
5564416Sbostic #define	PARITY(c)	(char_type[c] & O)
5664416Sbostic 
5764416Sbostic #define	ALPHA	0x40	/* Alpha or underscore. */
5864416Sbostic #define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
5964416Sbostic 
6049380Skarels #define	CCLASSMASK	0x3f
6164416Sbostic #define	CCLASS(c)	(char_type[c] & CCLASSMASK)
6239Sbill 
6364416Sbostic #define	BS	BACKSPACE
6449380Skarels #define	CC	CONTROL
6564416Sbostic #define	CR	RETURN
6664416Sbostic #define	NA	ORDINARY | ALPHA
6749380Skarels #define	NL	NEWLINE
6864416Sbostic #define	NO	ORDINARY
6949380Skarels #define	TB	TAB
7049380Skarels #define	VT	VTAB
7149380Skarels 
7264416Sbostic char const char_type[] = {
7349380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
7449380Skarels 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
7549380Skarels 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
7649380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
7749380Skarels 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7849380Skarels 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7949380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
8049380Skarels 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
8149380Skarels 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
8249380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
8349380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
8449380Skarels 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
8549380Skarels 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
8649380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
8749380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8849380Skarels 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
897436Skre 	/*
9064416Sbostic 	 * Meta chars; should be settable per character set;
9164416Sbostic 	 * for now, treat them all as normal characters.
927436Skre 	 */
9349380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9449380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9549380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9649380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9749380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9849380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9949380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10049380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10149380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10249380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10349380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10449380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10549380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10649380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10749380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10849380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
1097436Skre };
11064416Sbostic #undef	BS
11164416Sbostic #undef	CC
11264416Sbostic #undef	CR
11349380Skarels #undef	NA
11449380Skarels #undef	NL
11564416Sbostic #undef	NO
11649380Skarels #undef	TB
11749380Skarels #undef	VT
1187436Skre 
11964416Sbostic /* Macros to clear/set/test flags. */
12064416Sbostic #define	SET(t, f)	(t) |= (f)
12164416Sbostic #define	CLR(t, f)	(t) &= ~(f)
12264416Sbostic #define	ISSET(t, f)	((t) & (f))
12335811Smarc 
124146Sbill /*
12564416Sbostic  * Initial open of tty, or (re)entry to standard tty line discipline.
12639Sbill  */
12764416Sbostic int
ttyopen(device,tp)12864416Sbostic ttyopen(device, tp)
12964416Sbostic 	dev_t device;
13012752Ssam 	register struct tty *tp;
13112752Ssam {
13252485Storek 	int s;
13347545Skarels 
13452485Storek 	s = spltty();
13564416Sbostic 	tp->t_dev = device;
13664416Sbostic 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
13764416Sbostic 		SET(tp->t_state, TS_ISOPEN);
13864416Sbostic 		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
139903Sbill 	}
14064416Sbostic 	CLR(tp->t_state, TS_WOPEN);
1415408Swnj 	splx(s);
1425408Swnj 	return (0);
1434484Swnj }
1447436Skre 
1457502Sroot /*
14649380Skarels  * Handle close() on a tty line: flush and set to initial state,
14749380Skarels  * bumping generation number so that pending read/write calls
14849380Skarels  * can detect recycling of the tty.
1497502Sroot  */
15064416Sbostic int
ttyclose(tp)1517502Sroot ttyclose(tp)
1527625Ssam 	register struct tty *tp;
1537502Sroot {
15464416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
15564416Sbostic 
15630534Skarels 	if (constty == tp)
15730534Skarels 		constty = NULL;
15864416Sbostic 
15964416Sbostic 	ttyflush(tp, FREAD | FWRITE);
16064416Sbostic 
16164416Sbostic 	tp->t_gen++;
16264416Sbostic 	tp->t_pgrp = NULL;
16339555Smarc 	tp->t_session = NULL;
1647502Sroot 	tp->t_state = 0;
16540712Skarels 	return (0);
1667502Sroot }
1677502Sroot 
16864416Sbostic #define	FLUSHQ(q) {							\
16964416Sbostic 	if ((q)->c_cc)							\
17064416Sbostic 		ndflush(q, (q)->c_cc);					\
17125391Skarels }
17225391Skarels 
17364416Sbostic /* Is 'c' a line delimiter ("break" character)? */
17464416Sbostic #define	TTBREAKC(c)							\
17564416Sbostic 	((c) == '\n' || ((c) == cc[VEOF] ||				\
17664416Sbostic 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
17725404Skarels 
1787502Sroot 
1797502Sroot /*
18049380Skarels  * Process input of a single character received on a tty.
1817502Sroot  */
18264416Sbostic int
ttyinput(c,tp)1837502Sroot ttyinput(c, tp)
18464416Sbostic 	register int c;
1857625Ssam 	register struct tty *tp;
1867502Sroot {
18764416Sbostic 	register int iflag, lflag;
18864416Sbostic 	register u_char *cc;
18935811Smarc 	int i, err;
1907502Sroot 
1919578Ssam 	/*
1929578Ssam 	 * If input is pending take it first.
1939578Ssam 	 */
19464416Sbostic 	lflag = tp->t_lflag;
19564416Sbostic 	if (ISSET(lflag, PENDIN))
1967502Sroot 		ttypend(tp);
19735811Smarc 	/*
19835811Smarc 	 * Gather stats.
19935811Smarc 	 */
20064416Sbostic 	if (ISSET(lflag, ICANON)) {
20164416Sbostic 		++tk_cancc;
20264416Sbostic 		++tp->t_cancc;
20335811Smarc 	} else {
20464416Sbostic 		++tk_rawcc;
20564416Sbostic 		++tp->t_rawcc;
20635811Smarc 	}
20764416Sbostic 	++tk_nin;
20864416Sbostic 
20964416Sbostic 	/* Handle exceptional conditions (break, parity, framing). */
21064416Sbostic 	cc = tp->t_cc;
21164416Sbostic 	iflag = tp->t_iflag;
21264576Sbostic 	if (err = (ISSET(c, TTY_ERRORMASK))) {
21364576Sbostic 		CLR(c, TTY_ERRORMASK);
21464576Sbostic 		if (ISSET(err, TTY_FE) && !c) {	/* Break. */
21564416Sbostic 			if (ISSET(iflag, IGNBRK))
21635811Smarc 				goto endcase;
21764416Sbostic 			else if (ISSET(iflag, BRKINT) &&
21864416Sbostic 			    ISSET(lflag, ISIG) &&
21964416Sbostic 			    (cc[VINTR] != _POSIX_VDISABLE))
22035811Smarc 				c = cc[VINTR];
22164416Sbostic 			else if (ISSET(iflag, PARMRK))
22247545Skarels 				goto parmrk;
22364576Sbostic 		} else if (ISSET(err, TTY_PE) &&
22464576Sbostic 		    ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) {
22564416Sbostic 			if (ISSET(iflag, IGNPAR))
22635811Smarc 				goto endcase;
22764416Sbostic 			else if (ISSET(iflag, PARMRK)) {
22864576Sbostic parmrk:				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
22964576Sbostic 				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
23064576Sbostic 				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
23135811Smarc 				goto endcase;
23235811Smarc 			} else
23335811Smarc 				c = 0;
2347502Sroot 		}
2359578Ssam 	}
2369578Ssam 	/*
23735811Smarc 	 * In tandem mode, check high water mark.
2389578Ssam 	 */
23964416Sbostic 	if (ISSET(iflag, IXOFF))
24035811Smarc 		ttyblock(tp);
24164416Sbostic 	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
24264576Sbostic 		CLR(c, 0x80);
24364416Sbostic 	if (!ISSET(lflag, EXTPROC)) {
24444419Smarc 		/*
24544419Smarc 		 * Check for literal nexting very first
24644419Smarc 		 */
24764416Sbostic 		if (ISSET(tp->t_state, TS_LNCH)) {
24864576Sbostic 			SET(c, TTY_QUOTE);
24964416Sbostic 			CLR(tp->t_state, TS_LNCH);
25044419Smarc 		}
25144419Smarc 		/*
25244419Smarc 		 * Scan for special characters.  This code
25344419Smarc 		 * is really just a big case statement with
25444419Smarc 		 * non-constant cases.  The bottom of the
25544419Smarc 		 * case statement is labeled ``endcase'', so goto
25644419Smarc 		 * it after a case match, or similar.
25744419Smarc 		 */
25844419Smarc 
25944419Smarc 		/*
26044419Smarc 		 * Control chars which aren't controlled
26144419Smarc 		 * by ICANON, ISIG, or IXON.
26244419Smarc 		 */
26364416Sbostic 		if (ISSET(lflag, IEXTEN)) {
26444419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
26564416Sbostic 				if (ISSET(lflag, ECHO)) {
26664416Sbostic 					if (ISSET(lflag, ECHOE)) {
26764416Sbostic 						(void)ttyoutput('^', tp);
26864416Sbostic 						(void)ttyoutput('\b', tp);
26964416Sbostic 					} else
27044419Smarc 						ttyecho(c, tp);
27144419Smarc 				}
27264416Sbostic 				SET(tp->t_state, TS_LNCH);
27344419Smarc 				goto endcase;
27444419Smarc 			}
27544419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
27664416Sbostic 				if (ISSET(lflag, FLUSHO))
27764416Sbostic 					CLR(tp->t_lflag, FLUSHO);
27844419Smarc 				else {
27944419Smarc 					ttyflush(tp, FWRITE);
28035811Smarc 					ttyecho(c, tp);
28144419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
28244419Smarc 						ttyretype(tp);
28364416Sbostic 					SET(tp->t_lflag, FLUSHO);
28444419Smarc 				}
28544419Smarc 				goto startoutput;
28635811Smarc 			}
2879578Ssam 		}
28844419Smarc 		/*
28944419Smarc 		 * Signals.
29044419Smarc 		 */
29164416Sbostic 		if (ISSET(lflag, ISIG)) {
29244419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
29364416Sbostic 				if (!ISSET(lflag, NOFLSH))
29464416Sbostic 					ttyflush(tp, FREAD | FWRITE);
2957502Sroot 				ttyecho(c, tp);
29644419Smarc 				pgsignal(tp->t_pgrp,
29744419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
29844419Smarc 				goto endcase;
2997502Sroot 			}
30044419Smarc 			if (CCEQ(cc[VSUSP], c)) {
30164416Sbostic 				if (!ISSET(lflag, NOFLSH))
30244419Smarc 					ttyflush(tp, FREAD);
30344419Smarc 				ttyecho(c, tp);
30444419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
30544419Smarc 				goto endcase;
30644419Smarc 			}
3079578Ssam 		}
30844419Smarc 		/*
30944419Smarc 		 * Handle start/stop characters.
31044419Smarc 		 */
31164416Sbostic 		if (ISSET(iflag, IXON)) {
31244419Smarc 			if (CCEQ(cc[VSTOP], c)) {
31364416Sbostic 				if (!ISSET(tp->t_state, TS_TTSTOP)) {
31464416Sbostic 					SET(tp->t_state, TS_TTSTOP);
31552485Storek #ifdef sun4c						/* XXX */
31652485Storek 					(*tp->t_stop)(tp, 0);
31752485Storek #else
31844419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
31944419Smarc 					   0);
32052485Storek #endif
32164416Sbostic 					return (0);
32244419Smarc 				}
32344419Smarc 				if (!CCEQ(cc[VSTART], c))
32464416Sbostic 					return (0);
32564416Sbostic 				/*
32664416Sbostic 				 * if VSTART == VSTOP then toggle
32744419Smarc 				 */
32844419Smarc 				goto endcase;
32935811Smarc 			}
33044419Smarc 			if (CCEQ(cc[VSTART], c))
33144419Smarc 				goto restartoutput;
3329578Ssam 		}
33344419Smarc 		/*
33444419Smarc 		 * IGNCR, ICRNL, & INLCR
33544419Smarc 		 */
33644419Smarc 		if (c == '\r') {
33764416Sbostic 			if (ISSET(iflag, IGNCR))
33844419Smarc 				goto endcase;
33964416Sbostic 			else if (ISSET(iflag, ICRNL))
34044419Smarc 				c = '\n';
34164416Sbostic 		} else if (c == '\n' && ISSET(iflag, INLCR))
34244419Smarc 			c = '\r';
3439578Ssam 	}
34464416Sbostic 	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
34544419Smarc 		/*
34644419Smarc 		 * From here on down canonical mode character
34744419Smarc 		 * processing takes place.
34844419Smarc 		 */
34944419Smarc 		/*
35044419Smarc 		 * erase (^H / ^?)
35144419Smarc 		 */
35244419Smarc 		if (CCEQ(cc[VERASE], c)) {
35344419Smarc 			if (tp->t_rawq.c_cc)
3549578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
35544419Smarc 			goto endcase;
3569578Ssam 		}
35744419Smarc 		/*
35844419Smarc 		 * kill (^U)
35944419Smarc 		 */
36044419Smarc 		if (CCEQ(cc[VKILL], c)) {
36164416Sbostic 			if (ISSET(lflag, ECHOKE) &&
36264416Sbostic 			    tp->t_rawq.c_cc == tp->t_rocount &&
36364416Sbostic 			    !ISSET(lflag, ECHOPRT))
36444419Smarc 				while (tp->t_rawq.c_cc)
36544419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
36664416Sbostic 			else {
36744419Smarc 				ttyecho(c, tp);
36864416Sbostic 				if (ISSET(lflag, ECHOK) ||
36964416Sbostic 				    ISSET(lflag, ECHOKE))
37044419Smarc 					ttyecho('\n', tp);
37164416Sbostic 				FLUSHQ(&tp->t_rawq);
37244419Smarc 				tp->t_rocount = 0;
37344419Smarc 			}
37464416Sbostic 			CLR(tp->t_state, TS_LOCAL);
37544419Smarc 			goto endcase;
37644419Smarc 		}
37744419Smarc 		/*
37844419Smarc 		 * word erase (^W)
37944419Smarc 		 */
38064416Sbostic 		if (CCEQ(cc[VWERASE], c)) {
38164416Sbostic 			int alt = ISSET(lflag, ALTWERASE);
38244419Smarc 			int ctype;
38335811Smarc 
38464416Sbostic 			/*
38564416Sbostic 			 * erase whitespace
38644419Smarc 			 */
38744419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
38844419Smarc 				ttyrub(c, tp);
38944419Smarc 			if (c == -1)
39044419Smarc 				goto endcase;
39144419Smarc 			/*
39247545Skarels 			 * erase last char of word and remember the
39347545Skarels 			 * next chars type (for ALTWERASE)
39444419Smarc 			 */
39535811Smarc 			ttyrub(c, tp);
39644419Smarc 			c = unputc(&tp->t_rawq);
39747545Skarels 			if (c == -1)
39844419Smarc 				goto endcase;
39951003Sbostic 			if (c == ' ' || c == '\t') {
40064576Sbostic 				(void)putc(c, &tp->t_rawq);
40151003Sbostic 				goto endcase;
40251003Sbostic 			}
40349380Skarels 			ctype = ISALPHA(c);
40444419Smarc 			/*
40547545Skarels 			 * erase rest of word
40644419Smarc 			 */
40744419Smarc 			do {
40844419Smarc 				ttyrub(c, tp);
40944419Smarc 				c = unputc(&tp->t_rawq);
41044419Smarc 				if (c == -1)
41144419Smarc 					goto endcase;
41264416Sbostic 			} while (c != ' ' && c != '\t' &&
41364416Sbostic 			    (alt == 0 || ISALPHA(c) == ctype));
41464416Sbostic 			(void)putc(c, &tp->t_rawq);
41534492Skarels 			goto endcase;
41644419Smarc 		}
41735811Smarc 		/*
41844419Smarc 		 * reprint line (^R)
41935811Smarc 		 */
42044419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
42144419Smarc 			ttyretype(tp);
42234492Skarels 			goto endcase;
42334492Skarels 		}
42435811Smarc 		/*
42544419Smarc 		 * ^T - kernel info and generate SIGINFO
42635811Smarc 		 */
42744419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
42864416Sbostic 			if (ISSET(lflag, ISIG))
42951068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
43064416Sbostic 			if (!ISSET(lflag, NOKERNINFO))
43144419Smarc 				ttyinfo(tp);
43244419Smarc 			goto endcase;
43344419Smarc 		}
4349578Ssam 	}
4359578Ssam 	/*
4369578Ssam 	 * Check for input buffer overflow
4379578Ssam 	 */
43847545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
43964416Sbostic 		if (ISSET(iflag, IMAXBEL)) {
44035811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
44164416Sbostic 				(void)ttyoutput(CTRL('g'), tp);
44235811Smarc 		} else
44335811Smarc 			ttyflush(tp, FREAD | FWRITE);
4449578Ssam 		goto endcase;
44510391Ssam 	}
4469578Ssam 	/*
4479578Ssam 	 * Put data char in q for user and
4489578Ssam 	 * wakeup on seeing a line delimiter.
4499578Ssam 	 */
4509578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
45164416Sbostic 		if (!ISSET(lflag, ICANON)) {
45247545Skarels 			ttwakeup(tp);
45347545Skarels 			ttyecho(c, tp);
45447545Skarels 			goto endcase;
45547545Skarels 		}
45664416Sbostic 		if (TTBREAKC(c)) {
4579578Ssam 			tp->t_rocount = 0;
4589578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
4597502Sroot 			ttwakeup(tp);
4609578Ssam 		} else if (tp->t_rocount++ == 0)
46164530Sbostic 			tp->t_rocol = tp->t_column;
46264416Sbostic 		if (ISSET(tp->t_state, TS_ERASE)) {
46335811Smarc 			/*
46435811Smarc 			 * end of prterase \.../
46535811Smarc 			 */
46664416Sbostic 			CLR(tp->t_state, TS_ERASE);
46764416Sbostic 			(void)ttyoutput('/', tp);
4689578Ssam 		}
46964530Sbostic 		i = tp->t_column;
4707502Sroot 		ttyecho(c, tp);
47164416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
47235811Smarc 			/*
47335811Smarc 			 * Place the cursor over the '^' of the ^D.
47435811Smarc 			 */
47564530Sbostic 			i = min(2, tp->t_column - i);
4769578Ssam 			while (i > 0) {
47764416Sbostic 				(void)ttyoutput('\b', tp);
4789578Ssam 				i--;
4799578Ssam 			}
4809578Ssam 		}
4817502Sroot 	}
4829578Ssam endcase:
4839578Ssam 	/*
48435811Smarc 	 * IXANY means allow any character to restart output.
4859578Ssam 	 */
48664416Sbostic 	if (ISSET(tp->t_state, TS_TTSTOP) &&
48764416Sbostic 	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
48864416Sbostic 		return (0);
4899578Ssam restartoutput:
49064416Sbostic 	CLR(tp->t_lflag, FLUSHO);
49164416Sbostic 	CLR(tp->t_state, TS_TTSTOP);
4929578Ssam startoutput:
49364416Sbostic 	return (ttstart(tp));
4947502Sroot }
4957502Sroot 
4967502Sroot /*
49749380Skarels  * Output a single character on a tty, doing output processing
49849380Skarels  * as needed (expanding tabs, newline processing, etc.).
49964416Sbostic  * Returns < 0 if succeeds, otherwise returns char to resend.
5007502Sroot  * Must be recursive.
5017502Sroot  */
50264416Sbostic int
ttyoutput(c,tp)5037502Sroot ttyoutput(c, tp)
50464416Sbostic 	register int c;
5057502Sroot 	register struct tty *tp;
5067502Sroot {
50764416Sbostic 	register long oflag;
50867115Smckusick 	register int notout, col, s;
50964416Sbostic 
51064416Sbostic 	oflag = tp->t_oflag;
51164416Sbostic 	if (!ISSET(oflag, OPOST)) {
51264416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO))
5137502Sroot 			return (-1);
5147502Sroot 		if (putc(c, &tp->t_outq))
5157625Ssam 			return (c);
5167502Sroot 		tk_nout++;
51735811Smarc 		tp->t_outcc++;
5187502Sroot 		return (-1);
5197502Sroot 	}
5207502Sroot 	/*
52164416Sbostic 	 * Do tab expansion if OXTABS is set.  Special case if we external
52264416Sbostic 	 * processing, we don't do the tab expansion because we'll probably
52364416Sbostic 	 * get it wrong.  If tab expansion needs to be done, let it happen
52464416Sbostic 	 * externally.
5257502Sroot 	 */
52664576Sbostic 	CLR(c, ~TTY_CHARMASK);
52764416Sbostic 	if (c == '\t' &&
52864416Sbostic 	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
52964530Sbostic 		c = 8 - (tp->t_column & 7);
53067115Smckusick 		if (ISSET(tp->t_lflag, FLUSHO)) {
53167115Smckusick 			notout = 0;
53267115Smckusick 		} else {
53364416Sbostic 			s = spltty();		/* Don't interrupt tabs. */
53467115Smckusick 			notout = b_to_q("        ", c, &tp->t_outq);
53567115Smckusick 			c -= notout;
5367502Sroot 			tk_nout += c;
53735811Smarc 			tp->t_outcc += c;
5387502Sroot 			splx(s);
5397502Sroot 		}
54064530Sbostic 		tp->t_column += c;
54167115Smckusick 		return (notout ? '\t' : -1);
5427502Sroot 	}
54364416Sbostic 	if (c == CEOT && ISSET(oflag, ONOEOT))
54447545Skarels 		return (-1);
54564576Sbostic 
5467502Sroot 	/*
54749380Skarels 	 * Newline translation: if ONLCR is set,
54849380Skarels 	 * translate newline into "\r\n".
5497502Sroot 	 */
55064576Sbostic 	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
55164576Sbostic 		tk_nout++;
55264576Sbostic 		tp->t_outcc++;
55364576Sbostic 		if (putc('\r', &tp->t_outq))
55464576Sbostic 			return (c);
55564576Sbostic 	}
55664576Sbostic 	tk_nout++;
55764576Sbostic 	tp->t_outcc++;
55864416Sbostic 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
55935811Smarc 		return (c);
56047545Skarels 
56164530Sbostic 	col = tp->t_column;
56249380Skarels 	switch (CCLASS(c)) {
5637502Sroot 	case BACKSPACE:
56449380Skarels 		if (col > 0)
56564416Sbostic 			--col;
5667502Sroot 		break;
56764416Sbostic 	case CONTROL:
56864416Sbostic 		break;
5697502Sroot 	case NEWLINE:
57064416Sbostic 	case RETURN:
57149380Skarels 		col = 0;
5727502Sroot 		break;
57364416Sbostic 	case ORDINARY:
57464416Sbostic 		++col;
57564416Sbostic 		break;
5767502Sroot 	case TAB:
57764416Sbostic 		col = (col + 8) & ~7;
5787502Sroot 		break;
5797502Sroot 	}
58064530Sbostic 	tp->t_column = col;
5817502Sroot 	return (-1);
5827502Sroot }
5837502Sroot 
5847502Sroot /*
58564576Sbostic  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
58664576Sbostic  * has been called to do discipline-specific functions and/or reject any
58764576Sbostic  * of these ioctl commands.
58864416Sbostic  */
58964416Sbostic /* ARGSUSED */
59064416Sbostic int
ttioctl(tp,cmd,data,flag)59164576Sbostic ttioctl(tp, cmd, data, flag)
59264416Sbostic 	register struct tty *tp;
593*68171Scgd 	u_long cmd;
59464416Sbostic 	void *data;
595*68171Scgd 	int flag;
59664416Sbostic {
59764416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
59864576Sbostic 	extern int nlinesw;
59964416Sbostic 	register struct proc *p;
60064416Sbostic 	int s, error;
60164416Sbostic 
60264416Sbostic 	p = curproc;			/* XXX */
60364416Sbostic 
60464416Sbostic 	/* If the ioctl involves modification, hang if in the background. */
60564576Sbostic 	switch (cmd) {
60664416Sbostic 	case  TIOCFLUSH:
60764416Sbostic 	case  TIOCSETA:
60864416Sbostic 	case  TIOCSETD:
60964416Sbostic 	case  TIOCSETAF:
61064416Sbostic 	case  TIOCSETAW:
61164416Sbostic #ifdef notdef
61264416Sbostic 	case  TIOCSPGRP:
61364416Sbostic #endif
61464416Sbostic 	case  TIOCSTI:
61564416Sbostic 	case  TIOCSWINSZ:
61664416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
61764416Sbostic 	case  TIOCLBIC:
61864416Sbostic 	case  TIOCLBIS:
61964416Sbostic 	case  TIOCLSET:
62064416Sbostic 	case  TIOCSETC:
62164416Sbostic 	case OTIOCSETD:
62264416Sbostic 	case  TIOCSETN:
62364416Sbostic 	case  TIOCSETP:
62464416Sbostic 	case  TIOCSLTC:
62564416Sbostic #endif
62664416Sbostic 		while (isbackground(curproc, tp) &&
62764576Sbostic 		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
62864416Sbostic 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
62964416Sbostic 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
63064416Sbostic 			pgsignal(p->p_pgrp, SIGTTOU, 1);
63164416Sbostic 			if (error = ttysleep(tp,
63264416Sbostic 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
63364416Sbostic 				return (error);
63464416Sbostic 		}
63564416Sbostic 		break;
63664416Sbostic 	}
63764416Sbostic 
63864576Sbostic 	switch (cmd) {			/* Process the ioctl. */
63964416Sbostic 	case FIOASYNC:			/* set/clear async i/o */
64064416Sbostic 		s = spltty();
64164416Sbostic 		if (*(int *)data)
64264416Sbostic 			SET(tp->t_state, TS_ASYNC);
64364416Sbostic 		else
64464416Sbostic 			CLR(tp->t_state, TS_ASYNC);
64564416Sbostic 		splx(s);
64664416Sbostic 		break;
64764416Sbostic 	case FIONBIO:			/* set/clear non-blocking i/o */
64864416Sbostic 		break;			/* XXX: delete. */
64964416Sbostic 	case FIONREAD:			/* get # bytes to read */
65064416Sbostic 		*(int *)data = ttnread(tp);
65164416Sbostic 		break;
65264416Sbostic 	case TIOCEXCL:			/* set exclusive use of tty */
65364416Sbostic 		s = spltty();
65464416Sbostic 		SET(tp->t_state, TS_XCLUDE);
65564416Sbostic 		splx(s);
65664416Sbostic 		break;
65764416Sbostic 	case TIOCFLUSH: {		/* flush buffers */
65864416Sbostic 		register int flags = *(int *)data;
65964416Sbostic 
66064416Sbostic 		if (flags == 0)
66164416Sbostic 			flags = FREAD | FWRITE;
66264416Sbostic 		else
66364416Sbostic 			flags &= FREAD | FWRITE;
66464416Sbostic 		ttyflush(tp, flags);
66564416Sbostic 		break;
66664416Sbostic 	}
66764416Sbostic 	case TIOCCONS:			/* become virtual console */
66864416Sbostic 		if (*(int *)data) {
66964416Sbostic 			if (constty && constty != tp &&
67064416Sbostic 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
67164416Sbostic 			    (TS_CARR_ON | TS_ISOPEN))
67264416Sbostic 				return (EBUSY);
67364416Sbostic #ifndef	UCONSOLE
67464416Sbostic 			if (error = suser(p->p_ucred, &p->p_acflag))
67564416Sbostic 				return (error);
67664416Sbostic #endif
67764416Sbostic 			constty = tp;
67864416Sbostic 		} else if (tp == constty)
67964416Sbostic 			constty = NULL;
68064416Sbostic 		break;
68164416Sbostic 	case TIOCDRAIN:			/* wait till output drained */
68264416Sbostic 		if (error = ttywait(tp))
68364416Sbostic 			return (error);
68464416Sbostic 		break;
68564416Sbostic 	case TIOCGETA: {		/* get termios struct */
68664416Sbostic 		struct termios *t = (struct termios *)data;
68764416Sbostic 
68864416Sbostic 		bcopy(&tp->t_termios, t, sizeof(struct termios));
68964416Sbostic 		break;
69064416Sbostic 	}
69164416Sbostic 	case TIOCGETD:			/* get line discipline */
69264416Sbostic 		*(int *)data = tp->t_line;
69364416Sbostic 		break;
69464416Sbostic 	case TIOCGWINSZ:		/* get window size */
69564416Sbostic 		*(struct winsize *)data = tp->t_winsize;
69664416Sbostic 		break;
69764416Sbostic 	case TIOCGPGRP:			/* get pgrp of tty */
69864416Sbostic 		if (!isctty(p, tp))
69964416Sbostic 			return (ENOTTY);
70064416Sbostic 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
70164416Sbostic 		break;
70264416Sbostic #ifdef TIOCHPCL
70364416Sbostic 	case TIOCHPCL:			/* hang up on last close */
70464416Sbostic 		s = spltty();
70564576Sbostic 		SET(tp->t_cflag, HUPCL);
70664416Sbostic 		splx(s);
70764416Sbostic 		break;
70864416Sbostic #endif
70964416Sbostic 	case TIOCNXCL:			/* reset exclusive use of tty */
71064416Sbostic 		s = spltty();
71164416Sbostic 		CLR(tp->t_state, TS_XCLUDE);
71264416Sbostic 		splx(s);
71364416Sbostic 		break;
71464416Sbostic 	case TIOCOUTQ:			/* output queue size */
71564416Sbostic 		*(int *)data = tp->t_outq.c_cc;
71664416Sbostic 		break;
71764416Sbostic 	case TIOCSETA:			/* set termios struct */
71864416Sbostic 	case TIOCSETAW:			/* drain output, set */
71964416Sbostic 	case TIOCSETAF: {		/* drn out, fls in, set */
72064416Sbostic 		register struct termios *t = (struct termios *)data;
72164416Sbostic 
72264416Sbostic 		s = spltty();
72364576Sbostic 		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
72464416Sbostic 			if (error = ttywait(tp)) {
72564416Sbostic 				splx(s);
72664416Sbostic 				return (error);
72764416Sbostic 			}
72864576Sbostic 			if (cmd == TIOCSETAF)
72964416Sbostic 				ttyflush(tp, FREAD);
73064416Sbostic 		}
73164416Sbostic 		if (!ISSET(t->c_cflag, CIGNORE)) {
73264416Sbostic 			/*
73364416Sbostic 			 * Set device hardware.
73464416Sbostic 			 */
73564416Sbostic 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
73664416Sbostic 				splx(s);
73764416Sbostic 				return (error);
73864416Sbostic 			} else {
73964416Sbostic 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
74064416Sbostic 				    ISSET(tp->t_cflag, CLOCAL) &&
74164416Sbostic 				    !ISSET(t->c_cflag, CLOCAL)) {
74264416Sbostic 					CLR(tp->t_state, TS_ISOPEN);
74364416Sbostic 					SET(tp->t_state, TS_WOPEN);
74464416Sbostic 					ttwakeup(tp);
74564416Sbostic 				}
74664416Sbostic 				tp->t_cflag = t->c_cflag;
74764416Sbostic 				tp->t_ispeed = t->c_ispeed;
74864416Sbostic 				tp->t_ospeed = t->c_ospeed;
74964416Sbostic 			}
75064416Sbostic 			ttsetwater(tp);
75164416Sbostic 		}
75264576Sbostic 		if (cmd != TIOCSETAF) {
75364416Sbostic 			if (ISSET(t->c_lflag, ICANON) !=
75464416Sbostic 			    ISSET(tp->t_lflag, ICANON))
75564416Sbostic 				if (ISSET(t->c_lflag, ICANON)) {
75664576Sbostic 					SET(tp->t_lflag, PENDIN);
75764416Sbostic 					ttwakeup(tp);
75864416Sbostic 				} else {
75964416Sbostic 					struct clist tq;
76064416Sbostic 
76164416Sbostic 					catq(&tp->t_rawq, &tp->t_canq);
76264416Sbostic 					tq = tp->t_rawq;
76364416Sbostic 					tp->t_rawq = tp->t_canq;
76464416Sbostic 					tp->t_canq = tq;
76565324Sbostic 					CLR(tp->t_lflag, PENDIN);
76664416Sbostic 				}
76764416Sbostic 		}
76864416Sbostic 		tp->t_iflag = t->c_iflag;
76964416Sbostic 		tp->t_oflag = t->c_oflag;
77064416Sbostic 		/*
77164416Sbostic 		 * Make the EXTPROC bit read only.
77264416Sbostic 		 */
77364416Sbostic 		if (ISSET(tp->t_lflag, EXTPROC))
77464416Sbostic 			SET(t->c_lflag, EXTPROC);
77564416Sbostic 		else
77664416Sbostic 			CLR(t->c_lflag, EXTPROC);
77765324Sbostic 		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
77864416Sbostic 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
77964416Sbostic 		splx(s);
78064416Sbostic 		break;
78164416Sbostic 	}
78264416Sbostic 	case TIOCSETD: {		/* set line discipline */
78364416Sbostic 		register int t = *(int *)data;
78464416Sbostic 		dev_t device = tp->t_dev;
78564416Sbostic 
78664576Sbostic 		if ((u_int)t >= nlinesw)
78764416Sbostic 			return (ENXIO);
78864416Sbostic 		if (t != tp->t_line) {
78964416Sbostic 			s = spltty();
79064416Sbostic 			(*linesw[tp->t_line].l_close)(tp, flag);
79164416Sbostic 			error = (*linesw[t].l_open)(device, tp);
79264416Sbostic 			if (error) {
79364416Sbostic 				(void)(*linesw[tp->t_line].l_open)(device, tp);
79464416Sbostic 				splx(s);
79564416Sbostic 				return (error);
79664416Sbostic 			}
79764416Sbostic 			tp->t_line = t;
79864416Sbostic 			splx(s);
79964416Sbostic 		}
80064416Sbostic 		break;
80164416Sbostic 	}
80264416Sbostic 	case TIOCSTART:			/* start output, like ^Q */
80364416Sbostic 		s = spltty();
80464416Sbostic 		if (ISSET(tp->t_state, TS_TTSTOP) ||
80564416Sbostic 		    ISSET(tp->t_lflag, FLUSHO)) {
80664416Sbostic 			CLR(tp->t_lflag, FLUSHO);
80764416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
80864416Sbostic 			ttstart(tp);
80964416Sbostic 		}
81064416Sbostic 		splx(s);
81164416Sbostic 		break;
81264416Sbostic 	case TIOCSTI:			/* simulate terminal input */
81364416Sbostic 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
81464416Sbostic 			return (EPERM);
81564416Sbostic 		if (p->p_ucred->cr_uid && !isctty(p, tp))
81664416Sbostic 			return (EACCES);
81764416Sbostic 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
81864416Sbostic 		break;
81964416Sbostic 	case TIOCSTOP:			/* stop output, like ^S */
82064416Sbostic 		s = spltty();
82164416Sbostic 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
82264416Sbostic 			SET(tp->t_state, TS_TTSTOP);
82364416Sbostic #ifdef sun4c				/* XXX */
82464416Sbostic 			(*tp->t_stop)(tp, 0);
82564416Sbostic #else
82664416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
82764416Sbostic #endif
82864416Sbostic 		}
82964416Sbostic 		splx(s);
83064416Sbostic 		break;
83164416Sbostic 	case TIOCSCTTY:			/* become controlling tty */
83264416Sbostic 		/* Session ctty vnode pointer set in vnode layer. */
83364416Sbostic 		if (!SESS_LEADER(p) ||
83467685Smckusick 		    (p->p_session->s_ttyvp || tp->t_session) &&
83567685Smckusick 		    (tp->t_session != p->p_session))
83664416Sbostic 			return (EPERM);
83764416Sbostic 		tp->t_session = p->p_session;
83864416Sbostic 		tp->t_pgrp = p->p_pgrp;
83964416Sbostic 		p->p_session->s_ttyp = tp;
84064576Sbostic 		p->p_flag |= P_CONTROLT;
84164416Sbostic 		break;
84264416Sbostic 	case TIOCSPGRP: {		/* set pgrp of tty */
84364416Sbostic 		register struct pgrp *pgrp = pgfind(*(int *)data);
84464416Sbostic 
84564416Sbostic 		if (!isctty(p, tp))
84664416Sbostic 			return (ENOTTY);
84764416Sbostic 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
84864416Sbostic 			return (EPERM);
84964416Sbostic 		tp->t_pgrp = pgrp;
85064416Sbostic 		break;
85164416Sbostic 	}
85264416Sbostic 	case TIOCSWINSZ:		/* set window size */
85364416Sbostic 		if (bcmp((caddr_t)&tp->t_winsize, data,
85464416Sbostic 		    sizeof (struct winsize))) {
85564416Sbostic 			tp->t_winsize = *(struct winsize *)data;
85664416Sbostic 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
85764416Sbostic 		}
85864416Sbostic 		break;
85964416Sbostic 	default:
86064416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
86164576Sbostic 		return (ttcompat(tp, cmd, data, flag));
86264416Sbostic #else
86364416Sbostic 		return (-1);
86464416Sbostic #endif
86564416Sbostic 	}
86664416Sbostic 	return (0);
86764416Sbostic }
86864416Sbostic 
86964416Sbostic int
ttselect(device,rw,p)87064416Sbostic ttselect(device, rw, p)
87164416Sbostic 	dev_t device;
87264416Sbostic 	int rw;
87364416Sbostic 	struct proc *p;
87464416Sbostic {
87564416Sbostic 	register struct tty *tp;
87664416Sbostic 	int nread, s;
87764416Sbostic 
87864416Sbostic 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
87964416Sbostic 
88064416Sbostic 	s = spltty();
88164416Sbostic 	switch (rw) {
88264416Sbostic 	case FREAD:
88364416Sbostic 		nread = ttnread(tp);
88464416Sbostic 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
88564416Sbostic 		    !ISSET(tp->t_state, TS_CARR_ON))
88664416Sbostic 			goto win;
88764416Sbostic 		selrecord(p, &tp->t_rsel);
88864416Sbostic 		break;
88964416Sbostic 	case FWRITE:
89064416Sbostic 		if (tp->t_outq.c_cc <= tp->t_lowat) {
89164416Sbostic win:			splx(s);
89264416Sbostic 			return (1);
89364416Sbostic 		}
89464416Sbostic 		selrecord(p, &tp->t_wsel);
89564416Sbostic 		break;
89664416Sbostic 	}
89764416Sbostic 	splx(s);
89864416Sbostic 	return (0);
89964416Sbostic }
90064416Sbostic 
90164416Sbostic static int
ttnread(tp)90264416Sbostic ttnread(tp)
90364416Sbostic 	struct tty *tp;
90464416Sbostic {
90564416Sbostic 	int nread;
90664416Sbostic 
90764416Sbostic 	if (ISSET(tp->t_lflag, PENDIN))
90864416Sbostic 		ttypend(tp);
90964416Sbostic 	nread = tp->t_canq.c_cc;
91064416Sbostic 	if (!ISSET(tp->t_lflag, ICANON))
91164416Sbostic 		nread += tp->t_rawq.c_cc;
91264416Sbostic 	return (nread);
91364416Sbostic }
91464416Sbostic 
91564416Sbostic /*
91664416Sbostic  * Wait for output to drain.
91764416Sbostic  */
91864416Sbostic int
ttywait(tp)91964416Sbostic ttywait(tp)
92064416Sbostic 	register struct tty *tp;
92164416Sbostic {
92264416Sbostic 	int error, s;
92364416Sbostic 
92464416Sbostic 	error = 0;
92564416Sbostic 	s = spltty();
92664416Sbostic 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
92764416Sbostic 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
92864416Sbostic 	    && tp->t_oproc) {
92964416Sbostic 		(*tp->t_oproc)(tp);
93064416Sbostic 		SET(tp->t_state, TS_ASLEEP);
93164416Sbostic 		if (error = ttysleep(tp,
93264416Sbostic 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
93364416Sbostic 			break;
93464416Sbostic 	}
93564416Sbostic 	splx(s);
93664416Sbostic 	return (error);
93764416Sbostic }
93864416Sbostic 
93964416Sbostic /*
94064416Sbostic  * Flush if successfully wait.
94164416Sbostic  */
94264416Sbostic int
ttywflush(tp)94364416Sbostic ttywflush(tp)
94464416Sbostic 	struct tty *tp;
94564416Sbostic {
94664416Sbostic 	int error;
94764416Sbostic 
94864416Sbostic 	if ((error = ttywait(tp)) == 0)
94964416Sbostic 		ttyflush(tp, FREAD);
95064416Sbostic 	return (error);
95164416Sbostic }
95264416Sbostic 
95364416Sbostic /*
95464416Sbostic  * Flush tty read and/or write queues, notifying anyone waiting.
95564416Sbostic  */
95664416Sbostic void
ttyflush(tp,rw)95764416Sbostic ttyflush(tp, rw)
95864416Sbostic 	register struct tty *tp;
95964416Sbostic 	int rw;
96064416Sbostic {
96164416Sbostic 	register int s;
96264416Sbostic 
96364416Sbostic 	s = spltty();
96464416Sbostic 	if (rw & FREAD) {
96564416Sbostic 		FLUSHQ(&tp->t_canq);
96664416Sbostic 		FLUSHQ(&tp->t_rawq);
96764416Sbostic 		tp->t_rocount = 0;
96864416Sbostic 		tp->t_rocol = 0;
96964416Sbostic 		CLR(tp->t_state, TS_LOCAL);
97064416Sbostic 		ttwakeup(tp);
97164416Sbostic 	}
97264416Sbostic 	if (rw & FWRITE) {
97364416Sbostic 		CLR(tp->t_state, TS_TTSTOP);
97464416Sbostic #ifdef sun4c						/* XXX */
97564416Sbostic 		(*tp->t_stop)(tp, rw);
97664416Sbostic #else
97764416Sbostic 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
97864416Sbostic #endif
97964416Sbostic 		FLUSHQ(&tp->t_outq);
98064416Sbostic 		wakeup((caddr_t)&tp->t_outq);
98164416Sbostic 		selwakeup(&tp->t_wsel);
98264416Sbostic 	}
98364416Sbostic 	splx(s);
98464416Sbostic }
98564416Sbostic 
98664416Sbostic /*
98764416Sbostic  * Copy in the default termios characters.
98864416Sbostic  */
98964416Sbostic void
ttychars(tp)99064416Sbostic ttychars(tp)
99164416Sbostic 	struct tty *tp;
99264416Sbostic {
99364416Sbostic 
99464416Sbostic 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
99564416Sbostic }
99664416Sbostic 
99764416Sbostic /*
99864416Sbostic  * Send stop character on input overflow.
99964416Sbostic  */
100064416Sbostic static void
ttyblock(tp)100164416Sbostic ttyblock(tp)
100264416Sbostic 	register struct tty *tp;
100364416Sbostic {
100464416Sbostic 	register int total;
100564416Sbostic 
100664416Sbostic 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
100764416Sbostic 	if (tp->t_rawq.c_cc > TTYHOG) {
100864416Sbostic 		ttyflush(tp, FREAD | FWRITE);
100964416Sbostic 		CLR(tp->t_state, TS_TBLOCK);
101064416Sbostic 	}
101164416Sbostic 	/*
101264416Sbostic 	 * Block further input iff: current input > threshold
101364416Sbostic 	 * AND input is available to user program.
101464416Sbostic 	 */
101564416Sbostic 	if (total >= TTYHOG / 2 &&
101664416Sbostic 	    !ISSET(tp->t_state, TS_TBLOCK) &&
101764416Sbostic 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
101864416Sbostic 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
101964416Sbostic 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
102064416Sbostic 			SET(tp->t_state, TS_TBLOCK);
102164416Sbostic 			ttstart(tp);
102264416Sbostic 		}
102364416Sbostic 	}
102464416Sbostic }
102564416Sbostic 
102664416Sbostic void
ttrstrt(tp_arg)102764416Sbostic ttrstrt(tp_arg)
102864416Sbostic 	void *tp_arg;
102964416Sbostic {
103064416Sbostic 	struct tty *tp;
103164416Sbostic 	int s;
103264416Sbostic 
103364416Sbostic #ifdef DIAGNOSTIC
103464416Sbostic 	if (tp_arg == NULL)
103564416Sbostic 		panic("ttrstrt");
103664416Sbostic #endif
103764416Sbostic 	tp = tp_arg;
103864416Sbostic 	s = spltty();
103964416Sbostic 
104064416Sbostic 	CLR(tp->t_state, TS_TIMEOUT);
104164416Sbostic 	ttstart(tp);
104264416Sbostic 
104364416Sbostic 	splx(s);
104464416Sbostic }
104564416Sbostic 
104664416Sbostic int
ttstart(tp)104764416Sbostic ttstart(tp)
104864416Sbostic 	struct tty *tp;
104964416Sbostic {
105064416Sbostic 
105164416Sbostic 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
105264416Sbostic 		(*tp->t_oproc)(tp);
105364416Sbostic 	return (0);
105464416Sbostic }
105564416Sbostic 
105664416Sbostic /*
105764416Sbostic  * "close" a line discipline
105864416Sbostic  */
105964416Sbostic int
ttylclose(tp,flag)106064416Sbostic ttylclose(tp, flag)
106164416Sbostic 	struct tty *tp;
106264416Sbostic 	int flag;
106364416Sbostic {
106464416Sbostic 
106564416Sbostic 	if (flag & IO_NDELAY)
106664416Sbostic 		ttyflush(tp, FREAD | FWRITE);
106764416Sbostic 	else
106864416Sbostic 		ttywflush(tp);
106964416Sbostic 	return (0);
107064416Sbostic }
107164416Sbostic 
107264416Sbostic /*
107364416Sbostic  * Handle modem control transition on a tty.
107464416Sbostic  * Flag indicates new state of carrier.
107564416Sbostic  * Returns 0 if the line should be turned off, otherwise 1.
107664416Sbostic  */
107764416Sbostic int
ttymodem(tp,flag)107864416Sbostic ttymodem(tp, flag)
107964416Sbostic 	register struct tty *tp;
108064416Sbostic 	int flag;
108164416Sbostic {
108264416Sbostic 
108364416Sbostic 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
108464416Sbostic 		/*
108564416Sbostic 		 * MDMBUF: do flow control according to carrier flag
108664416Sbostic 		 */
108764416Sbostic 		if (flag) {
108864416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
108964416Sbostic 			ttstart(tp);
109064416Sbostic 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
109164416Sbostic 			SET(tp->t_state, TS_TTSTOP);
109264416Sbostic #ifdef sun4c						/* XXX */
109364416Sbostic 			(*tp->t_stop)(tp, 0);
109464416Sbostic #else
109564416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
109664416Sbostic #endif
109764416Sbostic 		}
109864416Sbostic 	} else if (flag == 0) {
109964416Sbostic 		/*
110064416Sbostic 		 * Lost carrier.
110164416Sbostic 		 */
110264416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
110364416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN) &&
110464416Sbostic 		    !ISSET(tp->t_cflag, CLOCAL)) {
110564416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
110664416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
110764416Sbostic 			ttyflush(tp, FREAD | FWRITE);
110864416Sbostic 			return (0);
110964416Sbostic 		}
111064416Sbostic 	} else {
111164416Sbostic 		/*
111264416Sbostic 		 * Carrier now on.
111364416Sbostic 		 */
111464416Sbostic 		SET(tp->t_state, TS_CARR_ON);
111564416Sbostic 		ttwakeup(tp);
111664416Sbostic 	}
111764416Sbostic 	return (1);
111864416Sbostic }
111964416Sbostic 
112064416Sbostic /*
112164416Sbostic  * Default modem control routine (for other line disciplines).
112264416Sbostic  * Return argument flag, to turn off device on carrier drop.
112364416Sbostic  */
112464416Sbostic int
nullmodem(tp,flag)112564416Sbostic nullmodem(tp, flag)
112664416Sbostic 	register struct tty *tp;
112764416Sbostic 	int flag;
112864416Sbostic {
112964416Sbostic 
113064416Sbostic 	if (flag)
113164416Sbostic 		SET(tp->t_state, TS_CARR_ON);
113264416Sbostic 	else {
113364416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
113464416Sbostic 		if (!ISSET(tp->t_cflag, CLOCAL)) {
113564416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
113664416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
113764416Sbostic 			return (0);
113864416Sbostic 		}
113964416Sbostic 	}
114064416Sbostic 	return (1);
114164416Sbostic }
114264416Sbostic 
114364416Sbostic /*
114464416Sbostic  * Reinput pending characters after state switch
114564416Sbostic  * call at spltty().
114664416Sbostic  */
114764416Sbostic void
ttypend(tp)114864416Sbostic ttypend(tp)
114964416Sbostic 	register struct tty *tp;
115064416Sbostic {
115164416Sbostic 	struct clist tq;
115264416Sbostic 	register c;
115364416Sbostic 
115464416Sbostic 	CLR(tp->t_lflag, PENDIN);
115564416Sbostic 	SET(tp->t_state, TS_TYPEN);
115664416Sbostic 	tq = tp->t_rawq;
115764416Sbostic 	tp->t_rawq.c_cc = 0;
115864416Sbostic 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
115964416Sbostic 	while ((c = getc(&tq)) >= 0)
116064416Sbostic 		ttyinput(c, tp);
116164416Sbostic 	CLR(tp->t_state, TS_TYPEN);
116264416Sbostic }
116364416Sbostic 
116464416Sbostic /*
116549380Skarels  * Process a read call on a tty device.
11667502Sroot  */
116764416Sbostic int
ttread(tp,uio,flag)116837584Smarc ttread(tp, uio, flag)
11697625Ssam 	register struct tty *tp;
11707722Swnj 	struct uio *uio;
117152485Storek 	int flag;
11727502Sroot {
11737502Sroot 	register struct clist *qp;
117435811Smarc 	register int c;
117541383Smarc 	register long lflag;
117635811Smarc 	register u_char *cc = tp->t_cc;
117747545Skarels 	register struct proc *p = curproc;
11789859Ssam 	int s, first, error = 0;
11797502Sroot 
118064416Sbostic loop:	lflag = tp->t_lflag;
118137584Smarc 	s = spltty();
11829578Ssam 	/*
118364416Sbostic 	 * take pending input first
11849578Ssam 	 */
118564416Sbostic 	if (ISSET(lflag, PENDIN))
11867502Sroot 		ttypend(tp);
11879859Ssam 	splx(s);
118840712Skarels 
11899578Ssam 	/*
11909578Ssam 	 * Hang process if it's in the background.
11919578Ssam 	 */
119247545Skarels 	if (isbackground(p, tp)) {
119347545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
119447545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
119564576Sbostic 		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
11968520Sroot 			return (EIO);
119747545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119864416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
119940712Skarels 			return (error);
120023165Sbloom 		goto loop;
12017502Sroot 	}
120240712Skarels 
12039578Ssam 	/*
120435811Smarc 	 * If canonical, use the canonical queue,
120535811Smarc 	 * else use the raw queue.
120637584Smarc 	 *
120747545Skarels 	 * (should get rid of clists...)
12089578Ssam 	 */
120964416Sbostic 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
121040712Skarels 
12119578Ssam 	/*
121240712Skarels 	 * If there is no input, sleep on rawq
121340712Skarels 	 * awaiting hardware receipt and notification.
121440712Skarels 	 * If we have data, we don't need to check for carrier.
12159578Ssam 	 */
121617545Skarels 	s = spltty();
12179578Ssam 	if (qp->c_cc <= 0) {
121840712Skarels 		int carrier;
121940712Skarels 
122064416Sbostic 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
122164416Sbostic 		    ISSET(tp->t_cflag, CLOCAL);
122264416Sbostic 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12239859Ssam 			splx(s);
122440712Skarels 			return (0);	/* EOF */
12257502Sroot 		}
122637728Smckusick 		if (flag & IO_NDELAY) {
122737584Smarc 			splx(s);
122837584Smarc 			return (EWOULDBLOCK);
122937584Smarc 		}
123064416Sbostic 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
123140712Skarels 		    carrier ? ttyin : ttopen, 0);
12329859Ssam 		splx(s);
123343377Smarc 		if (error)
123440712Skarels 			return (error);
12359578Ssam 		goto loop;
12369578Ssam 	}
12379859Ssam 	splx(s);
123840712Skarels 
12399578Ssam 	/*
124035811Smarc 	 * Input present, check for input mapping and processing.
12419578Ssam 	 */
12429578Ssam 	first = 1;
12439578Ssam 	while ((c = getc(qp)) >= 0) {
12449578Ssam 		/*
124535811Smarc 		 * delayed suspend (^Y)
12469578Ssam 		 */
124764416Sbostic 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
124842882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12499578Ssam 			if (first) {
125064416Sbostic 				if (error = ttysleep(tp,
125164416Sbostic 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
125240712Skarels 					break;
12539578Ssam 				goto loop;
12549578Ssam 			}
12559578Ssam 			break;
12567502Sroot 		}
12579578Ssam 		/*
125835811Smarc 		 * Interpret EOF only in canonical mode.
12599578Ssam 		 */
126064416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12619578Ssam 			break;
12629578Ssam 		/*
12639578Ssam 		 * Give user character.
12649578Ssam 		 */
126540712Skarels  		error = ureadc(c, uio);
12669578Ssam 		if (error)
12679578Ssam 			break;
126814938Smckusick  		if (uio->uio_resid == 0)
12699578Ssam 			break;
12709578Ssam 		/*
127135811Smarc 		 * In canonical mode check for a "break character"
12729578Ssam 		 * marking the end of a "line of input".
12739578Ssam 		 */
127464416Sbostic 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
12759578Ssam 			break;
12769578Ssam 		first = 0;
12777502Sroot 	}
12789578Ssam 	/*
12799578Ssam 	 * Look to unblock output now that (presumably)
12809578Ssam 	 * the input queue has gone down.
12819578Ssam 	 */
128252485Storek 	s = spltty();
128364416Sbostic 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
128447545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
128547545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
128664416Sbostic 			CLR(tp->t_state, TS_TBLOCK);
12877502Sroot 			ttstart(tp);
12887502Sroot 		}
128935811Smarc 	}
129052485Storek 	splx(s);
12918520Sroot 	return (error);
12927502Sroot }
12937502Sroot 
12947502Sroot /*
129564416Sbostic  * Check the output queue on tp for space for a kernel message (from uprintf
129664416Sbostic  * or tprintf).  Allow some space over the normal hiwater mark so we don't
129764416Sbostic  * lose messages due to normal flow control, but don't let the tty run amok.
129864416Sbostic  * Sleeps here are not interruptible, but we return prematurely if new signals
129964416Sbostic  * arrive.
130025391Skarels  */
130164416Sbostic int
ttycheckoutq(tp,wait)130225391Skarels ttycheckoutq(tp, wait)
130325391Skarels 	register struct tty *tp;
130425391Skarels 	int wait;
130525391Skarels {
130630695Skarels 	int hiwat, s, oldsig;
130725391Skarels 
130835811Smarc 	hiwat = tp->t_hiwat;
130925391Skarels 	s = spltty();
131064576Sbostic 	oldsig = wait ? curproc->p_siglist : 0;
131125391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
131229946Skarels 		while (tp->t_outq.c_cc > hiwat) {
131329946Skarels 			ttstart(tp);
131464576Sbostic 			if (wait == 0 || curproc->p_siglist != oldsig) {
131529946Skarels 				splx(s);
131629946Skarels 				return (0);
131729946Skarels 			}
131854782Storek 			timeout((void (*)__P((void *)))wakeup,
131954782Storek 			    (void *)&tp->t_outq, hz);
132064416Sbostic 			SET(tp->t_state, TS_ASLEEP);
132130695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
132225391Skarels 		}
132325391Skarels 	splx(s);
132425391Skarels 	return (1);
132525391Skarels }
132625391Skarels 
132725391Skarels /*
132849380Skarels  * Process a write call on a tty device.
13297502Sroot  */
133064416Sbostic int
ttwrite(tp,uio,flag)133137584Smarc ttwrite(tp, uio, flag)
13327625Ssam 	register struct tty *tp;
13339578Ssam 	register struct uio *uio;
133452485Storek 	int flag;
13357502Sroot {
13367502Sroot 	register char *cp;
133764416Sbostic 	register int cc, ce;
133864416Sbostic 	register struct proc *p;
13399578Ssam 	int i, hiwat, cnt, error, s;
13407502Sroot 	char obuf[OBUFSIZ];
13417502Sroot 
134235811Smarc 	hiwat = tp->t_hiwat;
13439578Ssam 	cnt = uio->uio_resid;
13449578Ssam 	error = 0;
134564878Smckusick 	cc = 0;
13467502Sroot loop:
134737584Smarc 	s = spltty();
134864416Sbostic 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
134964416Sbostic 	    !ISSET(tp->t_cflag, CLOCAL)) {
135064416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN)) {
135137584Smarc 			splx(s);
135237584Smarc 			return (EIO);
135337728Smckusick 		} else if (flag & IO_NDELAY) {
135437584Smarc 			splx(s);
135540712Skarels 			error = EWOULDBLOCK;
135640712Skarels 			goto out;
135737584Smarc 		} else {
135864416Sbostic 			/* Sleep awaiting carrier. */
135964416Sbostic 			error = ttysleep(tp,
136064416Sbostic 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
136137584Smarc 			splx(s);
136243377Smarc 			if (error)
136340712Skarels 				goto out;
136437584Smarc 			goto loop;
136537584Smarc 		}
136637584Smarc 	}
136737584Smarc 	splx(s);
13689578Ssam 	/*
13699578Ssam 	 * Hang the process if it's in the background.
13709578Ssam 	 */
137164416Sbostic 	p = curproc;
137264416Sbostic 	if (isbackground(p, tp) &&
137364576Sbostic 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
137447545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
137547545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
137647545Skarels 	     p->p_pgrp->pg_jobc) {
137747545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
137864416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
137940712Skarels 			goto out;
138021776Sbloom 		goto loop;
13817502Sroot 	}
13829578Ssam 	/*
138364416Sbostic 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
138464416Sbostic 	 * output translation.  Keep track of high water mark, sleep on
138564416Sbostic 	 * overflow awaiting device aid in acquiring new space.
13869578Ssam 	 */
138764878Smckusick 	while (uio->uio_resid > 0 || cc > 0) {
138864416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO)) {
138940712Skarels 			uio->uio_resid = 0;
139040712Skarels 			return (0);
139140712Skarels 		}
139240712Skarels 		if (tp->t_outq.c_cc > hiwat)
139332067Skarels 			goto ovhiwat;
13949578Ssam 		/*
139564416Sbostic 		 * Grab a hunk of data from the user, unless we have some
139664416Sbostic 		 * leftover from last time.
13979578Ssam 		 */
13987822Sroot 		if (cc == 0) {
139940712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
140040712Skarels 			cp = obuf;
140140712Skarels 			error = uiomove(cp, cc, uio);
140240712Skarels 			if (error) {
140340712Skarels 				cc = 0;
140440712Skarels 				break;
140540712Skarels 			}
14067822Sroot 		}
14079578Ssam 		/*
14089578Ssam 		 * If nothing fancy need be done, grab those characters we
14099578Ssam 		 * can handle without any of ttyoutput's processing and
14109578Ssam 		 * just transfer them to the output q.  For those chars
14119578Ssam 		 * which require special processing (as indicated by the
141264416Sbostic 		 * bits in char_type), call ttyoutput.  After processing
14139578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14149578Ssam 		 * immediately.
14159578Ssam 		 */
14169578Ssam 		while (cc > 0) {
141764416Sbostic 			if (!ISSET(tp->t_oflag, OPOST))
14187502Sroot 				ce = cc;
14197502Sroot 			else {
142064416Sbostic 				ce = cc - scanc((u_int)cc, (u_char *)cp,
142164416Sbostic 				   (u_char *)char_type, CCLASSMASK);
14229578Ssam 				/*
14239578Ssam 				 * If ce is zero, then we're processing
14249578Ssam 				 * a special character through ttyoutput.
14259578Ssam 				 */
14269578Ssam 				if (ce == 0) {
14277502Sroot 					tp->t_rocount = 0;
14287502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142964416Sbostic 						/* No Clists, wait a bit. */
143064416Sbostic 						ttstart(tp);
143164416Sbostic 						if (error = ttysleep(tp, &lbolt,
143264416Sbostic 						    TTOPRI | PCATCH, ttybuf, 0))
143364416Sbostic 							break;
143464416Sbostic 						goto loop;
14357502Sroot 					}
143664416Sbostic 					cp++;
143764416Sbostic 					cc--;
143864416Sbostic 					if (ISSET(tp->t_lflag, FLUSHO) ||
14399578Ssam 					    tp->t_outq.c_cc > hiwat)
14407502Sroot 						goto ovhiwat;
14419578Ssam 					continue;
14427502Sroot 				}
14437502Sroot 			}
14449578Ssam 			/*
144564416Sbostic 			 * A bunch of normal characters have been found.
144664416Sbostic 			 * Transfer them en masse to the output queue and
14479578Ssam 			 * continue processing at the top of the loop.
14489578Ssam 			 * If there are any further characters in this
14499578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14509578Ssam 			 * requiring special handling by ttyoutput.
14519578Ssam 			 */
14527502Sroot 			tp->t_rocount = 0;
14539578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14549578Ssam 			ce -= i;
145564530Sbostic 			tp->t_column += ce;
14569578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
145735811Smarc 			tp->t_outcc += ce;
14589578Ssam 			if (i > 0) {
145964416Sbostic 				/* No Clists, wait a bit. */
14607502Sroot 				ttstart(tp);
146164416Sbostic 				if (error = ttysleep(tp,
146264416Sbostic 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
146340712Skarels 					break;
146421776Sbloom 				goto loop;
14657502Sroot 			}
146664416Sbostic 			if (ISSET(tp->t_lflag, FLUSHO) ||
146764416Sbostic 			    tp->t_outq.c_cc > hiwat)
146840712Skarels 				break;
14697502Sroot 		}
147035811Smarc 		ttstart(tp);
14717502Sroot 	}
147240712Skarels out:
147340712Skarels 	/*
147464416Sbostic 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
147564416Sbostic 	 * offset and iov pointers have moved forward, but it doesn't matter
147664416Sbostic 	 * (the call will either return short or restart with a new uio).
147740712Skarels 	 */
147840712Skarels 	uio->uio_resid += cc;
14798520Sroot 	return (error);
148040712Skarels 
14817502Sroot ovhiwat:
148232067Skarels 	ttstart(tp);
148332067Skarels 	s = spltty();
14849578Ssam 	/*
148535811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
148632067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14879578Ssam 	 */
14887502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14899578Ssam 		splx(s);
14907502Sroot 		goto loop;
14917502Sroot 	}
149237728Smckusick 	if (flag & IO_NDELAY) {
149317545Skarels 		splx(s);
149440712Skarels 		uio->uio_resid += cc;
149564416Sbostic 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14967502Sroot 	}
149764416Sbostic 	SET(tp->t_state, TS_ASLEEP);
149864416Sbostic 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14999578Ssam 	splx(s);
150043377Smarc 	if (error)
150140712Skarels 		goto out;
15027502Sroot 	goto loop;
15037502Sroot }
15047502Sroot 
15057502Sroot /*
15067502Sroot  * Rubout one character from the rawq of tp
15077502Sroot  * as cleanly as possible.
15087502Sroot  */
150964416Sbostic void
ttyrub(c,tp)15107502Sroot ttyrub(c, tp)
151164416Sbostic 	register int c;
15127625Ssam 	register struct tty *tp;
15137502Sroot {
15147502Sroot 	register char *cp;
15157502Sroot 	register int savecol;
151664416Sbostic 	int tabc, s;
15177502Sroot 
151864416Sbostic 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15197502Sroot 		return;
152064416Sbostic 	CLR(tp->t_lflag, FLUSHO);
152164416Sbostic 	if (ISSET(tp->t_lflag, ECHOE)) {
15227502Sroot 		if (tp->t_rocount == 0) {
15237502Sroot 			/*
15247502Sroot 			 * Screwed by ttwrite; retype
15257502Sroot 			 */
15267502Sroot 			ttyretype(tp);
15277502Sroot 			return;
15287502Sroot 		}
152964416Sbostic 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15307502Sroot 			ttyrubo(tp, 2);
153164576Sbostic 		else {
153264576Sbostic 			CLR(c, ~TTY_CHARMASK);
153364576Sbostic 			switch (CCLASS(c)) {
153464576Sbostic 			case ORDINARY:
153564576Sbostic 				ttyrubo(tp, 1);
153664576Sbostic 				break;
153764576Sbostic 			case BACKSPACE:
153864576Sbostic 			case CONTROL:
153964576Sbostic 			case NEWLINE:
154064576Sbostic 			case RETURN:
154164576Sbostic 			case VTAB:
154264576Sbostic 				if (ISSET(tp->t_lflag, ECHOCTL))
154364576Sbostic 					ttyrubo(tp, 2);
154464576Sbostic 				break;
154564576Sbostic 			case TAB:
154664576Sbostic 				if (tp->t_rocount < tp->t_rawq.c_cc) {
154764576Sbostic 					ttyretype(tp);
154864576Sbostic 					return;
154964576Sbostic 				}
155064576Sbostic 				s = spltty();
155164576Sbostic 				savecol = tp->t_column;
155264576Sbostic 				SET(tp->t_state, TS_CNTTB);
155364576Sbostic 				SET(tp->t_lflag, FLUSHO);
155464576Sbostic 				tp->t_column = tp->t_rocol;
155564576Sbostic 				cp = tp->t_rawq.c_cf;
155664576Sbostic 				if (cp)
155764576Sbostic 					tabc = *cp;	/* XXX FIX NEXTC */
155864576Sbostic 				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
155964576Sbostic 					ttyecho(tabc, tp);
156064576Sbostic 				CLR(tp->t_lflag, FLUSHO);
156164576Sbostic 				CLR(tp->t_state, TS_CNTTB);
156264576Sbostic 				splx(s);
156364416Sbostic 
156464576Sbostic 				/* savecol will now be length of the tab. */
156564576Sbostic 				savecol -= tp->t_column;
156664576Sbostic 				tp->t_column += savecol;
156764576Sbostic 				if (savecol > 8)
156864576Sbostic 					savecol = 8;	/* overflow screw */
156964576Sbostic 				while (--savecol >= 0)
157064576Sbostic 					(void)ttyoutput('\b', tp);
157164576Sbostic 				break;
157264576Sbostic 			default:			/* XXX */
157364416Sbostic #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
157464576Sbostic 				(void)printf(PANICSTR, c, CCLASS(c));
157564416Sbostic #ifdef notdef
157664576Sbostic 				panic(PANICSTR, c, CCLASS(c));
157764416Sbostic #endif
157864576Sbostic 			}
157935811Smarc 		}
158064416Sbostic 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
158164416Sbostic 		if (!ISSET(tp->t_state, TS_ERASE)) {
158264416Sbostic 			SET(tp->t_state, TS_ERASE);
158364416Sbostic 			(void)ttyoutput('\\', tp);
15847502Sroot 		}
15857502Sroot 		ttyecho(c, tp);
15867502Sroot 	} else
158735811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
158864416Sbostic 	--tp->t_rocount;
15897502Sroot }
15907502Sroot 
15917502Sroot /*
159264416Sbostic  * Back over cnt characters, erasing them.
15937502Sroot  */
159464416Sbostic static void
ttyrubo(tp,cnt)15957502Sroot ttyrubo(tp, cnt)
15967625Ssam 	register struct tty *tp;
15977625Ssam 	int cnt;
15987502Sroot {
15997502Sroot 
160064416Sbostic 	while (cnt-- > 0) {
160164416Sbostic 		(void)ttyoutput('\b', tp);
160264416Sbostic 		(void)ttyoutput(' ', tp);
160364416Sbostic 		(void)ttyoutput('\b', tp);
160464416Sbostic 	}
16057502Sroot }
16067502Sroot 
16077502Sroot /*
160864416Sbostic  * ttyretype --
160964416Sbostic  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
161064416Sbostic  *	been checked.
16117502Sroot  */
161264416Sbostic void
ttyretype(tp)16137502Sroot ttyretype(tp)
16147625Ssam 	register struct tty *tp;
16157502Sroot {
16167502Sroot 	register char *cp;
161735811Smarc 	int s, c;
16187502Sroot 
161964416Sbostic 	/* Echo the reprint character. */
162035811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
162135811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
162264416Sbostic 
162364416Sbostic 	(void)ttyoutput('\n', tp);
162464416Sbostic 
162564416Sbostic 	/*
162664416Sbostic 	 * XXX
162764416Sbostic 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162864416Sbostic 	 * BIT OF FIRST CHAR.
162964416Sbostic 	 */
163017545Skarels 	s = spltty();
163164416Sbostic 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
163264416Sbostic 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
163335811Smarc 		ttyecho(c, tp);
163464416Sbostic 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
163564416Sbostic 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
163635811Smarc 		ttyecho(c, tp);
163764416Sbostic 	CLR(tp->t_state, TS_ERASE);
16387502Sroot 	splx(s);
163964416Sbostic 
16407502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16417502Sroot 	tp->t_rocol = 0;
16427502Sroot }
16437502Sroot 
16447502Sroot /*
164535811Smarc  * Echo a typed character to the terminal.
16467502Sroot  */
164764416Sbostic static void
ttyecho(c,tp)16487502Sroot ttyecho(c, tp)
164964416Sbostic 	register int c;
16507625Ssam 	register struct tty *tp;
16517502Sroot {
165264416Sbostic 
165364416Sbostic 	if (!ISSET(tp->t_state, TS_CNTTB))
165464416Sbostic 		CLR(tp->t_lflag, FLUSHO);
165564416Sbostic 	if ((!ISSET(tp->t_lflag, ECHO) &&
165664416Sbostic 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
165764416Sbostic 	    ISSET(tp->t_lflag, EXTPROC))
16587502Sroot 		return;
165964416Sbostic 	if (ISSET(tp->t_lflag, ECHOCTL) &&
166064576Sbostic 	    (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
166164576Sbostic 	    ISSET(c, TTY_CHARMASK) == 0177)) {
166264416Sbostic 		(void)ttyoutput('^', tp);
166364576Sbostic 		CLR(c, ~TTY_CHARMASK);
166464416Sbostic 		if (c == 0177)
166564416Sbostic 			c = '?';
166664416Sbostic 		else
166764416Sbostic 			c += 'A' - 1;
16687502Sroot 	}
166964416Sbostic 	(void)ttyoutput(c, tp);
16707502Sroot }
16717502Sroot 
16727502Sroot /*
167349380Skarels  * Wake up any readers on a tty.
167449380Skarels  */
167564416Sbostic void
ttwakeup(tp)16767502Sroot ttwakeup(tp)
167747545Skarels 	register struct tty *tp;
16787502Sroot {
16797502Sroot 
168052522Smckusick 	selwakeup(&tp->t_rsel);
168164416Sbostic 	if (ISSET(tp->t_state, TS_ASYNC))
168264416Sbostic 		pgsignal(tp->t_pgrp, SIGIO, 1);
16837502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16847502Sroot }
168535811Smarc 
168635811Smarc /*
168748439Skarels  * Look up a code for a specified speed in a conversion table;
168848439Skarels  * used by drivers to map software speed values to hardware parameters.
168948439Skarels  */
169064416Sbostic int
ttspeedtab(speed,table)169148439Skarels ttspeedtab(speed, table)
169252485Storek 	int speed;
169348439Skarels 	register struct speedtab *table;
169448439Skarels {
169548439Skarels 
169648439Skarels 	for ( ; table->sp_speed != -1; table++)
169748439Skarels 		if (table->sp_speed == speed)
169848439Skarels 			return (table->sp_code);
169948439Skarels 	return (-1);
170048439Skarels }
170148439Skarels 
170248439Skarels /*
170364416Sbostic  * Set tty hi and low water marks.
170435811Smarc  *
170535811Smarc  * Try to arrange the dynamics so there's about one second
170635811Smarc  * from hi to low water.
170764416Sbostic  *
170835811Smarc  */
170964416Sbostic void
ttsetwater(tp)171035811Smarc ttsetwater(tp)
171135811Smarc 	struct tty *tp;
171235811Smarc {
171364416Sbostic 	register int cps, x;
171435811Smarc 
171564416Sbostic #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
171664416Sbostic 
171764416Sbostic 	cps = tp->t_ospeed / 10;
171864416Sbostic 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
171935811Smarc 	x += cps;
172064416Sbostic 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
172135811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
172264416Sbostic #undef	CLAMP
172335811Smarc }
172435811Smarc 
172539407Smarc /*
172639407Smarc  * Report on state of foreground process group.
172739407Smarc  */
172864416Sbostic void
ttyinfo(tp)172939407Smarc ttyinfo(tp)
173049907Sbostic 	register struct tty *tp;
173139407Smarc {
173249907Sbostic 	register struct proc *p, *pick;
173341177Smarc 	struct timeval utime, stime;
173449907Sbostic 	int tmp;
173539407Smarc 
173664416Sbostic 	if (ttycheckoutq(tp,0) == 0)
173739407Smarc 		return;
173849907Sbostic 
173949907Sbostic 	/* Print load average. */
174052666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
174149907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
174249907Sbostic 
174339555Smarc 	if (tp->t_session == NULL)
174449907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
174541177Smarc 	else if (tp->t_pgrp == NULL)
174649907Sbostic 		ttyprintf(tp, "no foreground process group\n");
174767732Smckusick 	else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
174849907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174939407Smarc 	else {
175049907Sbostic 		/* Pick interesting process. */
175167732Smckusick 		for (pick = NULL; p != 0; p = p->p_pglist.le_next)
175241177Smarc 			if (proc_compare(pick, p))
175341177Smarc 				pick = p;
175449907Sbostic 
175549907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
175649907Sbostic 		    pick->p_stat == SRUN ? "running" :
175749907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
175849907Sbostic 
175954782Storek 		calcru(pick, &utime, &stime, NULL);
176039407Smarc 
176149907Sbostic 		/* Print user time. */
176249907Sbostic 		ttyprintf(tp, "%d.%02du ",
176349907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
176441177Smarc 
176549907Sbostic 		/* Print system time. */
176649907Sbostic 		ttyprintf(tp, "%d.%02ds ",
176749907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176849907Sbostic 
176949907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
177049907Sbostic 		/* Print percentage cpu, resident set size. */
177149907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
177249907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
177352485Storek 		    tmp / 100,
177452485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
177565549Smckusick #ifdef pmap_resident_count
177665549Smckusick 			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
177765549Smckusick #else
177865549Smckusick 			pgtok(pick->p_vmspace->vm_rssize)
177965549Smckusick #endif
178065549Smckusick 			);
178141177Smarc 	}
178249907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
178341177Smarc }
178441177Smarc 
178541177Smarc /*
178641177Smarc  * Returns 1 if p2 is "better" than p1
178741177Smarc  *
178841177Smarc  * The algorithm for picking the "interesting" process is thus:
178941177Smarc  *
179064576Sbostic  *	1) Only foreground processes are eligible - implied.
179164576Sbostic  *	2) Runnable processes are favored over anything else.  The runner
179264576Sbostic  *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
179341177Smarc  *	   broken by picking the highest pid.
179464576Sbostic  *	3) The sleeper with the shortest sleep time is next.  With ties,
179564576Sbostic  *	   we pick out just "short-term" sleepers (P_SINTR == 0).
179664576Sbostic  *	4) Further ties are broken by picking the highest pid.
179741177Smarc  */
179864576Sbostic #define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179945723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
180045723Smckusick #define ONLYA   2
180145723Smckusick #define ONLYB   1
180245723Smckusick #define BOTH    3
180364576Sbostic 
180449907Sbostic static int
proc_compare(p1,p2)180541177Smarc proc_compare(p1, p2)
180641177Smarc 	register struct proc *p1, *p2;
180741177Smarc {
180841177Smarc 
180941177Smarc 	if (p1 == NULL)
181041177Smarc 		return (1);
181141177Smarc 	/*
181241177Smarc 	 * see if at least one of them is runnable
181341177Smarc 	 */
181464576Sbostic 	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
181545723Smckusick 	case ONLYA:
181645723Smckusick 		return (0);
181745723Smckusick 	case ONLYB:
181841177Smarc 		return (1);
181945723Smckusick 	case BOTH:
182041177Smarc 		/*
182141177Smarc 		 * tie - favor one with highest recent cpu utilization
182241177Smarc 		 */
182364576Sbostic 		if (p2->p_estcpu > p1->p_estcpu)
182441177Smarc 			return (1);
182564576Sbostic 		if (p1->p_estcpu > p2->p_estcpu)
182641177Smarc 			return (0);
182741177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182841177Smarc 	}
182945723Smckusick 	/*
183045723Smckusick  	 * weed out zombies
183145723Smckusick 	 */
183245723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
183345723Smckusick 	case ONLYA:
183445723Smckusick 		return (1);
183545723Smckusick 	case ONLYB:
183645723Smckusick 		return (0);
183745723Smckusick 	case BOTH:
183845723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183945723Smckusick 	}
184064416Sbostic 	/*
184141177Smarc 	 * pick the one with the smallest sleep time
184241177Smarc 	 */
184341177Smarc 	if (p2->p_slptime > p1->p_slptime)
184441177Smarc 		return (0);
184541177Smarc 	if (p1->p_slptime > p2->p_slptime)
184641177Smarc 		return (1);
184741177Smarc 	/*
184841177Smarc 	 * favor one sleeping in a non-interruptible sleep
184941177Smarc 	 */
185064576Sbostic 	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
185141177Smarc 		return (1);
185264576Sbostic 	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
185341177Smarc 		return (0);
185447545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
185541177Smarc }
185645723Smckusick 
185739555Smarc /*
185839555Smarc  * Output char to tty; console putchar style.
185939555Smarc  */
186064416Sbostic int
tputchar(c,tp)186139555Smarc tputchar(c, tp)
186239555Smarc 	int c;
186339555Smarc 	struct tty *tp;
186439555Smarc {
186564416Sbostic 	register int s;
186639555Smarc 
186764416Sbostic 	s = spltty();
186864416Sbostic 	if (ISSET(tp->t_state,
186964416Sbostic 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
187039555Smarc 		splx(s);
187164416Sbostic 		return (-1);
187239555Smarc 	}
187364416Sbostic 	if (c == '\n')
187464416Sbostic 		(void)ttyoutput('\r', tp);
187564416Sbostic 	(void)ttyoutput(c, tp);
187664416Sbostic 	ttstart(tp);
187739555Smarc 	splx(s);
187864416Sbostic 	return (0);
187939555Smarc }
188043377Smarc 
188144419Smarc /*
188264416Sbostic  * Sleep on chan, returning ERESTART if tty changed while we napped and
188364416Sbostic  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
188464416Sbostic  * the tty is revoked, restarting a pending call will redo validation done
188564416Sbostic  * at the start of the call.
188644419Smarc  */
188764416Sbostic int
ttysleep(tp,chan,pri,wmesg,timo)188843377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188943377Smarc 	struct tty *tp;
189064416Sbostic 	void *chan;
189164416Sbostic 	int pri, timo;
189243377Smarc 	char *wmesg;
189343377Smarc {
189443377Smarc 	int error;
189564416Sbostic 	short gen;
189643377Smarc 
189764416Sbostic 	gen = tp->t_gen;
189843377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
189943377Smarc 		return (error);
190064416Sbostic 	return (tp->t_gen == gen ? 0 : ERESTART);
190143377Smarc }
1902