xref: /csrg-svn/sys/kern/tty.c (revision 65771)
149594Sbostic /*-
263178Sbostic  * Copyright (c) 1982, 1986, 1990, 1991, 1993
363178Sbostic  *	The Regents of the University of California.  All rights reserved.
4*65771Sbostic  * (c) UNIX System Laboratories, Inc.
5*65771Sbostic  * All or some portions of this file are derived from material licensed
6*65771Sbostic  * to the University of California by American Telephone and Telegraph
7*65771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65771Sbostic  * the permission of UNIX System Laboratories, Inc.
923387Smckusick  *
1049594Sbostic  * %sccs.include.redist.c%
1149594Sbostic  *
12*65771Sbostic  *	@(#)tty.c	8.8 (Berkeley) 01/21/94
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
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
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
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
5037502Sroot ttyoutput(c, tp)
50464416Sbostic 	register int c;
5057502Sroot 	register struct tty *tp;
5067502Sroot {
50764416Sbostic 	register long oflag;
50864416Sbostic 	register int 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);
53064416Sbostic 		if (!ISSET(tp->t_lflag, FLUSHO)) {
53164416Sbostic 			s = spltty();		/* Don't interrupt tabs. */
5327502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
5337502Sroot 			tk_nout += c;
53435811Smarc 			tp->t_outcc += c;
5357502Sroot 			splx(s);
5367502Sroot 		}
53764530Sbostic 		tp->t_column += c;
5387502Sroot 		return (c ? -1 : '\t');
5397502Sroot 	}
54064416Sbostic 	if (c == CEOT && ISSET(oflag, ONOEOT))
54147545Skarels 		return (-1);
54264576Sbostic 
5437502Sroot 	/*
54449380Skarels 	 * Newline translation: if ONLCR is set,
54549380Skarels 	 * translate newline into "\r\n".
5467502Sroot 	 */
54764576Sbostic 	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
54864576Sbostic 		tk_nout++;
54964576Sbostic 		tp->t_outcc++;
55064576Sbostic 		if (putc('\r', &tp->t_outq))
55164576Sbostic 			return (c);
55264576Sbostic 	}
55364576Sbostic 	tk_nout++;
55464576Sbostic 	tp->t_outcc++;
55564416Sbostic 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
55635811Smarc 		return (c);
55747545Skarels 
55864530Sbostic 	col = tp->t_column;
55949380Skarels 	switch (CCLASS(c)) {
5607502Sroot 	case BACKSPACE:
56149380Skarels 		if (col > 0)
56264416Sbostic 			--col;
5637502Sroot 		break;
56464416Sbostic 	case CONTROL:
56564416Sbostic 		break;
5667502Sroot 	case NEWLINE:
56764416Sbostic 	case RETURN:
56849380Skarels 		col = 0;
5697502Sroot 		break;
57064416Sbostic 	case ORDINARY:
57164416Sbostic 		++col;
57264416Sbostic 		break;
5737502Sroot 	case TAB:
57464416Sbostic 		col = (col + 8) & ~7;
5757502Sroot 		break;
5767502Sroot 	}
57764530Sbostic 	tp->t_column = col;
5787502Sroot 	return (-1);
5797502Sroot }
5807502Sroot 
5817502Sroot /*
58264576Sbostic  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
58364576Sbostic  * has been called to do discipline-specific functions and/or reject any
58464576Sbostic  * of these ioctl commands.
58564416Sbostic  */
58664416Sbostic /* ARGSUSED */
58764416Sbostic int
58864576Sbostic ttioctl(tp, cmd, data, flag)
58964416Sbostic 	register struct tty *tp;
59064576Sbostic 	int cmd, flag;
59164416Sbostic 	void *data;
59264416Sbostic {
59364416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
59464576Sbostic 	extern int nlinesw;
59564416Sbostic 	register struct proc *p;
59664416Sbostic 	int s, error;
59764416Sbostic 
59864416Sbostic 	p = curproc;			/* XXX */
59964416Sbostic 
60064416Sbostic 	/* If the ioctl involves modification, hang if in the background. */
60164576Sbostic 	switch (cmd) {
60264416Sbostic 	case  TIOCFLUSH:
60364416Sbostic 	case  TIOCSETA:
60464416Sbostic 	case  TIOCSETD:
60564416Sbostic 	case  TIOCSETAF:
60664416Sbostic 	case  TIOCSETAW:
60764416Sbostic #ifdef notdef
60864416Sbostic 	case  TIOCSPGRP:
60964416Sbostic #endif
61064416Sbostic 	case  TIOCSTI:
61164416Sbostic 	case  TIOCSWINSZ:
61264416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
61364416Sbostic 	case  TIOCLBIC:
61464416Sbostic 	case  TIOCLBIS:
61564416Sbostic 	case  TIOCLSET:
61664416Sbostic 	case  TIOCSETC:
61764416Sbostic 	case OTIOCSETD:
61864416Sbostic 	case  TIOCSETN:
61964416Sbostic 	case  TIOCSETP:
62064416Sbostic 	case  TIOCSLTC:
62164416Sbostic #endif
62264416Sbostic 		while (isbackground(curproc, tp) &&
62364576Sbostic 		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
62464416Sbostic 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
62564416Sbostic 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
62664416Sbostic 			pgsignal(p->p_pgrp, SIGTTOU, 1);
62764416Sbostic 			if (error = ttysleep(tp,
62864416Sbostic 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
62964416Sbostic 				return (error);
63064416Sbostic 		}
63164416Sbostic 		break;
63264416Sbostic 	}
63364416Sbostic 
63464576Sbostic 	switch (cmd) {			/* Process the ioctl. */
63564416Sbostic 	case FIOASYNC:			/* set/clear async i/o */
63664416Sbostic 		s = spltty();
63764416Sbostic 		if (*(int *)data)
63864416Sbostic 			SET(tp->t_state, TS_ASYNC);
63964416Sbostic 		else
64064416Sbostic 			CLR(tp->t_state, TS_ASYNC);
64164416Sbostic 		splx(s);
64264416Sbostic 		break;
64364416Sbostic 	case FIONBIO:			/* set/clear non-blocking i/o */
64464416Sbostic 		break;			/* XXX: delete. */
64564416Sbostic 	case FIONREAD:			/* get # bytes to read */
64664416Sbostic 		*(int *)data = ttnread(tp);
64764416Sbostic 		break;
64864416Sbostic 	case TIOCEXCL:			/* set exclusive use of tty */
64964416Sbostic 		s = spltty();
65064416Sbostic 		SET(tp->t_state, TS_XCLUDE);
65164416Sbostic 		splx(s);
65264416Sbostic 		break;
65364416Sbostic 	case TIOCFLUSH: {		/* flush buffers */
65464416Sbostic 		register int flags = *(int *)data;
65564416Sbostic 
65664416Sbostic 		if (flags == 0)
65764416Sbostic 			flags = FREAD | FWRITE;
65864416Sbostic 		else
65964416Sbostic 			flags &= FREAD | FWRITE;
66064416Sbostic 		ttyflush(tp, flags);
66164416Sbostic 		break;
66264416Sbostic 	}
66364416Sbostic 	case TIOCCONS:			/* become virtual console */
66464416Sbostic 		if (*(int *)data) {
66564416Sbostic 			if (constty && constty != tp &&
66664416Sbostic 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
66764416Sbostic 			    (TS_CARR_ON | TS_ISOPEN))
66864416Sbostic 				return (EBUSY);
66964416Sbostic #ifndef	UCONSOLE
67064416Sbostic 			if (error = suser(p->p_ucred, &p->p_acflag))
67164416Sbostic 				return (error);
67264416Sbostic #endif
67364416Sbostic 			constty = tp;
67464416Sbostic 		} else if (tp == constty)
67564416Sbostic 			constty = NULL;
67664416Sbostic 		break;
67764416Sbostic 	case TIOCDRAIN:			/* wait till output drained */
67864416Sbostic 		if (error = ttywait(tp))
67964416Sbostic 			return (error);
68064416Sbostic 		break;
68164416Sbostic 	case TIOCGETA: {		/* get termios struct */
68264416Sbostic 		struct termios *t = (struct termios *)data;
68364416Sbostic 
68464416Sbostic 		bcopy(&tp->t_termios, t, sizeof(struct termios));
68564416Sbostic 		break;
68664416Sbostic 	}
68764416Sbostic 	case TIOCGETD:			/* get line discipline */
68864416Sbostic 		*(int *)data = tp->t_line;
68964416Sbostic 		break;
69064416Sbostic 	case TIOCGWINSZ:		/* get window size */
69164416Sbostic 		*(struct winsize *)data = tp->t_winsize;
69264416Sbostic 		break;
69364416Sbostic 	case TIOCGPGRP:			/* get pgrp of tty */
69464416Sbostic 		if (!isctty(p, tp))
69564416Sbostic 			return (ENOTTY);
69664416Sbostic 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
69764416Sbostic 		break;
69864416Sbostic #ifdef TIOCHPCL
69964416Sbostic 	case TIOCHPCL:			/* hang up on last close */
70064416Sbostic 		s = spltty();
70164576Sbostic 		SET(tp->t_cflag, HUPCL);
70264416Sbostic 		splx(s);
70364416Sbostic 		break;
70464416Sbostic #endif
70564416Sbostic 	case TIOCNXCL:			/* reset exclusive use of tty */
70664416Sbostic 		s = spltty();
70764416Sbostic 		CLR(tp->t_state, TS_XCLUDE);
70864416Sbostic 		splx(s);
70964416Sbostic 		break;
71064416Sbostic 	case TIOCOUTQ:			/* output queue size */
71164416Sbostic 		*(int *)data = tp->t_outq.c_cc;
71264416Sbostic 		break;
71364416Sbostic 	case TIOCSETA:			/* set termios struct */
71464416Sbostic 	case TIOCSETAW:			/* drain output, set */
71564416Sbostic 	case TIOCSETAF: {		/* drn out, fls in, set */
71664416Sbostic 		register struct termios *t = (struct termios *)data;
71764416Sbostic 
71864416Sbostic 		s = spltty();
71964576Sbostic 		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
72064416Sbostic 			if (error = ttywait(tp)) {
72164416Sbostic 				splx(s);
72264416Sbostic 				return (error);
72364416Sbostic 			}
72464576Sbostic 			if (cmd == TIOCSETAF)
72564416Sbostic 				ttyflush(tp, FREAD);
72664416Sbostic 		}
72764416Sbostic 		if (!ISSET(t->c_cflag, CIGNORE)) {
72864416Sbostic 			/*
72964416Sbostic 			 * Set device hardware.
73064416Sbostic 			 */
73164416Sbostic 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
73264416Sbostic 				splx(s);
73364416Sbostic 				return (error);
73464416Sbostic 			} else {
73564416Sbostic 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
73664416Sbostic 				    ISSET(tp->t_cflag, CLOCAL) &&
73764416Sbostic 				    !ISSET(t->c_cflag, CLOCAL)) {
73864416Sbostic 					CLR(tp->t_state, TS_ISOPEN);
73964416Sbostic 					SET(tp->t_state, TS_WOPEN);
74064416Sbostic 					ttwakeup(tp);
74164416Sbostic 				}
74264416Sbostic 				tp->t_cflag = t->c_cflag;
74364416Sbostic 				tp->t_ispeed = t->c_ispeed;
74464416Sbostic 				tp->t_ospeed = t->c_ospeed;
74564416Sbostic 			}
74664416Sbostic 			ttsetwater(tp);
74764416Sbostic 		}
74864576Sbostic 		if (cmd != TIOCSETAF) {
74964416Sbostic 			if (ISSET(t->c_lflag, ICANON) !=
75064416Sbostic 			    ISSET(tp->t_lflag, ICANON))
75164416Sbostic 				if (ISSET(t->c_lflag, ICANON)) {
75264576Sbostic 					SET(tp->t_lflag, PENDIN);
75364416Sbostic 					ttwakeup(tp);
75464416Sbostic 				} else {
75564416Sbostic 					struct clist tq;
75664416Sbostic 
75764416Sbostic 					catq(&tp->t_rawq, &tp->t_canq);
75864416Sbostic 					tq = tp->t_rawq;
75964416Sbostic 					tp->t_rawq = tp->t_canq;
76064416Sbostic 					tp->t_canq = tq;
76165324Sbostic 					CLR(tp->t_lflag, PENDIN);
76264416Sbostic 				}
76364416Sbostic 		}
76464416Sbostic 		tp->t_iflag = t->c_iflag;
76564416Sbostic 		tp->t_oflag = t->c_oflag;
76664416Sbostic 		/*
76764416Sbostic 		 * Make the EXTPROC bit read only.
76864416Sbostic 		 */
76964416Sbostic 		if (ISSET(tp->t_lflag, EXTPROC))
77064416Sbostic 			SET(t->c_lflag, EXTPROC);
77164416Sbostic 		else
77264416Sbostic 			CLR(t->c_lflag, EXTPROC);
77365324Sbostic 		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
77464416Sbostic 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
77564416Sbostic 		splx(s);
77664416Sbostic 		break;
77764416Sbostic 	}
77864416Sbostic 	case TIOCSETD: {		/* set line discipline */
77964416Sbostic 		register int t = *(int *)data;
78064416Sbostic 		dev_t device = tp->t_dev;
78164416Sbostic 
78264576Sbostic 		if ((u_int)t >= nlinesw)
78364416Sbostic 			return (ENXIO);
78464416Sbostic 		if (t != tp->t_line) {
78564416Sbostic 			s = spltty();
78664416Sbostic 			(*linesw[tp->t_line].l_close)(tp, flag);
78764416Sbostic 			error = (*linesw[t].l_open)(device, tp);
78864416Sbostic 			if (error) {
78964416Sbostic 				(void)(*linesw[tp->t_line].l_open)(device, tp);
79064416Sbostic 				splx(s);
79164416Sbostic 				return (error);
79264416Sbostic 			}
79364416Sbostic 			tp->t_line = t;
79464416Sbostic 			splx(s);
79564416Sbostic 		}
79664416Sbostic 		break;
79764416Sbostic 	}
79864416Sbostic 	case TIOCSTART:			/* start output, like ^Q */
79964416Sbostic 		s = spltty();
80064416Sbostic 		if (ISSET(tp->t_state, TS_TTSTOP) ||
80164416Sbostic 		    ISSET(tp->t_lflag, FLUSHO)) {
80264416Sbostic 			CLR(tp->t_lflag, FLUSHO);
80364416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
80464416Sbostic 			ttstart(tp);
80564416Sbostic 		}
80664416Sbostic 		splx(s);
80764416Sbostic 		break;
80864416Sbostic 	case TIOCSTI:			/* simulate terminal input */
80964416Sbostic 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
81064416Sbostic 			return (EPERM);
81164416Sbostic 		if (p->p_ucred->cr_uid && !isctty(p, tp))
81264416Sbostic 			return (EACCES);
81364416Sbostic 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
81464416Sbostic 		break;
81564416Sbostic 	case TIOCSTOP:			/* stop output, like ^S */
81664416Sbostic 		s = spltty();
81764416Sbostic 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
81864416Sbostic 			SET(tp->t_state, TS_TTSTOP);
81964416Sbostic #ifdef sun4c				/* XXX */
82064416Sbostic 			(*tp->t_stop)(tp, 0);
82164416Sbostic #else
82264416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
82364416Sbostic #endif
82464416Sbostic 		}
82564416Sbostic 		splx(s);
82664416Sbostic 		break;
82764416Sbostic 	case TIOCSCTTY:			/* become controlling tty */
82864416Sbostic 		/* Session ctty vnode pointer set in vnode layer. */
82964416Sbostic 		if (!SESS_LEADER(p) ||
83064416Sbostic 		    (p->p_session->s_ttyvp || tp->t_session) &&
83164416Sbostic 		    (tp->t_session != p->p_session))
83264416Sbostic 			return (EPERM);
83364416Sbostic 		tp->t_session = p->p_session;
83464416Sbostic 		tp->t_pgrp = p->p_pgrp;
83564416Sbostic 		p->p_session->s_ttyp = tp;
83664576Sbostic 		p->p_flag |= P_CONTROLT;
83764416Sbostic 		break;
83864416Sbostic 	case TIOCSPGRP: {		/* set pgrp of tty */
83964416Sbostic 		register struct pgrp *pgrp = pgfind(*(int *)data);
84064416Sbostic 
84164416Sbostic 		if (!isctty(p, tp))
84264416Sbostic 			return (ENOTTY);
84364416Sbostic 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
84464416Sbostic 			return (EPERM);
84564416Sbostic 		tp->t_pgrp = pgrp;
84664416Sbostic 		break;
84764416Sbostic 	}
84864416Sbostic 	case TIOCSWINSZ:		/* set window size */
84964416Sbostic 		if (bcmp((caddr_t)&tp->t_winsize, data,
85064416Sbostic 		    sizeof (struct winsize))) {
85164416Sbostic 			tp->t_winsize = *(struct winsize *)data;
85264416Sbostic 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
85364416Sbostic 		}
85464416Sbostic 		break;
85564416Sbostic 	default:
85664416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
85764576Sbostic 		return (ttcompat(tp, cmd, data, flag));
85864416Sbostic #else
85964416Sbostic 		return (-1);
86064416Sbostic #endif
86164416Sbostic 	}
86264416Sbostic 	return (0);
86364416Sbostic }
86464416Sbostic 
86564416Sbostic int
86664416Sbostic ttselect(device, rw, p)
86764416Sbostic 	dev_t device;
86864416Sbostic 	int rw;
86964416Sbostic 	struct proc *p;
87064416Sbostic {
87164416Sbostic 	register struct tty *tp;
87264416Sbostic 	int nread, s;
87364416Sbostic 
87464416Sbostic 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
87564416Sbostic 
87664416Sbostic 	s = spltty();
87764416Sbostic 	switch (rw) {
87864416Sbostic 	case FREAD:
87964416Sbostic 		nread = ttnread(tp);
88064416Sbostic 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
88164416Sbostic 		    !ISSET(tp->t_state, TS_CARR_ON))
88264416Sbostic 			goto win;
88364416Sbostic 		selrecord(p, &tp->t_rsel);
88464416Sbostic 		break;
88564416Sbostic 	case FWRITE:
88664416Sbostic 		if (tp->t_outq.c_cc <= tp->t_lowat) {
88764416Sbostic win:			splx(s);
88864416Sbostic 			return (1);
88964416Sbostic 		}
89064416Sbostic 		selrecord(p, &tp->t_wsel);
89164416Sbostic 		break;
89264416Sbostic 	}
89364416Sbostic 	splx(s);
89464416Sbostic 	return (0);
89564416Sbostic }
89664416Sbostic 
89764416Sbostic static int
89864416Sbostic ttnread(tp)
89964416Sbostic 	struct tty *tp;
90064416Sbostic {
90164416Sbostic 	int nread;
90264416Sbostic 
90364416Sbostic 	if (ISSET(tp->t_lflag, PENDIN))
90464416Sbostic 		ttypend(tp);
90564416Sbostic 	nread = tp->t_canq.c_cc;
90664416Sbostic 	if (!ISSET(tp->t_lflag, ICANON))
90764416Sbostic 		nread += tp->t_rawq.c_cc;
90864416Sbostic 	return (nread);
90964416Sbostic }
91064416Sbostic 
91164416Sbostic /*
91264416Sbostic  * Wait for output to drain.
91364416Sbostic  */
91464416Sbostic int
91564416Sbostic ttywait(tp)
91664416Sbostic 	register struct tty *tp;
91764416Sbostic {
91864416Sbostic 	int error, s;
91964416Sbostic 
92064416Sbostic 	error = 0;
92164416Sbostic 	s = spltty();
92264416Sbostic 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
92364416Sbostic 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
92464416Sbostic 	    && tp->t_oproc) {
92564416Sbostic 		(*tp->t_oproc)(tp);
92664416Sbostic 		SET(tp->t_state, TS_ASLEEP);
92764416Sbostic 		if (error = ttysleep(tp,
92864416Sbostic 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
92964416Sbostic 			break;
93064416Sbostic 	}
93164416Sbostic 	splx(s);
93264416Sbostic 	return (error);
93364416Sbostic }
93464416Sbostic 
93564416Sbostic /*
93664416Sbostic  * Flush if successfully wait.
93764416Sbostic  */
93864416Sbostic int
93964416Sbostic ttywflush(tp)
94064416Sbostic 	struct tty *tp;
94164416Sbostic {
94264416Sbostic 	int error;
94364416Sbostic 
94464416Sbostic 	if ((error = ttywait(tp)) == 0)
94564416Sbostic 		ttyflush(tp, FREAD);
94664416Sbostic 	return (error);
94764416Sbostic }
94864416Sbostic 
94964416Sbostic /*
95064416Sbostic  * Flush tty read and/or write queues, notifying anyone waiting.
95164416Sbostic  */
95264416Sbostic void
95364416Sbostic ttyflush(tp, rw)
95464416Sbostic 	register struct tty *tp;
95564416Sbostic 	int rw;
95664416Sbostic {
95764416Sbostic 	register int s;
95864416Sbostic 
95964416Sbostic 	s = spltty();
96064416Sbostic 	if (rw & FREAD) {
96164416Sbostic 		FLUSHQ(&tp->t_canq);
96264416Sbostic 		FLUSHQ(&tp->t_rawq);
96364416Sbostic 		tp->t_rocount = 0;
96464416Sbostic 		tp->t_rocol = 0;
96564416Sbostic 		CLR(tp->t_state, TS_LOCAL);
96664416Sbostic 		ttwakeup(tp);
96764416Sbostic 	}
96864416Sbostic 	if (rw & FWRITE) {
96964416Sbostic 		CLR(tp->t_state, TS_TTSTOP);
97064416Sbostic #ifdef sun4c						/* XXX */
97164416Sbostic 		(*tp->t_stop)(tp, rw);
97264416Sbostic #else
97364416Sbostic 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
97464416Sbostic #endif
97564416Sbostic 		FLUSHQ(&tp->t_outq);
97664416Sbostic 		wakeup((caddr_t)&tp->t_outq);
97764416Sbostic 		selwakeup(&tp->t_wsel);
97864416Sbostic 	}
97964416Sbostic 	splx(s);
98064416Sbostic }
98164416Sbostic 
98264416Sbostic /*
98364416Sbostic  * Copy in the default termios characters.
98464416Sbostic  */
98564416Sbostic void
98664416Sbostic ttychars(tp)
98764416Sbostic 	struct tty *tp;
98864416Sbostic {
98964416Sbostic 
99064416Sbostic 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
99164416Sbostic }
99264416Sbostic 
99364416Sbostic /*
99464416Sbostic  * Send stop character on input overflow.
99564416Sbostic  */
99664416Sbostic static void
99764416Sbostic ttyblock(tp)
99864416Sbostic 	register struct tty *tp;
99964416Sbostic {
100064416Sbostic 	register int total;
100164416Sbostic 
100264416Sbostic 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
100364416Sbostic 	if (tp->t_rawq.c_cc > TTYHOG) {
100464416Sbostic 		ttyflush(tp, FREAD | FWRITE);
100564416Sbostic 		CLR(tp->t_state, TS_TBLOCK);
100664416Sbostic 	}
100764416Sbostic 	/*
100864416Sbostic 	 * Block further input iff: current input > threshold
100964416Sbostic 	 * AND input is available to user program.
101064416Sbostic 	 */
101164416Sbostic 	if (total >= TTYHOG / 2 &&
101264416Sbostic 	    !ISSET(tp->t_state, TS_TBLOCK) &&
101364416Sbostic 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
101464416Sbostic 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
101564416Sbostic 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
101664416Sbostic 			SET(tp->t_state, TS_TBLOCK);
101764416Sbostic 			ttstart(tp);
101864416Sbostic 		}
101964416Sbostic 	}
102064416Sbostic }
102164416Sbostic 
102264416Sbostic void
102364416Sbostic ttrstrt(tp_arg)
102464416Sbostic 	void *tp_arg;
102564416Sbostic {
102664416Sbostic 	struct tty *tp;
102764416Sbostic 	int s;
102864416Sbostic 
102964416Sbostic #ifdef DIAGNOSTIC
103064416Sbostic 	if (tp_arg == NULL)
103164416Sbostic 		panic("ttrstrt");
103264416Sbostic #endif
103364416Sbostic 	tp = tp_arg;
103464416Sbostic 	s = spltty();
103564416Sbostic 
103664416Sbostic 	CLR(tp->t_state, TS_TIMEOUT);
103764416Sbostic 	ttstart(tp);
103864416Sbostic 
103964416Sbostic 	splx(s);
104064416Sbostic }
104164416Sbostic 
104264416Sbostic int
104364416Sbostic ttstart(tp)
104464416Sbostic 	struct tty *tp;
104564416Sbostic {
104664416Sbostic 
104764416Sbostic 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
104864416Sbostic 		(*tp->t_oproc)(tp);
104964416Sbostic 	return (0);
105064416Sbostic }
105164416Sbostic 
105264416Sbostic /*
105364416Sbostic  * "close" a line discipline
105464416Sbostic  */
105564416Sbostic int
105664416Sbostic ttylclose(tp, flag)
105764416Sbostic 	struct tty *tp;
105864416Sbostic 	int flag;
105964416Sbostic {
106064416Sbostic 
106164416Sbostic 	if (flag & IO_NDELAY)
106264416Sbostic 		ttyflush(tp, FREAD | FWRITE);
106364416Sbostic 	else
106464416Sbostic 		ttywflush(tp);
106564416Sbostic 	return (0);
106664416Sbostic }
106764416Sbostic 
106864416Sbostic /*
106964416Sbostic  * Handle modem control transition on a tty.
107064416Sbostic  * Flag indicates new state of carrier.
107164416Sbostic  * Returns 0 if the line should be turned off, otherwise 1.
107264416Sbostic  */
107364416Sbostic int
107464416Sbostic ttymodem(tp, flag)
107564416Sbostic 	register struct tty *tp;
107664416Sbostic 	int flag;
107764416Sbostic {
107864416Sbostic 
107964416Sbostic 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
108064416Sbostic 		/*
108164416Sbostic 		 * MDMBUF: do flow control according to carrier flag
108264416Sbostic 		 */
108364416Sbostic 		if (flag) {
108464416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
108564416Sbostic 			ttstart(tp);
108664416Sbostic 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
108764416Sbostic 			SET(tp->t_state, TS_TTSTOP);
108864416Sbostic #ifdef sun4c						/* XXX */
108964416Sbostic 			(*tp->t_stop)(tp, 0);
109064416Sbostic #else
109164416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
109264416Sbostic #endif
109364416Sbostic 		}
109464416Sbostic 	} else if (flag == 0) {
109564416Sbostic 		/*
109664416Sbostic 		 * Lost carrier.
109764416Sbostic 		 */
109864416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
109964416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN) &&
110064416Sbostic 		    !ISSET(tp->t_cflag, CLOCAL)) {
110164416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
110264416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
110364416Sbostic 			ttyflush(tp, FREAD | FWRITE);
110464416Sbostic 			return (0);
110564416Sbostic 		}
110664416Sbostic 	} else {
110764416Sbostic 		/*
110864416Sbostic 		 * Carrier now on.
110964416Sbostic 		 */
111064416Sbostic 		SET(tp->t_state, TS_CARR_ON);
111164416Sbostic 		ttwakeup(tp);
111264416Sbostic 	}
111364416Sbostic 	return (1);
111464416Sbostic }
111564416Sbostic 
111664416Sbostic /*
111764416Sbostic  * Default modem control routine (for other line disciplines).
111864416Sbostic  * Return argument flag, to turn off device on carrier drop.
111964416Sbostic  */
112064416Sbostic int
112164416Sbostic nullmodem(tp, flag)
112264416Sbostic 	register struct tty *tp;
112364416Sbostic 	int flag;
112464416Sbostic {
112564416Sbostic 
112664416Sbostic 	if (flag)
112764416Sbostic 		SET(tp->t_state, TS_CARR_ON);
112864416Sbostic 	else {
112964416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
113064416Sbostic 		if (!ISSET(tp->t_cflag, CLOCAL)) {
113164416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
113264416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
113364416Sbostic 			return (0);
113464416Sbostic 		}
113564416Sbostic 	}
113664416Sbostic 	return (1);
113764416Sbostic }
113864416Sbostic 
113964416Sbostic /*
114064416Sbostic  * Reinput pending characters after state switch
114164416Sbostic  * call at spltty().
114264416Sbostic  */
114364416Sbostic void
114464416Sbostic ttypend(tp)
114564416Sbostic 	register struct tty *tp;
114664416Sbostic {
114764416Sbostic 	struct clist tq;
114864416Sbostic 	register c;
114964416Sbostic 
115064416Sbostic 	CLR(tp->t_lflag, PENDIN);
115164416Sbostic 	SET(tp->t_state, TS_TYPEN);
115264416Sbostic 	tq = tp->t_rawq;
115364416Sbostic 	tp->t_rawq.c_cc = 0;
115464416Sbostic 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
115564416Sbostic 	while ((c = getc(&tq)) >= 0)
115664416Sbostic 		ttyinput(c, tp);
115764416Sbostic 	CLR(tp->t_state, TS_TYPEN);
115864416Sbostic }
115964416Sbostic 
116064416Sbostic /*
116149380Skarels  * Process a read call on a tty device.
11627502Sroot  */
116364416Sbostic int
116437584Smarc ttread(tp, uio, flag)
11657625Ssam 	register struct tty *tp;
11667722Swnj 	struct uio *uio;
116752485Storek 	int flag;
11687502Sroot {
11697502Sroot 	register struct clist *qp;
117035811Smarc 	register int c;
117141383Smarc 	register long lflag;
117235811Smarc 	register u_char *cc = tp->t_cc;
117347545Skarels 	register struct proc *p = curproc;
11749859Ssam 	int s, first, error = 0;
11757502Sroot 
117664416Sbostic loop:	lflag = tp->t_lflag;
117737584Smarc 	s = spltty();
11789578Ssam 	/*
117964416Sbostic 	 * take pending input first
11809578Ssam 	 */
118164416Sbostic 	if (ISSET(lflag, PENDIN))
11827502Sroot 		ttypend(tp);
11839859Ssam 	splx(s);
118440712Skarels 
11859578Ssam 	/*
11869578Ssam 	 * Hang process if it's in the background.
11879578Ssam 	 */
118847545Skarels 	if (isbackground(p, tp)) {
118947545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
119047545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
119164576Sbostic 		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
11928520Sroot 			return (EIO);
119347545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119464416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
119540712Skarels 			return (error);
119623165Sbloom 		goto loop;
11977502Sroot 	}
119840712Skarels 
11999578Ssam 	/*
120035811Smarc 	 * If canonical, use the canonical queue,
120135811Smarc 	 * else use the raw queue.
120237584Smarc 	 *
120347545Skarels 	 * (should get rid of clists...)
12049578Ssam 	 */
120564416Sbostic 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
120640712Skarels 
12079578Ssam 	/*
120840712Skarels 	 * If there is no input, sleep on rawq
120940712Skarels 	 * awaiting hardware receipt and notification.
121040712Skarels 	 * If we have data, we don't need to check for carrier.
12119578Ssam 	 */
121217545Skarels 	s = spltty();
12139578Ssam 	if (qp->c_cc <= 0) {
121440712Skarels 		int carrier;
121540712Skarels 
121664416Sbostic 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
121764416Sbostic 		    ISSET(tp->t_cflag, CLOCAL);
121864416Sbostic 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12199859Ssam 			splx(s);
122040712Skarels 			return (0);	/* EOF */
12217502Sroot 		}
122237728Smckusick 		if (flag & IO_NDELAY) {
122337584Smarc 			splx(s);
122437584Smarc 			return (EWOULDBLOCK);
122537584Smarc 		}
122664416Sbostic 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
122740712Skarels 		    carrier ? ttyin : ttopen, 0);
12289859Ssam 		splx(s);
122943377Smarc 		if (error)
123040712Skarels 			return (error);
12319578Ssam 		goto loop;
12329578Ssam 	}
12339859Ssam 	splx(s);
123440712Skarels 
12359578Ssam 	/*
123635811Smarc 	 * Input present, check for input mapping and processing.
12379578Ssam 	 */
12389578Ssam 	first = 1;
12399578Ssam 	while ((c = getc(qp)) >= 0) {
12409578Ssam 		/*
124135811Smarc 		 * delayed suspend (^Y)
12429578Ssam 		 */
124364416Sbostic 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
124442882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12459578Ssam 			if (first) {
124664416Sbostic 				if (error = ttysleep(tp,
124764416Sbostic 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
124840712Skarels 					break;
12499578Ssam 				goto loop;
12509578Ssam 			}
12519578Ssam 			break;
12527502Sroot 		}
12539578Ssam 		/*
125435811Smarc 		 * Interpret EOF only in canonical mode.
12559578Ssam 		 */
125664416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12579578Ssam 			break;
12589578Ssam 		/*
12599578Ssam 		 * Give user character.
12609578Ssam 		 */
126140712Skarels  		error = ureadc(c, uio);
12629578Ssam 		if (error)
12639578Ssam 			break;
126414938Smckusick  		if (uio->uio_resid == 0)
12659578Ssam 			break;
12669578Ssam 		/*
126735811Smarc 		 * In canonical mode check for a "break character"
12689578Ssam 		 * marking the end of a "line of input".
12699578Ssam 		 */
127064416Sbostic 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
12719578Ssam 			break;
12729578Ssam 		first = 0;
12737502Sroot 	}
12749578Ssam 	/*
12759578Ssam 	 * Look to unblock output now that (presumably)
12769578Ssam 	 * the input queue has gone down.
12779578Ssam 	 */
127852485Storek 	s = spltty();
127964416Sbostic 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
128047545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
128147545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
128264416Sbostic 			CLR(tp->t_state, TS_TBLOCK);
12837502Sroot 			ttstart(tp);
12847502Sroot 		}
128535811Smarc 	}
128652485Storek 	splx(s);
12878520Sroot 	return (error);
12887502Sroot }
12897502Sroot 
12907502Sroot /*
129164416Sbostic  * Check the output queue on tp for space for a kernel message (from uprintf
129264416Sbostic  * or tprintf).  Allow some space over the normal hiwater mark so we don't
129364416Sbostic  * lose messages due to normal flow control, but don't let the tty run amok.
129464416Sbostic  * Sleeps here are not interruptible, but we return prematurely if new signals
129564416Sbostic  * arrive.
129625391Skarels  */
129764416Sbostic int
129825391Skarels ttycheckoutq(tp, wait)
129925391Skarels 	register struct tty *tp;
130025391Skarels 	int wait;
130125391Skarels {
130230695Skarels 	int hiwat, s, oldsig;
130325391Skarels 
130435811Smarc 	hiwat = tp->t_hiwat;
130525391Skarels 	s = spltty();
130664576Sbostic 	oldsig = wait ? curproc->p_siglist : 0;
130725391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
130829946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130929946Skarels 			ttstart(tp);
131064576Sbostic 			if (wait == 0 || curproc->p_siglist != oldsig) {
131129946Skarels 				splx(s);
131229946Skarels 				return (0);
131329946Skarels 			}
131454782Storek 			timeout((void (*)__P((void *)))wakeup,
131554782Storek 			    (void *)&tp->t_outq, hz);
131664416Sbostic 			SET(tp->t_state, TS_ASLEEP);
131730695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
131825391Skarels 		}
131925391Skarels 	splx(s);
132025391Skarels 	return (1);
132125391Skarels }
132225391Skarels 
132325391Skarels /*
132449380Skarels  * Process a write call on a tty device.
13257502Sroot  */
132664416Sbostic int
132737584Smarc ttwrite(tp, uio, flag)
13287625Ssam 	register struct tty *tp;
13299578Ssam 	register struct uio *uio;
133052485Storek 	int flag;
13317502Sroot {
13327502Sroot 	register char *cp;
133364416Sbostic 	register int cc, ce;
133464416Sbostic 	register struct proc *p;
13359578Ssam 	int i, hiwat, cnt, error, s;
13367502Sroot 	char obuf[OBUFSIZ];
13377502Sroot 
133835811Smarc 	hiwat = tp->t_hiwat;
13399578Ssam 	cnt = uio->uio_resid;
13409578Ssam 	error = 0;
134164878Smckusick 	cc = 0;
13427502Sroot loop:
134337584Smarc 	s = spltty();
134464416Sbostic 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
134564416Sbostic 	    !ISSET(tp->t_cflag, CLOCAL)) {
134664416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN)) {
134737584Smarc 			splx(s);
134837584Smarc 			return (EIO);
134937728Smckusick 		} else if (flag & IO_NDELAY) {
135037584Smarc 			splx(s);
135140712Skarels 			error = EWOULDBLOCK;
135240712Skarels 			goto out;
135337584Smarc 		} else {
135464416Sbostic 			/* Sleep awaiting carrier. */
135564416Sbostic 			error = ttysleep(tp,
135664416Sbostic 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
135737584Smarc 			splx(s);
135843377Smarc 			if (error)
135940712Skarels 				goto out;
136037584Smarc 			goto loop;
136137584Smarc 		}
136237584Smarc 	}
136337584Smarc 	splx(s);
13649578Ssam 	/*
13659578Ssam 	 * Hang the process if it's in the background.
13669578Ssam 	 */
136764416Sbostic 	p = curproc;
136864416Sbostic 	if (isbackground(p, tp) &&
136964576Sbostic 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
137047545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
137147545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
137247545Skarels 	     p->p_pgrp->pg_jobc) {
137347545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
137464416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
137540712Skarels 			goto out;
137621776Sbloom 		goto loop;
13777502Sroot 	}
13789578Ssam 	/*
137964416Sbostic 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
138064416Sbostic 	 * output translation.  Keep track of high water mark, sleep on
138164416Sbostic 	 * overflow awaiting device aid in acquiring new space.
13829578Ssam 	 */
138364878Smckusick 	while (uio->uio_resid > 0 || cc > 0) {
138464416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO)) {
138540712Skarels 			uio->uio_resid = 0;
138640712Skarels 			return (0);
138740712Skarels 		}
138840712Skarels 		if (tp->t_outq.c_cc > hiwat)
138932067Skarels 			goto ovhiwat;
13909578Ssam 		/*
139164416Sbostic 		 * Grab a hunk of data from the user, unless we have some
139264416Sbostic 		 * leftover from last time.
13939578Ssam 		 */
13947822Sroot 		if (cc == 0) {
139540712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139640712Skarels 			cp = obuf;
139740712Skarels 			error = uiomove(cp, cc, uio);
139840712Skarels 			if (error) {
139940712Skarels 				cc = 0;
140040712Skarels 				break;
140140712Skarels 			}
14027822Sroot 		}
14039578Ssam 		/*
14049578Ssam 		 * If nothing fancy need be done, grab those characters we
14059578Ssam 		 * can handle without any of ttyoutput's processing and
14069578Ssam 		 * just transfer them to the output q.  For those chars
14079578Ssam 		 * which require special processing (as indicated by the
140864416Sbostic 		 * bits in char_type), call ttyoutput.  After processing
14099578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14109578Ssam 		 * immediately.
14119578Ssam 		 */
14129578Ssam 		while (cc > 0) {
141364416Sbostic 			if (!ISSET(tp->t_oflag, OPOST))
14147502Sroot 				ce = cc;
14157502Sroot 			else {
141664416Sbostic 				ce = cc - scanc((u_int)cc, (u_char *)cp,
141764416Sbostic 				   (u_char *)char_type, CCLASSMASK);
14189578Ssam 				/*
14199578Ssam 				 * If ce is zero, then we're processing
14209578Ssam 				 * a special character through ttyoutput.
14219578Ssam 				 */
14229578Ssam 				if (ce == 0) {
14237502Sroot 					tp->t_rocount = 0;
14247502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142564416Sbostic 						/* No Clists, wait a bit. */
142664416Sbostic 						ttstart(tp);
142764416Sbostic 						if (error = ttysleep(tp, &lbolt,
142864416Sbostic 						    TTOPRI | PCATCH, ttybuf, 0))
142964416Sbostic 							break;
143064416Sbostic 						goto loop;
14317502Sroot 					}
143264416Sbostic 					cp++;
143364416Sbostic 					cc--;
143464416Sbostic 					if (ISSET(tp->t_lflag, FLUSHO) ||
14359578Ssam 					    tp->t_outq.c_cc > hiwat)
14367502Sroot 						goto ovhiwat;
14379578Ssam 					continue;
14387502Sroot 				}
14397502Sroot 			}
14409578Ssam 			/*
144164416Sbostic 			 * A bunch of normal characters have been found.
144264416Sbostic 			 * Transfer them en masse to the output queue and
14439578Ssam 			 * continue processing at the top of the loop.
14449578Ssam 			 * If there are any further characters in this
14459578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14469578Ssam 			 * requiring special handling by ttyoutput.
14479578Ssam 			 */
14487502Sroot 			tp->t_rocount = 0;
14499578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14509578Ssam 			ce -= i;
145164530Sbostic 			tp->t_column += ce;
14529578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
145335811Smarc 			tp->t_outcc += ce;
14549578Ssam 			if (i > 0) {
145564416Sbostic 				/* No Clists, wait a bit. */
14567502Sroot 				ttstart(tp);
145764416Sbostic 				if (error = ttysleep(tp,
145864416Sbostic 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
145940712Skarels 					break;
146021776Sbloom 				goto loop;
14617502Sroot 			}
146264416Sbostic 			if (ISSET(tp->t_lflag, FLUSHO) ||
146364416Sbostic 			    tp->t_outq.c_cc > hiwat)
146440712Skarels 				break;
14657502Sroot 		}
146635811Smarc 		ttstart(tp);
14677502Sroot 	}
146840712Skarels out:
146940712Skarels 	/*
147064416Sbostic 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
147164416Sbostic 	 * offset and iov pointers have moved forward, but it doesn't matter
147264416Sbostic 	 * (the call will either return short or restart with a new uio).
147340712Skarels 	 */
147440712Skarels 	uio->uio_resid += cc;
14758520Sroot 	return (error);
147640712Skarels 
14777502Sroot ovhiwat:
147832067Skarels 	ttstart(tp);
147932067Skarels 	s = spltty();
14809578Ssam 	/*
148135811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
148232067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14839578Ssam 	 */
14847502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14859578Ssam 		splx(s);
14867502Sroot 		goto loop;
14877502Sroot 	}
148837728Smckusick 	if (flag & IO_NDELAY) {
148917545Skarels 		splx(s);
149040712Skarels 		uio->uio_resid += cc;
149164416Sbostic 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14927502Sroot 	}
149364416Sbostic 	SET(tp->t_state, TS_ASLEEP);
149464416Sbostic 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14959578Ssam 	splx(s);
149643377Smarc 	if (error)
149740712Skarels 		goto out;
14987502Sroot 	goto loop;
14997502Sroot }
15007502Sroot 
15017502Sroot /*
15027502Sroot  * Rubout one character from the rawq of tp
15037502Sroot  * as cleanly as possible.
15047502Sroot  */
150564416Sbostic void
15067502Sroot ttyrub(c, tp)
150764416Sbostic 	register int c;
15087625Ssam 	register struct tty *tp;
15097502Sroot {
15107502Sroot 	register char *cp;
15117502Sroot 	register int savecol;
151264416Sbostic 	int tabc, s;
15137502Sroot 
151464416Sbostic 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15157502Sroot 		return;
151664416Sbostic 	CLR(tp->t_lflag, FLUSHO);
151764416Sbostic 	if (ISSET(tp->t_lflag, ECHOE)) {
15187502Sroot 		if (tp->t_rocount == 0) {
15197502Sroot 			/*
15207502Sroot 			 * Screwed by ttwrite; retype
15217502Sroot 			 */
15227502Sroot 			ttyretype(tp);
15237502Sroot 			return;
15247502Sroot 		}
152564416Sbostic 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15267502Sroot 			ttyrubo(tp, 2);
152764576Sbostic 		else {
152864576Sbostic 			CLR(c, ~TTY_CHARMASK);
152964576Sbostic 			switch (CCLASS(c)) {
153064576Sbostic 			case ORDINARY:
153164576Sbostic 				ttyrubo(tp, 1);
153264576Sbostic 				break;
153364576Sbostic 			case BACKSPACE:
153464576Sbostic 			case CONTROL:
153564576Sbostic 			case NEWLINE:
153664576Sbostic 			case RETURN:
153764576Sbostic 			case VTAB:
153864576Sbostic 				if (ISSET(tp->t_lflag, ECHOCTL))
153964576Sbostic 					ttyrubo(tp, 2);
154064576Sbostic 				break;
154164576Sbostic 			case TAB:
154264576Sbostic 				if (tp->t_rocount < tp->t_rawq.c_cc) {
154364576Sbostic 					ttyretype(tp);
154464576Sbostic 					return;
154564576Sbostic 				}
154664576Sbostic 				s = spltty();
154764576Sbostic 				savecol = tp->t_column;
154864576Sbostic 				SET(tp->t_state, TS_CNTTB);
154964576Sbostic 				SET(tp->t_lflag, FLUSHO);
155064576Sbostic 				tp->t_column = tp->t_rocol;
155164576Sbostic 				cp = tp->t_rawq.c_cf;
155264576Sbostic 				if (cp)
155364576Sbostic 					tabc = *cp;	/* XXX FIX NEXTC */
155464576Sbostic 				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
155564576Sbostic 					ttyecho(tabc, tp);
155664576Sbostic 				CLR(tp->t_lflag, FLUSHO);
155764576Sbostic 				CLR(tp->t_state, TS_CNTTB);
155864576Sbostic 				splx(s);
155964416Sbostic 
156064576Sbostic 				/* savecol will now be length of the tab. */
156164576Sbostic 				savecol -= tp->t_column;
156264576Sbostic 				tp->t_column += savecol;
156364576Sbostic 				if (savecol > 8)
156464576Sbostic 					savecol = 8;	/* overflow screw */
156564576Sbostic 				while (--savecol >= 0)
156664576Sbostic 					(void)ttyoutput('\b', tp);
156764576Sbostic 				break;
156864576Sbostic 			default:			/* XXX */
156964416Sbostic #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
157064576Sbostic 				(void)printf(PANICSTR, c, CCLASS(c));
157164416Sbostic #ifdef notdef
157264576Sbostic 				panic(PANICSTR, c, CCLASS(c));
157364416Sbostic #endif
157464576Sbostic 			}
157535811Smarc 		}
157664416Sbostic 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
157764416Sbostic 		if (!ISSET(tp->t_state, TS_ERASE)) {
157864416Sbostic 			SET(tp->t_state, TS_ERASE);
157964416Sbostic 			(void)ttyoutput('\\', tp);
15807502Sroot 		}
15817502Sroot 		ttyecho(c, tp);
15827502Sroot 	} else
158335811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
158464416Sbostic 	--tp->t_rocount;
15857502Sroot }
15867502Sroot 
15877502Sroot /*
158864416Sbostic  * Back over cnt characters, erasing them.
15897502Sroot  */
159064416Sbostic static void
15917502Sroot ttyrubo(tp, cnt)
15927625Ssam 	register struct tty *tp;
15937625Ssam 	int cnt;
15947502Sroot {
15957502Sroot 
159664416Sbostic 	while (cnt-- > 0) {
159764416Sbostic 		(void)ttyoutput('\b', tp);
159864416Sbostic 		(void)ttyoutput(' ', tp);
159964416Sbostic 		(void)ttyoutput('\b', tp);
160064416Sbostic 	}
16017502Sroot }
16027502Sroot 
16037502Sroot /*
160464416Sbostic  * ttyretype --
160564416Sbostic  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
160664416Sbostic  *	been checked.
16077502Sroot  */
160864416Sbostic void
16097502Sroot ttyretype(tp)
16107625Ssam 	register struct tty *tp;
16117502Sroot {
16127502Sroot 	register char *cp;
161335811Smarc 	int s, c;
16147502Sroot 
161564416Sbostic 	/* Echo the reprint character. */
161635811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
161735811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
161864416Sbostic 
161964416Sbostic 	(void)ttyoutput('\n', tp);
162064416Sbostic 
162164416Sbostic 	/*
162264416Sbostic 	 * XXX
162364416Sbostic 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162464416Sbostic 	 * BIT OF FIRST CHAR.
162564416Sbostic 	 */
162617545Skarels 	s = spltty();
162764416Sbostic 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
162864416Sbostic 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
162935811Smarc 		ttyecho(c, tp);
163064416Sbostic 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
163164416Sbostic 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
163235811Smarc 		ttyecho(c, tp);
163364416Sbostic 	CLR(tp->t_state, TS_ERASE);
16347502Sroot 	splx(s);
163564416Sbostic 
16367502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16377502Sroot 	tp->t_rocol = 0;
16387502Sroot }
16397502Sroot 
16407502Sroot /*
164135811Smarc  * Echo a typed character to the terminal.
16427502Sroot  */
164364416Sbostic static void
16447502Sroot ttyecho(c, tp)
164564416Sbostic 	register int c;
16467625Ssam 	register struct tty *tp;
16477502Sroot {
164864416Sbostic 
164964416Sbostic 	if (!ISSET(tp->t_state, TS_CNTTB))
165064416Sbostic 		CLR(tp->t_lflag, FLUSHO);
165164416Sbostic 	if ((!ISSET(tp->t_lflag, ECHO) &&
165264416Sbostic 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
165364416Sbostic 	    ISSET(tp->t_lflag, EXTPROC))
16547502Sroot 		return;
165564416Sbostic 	if (ISSET(tp->t_lflag, ECHOCTL) &&
165664576Sbostic 	    (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
165764576Sbostic 	    ISSET(c, TTY_CHARMASK) == 0177)) {
165864416Sbostic 		(void)ttyoutput('^', tp);
165964576Sbostic 		CLR(c, ~TTY_CHARMASK);
166064416Sbostic 		if (c == 0177)
166164416Sbostic 			c = '?';
166264416Sbostic 		else
166364416Sbostic 			c += 'A' - 1;
16647502Sroot 	}
166564416Sbostic 	(void)ttyoutput(c, tp);
16667502Sroot }
16677502Sroot 
16687502Sroot /*
166949380Skarels  * Wake up any readers on a tty.
167049380Skarels  */
167164416Sbostic void
16727502Sroot ttwakeup(tp)
167347545Skarels 	register struct tty *tp;
16747502Sroot {
16757502Sroot 
167652522Smckusick 	selwakeup(&tp->t_rsel);
167764416Sbostic 	if (ISSET(tp->t_state, TS_ASYNC))
167864416Sbostic 		pgsignal(tp->t_pgrp, SIGIO, 1);
16797502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16807502Sroot }
168135811Smarc 
168235811Smarc /*
168348439Skarels  * Look up a code for a specified speed in a conversion table;
168448439Skarels  * used by drivers to map software speed values to hardware parameters.
168548439Skarels  */
168664416Sbostic int
168748439Skarels ttspeedtab(speed, table)
168852485Storek 	int speed;
168948439Skarels 	register struct speedtab *table;
169048439Skarels {
169148439Skarels 
169248439Skarels 	for ( ; table->sp_speed != -1; table++)
169348439Skarels 		if (table->sp_speed == speed)
169448439Skarels 			return (table->sp_code);
169548439Skarels 	return (-1);
169648439Skarels }
169748439Skarels 
169848439Skarels /*
169964416Sbostic  * Set tty hi and low water marks.
170035811Smarc  *
170135811Smarc  * Try to arrange the dynamics so there's about one second
170235811Smarc  * from hi to low water.
170364416Sbostic  *
170435811Smarc  */
170564416Sbostic void
170635811Smarc ttsetwater(tp)
170735811Smarc 	struct tty *tp;
170835811Smarc {
170964416Sbostic 	register int cps, x;
171035811Smarc 
171164416Sbostic #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
171264416Sbostic 
171364416Sbostic 	cps = tp->t_ospeed / 10;
171464416Sbostic 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
171535811Smarc 	x += cps;
171664416Sbostic 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
171735811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
171864416Sbostic #undef	CLAMP
171935811Smarc }
172035811Smarc 
172139407Smarc /*
172239407Smarc  * Report on state of foreground process group.
172339407Smarc  */
172464416Sbostic void
172539407Smarc ttyinfo(tp)
172649907Sbostic 	register struct tty *tp;
172739407Smarc {
172849907Sbostic 	register struct proc *p, *pick;
172941177Smarc 	struct timeval utime, stime;
173049907Sbostic 	int tmp;
173139407Smarc 
173264416Sbostic 	if (ttycheckoutq(tp,0) == 0)
173339407Smarc 		return;
173449907Sbostic 
173549907Sbostic 	/* Print load average. */
173652666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
173749907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
173849907Sbostic 
173939555Smarc 	if (tp->t_session == NULL)
174049907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
174141177Smarc 	else if (tp->t_pgrp == NULL)
174249907Sbostic 		ttyprintf(tp, "no foreground process group\n");
174341177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
174449907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174539407Smarc 	else {
174649907Sbostic 		/* Pick interesting process. */
174749907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
174841177Smarc 			if (proc_compare(pick, p))
174941177Smarc 				pick = p;
175049907Sbostic 
175149907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
175249907Sbostic 		    pick->p_stat == SRUN ? "running" :
175349907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
175449907Sbostic 
175554782Storek 		calcru(pick, &utime, &stime, NULL);
175639407Smarc 
175749907Sbostic 		/* Print user time. */
175849907Sbostic 		ttyprintf(tp, "%d.%02du ",
175949907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
176041177Smarc 
176149907Sbostic 		/* Print system time. */
176249907Sbostic 		ttyprintf(tp, "%d.%02ds ",
176349907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176449907Sbostic 
176549907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
176649907Sbostic 		/* Print percentage cpu, resident set size. */
176749907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
176849907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
176952485Storek 		    tmp / 100,
177052485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
177165549Smckusick #ifdef pmap_resident_count
177265549Smckusick 			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
177365549Smckusick #else
177465549Smckusick 			pgtok(pick->p_vmspace->vm_rssize)
177565549Smckusick #endif
177665549Smckusick 			);
177741177Smarc 	}
177849907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
177941177Smarc }
178041177Smarc 
178141177Smarc /*
178241177Smarc  * Returns 1 if p2 is "better" than p1
178341177Smarc  *
178441177Smarc  * The algorithm for picking the "interesting" process is thus:
178541177Smarc  *
178664576Sbostic  *	1) Only foreground processes are eligible - implied.
178764576Sbostic  *	2) Runnable processes are favored over anything else.  The runner
178864576Sbostic  *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
178941177Smarc  *	   broken by picking the highest pid.
179064576Sbostic  *	3) The sleeper with the shortest sleep time is next.  With ties,
179164576Sbostic  *	   we pick out just "short-term" sleepers (P_SINTR == 0).
179264576Sbostic  *	4) Further ties are broken by picking the highest pid.
179341177Smarc  */
179464576Sbostic #define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179545723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179645723Smckusick #define ONLYA   2
179745723Smckusick #define ONLYB   1
179845723Smckusick #define BOTH    3
179964576Sbostic 
180049907Sbostic static int
180141177Smarc proc_compare(p1, p2)
180241177Smarc 	register struct proc *p1, *p2;
180341177Smarc {
180441177Smarc 
180541177Smarc 	if (p1 == NULL)
180641177Smarc 		return (1);
180741177Smarc 	/*
180841177Smarc 	 * see if at least one of them is runnable
180941177Smarc 	 */
181064576Sbostic 	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
181145723Smckusick 	case ONLYA:
181245723Smckusick 		return (0);
181345723Smckusick 	case ONLYB:
181441177Smarc 		return (1);
181545723Smckusick 	case BOTH:
181641177Smarc 		/*
181741177Smarc 		 * tie - favor one with highest recent cpu utilization
181841177Smarc 		 */
181964576Sbostic 		if (p2->p_estcpu > p1->p_estcpu)
182041177Smarc 			return (1);
182164576Sbostic 		if (p1->p_estcpu > p2->p_estcpu)
182241177Smarc 			return (0);
182341177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182441177Smarc 	}
182545723Smckusick 	/*
182645723Smckusick  	 * weed out zombies
182745723Smckusick 	 */
182845723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
182945723Smckusick 	case ONLYA:
183045723Smckusick 		return (1);
183145723Smckusick 	case ONLYB:
183245723Smckusick 		return (0);
183345723Smckusick 	case BOTH:
183445723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183545723Smckusick 	}
183664416Sbostic 	/*
183741177Smarc 	 * pick the one with the smallest sleep time
183841177Smarc 	 */
183941177Smarc 	if (p2->p_slptime > p1->p_slptime)
184041177Smarc 		return (0);
184141177Smarc 	if (p1->p_slptime > p2->p_slptime)
184241177Smarc 		return (1);
184341177Smarc 	/*
184441177Smarc 	 * favor one sleeping in a non-interruptible sleep
184541177Smarc 	 */
184664576Sbostic 	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
184741177Smarc 		return (1);
184864576Sbostic 	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
184941177Smarc 		return (0);
185047545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
185141177Smarc }
185245723Smckusick 
185339555Smarc /*
185439555Smarc  * Output char to tty; console putchar style.
185539555Smarc  */
185664416Sbostic int
185739555Smarc tputchar(c, tp)
185839555Smarc 	int c;
185939555Smarc 	struct tty *tp;
186039555Smarc {
186164416Sbostic 	register int s;
186239555Smarc 
186364416Sbostic 	s = spltty();
186464416Sbostic 	if (ISSET(tp->t_state,
186564416Sbostic 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
186639555Smarc 		splx(s);
186764416Sbostic 		return (-1);
186839555Smarc 	}
186964416Sbostic 	if (c == '\n')
187064416Sbostic 		(void)ttyoutput('\r', tp);
187164416Sbostic 	(void)ttyoutput(c, tp);
187264416Sbostic 	ttstart(tp);
187339555Smarc 	splx(s);
187464416Sbostic 	return (0);
187539555Smarc }
187643377Smarc 
187744419Smarc /*
187864416Sbostic  * Sleep on chan, returning ERESTART if tty changed while we napped and
187964416Sbostic  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
188064416Sbostic  * the tty is revoked, restarting a pending call will redo validation done
188164416Sbostic  * at the start of the call.
188244419Smarc  */
188364416Sbostic int
188443377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188543377Smarc 	struct tty *tp;
188664416Sbostic 	void *chan;
188764416Sbostic 	int pri, timo;
188843377Smarc 	char *wmesg;
188943377Smarc {
189043377Smarc 	int error;
189164416Sbostic 	short gen;
189243377Smarc 
189364416Sbostic 	gen = tp->t_gen;
189443377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
189543377Smarc 		return (error);
189664416Sbostic 	return (tp->t_gen == gen ? 0 : ERESTART);
189743377Smarc }
1898