xref: /csrg-svn/sys/kern/tty.c (revision 52666)
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*52666Smckusick  *	@(#)tty.c	7.50 (Berkeley) 02/25/92
923387Smckusick  */
1039Sbill 
1117095Sbloom #include "param.h"
1217095Sbloom #include "systm.h"
1317095Sbloom #include "ioctl.h"
1452522Smckusick #include "proc.h"
1539407Smarc #define TTYDEFCHARS
1617095Sbloom #include "tty.h"
1735811Smarc #undef TTYDEFCHARS
1817095Sbloom #include "file.h"
1917095Sbloom #include "conf.h"
2029946Skarels #include "dkstat.h"
2117095Sbloom #include "uio.h"
2217095Sbloom #include "kernel.h"
2337728Smckusick #include "vnode.h"
2435811Smarc #include "syslog.h"
2539Sbill 
2648439Skarels #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 
23547545Skarels ttrstrt(tp)				/* XXX */
23647545Skarels 	struct tty *tp;
23747545Skarels {
23852485Storek 	int s;
23947545Skarels 
24040712Skarels #ifdef DIAGNOSTIC
2419578Ssam 	if (tp == 0)
2429578Ssam 		panic("ttrstrt");
24340712Skarels #endif
24452485Storek 	s = spltty();
2455408Swnj 	tp->t_state &= ~TS_TIMEOUT;
246903Sbill 	ttstart(tp);
24752485Storek 	splx(s);
248121Sbill }
249121Sbill 
25039Sbill 
25139Sbill /*
25249380Skarels  * Common code for ioctls on tty devices.
25349380Skarels  * Called after line-discipline-specific ioctl
25449380Skarels  * has been called to do discipline-specific functions
25549380Skarels  * and/or reject any of these ioctl commands.
25639Sbill  */
2571780Sbill /*ARGSUSED*/
2587625Ssam ttioctl(tp, com, data, flag)
2597625Ssam 	register struct tty *tp;
26052485Storek 	int com;
2617625Ssam 	caddr_t data;
26252485Storek 	int flag;
26339Sbill {
26447545Skarels 	register struct proc *p = curproc;		/* XXX */
26539Sbill 	extern int nldisp;
26637554Smckusick 	int s, error;
26739Sbill 
268903Sbill 	/*
269903Sbill 	 * If the ioctl involves modification,
27017545Skarels 	 * hang if in the background.
271903Sbill 	 */
2727625Ssam 	switch (com) {
27339Sbill 
27435811Smarc 	case TIOCSETD:
275903Sbill 	case TIOCFLUSH:
27635811Smarc 	/*case TIOCSPGRP:*/
2779325Ssam 	case TIOCSTI:
27817598Sbloom 	case TIOCSWINSZ:
27935811Smarc 	case TIOCSETA:
28035811Smarc 	case TIOCSETAW:
28135811Smarc 	case TIOCSETAF:
28252485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
28340030Smarc 	case TIOCSETP:
28440030Smarc 	case TIOCSETN:
28540030Smarc 	case TIOCSETC:
28640030Smarc 	case TIOCSLTC:
28740030Smarc 	case TIOCLBIS:
28840030Smarc 	case TIOCLBIC:
28940030Smarc 	case TIOCLSET:
29040030Smarc 	case OTIOCSETD:
29140030Smarc #endif
29247545Skarels 		while (isbackground(curproc, tp) &&
29347545Skarels 		   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
29447545Skarels 		   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
29547545Skarels 		   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
29647545Skarels 			pgsignal(p->p_pgrp, SIGTTOU, 1);
29743377Smarc 			if (error = ttysleep(tp, (caddr_t)&lbolt,
29843377Smarc 			    TTOPRI | PCATCH, ttybg, 0))
29940712Skarels 				return (error);
300903Sbill 		}
301903Sbill 		break;
302903Sbill 	}
303903Sbill 
3049578Ssam 	/*
3059578Ssam 	 * Process the ioctl.
3069578Ssam 	 */
3077625Ssam 	switch (com) {
308903Sbill 
3098556Sroot 	/* get discipline number */
31039Sbill 	case TIOCGETD:
3117625Ssam 		*(int *)data = tp->t_line;
31239Sbill 		break;
31339Sbill 
3148556Sroot 	/* set line discipline */
3157625Ssam 	case TIOCSETD: {
3167625Ssam 		register int t = *(int *)data;
31735811Smarc 		dev_t dev = tp->t_dev;
3187625Ssam 
31935811Smarc 		if ((unsigned)t >= nldisp)
32010851Ssam 			return (ENXIO);
32125584Skarels 		if (t != tp->t_line) {
32225584Skarels 			s = spltty();
32349752Smarc 			(*linesw[tp->t_line].l_close)(tp, flag);
32425584Skarels 			error = (*linesw[t].l_open)(dev, tp);
32525584Skarels 			if (error) {
32635811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
32725584Skarels 				splx(s);
32825584Skarels 				return (error);
32925584Skarels 			}
33025584Skarels 			tp->t_line = t;
33110851Ssam 			splx(s);
33210851Ssam 		}
33339Sbill 		break;
3347625Ssam 	}
33539Sbill 
3368556Sroot 	/* prevent more opens on channel */
3375614Swnj 	case TIOCEXCL:
33852485Storek 		s = spltty();
3395614Swnj 		tp->t_state |= TS_XCLUDE;
34052485Storek 		splx(s);
3415614Swnj 		break;
3425614Swnj 
3435614Swnj 	case TIOCNXCL:
34452485Storek 		s = spltty();
3455614Swnj 		tp->t_state &= ~TS_XCLUDE;
34652485Storek 		splx(s);
3475614Swnj 		break;
3485614Swnj 
34952485Storek #ifdef TIOCHPCL
35039Sbill 	case TIOCHPCL:
35152485Storek 		s = spltty();
35235811Smarc 		tp->t_cflag |= HUPCL;
35352485Storek 		splx(s);
35439Sbill 		break;
35552485Storek #endif
35639Sbill 
3573942Sbugs 	case TIOCFLUSH: {
3587625Ssam 		register int flags = *(int *)data;
3597625Ssam 
3607625Ssam 		if (flags == 0)
3613942Sbugs 			flags = FREAD|FWRITE;
3627625Ssam 		else
3637625Ssam 			flags &= FREAD|FWRITE;
36412752Ssam 		ttyflush(tp, flags);
36539Sbill 		break;
3663944Sbugs 	}
36739Sbill 
36837584Smarc 	case FIOASYNC:
36952485Storek 		s = spltty();
37037584Smarc 		if (*(int *)data)
37137584Smarc 			tp->t_state |= TS_ASYNC;
37237584Smarc 		else
37337584Smarc 			tp->t_state &= ~TS_ASYNC;
37452485Storek 		splx(s);
37537584Smarc 		break;
37637584Smarc 
37737584Smarc 	case FIONBIO:
37837584Smarc 		break;	/* XXX remove */
37937584Smarc 
3808556Sroot 	/* return number of characters immediately available */
3817625Ssam 	case FIONREAD:
3827625Ssam 		*(off_t *)data = ttnread(tp);
383174Sbill 		break;
384174Sbill 
38513077Ssam 	case TIOCOUTQ:
38613077Ssam 		*(int *)data = tp->t_outq.c_cc;
38713077Ssam 		break;
38813077Ssam 
3898589Sroot 	case TIOCSTOP:
39017545Skarels 		s = spltty();
3919578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3925573Swnj 			tp->t_state |= TS_TTSTOP;
39352485Storek #ifdef sun4c						/* XXX */
39452485Storek 			(*tp->t_stop)(tp, 0);
39552485Storek #else
3965573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
39752485Storek #endif
3985573Swnj 		}
3997625Ssam 		splx(s);
4005573Swnj 		break;
4015573Swnj 
4028589Sroot 	case TIOCSTART:
40317545Skarels 		s = spltty();
40435811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
4055573Swnj 			tp->t_state &= ~TS_TTSTOP;
40635811Smarc 			tp->t_lflag &= ~FLUSHO;
4075573Swnj 			ttstart(tp);
4085573Swnj 		}
4097625Ssam 		splx(s);
4105573Swnj 		break;
4115573Swnj 
4129325Ssam 	/*
4139325Ssam 	 * Simulate typing of a character at the terminal.
4149325Ssam 	 */
4159325Ssam 	case TIOCSTI:
41647545Skarels 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
41717183Smckusick 			return (EPERM);
41847545Skarels 		if (p->p_ucred->cr_uid && !isctty(p, tp))
4199325Ssam 			return (EACCES);
4209578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4219325Ssam 		break;
4229325Ssam 
42335811Smarc 	case TIOCGETA: {
42435811Smarc 		struct termios *t = (struct termios *)data;
42512752Ssam 
42635811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
42735811Smarc 		break;
42835811Smarc 	}
42935811Smarc 
43035811Smarc 	case TIOCSETA:
43135811Smarc 	case TIOCSETAW:
43237584Smarc 	case TIOCSETAF: {
43335811Smarc 		register struct termios *t = (struct termios *)data;
43440712Skarels 
43517545Skarels 		s = spltty();
43639407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
43740712Skarels 			if (error = ttywait(tp)) {
43840712Skarels 				splx(s);
43940712Skarels 				return (error);
44040712Skarels 			}
44145007Smarc 			if (com == TIOCSETAF)
44239407Smarc 				ttyflush(tp, FREAD);
44339407Smarc 		}
44440712Skarels 		if ((t->c_cflag&CIGNORE) == 0) {
44535811Smarc 			/*
44635811Smarc 			 * set device hardware
44735811Smarc 			 */
44837584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
44937584Smarc 				splx(s);
45035811Smarc 				return (error);
45137584Smarc 			} else {
45240712Skarels 				if ((tp->t_state&TS_CARR_ON) == 0 &&
45337584Smarc 				    (tp->t_cflag&CLOCAL) &&
45440712Skarels 				    (t->c_cflag&CLOCAL) == 0) {
45537584Smarc 					tp->t_state &= ~TS_ISOPEN;
45637584Smarc 					tp->t_state |= TS_WOPEN;
45737584Smarc 					ttwakeup(tp);
45837584Smarc 				}
45935811Smarc 				tp->t_cflag = t->c_cflag;
46035811Smarc 				tp->t_ispeed = t->c_ispeed;
46135811Smarc 				tp->t_ospeed = t->c_ospeed;
46234492Skarels 			}
46335811Smarc 			ttsetwater(tp);
46412752Ssam 		}
46539407Smarc 		if (com != TIOCSETAF) {
46635811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
46735811Smarc 				if (t->c_lflag&ICANON) {
46835811Smarc 					tp->t_lflag |= PENDIN;
46935811Smarc 					ttwakeup(tp);
47035811Smarc 				}
47135811Smarc 				else {
47235811Smarc 					struct clist tq;
47335811Smarc 
47435811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
47535811Smarc 					tq = tp->t_rawq;
47635811Smarc 					tp->t_rawq = tp->t_canq;
47735811Smarc 					tp->t_canq = tq;
47835811Smarc 				}
47912752Ssam 		}
48035811Smarc 		tp->t_iflag = t->c_iflag;
48135811Smarc 		tp->t_oflag = t->c_oflag;
48242882Smarc 		/*
48342882Smarc 		 * Make the EXTPROC bit read only.
48442882Smarc 		 */
48542882Smarc 		if (tp->t_lflag&EXTPROC)
48642882Smarc 			t->c_lflag |= EXTPROC;
48742882Smarc 		else
48842882Smarc 			t->c_lflag &= ~EXTPROC;
48935811Smarc 		tp->t_lflag = t->c_lflag;
49035811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
49112752Ssam 		splx(s);
49212752Ssam 		break;
49312752Ssam 	}
49412752Ssam 
49512752Ssam 	/*
49639555Smarc 	 * Set controlling terminal.
49739555Smarc 	 * Session ctty vnode pointer set in vnode layer.
49834492Skarels 	 */
49947545Skarels 	case TIOCSCTTY:
50039555Smarc 		if (!SESS_LEADER(p) ||
50139555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
50239555Smarc 		   (tp->t_session != p->p_session))
50339407Smarc 			return (EPERM);
50435811Smarc 		tp->t_session = p->p_session;
50539555Smarc 		tp->t_pgrp = p->p_pgrp;
50639555Smarc 		p->p_session->s_ttyp = tp;
50739555Smarc 		p->p_flag |= SCTTY;
50834492Skarels 		break;
50939555Smarc 
51034492Skarels 	/*
51135811Smarc 	 * Set terminal process group.
51217545Skarels 	 */
51318650Sbloom 	case TIOCSPGRP: {
51435811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
51517545Skarels 
51639555Smarc 		if (!isctty(p, tp))
51739555Smarc 			return (ENOTTY);
51840030Smarc 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
51939555Smarc 			return (EPERM);
52039555Smarc 		tp->t_pgrp = pgrp;
52112752Ssam 		break;
52218650Sbloom 	}
52312752Ssam 
52412752Ssam 	case TIOCGPGRP:
52547545Skarels 		if (!isctty(p, tp))
52639555Smarc 			return (ENOTTY);
52745007Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
52812752Ssam 		break;
52912752Ssam 
53017598Sbloom 	case TIOCSWINSZ:
53118650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
53218650Sbloom 		    sizeof (struct winsize))) {
53317598Sbloom 			tp->t_winsize = *(struct winsize *)data;
53442882Smarc 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
53517598Sbloom 		}
53617598Sbloom 		break;
53717598Sbloom 
53817598Sbloom 	case TIOCGWINSZ:
53917598Sbloom 		*(struct winsize *)data = tp->t_winsize;
54017598Sbloom 		break;
54117598Sbloom 
54230534Skarels 	case TIOCCONS:
54330534Skarels 		if (*(int *)data) {
54442141Smckusick 			if (constty && constty != tp &&
54542141Smckusick 			    (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
54642141Smckusick 			    (TS_CARR_ON|TS_ISOPEN))
54730534Skarels 				return (EBUSY);
54830534Skarels #ifndef	UCONSOLE
54947545Skarels 			if (error = suser(p->p_ucred, &p->p_acflag))
55037554Smckusick 				return (error);
55130534Skarels #endif
55230534Skarels 			constty = tp;
55330534Skarels 		} else if (tp == constty)
55433404Skarels 			constty = NULL;
55530534Skarels 		break;
55630534Skarels 
55748439Skarels 	case TIOCDRAIN:
55848439Skarels 		if (error = ttywait(tp))
55948439Skarels 			return (error);
56048439Skarels 		break;
56148439Skarels 
56247545Skarels 	default:
56352485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
56447545Skarels 		return (ttcompat(tp, com, data, flag));
56547545Skarels #else
56647545Skarels 		return (-1);
56735811Smarc #endif
56839Sbill 	}
5698556Sroot 	return (0);
57039Sbill }
5714484Swnj 
5724484Swnj ttnread(tp)
5734484Swnj 	struct tty *tp;
5744484Swnj {
5754484Swnj 	int nread = 0;
5764484Swnj 
57735811Smarc 	if (tp->t_lflag & PENDIN)
5784484Swnj 		ttypend(tp);
5794484Swnj 	nread = tp->t_canq.c_cc;
58035811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5814484Swnj 		nread += tp->t_rawq.c_cc;
5824484Swnj 	return (nread);
5834484Swnj }
5844484Swnj 
58552522Smckusick ttselect(dev, rw, p)
5864484Swnj 	dev_t dev;
5875408Swnj 	int rw;
58852522Smckusick 	struct proc *p;
5894484Swnj {
5904484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5914484Swnj 	int nread;
59217545Skarels 	int s = spltty();
5934484Swnj 
5945408Swnj 	switch (rw) {
5954484Swnj 
5964484Swnj 	case FREAD:
5974484Swnj 		nread = ttnread(tp);
59837584Smarc 		if (nread > 0 ||
59940712Skarels 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
6005408Swnj 			goto win;
60152522Smckusick 		selrecord(p, &tp->t_rsel);
6025408Swnj 		break;
6034484Swnj 
6045408Swnj 	case FWRITE:
60535811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
6065408Swnj 			goto win;
60752522Smckusick 		selrecord(p, &tp->t_wsel);
6085408Swnj 		break;
6094484Swnj 	}
6105408Swnj 	splx(s);
6115408Swnj 	return (0);
6125408Swnj win:
6135408Swnj 	splx(s);
6145408Swnj 	return (1);
6154484Swnj }
6167436Skre 
6177502Sroot /*
61849380Skarels  * Initial open of tty, or (re)entry to standard tty line discipline.
6197502Sroot  */
6207502Sroot ttyopen(dev, tp)
6217625Ssam 	dev_t dev;
6227625Ssam 	register struct tty *tp;
6237502Sroot {
62452485Storek 	int s = spltty();
6257502Sroot 
6267502Sroot 	tp->t_dev = dev;
62735811Smarc 
6287502Sroot 	tp->t_state &= ~TS_WOPEN;
62917545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
63017545Skarels 		tp->t_state |= TS_ISOPEN;
63117598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
63217545Skarels 	}
63352485Storek 	splx(s);
6348556Sroot 	return (0);
6357502Sroot }
6367502Sroot 
6377502Sroot /*
63825391Skarels  * "close" a line discipline
63925391Skarels  */
64049752Smarc ttylclose(tp, flag)
64149752Smarc 	struct tty *tp;
64249752Smarc 	int flag;
64325391Skarels {
64425391Skarels 
64549752Smarc 	if (flag&IO_NDELAY)
64649752Smarc 		ttyflush(tp, FREAD|FWRITE);
64749752Smarc 	else
64849752Smarc 		ttywflush(tp);
64925391Skarels }
65025391Skarels 
65125391Skarels /*
65249380Skarels  * Handle close() on a tty line: flush and set to initial state,
65349380Skarels  * bumping generation number so that pending read/write calls
65449380Skarels  * can detect recycling of the tty.
6557502Sroot  */
6567502Sroot ttyclose(tp)
6577625Ssam 	register struct tty *tp;
6587502Sroot {
65930534Skarels 	if (constty == tp)
66030534Skarels 		constty = NULL;
66125391Skarels 	ttyflush(tp, FREAD|FWRITE);
66239555Smarc 	tp->t_session = NULL;
66339555Smarc 	tp->t_pgrp = NULL;
6647502Sroot 	tp->t_state = 0;
66543377Smarc 	tp->t_gen++;
66640712Skarels 	return (0);
6677502Sroot }
6687502Sroot 
6697502Sroot /*
67025391Skarels  * Handle modem control transition on a tty.
67125391Skarels  * Flag indicates new state of carrier.
67225391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
67325391Skarels  */
67425391Skarels ttymodem(tp, flag)
67525391Skarels 	register struct tty *tp;
67652485Storek 	int flag;
67725391Skarels {
67825391Skarels 
67942193Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
68025391Skarels 		/*
68125391Skarels 		 * MDMBUF: do flow control according to carrier flag
68225391Skarels 		 */
68325391Skarels 		if (flag) {
68425391Skarels 			tp->t_state &= ~TS_TTSTOP;
68525391Skarels 			ttstart(tp);
68625391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
68725391Skarels 			tp->t_state |= TS_TTSTOP;
68852485Storek #ifdef sun4c						/* XXX */
68952485Storek 			(*tp->t_stop)(tp, 0);
69052485Storek #else
69125391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
69252485Storek #endif
69325391Skarels 		}
69425391Skarels 	} else if (flag == 0) {
69525391Skarels 		/*
69625391Skarels 		 * Lost carrier.
69725391Skarels 		 */
69825391Skarels 		tp->t_state &= ~TS_CARR_ON;
69942193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
70042193Smarc 			if (tp->t_session && tp->t_session->s_leader)
70142193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
70242193Smarc 			ttyflush(tp, FREAD|FWRITE);
70342193Smarc 			return (0);
70425391Skarels 		}
70525391Skarels 	} else {
70625391Skarels 		/*
70725391Skarels 		 * Carrier now on.
70825391Skarels 		 */
70925391Skarels 		tp->t_state |= TS_CARR_ON;
71037584Smarc 		ttwakeup(tp);
71125391Skarels 	}
71225391Skarels 	return (1);
71325391Skarels }
71425391Skarels 
71525391Skarels /*
71625404Skarels  * Default modem control routine (for other line disciplines).
71725404Skarels  * Return argument flag, to turn off device on carrier drop.
71825404Skarels  */
71925415Skarels nullmodem(tp, flag)
72025415Skarels 	register struct tty *tp;
72125404Skarels 	int flag;
72225404Skarels {
72325404Skarels 
72425404Skarels 	if (flag)
72525404Skarels 		tp->t_state |= TS_CARR_ON;
72639407Smarc 	else {
72725404Skarels 		tp->t_state &= ~TS_CARR_ON;
72842193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
72942193Smarc 			if (tp->t_session && tp->t_session->s_leader)
73042193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
73142193Smarc 			return (0);
73242193Smarc 		}
73339407Smarc 	}
73442193Smarc 	return (1);
73525404Skarels }
73625404Skarels 
73725404Skarels /*
7387502Sroot  * reinput pending characters after state switch
73917545Skarels  * call at spltty().
7407502Sroot  */
7417502Sroot ttypend(tp)
7427625Ssam 	register struct tty *tp;
7437502Sroot {
7447502Sroot 	struct clist tq;
7457502Sroot 	register c;
7467502Sroot 
74735811Smarc 	tp->t_lflag &= ~PENDIN;
7489578Ssam 	tp->t_state |= TS_TYPEN;
7497502Sroot 	tq = tp->t_rawq;
7507502Sroot 	tp->t_rawq.c_cc = 0;
7517502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7527502Sroot 	while ((c = getc(&tq)) >= 0)
7537502Sroot 		ttyinput(c, tp);
7549578Ssam 	tp->t_state &= ~TS_TYPEN;
7557502Sroot }
7567502Sroot 
7577502Sroot /*
75849380Skarels  * Process input of a single character received on a tty.
7597502Sroot  */
7607502Sroot ttyinput(c, tp)
7617625Ssam 	register c;
7627625Ssam 	register struct tty *tp;
7637502Sroot {
76435811Smarc 	register int iflag = tp->t_iflag;
76535811Smarc 	register int lflag = tp->t_lflag;
76635811Smarc 	register u_char *cc = tp->t_cc;
76735811Smarc 	int i, err;
7687502Sroot 
7699578Ssam 	/*
7709578Ssam 	 * If input is pending take it first.
7719578Ssam 	 */
77235811Smarc 	if (lflag&PENDIN)
7737502Sroot 		ttypend(tp);
77435811Smarc 	/*
77535811Smarc 	 * Gather stats.
77635811Smarc 	 */
7777502Sroot 	tk_nin++;
77835811Smarc 	if (lflag&ICANON) {
77935811Smarc 		tk_cancc++;
78035811Smarc 		tp->t_cancc++;
78135811Smarc 	} else {
78235811Smarc 		tk_rawcc++;
78335811Smarc 		tp->t_rawcc++;
78435811Smarc 	}
7859578Ssam 	/*
78635811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7879578Ssam 	 */
78835811Smarc 	if (err = (c&TTY_ERRORMASK)) {
78935811Smarc 		c &= ~TTY_ERRORMASK;
79035811Smarc 		if (err&TTY_FE && !c) {		/* break */
79135811Smarc 			if (iflag&IGNBRK)
79235811Smarc 				goto endcase;
79335811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
79435811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
79535811Smarc 				c = cc[VINTR];
79647545Skarels 			else if (iflag&PARMRK)
79747545Skarels 				goto parmrk;
79835811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
79935811Smarc 			if (iflag&IGNPAR)
80035811Smarc 				goto endcase;
80135811Smarc 			else if (iflag&PARMRK) {
80235811Smarc parmrk:
80335811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
80435811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
80535811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
80635811Smarc 				goto endcase;
80735811Smarc 			} else
80835811Smarc 				c = 0;
8097502Sroot 		}
8109578Ssam 	}
8119578Ssam 	/*
81235811Smarc 	 * In tandem mode, check high water mark.
8139578Ssam 	 */
81435811Smarc 	if (iflag&IXOFF)
81535811Smarc 		ttyblock(tp);
81635811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
81749380Skarels 		c &= ~0x80;
81844419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
81944419Smarc 		/*
82044419Smarc 		 * Check for literal nexting very first
82144419Smarc 		 */
82244419Smarc 		if (tp->t_state&TS_LNCH) {
82344419Smarc 			c |= TTY_QUOTE;
82444419Smarc 			tp->t_state &= ~TS_LNCH;
82544419Smarc 		}
82644419Smarc 		/*
82744419Smarc 		 * Scan for special characters.  This code
82844419Smarc 		 * is really just a big case statement with
82944419Smarc 		 * non-constant cases.  The bottom of the
83044419Smarc 		 * case statement is labeled ``endcase'', so goto
83144419Smarc 		 * it after a case match, or similar.
83244419Smarc 		 */
83344419Smarc 
83444419Smarc 		/*
83544419Smarc 		 * Control chars which aren't controlled
83644419Smarc 		 * by ICANON, ISIG, or IXON.
83744419Smarc 		 */
83844419Smarc 		if (lflag&IEXTEN) {
83944419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
84044419Smarc 				if (lflag&ECHO) {
84144419Smarc 					if (lflag&ECHOE)
84244419Smarc 						ttyoutstr("^\b", tp);
84344419Smarc 					else
84444419Smarc 						ttyecho(c, tp);
84544419Smarc 				}
84644419Smarc 				tp->t_state |= TS_LNCH;
84744419Smarc 				goto endcase;
84844419Smarc 			}
84944419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
85044419Smarc 				if (lflag&FLUSHO)
85144419Smarc 					tp->t_lflag &= ~FLUSHO;
85244419Smarc 				else {
85344419Smarc 					ttyflush(tp, FWRITE);
85435811Smarc 					ttyecho(c, tp);
85544419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
85644419Smarc 						ttyretype(tp);
85744419Smarc 					tp->t_lflag |= FLUSHO;
85844419Smarc 				}
85944419Smarc 				goto startoutput;
86035811Smarc 			}
8619578Ssam 		}
86244419Smarc 		/*
86344419Smarc 		 * Signals.
86444419Smarc 		 */
86544419Smarc 		if (lflag&ISIG) {
86644419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
86744419Smarc 				if ((lflag&NOFLSH) == 0)
86844419Smarc 					ttyflush(tp, FREAD|FWRITE);
8697502Sroot 				ttyecho(c, tp);
87044419Smarc 				pgsignal(tp->t_pgrp,
87144419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
87244419Smarc 				goto endcase;
8737502Sroot 			}
87444419Smarc 			if (CCEQ(cc[VSUSP], c)) {
87544419Smarc 				if ((lflag&NOFLSH) == 0)
87644419Smarc 					ttyflush(tp, FREAD);
87744419Smarc 				ttyecho(c, tp);
87844419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
87944419Smarc 				goto endcase;
88044419Smarc 			}
8819578Ssam 		}
88244419Smarc 		/*
88344419Smarc 		 * Handle start/stop characters.
88444419Smarc 		 */
88544419Smarc 		if (iflag&IXON) {
88644419Smarc 			if (CCEQ(cc[VSTOP], c)) {
88744419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
88844419Smarc 					tp->t_state |= TS_TTSTOP;
88952485Storek #ifdef sun4c						/* XXX */
89052485Storek 					(*tp->t_stop)(tp, 0);
89152485Storek #else
89244419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
89344419Smarc 					   0);
89452485Storek #endif
89544419Smarc 					return;
89644419Smarc 				}
89744419Smarc 				if (!CCEQ(cc[VSTART], c))
89844419Smarc 					return;
89944419Smarc 				/*
90044419Smarc 				 * if VSTART == VSTOP then toggle
90144419Smarc 				 */
90244419Smarc 				goto endcase;
90335811Smarc 			}
90444419Smarc 			if (CCEQ(cc[VSTART], c))
90544419Smarc 				goto restartoutput;
9069578Ssam 		}
90744419Smarc 		/*
90844419Smarc 		 * IGNCR, ICRNL, & INLCR
90944419Smarc 		 */
91044419Smarc 		if (c == '\r') {
91144419Smarc 			if (iflag&IGNCR)
91244419Smarc 				goto endcase;
91344419Smarc 			else if (iflag&ICRNL)
91444419Smarc 				c = '\n';
91544419Smarc 		} else if (c == '\n' && iflag&INLCR)
91644419Smarc 			c = '\r';
9179578Ssam 	}
91847545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
91944419Smarc 		/*
92044419Smarc 		 * From here on down canonical mode character
92144419Smarc 		 * processing takes place.
92244419Smarc 		 */
92344419Smarc 		/*
92444419Smarc 		 * erase (^H / ^?)
92544419Smarc 		 */
92644419Smarc 		if (CCEQ(cc[VERASE], c)) {
92744419Smarc 			if (tp->t_rawq.c_cc)
9289578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
92944419Smarc 			goto endcase;
9309578Ssam 		}
93144419Smarc 		/*
93244419Smarc 		 * kill (^U)
93344419Smarc 		 */
93444419Smarc 		if (CCEQ(cc[VKILL], c)) {
93544419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
93644419Smarc 			    (lflag&ECHOPRT) == 0) {
93744419Smarc 				while (tp->t_rawq.c_cc)
93844419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
93944419Smarc 			} else {
94044419Smarc 				ttyecho(c, tp);
94144419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
94244419Smarc 					ttyecho('\n', tp);
94352485Storek 				flushq(&tp->t_rawq);
94444419Smarc 				tp->t_rocount = 0;
94544419Smarc 			}
94644419Smarc 			tp->t_state &= ~TS_LOCAL;
94744419Smarc 			goto endcase;
94844419Smarc 		}
94944419Smarc 		/*
95044419Smarc 		 * word erase (^W)
95144419Smarc 		 */
95244419Smarc 		if (CCEQ(cc[VWERASE], c)) {
95344419Smarc 			int ctype;
95447545Skarels 			int alt = lflag&ALTWERASE;
95535811Smarc 
95644419Smarc 			/*
95744419Smarc 			 * erase whitespace
95844419Smarc 			 */
95944419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
96044419Smarc 				ttyrub(c, tp);
96144419Smarc 			if (c == -1)
96244419Smarc 				goto endcase;
96344419Smarc 			/*
96447545Skarels 			 * erase last char of word and remember the
96547545Skarels 			 * next chars type (for ALTWERASE)
96644419Smarc 			 */
96735811Smarc 			ttyrub(c, tp);
96844419Smarc 			c = unputc(&tp->t_rawq);
96947545Skarels 			if (c == -1)
97044419Smarc 				goto endcase;
97151003Sbostic 			if (c == ' ' || c == '\t') {
97251003Sbostic 				putc(c, &tp->t_rawq);
97351003Sbostic 				goto endcase;
97451003Sbostic 			}
97549380Skarels 			ctype = ISALPHA(c);
97644419Smarc 			/*
97747545Skarels 			 * erase rest of word
97844419Smarc 			 */
97944419Smarc 			do {
98044419Smarc 				ttyrub(c, tp);
98144419Smarc 				c = unputc(&tp->t_rawq);
98244419Smarc 				if (c == -1)
98344419Smarc 					goto endcase;
98447545Skarels 			} while (c != ' ' && c != '\t' &&
98549380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
98644419Smarc 			(void) putc(c, &tp->t_rawq);
98734492Skarels 			goto endcase;
98844419Smarc 		}
98935811Smarc 		/*
99044419Smarc 		 * reprint line (^R)
99135811Smarc 		 */
99244419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
99344419Smarc 			ttyretype(tp);
99434492Skarels 			goto endcase;
99534492Skarels 		}
99635811Smarc 		/*
99744419Smarc 		 * ^T - kernel info and generate SIGINFO
99835811Smarc 		 */
99944419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
100051068Smarc 			if (lflag&ISIG)
100151068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
100244419Smarc 			if ((lflag&NOKERNINFO) == 0)
100344419Smarc 				ttyinfo(tp);
100444419Smarc 			goto endcase;
100544419Smarc 		}
10069578Ssam 	}
10079578Ssam 	/*
10089578Ssam 	 * Check for input buffer overflow
10099578Ssam 	 */
101047545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
101135811Smarc 		if (iflag&IMAXBEL) {
101235811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
101335811Smarc 				(void) ttyoutput(CTRL('g'), tp);
101435811Smarc 		} else
101535811Smarc 			ttyflush(tp, FREAD | FWRITE);
10169578Ssam 		goto endcase;
101710391Ssam 	}
10189578Ssam 	/*
10199578Ssam 	 * Put data char in q for user and
10209578Ssam 	 * wakeup on seeing a line delimiter.
10219578Ssam 	 */
10229578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
102347545Skarels 		if ((lflag&ICANON) == 0) {
102447545Skarels 			ttwakeup(tp);
102547545Skarels 			ttyecho(c, tp);
102647545Skarels 			goto endcase;
102747545Skarels 		}
102835811Smarc 		if (ttbreakc(c)) {
10299578Ssam 			tp->t_rocount = 0;
10309578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
10317502Sroot 			ttwakeup(tp);
10329578Ssam 		} else if (tp->t_rocount++ == 0)
10339578Ssam 			tp->t_rocol = tp->t_col;
10349578Ssam 		if (tp->t_state&TS_ERASE) {
103535811Smarc 			/*
103635811Smarc 			 * end of prterase \.../
103735811Smarc 			 */
10389578Ssam 			tp->t_state &= ~TS_ERASE;
10399578Ssam 			(void) ttyoutput('/', tp);
10409578Ssam 		}
10419578Ssam 		i = tp->t_col;
10427502Sroot 		ttyecho(c, tp);
104335811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
104435811Smarc 			/*
104535811Smarc 			 * Place the cursor over the '^' of the ^D.
104635811Smarc 			 */
10479578Ssam 			i = MIN(2, tp->t_col - i);
10489578Ssam 			while (i > 0) {
10499578Ssam 				(void) ttyoutput('\b', tp);
10509578Ssam 				i--;
10519578Ssam 			}
10529578Ssam 		}
10537502Sroot 	}
10549578Ssam endcase:
10559578Ssam 	/*
105635811Smarc 	 * IXANY means allow any character to restart output.
10579578Ssam 	 */
105840712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
105940712Skarels 	    cc[VSTART] != cc[VSTOP])
10607502Sroot 		return;
10619578Ssam restartoutput:
10627502Sroot 	tp->t_state &= ~TS_TTSTOP;
106335811Smarc 	tp->t_lflag &= ~FLUSHO;
10649578Ssam startoutput:
10657502Sroot 	ttstart(tp);
10667502Sroot }
10677502Sroot 
10687502Sroot /*
106949380Skarels  * Output a single character on a tty, doing output processing
107049380Skarels  * as needed (expanding tabs, newline processing, etc.).
107149380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10727502Sroot  * Must be recursive.
10737502Sroot  */
10747502Sroot ttyoutput(c, tp)
10757502Sroot 	register c;
10767502Sroot 	register struct tty *tp;
10777502Sroot {
107849380Skarels 	register int col;
107935811Smarc 	register long oflag = tp->t_oflag;
108035811Smarc 
108140712Skarels 	if ((oflag&OPOST) == 0) {
108235811Smarc 		if (tp->t_lflag&FLUSHO)
10837502Sroot 			return (-1);
10847502Sroot 		if (putc(c, &tp->t_outq))
10857625Ssam 			return (c);
10867502Sroot 		tk_nout++;
108735811Smarc 		tp->t_outcc++;
10887502Sroot 		return (-1);
10897502Sroot 	}
109035811Smarc 	c &= TTY_CHARMASK;
10917502Sroot 	/*
109249380Skarels 	 * Do tab expansion if OXTABS is set.
109342882Smarc 	 * Special case if we have external processing, we don't
109442882Smarc 	 * do the tab expansion because we'll probably get it
109542882Smarc 	 * wrong.  If tab expansion needs to be done, let it
109642882Smarc 	 * happen externally.
10977502Sroot 	 */
109847545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
10997502Sroot 		register int s;
11007502Sroot 
11017502Sroot 		c = 8 - (tp->t_col&7);
110235811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
110317545Skarels 			s = spltty();		/* don't interrupt tabs */
11047502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
11057502Sroot 			tk_nout += c;
110635811Smarc 			tp->t_outcc += c;
11077502Sroot 			splx(s);
11087502Sroot 		}
11097502Sroot 		tp->t_col += c;
11107502Sroot 		return (c ? -1 : '\t');
11117502Sroot 	}
111235811Smarc 	if (c == CEOT && oflag&ONOEOT)
111347545Skarels 		return (-1);
11147502Sroot 	tk_nout++;
111535811Smarc 	tp->t_outcc++;
11167502Sroot 	/*
111749380Skarels 	 * Newline translation: if ONLCR is set,
111849380Skarels 	 * translate newline into "\r\n".
11197502Sroot 	 */
112035811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
11217502Sroot 		return (c);
112235811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
112335811Smarc 		return (c);
112447545Skarels 
112549380Skarels 	col = tp->t_col;
112649380Skarels 	switch (CCLASS(c)) {
11277502Sroot 
11287502Sroot 	case ORDINARY:
112949380Skarels 		col++;
11307502Sroot 
11317502Sroot 	case CONTROL:
11327502Sroot 		break;
11337502Sroot 
11347502Sroot 	case BACKSPACE:
113549380Skarels 		if (col > 0)
113649380Skarels 			col--;
11377502Sroot 		break;
11387502Sroot 
11397502Sroot 	case NEWLINE:
114049380Skarels 		col = 0;
11417502Sroot 		break;
11427502Sroot 
11437502Sroot 	case TAB:
114449380Skarels 		col = (col + 8) &~ 0x7;
11457502Sroot 		break;
11467502Sroot 
11477502Sroot 	case RETURN:
114849380Skarels 		col = 0;
11497502Sroot 	}
115049380Skarels 	tp->t_col = col;
11517502Sroot 	return (-1);
11527502Sroot }
11537502Sroot 
11547502Sroot /*
115549380Skarels  * Process a read call on a tty device.
11567502Sroot  */
115737584Smarc ttread(tp, uio, flag)
11587625Ssam 	register struct tty *tp;
11597722Swnj 	struct uio *uio;
116052485Storek 	int flag;
11617502Sroot {
11627502Sroot 	register struct clist *qp;
116335811Smarc 	register int c;
116441383Smarc 	register long lflag;
116535811Smarc 	register u_char *cc = tp->t_cc;
116647545Skarels 	register struct proc *p = curproc;
11679859Ssam 	int s, first, error = 0;
11687502Sroot 
11697502Sroot loop:
117041383Smarc 	lflag = tp->t_lflag;
117137584Smarc 	s = spltty();
11729578Ssam 	/*
117337584Smarc 	 * take pending input first
11749578Ssam 	 */
117535811Smarc 	if (lflag&PENDIN)
11767502Sroot 		ttypend(tp);
11779859Ssam 	splx(s);
117840712Skarels 
11799578Ssam 	/*
11809578Ssam 	 * Hang process if it's in the background.
11819578Ssam 	 */
118247545Skarels 	if (isbackground(p, tp)) {
118347545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
118447545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
118547545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11868520Sroot 			return (EIO);
118747545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
118843377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
118943377Smarc 		    ttybg, 0))
119040712Skarels 			return (error);
119123165Sbloom 		goto loop;
11927502Sroot 	}
119340712Skarels 
11949578Ssam 	/*
119535811Smarc 	 * If canonical, use the canonical queue,
119635811Smarc 	 * else use the raw queue.
119737584Smarc 	 *
119847545Skarels 	 * (should get rid of clists...)
11999578Ssam 	 */
120035811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
120140712Skarels 
12029578Ssam 	/*
120340712Skarels 	 * If there is no input, sleep on rawq
120440712Skarels 	 * awaiting hardware receipt and notification.
120540712Skarels 	 * If we have data, we don't need to check for carrier.
12069578Ssam 	 */
120717545Skarels 	s = spltty();
12089578Ssam 	if (qp->c_cc <= 0) {
120940712Skarels 		int carrier;
121040712Skarels 
121140712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
121240712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
12139859Ssam 			splx(s);
121440712Skarels 			return (0);	/* EOF */
12157502Sroot 		}
121637728Smckusick 		if (flag & IO_NDELAY) {
121737584Smarc 			splx(s);
121837584Smarc 			return (EWOULDBLOCK);
121937584Smarc 		}
122043377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
122140712Skarels 		    carrier ? ttyin : ttopen, 0);
12229859Ssam 		splx(s);
122343377Smarc 		if (error)
122440712Skarels 			return (error);
12259578Ssam 		goto loop;
12269578Ssam 	}
12279859Ssam 	splx(s);
122840712Skarels 
12299578Ssam 	/*
123035811Smarc 	 * Input present, check for input mapping and processing.
12319578Ssam 	 */
12329578Ssam 	first = 1;
12339578Ssam 	while ((c = getc(qp)) >= 0) {
12349578Ssam 		/*
123535811Smarc 		 * delayed suspend (^Y)
12369578Ssam 		 */
123735811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
123842882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12399578Ssam 			if (first) {
124043377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
124143377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
124240712Skarels 					break;
12439578Ssam 				goto loop;
12449578Ssam 			}
12459578Ssam 			break;
12467502Sroot 		}
12479578Ssam 		/*
124835811Smarc 		 * Interpret EOF only in canonical mode.
12499578Ssam 		 */
125035811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12519578Ssam 			break;
12529578Ssam 		/*
12539578Ssam 		 * Give user character.
12549578Ssam 		 */
125540712Skarels  		error = ureadc(c, uio);
12569578Ssam 		if (error)
12579578Ssam 			break;
125814938Smckusick  		if (uio->uio_resid == 0)
12599578Ssam 			break;
12609578Ssam 		/*
126135811Smarc 		 * In canonical mode check for a "break character"
12629578Ssam 		 * marking the end of a "line of input".
12639578Ssam 		 */
126440712Skarels 		if (lflag&ICANON && ttbreakc(c))
12659578Ssam 			break;
12669578Ssam 		first = 0;
12677502Sroot 	}
12689578Ssam 	/*
12699578Ssam 	 * Look to unblock output now that (presumably)
12709578Ssam 	 * the input queue has gone down.
12719578Ssam 	 */
127252485Storek 	s = spltty();
127335811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
127447545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
127547545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12767502Sroot 			tp->t_state &= ~TS_TBLOCK;
12777502Sroot 			ttstart(tp);
12787502Sroot 		}
127935811Smarc 	}
128052485Storek 	splx(s);
12818520Sroot 	return (error);
12827502Sroot }
12837502Sroot 
12847502Sroot /*
128525391Skarels  * Check the output queue on tp for space for a kernel message
128625391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
128725391Skarels  * hiwater mark so we don't lose messages due to normal flow
128825391Skarels  * control, but don't let the tty run amok.
128930695Skarels  * Sleeps here are not interruptible, but we return prematurely
129030695Skarels  * if new signals come in.
129125391Skarels  */
129225391Skarels ttycheckoutq(tp, wait)
129325391Skarels 	register struct tty *tp;
129425391Skarels 	int wait;
129525391Skarels {
129630695Skarels 	int hiwat, s, oldsig;
129748439Skarels 	extern int wakeup();
129825391Skarels 
129935811Smarc 	hiwat = tp->t_hiwat;
130025391Skarels 	s = spltty();
130152485Storek 	oldsig = wait ? curproc->p_sig : 0;
130225391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
130329946Skarels 		while (tp->t_outq.c_cc > hiwat) {
130429946Skarels 			ttstart(tp);
130547545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
130629946Skarels 				splx(s);
130729946Skarels 				return (0);
130829946Skarels 			}
130930695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
131029946Skarels 			tp->t_state |= TS_ASLEEP;
131130695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
131225391Skarels 		}
131325391Skarels 	splx(s);
131425391Skarels 	return (1);
131525391Skarels }
131625391Skarels 
131725391Skarels /*
131849380Skarels  * Process a write call on a tty device.
13197502Sroot  */
132037584Smarc ttwrite(tp, uio, flag)
13217625Ssam 	register struct tty *tp;
13229578Ssam 	register struct uio *uio;
132352485Storek 	int flag;
13247502Sroot {
13257502Sroot 	register char *cp;
132640712Skarels 	register int cc = 0, ce;
132747545Skarels 	register struct proc *p = curproc;
13289578Ssam 	int i, hiwat, cnt, error, s;
13297502Sroot 	char obuf[OBUFSIZ];
13307502Sroot 
133135811Smarc 	hiwat = tp->t_hiwat;
13329578Ssam 	cnt = uio->uio_resid;
13339578Ssam 	error = 0;
13347502Sroot loop:
133537584Smarc 	s = spltty();
133640712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
133737584Smarc 		if (tp->t_state&TS_ISOPEN) {
133837584Smarc 			splx(s);
133937584Smarc 			return (EIO);
134037728Smckusick 		} else if (flag & IO_NDELAY) {
134137584Smarc 			splx(s);
134240712Skarels 			error = EWOULDBLOCK;
134340712Skarels 			goto out;
134437584Smarc 		} else {
134537584Smarc 			/*
134637584Smarc 			 * sleep awaiting carrier
134737584Smarc 			 */
134843377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
134943377Smarc 					TTIPRI | PCATCH,ttopen, 0);
135037584Smarc 			splx(s);
135143377Smarc 			if (error)
135240712Skarels 				goto out;
135337584Smarc 			goto loop;
135437584Smarc 		}
135537584Smarc 	}
135637584Smarc 	splx(s);
13579578Ssam 	/*
13589578Ssam 	 * Hang the process if it's in the background.
13599578Ssam 	 */
136047545Skarels 	if (isbackground(p, tp) &&
136147545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
136247545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
136347545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
136447545Skarels 	     p->p_pgrp->pg_jobc) {
136547545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
136643377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
136743377Smarc 		    ttybg, 0))
136840712Skarels 			goto out;
136921776Sbloom 		goto loop;
13707502Sroot 	}
13719578Ssam 	/*
13729578Ssam 	 * Process the user's data in at most OBUFSIZ
137340712Skarels 	 * chunks.  Perform any output translation.
137440712Skarels 	 * Keep track of high water mark, sleep on overflow
137540712Skarels 	 * awaiting device aid in acquiring new space.
13769578Ssam 	 */
137740712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
137840712Skarels 		if (tp->t_lflag&FLUSHO) {
137940712Skarels 			uio->uio_resid = 0;
138040712Skarels 			return (0);
138140712Skarels 		}
138240712Skarels 		if (tp->t_outq.c_cc > hiwat)
138332067Skarels 			goto ovhiwat;
13849578Ssam 		/*
138540712Skarels 		 * Grab a hunk of data from the user,
138640712Skarels 		 * unless we have some leftover from last time.
13879578Ssam 		 */
13887822Sroot 		if (cc == 0) {
138940712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139040712Skarels 			cp = obuf;
139140712Skarels 			error = uiomove(cp, cc, uio);
139240712Skarels 			if (error) {
139340712Skarels 				cc = 0;
139440712Skarels 				break;
139540712Skarels 			}
13967822Sroot 		}
13979578Ssam 		/*
13989578Ssam 		 * If nothing fancy need be done, grab those characters we
13999578Ssam 		 * can handle without any of ttyoutput's processing and
14009578Ssam 		 * just transfer them to the output q.  For those chars
14019578Ssam 		 * which require special processing (as indicated by the
14029578Ssam 		 * bits in partab), call ttyoutput.  After processing
14039578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14049578Ssam 		 * immediately.
14059578Ssam 		 */
14069578Ssam 		while (cc > 0) {
140740712Skarels 			if ((tp->t_oflag&OPOST) == 0)
14087502Sroot 				ce = cc;
14097502Sroot 			else {
141034492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
141149380Skarels 				   (u_char *)partab, CCLASSMASK);
14129578Ssam 				/*
14139578Ssam 				 * If ce is zero, then we're processing
14149578Ssam 				 * a special character through ttyoutput.
14159578Ssam 				 */
14169578Ssam 				if (ce == 0) {
14177502Sroot 					tp->t_rocount = 0;
14187502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
141921776Sbloom 					    /* no c-lists, wait a bit */
142021776Sbloom 					    ttstart(tp);
142143377Smarc 					    if (error = ttysleep(tp,
142243377Smarc 						(caddr_t)&lbolt,
142343377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
142440712Skarels 						    break;
142521776Sbloom 					    goto loop;
14267502Sroot 					}
14279578Ssam 					cp++, cc--;
142835811Smarc 					if ((tp->t_lflag&FLUSHO) ||
14299578Ssam 					    tp->t_outq.c_cc > hiwat)
14307502Sroot 						goto ovhiwat;
14319578Ssam 					continue;
14327502Sroot 				}
14337502Sroot 			}
14349578Ssam 			/*
14359578Ssam 			 * A bunch of normal characters have been found,
14369578Ssam 			 * transfer them en masse to the output queue and
14379578Ssam 			 * continue processing at the top of the loop.
14389578Ssam 			 * If there are any further characters in this
14399578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14409578Ssam 			 * requiring special handling by ttyoutput.
14419578Ssam 			 */
14427502Sroot 			tp->t_rocount = 0;
14439578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14449578Ssam 			ce -= i;
14459578Ssam 			tp->t_col += ce;
14469578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
144735811Smarc 			tp->t_outcc += ce;
14489578Ssam 			if (i > 0) {
14499578Ssam 				/* out of c-lists, wait a bit */
14507502Sroot 				ttstart(tp);
145143377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
145243377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
145340712Skarels 					break;
145421776Sbloom 				goto loop;
14557502Sroot 			}
145635811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
145740712Skarels 				break;
14587502Sroot 		}
145935811Smarc 		ttstart(tp);
14607502Sroot 	}
146140712Skarels out:
146240712Skarels 	/*
146340712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
146440712Skarels 	 * as the offset and iov pointers have moved forward,
146540712Skarels 	 * but it doesn't matter (the call will either return short
146640712Skarels 	 * or restart with a new uio).
146740712Skarels 	 */
146840712Skarels 	uio->uio_resid += cc;
14698520Sroot 	return (error);
147040712Skarels 
14717502Sroot ovhiwat:
147232067Skarels 	ttstart(tp);
147332067Skarels 	s = spltty();
14749578Ssam 	/*
147535811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
147632067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14779578Ssam 	 */
14787502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14799578Ssam 		splx(s);
14807502Sroot 		goto loop;
14817502Sroot 	}
148237728Smckusick 	if (flag & IO_NDELAY) {
148317545Skarels 		splx(s);
148440712Skarels 		uio->uio_resid += cc;
14857822Sroot 		if (uio->uio_resid == cnt)
14868520Sroot 			return (EWOULDBLOCK);
14878520Sroot 		return (0);
14887502Sroot 	}
14897502Sroot 	tp->t_state |= TS_ASLEEP;
149043377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14919578Ssam 	splx(s);
149243377Smarc 	if (error)
149340712Skarels 		goto out;
14947502Sroot 	goto loop;
14957502Sroot }
14967502Sroot 
14977502Sroot /*
14987502Sroot  * Rubout one character from the rawq of tp
14997502Sroot  * as cleanly as possible.
15007502Sroot  */
15017502Sroot ttyrub(c, tp)
15027625Ssam 	register c;
15037625Ssam 	register struct tty *tp;
15047502Sroot {
15057502Sroot 	register char *cp;
15067502Sroot 	register int savecol;
15077502Sroot 	int s;
15087502Sroot 	char *nextc();
15097502Sroot 
151042882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
15117502Sroot 		return;
151235811Smarc 	tp->t_lflag &= ~FLUSHO;
151335811Smarc 	if (tp->t_lflag&ECHOE) {
15147502Sroot 		if (tp->t_rocount == 0) {
15157502Sroot 			/*
15167502Sroot 			 * Screwed by ttwrite; retype
15177502Sroot 			 */
15187502Sroot 			ttyretype(tp);
15197502Sroot 			return;
15207502Sroot 		}
152135811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
15227502Sroot 			ttyrubo(tp, 2);
152349380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
15247502Sroot 
15257502Sroot 		case ORDINARY:
152635811Smarc 			ttyrubo(tp, 1);
15277502Sroot 			break;
15287502Sroot 
15297502Sroot 		case VTAB:
15307502Sroot 		case BACKSPACE:
15317502Sroot 		case CONTROL:
15327502Sroot 		case RETURN:
153347545Skarels 		case NEWLINE:
153435811Smarc 			if (tp->t_lflag&ECHOCTL)
15357502Sroot 				ttyrubo(tp, 2);
15367502Sroot 			break;
15377502Sroot 
153835811Smarc 		case TAB: {
153935811Smarc 			int c;
154035811Smarc 
15417502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15427502Sroot 				ttyretype(tp);
15437502Sroot 				return;
15447502Sroot 			}
154517545Skarels 			s = spltty();
15467502Sroot 			savecol = tp->t_col;
15479578Ssam 			tp->t_state |= TS_CNTTB;
154835811Smarc 			tp->t_lflag |= FLUSHO;
15497502Sroot 			tp->t_col = tp->t_rocol;
15509578Ssam 			cp = tp->t_rawq.c_cf;
155139407Smarc 			if (cp)
155239407Smarc 				c = *cp;	/* XXX FIX NEXTC */
155335811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
155435811Smarc 				ttyecho(c, tp);
155535811Smarc 			tp->t_lflag &= ~FLUSHO;
15569578Ssam 			tp->t_state &= ~TS_CNTTB;
15577502Sroot 			splx(s);
15587502Sroot 			/*
15597502Sroot 			 * savecol will now be length of the tab
15607502Sroot 			 */
15617502Sroot 			savecol -= tp->t_col;
15627502Sroot 			tp->t_col += savecol;
15637502Sroot 			if (savecol > 8)
15647502Sroot 				savecol = 8;		/* overflow screw */
15657502Sroot 			while (--savecol >= 0)
15667502Sroot 				(void) ttyoutput('\b', tp);
15677502Sroot 			break;
156835811Smarc 		}
15697502Sroot 
15707502Sroot 		default:
157137584Smarc 			/* XXX */
157235811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
157349380Skarels 				c, CCLASS(c));
157435811Smarc 			/*panic("ttyrub");*/
15757502Sroot 		}
157635811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15779578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15787502Sroot 			(void) ttyoutput('\\', tp);
15799578Ssam 			tp->t_state |= TS_ERASE;
15807502Sroot 		}
15817502Sroot 		ttyecho(c, tp);
15827502Sroot 	} else
158335811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15847502Sroot 	tp->t_rocount--;
15857502Sroot }
15867502Sroot 
15877502Sroot /*
15887502Sroot  * Crt back over cnt chars perhaps
15897502Sroot  * erasing them.
15907502Sroot  */
15917502Sroot ttyrubo(tp, cnt)
15927625Ssam 	register struct tty *tp;
15937625Ssam 	int cnt;
15947502Sroot {
15957502Sroot 
15967502Sroot 	while (--cnt >= 0)
159740712Skarels 		ttyoutstr("\b \b", tp);
15987502Sroot }
15997502Sroot 
16007502Sroot /*
16017502Sroot  * Reprint the rawq line.
16027502Sroot  * We assume c_cc has already been checked.
16037502Sroot  */
16047502Sroot ttyretype(tp)
16057625Ssam 	register struct tty *tp;
16067502Sroot {
16077502Sroot 	register char *cp;
16087502Sroot 	char *nextc();
160935811Smarc 	int s, c;
16107502Sroot 
161135811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
161235811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
16137502Sroot 	(void) ttyoutput('\n', tp);
161417545Skarels 	s = spltty();
161535811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
161635811Smarc 	  BIT OF FIRST CHAR ****/
161735811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
161835811Smarc 		ttyecho(c, tp);
161935811Smarc 	}
162035811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
162135811Smarc 		ttyecho(c, tp);
162235811Smarc 	}
16239578Ssam 	tp->t_state &= ~TS_ERASE;
16247502Sroot 	splx(s);
16257502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16267502Sroot 	tp->t_rocol = 0;
16277502Sroot }
16287502Sroot 
16297502Sroot /*
163035811Smarc  * Echo a typed character to the terminal.
16317502Sroot  */
16327502Sroot ttyecho(c, tp)
16337625Ssam 	register c;
16347625Ssam 	register struct tty *tp;
16357502Sroot {
16369578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
163735811Smarc 		tp->t_lflag &= ~FLUSHO;
163847545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
163947545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16407502Sroot 		return;
164135811Smarc 	if (tp->t_lflag&ECHOCTL) {
164240712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
164340712Skarels 		    c == 0177) {
16447502Sroot 			(void) ttyoutput('^', tp);
164535811Smarc 			c &= TTY_CHARMASK;
16467502Sroot 			if (c == 0177)
16477502Sroot 				c = '?';
16487502Sroot 			else
16497502Sroot 				c += 'A' - 1;
16507502Sroot 		}
16517502Sroot 	}
165235811Smarc 	(void) ttyoutput(c, tp);
16537502Sroot }
16547502Sroot 
16557502Sroot /*
16567502Sroot  * send string cp to tp
16577502Sroot  */
165840712Skarels ttyoutstr(cp, tp)
16597625Ssam 	register char *cp;
16607625Ssam 	register struct tty *tp;
16617502Sroot {
16627502Sroot 	register char c;
16637502Sroot 
16647502Sroot 	while (c = *cp++)
16657502Sroot 		(void) ttyoutput(c, tp);
16667502Sroot }
16677502Sroot 
166849380Skarels /*
166949380Skarels  * Wake up any readers on a tty.
167049380Skarels  */
16717502Sroot ttwakeup(tp)
167247545Skarels 	register struct tty *tp;
16737502Sroot {
16747502Sroot 
167552522Smckusick 	selwakeup(&tp->t_rsel);
167612752Ssam 	if (tp->t_state & TS_ASYNC)
167742882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16787502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16797502Sroot }
168035811Smarc 
168135811Smarc /*
168248439Skarels  * Look up a code for a specified speed in a conversion table;
168348439Skarels  * used by drivers to map software speed values to hardware parameters.
168448439Skarels  */
168548439Skarels ttspeedtab(speed, table)
168652485Storek 	int speed;
168748439Skarels 	register struct speedtab *table;
168848439Skarels {
168948439Skarels 
169048439Skarels 	for ( ; table->sp_speed != -1; table++)
169148439Skarels 		if (table->sp_speed == speed)
169248439Skarels 			return (table->sp_code);
169348439Skarels 	return (-1);
169448439Skarels }
169548439Skarels 
169648439Skarels /*
169735811Smarc  * set tty hi and low water marks
169835811Smarc  *
169935811Smarc  * Try to arrange the dynamics so there's about one second
170035811Smarc  * from hi to low water.
170135811Smarc  *
170235811Smarc  */
170335811Smarc ttsetwater(tp)
170435811Smarc 	struct tty *tp;
170535811Smarc {
170635811Smarc 	register cps = tp->t_ospeed / 10;
170735811Smarc 	register x;
170835811Smarc 
170935811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
171035811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
171135811Smarc 	x += cps;
171235811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
171335811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
171435811Smarc #undef clamp
171535811Smarc }
171635811Smarc 
171739407Smarc /*
171839407Smarc  * Report on state of foreground process group.
171939407Smarc  */
172039407Smarc ttyinfo(tp)
172149907Sbostic 	register struct tty *tp;
172239407Smarc {
172349907Sbostic 	register struct proc *p, *pick;
172441177Smarc 	struct timeval utime, stime;
172549907Sbostic 	int tmp;
172639407Smarc 
172739407Smarc 	if (ttycheckoutq(tp,0) == 0)
172839407Smarc 		return;
172949907Sbostic 
173049907Sbostic 	/* Print load average. */
1731*52666Smckusick 	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
173249907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
173349907Sbostic 
173439555Smarc 	if (tp->t_session == NULL)
173549907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
173641177Smarc 	else if (tp->t_pgrp == NULL)
173749907Sbostic 		ttyprintf(tp, "no foreground process group\n");
173841177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
173949907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
174039407Smarc 	else {
174149907Sbostic 		/* Pick interesting process. */
174249907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
174341177Smarc 			if (proc_compare(pick, p))
174441177Smarc 				pick = p;
174549907Sbostic 
174649907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
174749907Sbostic 		    pick->p_stat == SRUN ? "running" :
174849907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
174949907Sbostic 
175049907Sbostic 		/*
175149907Sbostic 		 * Lock out clock if process is running; get user/system
175249907Sbostic 		 * cpu time.
175341177Smarc 		 */
175447545Skarels 		if (curproc == pick)
175549907Sbostic 			tmp = splclock();
175641177Smarc 		utime = pick->p_utime;
175741177Smarc 		stime = pick->p_stime;
175847545Skarels 		if (curproc == pick)
175949907Sbostic 			splx(tmp);
176039407Smarc 
176149907Sbostic 		/* Print user time. */
176249907Sbostic 		ttyprintf(tp, "%d.%02du ",
176349907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
176441177Smarc 
176549907Sbostic 		/* Print system time. */
176649907Sbostic 		ttyprintf(tp, "%d.%02ds ",
176749907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176849907Sbostic 
176949907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
177049907Sbostic 		/* Print percentage cpu, resident set size. */
177149907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
177249907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
177352485Storek 		    tmp / 100,
177452485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
177552485Storek 			pgtok(pick->p_vmspace->vm_rssize));
177641177Smarc 	}
177749907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
177841177Smarc }
177941177Smarc 
178041177Smarc /*
178141177Smarc  * Returns 1 if p2 is "better" than p1
178241177Smarc  *
178341177Smarc  * The algorithm for picking the "interesting" process is thus:
178441177Smarc  *
178541177Smarc  *	1) (Only foreground processes are eligable - implied)
178641177Smarc  *	2) Runnable processes are favored over anything
178741177Smarc  *	   else.  The runner with the highest cpu
178841177Smarc  *	   utilization is picked (p_cpu).  Ties are
178941177Smarc  *	   broken by picking the highest pid.
179041177Smarc  *	3  Next, the sleeper with the shortest sleep
179141177Smarc  *	   time is favored.  With ties, we pick out
179241177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
179341177Smarc  *	   Further ties are broken by picking the highest
179441177Smarc  *	   pid.
179541177Smarc  *
179641177Smarc  */
179741177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179845723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179945723Smckusick #define ONLYA   2
180045723Smckusick #define ONLYB   1
180145723Smckusick #define BOTH    3
180245723Smckusick 
180349907Sbostic static int
180441177Smarc proc_compare(p1, p2)
180541177Smarc 	register struct proc *p1, *p2;
180641177Smarc {
180741177Smarc 
180841177Smarc 	if (p1 == NULL)
180941177Smarc 		return (1);
181041177Smarc 	/*
181141177Smarc 	 * see if at least one of them is runnable
181241177Smarc 	 */
181345723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
181445723Smckusick 	case ONLYA:
181545723Smckusick 		return (0);
181645723Smckusick 	case ONLYB:
181741177Smarc 		return (1);
181845723Smckusick 	case BOTH:
181941177Smarc 		/*
182041177Smarc 		 * tie - favor one with highest recent cpu utilization
182141177Smarc 		 */
182241177Smarc 		if (p2->p_cpu > p1->p_cpu)
182341177Smarc 			return (1);
182441177Smarc 		if (p1->p_cpu > p2->p_cpu)
182541177Smarc 			return (0);
182641177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
182741177Smarc 	}
182845723Smckusick 	/*
182945723Smckusick  	 * weed out zombies
183045723Smckusick 	 */
183145723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
183245723Smckusick 	case ONLYA:
183345723Smckusick 		return (1);
183445723Smckusick 	case ONLYB:
183545723Smckusick 		return (0);
183645723Smckusick 	case BOTH:
183745723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183845723Smckusick 	}
183941177Smarc 	/*
184041177Smarc 	 * pick the one with the smallest sleep time
184141177Smarc 	 */
184241177Smarc 	if (p2->p_slptime > p1->p_slptime)
184341177Smarc 		return (0);
184441177Smarc 	if (p1->p_slptime > p2->p_slptime)
184541177Smarc 		return (1);
184641177Smarc 	/*
184741177Smarc 	 * favor one sleeping in a non-interruptible sleep
184841177Smarc 	 */
184941177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
185041177Smarc 		return (1);
185141177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
185241177Smarc 		return (0);
185347545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
185441177Smarc }
185545723Smckusick 
185639555Smarc /*
185739555Smarc  * Output char to tty; console putchar style.
185839555Smarc  */
185939555Smarc tputchar(c, tp)
186039555Smarc 	int c;
186139555Smarc 	struct tty *tp;
186239555Smarc {
186339555Smarc 	register s = spltty();
186439555Smarc 
186547545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
186639555Smarc 		if (c == '\n')
186739555Smarc 			(void) ttyoutput('\r', tp);
186839555Smarc 		(void) ttyoutput(c, tp);
186939555Smarc 		ttstart(tp);
187039555Smarc 		splx(s);
187139555Smarc 		return (0);
187239555Smarc 	}
187339555Smarc 	splx(s);
187439555Smarc 	return (-1);
187539555Smarc }
187643377Smarc 
187744419Smarc /*
187849380Skarels  * Sleep on chan, returning ERESTART if tty changed
187949380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
188049380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
188149380Skarels  * call will redo validation done at the start of the call.
188244419Smarc  */
188343377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188443377Smarc 	struct tty *tp;
188543377Smarc 	caddr_t chan;
188643377Smarc 	int pri;
188743377Smarc 	char *wmesg;
188843377Smarc 	int timo;
188943377Smarc {
189043377Smarc 	int error;
189143377Smarc 	short gen = tp->t_gen;
189243377Smarc 
189343377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
189443377Smarc 		return (error);
189543377Smarc 	if (tp->t_gen != gen)
189643377Smarc 		return (ERESTART);
189743377Smarc 	return (0);
189843377Smarc }
1899