xref: /csrg-svn/sys/kern/tty.c (revision 65549)
149594Sbostic /*-
263178Sbostic  * Copyright (c) 1982, 1986, 1990, 1991, 1993
363178Sbostic  *	The Regents of the University of California.  All rights reserved.
449594Sbostic  * All rights reserved.
523387Smckusick  *
649594Sbostic  * %sccs.include.redist.c%
749594Sbostic  *
8*65549Smckusick  *	@(#)tty.c	8.7 (Berkeley) 01/06/94
923387Smckusick  */
1039Sbill 
1156517Sbostic #include <sys/param.h>
1256517Sbostic #include <sys/systm.h>
1356517Sbostic #include <sys/ioctl.h>
1456517Sbostic #include <sys/proc.h>
1564416Sbostic #define	TTYDEFCHARS
1656517Sbostic #include <sys/tty.h>
1764416Sbostic #undef	TTYDEFCHARS
1856517Sbostic #include <sys/file.h>
1956517Sbostic #include <sys/conf.h>
2056517Sbostic #include <sys/dkstat.h>
2156517Sbostic #include <sys/uio.h>
2256517Sbostic #include <sys/kernel.h>
2356517Sbostic #include <sys/vnode.h>
2456517Sbostic #include <sys/syslog.h>
2539Sbill 
2656517Sbostic #include <vm/vm.h>
2737525Smckusick 
2864416Sbostic static int	proc_compare __P((struct proc *p1, struct proc *p2));
2964416Sbostic static int	ttnread __P((struct tty *));
3064416Sbostic static void	ttyblock __P((struct tty *tp));
3164416Sbostic static void	ttyecho __P((int, struct tty *tp));
3264416Sbostic static void	ttyrubo __P((struct tty *, int));
3349907Sbostic 
3464416Sbostic /* Symbolic sleep message strings. */
3564416Sbostic char ttclos[]	= "ttycls";
3664416Sbostic char ttopen[]	= "ttyopn";
3764416Sbostic char ttybg[]	= "ttybg";
3864416Sbostic char ttybuf[]	= "ttybuf";
3964416Sbostic char ttyin[]	= "ttyin";
4064416Sbostic char ttyout[]	= "ttyout";
4140712Skarels 
427436Skre /*
4364416Sbostic  * Table with character classes and parity. The 8th bit indicates parity,
4464416Sbostic  * the 7th bit indicates the character is an alphameric or underscore (for
4564416Sbostic  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
4664416Sbostic  * are 0 then the character needs no special processing on output; classes
4764416Sbostic  * other than 0 might be translated or (not currently) require delays.
487436Skre  */
4964416Sbostic #define	E	0x00	/* Even parity. */
5064416Sbostic #define	O	0x80	/* Odd parity. */
5164416Sbostic #define	PARITY(c)	(char_type[c] & O)
5264416Sbostic 
5364416Sbostic #define	ALPHA	0x40	/* Alpha or underscore. */
5464416Sbostic #define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
5564416Sbostic 
5649380Skarels #define	CCLASSMASK	0x3f
5764416Sbostic #define	CCLASS(c)	(char_type[c] & CCLASSMASK)
5839Sbill 
5964416Sbostic #define	BS	BACKSPACE
6049380Skarels #define	CC	CONTROL
6164416Sbostic #define	CR	RETURN
6264416Sbostic #define	NA	ORDINARY | ALPHA
6349380Skarels #define	NL	NEWLINE
6464416Sbostic #define	NO	ORDINARY
6549380Skarels #define	TB	TAB
6649380Skarels #define	VT	VTAB
6749380Skarels 
6864416Sbostic char const char_type[] = {
6949380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
7049380Skarels 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
7149380Skarels 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
7249380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
7349380Skarels 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7449380Skarels 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7549380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
7649380Skarels 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
7749380Skarels 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
7849380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
7949380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
8049380Skarels 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
8149380Skarels 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
8249380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
8349380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8449380Skarels 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
857436Skre 	/*
8664416Sbostic 	 * Meta chars; should be settable per character set;
8764416Sbostic 	 * for now, treat them all as normal characters.
887436Skre 	 */
8949380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9049380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9149380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9249380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
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,
1057436Skre };
10664416Sbostic #undef	BS
10764416Sbostic #undef	CC
10864416Sbostic #undef	CR
10949380Skarels #undef	NA
11049380Skarels #undef	NL
11164416Sbostic #undef	NO
11249380Skarels #undef	TB
11349380Skarels #undef	VT
1147436Skre 
11564416Sbostic /* Macros to clear/set/test flags. */
11664416Sbostic #define	SET(t, f)	(t) |= (f)
11764416Sbostic #define	CLR(t, f)	(t) &= ~(f)
11864416Sbostic #define	ISSET(t, f)	((t) & (f))
11935811Smarc 
120146Sbill /*
12164416Sbostic  * Initial open of tty, or (re)entry to standard tty line discipline.
12239Sbill  */
12364416Sbostic int
12464416Sbostic ttyopen(device, tp)
12564416Sbostic 	dev_t device;
12612752Ssam 	register struct tty *tp;
12712752Ssam {
12852485Storek 	int s;
12947545Skarels 
13052485Storek 	s = spltty();
13164416Sbostic 	tp->t_dev = device;
13264416Sbostic 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
13364416Sbostic 		SET(tp->t_state, TS_ISOPEN);
13464416Sbostic 		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
135903Sbill 	}
13664416Sbostic 	CLR(tp->t_state, TS_WOPEN);
1375408Swnj 	splx(s);
1385408Swnj 	return (0);
1394484Swnj }
1407436Skre 
1417502Sroot /*
14249380Skarels  * Handle close() on a tty line: flush and set to initial state,
14349380Skarels  * bumping generation number so that pending read/write calls
14449380Skarels  * can detect recycling of the tty.
1457502Sroot  */
14664416Sbostic int
1477502Sroot ttyclose(tp)
1487625Ssam 	register struct tty *tp;
1497502Sroot {
15064416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
15164416Sbostic 
15230534Skarels 	if (constty == tp)
15330534Skarels 		constty = NULL;
15464416Sbostic 
15564416Sbostic 	ttyflush(tp, FREAD | FWRITE);
15664416Sbostic 
15764416Sbostic 	tp->t_gen++;
15864416Sbostic 	tp->t_pgrp = NULL;
15939555Smarc 	tp->t_session = NULL;
1607502Sroot 	tp->t_state = 0;
16140712Skarels 	return (0);
1627502Sroot }
1637502Sroot 
16464416Sbostic #define	FLUSHQ(q) {							\
16564416Sbostic 	if ((q)->c_cc)							\
16664416Sbostic 		ndflush(q, (q)->c_cc);					\
16725391Skarels }
16825391Skarels 
16964416Sbostic /* Is 'c' a line delimiter ("break" character)? */
17064416Sbostic #define	TTBREAKC(c)							\
17164416Sbostic 	((c) == '\n' || ((c) == cc[VEOF] ||				\
17264416Sbostic 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
17325404Skarels 
1747502Sroot 
1757502Sroot /*
17649380Skarels  * Process input of a single character received on a tty.
1777502Sroot  */
17864416Sbostic int
1797502Sroot ttyinput(c, tp)
18064416Sbostic 	register int c;
1817625Ssam 	register struct tty *tp;
1827502Sroot {
18364416Sbostic 	register int iflag, lflag;
18464416Sbostic 	register u_char *cc;
18535811Smarc 	int i, err;
1867502Sroot 
1879578Ssam 	/*
1889578Ssam 	 * If input is pending take it first.
1899578Ssam 	 */
19064416Sbostic 	lflag = tp->t_lflag;
19164416Sbostic 	if (ISSET(lflag, PENDIN))
1927502Sroot 		ttypend(tp);
19335811Smarc 	/*
19435811Smarc 	 * Gather stats.
19535811Smarc 	 */
19664416Sbostic 	if (ISSET(lflag, ICANON)) {
19764416Sbostic 		++tk_cancc;
19864416Sbostic 		++tp->t_cancc;
19935811Smarc 	} else {
20064416Sbostic 		++tk_rawcc;
20164416Sbostic 		++tp->t_rawcc;
20235811Smarc 	}
20364416Sbostic 	++tk_nin;
20464416Sbostic 
20564416Sbostic 	/* Handle exceptional conditions (break, parity, framing). */
20664416Sbostic 	cc = tp->t_cc;
20764416Sbostic 	iflag = tp->t_iflag;
20864576Sbostic 	if (err = (ISSET(c, TTY_ERRORMASK))) {
20964576Sbostic 		CLR(c, TTY_ERRORMASK);
21064576Sbostic 		if (ISSET(err, TTY_FE) && !c) {	/* Break. */
21164416Sbostic 			if (ISSET(iflag, IGNBRK))
21235811Smarc 				goto endcase;
21364416Sbostic 			else if (ISSET(iflag, BRKINT) &&
21464416Sbostic 			    ISSET(lflag, ISIG) &&
21564416Sbostic 			    (cc[VINTR] != _POSIX_VDISABLE))
21635811Smarc 				c = cc[VINTR];
21764416Sbostic 			else if (ISSET(iflag, PARMRK))
21847545Skarels 				goto parmrk;
21964576Sbostic 		} else if (ISSET(err, TTY_PE) &&
22064576Sbostic 		    ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) {
22164416Sbostic 			if (ISSET(iflag, IGNPAR))
22235811Smarc 				goto endcase;
22364416Sbostic 			else if (ISSET(iflag, PARMRK)) {
22464576Sbostic parmrk:				(void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
22564576Sbostic 				(void)putc(0 | TTY_QUOTE, &tp->t_rawq);
22664576Sbostic 				(void)putc(c | TTY_QUOTE, &tp->t_rawq);
22735811Smarc 				goto endcase;
22835811Smarc 			} else
22935811Smarc 				c = 0;
2307502Sroot 		}
2319578Ssam 	}
2329578Ssam 	/*
23335811Smarc 	 * In tandem mode, check high water mark.
2349578Ssam 	 */
23564416Sbostic 	if (ISSET(iflag, IXOFF))
23635811Smarc 		ttyblock(tp);
23764416Sbostic 	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
23864576Sbostic 		CLR(c, 0x80);
23964416Sbostic 	if (!ISSET(lflag, EXTPROC)) {
24044419Smarc 		/*
24144419Smarc 		 * Check for literal nexting very first
24244419Smarc 		 */
24364416Sbostic 		if (ISSET(tp->t_state, TS_LNCH)) {
24464576Sbostic 			SET(c, TTY_QUOTE);
24564416Sbostic 			CLR(tp->t_state, TS_LNCH);
24644419Smarc 		}
24744419Smarc 		/*
24844419Smarc 		 * Scan for special characters.  This code
24944419Smarc 		 * is really just a big case statement with
25044419Smarc 		 * non-constant cases.  The bottom of the
25144419Smarc 		 * case statement is labeled ``endcase'', so goto
25244419Smarc 		 * it after a case match, or similar.
25344419Smarc 		 */
25444419Smarc 
25544419Smarc 		/*
25644419Smarc 		 * Control chars which aren't controlled
25744419Smarc 		 * by ICANON, ISIG, or IXON.
25844419Smarc 		 */
25964416Sbostic 		if (ISSET(lflag, IEXTEN)) {
26044419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
26164416Sbostic 				if (ISSET(lflag, ECHO)) {
26264416Sbostic 					if (ISSET(lflag, ECHOE)) {
26364416Sbostic 						(void)ttyoutput('^', tp);
26464416Sbostic 						(void)ttyoutput('\b', tp);
26564416Sbostic 					} else
26644419Smarc 						ttyecho(c, tp);
26744419Smarc 				}
26864416Sbostic 				SET(tp->t_state, TS_LNCH);
26944419Smarc 				goto endcase;
27044419Smarc 			}
27144419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
27264416Sbostic 				if (ISSET(lflag, FLUSHO))
27364416Sbostic 					CLR(tp->t_lflag, FLUSHO);
27444419Smarc 				else {
27544419Smarc 					ttyflush(tp, FWRITE);
27635811Smarc 					ttyecho(c, tp);
27744419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
27844419Smarc 						ttyretype(tp);
27964416Sbostic 					SET(tp->t_lflag, FLUSHO);
28044419Smarc 				}
28144419Smarc 				goto startoutput;
28235811Smarc 			}
2839578Ssam 		}
28444419Smarc 		/*
28544419Smarc 		 * Signals.
28644419Smarc 		 */
28764416Sbostic 		if (ISSET(lflag, ISIG)) {
28844419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
28964416Sbostic 				if (!ISSET(lflag, NOFLSH))
29064416Sbostic 					ttyflush(tp, FREAD | FWRITE);
2917502Sroot 				ttyecho(c, tp);
29244419Smarc 				pgsignal(tp->t_pgrp,
29344419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
29444419Smarc 				goto endcase;
2957502Sroot 			}
29644419Smarc 			if (CCEQ(cc[VSUSP], c)) {
29764416Sbostic 				if (!ISSET(lflag, NOFLSH))
29844419Smarc 					ttyflush(tp, FREAD);
29944419Smarc 				ttyecho(c, tp);
30044419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
30144419Smarc 				goto endcase;
30244419Smarc 			}
3039578Ssam 		}
30444419Smarc 		/*
30544419Smarc 		 * Handle start/stop characters.
30644419Smarc 		 */
30764416Sbostic 		if (ISSET(iflag, IXON)) {
30844419Smarc 			if (CCEQ(cc[VSTOP], c)) {
30964416Sbostic 				if (!ISSET(tp->t_state, TS_TTSTOP)) {
31064416Sbostic 					SET(tp->t_state, TS_TTSTOP);
31152485Storek #ifdef sun4c						/* XXX */
31252485Storek 					(*tp->t_stop)(tp, 0);
31352485Storek #else
31444419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
31544419Smarc 					   0);
31652485Storek #endif
31764416Sbostic 					return (0);
31844419Smarc 				}
31944419Smarc 				if (!CCEQ(cc[VSTART], c))
32064416Sbostic 					return (0);
32164416Sbostic 				/*
32264416Sbostic 				 * if VSTART == VSTOP then toggle
32344419Smarc 				 */
32444419Smarc 				goto endcase;
32535811Smarc 			}
32644419Smarc 			if (CCEQ(cc[VSTART], c))
32744419Smarc 				goto restartoutput;
3289578Ssam 		}
32944419Smarc 		/*
33044419Smarc 		 * IGNCR, ICRNL, & INLCR
33144419Smarc 		 */
33244419Smarc 		if (c == '\r') {
33364416Sbostic 			if (ISSET(iflag, IGNCR))
33444419Smarc 				goto endcase;
33564416Sbostic 			else if (ISSET(iflag, ICRNL))
33644419Smarc 				c = '\n';
33764416Sbostic 		} else if (c == '\n' && ISSET(iflag, INLCR))
33844419Smarc 			c = '\r';
3399578Ssam 	}
34064416Sbostic 	if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
34144419Smarc 		/*
34244419Smarc 		 * From here on down canonical mode character
34344419Smarc 		 * processing takes place.
34444419Smarc 		 */
34544419Smarc 		/*
34644419Smarc 		 * erase (^H / ^?)
34744419Smarc 		 */
34844419Smarc 		if (CCEQ(cc[VERASE], c)) {
34944419Smarc 			if (tp->t_rawq.c_cc)
3509578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
35144419Smarc 			goto endcase;
3529578Ssam 		}
35344419Smarc 		/*
35444419Smarc 		 * kill (^U)
35544419Smarc 		 */
35644419Smarc 		if (CCEQ(cc[VKILL], c)) {
35764416Sbostic 			if (ISSET(lflag, ECHOKE) &&
35864416Sbostic 			    tp->t_rawq.c_cc == tp->t_rocount &&
35964416Sbostic 			    !ISSET(lflag, ECHOPRT))
36044419Smarc 				while (tp->t_rawq.c_cc)
36144419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
36264416Sbostic 			else {
36344419Smarc 				ttyecho(c, tp);
36464416Sbostic 				if (ISSET(lflag, ECHOK) ||
36564416Sbostic 				    ISSET(lflag, ECHOKE))
36644419Smarc 					ttyecho('\n', tp);
36764416Sbostic 				FLUSHQ(&tp->t_rawq);
36844419Smarc 				tp->t_rocount = 0;
36944419Smarc 			}
37064416Sbostic 			CLR(tp->t_state, TS_LOCAL);
37144419Smarc 			goto endcase;
37244419Smarc 		}
37344419Smarc 		/*
37444419Smarc 		 * word erase (^W)
37544419Smarc 		 */
37664416Sbostic 		if (CCEQ(cc[VWERASE], c)) {
37764416Sbostic 			int alt = ISSET(lflag, ALTWERASE);
37844419Smarc 			int ctype;
37935811Smarc 
38064416Sbostic 			/*
38164416Sbostic 			 * erase whitespace
38244419Smarc 			 */
38344419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
38444419Smarc 				ttyrub(c, tp);
38544419Smarc 			if (c == -1)
38644419Smarc 				goto endcase;
38744419Smarc 			/*
38847545Skarels 			 * erase last char of word and remember the
38947545Skarels 			 * next chars type (for ALTWERASE)
39044419Smarc 			 */
39135811Smarc 			ttyrub(c, tp);
39244419Smarc 			c = unputc(&tp->t_rawq);
39347545Skarels 			if (c == -1)
39444419Smarc 				goto endcase;
39551003Sbostic 			if (c == ' ' || c == '\t') {
39664576Sbostic 				(void)putc(c, &tp->t_rawq);
39751003Sbostic 				goto endcase;
39851003Sbostic 			}
39949380Skarels 			ctype = ISALPHA(c);
40044419Smarc 			/*
40147545Skarels 			 * erase rest of word
40244419Smarc 			 */
40344419Smarc 			do {
40444419Smarc 				ttyrub(c, tp);
40544419Smarc 				c = unputc(&tp->t_rawq);
40644419Smarc 				if (c == -1)
40744419Smarc 					goto endcase;
40864416Sbostic 			} while (c != ' ' && c != '\t' &&
40964416Sbostic 			    (alt == 0 || ISALPHA(c) == ctype));
41064416Sbostic 			(void)putc(c, &tp->t_rawq);
41134492Skarels 			goto endcase;
41244419Smarc 		}
41335811Smarc 		/*
41444419Smarc 		 * reprint line (^R)
41535811Smarc 		 */
41644419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
41744419Smarc 			ttyretype(tp);
41834492Skarels 			goto endcase;
41934492Skarels 		}
42035811Smarc 		/*
42144419Smarc 		 * ^T - kernel info and generate SIGINFO
42235811Smarc 		 */
42344419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
42464416Sbostic 			if (ISSET(lflag, ISIG))
42551068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
42664416Sbostic 			if (!ISSET(lflag, NOKERNINFO))
42744419Smarc 				ttyinfo(tp);
42844419Smarc 			goto endcase;
42944419Smarc 		}
4309578Ssam 	}
4319578Ssam 	/*
4329578Ssam 	 * Check for input buffer overflow
4339578Ssam 	 */
43447545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
43564416Sbostic 		if (ISSET(iflag, IMAXBEL)) {
43635811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
43764416Sbostic 				(void)ttyoutput(CTRL('g'), tp);
43835811Smarc 		} else
43935811Smarc 			ttyflush(tp, FREAD | FWRITE);
4409578Ssam 		goto endcase;
44110391Ssam 	}
4429578Ssam 	/*
4439578Ssam 	 * Put data char in q for user and
4449578Ssam 	 * wakeup on seeing a line delimiter.
4459578Ssam 	 */
4469578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
44764416Sbostic 		if (!ISSET(lflag, ICANON)) {
44847545Skarels 			ttwakeup(tp);
44947545Skarels 			ttyecho(c, tp);
45047545Skarels 			goto endcase;
45147545Skarels 		}
45264416Sbostic 		if (TTBREAKC(c)) {
4539578Ssam 			tp->t_rocount = 0;
4549578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
4557502Sroot 			ttwakeup(tp);
4569578Ssam 		} else if (tp->t_rocount++ == 0)
45764530Sbostic 			tp->t_rocol = tp->t_column;
45864416Sbostic 		if (ISSET(tp->t_state, TS_ERASE)) {
45935811Smarc 			/*
46035811Smarc 			 * end of prterase \.../
46135811Smarc 			 */
46264416Sbostic 			CLR(tp->t_state, TS_ERASE);
46364416Sbostic 			(void)ttyoutput('/', tp);
4649578Ssam 		}
46564530Sbostic 		i = tp->t_column;
4667502Sroot 		ttyecho(c, tp);
46764416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
46835811Smarc 			/*
46935811Smarc 			 * Place the cursor over the '^' of the ^D.
47035811Smarc 			 */
47164530Sbostic 			i = min(2, tp->t_column - i);
4729578Ssam 			while (i > 0) {
47364416Sbostic 				(void)ttyoutput('\b', tp);
4749578Ssam 				i--;
4759578Ssam 			}
4769578Ssam 		}
4777502Sroot 	}
4789578Ssam endcase:
4799578Ssam 	/*
48035811Smarc 	 * IXANY means allow any character to restart output.
4819578Ssam 	 */
48264416Sbostic 	if (ISSET(tp->t_state, TS_TTSTOP) &&
48364416Sbostic 	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
48464416Sbostic 		return (0);
4859578Ssam restartoutput:
48664416Sbostic 	CLR(tp->t_lflag, FLUSHO);
48764416Sbostic 	CLR(tp->t_state, TS_TTSTOP);
4889578Ssam startoutput:
48964416Sbostic 	return (ttstart(tp));
4907502Sroot }
4917502Sroot 
4927502Sroot /*
49349380Skarels  * Output a single character on a tty, doing output processing
49449380Skarels  * as needed (expanding tabs, newline processing, etc.).
49564416Sbostic  * Returns < 0 if succeeds, otherwise returns char to resend.
4967502Sroot  * Must be recursive.
4977502Sroot  */
49864416Sbostic int
4997502Sroot ttyoutput(c, tp)
50064416Sbostic 	register int c;
5017502Sroot 	register struct tty *tp;
5027502Sroot {
50364416Sbostic 	register long oflag;
50464416Sbostic 	register int col, s;
50564416Sbostic 
50664416Sbostic 	oflag = tp->t_oflag;
50764416Sbostic 	if (!ISSET(oflag, OPOST)) {
50864416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO))
5097502Sroot 			return (-1);
5107502Sroot 		if (putc(c, &tp->t_outq))
5117625Ssam 			return (c);
5127502Sroot 		tk_nout++;
51335811Smarc 		tp->t_outcc++;
5147502Sroot 		return (-1);
5157502Sroot 	}
5167502Sroot 	/*
51764416Sbostic 	 * Do tab expansion if OXTABS is set.  Special case if we external
51864416Sbostic 	 * processing, we don't do the tab expansion because we'll probably
51964416Sbostic 	 * get it wrong.  If tab expansion needs to be done, let it happen
52064416Sbostic 	 * externally.
5217502Sroot 	 */
52264576Sbostic 	CLR(c, ~TTY_CHARMASK);
52364416Sbostic 	if (c == '\t' &&
52464416Sbostic 	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
52564530Sbostic 		c = 8 - (tp->t_column & 7);
52664416Sbostic 		if (!ISSET(tp->t_lflag, FLUSHO)) {
52764416Sbostic 			s = spltty();		/* Don't interrupt tabs. */
5287502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
5297502Sroot 			tk_nout += c;
53035811Smarc 			tp->t_outcc += c;
5317502Sroot 			splx(s);
5327502Sroot 		}
53364530Sbostic 		tp->t_column += c;
5347502Sroot 		return (c ? -1 : '\t');
5357502Sroot 	}
53664416Sbostic 	if (c == CEOT && ISSET(oflag, ONOEOT))
53747545Skarels 		return (-1);
53864576Sbostic 
5397502Sroot 	/*
54049380Skarels 	 * Newline translation: if ONLCR is set,
54149380Skarels 	 * translate newline into "\r\n".
5427502Sroot 	 */
54364576Sbostic 	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
54464576Sbostic 		tk_nout++;
54564576Sbostic 		tp->t_outcc++;
54664576Sbostic 		if (putc('\r', &tp->t_outq))
54764576Sbostic 			return (c);
54864576Sbostic 	}
54964576Sbostic 	tk_nout++;
55064576Sbostic 	tp->t_outcc++;
55164416Sbostic 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
55235811Smarc 		return (c);
55347545Skarels 
55464530Sbostic 	col = tp->t_column;
55549380Skarels 	switch (CCLASS(c)) {
5567502Sroot 	case BACKSPACE:
55749380Skarels 		if (col > 0)
55864416Sbostic 			--col;
5597502Sroot 		break;
56064416Sbostic 	case CONTROL:
56164416Sbostic 		break;
5627502Sroot 	case NEWLINE:
56364416Sbostic 	case RETURN:
56449380Skarels 		col = 0;
5657502Sroot 		break;
56664416Sbostic 	case ORDINARY:
56764416Sbostic 		++col;
56864416Sbostic 		break;
5697502Sroot 	case TAB:
57064416Sbostic 		col = (col + 8) & ~7;
5717502Sroot 		break;
5727502Sroot 	}
57364530Sbostic 	tp->t_column = col;
5747502Sroot 	return (-1);
5757502Sroot }
5767502Sroot 
5777502Sroot /*
57864576Sbostic  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
57964576Sbostic  * has been called to do discipline-specific functions and/or reject any
58064576Sbostic  * of these ioctl commands.
58164416Sbostic  */
58264416Sbostic /* ARGSUSED */
58364416Sbostic int
58464576Sbostic ttioctl(tp, cmd, data, flag)
58564416Sbostic 	register struct tty *tp;
58664576Sbostic 	int cmd, flag;
58764416Sbostic 	void *data;
58864416Sbostic {
58964416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
59064576Sbostic 	extern int nlinesw;
59164416Sbostic 	register struct proc *p;
59264416Sbostic 	int s, error;
59364416Sbostic 
59464416Sbostic 	p = curproc;			/* XXX */
59564416Sbostic 
59664416Sbostic 	/* If the ioctl involves modification, hang if in the background. */
59764576Sbostic 	switch (cmd) {
59864416Sbostic 	case  TIOCFLUSH:
59964416Sbostic 	case  TIOCSETA:
60064416Sbostic 	case  TIOCSETD:
60164416Sbostic 	case  TIOCSETAF:
60264416Sbostic 	case  TIOCSETAW:
60364416Sbostic #ifdef notdef
60464416Sbostic 	case  TIOCSPGRP:
60564416Sbostic #endif
60664416Sbostic 	case  TIOCSTI:
60764416Sbostic 	case  TIOCSWINSZ:
60864416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
60964416Sbostic 	case  TIOCLBIC:
61064416Sbostic 	case  TIOCLBIS:
61164416Sbostic 	case  TIOCLSET:
61264416Sbostic 	case  TIOCSETC:
61364416Sbostic 	case OTIOCSETD:
61464416Sbostic 	case  TIOCSETN:
61564416Sbostic 	case  TIOCSETP:
61664416Sbostic 	case  TIOCSLTC:
61764416Sbostic #endif
61864416Sbostic 		while (isbackground(curproc, tp) &&
61964576Sbostic 		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
62064416Sbostic 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
62164416Sbostic 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
62264416Sbostic 			pgsignal(p->p_pgrp, SIGTTOU, 1);
62364416Sbostic 			if (error = ttysleep(tp,
62464416Sbostic 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
62564416Sbostic 				return (error);
62664416Sbostic 		}
62764416Sbostic 		break;
62864416Sbostic 	}
62964416Sbostic 
63064576Sbostic 	switch (cmd) {			/* Process the ioctl. */
63164416Sbostic 	case FIOASYNC:			/* set/clear async i/o */
63264416Sbostic 		s = spltty();
63364416Sbostic 		if (*(int *)data)
63464416Sbostic 			SET(tp->t_state, TS_ASYNC);
63564416Sbostic 		else
63664416Sbostic 			CLR(tp->t_state, TS_ASYNC);
63764416Sbostic 		splx(s);
63864416Sbostic 		break;
63964416Sbostic 	case FIONBIO:			/* set/clear non-blocking i/o */
64064416Sbostic 		break;			/* XXX: delete. */
64164416Sbostic 	case FIONREAD:			/* get # bytes to read */
64264416Sbostic 		*(int *)data = ttnread(tp);
64364416Sbostic 		break;
64464416Sbostic 	case TIOCEXCL:			/* set exclusive use of tty */
64564416Sbostic 		s = spltty();
64664416Sbostic 		SET(tp->t_state, TS_XCLUDE);
64764416Sbostic 		splx(s);
64864416Sbostic 		break;
64964416Sbostic 	case TIOCFLUSH: {		/* flush buffers */
65064416Sbostic 		register int flags = *(int *)data;
65164416Sbostic 
65264416Sbostic 		if (flags == 0)
65364416Sbostic 			flags = FREAD | FWRITE;
65464416Sbostic 		else
65564416Sbostic 			flags &= FREAD | FWRITE;
65664416Sbostic 		ttyflush(tp, flags);
65764416Sbostic 		break;
65864416Sbostic 	}
65964416Sbostic 	case TIOCCONS:			/* become virtual console */
66064416Sbostic 		if (*(int *)data) {
66164416Sbostic 			if (constty && constty != tp &&
66264416Sbostic 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
66364416Sbostic 			    (TS_CARR_ON | TS_ISOPEN))
66464416Sbostic 				return (EBUSY);
66564416Sbostic #ifndef	UCONSOLE
66664416Sbostic 			if (error = suser(p->p_ucred, &p->p_acflag))
66764416Sbostic 				return (error);
66864416Sbostic #endif
66964416Sbostic 			constty = tp;
67064416Sbostic 		} else if (tp == constty)
67164416Sbostic 			constty = NULL;
67264416Sbostic 		break;
67364416Sbostic 	case TIOCDRAIN:			/* wait till output drained */
67464416Sbostic 		if (error = ttywait(tp))
67564416Sbostic 			return (error);
67664416Sbostic 		break;
67764416Sbostic 	case TIOCGETA: {		/* get termios struct */
67864416Sbostic 		struct termios *t = (struct termios *)data;
67964416Sbostic 
68064416Sbostic 		bcopy(&tp->t_termios, t, sizeof(struct termios));
68164416Sbostic 		break;
68264416Sbostic 	}
68364416Sbostic 	case TIOCGETD:			/* get line discipline */
68464416Sbostic 		*(int *)data = tp->t_line;
68564416Sbostic 		break;
68664416Sbostic 	case TIOCGWINSZ:		/* get window size */
68764416Sbostic 		*(struct winsize *)data = tp->t_winsize;
68864416Sbostic 		break;
68964416Sbostic 	case TIOCGPGRP:			/* get pgrp of tty */
69064416Sbostic 		if (!isctty(p, tp))
69164416Sbostic 			return (ENOTTY);
69264416Sbostic 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
69364416Sbostic 		break;
69464416Sbostic #ifdef TIOCHPCL
69564416Sbostic 	case TIOCHPCL:			/* hang up on last close */
69664416Sbostic 		s = spltty();
69764576Sbostic 		SET(tp->t_cflag, HUPCL);
69864416Sbostic 		splx(s);
69964416Sbostic 		break;
70064416Sbostic #endif
70164416Sbostic 	case TIOCNXCL:			/* reset exclusive use of tty */
70264416Sbostic 		s = spltty();
70364416Sbostic 		CLR(tp->t_state, TS_XCLUDE);
70464416Sbostic 		splx(s);
70564416Sbostic 		break;
70664416Sbostic 	case TIOCOUTQ:			/* output queue size */
70764416Sbostic 		*(int *)data = tp->t_outq.c_cc;
70864416Sbostic 		break;
70964416Sbostic 	case TIOCSETA:			/* set termios struct */
71064416Sbostic 	case TIOCSETAW:			/* drain output, set */
71164416Sbostic 	case TIOCSETAF: {		/* drn out, fls in, set */
71264416Sbostic 		register struct termios *t = (struct termios *)data;
71364416Sbostic 
71464416Sbostic 		s = spltty();
71564576Sbostic 		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
71664416Sbostic 			if (error = ttywait(tp)) {
71764416Sbostic 				splx(s);
71864416Sbostic 				return (error);
71964416Sbostic 			}
72064576Sbostic 			if (cmd == TIOCSETAF)
72164416Sbostic 				ttyflush(tp, FREAD);
72264416Sbostic 		}
72364416Sbostic 		if (!ISSET(t->c_cflag, CIGNORE)) {
72464416Sbostic 			/*
72564416Sbostic 			 * Set device hardware.
72664416Sbostic 			 */
72764416Sbostic 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
72864416Sbostic 				splx(s);
72964416Sbostic 				return (error);
73064416Sbostic 			} else {
73164416Sbostic 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
73264416Sbostic 				    ISSET(tp->t_cflag, CLOCAL) &&
73364416Sbostic 				    !ISSET(t->c_cflag, CLOCAL)) {
73464416Sbostic 					CLR(tp->t_state, TS_ISOPEN);
73564416Sbostic 					SET(tp->t_state, TS_WOPEN);
73664416Sbostic 					ttwakeup(tp);
73764416Sbostic 				}
73864416Sbostic 				tp->t_cflag = t->c_cflag;
73964416Sbostic 				tp->t_ispeed = t->c_ispeed;
74064416Sbostic 				tp->t_ospeed = t->c_ospeed;
74164416Sbostic 			}
74264416Sbostic 			ttsetwater(tp);
74364416Sbostic 		}
74464576Sbostic 		if (cmd != TIOCSETAF) {
74564416Sbostic 			if (ISSET(t->c_lflag, ICANON) !=
74664416Sbostic 			    ISSET(tp->t_lflag, ICANON))
74764416Sbostic 				if (ISSET(t->c_lflag, ICANON)) {
74864576Sbostic 					SET(tp->t_lflag, PENDIN);
74964416Sbostic 					ttwakeup(tp);
75064416Sbostic 				} else {
75164416Sbostic 					struct clist tq;
75264416Sbostic 
75364416Sbostic 					catq(&tp->t_rawq, &tp->t_canq);
75464416Sbostic 					tq = tp->t_rawq;
75564416Sbostic 					tp->t_rawq = tp->t_canq;
75664416Sbostic 					tp->t_canq = tq;
75765324Sbostic 					CLR(tp->t_lflag, PENDIN);
75864416Sbostic 				}
75964416Sbostic 		}
76064416Sbostic 		tp->t_iflag = t->c_iflag;
76164416Sbostic 		tp->t_oflag = t->c_oflag;
76264416Sbostic 		/*
76364416Sbostic 		 * Make the EXTPROC bit read only.
76464416Sbostic 		 */
76564416Sbostic 		if (ISSET(tp->t_lflag, EXTPROC))
76664416Sbostic 			SET(t->c_lflag, EXTPROC);
76764416Sbostic 		else
76864416Sbostic 			CLR(t->c_lflag, EXTPROC);
76965324Sbostic 		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
77064416Sbostic 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
77164416Sbostic 		splx(s);
77264416Sbostic 		break;
77364416Sbostic 	}
77464416Sbostic 	case TIOCSETD: {		/* set line discipline */
77564416Sbostic 		register int t = *(int *)data;
77664416Sbostic 		dev_t device = tp->t_dev;
77764416Sbostic 
77864576Sbostic 		if ((u_int)t >= nlinesw)
77964416Sbostic 			return (ENXIO);
78064416Sbostic 		if (t != tp->t_line) {
78164416Sbostic 			s = spltty();
78264416Sbostic 			(*linesw[tp->t_line].l_close)(tp, flag);
78364416Sbostic 			error = (*linesw[t].l_open)(device, tp);
78464416Sbostic 			if (error) {
78564416Sbostic 				(void)(*linesw[tp->t_line].l_open)(device, tp);
78664416Sbostic 				splx(s);
78764416Sbostic 				return (error);
78864416Sbostic 			}
78964416Sbostic 			tp->t_line = t;
79064416Sbostic 			splx(s);
79164416Sbostic 		}
79264416Sbostic 		break;
79364416Sbostic 	}
79464416Sbostic 	case TIOCSTART:			/* start output, like ^Q */
79564416Sbostic 		s = spltty();
79664416Sbostic 		if (ISSET(tp->t_state, TS_TTSTOP) ||
79764416Sbostic 		    ISSET(tp->t_lflag, FLUSHO)) {
79864416Sbostic 			CLR(tp->t_lflag, FLUSHO);
79964416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
80064416Sbostic 			ttstart(tp);
80164416Sbostic 		}
80264416Sbostic 		splx(s);
80364416Sbostic 		break;
80464416Sbostic 	case TIOCSTI:			/* simulate terminal input */
80564416Sbostic 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
80664416Sbostic 			return (EPERM);
80764416Sbostic 		if (p->p_ucred->cr_uid && !isctty(p, tp))
80864416Sbostic 			return (EACCES);
80964416Sbostic 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
81064416Sbostic 		break;
81164416Sbostic 	case TIOCSTOP:			/* stop output, like ^S */
81264416Sbostic 		s = spltty();
81364416Sbostic 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
81464416Sbostic 			SET(tp->t_state, TS_TTSTOP);
81564416Sbostic #ifdef sun4c				/* XXX */
81664416Sbostic 			(*tp->t_stop)(tp, 0);
81764416Sbostic #else
81864416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
81964416Sbostic #endif
82064416Sbostic 		}
82164416Sbostic 		splx(s);
82264416Sbostic 		break;
82364416Sbostic 	case TIOCSCTTY:			/* become controlling tty */
82464416Sbostic 		/* Session ctty vnode pointer set in vnode layer. */
82564416Sbostic 		if (!SESS_LEADER(p) ||
82664416Sbostic 		    (p->p_session->s_ttyvp || tp->t_session) &&
82764416Sbostic 		    (tp->t_session != p->p_session))
82864416Sbostic 			return (EPERM);
82964416Sbostic 		tp->t_session = p->p_session;
83064416Sbostic 		tp->t_pgrp = p->p_pgrp;
83164416Sbostic 		p->p_session->s_ttyp = tp;
83264576Sbostic 		p->p_flag |= P_CONTROLT;
83364416Sbostic 		break;
83464416Sbostic 	case TIOCSPGRP: {		/* set pgrp of tty */
83564416Sbostic 		register struct pgrp *pgrp = pgfind(*(int *)data);
83664416Sbostic 
83764416Sbostic 		if (!isctty(p, tp))
83864416Sbostic 			return (ENOTTY);
83964416Sbostic 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
84064416Sbostic 			return (EPERM);
84164416Sbostic 		tp->t_pgrp = pgrp;
84264416Sbostic 		break;
84364416Sbostic 	}
84464416Sbostic 	case TIOCSWINSZ:		/* set window size */
84564416Sbostic 		if (bcmp((caddr_t)&tp->t_winsize, data,
84664416Sbostic 		    sizeof (struct winsize))) {
84764416Sbostic 			tp->t_winsize = *(struct winsize *)data;
84864416Sbostic 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
84964416Sbostic 		}
85064416Sbostic 		break;
85164416Sbostic 	default:
85264416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
85364576Sbostic 		return (ttcompat(tp, cmd, data, flag));
85464416Sbostic #else
85564416Sbostic 		return (-1);
85664416Sbostic #endif
85764416Sbostic 	}
85864416Sbostic 	return (0);
85964416Sbostic }
86064416Sbostic 
86164416Sbostic int
86264416Sbostic ttselect(device, rw, p)
86364416Sbostic 	dev_t device;
86464416Sbostic 	int rw;
86564416Sbostic 	struct proc *p;
86664416Sbostic {
86764416Sbostic 	register struct tty *tp;
86864416Sbostic 	int nread, s;
86964416Sbostic 
87064416Sbostic 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
87164416Sbostic 
87264416Sbostic 	s = spltty();
87364416Sbostic 	switch (rw) {
87464416Sbostic 	case FREAD:
87564416Sbostic 		nread = ttnread(tp);
87664416Sbostic 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
87764416Sbostic 		    !ISSET(tp->t_state, TS_CARR_ON))
87864416Sbostic 			goto win;
87964416Sbostic 		selrecord(p, &tp->t_rsel);
88064416Sbostic 		break;
88164416Sbostic 	case FWRITE:
88264416Sbostic 		if (tp->t_outq.c_cc <= tp->t_lowat) {
88364416Sbostic win:			splx(s);
88464416Sbostic 			return (1);
88564416Sbostic 		}
88664416Sbostic 		selrecord(p, &tp->t_wsel);
88764416Sbostic 		break;
88864416Sbostic 	}
88964416Sbostic 	splx(s);
89064416Sbostic 	return (0);
89164416Sbostic }
89264416Sbostic 
89364416Sbostic static int
89464416Sbostic ttnread(tp)
89564416Sbostic 	struct tty *tp;
89664416Sbostic {
89764416Sbostic 	int nread;
89864416Sbostic 
89964416Sbostic 	if (ISSET(tp->t_lflag, PENDIN))
90064416Sbostic 		ttypend(tp);
90164416Sbostic 	nread = tp->t_canq.c_cc;
90264416Sbostic 	if (!ISSET(tp->t_lflag, ICANON))
90364416Sbostic 		nread += tp->t_rawq.c_cc;
90464416Sbostic 	return (nread);
90564416Sbostic }
90664416Sbostic 
90764416Sbostic /*
90864416Sbostic  * Wait for output to drain.
90964416Sbostic  */
91064416Sbostic int
91164416Sbostic ttywait(tp)
91264416Sbostic 	register struct tty *tp;
91364416Sbostic {
91464416Sbostic 	int error, s;
91564416Sbostic 
91664416Sbostic 	error = 0;
91764416Sbostic 	s = spltty();
91864416Sbostic 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
91964416Sbostic 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
92064416Sbostic 	    && tp->t_oproc) {
92164416Sbostic 		(*tp->t_oproc)(tp);
92264416Sbostic 		SET(tp->t_state, TS_ASLEEP);
92364416Sbostic 		if (error = ttysleep(tp,
92464416Sbostic 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
92564416Sbostic 			break;
92664416Sbostic 	}
92764416Sbostic 	splx(s);
92864416Sbostic 	return (error);
92964416Sbostic }
93064416Sbostic 
93164416Sbostic /*
93264416Sbostic  * Flush if successfully wait.
93364416Sbostic  */
93464416Sbostic int
93564416Sbostic ttywflush(tp)
93664416Sbostic 	struct tty *tp;
93764416Sbostic {
93864416Sbostic 	int error;
93964416Sbostic 
94064416Sbostic 	if ((error = ttywait(tp)) == 0)
94164416Sbostic 		ttyflush(tp, FREAD);
94264416Sbostic 	return (error);
94364416Sbostic }
94464416Sbostic 
94564416Sbostic /*
94664416Sbostic  * Flush tty read and/or write queues, notifying anyone waiting.
94764416Sbostic  */
94864416Sbostic void
94964416Sbostic ttyflush(tp, rw)
95064416Sbostic 	register struct tty *tp;
95164416Sbostic 	int rw;
95264416Sbostic {
95364416Sbostic 	register int s;
95464416Sbostic 
95564416Sbostic 	s = spltty();
95664416Sbostic 	if (rw & FREAD) {
95764416Sbostic 		FLUSHQ(&tp->t_canq);
95864416Sbostic 		FLUSHQ(&tp->t_rawq);
95964416Sbostic 		tp->t_rocount = 0;
96064416Sbostic 		tp->t_rocol = 0;
96164416Sbostic 		CLR(tp->t_state, TS_LOCAL);
96264416Sbostic 		ttwakeup(tp);
96364416Sbostic 	}
96464416Sbostic 	if (rw & FWRITE) {
96564416Sbostic 		CLR(tp->t_state, TS_TTSTOP);
96664416Sbostic #ifdef sun4c						/* XXX */
96764416Sbostic 		(*tp->t_stop)(tp, rw);
96864416Sbostic #else
96964416Sbostic 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
97064416Sbostic #endif
97164416Sbostic 		FLUSHQ(&tp->t_outq);
97264416Sbostic 		wakeup((caddr_t)&tp->t_outq);
97364416Sbostic 		selwakeup(&tp->t_wsel);
97464416Sbostic 	}
97564416Sbostic 	splx(s);
97664416Sbostic }
97764416Sbostic 
97864416Sbostic /*
97964416Sbostic  * Copy in the default termios characters.
98064416Sbostic  */
98164416Sbostic void
98264416Sbostic ttychars(tp)
98364416Sbostic 	struct tty *tp;
98464416Sbostic {
98564416Sbostic 
98664416Sbostic 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
98764416Sbostic }
98864416Sbostic 
98964416Sbostic /*
99064416Sbostic  * Send stop character on input overflow.
99164416Sbostic  */
99264416Sbostic static void
99364416Sbostic ttyblock(tp)
99464416Sbostic 	register struct tty *tp;
99564416Sbostic {
99664416Sbostic 	register int total;
99764416Sbostic 
99864416Sbostic 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
99964416Sbostic 	if (tp->t_rawq.c_cc > TTYHOG) {
100064416Sbostic 		ttyflush(tp, FREAD | FWRITE);
100164416Sbostic 		CLR(tp->t_state, TS_TBLOCK);
100264416Sbostic 	}
100364416Sbostic 	/*
100464416Sbostic 	 * Block further input iff: current input > threshold
100564416Sbostic 	 * AND input is available to user program.
100664416Sbostic 	 */
100764416Sbostic 	if (total >= TTYHOG / 2 &&
100864416Sbostic 	    !ISSET(tp->t_state, TS_TBLOCK) &&
100964416Sbostic 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
101064416Sbostic 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
101164416Sbostic 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
101264416Sbostic 			SET(tp->t_state, TS_TBLOCK);
101364416Sbostic 			ttstart(tp);
101464416Sbostic 		}
101564416Sbostic 	}
101664416Sbostic }
101764416Sbostic 
101864416Sbostic void
101964416Sbostic ttrstrt(tp_arg)
102064416Sbostic 	void *tp_arg;
102164416Sbostic {
102264416Sbostic 	struct tty *tp;
102364416Sbostic 	int s;
102464416Sbostic 
102564416Sbostic #ifdef DIAGNOSTIC
102664416Sbostic 	if (tp_arg == NULL)
102764416Sbostic 		panic("ttrstrt");
102864416Sbostic #endif
102964416Sbostic 	tp = tp_arg;
103064416Sbostic 	s = spltty();
103164416Sbostic 
103264416Sbostic 	CLR(tp->t_state, TS_TIMEOUT);
103364416Sbostic 	ttstart(tp);
103464416Sbostic 
103564416Sbostic 	splx(s);
103664416Sbostic }
103764416Sbostic 
103864416Sbostic int
103964416Sbostic ttstart(tp)
104064416Sbostic 	struct tty *tp;
104164416Sbostic {
104264416Sbostic 
104364416Sbostic 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
104464416Sbostic 		(*tp->t_oproc)(tp);
104564416Sbostic 	return (0);
104664416Sbostic }
104764416Sbostic 
104864416Sbostic /*
104964416Sbostic  * "close" a line discipline
105064416Sbostic  */
105164416Sbostic int
105264416Sbostic ttylclose(tp, flag)
105364416Sbostic 	struct tty *tp;
105464416Sbostic 	int flag;
105564416Sbostic {
105664416Sbostic 
105764416Sbostic 	if (flag & IO_NDELAY)
105864416Sbostic 		ttyflush(tp, FREAD | FWRITE);
105964416Sbostic 	else
106064416Sbostic 		ttywflush(tp);
106164416Sbostic 	return (0);
106264416Sbostic }
106364416Sbostic 
106464416Sbostic /*
106564416Sbostic  * Handle modem control transition on a tty.
106664416Sbostic  * Flag indicates new state of carrier.
106764416Sbostic  * Returns 0 if the line should be turned off, otherwise 1.
106864416Sbostic  */
106964416Sbostic int
107064416Sbostic ttymodem(tp, flag)
107164416Sbostic 	register struct tty *tp;
107264416Sbostic 	int flag;
107364416Sbostic {
107464416Sbostic 
107564416Sbostic 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
107664416Sbostic 		/*
107764416Sbostic 		 * MDMBUF: do flow control according to carrier flag
107864416Sbostic 		 */
107964416Sbostic 		if (flag) {
108064416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
108164416Sbostic 			ttstart(tp);
108264416Sbostic 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
108364416Sbostic 			SET(tp->t_state, TS_TTSTOP);
108464416Sbostic #ifdef sun4c						/* XXX */
108564416Sbostic 			(*tp->t_stop)(tp, 0);
108664416Sbostic #else
108764416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
108864416Sbostic #endif
108964416Sbostic 		}
109064416Sbostic 	} else if (flag == 0) {
109164416Sbostic 		/*
109264416Sbostic 		 * Lost carrier.
109364416Sbostic 		 */
109464416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
109564416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN) &&
109664416Sbostic 		    !ISSET(tp->t_cflag, CLOCAL)) {
109764416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
109864416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
109964416Sbostic 			ttyflush(tp, FREAD | FWRITE);
110064416Sbostic 			return (0);
110164416Sbostic 		}
110264416Sbostic 	} else {
110364416Sbostic 		/*
110464416Sbostic 		 * Carrier now on.
110564416Sbostic 		 */
110664416Sbostic 		SET(tp->t_state, TS_CARR_ON);
110764416Sbostic 		ttwakeup(tp);
110864416Sbostic 	}
110964416Sbostic 	return (1);
111064416Sbostic }
111164416Sbostic 
111264416Sbostic /*
111364416Sbostic  * Default modem control routine (for other line disciplines).
111464416Sbostic  * Return argument flag, to turn off device on carrier drop.
111564416Sbostic  */
111664416Sbostic int
111764416Sbostic nullmodem(tp, flag)
111864416Sbostic 	register struct tty *tp;
111964416Sbostic 	int flag;
112064416Sbostic {
112164416Sbostic 
112264416Sbostic 	if (flag)
112364416Sbostic 		SET(tp->t_state, TS_CARR_ON);
112464416Sbostic 	else {
112564416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
112664416Sbostic 		if (!ISSET(tp->t_cflag, CLOCAL)) {
112764416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
112864416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
112964416Sbostic 			return (0);
113064416Sbostic 		}
113164416Sbostic 	}
113264416Sbostic 	return (1);
113364416Sbostic }
113464416Sbostic 
113564416Sbostic /*
113664416Sbostic  * Reinput pending characters after state switch
113764416Sbostic  * call at spltty().
113864416Sbostic  */
113964416Sbostic void
114064416Sbostic ttypend(tp)
114164416Sbostic 	register struct tty *tp;
114264416Sbostic {
114364416Sbostic 	struct clist tq;
114464416Sbostic 	register c;
114564416Sbostic 
114664416Sbostic 	CLR(tp->t_lflag, PENDIN);
114764416Sbostic 	SET(tp->t_state, TS_TYPEN);
114864416Sbostic 	tq = tp->t_rawq;
114964416Sbostic 	tp->t_rawq.c_cc = 0;
115064416Sbostic 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
115164416Sbostic 	while ((c = getc(&tq)) >= 0)
115264416Sbostic 		ttyinput(c, tp);
115364416Sbostic 	CLR(tp->t_state, TS_TYPEN);
115464416Sbostic }
115564416Sbostic 
115664416Sbostic /*
115749380Skarels  * Process a read call on a tty device.
11587502Sroot  */
115964416Sbostic int
116037584Smarc ttread(tp, uio, flag)
11617625Ssam 	register struct tty *tp;
11627722Swnj 	struct uio *uio;
116352485Storek 	int flag;
11647502Sroot {
11657502Sroot 	register struct clist *qp;
116635811Smarc 	register int c;
116741383Smarc 	register long lflag;
116835811Smarc 	register u_char *cc = tp->t_cc;
116947545Skarels 	register struct proc *p = curproc;
11709859Ssam 	int s, first, error = 0;
11717502Sroot 
117264416Sbostic loop:	lflag = tp->t_lflag;
117337584Smarc 	s = spltty();
11749578Ssam 	/*
117564416Sbostic 	 * take pending input first
11769578Ssam 	 */
117764416Sbostic 	if (ISSET(lflag, PENDIN))
11787502Sroot 		ttypend(tp);
11799859Ssam 	splx(s);
118040712Skarels 
11819578Ssam 	/*
11829578Ssam 	 * Hang process if it's in the background.
11839578Ssam 	 */
118447545Skarels 	if (isbackground(p, tp)) {
118547545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
118647545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
118764576Sbostic 		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
11888520Sroot 			return (EIO);
118947545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119064416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
119140712Skarels 			return (error);
119223165Sbloom 		goto loop;
11937502Sroot 	}
119440712Skarels 
11959578Ssam 	/*
119635811Smarc 	 * If canonical, use the canonical queue,
119735811Smarc 	 * else use the raw queue.
119837584Smarc 	 *
119947545Skarels 	 * (should get rid of clists...)
12009578Ssam 	 */
120164416Sbostic 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
120240712Skarels 
12039578Ssam 	/*
120440712Skarels 	 * If there is no input, sleep on rawq
120540712Skarels 	 * awaiting hardware receipt and notification.
120640712Skarels 	 * If we have data, we don't need to check for carrier.
12079578Ssam 	 */
120817545Skarels 	s = spltty();
12099578Ssam 	if (qp->c_cc <= 0) {
121040712Skarels 		int carrier;
121140712Skarels 
121264416Sbostic 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
121364416Sbostic 		    ISSET(tp->t_cflag, CLOCAL);
121464416Sbostic 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12159859Ssam 			splx(s);
121640712Skarels 			return (0);	/* EOF */
12177502Sroot 		}
121837728Smckusick 		if (flag & IO_NDELAY) {
121937584Smarc 			splx(s);
122037584Smarc 			return (EWOULDBLOCK);
122137584Smarc 		}
122264416Sbostic 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
122340712Skarels 		    carrier ? ttyin : ttopen, 0);
12249859Ssam 		splx(s);
122543377Smarc 		if (error)
122640712Skarels 			return (error);
12279578Ssam 		goto loop;
12289578Ssam 	}
12299859Ssam 	splx(s);
123040712Skarels 
12319578Ssam 	/*
123235811Smarc 	 * Input present, check for input mapping and processing.
12339578Ssam 	 */
12349578Ssam 	first = 1;
12359578Ssam 	while ((c = getc(qp)) >= 0) {
12369578Ssam 		/*
123735811Smarc 		 * delayed suspend (^Y)
12389578Ssam 		 */
123964416Sbostic 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
124042882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12419578Ssam 			if (first) {
124264416Sbostic 				if (error = ttysleep(tp,
124364416Sbostic 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
124440712Skarels 					break;
12459578Ssam 				goto loop;
12469578Ssam 			}
12479578Ssam 			break;
12487502Sroot 		}
12499578Ssam 		/*
125035811Smarc 		 * Interpret EOF only in canonical mode.
12519578Ssam 		 */
125264416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12539578Ssam 			break;
12549578Ssam 		/*
12559578Ssam 		 * Give user character.
12569578Ssam 		 */
125740712Skarels  		error = ureadc(c, uio);
12589578Ssam 		if (error)
12599578Ssam 			break;
126014938Smckusick  		if (uio->uio_resid == 0)
12619578Ssam 			break;
12629578Ssam 		/*
126335811Smarc 		 * In canonical mode check for a "break character"
12649578Ssam 		 * marking the end of a "line of input".
12659578Ssam 		 */
126664416Sbostic 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
12679578Ssam 			break;
12689578Ssam 		first = 0;
12697502Sroot 	}
12709578Ssam 	/*
12719578Ssam 	 * Look to unblock output now that (presumably)
12729578Ssam 	 * the input queue has gone down.
12739578Ssam 	 */
127452485Storek 	s = spltty();
127564416Sbostic 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
127647545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
127747545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
127864416Sbostic 			CLR(tp->t_state, TS_TBLOCK);
12797502Sroot 			ttstart(tp);
12807502Sroot 		}
128135811Smarc 	}
128252485Storek 	splx(s);
12838520Sroot 	return (error);
12847502Sroot }
12857502Sroot 
12867502Sroot /*
128764416Sbostic  * Check the output queue on tp for space for a kernel message (from uprintf
128864416Sbostic  * or tprintf).  Allow some space over the normal hiwater mark so we don't
128964416Sbostic  * lose messages due to normal flow control, but don't let the tty run amok.
129064416Sbostic  * Sleeps here are not interruptible, but we return prematurely if new signals
129164416Sbostic  * arrive.
129225391Skarels  */
129364416Sbostic int
129425391Skarels ttycheckoutq(tp, wait)
129525391Skarels 	register struct tty *tp;
129625391Skarels 	int wait;
129725391Skarels {
129830695Skarels 	int hiwat, s, oldsig;
129925391Skarels 
130035811Smarc 	hiwat = tp->t_hiwat;
130125391Skarels 	s = spltty();
130264576Sbostic 	oldsig = wait ? curproc->p_siglist : 0;
130325391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
130429946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130529946Skarels 			ttstart(tp);
130664576Sbostic 			if (wait == 0 || curproc->p_siglist != oldsig) {
130729946Skarels 				splx(s);
130829946Skarels 				return (0);
130929946Skarels 			}
131054782Storek 			timeout((void (*)__P((void *)))wakeup,
131154782Storek 			    (void *)&tp->t_outq, hz);
131264416Sbostic 			SET(tp->t_state, TS_ASLEEP);
131330695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
131425391Skarels 		}
131525391Skarels 	splx(s);
131625391Skarels 	return (1);
131725391Skarels }
131825391Skarels 
131925391Skarels /*
132049380Skarels  * Process a write call on a tty device.
13217502Sroot  */
132264416Sbostic int
132337584Smarc ttwrite(tp, uio, flag)
13247625Ssam 	register struct tty *tp;
13259578Ssam 	register struct uio *uio;
132652485Storek 	int flag;
13277502Sroot {
13287502Sroot 	register char *cp;
132964416Sbostic 	register int cc, ce;
133064416Sbostic 	register struct proc *p;
13319578Ssam 	int i, hiwat, cnt, error, s;
13327502Sroot 	char obuf[OBUFSIZ];
13337502Sroot 
133435811Smarc 	hiwat = tp->t_hiwat;
13359578Ssam 	cnt = uio->uio_resid;
13369578Ssam 	error = 0;
133764878Smckusick 	cc = 0;
13387502Sroot loop:
133937584Smarc 	s = spltty();
134064416Sbostic 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
134164416Sbostic 	    !ISSET(tp->t_cflag, CLOCAL)) {
134264416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN)) {
134337584Smarc 			splx(s);
134437584Smarc 			return (EIO);
134537728Smckusick 		} else if (flag & IO_NDELAY) {
134637584Smarc 			splx(s);
134740712Skarels 			error = EWOULDBLOCK;
134840712Skarels 			goto out;
134937584Smarc 		} else {
135064416Sbostic 			/* Sleep awaiting carrier. */
135164416Sbostic 			error = ttysleep(tp,
135264416Sbostic 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
135337584Smarc 			splx(s);
135443377Smarc 			if (error)
135540712Skarels 				goto out;
135637584Smarc 			goto loop;
135737584Smarc 		}
135837584Smarc 	}
135937584Smarc 	splx(s);
13609578Ssam 	/*
13619578Ssam 	 * Hang the process if it's in the background.
13629578Ssam 	 */
136364416Sbostic 	p = curproc;
136464416Sbostic 	if (isbackground(p, tp) &&
136564576Sbostic 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
136647545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
136747545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
136847545Skarels 	     p->p_pgrp->pg_jobc) {
136947545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
137064416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
137140712Skarels 			goto out;
137221776Sbloom 		goto loop;
13737502Sroot 	}
13749578Ssam 	/*
137564416Sbostic 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
137664416Sbostic 	 * output translation.  Keep track of high water mark, sleep on
137764416Sbostic 	 * overflow awaiting device aid in acquiring new space.
13789578Ssam 	 */
137964878Smckusick 	while (uio->uio_resid > 0 || cc > 0) {
138064416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO)) {
138140712Skarels 			uio->uio_resid = 0;
138240712Skarels 			return (0);
138340712Skarels 		}
138440712Skarels 		if (tp->t_outq.c_cc > hiwat)
138532067Skarels 			goto ovhiwat;
13869578Ssam 		/*
138764416Sbostic 		 * Grab a hunk of data from the user, unless we have some
138864416Sbostic 		 * leftover from last time.
13899578Ssam 		 */
13907822Sroot 		if (cc == 0) {
139140712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139240712Skarels 			cp = obuf;
139340712Skarels 			error = uiomove(cp, cc, uio);
139440712Skarels 			if (error) {
139540712Skarels 				cc = 0;
139640712Skarels 				break;
139740712Skarels 			}
13987822Sroot 		}
13999578Ssam 		/*
14009578Ssam 		 * If nothing fancy need be done, grab those characters we
14019578Ssam 		 * can handle without any of ttyoutput's processing and
14029578Ssam 		 * just transfer them to the output q.  For those chars
14039578Ssam 		 * which require special processing (as indicated by the
140464416Sbostic 		 * bits in char_type), call ttyoutput.  After processing
14059578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14069578Ssam 		 * immediately.
14079578Ssam 		 */
14089578Ssam 		while (cc > 0) {
140964416Sbostic 			if (!ISSET(tp->t_oflag, OPOST))
14107502Sroot 				ce = cc;
14117502Sroot 			else {
141264416Sbostic 				ce = cc - scanc((u_int)cc, (u_char *)cp,
141364416Sbostic 				   (u_char *)char_type, CCLASSMASK);
14149578Ssam 				/*
14159578Ssam 				 * If ce is zero, then we're processing
14169578Ssam 				 * a special character through ttyoutput.
14179578Ssam 				 */
14189578Ssam 				if (ce == 0) {
14197502Sroot 					tp->t_rocount = 0;
14207502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142164416Sbostic 						/* No Clists, wait a bit. */
142264416Sbostic 						ttstart(tp);
142364416Sbostic 						if (error = ttysleep(tp, &lbolt,
142464416Sbostic 						    TTOPRI | PCATCH, ttybuf, 0))
142564416Sbostic 							break;
142664416Sbostic 						goto loop;
14277502Sroot 					}
142864416Sbostic 					cp++;
142964416Sbostic 					cc--;
143064416Sbostic 					if (ISSET(tp->t_lflag, FLUSHO) ||
14319578Ssam 					    tp->t_outq.c_cc > hiwat)
14327502Sroot 						goto ovhiwat;
14339578Ssam 					continue;
14347502Sroot 				}
14357502Sroot 			}
14369578Ssam 			/*
143764416Sbostic 			 * A bunch of normal characters have been found.
143864416Sbostic 			 * Transfer them en masse to the output queue and
14399578Ssam 			 * continue processing at the top of the loop.
14409578Ssam 			 * If there are any further characters in this
14419578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14429578Ssam 			 * requiring special handling by ttyoutput.
14439578Ssam 			 */
14447502Sroot 			tp->t_rocount = 0;
14459578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14469578Ssam 			ce -= i;
144764530Sbostic 			tp->t_column += ce;
14489578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
144935811Smarc 			tp->t_outcc += ce;
14509578Ssam 			if (i > 0) {
145164416Sbostic 				/* No Clists, wait a bit. */
14527502Sroot 				ttstart(tp);
145364416Sbostic 				if (error = ttysleep(tp,
145464416Sbostic 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
145540712Skarels 					break;
145621776Sbloom 				goto loop;
14577502Sroot 			}
145864416Sbostic 			if (ISSET(tp->t_lflag, FLUSHO) ||
145964416Sbostic 			    tp->t_outq.c_cc > hiwat)
146040712Skarels 				break;
14617502Sroot 		}
146235811Smarc 		ttstart(tp);
14637502Sroot 	}
146440712Skarels out:
146540712Skarels 	/*
146664416Sbostic 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
146764416Sbostic 	 * offset and iov pointers have moved forward, but it doesn't matter
146864416Sbostic 	 * (the call will either return short or restart with a new uio).
146940712Skarels 	 */
147040712Skarels 	uio->uio_resid += cc;
14718520Sroot 	return (error);
147240712Skarels 
14737502Sroot ovhiwat:
147432067Skarels 	ttstart(tp);
147532067Skarels 	s = spltty();
14769578Ssam 	/*
147735811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
147832067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14799578Ssam 	 */
14807502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14819578Ssam 		splx(s);
14827502Sroot 		goto loop;
14837502Sroot 	}
148437728Smckusick 	if (flag & IO_NDELAY) {
148517545Skarels 		splx(s);
148640712Skarels 		uio->uio_resid += cc;
148764416Sbostic 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14887502Sroot 	}
148964416Sbostic 	SET(tp->t_state, TS_ASLEEP);
149064416Sbostic 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14919578Ssam 	splx(s);
149243377Smarc 	if (error)
149340712Skarels 		goto out;
14947502Sroot 	goto loop;
14957502Sroot }
14967502Sroot 
14977502Sroot /*
14987502Sroot  * Rubout one character from the rawq of tp
14997502Sroot  * as cleanly as possible.
15007502Sroot  */
150164416Sbostic void
15027502Sroot ttyrub(c, tp)
150364416Sbostic 	register int c;
15047625Ssam 	register struct tty *tp;
15057502Sroot {
15067502Sroot 	register char *cp;
15077502Sroot 	register int savecol;
150864416Sbostic 	int tabc, s;
15097502Sroot 
151064416Sbostic 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15117502Sroot 		return;
151264416Sbostic 	CLR(tp->t_lflag, FLUSHO);
151364416Sbostic 	if (ISSET(tp->t_lflag, ECHOE)) {
15147502Sroot 		if (tp->t_rocount == 0) {
15157502Sroot 			/*
15167502Sroot 			 * Screwed by ttwrite; retype
15177502Sroot 			 */
15187502Sroot 			ttyretype(tp);
15197502Sroot 			return;
15207502Sroot 		}
152164416Sbostic 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15227502Sroot 			ttyrubo(tp, 2);
152364576Sbostic 		else {
152464576Sbostic 			CLR(c, ~TTY_CHARMASK);
152564576Sbostic 			switch (CCLASS(c)) {
152664576Sbostic 			case ORDINARY:
152764576Sbostic 				ttyrubo(tp, 1);
152864576Sbostic 				break;
152964576Sbostic 			case BACKSPACE:
153064576Sbostic 			case CONTROL:
153164576Sbostic 			case NEWLINE:
153264576Sbostic 			case RETURN:
153364576Sbostic 			case VTAB:
153464576Sbostic 				if (ISSET(tp->t_lflag, ECHOCTL))
153564576Sbostic 					ttyrubo(tp, 2);
153664576Sbostic 				break;
153764576Sbostic 			case TAB:
153864576Sbostic 				if (tp->t_rocount < tp->t_rawq.c_cc) {
153964576Sbostic 					ttyretype(tp);
154064576Sbostic 					return;
154164576Sbostic 				}
154264576Sbostic 				s = spltty();
154364576Sbostic 				savecol = tp->t_column;
154464576Sbostic 				SET(tp->t_state, TS_CNTTB);
154564576Sbostic 				SET(tp->t_lflag, FLUSHO);
154664576Sbostic 				tp->t_column = tp->t_rocol;
154764576Sbostic 				cp = tp->t_rawq.c_cf;
154864576Sbostic 				if (cp)
154964576Sbostic 					tabc = *cp;	/* XXX FIX NEXTC */
155064576Sbostic 				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
155164576Sbostic 					ttyecho(tabc, tp);
155264576Sbostic 				CLR(tp->t_lflag, FLUSHO);
155364576Sbostic 				CLR(tp->t_state, TS_CNTTB);
155464576Sbostic 				splx(s);
155564416Sbostic 
155664576Sbostic 				/* savecol will now be length of the tab. */
155764576Sbostic 				savecol -= tp->t_column;
155864576Sbostic 				tp->t_column += savecol;
155964576Sbostic 				if (savecol > 8)
156064576Sbostic 					savecol = 8;	/* overflow screw */
156164576Sbostic 				while (--savecol >= 0)
156264576Sbostic 					(void)ttyoutput('\b', tp);
156364576Sbostic 				break;
156464576Sbostic 			default:			/* XXX */
156564416Sbostic #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
156664576Sbostic 				(void)printf(PANICSTR, c, CCLASS(c));
156764416Sbostic #ifdef notdef
156864576Sbostic 				panic(PANICSTR, c, CCLASS(c));
156964416Sbostic #endif
157064576Sbostic 			}
157135811Smarc 		}
157264416Sbostic 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
157364416Sbostic 		if (!ISSET(tp->t_state, TS_ERASE)) {
157464416Sbostic 			SET(tp->t_state, TS_ERASE);
157564416Sbostic 			(void)ttyoutput('\\', tp);
15767502Sroot 		}
15777502Sroot 		ttyecho(c, tp);
15787502Sroot 	} else
157935811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
158064416Sbostic 	--tp->t_rocount;
15817502Sroot }
15827502Sroot 
15837502Sroot /*
158464416Sbostic  * Back over cnt characters, erasing them.
15857502Sroot  */
158664416Sbostic static void
15877502Sroot ttyrubo(tp, cnt)
15887625Ssam 	register struct tty *tp;
15897625Ssam 	int cnt;
15907502Sroot {
15917502Sroot 
159264416Sbostic 	while (cnt-- > 0) {
159364416Sbostic 		(void)ttyoutput('\b', tp);
159464416Sbostic 		(void)ttyoutput(' ', tp);
159564416Sbostic 		(void)ttyoutput('\b', tp);
159664416Sbostic 	}
15977502Sroot }
15987502Sroot 
15997502Sroot /*
160064416Sbostic  * ttyretype --
160164416Sbostic  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
160264416Sbostic  *	been checked.
16037502Sroot  */
160464416Sbostic void
16057502Sroot ttyretype(tp)
16067625Ssam 	register struct tty *tp;
16077502Sroot {
16087502Sroot 	register char *cp;
160935811Smarc 	int s, c;
16107502Sroot 
161164416Sbostic 	/* Echo the reprint character. */
161235811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
161335811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
161464416Sbostic 
161564416Sbostic 	(void)ttyoutput('\n', tp);
161664416Sbostic 
161764416Sbostic 	/*
161864416Sbostic 	 * XXX
161964416Sbostic 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162064416Sbostic 	 * BIT OF FIRST CHAR.
162164416Sbostic 	 */
162217545Skarels 	s = spltty();
162364416Sbostic 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
162464416Sbostic 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
162535811Smarc 		ttyecho(c, tp);
162664416Sbostic 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
162764416Sbostic 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
162835811Smarc 		ttyecho(c, tp);
162964416Sbostic 	CLR(tp->t_state, TS_ERASE);
16307502Sroot 	splx(s);
163164416Sbostic 
16327502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16337502Sroot 	tp->t_rocol = 0;
16347502Sroot }
16357502Sroot 
16367502Sroot /*
163735811Smarc  * Echo a typed character to the terminal.
16387502Sroot  */
163964416Sbostic static void
16407502Sroot ttyecho(c, tp)
164164416Sbostic 	register int c;
16427625Ssam 	register struct tty *tp;
16437502Sroot {
164464416Sbostic 
164564416Sbostic 	if (!ISSET(tp->t_state, TS_CNTTB))
164664416Sbostic 		CLR(tp->t_lflag, FLUSHO);
164764416Sbostic 	if ((!ISSET(tp->t_lflag, ECHO) &&
164864416Sbostic 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
164964416Sbostic 	    ISSET(tp->t_lflag, EXTPROC))
16507502Sroot 		return;
165164416Sbostic 	if (ISSET(tp->t_lflag, ECHOCTL) &&
165264576Sbostic 	    (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
165364576Sbostic 	    ISSET(c, TTY_CHARMASK) == 0177)) {
165464416Sbostic 		(void)ttyoutput('^', tp);
165564576Sbostic 		CLR(c, ~TTY_CHARMASK);
165664416Sbostic 		if (c == 0177)
165764416Sbostic 			c = '?';
165864416Sbostic 		else
165964416Sbostic 			c += 'A' - 1;
16607502Sroot 	}
166164416Sbostic 	(void)ttyoutput(c, tp);
16627502Sroot }
16637502Sroot 
16647502Sroot /*
166549380Skarels  * Wake up any readers on a tty.
166649380Skarels  */
166764416Sbostic void
16687502Sroot ttwakeup(tp)
166947545Skarels 	register struct tty *tp;
16707502Sroot {
16717502Sroot 
167252522Smckusick 	selwakeup(&tp->t_rsel);
167364416Sbostic 	if (ISSET(tp->t_state, TS_ASYNC))
167464416Sbostic 		pgsignal(tp->t_pgrp, SIGIO, 1);
16757502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16767502Sroot }
167735811Smarc 
167835811Smarc /*
167948439Skarels  * Look up a code for a specified speed in a conversion table;
168048439Skarels  * used by drivers to map software speed values to hardware parameters.
168148439Skarels  */
168264416Sbostic int
168348439Skarels ttspeedtab(speed, table)
168452485Storek 	int speed;
168548439Skarels 	register struct speedtab *table;
168648439Skarels {
168748439Skarels 
168848439Skarels 	for ( ; table->sp_speed != -1; table++)
168948439Skarels 		if (table->sp_speed == speed)
169048439Skarels 			return (table->sp_code);
169148439Skarels 	return (-1);
169248439Skarels }
169348439Skarels 
169448439Skarels /*
169564416Sbostic  * Set tty hi and low water marks.
169635811Smarc  *
169735811Smarc  * Try to arrange the dynamics so there's about one second
169835811Smarc  * from hi to low water.
169964416Sbostic  *
170035811Smarc  */
170164416Sbostic void
170235811Smarc ttsetwater(tp)
170335811Smarc 	struct tty *tp;
170435811Smarc {
170564416Sbostic 	register int cps, x;
170635811Smarc 
170764416Sbostic #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
170864416Sbostic 
170964416Sbostic 	cps = tp->t_ospeed / 10;
171064416Sbostic 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
171135811Smarc 	x += cps;
171264416Sbostic 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
171335811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
171464416Sbostic #undef	CLAMP
171535811Smarc }
171635811Smarc 
171739407Smarc /*
171839407Smarc  * Report on state of foreground process group.
171939407Smarc  */
172064416Sbostic void
172139407Smarc ttyinfo(tp)
172249907Sbostic 	register struct tty *tp;
172339407Smarc {
172449907Sbostic 	register struct proc *p, *pick;
172541177Smarc 	struct timeval utime, stime;
172649907Sbostic 	int tmp;
172739407Smarc 
172864416Sbostic 	if (ttycheckoutq(tp,0) == 0)
172939407Smarc 		return;
173049907Sbostic 
173149907Sbostic 	/* Print load average. */
173252666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
173349907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
173449907Sbostic 
173539555Smarc 	if (tp->t_session == NULL)
173649907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
173741177Smarc 	else if (tp->t_pgrp == NULL)
173849907Sbostic 		ttyprintf(tp, "no foreground process group\n");
173941177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
174049907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174139407Smarc 	else {
174249907Sbostic 		/* Pick interesting process. */
174349907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
174441177Smarc 			if (proc_compare(pick, p))
174541177Smarc 				pick = p;
174649907Sbostic 
174749907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
174849907Sbostic 		    pick->p_stat == SRUN ? "running" :
174949907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
175049907Sbostic 
175154782Storek 		calcru(pick, &utime, &stime, NULL);
175239407Smarc 
175349907Sbostic 		/* Print user time. */
175449907Sbostic 		ttyprintf(tp, "%d.%02du ",
175549907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
175641177Smarc 
175749907Sbostic 		/* Print system time. */
175849907Sbostic 		ttyprintf(tp, "%d.%02ds ",
175949907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176049907Sbostic 
176149907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
176249907Sbostic 		/* Print percentage cpu, resident set size. */
176349907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
176449907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
176552485Storek 		    tmp / 100,
176652485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
1767*65549Smckusick #ifdef pmap_resident_count
1768*65549Smckusick 			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
1769*65549Smckusick #else
1770*65549Smckusick 			pgtok(pick->p_vmspace->vm_rssize)
1771*65549Smckusick #endif
1772*65549Smckusick 			);
177341177Smarc 	}
177449907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
177541177Smarc }
177641177Smarc 
177741177Smarc /*
177841177Smarc  * Returns 1 if p2 is "better" than p1
177941177Smarc  *
178041177Smarc  * The algorithm for picking the "interesting" process is thus:
178141177Smarc  *
178264576Sbostic  *	1) Only foreground processes are eligible - implied.
178364576Sbostic  *	2) Runnable processes are favored over anything else.  The runner
178464576Sbostic  *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
178541177Smarc  *	   broken by picking the highest pid.
178664576Sbostic  *	3) The sleeper with the shortest sleep time is next.  With ties,
178764576Sbostic  *	   we pick out just "short-term" sleepers (P_SINTR == 0).
178864576Sbostic  *	4) Further ties are broken by picking the highest pid.
178941177Smarc  */
179064576Sbostic #define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179145723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179245723Smckusick #define ONLYA   2
179345723Smckusick #define ONLYB   1
179445723Smckusick #define BOTH    3
179564576Sbostic 
179649907Sbostic static int
179741177Smarc proc_compare(p1, p2)
179841177Smarc 	register struct proc *p1, *p2;
179941177Smarc {
180041177Smarc 
180141177Smarc 	if (p1 == NULL)
180241177Smarc 		return (1);
180341177Smarc 	/*
180441177Smarc 	 * see if at least one of them is runnable
180541177Smarc 	 */
180664576Sbostic 	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
180745723Smckusick 	case ONLYA:
180845723Smckusick 		return (0);
180945723Smckusick 	case ONLYB:
181041177Smarc 		return (1);
181145723Smckusick 	case BOTH:
181241177Smarc 		/*
181341177Smarc 		 * tie - favor one with highest recent cpu utilization
181441177Smarc 		 */
181564576Sbostic 		if (p2->p_estcpu > p1->p_estcpu)
181641177Smarc 			return (1);
181764576Sbostic 		if (p1->p_estcpu > p2->p_estcpu)
181841177Smarc 			return (0);
181941177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182041177Smarc 	}
182145723Smckusick 	/*
182245723Smckusick  	 * weed out zombies
182345723Smckusick 	 */
182445723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
182545723Smckusick 	case ONLYA:
182645723Smckusick 		return (1);
182745723Smckusick 	case ONLYB:
182845723Smckusick 		return (0);
182945723Smckusick 	case BOTH:
183045723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183145723Smckusick 	}
183264416Sbostic 	/*
183341177Smarc 	 * pick the one with the smallest sleep time
183441177Smarc 	 */
183541177Smarc 	if (p2->p_slptime > p1->p_slptime)
183641177Smarc 		return (0);
183741177Smarc 	if (p1->p_slptime > p2->p_slptime)
183841177Smarc 		return (1);
183941177Smarc 	/*
184041177Smarc 	 * favor one sleeping in a non-interruptible sleep
184141177Smarc 	 */
184264576Sbostic 	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
184341177Smarc 		return (1);
184464576Sbostic 	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
184541177Smarc 		return (0);
184647545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
184741177Smarc }
184845723Smckusick 
184939555Smarc /*
185039555Smarc  * Output char to tty; console putchar style.
185139555Smarc  */
185264416Sbostic int
185339555Smarc tputchar(c, tp)
185439555Smarc 	int c;
185539555Smarc 	struct tty *tp;
185639555Smarc {
185764416Sbostic 	register int s;
185839555Smarc 
185964416Sbostic 	s = spltty();
186064416Sbostic 	if (ISSET(tp->t_state,
186164416Sbostic 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
186239555Smarc 		splx(s);
186364416Sbostic 		return (-1);
186439555Smarc 	}
186564416Sbostic 	if (c == '\n')
186664416Sbostic 		(void)ttyoutput('\r', tp);
186764416Sbostic 	(void)ttyoutput(c, tp);
186864416Sbostic 	ttstart(tp);
186939555Smarc 	splx(s);
187064416Sbostic 	return (0);
187139555Smarc }
187243377Smarc 
187344419Smarc /*
187464416Sbostic  * Sleep on chan, returning ERESTART if tty changed while we napped and
187564416Sbostic  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
187664416Sbostic  * the tty is revoked, restarting a pending call will redo validation done
187764416Sbostic  * at the start of the call.
187844419Smarc  */
187964416Sbostic int
188043377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188143377Smarc 	struct tty *tp;
188264416Sbostic 	void *chan;
188364416Sbostic 	int pri, timo;
188443377Smarc 	char *wmesg;
188543377Smarc {
188643377Smarc 	int error;
188764416Sbostic 	short gen;
188843377Smarc 
188964416Sbostic 	gen = tp->t_gen;
189043377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
189143377Smarc 		return (error);
189264416Sbostic 	return (tp->t_gen == gen ? 0 : ERESTART);
189343377Smarc }
1894