xref: /csrg-svn/sys/kern/tty.c (revision 67732)
149594Sbostic /*-
263178Sbostic  * Copyright (c) 1982, 1986, 1990, 1991, 1993
363178Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923387Smckusick  *
1049594Sbostic  * %sccs.include.redist.c%
1149594Sbostic  *
12*67732Smckusick  *	@(#)tty.c	8.12 (Berkeley) 08/22/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;
50867115Smckusick 	register int notout, col, s;
50964416Sbostic 
51064416Sbostic 	oflag = tp->t_oflag;
51164416Sbostic 	if (!ISSET(oflag, OPOST)) {
51264416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO))
5137502Sroot 			return (-1);
5147502Sroot 		if (putc(c, &tp->t_outq))
5157625Ssam 			return (c);
5167502Sroot 		tk_nout++;
51735811Smarc 		tp->t_outcc++;
5187502Sroot 		return (-1);
5197502Sroot 	}
5207502Sroot 	/*
52164416Sbostic 	 * Do tab expansion if OXTABS is set.  Special case if we external
52264416Sbostic 	 * processing, we don't do the tab expansion because we'll probably
52364416Sbostic 	 * get it wrong.  If tab expansion needs to be done, let it happen
52464416Sbostic 	 * externally.
5257502Sroot 	 */
52664576Sbostic 	CLR(c, ~TTY_CHARMASK);
52764416Sbostic 	if (c == '\t' &&
52864416Sbostic 	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
52964530Sbostic 		c = 8 - (tp->t_column & 7);
53067115Smckusick 		if (ISSET(tp->t_lflag, FLUSHO)) {
53167115Smckusick 			notout = 0;
53267115Smckusick 		} else {
53364416Sbostic 			s = spltty();		/* Don't interrupt tabs. */
53467115Smckusick 			notout = b_to_q("        ", c, &tp->t_outq);
53567115Smckusick 			c -= notout;
5367502Sroot 			tk_nout += c;
53735811Smarc 			tp->t_outcc += c;
5387502Sroot 			splx(s);
5397502Sroot 		}
54064530Sbostic 		tp->t_column += c;
54167115Smckusick 		return (notout ? '\t' : -1);
5427502Sroot 	}
54364416Sbostic 	if (c == CEOT && ISSET(oflag, ONOEOT))
54447545Skarels 		return (-1);
54564576Sbostic 
5467502Sroot 	/*
54749380Skarels 	 * Newline translation: if ONLCR is set,
54849380Skarels 	 * translate newline into "\r\n".
5497502Sroot 	 */
55064576Sbostic 	if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
55164576Sbostic 		tk_nout++;
55264576Sbostic 		tp->t_outcc++;
55364576Sbostic 		if (putc('\r', &tp->t_outq))
55464576Sbostic 			return (c);
55564576Sbostic 	}
55664576Sbostic 	tk_nout++;
55764576Sbostic 	tp->t_outcc++;
55864416Sbostic 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
55935811Smarc 		return (c);
56047545Skarels 
56164530Sbostic 	col = tp->t_column;
56249380Skarels 	switch (CCLASS(c)) {
5637502Sroot 	case BACKSPACE:
56449380Skarels 		if (col > 0)
56564416Sbostic 			--col;
5667502Sroot 		break;
56764416Sbostic 	case CONTROL:
56864416Sbostic 		break;
5697502Sroot 	case NEWLINE:
57064416Sbostic 	case RETURN:
57149380Skarels 		col = 0;
5727502Sroot 		break;
57364416Sbostic 	case ORDINARY:
57464416Sbostic 		++col;
57564416Sbostic 		break;
5767502Sroot 	case TAB:
57764416Sbostic 		col = (col + 8) & ~7;
5787502Sroot 		break;
5797502Sroot 	}
58064530Sbostic 	tp->t_column = col;
5817502Sroot 	return (-1);
5827502Sroot }
5837502Sroot 
5847502Sroot /*
58564576Sbostic  * Ioctls for all tty devices.  Called after line-discipline specific ioctl
58664576Sbostic  * has been called to do discipline-specific functions and/or reject any
58764576Sbostic  * of these ioctl commands.
58864416Sbostic  */
58964416Sbostic /* ARGSUSED */
59064416Sbostic int
59164576Sbostic ttioctl(tp, cmd, data, flag)
59264416Sbostic 	register struct tty *tp;
59364576Sbostic 	int cmd, flag;
59464416Sbostic 	void *data;
59564416Sbostic {
59664416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
59764576Sbostic 	extern int nlinesw;
59864416Sbostic 	register struct proc *p;
59964416Sbostic 	int s, error;
60064416Sbostic 
60164416Sbostic 	p = curproc;			/* XXX */
60264416Sbostic 
60364416Sbostic 	/* If the ioctl involves modification, hang if in the background. */
60464576Sbostic 	switch (cmd) {
60564416Sbostic 	case  TIOCFLUSH:
60664416Sbostic 	case  TIOCSETA:
60764416Sbostic 	case  TIOCSETD:
60864416Sbostic 	case  TIOCSETAF:
60964416Sbostic 	case  TIOCSETAW:
61064416Sbostic #ifdef notdef
61164416Sbostic 	case  TIOCSPGRP:
61264416Sbostic #endif
61364416Sbostic 	case  TIOCSTI:
61464416Sbostic 	case  TIOCSWINSZ:
61564416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
61664416Sbostic 	case  TIOCLBIC:
61764416Sbostic 	case  TIOCLBIS:
61864416Sbostic 	case  TIOCLSET:
61964416Sbostic 	case  TIOCSETC:
62064416Sbostic 	case OTIOCSETD:
62164416Sbostic 	case  TIOCSETN:
62264416Sbostic 	case  TIOCSETP:
62364416Sbostic 	case  TIOCSLTC:
62464416Sbostic #endif
62564416Sbostic 		while (isbackground(curproc, tp) &&
62664576Sbostic 		    p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
62764416Sbostic 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
62864416Sbostic 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
62964416Sbostic 			pgsignal(p->p_pgrp, SIGTTOU, 1);
63064416Sbostic 			if (error = ttysleep(tp,
63164416Sbostic 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
63264416Sbostic 				return (error);
63364416Sbostic 		}
63464416Sbostic 		break;
63564416Sbostic 	}
63664416Sbostic 
63764576Sbostic 	switch (cmd) {			/* Process the ioctl. */
63864416Sbostic 	case FIOASYNC:			/* set/clear async i/o */
63964416Sbostic 		s = spltty();
64064416Sbostic 		if (*(int *)data)
64164416Sbostic 			SET(tp->t_state, TS_ASYNC);
64264416Sbostic 		else
64364416Sbostic 			CLR(tp->t_state, TS_ASYNC);
64464416Sbostic 		splx(s);
64564416Sbostic 		break;
64664416Sbostic 	case FIONBIO:			/* set/clear non-blocking i/o */
64764416Sbostic 		break;			/* XXX: delete. */
64864416Sbostic 	case FIONREAD:			/* get # bytes to read */
64964416Sbostic 		*(int *)data = ttnread(tp);
65064416Sbostic 		break;
65164416Sbostic 	case TIOCEXCL:			/* set exclusive use of tty */
65264416Sbostic 		s = spltty();
65364416Sbostic 		SET(tp->t_state, TS_XCLUDE);
65464416Sbostic 		splx(s);
65564416Sbostic 		break;
65664416Sbostic 	case TIOCFLUSH: {		/* flush buffers */
65764416Sbostic 		register int flags = *(int *)data;
65864416Sbostic 
65964416Sbostic 		if (flags == 0)
66064416Sbostic 			flags = FREAD | FWRITE;
66164416Sbostic 		else
66264416Sbostic 			flags &= FREAD | FWRITE;
66364416Sbostic 		ttyflush(tp, flags);
66464416Sbostic 		break;
66564416Sbostic 	}
66664416Sbostic 	case TIOCCONS:			/* become virtual console */
66764416Sbostic 		if (*(int *)data) {
66864416Sbostic 			if (constty && constty != tp &&
66964416Sbostic 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
67064416Sbostic 			    (TS_CARR_ON | TS_ISOPEN))
67164416Sbostic 				return (EBUSY);
67264416Sbostic #ifndef	UCONSOLE
67364416Sbostic 			if (error = suser(p->p_ucred, &p->p_acflag))
67464416Sbostic 				return (error);
67564416Sbostic #endif
67664416Sbostic 			constty = tp;
67764416Sbostic 		} else if (tp == constty)
67864416Sbostic 			constty = NULL;
67964416Sbostic 		break;
68064416Sbostic 	case TIOCDRAIN:			/* wait till output drained */
68164416Sbostic 		if (error = ttywait(tp))
68264416Sbostic 			return (error);
68364416Sbostic 		break;
68464416Sbostic 	case TIOCGETA: {		/* get termios struct */
68564416Sbostic 		struct termios *t = (struct termios *)data;
68664416Sbostic 
68764416Sbostic 		bcopy(&tp->t_termios, t, sizeof(struct termios));
68864416Sbostic 		break;
68964416Sbostic 	}
69064416Sbostic 	case TIOCGETD:			/* get line discipline */
69164416Sbostic 		*(int *)data = tp->t_line;
69264416Sbostic 		break;
69364416Sbostic 	case TIOCGWINSZ:		/* get window size */
69464416Sbostic 		*(struct winsize *)data = tp->t_winsize;
69564416Sbostic 		break;
69664416Sbostic 	case TIOCGPGRP:			/* get pgrp of tty */
69764416Sbostic 		if (!isctty(p, tp))
69864416Sbostic 			return (ENOTTY);
69964416Sbostic 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
70064416Sbostic 		break;
70164416Sbostic #ifdef TIOCHPCL
70264416Sbostic 	case TIOCHPCL:			/* hang up on last close */
70364416Sbostic 		s = spltty();
70464576Sbostic 		SET(tp->t_cflag, HUPCL);
70564416Sbostic 		splx(s);
70664416Sbostic 		break;
70764416Sbostic #endif
70864416Sbostic 	case TIOCNXCL:			/* reset exclusive use of tty */
70964416Sbostic 		s = spltty();
71064416Sbostic 		CLR(tp->t_state, TS_XCLUDE);
71164416Sbostic 		splx(s);
71264416Sbostic 		break;
71364416Sbostic 	case TIOCOUTQ:			/* output queue size */
71464416Sbostic 		*(int *)data = tp->t_outq.c_cc;
71564416Sbostic 		break;
71664416Sbostic 	case TIOCSETA:			/* set termios struct */
71764416Sbostic 	case TIOCSETAW:			/* drain output, set */
71864416Sbostic 	case TIOCSETAF: {		/* drn out, fls in, set */
71964416Sbostic 		register struct termios *t = (struct termios *)data;
72064416Sbostic 
72164416Sbostic 		s = spltty();
72264576Sbostic 		if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
72364416Sbostic 			if (error = ttywait(tp)) {
72464416Sbostic 				splx(s);
72564416Sbostic 				return (error);
72664416Sbostic 			}
72764576Sbostic 			if (cmd == TIOCSETAF)
72864416Sbostic 				ttyflush(tp, FREAD);
72964416Sbostic 		}
73064416Sbostic 		if (!ISSET(t->c_cflag, CIGNORE)) {
73164416Sbostic 			/*
73264416Sbostic 			 * Set device hardware.
73364416Sbostic 			 */
73464416Sbostic 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
73564416Sbostic 				splx(s);
73664416Sbostic 				return (error);
73764416Sbostic 			} else {
73864416Sbostic 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
73964416Sbostic 				    ISSET(tp->t_cflag, CLOCAL) &&
74064416Sbostic 				    !ISSET(t->c_cflag, CLOCAL)) {
74164416Sbostic 					CLR(tp->t_state, TS_ISOPEN);
74264416Sbostic 					SET(tp->t_state, TS_WOPEN);
74364416Sbostic 					ttwakeup(tp);
74464416Sbostic 				}
74564416Sbostic 				tp->t_cflag = t->c_cflag;
74664416Sbostic 				tp->t_ispeed = t->c_ispeed;
74764416Sbostic 				tp->t_ospeed = t->c_ospeed;
74864416Sbostic 			}
74964416Sbostic 			ttsetwater(tp);
75064416Sbostic 		}
75164576Sbostic 		if (cmd != TIOCSETAF) {
75264416Sbostic 			if (ISSET(t->c_lflag, ICANON) !=
75364416Sbostic 			    ISSET(tp->t_lflag, ICANON))
75464416Sbostic 				if (ISSET(t->c_lflag, ICANON)) {
75564576Sbostic 					SET(tp->t_lflag, PENDIN);
75664416Sbostic 					ttwakeup(tp);
75764416Sbostic 				} else {
75864416Sbostic 					struct clist tq;
75964416Sbostic 
76064416Sbostic 					catq(&tp->t_rawq, &tp->t_canq);
76164416Sbostic 					tq = tp->t_rawq;
76264416Sbostic 					tp->t_rawq = tp->t_canq;
76364416Sbostic 					tp->t_canq = tq;
76465324Sbostic 					CLR(tp->t_lflag, PENDIN);
76564416Sbostic 				}
76664416Sbostic 		}
76764416Sbostic 		tp->t_iflag = t->c_iflag;
76864416Sbostic 		tp->t_oflag = t->c_oflag;
76964416Sbostic 		/*
77064416Sbostic 		 * Make the EXTPROC bit read only.
77164416Sbostic 		 */
77264416Sbostic 		if (ISSET(tp->t_lflag, EXTPROC))
77364416Sbostic 			SET(t->c_lflag, EXTPROC);
77464416Sbostic 		else
77564416Sbostic 			CLR(t->c_lflag, EXTPROC);
77665324Sbostic 		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
77764416Sbostic 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
77864416Sbostic 		splx(s);
77964416Sbostic 		break;
78064416Sbostic 	}
78164416Sbostic 	case TIOCSETD: {		/* set line discipline */
78264416Sbostic 		register int t = *(int *)data;
78364416Sbostic 		dev_t device = tp->t_dev;
78464416Sbostic 
78564576Sbostic 		if ((u_int)t >= nlinesw)
78664416Sbostic 			return (ENXIO);
78764416Sbostic 		if (t != tp->t_line) {
78864416Sbostic 			s = spltty();
78964416Sbostic 			(*linesw[tp->t_line].l_close)(tp, flag);
79064416Sbostic 			error = (*linesw[t].l_open)(device, tp);
79164416Sbostic 			if (error) {
79264416Sbostic 				(void)(*linesw[tp->t_line].l_open)(device, tp);
79364416Sbostic 				splx(s);
79464416Sbostic 				return (error);
79564416Sbostic 			}
79664416Sbostic 			tp->t_line = t;
79764416Sbostic 			splx(s);
79864416Sbostic 		}
79964416Sbostic 		break;
80064416Sbostic 	}
80164416Sbostic 	case TIOCSTART:			/* start output, like ^Q */
80264416Sbostic 		s = spltty();
80364416Sbostic 		if (ISSET(tp->t_state, TS_TTSTOP) ||
80464416Sbostic 		    ISSET(tp->t_lflag, FLUSHO)) {
80564416Sbostic 			CLR(tp->t_lflag, FLUSHO);
80664416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
80764416Sbostic 			ttstart(tp);
80864416Sbostic 		}
80964416Sbostic 		splx(s);
81064416Sbostic 		break;
81164416Sbostic 	case TIOCSTI:			/* simulate terminal input */
81264416Sbostic 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
81364416Sbostic 			return (EPERM);
81464416Sbostic 		if (p->p_ucred->cr_uid && !isctty(p, tp))
81564416Sbostic 			return (EACCES);
81664416Sbostic 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
81764416Sbostic 		break;
81864416Sbostic 	case TIOCSTOP:			/* stop output, like ^S */
81964416Sbostic 		s = spltty();
82064416Sbostic 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
82164416Sbostic 			SET(tp->t_state, TS_TTSTOP);
82264416Sbostic #ifdef sun4c				/* XXX */
82364416Sbostic 			(*tp->t_stop)(tp, 0);
82464416Sbostic #else
82564416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
82664416Sbostic #endif
82764416Sbostic 		}
82864416Sbostic 		splx(s);
82964416Sbostic 		break;
83064416Sbostic 	case TIOCSCTTY:			/* become controlling tty */
83164416Sbostic 		/* Session ctty vnode pointer set in vnode layer. */
83264416Sbostic 		if (!SESS_LEADER(p) ||
83367685Smckusick 		    (p->p_session->s_ttyvp || tp->t_session) &&
83467685Smckusick 		    (tp->t_session != p->p_session))
83564416Sbostic 			return (EPERM);
83664416Sbostic 		tp->t_session = p->p_session;
83764416Sbostic 		tp->t_pgrp = p->p_pgrp;
83864416Sbostic 		p->p_session->s_ttyp = tp;
83964576Sbostic 		p->p_flag |= P_CONTROLT;
84064416Sbostic 		break;
84164416Sbostic 	case TIOCSPGRP: {		/* set pgrp of tty */
84264416Sbostic 		register struct pgrp *pgrp = pgfind(*(int *)data);
84364416Sbostic 
84464416Sbostic 		if (!isctty(p, tp))
84564416Sbostic 			return (ENOTTY);
84664416Sbostic 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
84764416Sbostic 			return (EPERM);
84864416Sbostic 		tp->t_pgrp = pgrp;
84964416Sbostic 		break;
85064416Sbostic 	}
85164416Sbostic 	case TIOCSWINSZ:		/* set window size */
85264416Sbostic 		if (bcmp((caddr_t)&tp->t_winsize, data,
85364416Sbostic 		    sizeof (struct winsize))) {
85464416Sbostic 			tp->t_winsize = *(struct winsize *)data;
85564416Sbostic 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
85664416Sbostic 		}
85764416Sbostic 		break;
85864416Sbostic 	default:
85964416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
86064576Sbostic 		return (ttcompat(tp, cmd, data, flag));
86164416Sbostic #else
86264416Sbostic 		return (-1);
86364416Sbostic #endif
86464416Sbostic 	}
86564416Sbostic 	return (0);
86664416Sbostic }
86764416Sbostic 
86864416Sbostic int
86964416Sbostic ttselect(device, rw, p)
87064416Sbostic 	dev_t device;
87164416Sbostic 	int rw;
87264416Sbostic 	struct proc *p;
87364416Sbostic {
87464416Sbostic 	register struct tty *tp;
87564416Sbostic 	int nread, s;
87664416Sbostic 
87764416Sbostic 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
87864416Sbostic 
87964416Sbostic 	s = spltty();
88064416Sbostic 	switch (rw) {
88164416Sbostic 	case FREAD:
88264416Sbostic 		nread = ttnread(tp);
88364416Sbostic 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
88464416Sbostic 		    !ISSET(tp->t_state, TS_CARR_ON))
88564416Sbostic 			goto win;
88664416Sbostic 		selrecord(p, &tp->t_rsel);
88764416Sbostic 		break;
88864416Sbostic 	case FWRITE:
88964416Sbostic 		if (tp->t_outq.c_cc <= tp->t_lowat) {
89064416Sbostic win:			splx(s);
89164416Sbostic 			return (1);
89264416Sbostic 		}
89364416Sbostic 		selrecord(p, &tp->t_wsel);
89464416Sbostic 		break;
89564416Sbostic 	}
89664416Sbostic 	splx(s);
89764416Sbostic 	return (0);
89864416Sbostic }
89964416Sbostic 
90064416Sbostic static int
90164416Sbostic ttnread(tp)
90264416Sbostic 	struct tty *tp;
90364416Sbostic {
90464416Sbostic 	int nread;
90564416Sbostic 
90664416Sbostic 	if (ISSET(tp->t_lflag, PENDIN))
90764416Sbostic 		ttypend(tp);
90864416Sbostic 	nread = tp->t_canq.c_cc;
90964416Sbostic 	if (!ISSET(tp->t_lflag, ICANON))
91064416Sbostic 		nread += tp->t_rawq.c_cc;
91164416Sbostic 	return (nread);
91264416Sbostic }
91364416Sbostic 
91464416Sbostic /*
91564416Sbostic  * Wait for output to drain.
91664416Sbostic  */
91764416Sbostic int
91864416Sbostic ttywait(tp)
91964416Sbostic 	register struct tty *tp;
92064416Sbostic {
92164416Sbostic 	int error, s;
92264416Sbostic 
92364416Sbostic 	error = 0;
92464416Sbostic 	s = spltty();
92564416Sbostic 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
92664416Sbostic 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
92764416Sbostic 	    && tp->t_oproc) {
92864416Sbostic 		(*tp->t_oproc)(tp);
92964416Sbostic 		SET(tp->t_state, TS_ASLEEP);
93064416Sbostic 		if (error = ttysleep(tp,
93164416Sbostic 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
93264416Sbostic 			break;
93364416Sbostic 	}
93464416Sbostic 	splx(s);
93564416Sbostic 	return (error);
93664416Sbostic }
93764416Sbostic 
93864416Sbostic /*
93964416Sbostic  * Flush if successfully wait.
94064416Sbostic  */
94164416Sbostic int
94264416Sbostic ttywflush(tp)
94364416Sbostic 	struct tty *tp;
94464416Sbostic {
94564416Sbostic 	int error;
94664416Sbostic 
94764416Sbostic 	if ((error = ttywait(tp)) == 0)
94864416Sbostic 		ttyflush(tp, FREAD);
94964416Sbostic 	return (error);
95064416Sbostic }
95164416Sbostic 
95264416Sbostic /*
95364416Sbostic  * Flush tty read and/or write queues, notifying anyone waiting.
95464416Sbostic  */
95564416Sbostic void
95664416Sbostic ttyflush(tp, rw)
95764416Sbostic 	register struct tty *tp;
95864416Sbostic 	int rw;
95964416Sbostic {
96064416Sbostic 	register int s;
96164416Sbostic 
96264416Sbostic 	s = spltty();
96364416Sbostic 	if (rw & FREAD) {
96464416Sbostic 		FLUSHQ(&tp->t_canq);
96564416Sbostic 		FLUSHQ(&tp->t_rawq);
96664416Sbostic 		tp->t_rocount = 0;
96764416Sbostic 		tp->t_rocol = 0;
96864416Sbostic 		CLR(tp->t_state, TS_LOCAL);
96964416Sbostic 		ttwakeup(tp);
97064416Sbostic 	}
97164416Sbostic 	if (rw & FWRITE) {
97264416Sbostic 		CLR(tp->t_state, TS_TTSTOP);
97364416Sbostic #ifdef sun4c						/* XXX */
97464416Sbostic 		(*tp->t_stop)(tp, rw);
97564416Sbostic #else
97664416Sbostic 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
97764416Sbostic #endif
97864416Sbostic 		FLUSHQ(&tp->t_outq);
97964416Sbostic 		wakeup((caddr_t)&tp->t_outq);
98064416Sbostic 		selwakeup(&tp->t_wsel);
98164416Sbostic 	}
98264416Sbostic 	splx(s);
98364416Sbostic }
98464416Sbostic 
98564416Sbostic /*
98664416Sbostic  * Copy in the default termios characters.
98764416Sbostic  */
98864416Sbostic void
98964416Sbostic ttychars(tp)
99064416Sbostic 	struct tty *tp;
99164416Sbostic {
99264416Sbostic 
99364416Sbostic 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
99464416Sbostic }
99564416Sbostic 
99664416Sbostic /*
99764416Sbostic  * Send stop character on input overflow.
99864416Sbostic  */
99964416Sbostic static void
100064416Sbostic ttyblock(tp)
100164416Sbostic 	register struct tty *tp;
100264416Sbostic {
100364416Sbostic 	register int total;
100464416Sbostic 
100564416Sbostic 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
100664416Sbostic 	if (tp->t_rawq.c_cc > TTYHOG) {
100764416Sbostic 		ttyflush(tp, FREAD | FWRITE);
100864416Sbostic 		CLR(tp->t_state, TS_TBLOCK);
100964416Sbostic 	}
101064416Sbostic 	/*
101164416Sbostic 	 * Block further input iff: current input > threshold
101264416Sbostic 	 * AND input is available to user program.
101364416Sbostic 	 */
101464416Sbostic 	if (total >= TTYHOG / 2 &&
101564416Sbostic 	    !ISSET(tp->t_state, TS_TBLOCK) &&
101664416Sbostic 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
101764416Sbostic 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
101864416Sbostic 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
101964416Sbostic 			SET(tp->t_state, TS_TBLOCK);
102064416Sbostic 			ttstart(tp);
102164416Sbostic 		}
102264416Sbostic 	}
102364416Sbostic }
102464416Sbostic 
102564416Sbostic void
102664416Sbostic ttrstrt(tp_arg)
102764416Sbostic 	void *tp_arg;
102864416Sbostic {
102964416Sbostic 	struct tty *tp;
103064416Sbostic 	int s;
103164416Sbostic 
103264416Sbostic #ifdef DIAGNOSTIC
103364416Sbostic 	if (tp_arg == NULL)
103464416Sbostic 		panic("ttrstrt");
103564416Sbostic #endif
103664416Sbostic 	tp = tp_arg;
103764416Sbostic 	s = spltty();
103864416Sbostic 
103964416Sbostic 	CLR(tp->t_state, TS_TIMEOUT);
104064416Sbostic 	ttstart(tp);
104164416Sbostic 
104264416Sbostic 	splx(s);
104364416Sbostic }
104464416Sbostic 
104564416Sbostic int
104664416Sbostic ttstart(tp)
104764416Sbostic 	struct tty *tp;
104864416Sbostic {
104964416Sbostic 
105064416Sbostic 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
105164416Sbostic 		(*tp->t_oproc)(tp);
105264416Sbostic 	return (0);
105364416Sbostic }
105464416Sbostic 
105564416Sbostic /*
105664416Sbostic  * "close" a line discipline
105764416Sbostic  */
105864416Sbostic int
105964416Sbostic ttylclose(tp, flag)
106064416Sbostic 	struct tty *tp;
106164416Sbostic 	int flag;
106264416Sbostic {
106364416Sbostic 
106464416Sbostic 	if (flag & IO_NDELAY)
106564416Sbostic 		ttyflush(tp, FREAD | FWRITE);
106664416Sbostic 	else
106764416Sbostic 		ttywflush(tp);
106864416Sbostic 	return (0);
106964416Sbostic }
107064416Sbostic 
107164416Sbostic /*
107264416Sbostic  * Handle modem control transition on a tty.
107364416Sbostic  * Flag indicates new state of carrier.
107464416Sbostic  * Returns 0 if the line should be turned off, otherwise 1.
107564416Sbostic  */
107664416Sbostic int
107764416Sbostic ttymodem(tp, flag)
107864416Sbostic 	register struct tty *tp;
107964416Sbostic 	int flag;
108064416Sbostic {
108164416Sbostic 
108264416Sbostic 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
108364416Sbostic 		/*
108464416Sbostic 		 * MDMBUF: do flow control according to carrier flag
108564416Sbostic 		 */
108664416Sbostic 		if (flag) {
108764416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
108864416Sbostic 			ttstart(tp);
108964416Sbostic 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
109064416Sbostic 			SET(tp->t_state, TS_TTSTOP);
109164416Sbostic #ifdef sun4c						/* XXX */
109264416Sbostic 			(*tp->t_stop)(tp, 0);
109364416Sbostic #else
109464416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
109564416Sbostic #endif
109664416Sbostic 		}
109764416Sbostic 	} else if (flag == 0) {
109864416Sbostic 		/*
109964416Sbostic 		 * Lost carrier.
110064416Sbostic 		 */
110164416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
110264416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN) &&
110364416Sbostic 		    !ISSET(tp->t_cflag, CLOCAL)) {
110464416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
110564416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
110664416Sbostic 			ttyflush(tp, FREAD | FWRITE);
110764416Sbostic 			return (0);
110864416Sbostic 		}
110964416Sbostic 	} else {
111064416Sbostic 		/*
111164416Sbostic 		 * Carrier now on.
111264416Sbostic 		 */
111364416Sbostic 		SET(tp->t_state, TS_CARR_ON);
111464416Sbostic 		ttwakeup(tp);
111564416Sbostic 	}
111664416Sbostic 	return (1);
111764416Sbostic }
111864416Sbostic 
111964416Sbostic /*
112064416Sbostic  * Default modem control routine (for other line disciplines).
112164416Sbostic  * Return argument flag, to turn off device on carrier drop.
112264416Sbostic  */
112364416Sbostic int
112464416Sbostic nullmodem(tp, flag)
112564416Sbostic 	register struct tty *tp;
112664416Sbostic 	int flag;
112764416Sbostic {
112864416Sbostic 
112964416Sbostic 	if (flag)
113064416Sbostic 		SET(tp->t_state, TS_CARR_ON);
113164416Sbostic 	else {
113264416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
113364416Sbostic 		if (!ISSET(tp->t_cflag, CLOCAL)) {
113464416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
113564416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
113664416Sbostic 			return (0);
113764416Sbostic 		}
113864416Sbostic 	}
113964416Sbostic 	return (1);
114064416Sbostic }
114164416Sbostic 
114264416Sbostic /*
114364416Sbostic  * Reinput pending characters after state switch
114464416Sbostic  * call at spltty().
114564416Sbostic  */
114664416Sbostic void
114764416Sbostic ttypend(tp)
114864416Sbostic 	register struct tty *tp;
114964416Sbostic {
115064416Sbostic 	struct clist tq;
115164416Sbostic 	register c;
115264416Sbostic 
115364416Sbostic 	CLR(tp->t_lflag, PENDIN);
115464416Sbostic 	SET(tp->t_state, TS_TYPEN);
115564416Sbostic 	tq = tp->t_rawq;
115664416Sbostic 	tp->t_rawq.c_cc = 0;
115764416Sbostic 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
115864416Sbostic 	while ((c = getc(&tq)) >= 0)
115964416Sbostic 		ttyinput(c, tp);
116064416Sbostic 	CLR(tp->t_state, TS_TYPEN);
116164416Sbostic }
116264416Sbostic 
116364416Sbostic /*
116449380Skarels  * Process a read call on a tty device.
11657502Sroot  */
116664416Sbostic int
116737584Smarc ttread(tp, uio, flag)
11687625Ssam 	register struct tty *tp;
11697722Swnj 	struct uio *uio;
117052485Storek 	int flag;
11717502Sroot {
11727502Sroot 	register struct clist *qp;
117335811Smarc 	register int c;
117441383Smarc 	register long lflag;
117535811Smarc 	register u_char *cc = tp->t_cc;
117647545Skarels 	register struct proc *p = curproc;
11779859Ssam 	int s, first, error = 0;
11787502Sroot 
117964416Sbostic loop:	lflag = tp->t_lflag;
118037584Smarc 	s = spltty();
11819578Ssam 	/*
118264416Sbostic 	 * take pending input first
11839578Ssam 	 */
118464416Sbostic 	if (ISSET(lflag, PENDIN))
11857502Sroot 		ttypend(tp);
11869859Ssam 	splx(s);
118740712Skarels 
11889578Ssam 	/*
11899578Ssam 	 * Hang process if it's in the background.
11909578Ssam 	 */
119147545Skarels 	if (isbackground(p, tp)) {
119247545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
119347545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
119464576Sbostic 		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
11958520Sroot 			return (EIO);
119647545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119764416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
119840712Skarels 			return (error);
119923165Sbloom 		goto loop;
12007502Sroot 	}
120140712Skarels 
12029578Ssam 	/*
120335811Smarc 	 * If canonical, use the canonical queue,
120435811Smarc 	 * else use the raw queue.
120537584Smarc 	 *
120647545Skarels 	 * (should get rid of clists...)
12079578Ssam 	 */
120864416Sbostic 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
120940712Skarels 
12109578Ssam 	/*
121140712Skarels 	 * If there is no input, sleep on rawq
121240712Skarels 	 * awaiting hardware receipt and notification.
121340712Skarels 	 * If we have data, we don't need to check for carrier.
12149578Ssam 	 */
121517545Skarels 	s = spltty();
12169578Ssam 	if (qp->c_cc <= 0) {
121740712Skarels 		int carrier;
121840712Skarels 
121964416Sbostic 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
122064416Sbostic 		    ISSET(tp->t_cflag, CLOCAL);
122164416Sbostic 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12229859Ssam 			splx(s);
122340712Skarels 			return (0);	/* EOF */
12247502Sroot 		}
122537728Smckusick 		if (flag & IO_NDELAY) {
122637584Smarc 			splx(s);
122737584Smarc 			return (EWOULDBLOCK);
122837584Smarc 		}
122964416Sbostic 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
123040712Skarels 		    carrier ? ttyin : ttopen, 0);
12319859Ssam 		splx(s);
123243377Smarc 		if (error)
123340712Skarels 			return (error);
12349578Ssam 		goto loop;
12359578Ssam 	}
12369859Ssam 	splx(s);
123740712Skarels 
12389578Ssam 	/*
123935811Smarc 	 * Input present, check for input mapping and processing.
12409578Ssam 	 */
12419578Ssam 	first = 1;
12429578Ssam 	while ((c = getc(qp)) >= 0) {
12439578Ssam 		/*
124435811Smarc 		 * delayed suspend (^Y)
12459578Ssam 		 */
124664416Sbostic 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
124742882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12489578Ssam 			if (first) {
124964416Sbostic 				if (error = ttysleep(tp,
125064416Sbostic 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
125140712Skarels 					break;
12529578Ssam 				goto loop;
12539578Ssam 			}
12549578Ssam 			break;
12557502Sroot 		}
12569578Ssam 		/*
125735811Smarc 		 * Interpret EOF only in canonical mode.
12589578Ssam 		 */
125964416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12609578Ssam 			break;
12619578Ssam 		/*
12629578Ssam 		 * Give user character.
12639578Ssam 		 */
126440712Skarels  		error = ureadc(c, uio);
12659578Ssam 		if (error)
12669578Ssam 			break;
126714938Smckusick  		if (uio->uio_resid == 0)
12689578Ssam 			break;
12699578Ssam 		/*
127035811Smarc 		 * In canonical mode check for a "break character"
12719578Ssam 		 * marking the end of a "line of input".
12729578Ssam 		 */
127364416Sbostic 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
12749578Ssam 			break;
12759578Ssam 		first = 0;
12767502Sroot 	}
12779578Ssam 	/*
12789578Ssam 	 * Look to unblock output now that (presumably)
12799578Ssam 	 * the input queue has gone down.
12809578Ssam 	 */
128152485Storek 	s = spltty();
128264416Sbostic 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
128347545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
128447545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
128564416Sbostic 			CLR(tp->t_state, TS_TBLOCK);
12867502Sroot 			ttstart(tp);
12877502Sroot 		}
128835811Smarc 	}
128952485Storek 	splx(s);
12908520Sroot 	return (error);
12917502Sroot }
12927502Sroot 
12937502Sroot /*
129464416Sbostic  * Check the output queue on tp for space for a kernel message (from uprintf
129564416Sbostic  * or tprintf).  Allow some space over the normal hiwater mark so we don't
129664416Sbostic  * lose messages due to normal flow control, but don't let the tty run amok.
129764416Sbostic  * Sleeps here are not interruptible, but we return prematurely if new signals
129864416Sbostic  * arrive.
129925391Skarels  */
130064416Sbostic int
130125391Skarels ttycheckoutq(tp, wait)
130225391Skarels 	register struct tty *tp;
130325391Skarels 	int wait;
130425391Skarels {
130530695Skarels 	int hiwat, s, oldsig;
130625391Skarels 
130735811Smarc 	hiwat = tp->t_hiwat;
130825391Skarels 	s = spltty();
130964576Sbostic 	oldsig = wait ? curproc->p_siglist : 0;
131025391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
131129946Skarels 		while (tp->t_outq.c_cc > hiwat) {
131229946Skarels 			ttstart(tp);
131364576Sbostic 			if (wait == 0 || curproc->p_siglist != oldsig) {
131429946Skarels 				splx(s);
131529946Skarels 				return (0);
131629946Skarels 			}
131754782Storek 			timeout((void (*)__P((void *)))wakeup,
131854782Storek 			    (void *)&tp->t_outq, hz);
131964416Sbostic 			SET(tp->t_state, TS_ASLEEP);
132030695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
132125391Skarels 		}
132225391Skarels 	splx(s);
132325391Skarels 	return (1);
132425391Skarels }
132525391Skarels 
132625391Skarels /*
132749380Skarels  * Process a write call on a tty device.
13287502Sroot  */
132964416Sbostic int
133037584Smarc ttwrite(tp, uio, flag)
13317625Ssam 	register struct tty *tp;
13329578Ssam 	register struct uio *uio;
133352485Storek 	int flag;
13347502Sroot {
13357502Sroot 	register char *cp;
133664416Sbostic 	register int cc, ce;
133764416Sbostic 	register struct proc *p;
13389578Ssam 	int i, hiwat, cnt, error, s;
13397502Sroot 	char obuf[OBUFSIZ];
13407502Sroot 
134135811Smarc 	hiwat = tp->t_hiwat;
13429578Ssam 	cnt = uio->uio_resid;
13439578Ssam 	error = 0;
134464878Smckusick 	cc = 0;
13457502Sroot loop:
134637584Smarc 	s = spltty();
134764416Sbostic 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
134864416Sbostic 	    !ISSET(tp->t_cflag, CLOCAL)) {
134964416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN)) {
135037584Smarc 			splx(s);
135137584Smarc 			return (EIO);
135237728Smckusick 		} else if (flag & IO_NDELAY) {
135337584Smarc 			splx(s);
135440712Skarels 			error = EWOULDBLOCK;
135540712Skarels 			goto out;
135637584Smarc 		} else {
135764416Sbostic 			/* Sleep awaiting carrier. */
135864416Sbostic 			error = ttysleep(tp,
135964416Sbostic 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
136037584Smarc 			splx(s);
136143377Smarc 			if (error)
136240712Skarels 				goto out;
136337584Smarc 			goto loop;
136437584Smarc 		}
136537584Smarc 	}
136637584Smarc 	splx(s);
13679578Ssam 	/*
13689578Ssam 	 * Hang the process if it's in the background.
13699578Ssam 	 */
137064416Sbostic 	p = curproc;
137164416Sbostic 	if (isbackground(p, tp) &&
137264576Sbostic 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
137347545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
137447545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
137547545Skarels 	     p->p_pgrp->pg_jobc) {
137647545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
137764416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
137840712Skarels 			goto out;
137921776Sbloom 		goto loop;
13807502Sroot 	}
13819578Ssam 	/*
138264416Sbostic 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
138364416Sbostic 	 * output translation.  Keep track of high water mark, sleep on
138464416Sbostic 	 * overflow awaiting device aid in acquiring new space.
13859578Ssam 	 */
138664878Smckusick 	while (uio->uio_resid > 0 || cc > 0) {
138764416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO)) {
138840712Skarels 			uio->uio_resid = 0;
138940712Skarels 			return (0);
139040712Skarels 		}
139140712Skarels 		if (tp->t_outq.c_cc > hiwat)
139232067Skarels 			goto ovhiwat;
13939578Ssam 		/*
139464416Sbostic 		 * Grab a hunk of data from the user, unless we have some
139564416Sbostic 		 * leftover from last time.
13969578Ssam 		 */
13977822Sroot 		if (cc == 0) {
139840712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139940712Skarels 			cp = obuf;
140040712Skarels 			error = uiomove(cp, cc, uio);
140140712Skarels 			if (error) {
140240712Skarels 				cc = 0;
140340712Skarels 				break;
140440712Skarels 			}
14057822Sroot 		}
14069578Ssam 		/*
14079578Ssam 		 * If nothing fancy need be done, grab those characters we
14089578Ssam 		 * can handle without any of ttyoutput's processing and
14099578Ssam 		 * just transfer them to the output q.  For those chars
14109578Ssam 		 * which require special processing (as indicated by the
141164416Sbostic 		 * bits in char_type), call ttyoutput.  After processing
14129578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14139578Ssam 		 * immediately.
14149578Ssam 		 */
14159578Ssam 		while (cc > 0) {
141664416Sbostic 			if (!ISSET(tp->t_oflag, OPOST))
14177502Sroot 				ce = cc;
14187502Sroot 			else {
141964416Sbostic 				ce = cc - scanc((u_int)cc, (u_char *)cp,
142064416Sbostic 				   (u_char *)char_type, CCLASSMASK);
14219578Ssam 				/*
14229578Ssam 				 * If ce is zero, then we're processing
14239578Ssam 				 * a special character through ttyoutput.
14249578Ssam 				 */
14259578Ssam 				if (ce == 0) {
14267502Sroot 					tp->t_rocount = 0;
14277502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142864416Sbostic 						/* No Clists, wait a bit. */
142964416Sbostic 						ttstart(tp);
143064416Sbostic 						if (error = ttysleep(tp, &lbolt,
143164416Sbostic 						    TTOPRI | PCATCH, ttybuf, 0))
143264416Sbostic 							break;
143364416Sbostic 						goto loop;
14347502Sroot 					}
143564416Sbostic 					cp++;
143664416Sbostic 					cc--;
143764416Sbostic 					if (ISSET(tp->t_lflag, FLUSHO) ||
14389578Ssam 					    tp->t_outq.c_cc > hiwat)
14397502Sroot 						goto ovhiwat;
14409578Ssam 					continue;
14417502Sroot 				}
14427502Sroot 			}
14439578Ssam 			/*
144464416Sbostic 			 * A bunch of normal characters have been found.
144564416Sbostic 			 * Transfer them en masse to the output queue and
14469578Ssam 			 * continue processing at the top of the loop.
14479578Ssam 			 * If there are any further characters in this
14489578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14499578Ssam 			 * requiring special handling by ttyoutput.
14509578Ssam 			 */
14517502Sroot 			tp->t_rocount = 0;
14529578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14539578Ssam 			ce -= i;
145464530Sbostic 			tp->t_column += ce;
14559578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
145635811Smarc 			tp->t_outcc += ce;
14579578Ssam 			if (i > 0) {
145864416Sbostic 				/* No Clists, wait a bit. */
14597502Sroot 				ttstart(tp);
146064416Sbostic 				if (error = ttysleep(tp,
146164416Sbostic 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
146240712Skarels 					break;
146321776Sbloom 				goto loop;
14647502Sroot 			}
146564416Sbostic 			if (ISSET(tp->t_lflag, FLUSHO) ||
146664416Sbostic 			    tp->t_outq.c_cc > hiwat)
146740712Skarels 				break;
14687502Sroot 		}
146935811Smarc 		ttstart(tp);
14707502Sroot 	}
147140712Skarels out:
147240712Skarels 	/*
147364416Sbostic 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
147464416Sbostic 	 * offset and iov pointers have moved forward, but it doesn't matter
147564416Sbostic 	 * (the call will either return short or restart with a new uio).
147640712Skarels 	 */
147740712Skarels 	uio->uio_resid += cc;
14788520Sroot 	return (error);
147940712Skarels 
14807502Sroot ovhiwat:
148132067Skarels 	ttstart(tp);
148232067Skarels 	s = spltty();
14839578Ssam 	/*
148435811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
148532067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14869578Ssam 	 */
14877502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14889578Ssam 		splx(s);
14897502Sroot 		goto loop;
14907502Sroot 	}
149137728Smckusick 	if (flag & IO_NDELAY) {
149217545Skarels 		splx(s);
149340712Skarels 		uio->uio_resid += cc;
149464416Sbostic 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14957502Sroot 	}
149664416Sbostic 	SET(tp->t_state, TS_ASLEEP);
149764416Sbostic 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14989578Ssam 	splx(s);
149943377Smarc 	if (error)
150040712Skarels 		goto out;
15017502Sroot 	goto loop;
15027502Sroot }
15037502Sroot 
15047502Sroot /*
15057502Sroot  * Rubout one character from the rawq of tp
15067502Sroot  * as cleanly as possible.
15077502Sroot  */
150864416Sbostic void
15097502Sroot ttyrub(c, tp)
151064416Sbostic 	register int c;
15117625Ssam 	register struct tty *tp;
15127502Sroot {
15137502Sroot 	register char *cp;
15147502Sroot 	register int savecol;
151564416Sbostic 	int tabc, s;
15167502Sroot 
151764416Sbostic 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15187502Sroot 		return;
151964416Sbostic 	CLR(tp->t_lflag, FLUSHO);
152064416Sbostic 	if (ISSET(tp->t_lflag, ECHOE)) {
15217502Sroot 		if (tp->t_rocount == 0) {
15227502Sroot 			/*
15237502Sroot 			 * Screwed by ttwrite; retype
15247502Sroot 			 */
15257502Sroot 			ttyretype(tp);
15267502Sroot 			return;
15277502Sroot 		}
152864416Sbostic 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15297502Sroot 			ttyrubo(tp, 2);
153064576Sbostic 		else {
153164576Sbostic 			CLR(c, ~TTY_CHARMASK);
153264576Sbostic 			switch (CCLASS(c)) {
153364576Sbostic 			case ORDINARY:
153464576Sbostic 				ttyrubo(tp, 1);
153564576Sbostic 				break;
153664576Sbostic 			case BACKSPACE:
153764576Sbostic 			case CONTROL:
153864576Sbostic 			case NEWLINE:
153964576Sbostic 			case RETURN:
154064576Sbostic 			case VTAB:
154164576Sbostic 				if (ISSET(tp->t_lflag, ECHOCTL))
154264576Sbostic 					ttyrubo(tp, 2);
154364576Sbostic 				break;
154464576Sbostic 			case TAB:
154564576Sbostic 				if (tp->t_rocount < tp->t_rawq.c_cc) {
154664576Sbostic 					ttyretype(tp);
154764576Sbostic 					return;
154864576Sbostic 				}
154964576Sbostic 				s = spltty();
155064576Sbostic 				savecol = tp->t_column;
155164576Sbostic 				SET(tp->t_state, TS_CNTTB);
155264576Sbostic 				SET(tp->t_lflag, FLUSHO);
155364576Sbostic 				tp->t_column = tp->t_rocol;
155464576Sbostic 				cp = tp->t_rawq.c_cf;
155564576Sbostic 				if (cp)
155664576Sbostic 					tabc = *cp;	/* XXX FIX NEXTC */
155764576Sbostic 				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
155864576Sbostic 					ttyecho(tabc, tp);
155964576Sbostic 				CLR(tp->t_lflag, FLUSHO);
156064576Sbostic 				CLR(tp->t_state, TS_CNTTB);
156164576Sbostic 				splx(s);
156264416Sbostic 
156364576Sbostic 				/* savecol will now be length of the tab. */
156464576Sbostic 				savecol -= tp->t_column;
156564576Sbostic 				tp->t_column += savecol;
156664576Sbostic 				if (savecol > 8)
156764576Sbostic 					savecol = 8;	/* overflow screw */
156864576Sbostic 				while (--savecol >= 0)
156964576Sbostic 					(void)ttyoutput('\b', tp);
157064576Sbostic 				break;
157164576Sbostic 			default:			/* XXX */
157264416Sbostic #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
157364576Sbostic 				(void)printf(PANICSTR, c, CCLASS(c));
157464416Sbostic #ifdef notdef
157564576Sbostic 				panic(PANICSTR, c, CCLASS(c));
157664416Sbostic #endif
157764576Sbostic 			}
157835811Smarc 		}
157964416Sbostic 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
158064416Sbostic 		if (!ISSET(tp->t_state, TS_ERASE)) {
158164416Sbostic 			SET(tp->t_state, TS_ERASE);
158264416Sbostic 			(void)ttyoutput('\\', tp);
15837502Sroot 		}
15847502Sroot 		ttyecho(c, tp);
15857502Sroot 	} else
158635811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
158764416Sbostic 	--tp->t_rocount;
15887502Sroot }
15897502Sroot 
15907502Sroot /*
159164416Sbostic  * Back over cnt characters, erasing them.
15927502Sroot  */
159364416Sbostic static void
15947502Sroot ttyrubo(tp, cnt)
15957625Ssam 	register struct tty *tp;
15967625Ssam 	int cnt;
15977502Sroot {
15987502Sroot 
159964416Sbostic 	while (cnt-- > 0) {
160064416Sbostic 		(void)ttyoutput('\b', tp);
160164416Sbostic 		(void)ttyoutput(' ', tp);
160264416Sbostic 		(void)ttyoutput('\b', tp);
160364416Sbostic 	}
16047502Sroot }
16057502Sroot 
16067502Sroot /*
160764416Sbostic  * ttyretype --
160864416Sbostic  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
160964416Sbostic  *	been checked.
16107502Sroot  */
161164416Sbostic void
16127502Sroot ttyretype(tp)
16137625Ssam 	register struct tty *tp;
16147502Sroot {
16157502Sroot 	register char *cp;
161635811Smarc 	int s, c;
16177502Sroot 
161864416Sbostic 	/* Echo the reprint character. */
161935811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
162035811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
162164416Sbostic 
162264416Sbostic 	(void)ttyoutput('\n', tp);
162364416Sbostic 
162464416Sbostic 	/*
162564416Sbostic 	 * XXX
162664416Sbostic 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162764416Sbostic 	 * BIT OF FIRST CHAR.
162864416Sbostic 	 */
162917545Skarels 	s = spltty();
163064416Sbostic 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
163164416Sbostic 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
163235811Smarc 		ttyecho(c, tp);
163364416Sbostic 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
163464416Sbostic 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
163535811Smarc 		ttyecho(c, tp);
163664416Sbostic 	CLR(tp->t_state, TS_ERASE);
16377502Sroot 	splx(s);
163864416Sbostic 
16397502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16407502Sroot 	tp->t_rocol = 0;
16417502Sroot }
16427502Sroot 
16437502Sroot /*
164435811Smarc  * Echo a typed character to the terminal.
16457502Sroot  */
164664416Sbostic static void
16477502Sroot ttyecho(c, tp)
164864416Sbostic 	register int c;
16497625Ssam 	register struct tty *tp;
16507502Sroot {
165164416Sbostic 
165264416Sbostic 	if (!ISSET(tp->t_state, TS_CNTTB))
165364416Sbostic 		CLR(tp->t_lflag, FLUSHO);
165464416Sbostic 	if ((!ISSET(tp->t_lflag, ECHO) &&
165564416Sbostic 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
165664416Sbostic 	    ISSET(tp->t_lflag, EXTPROC))
16577502Sroot 		return;
165864416Sbostic 	if (ISSET(tp->t_lflag, ECHOCTL) &&
165964576Sbostic 	    (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
166064576Sbostic 	    ISSET(c, TTY_CHARMASK) == 0177)) {
166164416Sbostic 		(void)ttyoutput('^', tp);
166264576Sbostic 		CLR(c, ~TTY_CHARMASK);
166364416Sbostic 		if (c == 0177)
166464416Sbostic 			c = '?';
166564416Sbostic 		else
166664416Sbostic 			c += 'A' - 1;
16677502Sroot 	}
166864416Sbostic 	(void)ttyoutput(c, tp);
16697502Sroot }
16707502Sroot 
16717502Sroot /*
167249380Skarels  * Wake up any readers on a tty.
167349380Skarels  */
167464416Sbostic void
16757502Sroot ttwakeup(tp)
167647545Skarels 	register struct tty *tp;
16777502Sroot {
16787502Sroot 
167952522Smckusick 	selwakeup(&tp->t_rsel);
168064416Sbostic 	if (ISSET(tp->t_state, TS_ASYNC))
168164416Sbostic 		pgsignal(tp->t_pgrp, SIGIO, 1);
16827502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16837502Sroot }
168435811Smarc 
168535811Smarc /*
168648439Skarels  * Look up a code for a specified speed in a conversion table;
168748439Skarels  * used by drivers to map software speed values to hardware parameters.
168848439Skarels  */
168964416Sbostic int
169048439Skarels ttspeedtab(speed, table)
169152485Storek 	int speed;
169248439Skarels 	register struct speedtab *table;
169348439Skarels {
169448439Skarels 
169548439Skarels 	for ( ; table->sp_speed != -1; table++)
169648439Skarels 		if (table->sp_speed == speed)
169748439Skarels 			return (table->sp_code);
169848439Skarels 	return (-1);
169948439Skarels }
170048439Skarels 
170148439Skarels /*
170264416Sbostic  * Set tty hi and low water marks.
170335811Smarc  *
170435811Smarc  * Try to arrange the dynamics so there's about one second
170535811Smarc  * from hi to low water.
170664416Sbostic  *
170735811Smarc  */
170864416Sbostic void
170935811Smarc ttsetwater(tp)
171035811Smarc 	struct tty *tp;
171135811Smarc {
171264416Sbostic 	register int cps, x;
171335811Smarc 
171464416Sbostic #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
171564416Sbostic 
171664416Sbostic 	cps = tp->t_ospeed / 10;
171764416Sbostic 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
171835811Smarc 	x += cps;
171964416Sbostic 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
172035811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
172164416Sbostic #undef	CLAMP
172235811Smarc }
172335811Smarc 
172439407Smarc /*
172539407Smarc  * Report on state of foreground process group.
172639407Smarc  */
172764416Sbostic void
172839407Smarc ttyinfo(tp)
172949907Sbostic 	register struct tty *tp;
173039407Smarc {
173149907Sbostic 	register struct proc *p, *pick;
173241177Smarc 	struct timeval utime, stime;
173349907Sbostic 	int tmp;
173439407Smarc 
173564416Sbostic 	if (ttycheckoutq(tp,0) == 0)
173639407Smarc 		return;
173749907Sbostic 
173849907Sbostic 	/* Print load average. */
173952666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
174049907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
174149907Sbostic 
174239555Smarc 	if (tp->t_session == NULL)
174349907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
174441177Smarc 	else if (tp->t_pgrp == NULL)
174549907Sbostic 		ttyprintf(tp, "no foreground process group\n");
1746*67732Smckusick 	else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
174749907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174839407Smarc 	else {
174949907Sbostic 		/* Pick interesting process. */
1750*67732Smckusick 		for (pick = NULL; p != 0; p = p->p_pglist.le_next)
175141177Smarc 			if (proc_compare(pick, p))
175241177Smarc 				pick = p;
175349907Sbostic 
175449907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
175549907Sbostic 		    pick->p_stat == SRUN ? "running" :
175649907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
175749907Sbostic 
175854782Storek 		calcru(pick, &utime, &stime, NULL);
175939407Smarc 
176049907Sbostic 		/* Print user time. */
176149907Sbostic 		ttyprintf(tp, "%d.%02du ",
176249907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
176341177Smarc 
176449907Sbostic 		/* Print system time. */
176549907Sbostic 		ttyprintf(tp, "%d.%02ds ",
176649907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176749907Sbostic 
176849907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
176949907Sbostic 		/* Print percentage cpu, resident set size. */
177049907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
177149907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
177252485Storek 		    tmp / 100,
177352485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
177465549Smckusick #ifdef pmap_resident_count
177565549Smckusick 			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
177665549Smckusick #else
177765549Smckusick 			pgtok(pick->p_vmspace->vm_rssize)
177865549Smckusick #endif
177965549Smckusick 			);
178041177Smarc 	}
178149907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
178241177Smarc }
178341177Smarc 
178441177Smarc /*
178541177Smarc  * Returns 1 if p2 is "better" than p1
178641177Smarc  *
178741177Smarc  * The algorithm for picking the "interesting" process is thus:
178841177Smarc  *
178964576Sbostic  *	1) Only foreground processes are eligible - implied.
179064576Sbostic  *	2) Runnable processes are favored over anything else.  The runner
179164576Sbostic  *	   with the highest cpu utilization is picked (p_estcpu).  Ties are
179241177Smarc  *	   broken by picking the highest pid.
179364576Sbostic  *	3) The sleeper with the shortest sleep time is next.  With ties,
179464576Sbostic  *	   we pick out just "short-term" sleepers (P_SINTR == 0).
179564576Sbostic  *	4) Further ties are broken by picking the highest pid.
179641177Smarc  */
179764576Sbostic #define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179845723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179945723Smckusick #define ONLYA   2
180045723Smckusick #define ONLYB   1
180145723Smckusick #define BOTH    3
180264576Sbostic 
180349907Sbostic static int
180441177Smarc proc_compare(p1, p2)
180541177Smarc 	register struct proc *p1, *p2;
180641177Smarc {
180741177Smarc 
180841177Smarc 	if (p1 == NULL)
180941177Smarc 		return (1);
181041177Smarc 	/*
181141177Smarc 	 * see if at least one of them is runnable
181241177Smarc 	 */
181364576Sbostic 	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
181445723Smckusick 	case ONLYA:
181545723Smckusick 		return (0);
181645723Smckusick 	case ONLYB:
181741177Smarc 		return (1);
181845723Smckusick 	case BOTH:
181941177Smarc 		/*
182041177Smarc 		 * tie - favor one with highest recent cpu utilization
182141177Smarc 		 */
182264576Sbostic 		if (p2->p_estcpu > p1->p_estcpu)
182341177Smarc 			return (1);
182464576Sbostic 		if (p1->p_estcpu > p2->p_estcpu)
182541177Smarc 			return (0);
182641177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182741177Smarc 	}
182845723Smckusick 	/*
182945723Smckusick  	 * weed out zombies
183045723Smckusick 	 */
183145723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
183245723Smckusick 	case ONLYA:
183345723Smckusick 		return (1);
183445723Smckusick 	case ONLYB:
183545723Smckusick 		return (0);
183645723Smckusick 	case BOTH:
183745723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183845723Smckusick 	}
183964416Sbostic 	/*
184041177Smarc 	 * pick the one with the smallest sleep time
184141177Smarc 	 */
184241177Smarc 	if (p2->p_slptime > p1->p_slptime)
184341177Smarc 		return (0);
184441177Smarc 	if (p1->p_slptime > p2->p_slptime)
184541177Smarc 		return (1);
184641177Smarc 	/*
184741177Smarc 	 * favor one sleeping in a non-interruptible sleep
184841177Smarc 	 */
184964576Sbostic 	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
185041177Smarc 		return (1);
185164576Sbostic 	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
185241177Smarc 		return (0);
185347545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
185441177Smarc }
185545723Smckusick 
185639555Smarc /*
185739555Smarc  * Output char to tty; console putchar style.
185839555Smarc  */
185964416Sbostic int
186039555Smarc tputchar(c, tp)
186139555Smarc 	int c;
186239555Smarc 	struct tty *tp;
186339555Smarc {
186464416Sbostic 	register int s;
186539555Smarc 
186664416Sbostic 	s = spltty();
186764416Sbostic 	if (ISSET(tp->t_state,
186864416Sbostic 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
186939555Smarc 		splx(s);
187064416Sbostic 		return (-1);
187139555Smarc 	}
187264416Sbostic 	if (c == '\n')
187364416Sbostic 		(void)ttyoutput('\r', tp);
187464416Sbostic 	(void)ttyoutput(c, tp);
187564416Sbostic 	ttstart(tp);
187639555Smarc 	splx(s);
187764416Sbostic 	return (0);
187839555Smarc }
187943377Smarc 
188044419Smarc /*
188164416Sbostic  * Sleep on chan, returning ERESTART if tty changed while we napped and
188264416Sbostic  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
188364416Sbostic  * the tty is revoked, restarting a pending call will redo validation done
188464416Sbostic  * at the start of the call.
188544419Smarc  */
188664416Sbostic int
188743377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188843377Smarc 	struct tty *tp;
188964416Sbostic 	void *chan;
189064416Sbostic 	int pri, timo;
189143377Smarc 	char *wmesg;
189243377Smarc {
189343377Smarc 	int error;
189464416Sbostic 	short gen;
189543377Smarc 
189664416Sbostic 	gen = tp->t_gen;
189743377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
189843377Smarc 		return (error);
189964416Sbostic 	return (tp->t_gen == gen ? 0 : ERESTART);
190043377Smarc }
1901