xref: /csrg-svn/sys/kern/tty.c (revision 57138)
149594Sbostic /*-
249594Sbostic  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
349594Sbostic  * Copyright (c) 1991 The Regents of the University of California.
449594Sbostic  * All rights reserved.
523387Smckusick  *
649594Sbostic  * %sccs.include.redist.c%
749594Sbostic  *
8*57138Storek  *	@(#)tty.c	7.56 (Berkeley) 12/15/92
923387Smckusick  */
1039Sbill 
1156517Sbostic #include <sys/param.h>
1256517Sbostic #include <sys/systm.h>
1356517Sbostic #include <sys/ioctl.h>
1456517Sbostic #include <sys/proc.h>
1539407Smarc #define TTYDEFCHARS
1656517Sbostic #include <sys/tty.h>
1735811Smarc #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 
2849907Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2));
2949907Sbostic 
3040712Skarels /* symbolic sleep message strings */
3140712Skarels char ttyin[] = "ttyin";
3240712Skarels char ttyout[] = "ttyout";
3341370Smarc char ttopen[] = "ttyopn";
3441370Smarc char ttclos[] = "ttycls";
3540712Skarels char ttybg[] = "ttybg";
3640712Skarels char ttybuf[] = "ttybuf";
3740712Skarels 
387436Skre /*
397436Skre  * Table giving parity for characters and indicating
4035811Smarc  * character classes to tty driver. The 8th bit
4135811Smarc  * indicates parity, the 7th bit indicates the character
4235811Smarc  * is an alphameric or underscore (for ALTWERASE), and the
4335811Smarc  * low 6 bits indicate delay type.  If the low 6 bits are 0
4449380Skarels  * then the character needs no special processing on output;
4549380Skarels  * classes other than 0 might be translated or (not currently)
4649380Skarels  * require delays.
477436Skre  */
4849380Skarels #define	PARITY(c)	(partab[c] & 0x80)
4949380Skarels #define	ISALPHA(c)	(partab[(c)&TTY_CHARMASK] & 0x40)
5049380Skarels #define	CCLASSMASK	0x3f
5149380Skarels #define	CCLASS(c)	(partab[c] & CCLASSMASK)
5239Sbill 
5349380Skarels #define	E	0x00	/* even parity */
5449380Skarels #define	O	0x80	/* odd parity */
5549380Skarels #define	ALPHA	0x40	/* alpha or underscore */
5649380Skarels 
5749380Skarels #define	NO	ORDINARY
5849380Skarels #define	NA	ORDINARY|ALPHA
5949380Skarels #define	CC	CONTROL
6049380Skarels #define	BS	BACKSPACE
6149380Skarels #define	NL	NEWLINE
6249380Skarels #define	TB	TAB
6349380Skarels #define	VT	VTAB
6449380Skarels #define	CR	RETURN
6549380Skarels 
667436Skre char partab[] = {
6749380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
6849380Skarels 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
6949380Skarels 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
7049380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
7149380Skarels 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7249380Skarels 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7349380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
7449380Skarels 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
7549380Skarels 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
7649380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
7749380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
7849380Skarels 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
7949380Skarels 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
8049380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
8149380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8249380Skarels 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
837436Skre 	/*
8449380Skarels 	 * "meta" chars; should be settable per charset.
8549380Skarels 	 * For now, treat all as normal characters.
867436Skre 	 */
8749380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
8849380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
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,
1037436Skre };
10449380Skarels #undef	NO
10549380Skarels #undef	NA
10649380Skarels #undef	CC
10749380Skarels #undef	BS
10849380Skarels #undef	NL
10949380Skarels #undef	TB
11049380Skarels #undef	VT
11149380Skarels #undef	CR
1127436Skre 
11335811Smarc extern struct tty *constty;		/* temporary virtual console */
11435811Smarc 
115146Sbill /*
11635811Smarc  * Is 'c' a line delimiter ("break" character)?
11739Sbill  */
11840712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \
11940712Skarels 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
12039Sbill 
12139Sbill ttychars(tp)
1229578Ssam 	struct tty *tp;
12339Sbill {
12447545Skarels 
12535811Smarc 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
12639Sbill }
12739Sbill 
12839Sbill /*
12949380Skarels  * Flush tty after output has drained.
13039Sbill  */
13112752Ssam ttywflush(tp)
13237584Smarc 	struct tty *tp;
13339Sbill {
13440712Skarels 	int error;
13539Sbill 
13640712Skarels 	if ((error = ttywait(tp)) == 0)
13740712Skarels 		ttyflush(tp, FREAD);
13840712Skarels 	return (error);
13912752Ssam }
14012752Ssam 
14135811Smarc /*
14235811Smarc  * Wait for output to drain.
14335811Smarc  */
14412752Ssam ttywait(tp)
14512752Ssam 	register struct tty *tp;
14612752Ssam {
14740712Skarels 	int error = 0, s = spltty();
14812752Ssam 
14913809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
15037584Smarc 	    (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
15137584Smarc 	    tp->t_oproc) {
152903Sbill 		(*tp->t_oproc)(tp);
1535408Swnj 		tp->t_state |= TS_ASLEEP;
15443377Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_outq,
15543377Smarc 		    TTOPRI | PCATCH, ttyout, 0))
15640712Skarels 			break;
157903Sbill 	}
1589859Ssam 	splx(s);
15940712Skarels 	return (error);
16039Sbill }
16139Sbill 
16252485Storek #define	flushq(q) { \
16352485Storek 	if ((q)->c_cc) \
16452485Storek 		ndflush(q, (q)->c_cc); \
16549380Skarels }
16649380Skarels 
16739Sbill /*
16849380Skarels  * Flush TTY read and/or write queues,
16949380Skarels  * notifying anyone waiting.
17039Sbill  */
17112752Ssam ttyflush(tp, rw)
1727625Ssam 	register struct tty *tp;
17352485Storek 	int rw;
17439Sbill {
17552485Storek 	register int s;
176903Sbill 
17717545Skarels 	s = spltty();
178903Sbill 	if (rw & FREAD) {
17949380Skarels 		flushq(&tp->t_canq);
18049380Skarels 		flushq(&tp->t_rawq);
18149380Skarels 		tp->t_rocount = 0;
18249380Skarels 		tp->t_rocol = 0;
18349380Skarels 		tp->t_state &= ~TS_LOCAL;
18437584Smarc 		ttwakeup(tp);
185903Sbill 	}
186903Sbill 	if (rw & FWRITE) {
1875408Swnj 		tp->t_state &= ~TS_TTSTOP;
18852485Storek #ifdef sun4c						/* XXX */
18952485Storek 		(*tp->t_stop)(tp, rw);
19052485Storek #else
1915426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
19252485Storek #endif
19349380Skarels 		flushq(&tp->t_outq);
19449380Skarels 		wakeup((caddr_t)&tp->t_outq);
19552522Smckusick 		selwakeup(&tp->t_wsel);
196903Sbill 	}
197903Sbill 	splx(s);
19839Sbill }
19939Sbill 
200903Sbill /*
201903Sbill  * Send stop character on input overflow.
202903Sbill  */
203903Sbill ttyblock(tp)
2047625Ssam 	register struct tty *tp;
20539Sbill {
206903Sbill 	register x;
2079578Ssam 
208903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
209903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
21012752Ssam 		ttyflush(tp, FREAD|FWRITE);
2115408Swnj 		tp->t_state &= ~TS_TBLOCK;
212903Sbill 	}
21315118Skarels 	/*
21415118Skarels 	 * Block further input iff:
21515118Skarels 	 * Current input > threshold AND input is available to user program
21615118Skarels 	 */
21742350Smckusick 	if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
21840712Skarels 	    ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) &&
21935811Smarc 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
22042350Smckusick 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
22115118Skarels 			tp->t_state |= TS_TBLOCK;
22215118Skarels 			ttstart(tp);
22315118Skarels 		}
224903Sbill 	}
22539Sbill }
22639Sbill 
22747545Skarels ttstart(tp)
22837584Smarc 	struct tty *tp;
229121Sbill {
230121Sbill 
23147545Skarels 	if (tp->t_oproc)		/* kludge for pty */
23247545Skarels 		(*tp->t_oproc)(tp);
23347545Skarels }
23447545Skarels 
23554782Storek void
23654782Storek ttrstrt(tp0)
23754782Storek 	void *tp0;
23854782Storek {
23947545Skarels 	struct tty *tp;
24052485Storek 	int s;
24147545Skarels 
24254782Storek 	tp = (struct tty *)tp0;
24340712Skarels #ifdef DIAGNOSTIC
2449578Ssam 	if (tp == 0)
2459578Ssam 		panic("ttrstrt");
24640712Skarels #endif
24752485Storek 	s = spltty();
2485408Swnj 	tp->t_state &= ~TS_TIMEOUT;
249903Sbill 	ttstart(tp);
25052485Storek 	splx(s);
251121Sbill }
252121Sbill 
25339Sbill 
25439Sbill /*
25549380Skarels  * Common code for ioctls on tty devices.
25649380Skarels  * Called after line-discipline-specific ioctl
25749380Skarels  * has been called to do discipline-specific functions
25849380Skarels  * and/or reject any of these ioctl commands.
25939Sbill  */
2601780Sbill /*ARGSUSED*/
2617625Ssam ttioctl(tp, com, data, flag)
2627625Ssam 	register struct tty *tp;
26352485Storek 	int com;
2647625Ssam 	caddr_t data;
26552485Storek 	int flag;
26639Sbill {
26747545Skarels 	register struct proc *p = curproc;		/* XXX */
26839Sbill 	extern int nldisp;
26937554Smckusick 	int s, error;
27039Sbill 
271903Sbill 	/*
272903Sbill 	 * If the ioctl involves modification,
27317545Skarels 	 * hang if in the background.
274903Sbill 	 */
2757625Ssam 	switch (com) {
27639Sbill 
27735811Smarc 	case TIOCSETD:
278903Sbill 	case TIOCFLUSH:
27935811Smarc 	/*case TIOCSPGRP:*/
2809325Ssam 	case TIOCSTI:
28117598Sbloom 	case TIOCSWINSZ:
28235811Smarc 	case TIOCSETA:
28335811Smarc 	case TIOCSETAW:
28435811Smarc 	case TIOCSETAF:
28552485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
28640030Smarc 	case TIOCSETP:
28740030Smarc 	case TIOCSETN:
28840030Smarc 	case TIOCSETC:
28940030Smarc 	case TIOCSLTC:
29040030Smarc 	case TIOCLBIS:
29140030Smarc 	case TIOCLBIC:
29240030Smarc 	case TIOCLSET:
29340030Smarc 	case OTIOCSETD:
29440030Smarc #endif
29547545Skarels 		while (isbackground(curproc, tp) &&
29647545Skarels 		   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
29747545Skarels 		   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
29847545Skarels 		   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
29947545Skarels 			pgsignal(p->p_pgrp, SIGTTOU, 1);
30043377Smarc 			if (error = ttysleep(tp, (caddr_t)&lbolt,
30143377Smarc 			    TTOPRI | PCATCH, ttybg, 0))
30240712Skarels 				return (error);
303903Sbill 		}
304903Sbill 		break;
305903Sbill 	}
306903Sbill 
3079578Ssam 	/*
3089578Ssam 	 * Process the ioctl.
3099578Ssam 	 */
3107625Ssam 	switch (com) {
311903Sbill 
3128556Sroot 	/* get discipline number */
31339Sbill 	case TIOCGETD:
3147625Ssam 		*(int *)data = tp->t_line;
31539Sbill 		break;
31639Sbill 
3178556Sroot 	/* set line discipline */
3187625Ssam 	case TIOCSETD: {
3197625Ssam 		register int t = *(int *)data;
32035811Smarc 		dev_t dev = tp->t_dev;
3217625Ssam 
32235811Smarc 		if ((unsigned)t >= nldisp)
32310851Ssam 			return (ENXIO);
32425584Skarels 		if (t != tp->t_line) {
32525584Skarels 			s = spltty();
32649752Smarc 			(*linesw[tp->t_line].l_close)(tp, flag);
32725584Skarels 			error = (*linesw[t].l_open)(dev, tp);
32825584Skarels 			if (error) {
32935811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
33025584Skarels 				splx(s);
33125584Skarels 				return (error);
33225584Skarels 			}
33325584Skarels 			tp->t_line = t;
33410851Ssam 			splx(s);
33510851Ssam 		}
33639Sbill 		break;
3377625Ssam 	}
33839Sbill 
3398556Sroot 	/* prevent more opens on channel */
3405614Swnj 	case TIOCEXCL:
34152485Storek 		s = spltty();
3425614Swnj 		tp->t_state |= TS_XCLUDE;
34352485Storek 		splx(s);
3445614Swnj 		break;
3455614Swnj 
3465614Swnj 	case TIOCNXCL:
34752485Storek 		s = spltty();
3485614Swnj 		tp->t_state &= ~TS_XCLUDE;
34952485Storek 		splx(s);
3505614Swnj 		break;
3515614Swnj 
35252485Storek #ifdef TIOCHPCL
35339Sbill 	case TIOCHPCL:
35452485Storek 		s = spltty();
35535811Smarc 		tp->t_cflag |= HUPCL;
35652485Storek 		splx(s);
35739Sbill 		break;
35852485Storek #endif
35939Sbill 
3603942Sbugs 	case TIOCFLUSH: {
3617625Ssam 		register int flags = *(int *)data;
3627625Ssam 
3637625Ssam 		if (flags == 0)
3643942Sbugs 			flags = FREAD|FWRITE;
3657625Ssam 		else
3667625Ssam 			flags &= FREAD|FWRITE;
36712752Ssam 		ttyflush(tp, flags);
36839Sbill 		break;
3693944Sbugs 	}
37039Sbill 
37137584Smarc 	case FIOASYNC:
37252485Storek 		s = spltty();
37337584Smarc 		if (*(int *)data)
37437584Smarc 			tp->t_state |= TS_ASYNC;
37537584Smarc 		else
37637584Smarc 			tp->t_state &= ~TS_ASYNC;
37752485Storek 		splx(s);
37837584Smarc 		break;
37937584Smarc 
38037584Smarc 	case FIONBIO:
38137584Smarc 		break;	/* XXX remove */
38237584Smarc 
3838556Sroot 	/* return number of characters immediately available */
3847625Ssam 	case FIONREAD:
38554782Storek 		*(int *)data = ttnread(tp);
386174Sbill 		break;
387174Sbill 
38813077Ssam 	case TIOCOUTQ:
38913077Ssam 		*(int *)data = tp->t_outq.c_cc;
39013077Ssam 		break;
39113077Ssam 
3928589Sroot 	case TIOCSTOP:
39317545Skarels 		s = spltty();
3949578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3955573Swnj 			tp->t_state |= TS_TTSTOP;
39652485Storek #ifdef sun4c						/* XXX */
39752485Storek 			(*tp->t_stop)(tp, 0);
39852485Storek #else
3995573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
40052485Storek #endif
4015573Swnj 		}
4027625Ssam 		splx(s);
4035573Swnj 		break;
4045573Swnj 
4058589Sroot 	case TIOCSTART:
40617545Skarels 		s = spltty();
40735811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
4085573Swnj 			tp->t_state &= ~TS_TTSTOP;
40935811Smarc 			tp->t_lflag &= ~FLUSHO;
4105573Swnj 			ttstart(tp);
4115573Swnj 		}
4127625Ssam 		splx(s);
4135573Swnj 		break;
4145573Swnj 
4159325Ssam 	/*
4169325Ssam 	 * Simulate typing of a character at the terminal.
4179325Ssam 	 */
4189325Ssam 	case TIOCSTI:
41947545Skarels 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
42017183Smckusick 			return (EPERM);
42147545Skarels 		if (p->p_ucred->cr_uid && !isctty(p, tp))
4229325Ssam 			return (EACCES);
423*57138Storek 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
4249325Ssam 		break;
4259325Ssam 
42635811Smarc 	case TIOCGETA: {
42735811Smarc 		struct termios *t = (struct termios *)data;
42812752Ssam 
42935811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
43035811Smarc 		break;
43135811Smarc 	}
43235811Smarc 
43335811Smarc 	case TIOCSETA:
43435811Smarc 	case TIOCSETAW:
43537584Smarc 	case TIOCSETAF: {
43635811Smarc 		register struct termios *t = (struct termios *)data;
43740712Skarels 
43817545Skarels 		s = spltty();
43939407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
44040712Skarels 			if (error = ttywait(tp)) {
44140712Skarels 				splx(s);
44240712Skarels 				return (error);
44340712Skarels 			}
44445007Smarc 			if (com == TIOCSETAF)
44539407Smarc 				ttyflush(tp, FREAD);
44639407Smarc 		}
44740712Skarels 		if ((t->c_cflag&CIGNORE) == 0) {
44835811Smarc 			/*
44935811Smarc 			 * set device hardware
45035811Smarc 			 */
45137584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
45237584Smarc 				splx(s);
45335811Smarc 				return (error);
45437584Smarc 			} else {
45540712Skarels 				if ((tp->t_state&TS_CARR_ON) == 0 &&
45637584Smarc 				    (tp->t_cflag&CLOCAL) &&
45740712Skarels 				    (t->c_cflag&CLOCAL) == 0) {
45837584Smarc 					tp->t_state &= ~TS_ISOPEN;
45937584Smarc 					tp->t_state |= TS_WOPEN;
46037584Smarc 					ttwakeup(tp);
46137584Smarc 				}
46235811Smarc 				tp->t_cflag = t->c_cflag;
46335811Smarc 				tp->t_ispeed = t->c_ispeed;
46435811Smarc 				tp->t_ospeed = t->c_ospeed;
46534492Skarels 			}
46635811Smarc 			ttsetwater(tp);
46712752Ssam 		}
46839407Smarc 		if (com != TIOCSETAF) {
46935811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
47035811Smarc 				if (t->c_lflag&ICANON) {
47135811Smarc 					tp->t_lflag |= PENDIN;
47235811Smarc 					ttwakeup(tp);
47335811Smarc 				}
47435811Smarc 				else {
47535811Smarc 					struct clist tq;
47635811Smarc 
47735811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
47835811Smarc 					tq = tp->t_rawq;
47935811Smarc 					tp->t_rawq = tp->t_canq;
48035811Smarc 					tp->t_canq = tq;
48135811Smarc 				}
48212752Ssam 		}
48335811Smarc 		tp->t_iflag = t->c_iflag;
48435811Smarc 		tp->t_oflag = t->c_oflag;
48542882Smarc 		/*
48642882Smarc 		 * Make the EXTPROC bit read only.
48742882Smarc 		 */
48842882Smarc 		if (tp->t_lflag&EXTPROC)
48942882Smarc 			t->c_lflag |= EXTPROC;
49042882Smarc 		else
49142882Smarc 			t->c_lflag &= ~EXTPROC;
49235811Smarc 		tp->t_lflag = t->c_lflag;
49335811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
49412752Ssam 		splx(s);
49512752Ssam 		break;
49612752Ssam 	}
49712752Ssam 
49812752Ssam 	/*
49939555Smarc 	 * Set controlling terminal.
50039555Smarc 	 * Session ctty vnode pointer set in vnode layer.
50134492Skarels 	 */
50247545Skarels 	case TIOCSCTTY:
50339555Smarc 		if (!SESS_LEADER(p) ||
50439555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
50539555Smarc 		   (tp->t_session != p->p_session))
50639407Smarc 			return (EPERM);
50735811Smarc 		tp->t_session = p->p_session;
50839555Smarc 		tp->t_pgrp = p->p_pgrp;
50939555Smarc 		p->p_session->s_ttyp = tp;
51039555Smarc 		p->p_flag |= SCTTY;
51134492Skarels 		break;
51239555Smarc 
51334492Skarels 	/*
51435811Smarc 	 * Set terminal process group.
51517545Skarels 	 */
51618650Sbloom 	case TIOCSPGRP: {
51735811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
51817545Skarels 
51939555Smarc 		if (!isctty(p, tp))
52039555Smarc 			return (ENOTTY);
52140030Smarc 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
52239555Smarc 			return (EPERM);
52339555Smarc 		tp->t_pgrp = pgrp;
52412752Ssam 		break;
52518650Sbloom 	}
52612752Ssam 
52712752Ssam 	case TIOCGPGRP:
52847545Skarels 		if (!isctty(p, tp))
52939555Smarc 			return (ENOTTY);
53045007Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
53112752Ssam 		break;
53212752Ssam 
53317598Sbloom 	case TIOCSWINSZ:
53418650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
53518650Sbloom 		    sizeof (struct winsize))) {
53617598Sbloom 			tp->t_winsize = *(struct winsize *)data;
53742882Smarc 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
53817598Sbloom 		}
53917598Sbloom 		break;
54017598Sbloom 
54117598Sbloom 	case TIOCGWINSZ:
54217598Sbloom 		*(struct winsize *)data = tp->t_winsize;
54317598Sbloom 		break;
54417598Sbloom 
54530534Skarels 	case TIOCCONS:
54630534Skarels 		if (*(int *)data) {
54742141Smckusick 			if (constty && constty != tp &&
54842141Smckusick 			    (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
54942141Smckusick 			    (TS_CARR_ON|TS_ISOPEN))
55030534Skarels 				return (EBUSY);
55130534Skarels #ifndef	UCONSOLE
55247545Skarels 			if (error = suser(p->p_ucred, &p->p_acflag))
55337554Smckusick 				return (error);
55430534Skarels #endif
55530534Skarels 			constty = tp;
55630534Skarels 		} else if (tp == constty)
55733404Skarels 			constty = NULL;
55830534Skarels 		break;
55930534Skarels 
56048439Skarels 	case TIOCDRAIN:
56148439Skarels 		if (error = ttywait(tp))
56248439Skarels 			return (error);
56348439Skarels 		break;
56448439Skarels 
56547545Skarels 	default:
56652485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
56747545Skarels 		return (ttcompat(tp, com, data, flag));
56847545Skarels #else
56947545Skarels 		return (-1);
57035811Smarc #endif
57139Sbill 	}
5728556Sroot 	return (0);
57339Sbill }
5744484Swnj 
5754484Swnj ttnread(tp)
5764484Swnj 	struct tty *tp;
5774484Swnj {
5784484Swnj 	int nread = 0;
5794484Swnj 
58035811Smarc 	if (tp->t_lflag & PENDIN)
5814484Swnj 		ttypend(tp);
5824484Swnj 	nread = tp->t_canq.c_cc;
58335811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5844484Swnj 		nread += tp->t_rawq.c_cc;
5854484Swnj 	return (nread);
5864484Swnj }
5874484Swnj 
58852522Smckusick ttselect(dev, rw, p)
5894484Swnj 	dev_t dev;
5905408Swnj 	int rw;
59152522Smckusick 	struct proc *p;
5924484Swnj {
5934484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5944484Swnj 	int nread;
59517545Skarels 	int s = spltty();
5964484Swnj 
5975408Swnj 	switch (rw) {
5984484Swnj 
5994484Swnj 	case FREAD:
6004484Swnj 		nread = ttnread(tp);
60137584Smarc 		if (nread > 0 ||
60240712Skarels 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
6035408Swnj 			goto win;
60452522Smckusick 		selrecord(p, &tp->t_rsel);
6055408Swnj 		break;
6064484Swnj 
6075408Swnj 	case FWRITE:
60835811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
6095408Swnj 			goto win;
61052522Smckusick 		selrecord(p, &tp->t_wsel);
6115408Swnj 		break;
6124484Swnj 	}
6135408Swnj 	splx(s);
6145408Swnj 	return (0);
6155408Swnj win:
6165408Swnj 	splx(s);
6175408Swnj 	return (1);
6184484Swnj }
6197436Skre 
6207502Sroot /*
62149380Skarels  * Initial open of tty, or (re)entry to standard tty line discipline.
6227502Sroot  */
6237502Sroot ttyopen(dev, tp)
6247625Ssam 	dev_t dev;
6257625Ssam 	register struct tty *tp;
6267502Sroot {
62752485Storek 	int s = spltty();
6287502Sroot 
6297502Sroot 	tp->t_dev = dev;
63035811Smarc 
6317502Sroot 	tp->t_state &= ~TS_WOPEN;
63217545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
63317545Skarels 		tp->t_state |= TS_ISOPEN;
63417598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
63517545Skarels 	}
63652485Storek 	splx(s);
6378556Sroot 	return (0);
6387502Sroot }
6397502Sroot 
6407502Sroot /*
64125391Skarels  * "close" a line discipline
64225391Skarels  */
64349752Smarc ttylclose(tp, flag)
64449752Smarc 	struct tty *tp;
64549752Smarc 	int flag;
64625391Skarels {
64725391Skarels 
64849752Smarc 	if (flag&IO_NDELAY)
64949752Smarc 		ttyflush(tp, FREAD|FWRITE);
65049752Smarc 	else
65149752Smarc 		ttywflush(tp);
65225391Skarels }
65325391Skarels 
65425391Skarels /*
65549380Skarels  * Handle close() on a tty line: flush and set to initial state,
65649380Skarels  * bumping generation number so that pending read/write calls
65749380Skarels  * can detect recycling of the tty.
6587502Sroot  */
6597502Sroot ttyclose(tp)
6607625Ssam 	register struct tty *tp;
6617502Sroot {
66230534Skarels 	if (constty == tp)
66330534Skarels 		constty = NULL;
66425391Skarels 	ttyflush(tp, FREAD|FWRITE);
66539555Smarc 	tp->t_session = NULL;
66639555Smarc 	tp->t_pgrp = NULL;
6677502Sroot 	tp->t_state = 0;
66843377Smarc 	tp->t_gen++;
66940712Skarels 	return (0);
6707502Sroot }
6717502Sroot 
6727502Sroot /*
67325391Skarels  * Handle modem control transition on a tty.
67425391Skarels  * Flag indicates new state of carrier.
67525391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
67625391Skarels  */
67725391Skarels ttymodem(tp, flag)
67825391Skarels 	register struct tty *tp;
67952485Storek 	int flag;
68025391Skarels {
68125391Skarels 
68256012Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_cflag&MDMBUF)) {
68325391Skarels 		/*
68425391Skarels 		 * MDMBUF: do flow control according to carrier flag
68525391Skarels 		 */
68625391Skarels 		if (flag) {
68725391Skarels 			tp->t_state &= ~TS_TTSTOP;
68825391Skarels 			ttstart(tp);
68925391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
69025391Skarels 			tp->t_state |= TS_TTSTOP;
69152485Storek #ifdef sun4c						/* XXX */
69252485Storek 			(*tp->t_stop)(tp, 0);
69352485Storek #else
69425391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
69552485Storek #endif
69625391Skarels 		}
69725391Skarels 	} else if (flag == 0) {
69825391Skarels 		/*
69925391Skarels 		 * Lost carrier.
70025391Skarels 		 */
70125391Skarels 		tp->t_state &= ~TS_CARR_ON;
70242193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
70342193Smarc 			if (tp->t_session && tp->t_session->s_leader)
70442193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
70542193Smarc 			ttyflush(tp, FREAD|FWRITE);
70642193Smarc 			return (0);
70725391Skarels 		}
70825391Skarels 	} else {
70925391Skarels 		/*
71025391Skarels 		 * Carrier now on.
71125391Skarels 		 */
71225391Skarels 		tp->t_state |= TS_CARR_ON;
71337584Smarc 		ttwakeup(tp);
71425391Skarels 	}
71525391Skarels 	return (1);
71625391Skarels }
71725391Skarels 
71825391Skarels /*
71925404Skarels  * Default modem control routine (for other line disciplines).
72025404Skarels  * Return argument flag, to turn off device on carrier drop.
72125404Skarels  */
72225415Skarels nullmodem(tp, flag)
72325415Skarels 	register struct tty *tp;
72425404Skarels 	int flag;
72525404Skarels {
72625404Skarels 
72725404Skarels 	if (flag)
72825404Skarels 		tp->t_state |= TS_CARR_ON;
72939407Smarc 	else {
73025404Skarels 		tp->t_state &= ~TS_CARR_ON;
73142193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
73242193Smarc 			if (tp->t_session && tp->t_session->s_leader)
73342193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
73442193Smarc 			return (0);
73542193Smarc 		}
73639407Smarc 	}
73742193Smarc 	return (1);
73825404Skarels }
73925404Skarels 
74025404Skarels /*
7417502Sroot  * reinput pending characters after state switch
74217545Skarels  * call at spltty().
7437502Sroot  */
7447502Sroot ttypend(tp)
7457625Ssam 	register struct tty *tp;
7467502Sroot {
7477502Sroot 	struct clist tq;
7487502Sroot 	register c;
7497502Sroot 
75035811Smarc 	tp->t_lflag &= ~PENDIN;
7519578Ssam 	tp->t_state |= TS_TYPEN;
7527502Sroot 	tq = tp->t_rawq;
7537502Sroot 	tp->t_rawq.c_cc = 0;
7547502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7557502Sroot 	while ((c = getc(&tq)) >= 0)
7567502Sroot 		ttyinput(c, tp);
7579578Ssam 	tp->t_state &= ~TS_TYPEN;
7587502Sroot }
7597502Sroot 
7607502Sroot /*
76149380Skarels  * Process input of a single character received on a tty.
7627502Sroot  */
7637502Sroot ttyinput(c, tp)
7647625Ssam 	register c;
7657625Ssam 	register struct tty *tp;
7667502Sroot {
76735811Smarc 	register int iflag = tp->t_iflag;
76835811Smarc 	register int lflag = tp->t_lflag;
76935811Smarc 	register u_char *cc = tp->t_cc;
77035811Smarc 	int i, err;
7717502Sroot 
7729578Ssam 	/*
7739578Ssam 	 * If input is pending take it first.
7749578Ssam 	 */
77535811Smarc 	if (lflag&PENDIN)
7767502Sroot 		ttypend(tp);
77735811Smarc 	/*
77835811Smarc 	 * Gather stats.
77935811Smarc 	 */
7807502Sroot 	tk_nin++;
78135811Smarc 	if (lflag&ICANON) {
78235811Smarc 		tk_cancc++;
78335811Smarc 		tp->t_cancc++;
78435811Smarc 	} else {
78535811Smarc 		tk_rawcc++;
78635811Smarc 		tp->t_rawcc++;
78735811Smarc 	}
7889578Ssam 	/*
78935811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7909578Ssam 	 */
79135811Smarc 	if (err = (c&TTY_ERRORMASK)) {
79235811Smarc 		c &= ~TTY_ERRORMASK;
79335811Smarc 		if (err&TTY_FE && !c) {		/* break */
79435811Smarc 			if (iflag&IGNBRK)
79535811Smarc 				goto endcase;
79635811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
79735811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
79835811Smarc 				c = cc[VINTR];
79947545Skarels 			else if (iflag&PARMRK)
80047545Skarels 				goto parmrk;
80135811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
80235811Smarc 			if (iflag&IGNPAR)
80335811Smarc 				goto endcase;
80435811Smarc 			else if (iflag&PARMRK) {
80535811Smarc parmrk:
80635811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
80735811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
80835811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
80935811Smarc 				goto endcase;
81035811Smarc 			} else
81135811Smarc 				c = 0;
8127502Sroot 		}
8139578Ssam 	}
8149578Ssam 	/*
81535811Smarc 	 * In tandem mode, check high water mark.
8169578Ssam 	 */
81735811Smarc 	if (iflag&IXOFF)
81835811Smarc 		ttyblock(tp);
81935811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
82049380Skarels 		c &= ~0x80;
82144419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
82244419Smarc 		/*
82344419Smarc 		 * Check for literal nexting very first
82444419Smarc 		 */
82544419Smarc 		if (tp->t_state&TS_LNCH) {
82644419Smarc 			c |= TTY_QUOTE;
82744419Smarc 			tp->t_state &= ~TS_LNCH;
82844419Smarc 		}
82944419Smarc 		/*
83044419Smarc 		 * Scan for special characters.  This code
83144419Smarc 		 * is really just a big case statement with
83244419Smarc 		 * non-constant cases.  The bottom of the
83344419Smarc 		 * case statement is labeled ``endcase'', so goto
83444419Smarc 		 * it after a case match, or similar.
83544419Smarc 		 */
83644419Smarc 
83744419Smarc 		/*
83844419Smarc 		 * Control chars which aren't controlled
83944419Smarc 		 * by ICANON, ISIG, or IXON.
84044419Smarc 		 */
84144419Smarc 		if (lflag&IEXTEN) {
84244419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
84344419Smarc 				if (lflag&ECHO) {
84444419Smarc 					if (lflag&ECHOE)
84544419Smarc 						ttyoutstr("^\b", tp);
84644419Smarc 					else
84744419Smarc 						ttyecho(c, tp);
84844419Smarc 				}
84944419Smarc 				tp->t_state |= TS_LNCH;
85044419Smarc 				goto endcase;
85144419Smarc 			}
85244419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
85344419Smarc 				if (lflag&FLUSHO)
85444419Smarc 					tp->t_lflag &= ~FLUSHO;
85544419Smarc 				else {
85644419Smarc 					ttyflush(tp, FWRITE);
85735811Smarc 					ttyecho(c, tp);
85844419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
85944419Smarc 						ttyretype(tp);
86044419Smarc 					tp->t_lflag |= FLUSHO;
86144419Smarc 				}
86244419Smarc 				goto startoutput;
86335811Smarc 			}
8649578Ssam 		}
86544419Smarc 		/*
86644419Smarc 		 * Signals.
86744419Smarc 		 */
86844419Smarc 		if (lflag&ISIG) {
86944419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
87044419Smarc 				if ((lflag&NOFLSH) == 0)
87144419Smarc 					ttyflush(tp, FREAD|FWRITE);
8727502Sroot 				ttyecho(c, tp);
87344419Smarc 				pgsignal(tp->t_pgrp,
87444419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
87544419Smarc 				goto endcase;
8767502Sroot 			}
87744419Smarc 			if (CCEQ(cc[VSUSP], c)) {
87844419Smarc 				if ((lflag&NOFLSH) == 0)
87944419Smarc 					ttyflush(tp, FREAD);
88044419Smarc 				ttyecho(c, tp);
88144419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
88244419Smarc 				goto endcase;
88344419Smarc 			}
8849578Ssam 		}
88544419Smarc 		/*
88644419Smarc 		 * Handle start/stop characters.
88744419Smarc 		 */
88844419Smarc 		if (iflag&IXON) {
88944419Smarc 			if (CCEQ(cc[VSTOP], c)) {
89044419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
89144419Smarc 					tp->t_state |= TS_TTSTOP;
89252485Storek #ifdef sun4c						/* XXX */
89352485Storek 					(*tp->t_stop)(tp, 0);
89452485Storek #else
89544419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
89644419Smarc 					   0);
89752485Storek #endif
89844419Smarc 					return;
89944419Smarc 				}
90044419Smarc 				if (!CCEQ(cc[VSTART], c))
90144419Smarc 					return;
90244419Smarc 				/*
90344419Smarc 				 * if VSTART == VSTOP then toggle
90444419Smarc 				 */
90544419Smarc 				goto endcase;
90635811Smarc 			}
90744419Smarc 			if (CCEQ(cc[VSTART], c))
90844419Smarc 				goto restartoutput;
9099578Ssam 		}
91044419Smarc 		/*
91144419Smarc 		 * IGNCR, ICRNL, & INLCR
91244419Smarc 		 */
91344419Smarc 		if (c == '\r') {
91444419Smarc 			if (iflag&IGNCR)
91544419Smarc 				goto endcase;
91644419Smarc 			else if (iflag&ICRNL)
91744419Smarc 				c = '\n';
91844419Smarc 		} else if (c == '\n' && iflag&INLCR)
91944419Smarc 			c = '\r';
9209578Ssam 	}
92147545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
92244419Smarc 		/*
92344419Smarc 		 * From here on down canonical mode character
92444419Smarc 		 * processing takes place.
92544419Smarc 		 */
92644419Smarc 		/*
92744419Smarc 		 * erase (^H / ^?)
92844419Smarc 		 */
92944419Smarc 		if (CCEQ(cc[VERASE], c)) {
93044419Smarc 			if (tp->t_rawq.c_cc)
9319578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
93244419Smarc 			goto endcase;
9339578Ssam 		}
93444419Smarc 		/*
93544419Smarc 		 * kill (^U)
93644419Smarc 		 */
93744419Smarc 		if (CCEQ(cc[VKILL], c)) {
93844419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
93944419Smarc 			    (lflag&ECHOPRT) == 0) {
94044419Smarc 				while (tp->t_rawq.c_cc)
94144419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
94244419Smarc 			} else {
94344419Smarc 				ttyecho(c, tp);
94444419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
94544419Smarc 					ttyecho('\n', tp);
94652485Storek 				flushq(&tp->t_rawq);
94744419Smarc 				tp->t_rocount = 0;
94844419Smarc 			}
94944419Smarc 			tp->t_state &= ~TS_LOCAL;
95044419Smarc 			goto endcase;
95144419Smarc 		}
95244419Smarc 		/*
95344419Smarc 		 * word erase (^W)
95444419Smarc 		 */
95544419Smarc 		if (CCEQ(cc[VWERASE], c)) {
95644419Smarc 			int ctype;
95747545Skarels 			int alt = lflag&ALTWERASE;
95835811Smarc 
95944419Smarc 			/*
96044419Smarc 			 * erase whitespace
96144419Smarc 			 */
96244419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
96344419Smarc 				ttyrub(c, tp);
96444419Smarc 			if (c == -1)
96544419Smarc 				goto endcase;
96644419Smarc 			/*
96747545Skarels 			 * erase last char of word and remember the
96847545Skarels 			 * next chars type (for ALTWERASE)
96944419Smarc 			 */
97035811Smarc 			ttyrub(c, tp);
97144419Smarc 			c = unputc(&tp->t_rawq);
97247545Skarels 			if (c == -1)
97344419Smarc 				goto endcase;
97451003Sbostic 			if (c == ' ' || c == '\t') {
97551003Sbostic 				putc(c, &tp->t_rawq);
97651003Sbostic 				goto endcase;
97751003Sbostic 			}
97849380Skarels 			ctype = ISALPHA(c);
97944419Smarc 			/*
98047545Skarels 			 * erase rest of word
98144419Smarc 			 */
98244419Smarc 			do {
98344419Smarc 				ttyrub(c, tp);
98444419Smarc 				c = unputc(&tp->t_rawq);
98544419Smarc 				if (c == -1)
98644419Smarc 					goto endcase;
98747545Skarels 			} while (c != ' ' && c != '\t' &&
98849380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
98944419Smarc 			(void) putc(c, &tp->t_rawq);
99034492Skarels 			goto endcase;
99144419Smarc 		}
99235811Smarc 		/*
99344419Smarc 		 * reprint line (^R)
99435811Smarc 		 */
99544419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
99644419Smarc 			ttyretype(tp);
99734492Skarels 			goto endcase;
99834492Skarels 		}
99935811Smarc 		/*
100044419Smarc 		 * ^T - kernel info and generate SIGINFO
100135811Smarc 		 */
100244419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
100351068Smarc 			if (lflag&ISIG)
100451068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
100544419Smarc 			if ((lflag&NOKERNINFO) == 0)
100644419Smarc 				ttyinfo(tp);
100744419Smarc 			goto endcase;
100844419Smarc 		}
10099578Ssam 	}
10109578Ssam 	/*
10119578Ssam 	 * Check for input buffer overflow
10129578Ssam 	 */
101347545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
101435811Smarc 		if (iflag&IMAXBEL) {
101535811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
101635811Smarc 				(void) ttyoutput(CTRL('g'), tp);
101735811Smarc 		} else
101835811Smarc 			ttyflush(tp, FREAD | FWRITE);
10199578Ssam 		goto endcase;
102010391Ssam 	}
10219578Ssam 	/*
10229578Ssam 	 * Put data char in q for user and
10239578Ssam 	 * wakeup on seeing a line delimiter.
10249578Ssam 	 */
10259578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
102647545Skarels 		if ((lflag&ICANON) == 0) {
102747545Skarels 			ttwakeup(tp);
102847545Skarels 			ttyecho(c, tp);
102947545Skarels 			goto endcase;
103047545Skarels 		}
103135811Smarc 		if (ttbreakc(c)) {
10329578Ssam 			tp->t_rocount = 0;
10339578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
10347502Sroot 			ttwakeup(tp);
10359578Ssam 		} else if (tp->t_rocount++ == 0)
10369578Ssam 			tp->t_rocol = tp->t_col;
10379578Ssam 		if (tp->t_state&TS_ERASE) {
103835811Smarc 			/*
103935811Smarc 			 * end of prterase \.../
104035811Smarc 			 */
10419578Ssam 			tp->t_state &= ~TS_ERASE;
10429578Ssam 			(void) ttyoutput('/', tp);
10439578Ssam 		}
10449578Ssam 		i = tp->t_col;
10457502Sroot 		ttyecho(c, tp);
104635811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
104735811Smarc 			/*
104835811Smarc 			 * Place the cursor over the '^' of the ^D.
104935811Smarc 			 */
105055058Spendry 			i = min(2, tp->t_col - i);
10519578Ssam 			while (i > 0) {
10529578Ssam 				(void) ttyoutput('\b', tp);
10539578Ssam 				i--;
10549578Ssam 			}
10559578Ssam 		}
10567502Sroot 	}
10579578Ssam endcase:
10589578Ssam 	/*
105935811Smarc 	 * IXANY means allow any character to restart output.
10609578Ssam 	 */
106140712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
106240712Skarels 	    cc[VSTART] != cc[VSTOP])
10637502Sroot 		return;
10649578Ssam restartoutput:
10657502Sroot 	tp->t_state &= ~TS_TTSTOP;
106635811Smarc 	tp->t_lflag &= ~FLUSHO;
10679578Ssam startoutput:
10687502Sroot 	ttstart(tp);
10697502Sroot }
10707502Sroot 
10717502Sroot /*
107249380Skarels  * Output a single character on a tty, doing output processing
107349380Skarels  * as needed (expanding tabs, newline processing, etc.).
107449380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10757502Sroot  * Must be recursive.
10767502Sroot  */
10777502Sroot ttyoutput(c, tp)
10787502Sroot 	register c;
10797502Sroot 	register struct tty *tp;
10807502Sroot {
108149380Skarels 	register int col;
108235811Smarc 	register long oflag = tp->t_oflag;
108335811Smarc 
108440712Skarels 	if ((oflag&OPOST) == 0) {
108535811Smarc 		if (tp->t_lflag&FLUSHO)
10867502Sroot 			return (-1);
10877502Sroot 		if (putc(c, &tp->t_outq))
10887625Ssam 			return (c);
10897502Sroot 		tk_nout++;
109035811Smarc 		tp->t_outcc++;
10917502Sroot 		return (-1);
10927502Sroot 	}
109335811Smarc 	c &= TTY_CHARMASK;
10947502Sroot 	/*
109549380Skarels 	 * Do tab expansion if OXTABS is set.
109642882Smarc 	 * Special case if we have external processing, we don't
109742882Smarc 	 * do the tab expansion because we'll probably get it
109842882Smarc 	 * wrong.  If tab expansion needs to be done, let it
109942882Smarc 	 * happen externally.
11007502Sroot 	 */
110147545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
11027502Sroot 		register int s;
11037502Sroot 
11047502Sroot 		c = 8 - (tp->t_col&7);
110535811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
110617545Skarels 			s = spltty();		/* don't interrupt tabs */
11077502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
11087502Sroot 			tk_nout += c;
110935811Smarc 			tp->t_outcc += c;
11107502Sroot 			splx(s);
11117502Sroot 		}
11127502Sroot 		tp->t_col += c;
11137502Sroot 		return (c ? -1 : '\t');
11147502Sroot 	}
111535811Smarc 	if (c == CEOT && oflag&ONOEOT)
111647545Skarels 		return (-1);
11177502Sroot 	tk_nout++;
111835811Smarc 	tp->t_outcc++;
11197502Sroot 	/*
112049380Skarels 	 * Newline translation: if ONLCR is set,
112149380Skarels 	 * translate newline into "\r\n".
11227502Sroot 	 */
112335811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
11247502Sroot 		return (c);
112535811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
112635811Smarc 		return (c);
112747545Skarels 
112849380Skarels 	col = tp->t_col;
112949380Skarels 	switch (CCLASS(c)) {
11307502Sroot 
11317502Sroot 	case ORDINARY:
113249380Skarels 		col++;
11337502Sroot 
11347502Sroot 	case CONTROL:
11357502Sroot 		break;
11367502Sroot 
11377502Sroot 	case BACKSPACE:
113849380Skarels 		if (col > 0)
113949380Skarels 			col--;
11407502Sroot 		break;
11417502Sroot 
11427502Sroot 	case NEWLINE:
114349380Skarels 		col = 0;
11447502Sroot 		break;
11457502Sroot 
11467502Sroot 	case TAB:
114749380Skarels 		col = (col + 8) &~ 0x7;
11487502Sroot 		break;
11497502Sroot 
11507502Sroot 	case RETURN:
115149380Skarels 		col = 0;
11527502Sroot 	}
115349380Skarels 	tp->t_col = col;
11547502Sroot 	return (-1);
11557502Sroot }
11567502Sroot 
11577502Sroot /*
115849380Skarels  * Process a read call on a tty device.
11597502Sroot  */
116037584Smarc ttread(tp, uio, flag)
11617625Ssam 	register struct tty *tp;
11627722Swnj 	struct uio *uio;
116352485Storek 	int flag;
11647502Sroot {
11657502Sroot 	register struct clist *qp;
116635811Smarc 	register int c;
116741383Smarc 	register long lflag;
116835811Smarc 	register u_char *cc = tp->t_cc;
116947545Skarels 	register struct proc *p = curproc;
11709859Ssam 	int s, first, error = 0;
11717502Sroot 
11727502Sroot loop:
117341383Smarc 	lflag = tp->t_lflag;
117437584Smarc 	s = spltty();
11759578Ssam 	/*
117637584Smarc 	 * take pending input first
11779578Ssam 	 */
117835811Smarc 	if (lflag&PENDIN)
11797502Sroot 		ttypend(tp);
11809859Ssam 	splx(s);
118140712Skarels 
11829578Ssam 	/*
11839578Ssam 	 * Hang process if it's in the background.
11849578Ssam 	 */
118547545Skarels 	if (isbackground(p, tp)) {
118647545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
118747545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
118847545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11898520Sroot 			return (EIO);
119047545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119143377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
119243377Smarc 		    ttybg, 0))
119340712Skarels 			return (error);
119423165Sbloom 		goto loop;
11957502Sroot 	}
119640712Skarels 
11979578Ssam 	/*
119835811Smarc 	 * If canonical, use the canonical queue,
119935811Smarc 	 * else use the raw queue.
120037584Smarc 	 *
120147545Skarels 	 * (should get rid of clists...)
12029578Ssam 	 */
120335811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
120440712Skarels 
12059578Ssam 	/*
120640712Skarels 	 * If there is no input, sleep on rawq
120740712Skarels 	 * awaiting hardware receipt and notification.
120840712Skarels 	 * If we have data, we don't need to check for carrier.
12099578Ssam 	 */
121017545Skarels 	s = spltty();
12119578Ssam 	if (qp->c_cc <= 0) {
121240712Skarels 		int carrier;
121340712Skarels 
121440712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
121540712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
12169859Ssam 			splx(s);
121740712Skarels 			return (0);	/* EOF */
12187502Sroot 		}
121937728Smckusick 		if (flag & IO_NDELAY) {
122037584Smarc 			splx(s);
122137584Smarc 			return (EWOULDBLOCK);
122237584Smarc 		}
122343377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
122440712Skarels 		    carrier ? ttyin : ttopen, 0);
12259859Ssam 		splx(s);
122643377Smarc 		if (error)
122740712Skarels 			return (error);
12289578Ssam 		goto loop;
12299578Ssam 	}
12309859Ssam 	splx(s);
123140712Skarels 
12329578Ssam 	/*
123335811Smarc 	 * Input present, check for input mapping and processing.
12349578Ssam 	 */
12359578Ssam 	first = 1;
12369578Ssam 	while ((c = getc(qp)) >= 0) {
12379578Ssam 		/*
123835811Smarc 		 * delayed suspend (^Y)
12399578Ssam 		 */
124035811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
124142882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12429578Ssam 			if (first) {
124343377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
124443377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
124540712Skarels 					break;
12469578Ssam 				goto loop;
12479578Ssam 			}
12489578Ssam 			break;
12497502Sroot 		}
12509578Ssam 		/*
125135811Smarc 		 * Interpret EOF only in canonical mode.
12529578Ssam 		 */
125335811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12549578Ssam 			break;
12559578Ssam 		/*
12569578Ssam 		 * Give user character.
12579578Ssam 		 */
125840712Skarels  		error = ureadc(c, uio);
12599578Ssam 		if (error)
12609578Ssam 			break;
126114938Smckusick  		if (uio->uio_resid == 0)
12629578Ssam 			break;
12639578Ssam 		/*
126435811Smarc 		 * In canonical mode check for a "break character"
12659578Ssam 		 * marking the end of a "line of input".
12669578Ssam 		 */
126740712Skarels 		if (lflag&ICANON && ttbreakc(c))
12689578Ssam 			break;
12699578Ssam 		first = 0;
12707502Sroot 	}
12719578Ssam 	/*
12729578Ssam 	 * Look to unblock output now that (presumably)
12739578Ssam 	 * the input queue has gone down.
12749578Ssam 	 */
127552485Storek 	s = spltty();
127635811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
127747545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
127847545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12797502Sroot 			tp->t_state &= ~TS_TBLOCK;
12807502Sroot 			ttstart(tp);
12817502Sroot 		}
128235811Smarc 	}
128352485Storek 	splx(s);
12848520Sroot 	return (error);
12857502Sroot }
12867502Sroot 
12877502Sroot /*
128825391Skarels  * Check the output queue on tp for space for a kernel message
128925391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
129025391Skarels  * hiwater mark so we don't lose messages due to normal flow
129125391Skarels  * control, but don't let the tty run amok.
129230695Skarels  * Sleeps here are not interruptible, but we return prematurely
129330695Skarels  * if new signals come in.
129425391Skarels  */
129525391Skarels ttycheckoutq(tp, wait)
129625391Skarels 	register struct tty *tp;
129725391Skarels 	int wait;
129825391Skarels {
129930695Skarels 	int hiwat, s, oldsig;
130025391Skarels 
130135811Smarc 	hiwat = tp->t_hiwat;
130225391Skarels 	s = spltty();
130352485Storek 	oldsig = wait ? curproc->p_sig : 0;
130425391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
130529946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130629946Skarels 			ttstart(tp);
130747545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
130829946Skarels 				splx(s);
130929946Skarels 				return (0);
131029946Skarels 			}
131154782Storek 			timeout((void (*)__P((void *)))wakeup,
131254782Storek 			    (void *)&tp->t_outq, hz);
131329946Skarels 			tp->t_state |= TS_ASLEEP;
131430695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
131525391Skarels 		}
131625391Skarels 	splx(s);
131725391Skarels 	return (1);
131825391Skarels }
131925391Skarels 
132025391Skarels /*
132149380Skarels  * Process a write call on a tty device.
13227502Sroot  */
132337584Smarc ttwrite(tp, uio, flag)
13247625Ssam 	register struct tty *tp;
13259578Ssam 	register struct uio *uio;
132652485Storek 	int flag;
13277502Sroot {
13287502Sroot 	register char *cp;
132940712Skarels 	register int cc = 0, ce;
133047545Skarels 	register struct proc *p = curproc;
13319578Ssam 	int i, hiwat, cnt, error, s;
13327502Sroot 	char obuf[OBUFSIZ];
13337502Sroot 
133435811Smarc 	hiwat = tp->t_hiwat;
13359578Ssam 	cnt = uio->uio_resid;
13369578Ssam 	error = 0;
13377502Sroot loop:
133837584Smarc 	s = spltty();
133940712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
134037584Smarc 		if (tp->t_state&TS_ISOPEN) {
134137584Smarc 			splx(s);
134237584Smarc 			return (EIO);
134337728Smckusick 		} else if (flag & IO_NDELAY) {
134437584Smarc 			splx(s);
134540712Skarels 			error = EWOULDBLOCK;
134640712Skarels 			goto out;
134737584Smarc 		} else {
134837584Smarc 			/*
134937584Smarc 			 * sleep awaiting carrier
135037584Smarc 			 */
135143377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
135243377Smarc 					TTIPRI | PCATCH,ttopen, 0);
135337584Smarc 			splx(s);
135443377Smarc 			if (error)
135540712Skarels 				goto out;
135637584Smarc 			goto loop;
135737584Smarc 		}
135837584Smarc 	}
135937584Smarc 	splx(s);
13609578Ssam 	/*
13619578Ssam 	 * Hang the process if it's in the background.
13629578Ssam 	 */
136347545Skarels 	if (isbackground(p, tp) &&
136447545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
136547545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
136647545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
136747545Skarels 	     p->p_pgrp->pg_jobc) {
136847545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
136943377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
137043377Smarc 		    ttybg, 0))
137140712Skarels 			goto out;
137221776Sbloom 		goto loop;
13737502Sroot 	}
13749578Ssam 	/*
13759578Ssam 	 * Process the user's data in at most OBUFSIZ
137640712Skarels 	 * chunks.  Perform any output translation.
137740712Skarels 	 * Keep track of high water mark, sleep on overflow
137840712Skarels 	 * awaiting device aid in acquiring new space.
13799578Ssam 	 */
138040712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
138140712Skarels 		if (tp->t_lflag&FLUSHO) {
138240712Skarels 			uio->uio_resid = 0;
138340712Skarels 			return (0);
138440712Skarels 		}
138540712Skarels 		if (tp->t_outq.c_cc > hiwat)
138632067Skarels 			goto ovhiwat;
13879578Ssam 		/*
138840712Skarels 		 * Grab a hunk of data from the user,
138940712Skarels 		 * unless we have some leftover from last time.
13909578Ssam 		 */
13917822Sroot 		if (cc == 0) {
139240712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139340712Skarels 			cp = obuf;
139440712Skarels 			error = uiomove(cp, cc, uio);
139540712Skarels 			if (error) {
139640712Skarels 				cc = 0;
139740712Skarels 				break;
139840712Skarels 			}
13997822Sroot 		}
14009578Ssam 		/*
14019578Ssam 		 * If nothing fancy need be done, grab those characters we
14029578Ssam 		 * can handle without any of ttyoutput's processing and
14039578Ssam 		 * just transfer them to the output q.  For those chars
14049578Ssam 		 * which require special processing (as indicated by the
14059578Ssam 		 * bits in partab), call ttyoutput.  After processing
14069578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14079578Ssam 		 * immediately.
14089578Ssam 		 */
14099578Ssam 		while (cc > 0) {
141040712Skarels 			if ((tp->t_oflag&OPOST) == 0)
14117502Sroot 				ce = cc;
14127502Sroot 			else {
141334492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
141449380Skarels 				   (u_char *)partab, CCLASSMASK);
14159578Ssam 				/*
14169578Ssam 				 * If ce is zero, then we're processing
14179578Ssam 				 * a special character through ttyoutput.
14189578Ssam 				 */
14199578Ssam 				if (ce == 0) {
14207502Sroot 					tp->t_rocount = 0;
14217502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142221776Sbloom 					    /* no c-lists, wait a bit */
142321776Sbloom 					    ttstart(tp);
142443377Smarc 					    if (error = ttysleep(tp,
142543377Smarc 						(caddr_t)&lbolt,
142643377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
142740712Skarels 						    break;
142821776Sbloom 					    goto loop;
14297502Sroot 					}
14309578Ssam 					cp++, cc--;
143135811Smarc 					if ((tp->t_lflag&FLUSHO) ||
14329578Ssam 					    tp->t_outq.c_cc > hiwat)
14337502Sroot 						goto ovhiwat;
14349578Ssam 					continue;
14357502Sroot 				}
14367502Sroot 			}
14379578Ssam 			/*
14389578Ssam 			 * A bunch of normal characters have been found,
14399578Ssam 			 * transfer them en masse to the output queue and
14409578Ssam 			 * continue processing at the top of the loop.
14419578Ssam 			 * If there are any further characters in this
14429578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14439578Ssam 			 * requiring special handling by ttyoutput.
14449578Ssam 			 */
14457502Sroot 			tp->t_rocount = 0;
14469578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14479578Ssam 			ce -= i;
14489578Ssam 			tp->t_col += ce;
14499578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
145035811Smarc 			tp->t_outcc += ce;
14519578Ssam 			if (i > 0) {
14529578Ssam 				/* out of c-lists, wait a bit */
14537502Sroot 				ttstart(tp);
145443377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
145543377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
145640712Skarels 					break;
145721776Sbloom 				goto loop;
14587502Sroot 			}
145935811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
146040712Skarels 				break;
14617502Sroot 		}
146235811Smarc 		ttstart(tp);
14637502Sroot 	}
146440712Skarels out:
146540712Skarels 	/*
146640712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
146740712Skarels 	 * as the offset and iov pointers have moved forward,
146840712Skarels 	 * but it doesn't matter (the call will either return short
146940712Skarels 	 * or restart with a new uio).
147040712Skarels 	 */
147140712Skarels 	uio->uio_resid += cc;
14728520Sroot 	return (error);
147340712Skarels 
14747502Sroot ovhiwat:
147532067Skarels 	ttstart(tp);
147632067Skarels 	s = spltty();
14779578Ssam 	/*
147835811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
147932067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14809578Ssam 	 */
14817502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14829578Ssam 		splx(s);
14837502Sroot 		goto loop;
14847502Sroot 	}
148537728Smckusick 	if (flag & IO_NDELAY) {
148617545Skarels 		splx(s);
148740712Skarels 		uio->uio_resid += cc;
14887822Sroot 		if (uio->uio_resid == cnt)
14898520Sroot 			return (EWOULDBLOCK);
14908520Sroot 		return (0);
14917502Sroot 	}
14927502Sroot 	tp->t_state |= TS_ASLEEP;
149343377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14949578Ssam 	splx(s);
149543377Smarc 	if (error)
149640712Skarels 		goto out;
14977502Sroot 	goto loop;
14987502Sroot }
14997502Sroot 
15007502Sroot /*
15017502Sroot  * Rubout one character from the rawq of tp
15027502Sroot  * as cleanly as possible.
15037502Sroot  */
15047502Sroot ttyrub(c, tp)
15057625Ssam 	register c;
15067625Ssam 	register struct tty *tp;
15077502Sroot {
15087502Sroot 	register char *cp;
15097502Sroot 	register int savecol;
15107502Sroot 	int s;
15117502Sroot 	char *nextc();
15127502Sroot 
151342882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
15147502Sroot 		return;
151535811Smarc 	tp->t_lflag &= ~FLUSHO;
151635811Smarc 	if (tp->t_lflag&ECHOE) {
15177502Sroot 		if (tp->t_rocount == 0) {
15187502Sroot 			/*
15197502Sroot 			 * Screwed by ttwrite; retype
15207502Sroot 			 */
15217502Sroot 			ttyretype(tp);
15227502Sroot 			return;
15237502Sroot 		}
152435811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
15257502Sroot 			ttyrubo(tp, 2);
152649380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
15277502Sroot 
15287502Sroot 		case ORDINARY:
152935811Smarc 			ttyrubo(tp, 1);
15307502Sroot 			break;
15317502Sroot 
15327502Sroot 		case VTAB:
15337502Sroot 		case BACKSPACE:
15347502Sroot 		case CONTROL:
15357502Sroot 		case RETURN:
153647545Skarels 		case NEWLINE:
153735811Smarc 			if (tp->t_lflag&ECHOCTL)
15387502Sroot 				ttyrubo(tp, 2);
15397502Sroot 			break;
15407502Sroot 
154135811Smarc 		case TAB: {
154235811Smarc 			int c;
154335811Smarc 
15447502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15457502Sroot 				ttyretype(tp);
15467502Sroot 				return;
15477502Sroot 			}
154817545Skarels 			s = spltty();
15497502Sroot 			savecol = tp->t_col;
15509578Ssam 			tp->t_state |= TS_CNTTB;
155135811Smarc 			tp->t_lflag |= FLUSHO;
15527502Sroot 			tp->t_col = tp->t_rocol;
15539578Ssam 			cp = tp->t_rawq.c_cf;
155439407Smarc 			if (cp)
155539407Smarc 				c = *cp;	/* XXX FIX NEXTC */
155635811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
155735811Smarc 				ttyecho(c, tp);
155835811Smarc 			tp->t_lflag &= ~FLUSHO;
15599578Ssam 			tp->t_state &= ~TS_CNTTB;
15607502Sroot 			splx(s);
15617502Sroot 			/*
15627502Sroot 			 * savecol will now be length of the tab
15637502Sroot 			 */
15647502Sroot 			savecol -= tp->t_col;
15657502Sroot 			tp->t_col += savecol;
15667502Sroot 			if (savecol > 8)
15677502Sroot 				savecol = 8;		/* overflow screw */
15687502Sroot 			while (--savecol >= 0)
15697502Sroot 				(void) ttyoutput('\b', tp);
15707502Sroot 			break;
157135811Smarc 		}
15727502Sroot 
15737502Sroot 		default:
157437584Smarc 			/* XXX */
157535811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
157649380Skarels 				c, CCLASS(c));
157735811Smarc 			/*panic("ttyrub");*/
15787502Sroot 		}
157935811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15809578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15817502Sroot 			(void) ttyoutput('\\', tp);
15829578Ssam 			tp->t_state |= TS_ERASE;
15837502Sroot 		}
15847502Sroot 		ttyecho(c, tp);
15857502Sroot 	} else
158635811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15877502Sroot 	tp->t_rocount--;
15887502Sroot }
15897502Sroot 
15907502Sroot /*
15917502Sroot  * Crt back over cnt chars perhaps
15927502Sroot  * erasing them.
15937502Sroot  */
15947502Sroot ttyrubo(tp, cnt)
15957625Ssam 	register struct tty *tp;
15967625Ssam 	int cnt;
15977502Sroot {
15987502Sroot 
15997502Sroot 	while (--cnt >= 0)
160040712Skarels 		ttyoutstr("\b \b", tp);
16017502Sroot }
16027502Sroot 
16037502Sroot /*
16047502Sroot  * Reprint the rawq line.
16057502Sroot  * We assume c_cc has already been checked.
16067502Sroot  */
16077502Sroot ttyretype(tp)
16087625Ssam 	register struct tty *tp;
16097502Sroot {
16107502Sroot 	register char *cp;
16117502Sroot 	char *nextc();
161235811Smarc 	int s, c;
16137502Sroot 
161435811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
161535811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
16167502Sroot 	(void) ttyoutput('\n', tp);
161717545Skarels 	s = spltty();
161835811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
161935811Smarc 	  BIT OF FIRST CHAR ****/
162035811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
162135811Smarc 		ttyecho(c, tp);
162235811Smarc 	}
162335811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
162435811Smarc 		ttyecho(c, tp);
162535811Smarc 	}
16269578Ssam 	tp->t_state &= ~TS_ERASE;
16277502Sroot 	splx(s);
16287502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16297502Sroot 	tp->t_rocol = 0;
16307502Sroot }
16317502Sroot 
16327502Sroot /*
163335811Smarc  * Echo a typed character to the terminal.
16347502Sroot  */
16357502Sroot ttyecho(c, tp)
16367625Ssam 	register c;
16377625Ssam 	register struct tty *tp;
16387502Sroot {
16399578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
164035811Smarc 		tp->t_lflag &= ~FLUSHO;
164147545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
164247545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16437502Sroot 		return;
164435811Smarc 	if (tp->t_lflag&ECHOCTL) {
164540712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
164656013Smarc 		    (c&TTY_CHARMASK) == 0177) {
16477502Sroot 			(void) ttyoutput('^', tp);
164835811Smarc 			c &= TTY_CHARMASK;
16497502Sroot 			if (c == 0177)
16507502Sroot 				c = '?';
16517502Sroot 			else
16527502Sroot 				c += 'A' - 1;
16537502Sroot 		}
16547502Sroot 	}
165535811Smarc 	(void) ttyoutput(c, tp);
16567502Sroot }
16577502Sroot 
16587502Sroot /*
16597502Sroot  * send string cp to tp
16607502Sroot  */
166140712Skarels ttyoutstr(cp, tp)
16627625Ssam 	register char *cp;
16637625Ssam 	register struct tty *tp;
16647502Sroot {
16657502Sroot 	register char c;
16667502Sroot 
16677502Sroot 	while (c = *cp++)
16687502Sroot 		(void) ttyoutput(c, tp);
16697502Sroot }
16707502Sroot 
167149380Skarels /*
167249380Skarels  * Wake up any readers on a tty.
167349380Skarels  */
16747502Sroot ttwakeup(tp)
167547545Skarels 	register struct tty *tp;
16767502Sroot {
16777502Sroot 
167852522Smckusick 	selwakeup(&tp->t_rsel);
167912752Ssam 	if (tp->t_state & TS_ASYNC)
168042882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16817502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16827502Sroot }
168335811Smarc 
168435811Smarc /*
168548439Skarels  * Look up a code for a specified speed in a conversion table;
168648439Skarels  * used by drivers to map software speed values to hardware parameters.
168748439Skarels  */
168848439Skarels ttspeedtab(speed, table)
168952485Storek 	int speed;
169048439Skarels 	register struct speedtab *table;
169148439Skarels {
169248439Skarels 
169348439Skarels 	for ( ; table->sp_speed != -1; table++)
169448439Skarels 		if (table->sp_speed == speed)
169548439Skarels 			return (table->sp_code);
169648439Skarels 	return (-1);
169748439Skarels }
169848439Skarels 
169948439Skarels /*
170035811Smarc  * set tty hi and low water marks
170135811Smarc  *
170235811Smarc  * Try to arrange the dynamics so there's about one second
170335811Smarc  * from hi to low water.
170435811Smarc  *
170535811Smarc  */
170635811Smarc ttsetwater(tp)
170735811Smarc 	struct tty *tp;
170835811Smarc {
170935811Smarc 	register cps = tp->t_ospeed / 10;
171035811Smarc 	register x;
171135811Smarc 
171235811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
171335811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
171435811Smarc 	x += cps;
171535811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
171635811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
171735811Smarc #undef clamp
171835811Smarc }
171935811Smarc 
172039407Smarc /*
172139407Smarc  * Report on state of foreground process group.
172239407Smarc  */
172339407Smarc ttyinfo(tp)
172449907Sbostic 	register struct tty *tp;
172539407Smarc {
172649907Sbostic 	register struct proc *p, *pick;
172741177Smarc 	struct timeval utime, stime;
172849907Sbostic 	int tmp;
172939407Smarc 
173039407Smarc 	if (ttycheckoutq(tp,0) == 0)
173139407Smarc 		return;
173249907Sbostic 
173349907Sbostic 	/* Print load average. */
173452666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
173549907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
173649907Sbostic 
173739555Smarc 	if (tp->t_session == NULL)
173849907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
173941177Smarc 	else if (tp->t_pgrp == NULL)
174049907Sbostic 		ttyprintf(tp, "no foreground process group\n");
174141177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
174249907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174339407Smarc 	else {
174449907Sbostic 		/* Pick interesting process. */
174549907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
174641177Smarc 			if (proc_compare(pick, p))
174741177Smarc 				pick = p;
174849907Sbostic 
174949907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
175049907Sbostic 		    pick->p_stat == SRUN ? "running" :
175149907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
175249907Sbostic 
175354782Storek 		calcru(pick, &utime, &stime, NULL);
175439407Smarc 
175549907Sbostic 		/* Print user time. */
175649907Sbostic 		ttyprintf(tp, "%d.%02du ",
175749907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
175841177Smarc 
175949907Sbostic 		/* Print system time. */
176049907Sbostic 		ttyprintf(tp, "%d.%02ds ",
176149907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176249907Sbostic 
176349907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
176449907Sbostic 		/* Print percentage cpu, resident set size. */
176549907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
176649907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
176752485Storek 		    tmp / 100,
176852485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
176952485Storek 			pgtok(pick->p_vmspace->vm_rssize));
177041177Smarc 	}
177149907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
177241177Smarc }
177341177Smarc 
177441177Smarc /*
177541177Smarc  * Returns 1 if p2 is "better" than p1
177641177Smarc  *
177741177Smarc  * The algorithm for picking the "interesting" process is thus:
177841177Smarc  *
177941177Smarc  *	1) (Only foreground processes are eligable - implied)
178041177Smarc  *	2) Runnable processes are favored over anything
178141177Smarc  *	   else.  The runner with the highest cpu
178241177Smarc  *	   utilization is picked (p_cpu).  Ties are
178341177Smarc  *	   broken by picking the highest pid.
178441177Smarc  *	3  Next, the sleeper with the shortest sleep
178541177Smarc  *	   time is favored.  With ties, we pick out
178641177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
178741177Smarc  *	   Further ties are broken by picking the highest
178841177Smarc  *	   pid.
178941177Smarc  *
179041177Smarc  */
179141177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179245723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179345723Smckusick #define ONLYA   2
179445723Smckusick #define ONLYB   1
179545723Smckusick #define BOTH    3
179645723Smckusick 
179749907Sbostic static int
179841177Smarc proc_compare(p1, p2)
179941177Smarc 	register struct proc *p1, *p2;
180041177Smarc {
180141177Smarc 
180241177Smarc 	if (p1 == NULL)
180341177Smarc 		return (1);
180441177Smarc 	/*
180541177Smarc 	 * see if at least one of them is runnable
180641177Smarc 	 */
180745723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
180845723Smckusick 	case ONLYA:
180945723Smckusick 		return (0);
181045723Smckusick 	case ONLYB:
181141177Smarc 		return (1);
181245723Smckusick 	case BOTH:
181341177Smarc 		/*
181441177Smarc 		 * tie - favor one with highest recent cpu utilization
181541177Smarc 		 */
181641177Smarc 		if (p2->p_cpu > p1->p_cpu)
181741177Smarc 			return (1);
181841177Smarc 		if (p1->p_cpu > p2->p_cpu)
181941177Smarc 			return (0);
182041177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182141177Smarc 	}
182245723Smckusick 	/*
182345723Smckusick  	 * weed out zombies
182445723Smckusick 	 */
182545723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
182645723Smckusick 	case ONLYA:
182745723Smckusick 		return (1);
182845723Smckusick 	case ONLYB:
182945723Smckusick 		return (0);
183045723Smckusick 	case BOTH:
183145723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183245723Smckusick 	}
183341177Smarc 	/*
183441177Smarc 	 * pick the one with the smallest sleep time
183541177Smarc 	 */
183641177Smarc 	if (p2->p_slptime > p1->p_slptime)
183741177Smarc 		return (0);
183841177Smarc 	if (p1->p_slptime > p2->p_slptime)
183941177Smarc 		return (1);
184041177Smarc 	/*
184141177Smarc 	 * favor one sleeping in a non-interruptible sleep
184241177Smarc 	 */
184341177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
184441177Smarc 		return (1);
184541177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
184641177Smarc 		return (0);
184747545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
184841177Smarc }
184945723Smckusick 
185039555Smarc /*
185139555Smarc  * Output char to tty; console putchar style.
185239555Smarc  */
185339555Smarc tputchar(c, tp)
185439555Smarc 	int c;
185539555Smarc 	struct tty *tp;
185639555Smarc {
185739555Smarc 	register s = spltty();
185839555Smarc 
185947545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
186039555Smarc 		if (c == '\n')
186139555Smarc 			(void) ttyoutput('\r', tp);
186239555Smarc 		(void) ttyoutput(c, tp);
186339555Smarc 		ttstart(tp);
186439555Smarc 		splx(s);
186539555Smarc 		return (0);
186639555Smarc 	}
186739555Smarc 	splx(s);
186839555Smarc 	return (-1);
186939555Smarc }
187043377Smarc 
187144419Smarc /*
187249380Skarels  * Sleep on chan, returning ERESTART if tty changed
187349380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
187449380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
187549380Skarels  * call will redo validation done at the start of the call.
187644419Smarc  */
187743377Smarc ttysleep(tp, chan, pri, wmesg, timo)
187843377Smarc 	struct tty *tp;
187943377Smarc 	caddr_t chan;
188043377Smarc 	int pri;
188143377Smarc 	char *wmesg;
188243377Smarc 	int timo;
188343377Smarc {
188443377Smarc 	int error;
188543377Smarc 	short gen = tp->t_gen;
188643377Smarc 
188743377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
188843377Smarc 		return (error);
188943377Smarc 	if (tp->t_gen != gen)
189043377Smarc 		return (ERESTART);
189143377Smarc 	return (0);
189243377Smarc }
1893