xref: /csrg-svn/sys/kern/tty.c (revision 64416)
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*64416Sbostic  *	@(#)tty.c	8.2 (Berkeley) 09/05/93
923387Smckusick  */
1039Sbill 
1156517Sbostic #include <sys/param.h>
1256517Sbostic #include <sys/systm.h>
1356517Sbostic #include <sys/ioctl.h>
1456517Sbostic #include <sys/proc.h>
15*64416Sbostic #define	TTYDEFCHARS
1656517Sbostic #include <sys/tty.h>
17*64416Sbostic #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 
28*64416Sbostic static int	proc_compare __P((struct proc *p1, struct proc *p2));
29*64416Sbostic static int	ttnread __P((struct tty *));
30*64416Sbostic static void	ttyblock __P((struct tty *tp));
31*64416Sbostic static void	ttyecho __P((int, struct tty *tp));
32*64416Sbostic static void	ttyrubo __P((struct tty *, int));
3349907Sbostic 
34*64416Sbostic /* Symbolic sleep message strings. */
35*64416Sbostic char ttclos[]	= "ttycls";
36*64416Sbostic char ttopen[]	= "ttyopn";
37*64416Sbostic char ttybg[]	= "ttybg";
38*64416Sbostic char ttybuf[]	= "ttybuf";
39*64416Sbostic char ttyin[]	= "ttyin";
40*64416Sbostic char ttyout[]	= "ttyout";
4140712Skarels 
427436Skre /*
43*64416Sbostic  * Table with character classes and parity. The 8th bit indicates parity,
44*64416Sbostic  * the 7th bit indicates the character is an alphameric or underscore (for
45*64416Sbostic  * ALTWERASE), and the low 6 bits indicate delay type.  If the low 6 bits
46*64416Sbostic  * are 0 then the character needs no special processing on output; classes
47*64416Sbostic  * other than 0 might be translated or (not currently) require delays.
487436Skre  */
49*64416Sbostic #define	E	0x00	/* Even parity. */
50*64416Sbostic #define	O	0x80	/* Odd parity. */
51*64416Sbostic #define	PARITY(c)	(char_type[c] & O)
52*64416Sbostic 
53*64416Sbostic #define	ALPHA	0x40	/* Alpha or underscore. */
54*64416Sbostic #define	ISALPHA(c)	(char_type[(c) & TTY_CHARMASK] & ALPHA)
55*64416Sbostic 
5649380Skarels #define	CCLASSMASK	0x3f
57*64416Sbostic #define	CCLASS(c)	(char_type[c] & CCLASSMASK)
5839Sbill 
59*64416Sbostic #define	BS	BACKSPACE
6049380Skarels #define	CC	CONTROL
61*64416Sbostic #define	CR	RETURN
62*64416Sbostic #define	NA	ORDINARY | ALPHA
6349380Skarels #define	NL	NEWLINE
64*64416Sbostic #define	NO	ORDINARY
6549380Skarels #define	TB	TAB
6649380Skarels #define	VT	VTAB
6749380Skarels 
68*64416Sbostic 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 	/*
86*64416Sbostic 	 * Meta chars; should be settable per character set;
87*64416Sbostic 	 * 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 };
106*64416Sbostic #undef	BS
107*64416Sbostic #undef	CC
108*64416Sbostic #undef	CR
10949380Skarels #undef	NA
11049380Skarels #undef	NL
111*64416Sbostic #undef	NO
11249380Skarels #undef	TB
11349380Skarels #undef	VT
1147436Skre 
115*64416Sbostic /* Macros to clear/set/test flags. */
116*64416Sbostic #define	SET(t, f)	(t) |= (f)
117*64416Sbostic #define	CLR(t, f)	(t) &= ~(f)
118*64416Sbostic #define	ISSET(t, f)	((t) & (f))
11935811Smarc 
120146Sbill /*
121*64416Sbostic  * Initial open of tty, or (re)entry to standard tty line discipline.
12239Sbill  */
123*64416Sbostic int
124*64416Sbostic ttyopen(device, tp)
125*64416Sbostic 	dev_t device;
12612752Ssam 	register struct tty *tp;
12712752Ssam {
12852485Storek 	int s;
12947545Skarels 
13052485Storek 	s = spltty();
131*64416Sbostic 	tp->t_dev = device;
132*64416Sbostic 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
133*64416Sbostic 		SET(tp->t_state, TS_ISOPEN);
134*64416Sbostic 		bzero(&tp->t_winsize, sizeof(tp->t_winsize));
135903Sbill 	}
136*64416Sbostic 	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  */
146*64416Sbostic int
1477502Sroot ttyclose(tp)
1487625Ssam 	register struct tty *tp;
1497502Sroot {
150*64416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
151*64416Sbostic 
15230534Skarels 	if (constty == tp)
15330534Skarels 		constty = NULL;
154*64416Sbostic 
155*64416Sbostic 	ttyflush(tp, FREAD | FWRITE);
156*64416Sbostic 
157*64416Sbostic 	tp->t_gen++;
158*64416Sbostic 	tp->t_pgrp = NULL;
15939555Smarc 	tp->t_session = NULL;
1607502Sroot 	tp->t_state = 0;
16140712Skarels 	return (0);
1627502Sroot }
1637502Sroot 
164*64416Sbostic #define	FLUSHQ(q) {							\
165*64416Sbostic 	if ((q)->c_cc)							\
166*64416Sbostic 		ndflush(q, (q)->c_cc);					\
16725391Skarels }
16825391Skarels 
169*64416Sbostic /* Is 'c' a line delimiter ("break" character)? */
170*64416Sbostic #define	TTBREAKC(c)							\
171*64416Sbostic 	((c) == '\n' || ((c) == cc[VEOF] ||				\
172*64416Sbostic 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
17325404Skarels 
1747502Sroot 
1757502Sroot /*
17649380Skarels  * Process input of a single character received on a tty.
1777502Sroot  */
178*64416Sbostic int
1797502Sroot ttyinput(c, tp)
180*64416Sbostic 	register int c;
1817625Ssam 	register struct tty *tp;
1827502Sroot {
183*64416Sbostic 	register int iflag, lflag;
184*64416Sbostic 	register u_char *cc;
18535811Smarc 	int i, err;
1867502Sroot 
1879578Ssam 	/*
1889578Ssam 	 * If input is pending take it first.
1899578Ssam 	 */
190*64416Sbostic 	lflag = tp->t_lflag;
191*64416Sbostic 	if (ISSET(lflag, PENDIN))
1927502Sroot 		ttypend(tp);
19335811Smarc 	/*
19435811Smarc 	 * Gather stats.
19535811Smarc 	 */
196*64416Sbostic 	if (ISSET(lflag, ICANON)) {
197*64416Sbostic 		++tk_cancc;
198*64416Sbostic 		++tp->t_cancc;
19935811Smarc 	} else {
200*64416Sbostic 		++tk_rawcc;
201*64416Sbostic 		++tp->t_rawcc;
20235811Smarc 	}
203*64416Sbostic 	++tk_nin;
204*64416Sbostic 
205*64416Sbostic 	/* Handle exceptional conditions (break, parity, framing). */
206*64416Sbostic 	cc = tp->t_cc;
207*64416Sbostic 	iflag = tp->t_iflag;
208*64416Sbostic 	if (err = (c & TTY_ERRORMASK)) {
20935811Smarc 		c &= ~TTY_ERRORMASK;
210*64416Sbostic 		if (err & TTY_FE && !c) {	/* Break. */
211*64416Sbostic 			if (ISSET(iflag, IGNBRK))
21235811Smarc 				goto endcase;
213*64416Sbostic 			else if (ISSET(iflag, BRKINT) &&
214*64416Sbostic 			    ISSET(lflag, ISIG) &&
215*64416Sbostic 			    (cc[VINTR] != _POSIX_VDISABLE))
21635811Smarc 				c = cc[VINTR];
217*64416Sbostic 			else if (ISSET(iflag, PARMRK))
21847545Skarels 				goto parmrk;
219*64416Sbostic 		} else if (err & TTY_PE &&
220*64416Sbostic 		    ISSET(iflag, INPCK) || err & TTY_FE) {
221*64416Sbostic 			if (ISSET(iflag, IGNPAR))
22235811Smarc 				goto endcase;
223*64416Sbostic 			else if (ISSET(iflag, PARMRK)) {
224*64416Sbostic parmrk:				putc(0377 | TTY_QUOTE, &tp->t_rawq);
225*64416Sbostic 				putc(0 | TTY_QUOTE, &tp->t_rawq);
226*64416Sbostic 				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 	 */
235*64416Sbostic 	if (ISSET(iflag, IXOFF))
23635811Smarc 		ttyblock(tp);
237*64416Sbostic 	if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
23849380Skarels 		c &= ~0x80;
239*64416Sbostic 	if (!ISSET(lflag, EXTPROC)) {
24044419Smarc 		/*
24144419Smarc 		 * Check for literal nexting very first
24244419Smarc 		 */
243*64416Sbostic 		if (ISSET(tp->t_state, TS_LNCH)) {
24444419Smarc 			c |= TTY_QUOTE;
245*64416Sbostic 			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 		 */
259*64416Sbostic 		if (ISSET(lflag, IEXTEN)) {
26044419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
261*64416Sbostic 				if (ISSET(lflag, ECHO)) {
262*64416Sbostic 					if (ISSET(lflag, ECHOE)) {
263*64416Sbostic 						(void)ttyoutput('^', tp);
264*64416Sbostic 						(void)ttyoutput('\b', tp);
265*64416Sbostic 					} else
26644419Smarc 						ttyecho(c, tp);
26744419Smarc 				}
268*64416Sbostic 				SET(tp->t_state, TS_LNCH);
26944419Smarc 				goto endcase;
27044419Smarc 			}
27144419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
272*64416Sbostic 				if (ISSET(lflag, FLUSHO))
273*64416Sbostic 					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);
279*64416Sbostic 					SET(tp->t_lflag, FLUSHO);
28044419Smarc 				}
28144419Smarc 				goto startoutput;
28235811Smarc 			}
2839578Ssam 		}
28444419Smarc 		/*
28544419Smarc 		 * Signals.
28644419Smarc 		 */
287*64416Sbostic 		if (ISSET(lflag, ISIG)) {
28844419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
289*64416Sbostic 				if (!ISSET(lflag, NOFLSH))
290*64416Sbostic 					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)) {
297*64416Sbostic 				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 		 */
307*64416Sbostic 		if (ISSET(iflag, IXON)) {
30844419Smarc 			if (CCEQ(cc[VSTOP], c)) {
309*64416Sbostic 				if (!ISSET(tp->t_state, TS_TTSTOP)) {
310*64416Sbostic 					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
317*64416Sbostic 					return (0);
31844419Smarc 				}
31944419Smarc 				if (!CCEQ(cc[VSTART], c))
320*64416Sbostic 					return (0);
321*64416Sbostic 				/*
322*64416Sbostic 				 * 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') {
333*64416Sbostic 			if (ISSET(iflag, IGNCR))
33444419Smarc 				goto endcase;
335*64416Sbostic 			else if (ISSET(iflag, ICRNL))
33644419Smarc 				c = '\n';
337*64416Sbostic 		} else if (c == '\n' && ISSET(iflag, INLCR))
33844419Smarc 			c = '\r';
3399578Ssam 	}
340*64416Sbostic 	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)) {
357*64416Sbostic 			if (ISSET(lflag, ECHOKE) &&
358*64416Sbostic 			    tp->t_rawq.c_cc == tp->t_rocount &&
359*64416Sbostic 			    !ISSET(lflag, ECHOPRT))
36044419Smarc 				while (tp->t_rawq.c_cc)
36144419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
362*64416Sbostic 			else {
36344419Smarc 				ttyecho(c, tp);
364*64416Sbostic 				if (ISSET(lflag, ECHOK) ||
365*64416Sbostic 				    ISSET(lflag, ECHOKE))
36644419Smarc 					ttyecho('\n', tp);
367*64416Sbostic 				FLUSHQ(&tp->t_rawq);
36844419Smarc 				tp->t_rocount = 0;
36944419Smarc 			}
370*64416Sbostic 			CLR(tp->t_state, TS_LOCAL);
37144419Smarc 			goto endcase;
37244419Smarc 		}
37344419Smarc 		/*
37444419Smarc 		 * word erase (^W)
37544419Smarc 		 */
376*64416Sbostic 		if (CCEQ(cc[VWERASE], c)) {
377*64416Sbostic 			int alt = ISSET(lflag, ALTWERASE);
37844419Smarc 			int ctype;
37935811Smarc 
380*64416Sbostic 			/*
381*64416Sbostic 			 * 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') {
39651003Sbostic 				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;
408*64416Sbostic 			} while (c != ' ' && c != '\t' &&
409*64416Sbostic 			    (alt == 0 || ISALPHA(c) == ctype));
410*64416Sbostic 			(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)) {
424*64416Sbostic 			if (ISSET(lflag, ISIG))
42551068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
426*64416Sbostic 			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) {
435*64416Sbostic 		if (ISSET(iflag, IMAXBEL)) {
43635811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
437*64416Sbostic 				(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) {
447*64416Sbostic 		if (!ISSET(lflag, ICANON)) {
44847545Skarels 			ttwakeup(tp);
44947545Skarels 			ttyecho(c, tp);
45047545Skarels 			goto endcase;
45147545Skarels 		}
452*64416Sbostic 		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)
4579578Ssam 			tp->t_rocol = tp->t_col;
458*64416Sbostic 		if (ISSET(tp->t_state, TS_ERASE)) {
45935811Smarc 			/*
46035811Smarc 			 * end of prterase \.../
46135811Smarc 			 */
462*64416Sbostic 			CLR(tp->t_state, TS_ERASE);
463*64416Sbostic 			(void)ttyoutput('/', tp);
4649578Ssam 		}
4659578Ssam 		i = tp->t_col;
4667502Sroot 		ttyecho(c, tp);
467*64416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
46835811Smarc 			/*
46935811Smarc 			 * Place the cursor over the '^' of the ^D.
47035811Smarc 			 */
47155058Spendry 			i = min(2, tp->t_col - i);
4729578Ssam 			while (i > 0) {
473*64416Sbostic 				(void)ttyoutput('\b', tp);
4749578Ssam 				i--;
4759578Ssam 			}
4769578Ssam 		}
4777502Sroot 	}
4789578Ssam endcase:
4799578Ssam 	/*
48035811Smarc 	 * IXANY means allow any character to restart output.
4819578Ssam 	 */
482*64416Sbostic 	if (ISSET(tp->t_state, TS_TTSTOP) &&
483*64416Sbostic 	    !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
484*64416Sbostic 		return (0);
4859578Ssam restartoutput:
486*64416Sbostic 	CLR(tp->t_lflag, FLUSHO);
487*64416Sbostic 	CLR(tp->t_state, TS_TTSTOP);
4889578Ssam startoutput:
489*64416Sbostic 	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.).
495*64416Sbostic  * Returns < 0 if succeeds, otherwise returns char to resend.
4967502Sroot  * Must be recursive.
4977502Sroot  */
498*64416Sbostic int
4997502Sroot ttyoutput(c, tp)
500*64416Sbostic 	register int c;
5017502Sroot 	register struct tty *tp;
5027502Sroot {
503*64416Sbostic 	register long oflag;
504*64416Sbostic 	register int col, s;
505*64416Sbostic 
506*64416Sbostic 	oflag = tp->t_oflag;
507*64416Sbostic 	if (!ISSET(oflag, OPOST)) {
508*64416Sbostic 		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 	/*
517*64416Sbostic 	 * Do tab expansion if OXTABS is set.  Special case if we external
518*64416Sbostic 	 * processing, we don't do the tab expansion because we'll probably
519*64416Sbostic 	 * get it wrong.  If tab expansion needs to be done, let it happen
520*64416Sbostic 	 * externally.
5217502Sroot 	 */
522*64416Sbostic 	c &= TTY_CHARMASK;
523*64416Sbostic 	if (c == '\t' &&
524*64416Sbostic 	    ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
525*64416Sbostic 		c = 8 - (tp->t_col & 7);
526*64416Sbostic 		if (!ISSET(tp->t_lflag, FLUSHO)) {
527*64416Sbostic 			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 		}
5337502Sroot 		tp->t_col += c;
5347502Sroot 		return (c ? -1 : '\t');
5357502Sroot 	}
536*64416Sbostic 	if (c == CEOT && ISSET(oflag, ONOEOT))
53747545Skarels 		return (-1);
5387502Sroot 	tk_nout++;
53935811Smarc 	tp->t_outcc++;
5407502Sroot 	/*
54149380Skarels 	 * Newline translation: if ONLCR is set,
54249380Skarels 	 * translate newline into "\r\n".
5437502Sroot 	 */
544*64416Sbostic 	if (c == '\n' &&
545*64416Sbostic 	    ISSET(tp->t_oflag, ONLCR) && ttyoutput('\r', tp) >= 0)
5467502Sroot 		return (c);
547*64416Sbostic 	if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
54835811Smarc 		return (c);
54947545Skarels 
55049380Skarels 	col = tp->t_col;
55149380Skarels 	switch (CCLASS(c)) {
5527502Sroot 	case BACKSPACE:
55349380Skarels 		if (col > 0)
554*64416Sbostic 			--col;
5557502Sroot 		break;
556*64416Sbostic 	case CONTROL:
557*64416Sbostic 		break;
5587502Sroot 	case NEWLINE:
559*64416Sbostic 	case RETURN:
56049380Skarels 		col = 0;
5617502Sroot 		break;
562*64416Sbostic 	case ORDINARY:
563*64416Sbostic 		++col;
564*64416Sbostic 		break;
5657502Sroot 	case TAB:
566*64416Sbostic 		col = (col + 8) & ~7;
5677502Sroot 		break;
5687502Sroot 	}
56949380Skarels 	tp->t_col = col;
5707502Sroot 	return (-1);
5717502Sroot }
5727502Sroot 
5737502Sroot /*
574*64416Sbostic  * Common code for ioctls on all tty devices.  Called after line-discipline
575*64416Sbostic  * specific ioctl has been called to do discipline-specific functions and/or
576*64416Sbostic  * reject any of these ioctl commands.
577*64416Sbostic  */
578*64416Sbostic /* ARGSUSED */
579*64416Sbostic int
580*64416Sbostic ttioctl(tp, com, data, flag)
581*64416Sbostic 	register struct tty *tp;
582*64416Sbostic 	int com, flag;
583*64416Sbostic 	void *data;
584*64416Sbostic {
585*64416Sbostic 	extern struct tty *constty;	/* Temporary virtual console. */
586*64416Sbostic 	extern int nldisp;
587*64416Sbostic 	register struct proc *p;
588*64416Sbostic 	int s, error;
589*64416Sbostic 
590*64416Sbostic 	p = curproc;			/* XXX */
591*64416Sbostic 
592*64416Sbostic 	/* If the ioctl involves modification, hang if in the background. */
593*64416Sbostic 	switch (com) {
594*64416Sbostic 	case  TIOCFLUSH:
595*64416Sbostic 	case  TIOCSETA:
596*64416Sbostic 	case  TIOCSETD:
597*64416Sbostic 	case  TIOCSETAF:
598*64416Sbostic 	case  TIOCSETAW:
599*64416Sbostic #ifdef notdef
600*64416Sbostic 	case  TIOCSPGRP:
601*64416Sbostic #endif
602*64416Sbostic 	case  TIOCSTI:
603*64416Sbostic 	case  TIOCSWINSZ:
604*64416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
605*64416Sbostic 	case  TIOCLBIC:
606*64416Sbostic 	case  TIOCLBIS:
607*64416Sbostic 	case  TIOCLSET:
608*64416Sbostic 	case  TIOCSETC:
609*64416Sbostic 	case OTIOCSETD:
610*64416Sbostic 	case  TIOCSETN:
611*64416Sbostic 	case  TIOCSETP:
612*64416Sbostic 	case  TIOCSLTC:
613*64416Sbostic #endif
614*64416Sbostic 		while (isbackground(curproc, tp) &&
615*64416Sbostic 		    p->p_pgrp->pg_jobc && (p->p_flag & SPPWAIT) == 0 &&
616*64416Sbostic 		    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
617*64416Sbostic 		    (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
618*64416Sbostic 			pgsignal(p->p_pgrp, SIGTTOU, 1);
619*64416Sbostic 			if (error = ttysleep(tp,
620*64416Sbostic 			    &lbolt, TTOPRI | PCATCH, ttybg, 0))
621*64416Sbostic 				return (error);
622*64416Sbostic 		}
623*64416Sbostic 		break;
624*64416Sbostic 	}
625*64416Sbostic 
626*64416Sbostic 	switch (com) {			/* Process the ioctl. */
627*64416Sbostic 	case FIOASYNC:			/* set/clear async i/o */
628*64416Sbostic 		s = spltty();
629*64416Sbostic 		if (*(int *)data)
630*64416Sbostic 			SET(tp->t_state, TS_ASYNC);
631*64416Sbostic 		else
632*64416Sbostic 			CLR(tp->t_state, TS_ASYNC);
633*64416Sbostic 		splx(s);
634*64416Sbostic 		break;
635*64416Sbostic 	case FIONBIO:			/* set/clear non-blocking i/o */
636*64416Sbostic 		break;			/* XXX: delete. */
637*64416Sbostic 	case FIONREAD:			/* get # bytes to read */
638*64416Sbostic 		*(int *)data = ttnread(tp);
639*64416Sbostic 		break;
640*64416Sbostic 	case TIOCEXCL:			/* set exclusive use of tty */
641*64416Sbostic 		s = spltty();
642*64416Sbostic 		SET(tp->t_state, TS_XCLUDE);
643*64416Sbostic 		splx(s);
644*64416Sbostic 		break;
645*64416Sbostic 	case TIOCFLUSH: {		/* flush buffers */
646*64416Sbostic 		register int flags = *(int *)data;
647*64416Sbostic 
648*64416Sbostic 		if (flags == 0)
649*64416Sbostic 			flags = FREAD | FWRITE;
650*64416Sbostic 		else
651*64416Sbostic 			flags &= FREAD | FWRITE;
652*64416Sbostic 		ttyflush(tp, flags);
653*64416Sbostic 		break;
654*64416Sbostic 	}
655*64416Sbostic 	case TIOCCONS:			/* become virtual console */
656*64416Sbostic 		if (*(int *)data) {
657*64416Sbostic 			if (constty && constty != tp &&
658*64416Sbostic 			    ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
659*64416Sbostic 			    (TS_CARR_ON | TS_ISOPEN))
660*64416Sbostic 				return (EBUSY);
661*64416Sbostic #ifndef	UCONSOLE
662*64416Sbostic 			if (error = suser(p->p_ucred, &p->p_acflag))
663*64416Sbostic 				return (error);
664*64416Sbostic #endif
665*64416Sbostic 			constty = tp;
666*64416Sbostic 		} else if (tp == constty)
667*64416Sbostic 			constty = NULL;
668*64416Sbostic 		break;
669*64416Sbostic 	case TIOCDRAIN:			/* wait till output drained */
670*64416Sbostic 		if (error = ttywait(tp))
671*64416Sbostic 			return (error);
672*64416Sbostic 		break;
673*64416Sbostic 	case TIOCGETA: {		/* get termios struct */
674*64416Sbostic 		struct termios *t = (struct termios *)data;
675*64416Sbostic 
676*64416Sbostic 		bcopy(&tp->t_termios, t, sizeof(struct termios));
677*64416Sbostic 		break;
678*64416Sbostic 	}
679*64416Sbostic 	case TIOCGETD:			/* get line discipline */
680*64416Sbostic 		*(int *)data = tp->t_line;
681*64416Sbostic 		break;
682*64416Sbostic 	case TIOCGWINSZ:		/* get window size */
683*64416Sbostic 		*(struct winsize *)data = tp->t_winsize;
684*64416Sbostic 		break;
685*64416Sbostic 	case TIOCGPGRP:			/* get pgrp of tty */
686*64416Sbostic 		if (!isctty(p, tp))
687*64416Sbostic 			return (ENOTTY);
688*64416Sbostic 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
689*64416Sbostic 		break;
690*64416Sbostic #ifdef TIOCHPCL
691*64416Sbostic 	case TIOCHPCL:			/* hang up on last close */
692*64416Sbostic 		s = spltty();
693*64416Sbostic 		tp->t_cflag |= HUPCL;
694*64416Sbostic 		splx(s);
695*64416Sbostic 		break;
696*64416Sbostic #endif
697*64416Sbostic 	case TIOCNXCL:			/* reset exclusive use of tty */
698*64416Sbostic 		s = spltty();
699*64416Sbostic 		CLR(tp->t_state, TS_XCLUDE);
700*64416Sbostic 		splx(s);
701*64416Sbostic 		break;
702*64416Sbostic 	case TIOCOUTQ:			/* output queue size */
703*64416Sbostic 		*(int *)data = tp->t_outq.c_cc;
704*64416Sbostic 		break;
705*64416Sbostic 	case TIOCSETA:			/* set termios struct */
706*64416Sbostic 	case TIOCSETAW:			/* drain output, set */
707*64416Sbostic 	case TIOCSETAF: {		/* drn out, fls in, set */
708*64416Sbostic 		register struct termios *t = (struct termios *)data;
709*64416Sbostic 
710*64416Sbostic 		s = spltty();
711*64416Sbostic 		if (com == TIOCSETAW || com == TIOCSETAF) {
712*64416Sbostic 			if (error = ttywait(tp)) {
713*64416Sbostic 				splx(s);
714*64416Sbostic 				return (error);
715*64416Sbostic 			}
716*64416Sbostic 			if (com == TIOCSETAF)
717*64416Sbostic 				ttyflush(tp, FREAD);
718*64416Sbostic 		}
719*64416Sbostic 		if (!ISSET(t->c_cflag, CIGNORE)) {
720*64416Sbostic 			/*
721*64416Sbostic 			 * Set device hardware.
722*64416Sbostic 			 */
723*64416Sbostic 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
724*64416Sbostic 				splx(s);
725*64416Sbostic 				return (error);
726*64416Sbostic 			} else {
727*64416Sbostic 				if (!ISSET(tp->t_state, TS_CARR_ON) &&
728*64416Sbostic 				    ISSET(tp->t_cflag, CLOCAL) &&
729*64416Sbostic 				    !ISSET(t->c_cflag, CLOCAL)) {
730*64416Sbostic 					CLR(tp->t_state, TS_ISOPEN);
731*64416Sbostic 					SET(tp->t_state, TS_WOPEN);
732*64416Sbostic 					ttwakeup(tp);
733*64416Sbostic 				}
734*64416Sbostic 				tp->t_cflag = t->c_cflag;
735*64416Sbostic 				tp->t_ispeed = t->c_ispeed;
736*64416Sbostic 				tp->t_ospeed = t->c_ospeed;
737*64416Sbostic 			}
738*64416Sbostic 			ttsetwater(tp);
739*64416Sbostic 		}
740*64416Sbostic 		if (com != TIOCSETAF) {
741*64416Sbostic 			if (ISSET(t->c_lflag, ICANON) !=
742*64416Sbostic 			    ISSET(tp->t_lflag, ICANON))
743*64416Sbostic 				if (ISSET(t->c_lflag, ICANON)) {
744*64416Sbostic 					tp->t_lflag |= PENDIN;
745*64416Sbostic 					ttwakeup(tp);
746*64416Sbostic 				} else {
747*64416Sbostic 					struct clist tq;
748*64416Sbostic 
749*64416Sbostic 					catq(&tp->t_rawq, &tp->t_canq);
750*64416Sbostic 					tq = tp->t_rawq;
751*64416Sbostic 					tp->t_rawq = tp->t_canq;
752*64416Sbostic 					tp->t_canq = tq;
753*64416Sbostic 				}
754*64416Sbostic 		}
755*64416Sbostic 		tp->t_iflag = t->c_iflag;
756*64416Sbostic 		tp->t_oflag = t->c_oflag;
757*64416Sbostic 		/*
758*64416Sbostic 		 * Make the EXTPROC bit read only.
759*64416Sbostic 		 */
760*64416Sbostic 		if (ISSET(tp->t_lflag, EXTPROC))
761*64416Sbostic 			SET(t->c_lflag, EXTPROC);
762*64416Sbostic 		else
763*64416Sbostic 			CLR(t->c_lflag, EXTPROC);
764*64416Sbostic 		tp->t_lflag = t->c_lflag;
765*64416Sbostic 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
766*64416Sbostic 		splx(s);
767*64416Sbostic 		break;
768*64416Sbostic 	}
769*64416Sbostic 	case TIOCSETD: {		/* set line discipline */
770*64416Sbostic 		register int t = *(int *)data;
771*64416Sbostic 		dev_t device = tp->t_dev;
772*64416Sbostic 
773*64416Sbostic 		if ((u_int)t >= nldisp)
774*64416Sbostic 			return (ENXIO);
775*64416Sbostic 		if (t != tp->t_line) {
776*64416Sbostic 			s = spltty();
777*64416Sbostic 			(*linesw[tp->t_line].l_close)(tp, flag);
778*64416Sbostic 			error = (*linesw[t].l_open)(device, tp);
779*64416Sbostic 			if (error) {
780*64416Sbostic 				(void)(*linesw[tp->t_line].l_open)(device, tp);
781*64416Sbostic 				splx(s);
782*64416Sbostic 				return (error);
783*64416Sbostic 			}
784*64416Sbostic 			tp->t_line = t;
785*64416Sbostic 			splx(s);
786*64416Sbostic 		}
787*64416Sbostic 		break;
788*64416Sbostic 	}
789*64416Sbostic 	case TIOCSTART:			/* start output, like ^Q */
790*64416Sbostic 		s = spltty();
791*64416Sbostic 		if (ISSET(tp->t_state, TS_TTSTOP) ||
792*64416Sbostic 		    ISSET(tp->t_lflag, FLUSHO)) {
793*64416Sbostic 			CLR(tp->t_lflag, FLUSHO);
794*64416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
795*64416Sbostic 			ttstart(tp);
796*64416Sbostic 		}
797*64416Sbostic 		splx(s);
798*64416Sbostic 		break;
799*64416Sbostic 	case TIOCSTI:			/* simulate terminal input */
800*64416Sbostic 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
801*64416Sbostic 			return (EPERM);
802*64416Sbostic 		if (p->p_ucred->cr_uid && !isctty(p, tp))
803*64416Sbostic 			return (EACCES);
804*64416Sbostic 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
805*64416Sbostic 		break;
806*64416Sbostic 	case TIOCSTOP:			/* stop output, like ^S */
807*64416Sbostic 		s = spltty();
808*64416Sbostic 		if (!ISSET(tp->t_state, TS_TTSTOP)) {
809*64416Sbostic 			SET(tp->t_state, TS_TTSTOP);
810*64416Sbostic #ifdef sun4c				/* XXX */
811*64416Sbostic 			(*tp->t_stop)(tp, 0);
812*64416Sbostic #else
813*64416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
814*64416Sbostic #endif
815*64416Sbostic 		}
816*64416Sbostic 		splx(s);
817*64416Sbostic 		break;
818*64416Sbostic 	case TIOCSCTTY:			/* become controlling tty */
819*64416Sbostic 		/* Session ctty vnode pointer set in vnode layer. */
820*64416Sbostic 		if (!SESS_LEADER(p) ||
821*64416Sbostic 		    (p->p_session->s_ttyvp || tp->t_session) &&
822*64416Sbostic 		    (tp->t_session != p->p_session))
823*64416Sbostic 			return (EPERM);
824*64416Sbostic 		tp->t_session = p->p_session;
825*64416Sbostic 		tp->t_pgrp = p->p_pgrp;
826*64416Sbostic 		p->p_session->s_ttyp = tp;
827*64416Sbostic 		p->p_flag |= SCTTY;
828*64416Sbostic 		break;
829*64416Sbostic 	case TIOCSPGRP: {		/* set pgrp of tty */
830*64416Sbostic 		register struct pgrp *pgrp = pgfind(*(int *)data);
831*64416Sbostic 
832*64416Sbostic 		if (!isctty(p, tp))
833*64416Sbostic 			return (ENOTTY);
834*64416Sbostic 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
835*64416Sbostic 			return (EPERM);
836*64416Sbostic 		tp->t_pgrp = pgrp;
837*64416Sbostic 		break;
838*64416Sbostic 	}
839*64416Sbostic 	case TIOCSWINSZ:		/* set window size */
840*64416Sbostic 		if (bcmp((caddr_t)&tp->t_winsize, data,
841*64416Sbostic 		    sizeof (struct winsize))) {
842*64416Sbostic 			tp->t_winsize = *(struct winsize *)data;
843*64416Sbostic 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
844*64416Sbostic 		}
845*64416Sbostic 		break;
846*64416Sbostic 	default:
847*64416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
848*64416Sbostic 		return (ttcompat(tp, com, data, flag));
849*64416Sbostic #else
850*64416Sbostic 		return (-1);
851*64416Sbostic #endif
852*64416Sbostic 	}
853*64416Sbostic 	return (0);
854*64416Sbostic }
855*64416Sbostic 
856*64416Sbostic int
857*64416Sbostic ttselect(device, rw, p)
858*64416Sbostic 	dev_t device;
859*64416Sbostic 	int rw;
860*64416Sbostic 	struct proc *p;
861*64416Sbostic {
862*64416Sbostic 	register struct tty *tp;
863*64416Sbostic 	int nread, s;
864*64416Sbostic 
865*64416Sbostic 	tp = &cdevsw[major(device)].d_ttys[minor(device)];
866*64416Sbostic 
867*64416Sbostic 	s = spltty();
868*64416Sbostic 	switch (rw) {
869*64416Sbostic 	case FREAD:
870*64416Sbostic 		nread = ttnread(tp);
871*64416Sbostic 		if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
872*64416Sbostic 		    !ISSET(tp->t_state, TS_CARR_ON))
873*64416Sbostic 			goto win;
874*64416Sbostic 		selrecord(p, &tp->t_rsel);
875*64416Sbostic 		break;
876*64416Sbostic 	case FWRITE:
877*64416Sbostic 		if (tp->t_outq.c_cc <= tp->t_lowat) {
878*64416Sbostic win:			splx(s);
879*64416Sbostic 			return (1);
880*64416Sbostic 		}
881*64416Sbostic 		selrecord(p, &tp->t_wsel);
882*64416Sbostic 		break;
883*64416Sbostic 	}
884*64416Sbostic 	splx(s);
885*64416Sbostic 	return (0);
886*64416Sbostic }
887*64416Sbostic 
888*64416Sbostic static int
889*64416Sbostic ttnread(tp)
890*64416Sbostic 	struct tty *tp;
891*64416Sbostic {
892*64416Sbostic 	int nread;
893*64416Sbostic 
894*64416Sbostic 	if (ISSET(tp->t_lflag, PENDIN))
895*64416Sbostic 		ttypend(tp);
896*64416Sbostic 	nread = tp->t_canq.c_cc;
897*64416Sbostic 	if (!ISSET(tp->t_lflag, ICANON))
898*64416Sbostic 		nread += tp->t_rawq.c_cc;
899*64416Sbostic 	return (nread);
900*64416Sbostic }
901*64416Sbostic 
902*64416Sbostic /*
903*64416Sbostic  * Wait for output to drain.
904*64416Sbostic  */
905*64416Sbostic int
906*64416Sbostic ttywait(tp)
907*64416Sbostic 	register struct tty *tp;
908*64416Sbostic {
909*64416Sbostic 	int error, s;
910*64416Sbostic 
911*64416Sbostic 	error = 0;
912*64416Sbostic 	s = spltty();
913*64416Sbostic 	while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
914*64416Sbostic 	    (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
915*64416Sbostic 	    && tp->t_oproc) {
916*64416Sbostic 		(*tp->t_oproc)(tp);
917*64416Sbostic 		SET(tp->t_state, TS_ASLEEP);
918*64416Sbostic 		if (error = ttysleep(tp,
919*64416Sbostic 		    &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
920*64416Sbostic 			break;
921*64416Sbostic 	}
922*64416Sbostic 	splx(s);
923*64416Sbostic 	return (error);
924*64416Sbostic }
925*64416Sbostic 
926*64416Sbostic /*
927*64416Sbostic  * Flush if successfully wait.
928*64416Sbostic  */
929*64416Sbostic int
930*64416Sbostic ttywflush(tp)
931*64416Sbostic 	struct tty *tp;
932*64416Sbostic {
933*64416Sbostic 	int error;
934*64416Sbostic 
935*64416Sbostic 	if ((error = ttywait(tp)) == 0)
936*64416Sbostic 		ttyflush(tp, FREAD);
937*64416Sbostic 	return (error);
938*64416Sbostic }
939*64416Sbostic 
940*64416Sbostic /*
941*64416Sbostic  * Flush tty read and/or write queues, notifying anyone waiting.
942*64416Sbostic  */
943*64416Sbostic void
944*64416Sbostic ttyflush(tp, rw)
945*64416Sbostic 	register struct tty *tp;
946*64416Sbostic 	int rw;
947*64416Sbostic {
948*64416Sbostic 	register int s;
949*64416Sbostic 
950*64416Sbostic 	s = spltty();
951*64416Sbostic 	if (rw & FREAD) {
952*64416Sbostic 		FLUSHQ(&tp->t_canq);
953*64416Sbostic 		FLUSHQ(&tp->t_rawq);
954*64416Sbostic 		tp->t_rocount = 0;
955*64416Sbostic 		tp->t_rocol = 0;
956*64416Sbostic 		CLR(tp->t_state, TS_LOCAL);
957*64416Sbostic 		ttwakeup(tp);
958*64416Sbostic 	}
959*64416Sbostic 	if (rw & FWRITE) {
960*64416Sbostic 		CLR(tp->t_state, TS_TTSTOP);
961*64416Sbostic #ifdef sun4c						/* XXX */
962*64416Sbostic 		(*tp->t_stop)(tp, rw);
963*64416Sbostic #else
964*64416Sbostic 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
965*64416Sbostic #endif
966*64416Sbostic 		FLUSHQ(&tp->t_outq);
967*64416Sbostic 		wakeup((caddr_t)&tp->t_outq);
968*64416Sbostic 		selwakeup(&tp->t_wsel);
969*64416Sbostic 	}
970*64416Sbostic 	splx(s);
971*64416Sbostic }
972*64416Sbostic 
973*64416Sbostic /*
974*64416Sbostic  * Copy in the default termios characters.
975*64416Sbostic  */
976*64416Sbostic void
977*64416Sbostic ttychars(tp)
978*64416Sbostic 	struct tty *tp;
979*64416Sbostic {
980*64416Sbostic 
981*64416Sbostic 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
982*64416Sbostic }
983*64416Sbostic 
984*64416Sbostic /*
985*64416Sbostic  * Send stop character on input overflow.
986*64416Sbostic  */
987*64416Sbostic static void
988*64416Sbostic ttyblock(tp)
989*64416Sbostic 	register struct tty *tp;
990*64416Sbostic {
991*64416Sbostic 	register int total;
992*64416Sbostic 
993*64416Sbostic 	total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
994*64416Sbostic 	if (tp->t_rawq.c_cc > TTYHOG) {
995*64416Sbostic 		ttyflush(tp, FREAD | FWRITE);
996*64416Sbostic 		CLR(tp->t_state, TS_TBLOCK);
997*64416Sbostic 	}
998*64416Sbostic 	/*
999*64416Sbostic 	 * Block further input iff: current input > threshold
1000*64416Sbostic 	 * AND input is available to user program.
1001*64416Sbostic 	 */
1002*64416Sbostic 	if (total >= TTYHOG / 2 &&
1003*64416Sbostic 	    !ISSET(tp->t_state, TS_TBLOCK) &&
1004*64416Sbostic 	    !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
1005*64416Sbostic 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
1006*64416Sbostic 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
1007*64416Sbostic 			SET(tp->t_state, TS_TBLOCK);
1008*64416Sbostic 			ttstart(tp);
1009*64416Sbostic 		}
1010*64416Sbostic 	}
1011*64416Sbostic }
1012*64416Sbostic 
1013*64416Sbostic void
1014*64416Sbostic ttrstrt(tp_arg)
1015*64416Sbostic 	void *tp_arg;
1016*64416Sbostic {
1017*64416Sbostic 	struct tty *tp;
1018*64416Sbostic 	int s;
1019*64416Sbostic 
1020*64416Sbostic #ifdef DIAGNOSTIC
1021*64416Sbostic 	if (tp_arg == NULL)
1022*64416Sbostic 		panic("ttrstrt");
1023*64416Sbostic #endif
1024*64416Sbostic 	tp = tp_arg;
1025*64416Sbostic 	s = spltty();
1026*64416Sbostic 
1027*64416Sbostic 	CLR(tp->t_state, TS_TIMEOUT);
1028*64416Sbostic 	ttstart(tp);
1029*64416Sbostic 
1030*64416Sbostic 	splx(s);
1031*64416Sbostic }
1032*64416Sbostic 
1033*64416Sbostic int
1034*64416Sbostic ttstart(tp)
1035*64416Sbostic 	struct tty *tp;
1036*64416Sbostic {
1037*64416Sbostic 
1038*64416Sbostic 	if (tp->t_oproc != NULL)	/* XXX: Kludge for pty. */
1039*64416Sbostic 		(*tp->t_oproc)(tp);
1040*64416Sbostic 	return (0);
1041*64416Sbostic }
1042*64416Sbostic 
1043*64416Sbostic /*
1044*64416Sbostic  * "close" a line discipline
1045*64416Sbostic  */
1046*64416Sbostic int
1047*64416Sbostic ttylclose(tp, flag)
1048*64416Sbostic 	struct tty *tp;
1049*64416Sbostic 	int flag;
1050*64416Sbostic {
1051*64416Sbostic 
1052*64416Sbostic 	if (flag & IO_NDELAY)
1053*64416Sbostic 		ttyflush(tp, FREAD | FWRITE);
1054*64416Sbostic 	else
1055*64416Sbostic 		ttywflush(tp);
1056*64416Sbostic 	return (0);
1057*64416Sbostic }
1058*64416Sbostic 
1059*64416Sbostic /*
1060*64416Sbostic  * Handle modem control transition on a tty.
1061*64416Sbostic  * Flag indicates new state of carrier.
1062*64416Sbostic  * Returns 0 if the line should be turned off, otherwise 1.
1063*64416Sbostic  */
1064*64416Sbostic int
1065*64416Sbostic ttymodem(tp, flag)
1066*64416Sbostic 	register struct tty *tp;
1067*64416Sbostic 	int flag;
1068*64416Sbostic {
1069*64416Sbostic 
1070*64416Sbostic 	if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
1071*64416Sbostic 		/*
1072*64416Sbostic 		 * MDMBUF: do flow control according to carrier flag
1073*64416Sbostic 		 */
1074*64416Sbostic 		if (flag) {
1075*64416Sbostic 			CLR(tp->t_state, TS_TTSTOP);
1076*64416Sbostic 			ttstart(tp);
1077*64416Sbostic 		} else if (!ISSET(tp->t_state, TS_TTSTOP)) {
1078*64416Sbostic 			SET(tp->t_state, TS_TTSTOP);
1079*64416Sbostic #ifdef sun4c						/* XXX */
1080*64416Sbostic 			(*tp->t_stop)(tp, 0);
1081*64416Sbostic #else
1082*64416Sbostic 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
1083*64416Sbostic #endif
1084*64416Sbostic 		}
1085*64416Sbostic 	} else if (flag == 0) {
1086*64416Sbostic 		/*
1087*64416Sbostic 		 * Lost carrier.
1088*64416Sbostic 		 */
1089*64416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
1090*64416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN) &&
1091*64416Sbostic 		    !ISSET(tp->t_cflag, CLOCAL)) {
1092*64416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
1093*64416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
1094*64416Sbostic 			ttyflush(tp, FREAD | FWRITE);
1095*64416Sbostic 			return (0);
1096*64416Sbostic 		}
1097*64416Sbostic 	} else {
1098*64416Sbostic 		/*
1099*64416Sbostic 		 * Carrier now on.
1100*64416Sbostic 		 */
1101*64416Sbostic 		SET(tp->t_state, TS_CARR_ON);
1102*64416Sbostic 		ttwakeup(tp);
1103*64416Sbostic 	}
1104*64416Sbostic 	return (1);
1105*64416Sbostic }
1106*64416Sbostic 
1107*64416Sbostic /*
1108*64416Sbostic  * Default modem control routine (for other line disciplines).
1109*64416Sbostic  * Return argument flag, to turn off device on carrier drop.
1110*64416Sbostic  */
1111*64416Sbostic int
1112*64416Sbostic nullmodem(tp, flag)
1113*64416Sbostic 	register struct tty *tp;
1114*64416Sbostic 	int flag;
1115*64416Sbostic {
1116*64416Sbostic 
1117*64416Sbostic 	if (flag)
1118*64416Sbostic 		SET(tp->t_state, TS_CARR_ON);
1119*64416Sbostic 	else {
1120*64416Sbostic 		CLR(tp->t_state, TS_CARR_ON);
1121*64416Sbostic 		if (!ISSET(tp->t_cflag, CLOCAL)) {
1122*64416Sbostic 			if (tp->t_session && tp->t_session->s_leader)
1123*64416Sbostic 				psignal(tp->t_session->s_leader, SIGHUP);
1124*64416Sbostic 			return (0);
1125*64416Sbostic 		}
1126*64416Sbostic 	}
1127*64416Sbostic 	return (1);
1128*64416Sbostic }
1129*64416Sbostic 
1130*64416Sbostic /*
1131*64416Sbostic  * Reinput pending characters after state switch
1132*64416Sbostic  * call at spltty().
1133*64416Sbostic  */
1134*64416Sbostic void
1135*64416Sbostic ttypend(tp)
1136*64416Sbostic 	register struct tty *tp;
1137*64416Sbostic {
1138*64416Sbostic 	struct clist tq;
1139*64416Sbostic 	register c;
1140*64416Sbostic 
1141*64416Sbostic 	CLR(tp->t_lflag, PENDIN);
1142*64416Sbostic 	SET(tp->t_state, TS_TYPEN);
1143*64416Sbostic 	tq = tp->t_rawq;
1144*64416Sbostic 	tp->t_rawq.c_cc = 0;
1145*64416Sbostic 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
1146*64416Sbostic 	while ((c = getc(&tq)) >= 0)
1147*64416Sbostic 		ttyinput(c, tp);
1148*64416Sbostic 	CLR(tp->t_state, TS_TYPEN);
1149*64416Sbostic }
1150*64416Sbostic 
1151*64416Sbostic /*
115249380Skarels  * Process a read call on a tty device.
11537502Sroot  */
1154*64416Sbostic int
115537584Smarc ttread(tp, uio, flag)
11567625Ssam 	register struct tty *tp;
11577722Swnj 	struct uio *uio;
115852485Storek 	int flag;
11597502Sroot {
11607502Sroot 	register struct clist *qp;
116135811Smarc 	register int c;
116241383Smarc 	register long lflag;
116335811Smarc 	register u_char *cc = tp->t_cc;
116447545Skarels 	register struct proc *p = curproc;
11659859Ssam 	int s, first, error = 0;
11667502Sroot 
1167*64416Sbostic loop:	lflag = tp->t_lflag;
116837584Smarc 	s = spltty();
11699578Ssam 	/*
1170*64416Sbostic 	 * take pending input first
11719578Ssam 	 */
1172*64416Sbostic 	if (ISSET(lflag, PENDIN))
11737502Sroot 		ttypend(tp);
11749859Ssam 	splx(s);
117540712Skarels 
11769578Ssam 	/*
11779578Ssam 	 * Hang process if it's in the background.
11789578Ssam 	 */
117947545Skarels 	if (isbackground(p, tp)) {
118047545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
118147545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
1182*64416Sbostic 		    p->p_flag & SPPWAIT || p->p_pgrp->pg_jobc == 0)
11838520Sroot 			return (EIO);
118447545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
1185*64416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
118640712Skarels 			return (error);
118723165Sbloom 		goto loop;
11887502Sroot 	}
118940712Skarels 
11909578Ssam 	/*
119135811Smarc 	 * If canonical, use the canonical queue,
119235811Smarc 	 * else use the raw queue.
119337584Smarc 	 *
119447545Skarels 	 * (should get rid of clists...)
11959578Ssam 	 */
1196*64416Sbostic 	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq;
119740712Skarels 
11989578Ssam 	/*
119940712Skarels 	 * If there is no input, sleep on rawq
120040712Skarels 	 * awaiting hardware receipt and notification.
120140712Skarels 	 * If we have data, we don't need to check for carrier.
12029578Ssam 	 */
120317545Skarels 	s = spltty();
12049578Ssam 	if (qp->c_cc <= 0) {
120540712Skarels 		int carrier;
120640712Skarels 
1207*64416Sbostic 		carrier = ISSET(tp->t_state, TS_CARR_ON) ||
1208*64416Sbostic 		    ISSET(tp->t_cflag, CLOCAL);
1209*64416Sbostic 		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12109859Ssam 			splx(s);
121140712Skarels 			return (0);	/* EOF */
12127502Sroot 		}
121337728Smckusick 		if (flag & IO_NDELAY) {
121437584Smarc 			splx(s);
121537584Smarc 			return (EWOULDBLOCK);
121637584Smarc 		}
1217*64416Sbostic 		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
121840712Skarels 		    carrier ? ttyin : ttopen, 0);
12199859Ssam 		splx(s);
122043377Smarc 		if (error)
122140712Skarels 			return (error);
12229578Ssam 		goto loop;
12239578Ssam 	}
12249859Ssam 	splx(s);
122540712Skarels 
12269578Ssam 	/*
122735811Smarc 	 * Input present, check for input mapping and processing.
12289578Ssam 	 */
12299578Ssam 	first = 1;
12309578Ssam 	while ((c = getc(qp)) >= 0) {
12319578Ssam 		/*
123235811Smarc 		 * delayed suspend (^Y)
12339578Ssam 		 */
1234*64416Sbostic 		if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
123542882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12369578Ssam 			if (first) {
1237*64416Sbostic 				if (error = ttysleep(tp,
1238*64416Sbostic 				    &lbolt, TTIPRI | PCATCH, ttybg, 0))
123940712Skarels 					break;
12409578Ssam 				goto loop;
12419578Ssam 			}
12429578Ssam 			break;
12437502Sroot 		}
12449578Ssam 		/*
124535811Smarc 		 * Interpret EOF only in canonical mode.
12469578Ssam 		 */
1247*64416Sbostic 		if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12489578Ssam 			break;
12499578Ssam 		/*
12509578Ssam 		 * Give user character.
12519578Ssam 		 */
125240712Skarels  		error = ureadc(c, uio);
12539578Ssam 		if (error)
12549578Ssam 			break;
125514938Smckusick  		if (uio->uio_resid == 0)
12569578Ssam 			break;
12579578Ssam 		/*
125835811Smarc 		 * In canonical mode check for a "break character"
12599578Ssam 		 * marking the end of a "line of input".
12609578Ssam 		 */
1261*64416Sbostic 		if (ISSET(lflag, ICANON) && TTBREAKC(c))
12629578Ssam 			break;
12639578Ssam 		first = 0;
12647502Sroot 	}
12659578Ssam 	/*
12669578Ssam 	 * Look to unblock output now that (presumably)
12679578Ssam 	 * the input queue has gone down.
12689578Ssam 	 */
126952485Storek 	s = spltty();
1270*64416Sbostic 	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
127147545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
127247545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
1273*64416Sbostic 			CLR(tp->t_state, TS_TBLOCK);
12747502Sroot 			ttstart(tp);
12757502Sroot 		}
127635811Smarc 	}
127752485Storek 	splx(s);
12788520Sroot 	return (error);
12797502Sroot }
12807502Sroot 
12817502Sroot /*
1282*64416Sbostic  * Check the output queue on tp for space for a kernel message (from uprintf
1283*64416Sbostic  * or tprintf).  Allow some space over the normal hiwater mark so we don't
1284*64416Sbostic  * lose messages due to normal flow control, but don't let the tty run amok.
1285*64416Sbostic  * Sleeps here are not interruptible, but we return prematurely if new signals
1286*64416Sbostic  * arrive.
128725391Skarels  */
1288*64416Sbostic int
128925391Skarels ttycheckoutq(tp, wait)
129025391Skarels 	register struct tty *tp;
129125391Skarels 	int wait;
129225391Skarels {
129330695Skarels 	int hiwat, s, oldsig;
129425391Skarels 
129535811Smarc 	hiwat = tp->t_hiwat;
129625391Skarels 	s = spltty();
129752485Storek 	oldsig = wait ? curproc->p_sig : 0;
129825391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
129929946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130029946Skarels 			ttstart(tp);
130147545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
130229946Skarels 				splx(s);
130329946Skarels 				return (0);
130429946Skarels 			}
130554782Storek 			timeout((void (*)__P((void *)))wakeup,
130654782Storek 			    (void *)&tp->t_outq, hz);
1307*64416Sbostic 			SET(tp->t_state, TS_ASLEEP);
130830695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
130925391Skarels 		}
131025391Skarels 	splx(s);
131125391Skarels 	return (1);
131225391Skarels }
131325391Skarels 
131425391Skarels /*
131549380Skarels  * Process a write call on a tty device.
13167502Sroot  */
1317*64416Sbostic int
131837584Smarc ttwrite(tp, uio, flag)
13197625Ssam 	register struct tty *tp;
13209578Ssam 	register struct uio *uio;
132152485Storek 	int flag;
13227502Sroot {
13237502Sroot 	register char *cp;
1324*64416Sbostic 	register int cc, ce;
1325*64416Sbostic 	register struct proc *p;
13269578Ssam 	int i, hiwat, cnt, error, s;
13277502Sroot 	char obuf[OBUFSIZ];
13287502Sroot 
132935811Smarc 	hiwat = tp->t_hiwat;
13309578Ssam 	cnt = uio->uio_resid;
13319578Ssam 	error = 0;
13327502Sroot loop:
133337584Smarc 	s = spltty();
1334*64416Sbostic 	if (!ISSET(tp->t_state, TS_CARR_ON) &&
1335*64416Sbostic 	    !ISSET(tp->t_cflag, CLOCAL)) {
1336*64416Sbostic 		if (ISSET(tp->t_state, TS_ISOPEN)) {
133737584Smarc 			splx(s);
133837584Smarc 			return (EIO);
133937728Smckusick 		} else if (flag & IO_NDELAY) {
134037584Smarc 			splx(s);
134140712Skarels 			error = EWOULDBLOCK;
134240712Skarels 			goto out;
134337584Smarc 		} else {
1344*64416Sbostic 			/* Sleep awaiting carrier. */
1345*64416Sbostic 			error = ttysleep(tp,
1346*64416Sbostic 			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
134737584Smarc 			splx(s);
134843377Smarc 			if (error)
134940712Skarels 				goto out;
135037584Smarc 			goto loop;
135137584Smarc 		}
135237584Smarc 	}
135337584Smarc 	splx(s);
13549578Ssam 	/*
13559578Ssam 	 * Hang the process if it's in the background.
13569578Ssam 	 */
1357*64416Sbostic 	p = curproc;
1358*64416Sbostic 	if (isbackground(p, tp) &&
1359*64416Sbostic 	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & SPPWAIT) == 0 &&
136047545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
136147545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
136247545Skarels 	     p->p_pgrp->pg_jobc) {
136347545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
1364*64416Sbostic 		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
136540712Skarels 			goto out;
136621776Sbloom 		goto loop;
13677502Sroot 	}
13689578Ssam 	/*
1369*64416Sbostic 	 * Process the user's data in at most OBUFSIZ chunks.  Perform any
1370*64416Sbostic 	 * output translation.  Keep track of high water mark, sleep on
1371*64416Sbostic 	 * overflow awaiting device aid in acquiring new space.
13729578Ssam 	 */
1373*64416Sbostic 	for (cc = 0; uio->uio_resid > 0 || cc > 0;) {
1374*64416Sbostic 		if (ISSET(tp->t_lflag, FLUSHO)) {
137540712Skarels 			uio->uio_resid = 0;
137640712Skarels 			return (0);
137740712Skarels 		}
137840712Skarels 		if (tp->t_outq.c_cc > hiwat)
137932067Skarels 			goto ovhiwat;
13809578Ssam 		/*
1381*64416Sbostic 		 * Grab a hunk of data from the user, unless we have some
1382*64416Sbostic 		 * leftover from last time.
13839578Ssam 		 */
13847822Sroot 		if (cc == 0) {
138540712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
138640712Skarels 			cp = obuf;
138740712Skarels 			error = uiomove(cp, cc, uio);
138840712Skarels 			if (error) {
138940712Skarels 				cc = 0;
139040712Skarels 				break;
139140712Skarels 			}
13927822Sroot 		}
13939578Ssam 		/*
13949578Ssam 		 * If nothing fancy need be done, grab those characters we
13959578Ssam 		 * can handle without any of ttyoutput's processing and
13969578Ssam 		 * just transfer them to the output q.  For those chars
13979578Ssam 		 * which require special processing (as indicated by the
1398*64416Sbostic 		 * bits in char_type), call ttyoutput.  After processing
13999578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14009578Ssam 		 * immediately.
14019578Ssam 		 */
14029578Ssam 		while (cc > 0) {
1403*64416Sbostic 			if (!ISSET(tp->t_oflag, OPOST))
14047502Sroot 				ce = cc;
14057502Sroot 			else {
1406*64416Sbostic 				ce = cc - scanc((u_int)cc, (u_char *)cp,
1407*64416Sbostic 				   (u_char *)char_type, CCLASSMASK);
14089578Ssam 				/*
14099578Ssam 				 * If ce is zero, then we're processing
14109578Ssam 				 * a special character through ttyoutput.
14119578Ssam 				 */
14129578Ssam 				if (ce == 0) {
14137502Sroot 					tp->t_rocount = 0;
14147502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
1415*64416Sbostic 						/* No Clists, wait a bit. */
1416*64416Sbostic 						ttstart(tp);
1417*64416Sbostic 						if (error = ttysleep(tp, &lbolt,
1418*64416Sbostic 						    TTOPRI | PCATCH, ttybuf, 0))
1419*64416Sbostic 							break;
1420*64416Sbostic 						goto loop;
14217502Sroot 					}
1422*64416Sbostic 					cp++;
1423*64416Sbostic 					cc--;
1424*64416Sbostic 					if (ISSET(tp->t_lflag, FLUSHO) ||
14259578Ssam 					    tp->t_outq.c_cc > hiwat)
14267502Sroot 						goto ovhiwat;
14279578Ssam 					continue;
14287502Sroot 				}
14297502Sroot 			}
14309578Ssam 			/*
1431*64416Sbostic 			 * A bunch of normal characters have been found.
1432*64416Sbostic 			 * Transfer them en masse to the output queue and
14339578Ssam 			 * continue processing at the top of the loop.
14349578Ssam 			 * If there are any further characters in this
14359578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14369578Ssam 			 * requiring special handling by ttyoutput.
14379578Ssam 			 */
14387502Sroot 			tp->t_rocount = 0;
14399578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14409578Ssam 			ce -= i;
14419578Ssam 			tp->t_col += ce;
14429578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
144335811Smarc 			tp->t_outcc += ce;
14449578Ssam 			if (i > 0) {
1445*64416Sbostic 				/* No Clists, wait a bit. */
14467502Sroot 				ttstart(tp);
1447*64416Sbostic 				if (error = ttysleep(tp,
1448*64416Sbostic 				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))
144940712Skarels 					break;
145021776Sbloom 				goto loop;
14517502Sroot 			}
1452*64416Sbostic 			if (ISSET(tp->t_lflag, FLUSHO) ||
1453*64416Sbostic 			    tp->t_outq.c_cc > hiwat)
145440712Skarels 				break;
14557502Sroot 		}
145635811Smarc 		ttstart(tp);
14577502Sroot 	}
145840712Skarels out:
145940712Skarels 	/*
1460*64416Sbostic 	 * If cc is nonzero, we leave the uio structure inconsistent, as the
1461*64416Sbostic 	 * offset and iov pointers have moved forward, but it doesn't matter
1462*64416Sbostic 	 * (the call will either return short or restart with a new uio).
146340712Skarels 	 */
146440712Skarels 	uio->uio_resid += cc;
14658520Sroot 	return (error);
146640712Skarels 
14677502Sroot ovhiwat:
146832067Skarels 	ttstart(tp);
146932067Skarels 	s = spltty();
14709578Ssam 	/*
147135811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
147232067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14739578Ssam 	 */
14747502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14759578Ssam 		splx(s);
14767502Sroot 		goto loop;
14777502Sroot 	}
147837728Smckusick 	if (flag & IO_NDELAY) {
147917545Skarels 		splx(s);
148040712Skarels 		uio->uio_resid += cc;
1481*64416Sbostic 		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14827502Sroot 	}
1483*64416Sbostic 	SET(tp->t_state, TS_ASLEEP);
1484*64416Sbostic 	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14859578Ssam 	splx(s);
148643377Smarc 	if (error)
148740712Skarels 		goto out;
14887502Sroot 	goto loop;
14897502Sroot }
14907502Sroot 
14917502Sroot /*
14927502Sroot  * Rubout one character from the rawq of tp
14937502Sroot  * as cleanly as possible.
14947502Sroot  */
1495*64416Sbostic void
14967502Sroot ttyrub(c, tp)
1497*64416Sbostic 	register int c;
14987625Ssam 	register struct tty *tp;
14997502Sroot {
15007502Sroot 	register char *cp;
15017502Sroot 	register int savecol;
1502*64416Sbostic 	int tabc, s;
15037502Sroot 
1504*64416Sbostic 	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15057502Sroot 		return;
1506*64416Sbostic 	CLR(tp->t_lflag, FLUSHO);
1507*64416Sbostic 	if (ISSET(tp->t_lflag, ECHOE)) {
15087502Sroot 		if (tp->t_rocount == 0) {
15097502Sroot 			/*
15107502Sroot 			 * Screwed by ttwrite; retype
15117502Sroot 			 */
15127502Sroot 			ttyretype(tp);
15137502Sroot 			return;
15147502Sroot 		}
1515*64416Sbostic 		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15167502Sroot 			ttyrubo(tp, 2);
151749380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
15187502Sroot 		case ORDINARY:
151935811Smarc 			ttyrubo(tp, 1);
15207502Sroot 			break;
15217502Sroot 		case BACKSPACE:
15227502Sroot 		case CONTROL:
1523*64416Sbostic 		case NEWLINE:
15247502Sroot 		case RETURN:
1525*64416Sbostic 		case VTAB:
1526*64416Sbostic 			if (ISSET(tp->t_lflag, ECHOCTL))
15277502Sroot 				ttyrubo(tp, 2);
15287502Sroot 			break;
1529*64416Sbostic 		case TAB:
15307502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15317502Sroot 				ttyretype(tp);
15327502Sroot 				return;
15337502Sroot 			}
153417545Skarels 			s = spltty();
15357502Sroot 			savecol = tp->t_col;
1536*64416Sbostic 			SET(tp->t_state, TS_CNTTB);
1537*64416Sbostic 			SET(tp->t_lflag, FLUSHO);
15387502Sroot 			tp->t_col = tp->t_rocol;
15399578Ssam 			cp = tp->t_rawq.c_cf;
154039407Smarc 			if (cp)
1541*64416Sbostic 				tabc = *cp;	/* XXX FIX NEXTC */
1542*64416Sbostic 			for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
1543*64416Sbostic 				ttyecho(tabc, tp);
1544*64416Sbostic 			CLR(tp->t_lflag, FLUSHO);
1545*64416Sbostic 			CLR(tp->t_state, TS_CNTTB);
15467502Sroot 			splx(s);
1547*64416Sbostic 
1548*64416Sbostic 			/* savecol will now be length of the tab. */
15497502Sroot 			savecol -= tp->t_col;
15507502Sroot 			tp->t_col += savecol;
15517502Sroot 			if (savecol > 8)
15527502Sroot 				savecol = 8;		/* overflow screw */
15537502Sroot 			while (--savecol >= 0)
1554*64416Sbostic 				(void)ttyoutput('\b', tp);
15557502Sroot 			break;
1556*64416Sbostic 		default:			/* XXX */
1557*64416Sbostic #define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"
1558*64416Sbostic 			(void)printf(PANICSTR, c, CCLASS(c));
1559*64416Sbostic #ifdef notdef
1560*64416Sbostic 			panic(PANICSTR, c, CCLASS(c));
1561*64416Sbostic #endif
156235811Smarc 		}
1563*64416Sbostic 	} else if (ISSET(tp->t_lflag, ECHOPRT)) {
1564*64416Sbostic 		if (!ISSET(tp->t_state, TS_ERASE)) {
1565*64416Sbostic 			SET(tp->t_state, TS_ERASE);
1566*64416Sbostic 			(void)ttyoutput('\\', tp);
15677502Sroot 		}
15687502Sroot 		ttyecho(c, tp);
15697502Sroot 	} else
157035811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
1571*64416Sbostic 	--tp->t_rocount;
15727502Sroot }
15737502Sroot 
15747502Sroot /*
1575*64416Sbostic  * Back over cnt characters, erasing them.
15767502Sroot  */
1577*64416Sbostic static void
15787502Sroot ttyrubo(tp, cnt)
15797625Ssam 	register struct tty *tp;
15807625Ssam 	int cnt;
15817502Sroot {
15827502Sroot 
1583*64416Sbostic 	while (cnt-- > 0) {
1584*64416Sbostic 		(void)ttyoutput('\b', tp);
1585*64416Sbostic 		(void)ttyoutput(' ', tp);
1586*64416Sbostic 		(void)ttyoutput('\b', tp);
1587*64416Sbostic 	}
15887502Sroot }
15897502Sroot 
15907502Sroot /*
1591*64416Sbostic  * ttyretype --
1592*64416Sbostic  *	Reprint the rawq line.  Note, it is assumed that c_cc has already
1593*64416Sbostic  *	been checked.
15947502Sroot  */
1595*64416Sbostic void
15967502Sroot ttyretype(tp)
15977625Ssam 	register struct tty *tp;
15987502Sroot {
15997502Sroot 	register char *cp;
160035811Smarc 	int s, c;
16017502Sroot 
1602*64416Sbostic 	/* Echo the reprint character. */
160335811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
160435811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
1605*64416Sbostic 
1606*64416Sbostic 	(void)ttyoutput('\n', tp);
1607*64416Sbostic 
1608*64416Sbostic 	/*
1609*64416Sbostic 	 * XXX
1610*64416Sbostic 	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
1611*64416Sbostic 	 * BIT OF FIRST CHAR.
1612*64416Sbostic 	 */
161317545Skarels 	s = spltty();
1614*64416Sbostic 	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
1615*64416Sbostic 	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
161635811Smarc 		ttyecho(c, tp);
1617*64416Sbostic 	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
1618*64416Sbostic 	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
161935811Smarc 		ttyecho(c, tp);
1620*64416Sbostic 	CLR(tp->t_state, TS_ERASE);
16217502Sroot 	splx(s);
1622*64416Sbostic 
16237502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16247502Sroot 	tp->t_rocol = 0;
16257502Sroot }
16267502Sroot 
16277502Sroot /*
162835811Smarc  * Echo a typed character to the terminal.
16297502Sroot  */
1630*64416Sbostic static void
16317502Sroot ttyecho(c, tp)
1632*64416Sbostic 	register int c;
16337625Ssam 	register struct tty *tp;
16347502Sroot {
1635*64416Sbostic 
1636*64416Sbostic 	if (!ISSET(tp->t_state, TS_CNTTB))
1637*64416Sbostic 		CLR(tp->t_lflag, FLUSHO);
1638*64416Sbostic 	if ((!ISSET(tp->t_lflag, ECHO) &&
1639*64416Sbostic 	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
1640*64416Sbostic 	    ISSET(tp->t_lflag, EXTPROC))
16417502Sroot 		return;
1642*64416Sbostic 	if (ISSET(tp->t_lflag, ECHOCTL) &&
1643*64416Sbostic 	    ((c & TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
1644*64416Sbostic 	    (c & TTY_CHARMASK) == 0177)) {
1645*64416Sbostic 		(void)ttyoutput('^', tp);
1646*64416Sbostic 		c &= TTY_CHARMASK;
1647*64416Sbostic 		if (c == 0177)
1648*64416Sbostic 			c = '?';
1649*64416Sbostic 		else
1650*64416Sbostic 			c += 'A' - 1;
16517502Sroot 	}
1652*64416Sbostic 	(void)ttyoutput(c, tp);
16537502Sroot }
16547502Sroot 
16557502Sroot /*
165649380Skarels  * Wake up any readers on a tty.
165749380Skarels  */
1658*64416Sbostic void
16597502Sroot ttwakeup(tp)
166047545Skarels 	register struct tty *tp;
16617502Sroot {
16627502Sroot 
166352522Smckusick 	selwakeup(&tp->t_rsel);
1664*64416Sbostic 	if (ISSET(tp->t_state, TS_ASYNC))
1665*64416Sbostic 		pgsignal(tp->t_pgrp, SIGIO, 1);
16667502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16677502Sroot }
166835811Smarc 
166935811Smarc /*
167048439Skarels  * Look up a code for a specified speed in a conversion table;
167148439Skarels  * used by drivers to map software speed values to hardware parameters.
167248439Skarels  */
1673*64416Sbostic int
167448439Skarels ttspeedtab(speed, table)
167552485Storek 	int speed;
167648439Skarels 	register struct speedtab *table;
167748439Skarels {
167848439Skarels 
167948439Skarels 	for ( ; table->sp_speed != -1; table++)
168048439Skarels 		if (table->sp_speed == speed)
168148439Skarels 			return (table->sp_code);
168248439Skarels 	return (-1);
168348439Skarels }
168448439Skarels 
168548439Skarels /*
1686*64416Sbostic  * Set tty hi and low water marks.
168735811Smarc  *
168835811Smarc  * Try to arrange the dynamics so there's about one second
168935811Smarc  * from hi to low water.
1690*64416Sbostic  *
169135811Smarc  */
1692*64416Sbostic void
169335811Smarc ttsetwater(tp)
169435811Smarc 	struct tty *tp;
169535811Smarc {
1696*64416Sbostic 	register int cps, x;
169735811Smarc 
1698*64416Sbostic #define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))
1699*64416Sbostic 
1700*64416Sbostic 	cps = tp->t_ospeed / 10;
1701*64416Sbostic 	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
170235811Smarc 	x += cps;
1703*64416Sbostic 	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
170435811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
1705*64416Sbostic #undef	CLAMP
170635811Smarc }
170735811Smarc 
170839407Smarc /*
170939407Smarc  * Report on state of foreground process group.
171039407Smarc  */
1711*64416Sbostic void
171239407Smarc ttyinfo(tp)
171349907Sbostic 	register struct tty *tp;
171439407Smarc {
171549907Sbostic 	register struct proc *p, *pick;
171641177Smarc 	struct timeval utime, stime;
171749907Sbostic 	int tmp;
171839407Smarc 
1719*64416Sbostic 	if (ttycheckoutq(tp,0) == 0)
172039407Smarc 		return;
172149907Sbostic 
172249907Sbostic 	/* Print load average. */
172352666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
172449907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
172549907Sbostic 
172639555Smarc 	if (tp->t_session == NULL)
172749907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
172841177Smarc 	else if (tp->t_pgrp == NULL)
172949907Sbostic 		ttyprintf(tp, "no foreground process group\n");
173041177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
173149907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
173239407Smarc 	else {
173349907Sbostic 		/* Pick interesting process. */
173449907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
173541177Smarc 			if (proc_compare(pick, p))
173641177Smarc 				pick = p;
173749907Sbostic 
173849907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
173949907Sbostic 		    pick->p_stat == SRUN ? "running" :
174049907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
174149907Sbostic 
174254782Storek 		calcru(pick, &utime, &stime, NULL);
174339407Smarc 
174449907Sbostic 		/* Print user time. */
174549907Sbostic 		ttyprintf(tp, "%d.%02du ",
174649907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
174741177Smarc 
174849907Sbostic 		/* Print system time. */
174949907Sbostic 		ttyprintf(tp, "%d.%02ds ",
175049907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
175149907Sbostic 
175249907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
175349907Sbostic 		/* Print percentage cpu, resident set size. */
175449907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
175549907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
175652485Storek 		    tmp / 100,
175752485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
175852485Storek 			pgtok(pick->p_vmspace->vm_rssize));
175941177Smarc 	}
176049907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
176141177Smarc }
176241177Smarc 
176341177Smarc /*
176441177Smarc  * Returns 1 if p2 is "better" than p1
176541177Smarc  *
176641177Smarc  * The algorithm for picking the "interesting" process is thus:
176741177Smarc  *
176841177Smarc  *	1) (Only foreground processes are eligable - implied)
176941177Smarc  *	2) Runnable processes are favored over anything
177041177Smarc  *	   else.  The runner with the highest cpu
177141177Smarc  *	   utilization is picked (p_cpu).  Ties are
177241177Smarc  *	   broken by picking the highest pid.
177341177Smarc  *	3  Next, the sleeper with the shortest sleep
177441177Smarc  *	   time is favored.  With ties, we pick out
177541177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
177641177Smarc  *	   Further ties are broken by picking the highest
177741177Smarc  *	   pid.
177841177Smarc  *
177941177Smarc  */
178041177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
178145723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
178245723Smckusick #define ONLYA   2
178345723Smckusick #define ONLYB   1
178445723Smckusick #define BOTH    3
178549907Sbostic static int
178641177Smarc proc_compare(p1, p2)
178741177Smarc 	register struct proc *p1, *p2;
178841177Smarc {
178941177Smarc 
179041177Smarc 	if (p1 == NULL)
179141177Smarc 		return (1);
179241177Smarc 	/*
179341177Smarc 	 * see if at least one of them is runnable
179441177Smarc 	 */
179545723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
179645723Smckusick 	case ONLYA:
179745723Smckusick 		return (0);
179845723Smckusick 	case ONLYB:
179941177Smarc 		return (1);
180045723Smckusick 	case BOTH:
180141177Smarc 		/*
180241177Smarc 		 * tie - favor one with highest recent cpu utilization
180341177Smarc 		 */
180441177Smarc 		if (p2->p_cpu > p1->p_cpu)
180541177Smarc 			return (1);
180641177Smarc 		if (p1->p_cpu > p2->p_cpu)
180741177Smarc 			return (0);
180841177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
180941177Smarc 	}
181045723Smckusick 	/*
181145723Smckusick  	 * weed out zombies
181245723Smckusick 	 */
181345723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
181445723Smckusick 	case ONLYA:
181545723Smckusick 		return (1);
181645723Smckusick 	case ONLYB:
181745723Smckusick 		return (0);
181845723Smckusick 	case BOTH:
181945723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
182045723Smckusick 	}
1821*64416Sbostic 	/*
182241177Smarc 	 * pick the one with the smallest sleep time
182341177Smarc 	 */
182441177Smarc 	if (p2->p_slptime > p1->p_slptime)
182541177Smarc 		return (0);
182641177Smarc 	if (p1->p_slptime > p2->p_slptime)
182741177Smarc 		return (1);
182841177Smarc 	/*
182941177Smarc 	 * favor one sleeping in a non-interruptible sleep
183041177Smarc 	 */
1831*64416Sbostic 	if (p1->p_flag & SSINTR && (p2->p_flag & SSINTR) == 0)
183241177Smarc 		return (1);
1833*64416Sbostic 	if (p2->p_flag & SSINTR && (p1->p_flag & SSINTR) == 0)
183441177Smarc 		return (0);
183547545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
183641177Smarc }
183745723Smckusick 
183839555Smarc /*
183939555Smarc  * Output char to tty; console putchar style.
184039555Smarc  */
1841*64416Sbostic int
184239555Smarc tputchar(c, tp)
184339555Smarc 	int c;
184439555Smarc 	struct tty *tp;
184539555Smarc {
1846*64416Sbostic 	register int s;
184739555Smarc 
1848*64416Sbostic 	s = spltty();
1849*64416Sbostic 	if (ISSET(tp->t_state,
1850*64416Sbostic 	    TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
185139555Smarc 		splx(s);
1852*64416Sbostic 		return (-1);
185339555Smarc 	}
1854*64416Sbostic 	if (c == '\n')
1855*64416Sbostic 		(void)ttyoutput('\r', tp);
1856*64416Sbostic 	(void)ttyoutput(c, tp);
1857*64416Sbostic 	ttstart(tp);
185839555Smarc 	splx(s);
1859*64416Sbostic 	return (0);
186039555Smarc }
186143377Smarc 
186244419Smarc /*
1863*64416Sbostic  * Sleep on chan, returning ERESTART if tty changed while we napped and
1864*64416Sbostic  * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If
1865*64416Sbostic  * the tty is revoked, restarting a pending call will redo validation done
1866*64416Sbostic  * at the start of the call.
186744419Smarc  */
1868*64416Sbostic int
186943377Smarc ttysleep(tp, chan, pri, wmesg, timo)
187043377Smarc 	struct tty *tp;
1871*64416Sbostic 	void *chan;
1872*64416Sbostic 	int pri, timo;
187343377Smarc 	char *wmesg;
187443377Smarc {
187543377Smarc 	int error;
1876*64416Sbostic 	short gen;
187743377Smarc 
1878*64416Sbostic 	gen = tp->t_gen;
187943377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
188043377Smarc 		return (error);
1881*64416Sbostic 	return (tp->t_gen == gen ? 0 : ERESTART);
188243377Smarc }
1883