xref: /csrg-svn/sys/kern/tty.c (revision 49594)
1*49594Sbostic /*-
2*49594Sbostic  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3*49594Sbostic  * Copyright (c) 1991 The Regents of the University of California.
4*49594Sbostic  * All rights reserved.
523387Smckusick  *
6*49594Sbostic  * %sccs.include.redist.c%
7*49594Sbostic  *
8*49594Sbostic  *	@(#)tty.c	7.42 (Berkeley) 05/09/91
923387Smckusick  */
1039Sbill 
1117095Sbloom #include "param.h"
1217095Sbloom #include "systm.h"
1317095Sbloom #include "ioctl.h"
1439407Smarc #define TTYDEFCHARS
1517095Sbloom #include "tty.h"
1635811Smarc #undef TTYDEFCHARS
1717095Sbloom #include "proc.h"
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 
2840712Skarels /* symbolic sleep message strings */
2940712Skarels char ttyin[] = "ttyin";
3040712Skarels char ttyout[] = "ttyout";
3141370Smarc char ttopen[] = "ttyopn";
3241370Smarc char ttclos[] = "ttycls";
3340712Skarels char ttybg[] = "ttybg";
3440712Skarels char ttybuf[] = "ttybuf";
3540712Skarels 
367436Skre /*
377436Skre  * Table giving parity for characters and indicating
3835811Smarc  * character classes to tty driver. The 8th bit
3935811Smarc  * indicates parity, the 7th bit indicates the character
4035811Smarc  * is an alphameric or underscore (for ALTWERASE), and the
4135811Smarc  * low 6 bits indicate delay type.  If the low 6 bits are 0
4249380Skarels  * then the character needs no special processing on output;
4349380Skarels  * classes other than 0 might be translated or (not currently)
4449380Skarels  * require delays.
457436Skre  */
4649380Skarels #define	PARITY(c)	(partab[c] & 0x80)
4749380Skarels #define	ISALPHA(c)	(partab[(c)&TTY_CHARMASK] & 0x40)
4849380Skarels #define	CCLASSMASK	0x3f
4949380Skarels #define	CCLASS(c)	(partab[c] & CCLASSMASK)
5039Sbill 
5149380Skarels #define	E	0x00	/* even parity */
5249380Skarels #define	O	0x80	/* odd parity */
5349380Skarels #define	ALPHA	0x40	/* alpha or underscore */
5449380Skarels 
5549380Skarels #define	NO	ORDINARY
5649380Skarels #define	NA	ORDINARY|ALPHA
5749380Skarels #define	CC	CONTROL
5849380Skarels #define	BS	BACKSPACE
5949380Skarels #define	NL	NEWLINE
6049380Skarels #define	TB	TAB
6149380Skarels #define	VT	VTAB
6249380Skarels #define	CR	RETURN
6349380Skarels 
647436Skre char partab[] = {
6549380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
6649380Skarels 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
6749380Skarels 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
6849380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
6949380Skarels 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7049380Skarels 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7149380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
7249380Skarels 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
7349380Skarels 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
7449380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
7549380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
7649380Skarels 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
7749380Skarels 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
7849380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
7949380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8049380Skarels 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
817436Skre 	/*
8249380Skarels 	 * "meta" chars; should be settable per charset.
8349380Skarels 	 * For now, treat all as normal characters.
847436Skre 	 */
8549380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
8649380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
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,
1017436Skre };
10249380Skarels #undef	NO
10349380Skarels #undef	NA
10449380Skarels #undef	CC
10549380Skarels #undef	BS
10649380Skarels #undef	NL
10749380Skarels #undef	TB
10849380Skarels #undef	VT
10949380Skarels #undef	CR
1107436Skre 
11135811Smarc extern struct tty *constty;		/* temporary virtual console */
11235811Smarc 
113146Sbill /*
11435811Smarc  * Is 'c' a line delimiter ("break" character)?
11539Sbill  */
11640712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \
11740712Skarels 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
11839Sbill 
11939Sbill ttychars(tp)
1209578Ssam 	struct tty *tp;
12139Sbill {
12247545Skarels 
12335811Smarc 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
12439Sbill }
12539Sbill 
12639Sbill /*
12749380Skarels  * Flush tty after output has drained.
12839Sbill  */
12912752Ssam ttywflush(tp)
13037584Smarc 	struct tty *tp;
13139Sbill {
13240712Skarels 	int error;
13339Sbill 
13440712Skarels 	if ((error = ttywait(tp)) == 0)
13540712Skarels 		ttyflush(tp, FREAD);
13640712Skarels 	return (error);
13712752Ssam }
13812752Ssam 
13935811Smarc /*
14035811Smarc  * Wait for output to drain.
14135811Smarc  */
14212752Ssam ttywait(tp)
14312752Ssam 	register struct tty *tp;
14412752Ssam {
14540712Skarels 	int error = 0, s = spltty();
14612752Ssam 
14713809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
14837584Smarc 	    (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
14937584Smarc 	    tp->t_oproc) {
150903Sbill 		(*tp->t_oproc)(tp);
1515408Swnj 		tp->t_state |= TS_ASLEEP;
15243377Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_outq,
15343377Smarc 		    TTOPRI | PCATCH, ttyout, 0))
15440712Skarels 			break;
155903Sbill 	}
1569859Ssam 	splx(s);
15740712Skarels 	return (error);
15839Sbill }
15939Sbill 
16049380Skarels #define	flushq(qq) { \
16149380Skarels 	register struct clist *q = qq; \
16249380Skarels 	if (q->c_cc) \
16349380Skarels 		ndflush(q, q->c_cc); \
16449380Skarels }
16549380Skarels 
16639Sbill /*
16749380Skarels  * Flush TTY read and/or write queues,
16849380Skarels  * notifying anyone waiting.
16939Sbill  */
17012752Ssam ttyflush(tp, rw)
1717625Ssam 	register struct tty *tp;
17239Sbill {
173903Sbill 	register s;
174903Sbill 
17517545Skarels 	s = spltty();
176903Sbill 	if (rw & FREAD) {
17749380Skarels 		flushq(&tp->t_canq);
17849380Skarels 		flushq(&tp->t_rawq);
17949380Skarels 		tp->t_rocount = 0;
18049380Skarels 		tp->t_rocol = 0;
18149380Skarels 		tp->t_state &= ~TS_LOCAL;
18237584Smarc 		ttwakeup(tp);
183903Sbill 	}
184903Sbill 	if (rw & FWRITE) {
1855408Swnj 		tp->t_state &= ~TS_TTSTOP;
1865426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
18749380Skarels 		flushq(&tp->t_outq);
18849380Skarels 		wakeup((caddr_t)&tp->t_outq);
18949380Skarels 		if (tp->t_wsel) {
19049380Skarels 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
19149380Skarels 			tp->t_wsel = 0;
19249380Skarels 			tp->t_state &= ~TS_WCOLL;
19349380Skarels 		}
194903Sbill 	}
195903Sbill 	splx(s);
19639Sbill }
19739Sbill 
198903Sbill /*
199903Sbill  * Send stop character on input overflow.
200903Sbill  */
201903Sbill ttyblock(tp)
2027625Ssam 	register struct tty *tp;
20339Sbill {
204903Sbill 	register x;
2059578Ssam 
206903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
207903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
20812752Ssam 		ttyflush(tp, FREAD|FWRITE);
2095408Swnj 		tp->t_state &= ~TS_TBLOCK;
210903Sbill 	}
21115118Skarels 	/*
21215118Skarels 	 * Block further input iff:
21315118Skarels 	 * Current input > threshold AND input is available to user program
21415118Skarels 	 */
21542350Smckusick 	if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
21640712Skarels 	    ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) &&
21735811Smarc 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
21842350Smckusick 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
21915118Skarels 			tp->t_state |= TS_TBLOCK;
22015118Skarels 			ttstart(tp);
22115118Skarels 		}
222903Sbill 	}
22339Sbill }
22439Sbill 
22547545Skarels ttstart(tp)
22637584Smarc 	struct tty *tp;
227121Sbill {
228121Sbill 
22947545Skarels 	if (tp->t_oproc)		/* kludge for pty */
23047545Skarels 		(*tp->t_oproc)(tp);
23147545Skarels }
23247545Skarels 
23347545Skarels ttrstrt(tp)				/* XXX */
23447545Skarels 	struct tty *tp;
23547545Skarels {
23647545Skarels 
23740712Skarels #ifdef DIAGNOSTIC
2389578Ssam 	if (tp == 0)
2399578Ssam 		panic("ttrstrt");
24040712Skarels #endif
2415408Swnj 	tp->t_state &= ~TS_TIMEOUT;
242903Sbill 	ttstart(tp);
243121Sbill }
244121Sbill 
24539Sbill 
24639Sbill /*
24749380Skarels  * Common code for ioctls on tty devices.
24849380Skarels  * Called after line-discipline-specific ioctl
24949380Skarels  * has been called to do discipline-specific functions
25049380Skarels  * and/or reject any of these ioctl commands.
25139Sbill  */
2521780Sbill /*ARGSUSED*/
2537625Ssam ttioctl(tp, com, data, flag)
2547625Ssam 	register struct tty *tp;
2557625Ssam 	caddr_t data;
25639Sbill {
25747545Skarels 	register struct proc *p = curproc;		/* XXX */
25839Sbill 	extern int nldisp;
25937554Smckusick 	int s, error;
26039Sbill 
261903Sbill 	/*
262903Sbill 	 * If the ioctl involves modification,
26317545Skarels 	 * hang if in the background.
264903Sbill 	 */
2657625Ssam 	switch (com) {
26639Sbill 
26735811Smarc 	case TIOCSETD:
268903Sbill 	case TIOCFLUSH:
26935811Smarc 	/*case TIOCSPGRP:*/
2709325Ssam 	case TIOCSTI:
27117598Sbloom 	case TIOCSWINSZ:
27235811Smarc 	case TIOCSETA:
27335811Smarc 	case TIOCSETAW:
27435811Smarc 	case TIOCSETAF:
27540030Smarc #ifdef COMPAT_43
27640030Smarc 	case TIOCSETP:
27740030Smarc 	case TIOCSETN:
27840030Smarc 	case TIOCSETC:
27940030Smarc 	case TIOCSLTC:
28040030Smarc 	case TIOCLBIS:
28140030Smarc 	case TIOCLBIC:
28240030Smarc 	case TIOCLSET:
28340030Smarc 	case OTIOCSETD:
28440030Smarc #endif
28547545Skarels 		while (isbackground(curproc, tp) &&
28647545Skarels 		   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
28747545Skarels 		   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
28847545Skarels 		   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
28947545Skarels 			pgsignal(p->p_pgrp, SIGTTOU, 1);
29043377Smarc 			if (error = ttysleep(tp, (caddr_t)&lbolt,
29143377Smarc 			    TTOPRI | PCATCH, ttybg, 0))
29240712Skarels 				return (error);
293903Sbill 		}
294903Sbill 		break;
295903Sbill 	}
296903Sbill 
2979578Ssam 	/*
2989578Ssam 	 * Process the ioctl.
2999578Ssam 	 */
3007625Ssam 	switch (com) {
301903Sbill 
3028556Sroot 	/* get discipline number */
30339Sbill 	case TIOCGETD:
3047625Ssam 		*(int *)data = tp->t_line;
30539Sbill 		break;
30639Sbill 
3078556Sroot 	/* set line discipline */
3087625Ssam 	case TIOCSETD: {
3097625Ssam 		register int t = *(int *)data;
31035811Smarc 		dev_t dev = tp->t_dev;
3117625Ssam 
31235811Smarc 		if ((unsigned)t >= nldisp)
31310851Ssam 			return (ENXIO);
31425584Skarels 		if (t != tp->t_line) {
31525584Skarels 			s = spltty();
31625584Skarels 			(*linesw[tp->t_line].l_close)(tp);
31725584Skarels 			error = (*linesw[t].l_open)(dev, tp);
31825584Skarels 			if (error) {
31935811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
32025584Skarels 				splx(s);
32125584Skarels 				return (error);
32225584Skarels 			}
32325584Skarels 			tp->t_line = t;
32410851Ssam 			splx(s);
32510851Ssam 		}
32639Sbill 		break;
3277625Ssam 	}
32839Sbill 
3298556Sroot 	/* prevent more opens on channel */
3305614Swnj 	case TIOCEXCL:
3315614Swnj 		tp->t_state |= TS_XCLUDE;
3325614Swnj 		break;
3335614Swnj 
3345614Swnj 	case TIOCNXCL:
3355614Swnj 		tp->t_state &= ~TS_XCLUDE;
3365614Swnj 		break;
3375614Swnj 
33839Sbill 	case TIOCHPCL:
33935811Smarc 		tp->t_cflag |= HUPCL;
34039Sbill 		break;
34139Sbill 
3423942Sbugs 	case TIOCFLUSH: {
3437625Ssam 		register int flags = *(int *)data;
3447625Ssam 
3457625Ssam 		if (flags == 0)
3463942Sbugs 			flags = FREAD|FWRITE;
3477625Ssam 		else
3487625Ssam 			flags &= FREAD|FWRITE;
34912752Ssam 		ttyflush(tp, flags);
35039Sbill 		break;
3513944Sbugs 	}
35239Sbill 
35337584Smarc 	case FIOASYNC:
35437584Smarc 		if (*(int *)data)
35537584Smarc 			tp->t_state |= TS_ASYNC;
35637584Smarc 		else
35737584Smarc 			tp->t_state &= ~TS_ASYNC;
35837584Smarc 		break;
35937584Smarc 
36037584Smarc 	case FIONBIO:
36137584Smarc 		break;	/* XXX remove */
36237584Smarc 
3638556Sroot 	/* return number of characters immediately available */
3647625Ssam 	case FIONREAD:
3657625Ssam 		*(off_t *)data = ttnread(tp);
366174Sbill 		break;
367174Sbill 
36813077Ssam 	case TIOCOUTQ:
36913077Ssam 		*(int *)data = tp->t_outq.c_cc;
37013077Ssam 		break;
37113077Ssam 
3728589Sroot 	case TIOCSTOP:
37317545Skarels 		s = spltty();
3749578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3755573Swnj 			tp->t_state |= TS_TTSTOP;
3765573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3775573Swnj 		}
3787625Ssam 		splx(s);
3795573Swnj 		break;
3805573Swnj 
3818589Sroot 	case TIOCSTART:
38217545Skarels 		s = spltty();
38335811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
3845573Swnj 			tp->t_state &= ~TS_TTSTOP;
38535811Smarc 			tp->t_lflag &= ~FLUSHO;
3865573Swnj 			ttstart(tp);
3875573Swnj 		}
3887625Ssam 		splx(s);
3895573Swnj 		break;
3905573Swnj 
3919325Ssam 	/*
3929325Ssam 	 * Simulate typing of a character at the terminal.
3939325Ssam 	 */
3949325Ssam 	case TIOCSTI:
39547545Skarels 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
39617183Smckusick 			return (EPERM);
39747545Skarels 		if (p->p_ucred->cr_uid && !isctty(p, tp))
3989325Ssam 			return (EACCES);
3999578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4009325Ssam 		break;
4019325Ssam 
40235811Smarc 	case TIOCGETA: {
40335811Smarc 		struct termios *t = (struct termios *)data;
40412752Ssam 
40535811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
40635811Smarc 		break;
40735811Smarc 	}
40835811Smarc 
40935811Smarc 	case TIOCSETA:
41035811Smarc 	case TIOCSETAW:
41137584Smarc 	case TIOCSETAF: {
41235811Smarc 		register struct termios *t = (struct termios *)data;
41340712Skarels 
41417545Skarels 		s = spltty();
41539407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
41640712Skarels 			if (error = ttywait(tp)) {
41740712Skarels 				splx(s);
41840712Skarels 				return (error);
41940712Skarels 			}
42045007Smarc 			if (com == TIOCSETAF)
42139407Smarc 				ttyflush(tp, FREAD);
42239407Smarc 		}
42340712Skarels 		if ((t->c_cflag&CIGNORE) == 0) {
42435811Smarc 			/*
42535811Smarc 			 * set device hardware
42635811Smarc 			 */
42737584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
42837584Smarc 				splx(s);
42935811Smarc 				return (error);
43037584Smarc 			} else {
43140712Skarels 				if ((tp->t_state&TS_CARR_ON) == 0 &&
43237584Smarc 				    (tp->t_cflag&CLOCAL) &&
43340712Skarels 				    (t->c_cflag&CLOCAL) == 0) {
43437584Smarc 					tp->t_state &= ~TS_ISOPEN;
43537584Smarc 					tp->t_state |= TS_WOPEN;
43637584Smarc 					ttwakeup(tp);
43737584Smarc 				}
43835811Smarc 				tp->t_cflag = t->c_cflag;
43935811Smarc 				tp->t_ispeed = t->c_ispeed;
44035811Smarc 				tp->t_ospeed = t->c_ospeed;
44134492Skarels 			}
44235811Smarc 			ttsetwater(tp);
44312752Ssam 		}
44439407Smarc 		if (com != TIOCSETAF) {
44535811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
44635811Smarc 				if (t->c_lflag&ICANON) {
44735811Smarc 					tp->t_lflag |= PENDIN;
44835811Smarc 					ttwakeup(tp);
44935811Smarc 				}
45035811Smarc 				else {
45135811Smarc 					struct clist tq;
45235811Smarc 
45335811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
45435811Smarc 					tq = tp->t_rawq;
45535811Smarc 					tp->t_rawq = tp->t_canq;
45635811Smarc 					tp->t_canq = tq;
45735811Smarc 				}
45812752Ssam 		}
45935811Smarc 		tp->t_iflag = t->c_iflag;
46035811Smarc 		tp->t_oflag = t->c_oflag;
46142882Smarc 		/*
46242882Smarc 		 * Make the EXTPROC bit read only.
46342882Smarc 		 */
46442882Smarc 		if (tp->t_lflag&EXTPROC)
46542882Smarc 			t->c_lflag |= EXTPROC;
46642882Smarc 		else
46742882Smarc 			t->c_lflag &= ~EXTPROC;
46835811Smarc 		tp->t_lflag = t->c_lflag;
46935811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
47012752Ssam 		splx(s);
47112752Ssam 		break;
47212752Ssam 	}
47312752Ssam 
47412752Ssam 	/*
47539555Smarc 	 * Set controlling terminal.
47639555Smarc 	 * Session ctty vnode pointer set in vnode layer.
47734492Skarels 	 */
47847545Skarels 	case TIOCSCTTY:
47939555Smarc 		if (!SESS_LEADER(p) ||
48039555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
48139555Smarc 		   (tp->t_session != p->p_session))
48239407Smarc 			return (EPERM);
48335811Smarc 		tp->t_session = p->p_session;
48439555Smarc 		tp->t_pgrp = p->p_pgrp;
48539555Smarc 		p->p_session->s_ttyp = tp;
48639555Smarc 		p->p_flag |= SCTTY;
48734492Skarels 		break;
48839555Smarc 
48934492Skarels 	/*
49035811Smarc 	 * Set terminal process group.
49117545Skarels 	 */
49218650Sbloom 	case TIOCSPGRP: {
49335811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
49417545Skarels 
49539555Smarc 		if (!isctty(p, tp))
49639555Smarc 			return (ENOTTY);
49740030Smarc 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
49839555Smarc 			return (EPERM);
49939555Smarc 		tp->t_pgrp = pgrp;
50012752Ssam 		break;
50118650Sbloom 	}
50212752Ssam 
50312752Ssam 	case TIOCGPGRP:
50447545Skarels 		if (!isctty(p, tp))
50539555Smarc 			return (ENOTTY);
50645007Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
50712752Ssam 		break;
50812752Ssam 
50917598Sbloom 	case TIOCSWINSZ:
51018650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
51118650Sbloom 		    sizeof (struct winsize))) {
51217598Sbloom 			tp->t_winsize = *(struct winsize *)data;
51342882Smarc 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
51417598Sbloom 		}
51517598Sbloom 		break;
51617598Sbloom 
51717598Sbloom 	case TIOCGWINSZ:
51817598Sbloom 		*(struct winsize *)data = tp->t_winsize;
51917598Sbloom 		break;
52017598Sbloom 
52130534Skarels 	case TIOCCONS:
52230534Skarels 		if (*(int *)data) {
52342141Smckusick 			if (constty && constty != tp &&
52442141Smckusick 			    (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
52542141Smckusick 			    (TS_CARR_ON|TS_ISOPEN))
52630534Skarels 				return (EBUSY);
52730534Skarels #ifndef	UCONSOLE
52847545Skarels 			if (error = suser(p->p_ucred, &p->p_acflag))
52937554Smckusick 				return (error);
53030534Skarels #endif
53130534Skarels 			constty = tp;
53230534Skarels 		} else if (tp == constty)
53333404Skarels 			constty = NULL;
53430534Skarels 		break;
53530534Skarels 
53648439Skarels 	case TIOCDRAIN:
53748439Skarels 		if (error = ttywait(tp))
53848439Skarels 			return (error);
53948439Skarels 		break;
54048439Skarels 
54147545Skarels 	default:
54235811Smarc #ifdef COMPAT_43
54347545Skarels 		return (ttcompat(tp, com, data, flag));
54447545Skarels #else
54547545Skarels 		return (-1);
54635811Smarc #endif
54739Sbill 	}
5488556Sroot 	return (0);
54939Sbill }
5504484Swnj 
5514484Swnj ttnread(tp)
5524484Swnj 	struct tty *tp;
5534484Swnj {
5544484Swnj 	int nread = 0;
5554484Swnj 
55635811Smarc 	if (tp->t_lflag & PENDIN)
5574484Swnj 		ttypend(tp);
5584484Swnj 	nread = tp->t_canq.c_cc;
55935811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5604484Swnj 		nread += tp->t_rawq.c_cc;
5614484Swnj 	return (nread);
5624484Swnj }
5634484Swnj 
5645408Swnj ttselect(dev, rw)
5654484Swnj 	dev_t dev;
5665408Swnj 	int rw;
5674484Swnj {
5684484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5694484Swnj 	int nread;
57017545Skarels 	int s = spltty();
5714484Swnj 
5725408Swnj 	switch (rw) {
5734484Swnj 
5744484Swnj 	case FREAD:
5754484Swnj 		nread = ttnread(tp);
57637584Smarc 		if (nread > 0 ||
57740712Skarels 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
5785408Swnj 			goto win;
5794938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5805408Swnj 			tp->t_state |= TS_RCOLL;
5814484Swnj 		else
58247545Skarels 			tp->t_rsel = curproc;
5835408Swnj 		break;
5844484Swnj 
5855408Swnj 	case FWRITE:
58635811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
5875408Swnj 			goto win;
5885408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5895408Swnj 			tp->t_state |= TS_WCOLL;
5905408Swnj 		else
59147545Skarels 			tp->t_wsel = curproc;
5925408Swnj 		break;
5934484Swnj 	}
5945408Swnj 	splx(s);
5955408Swnj 	return (0);
5965408Swnj win:
5975408Swnj 	splx(s);
5985408Swnj 	return (1);
5994484Swnj }
6007436Skre 
6017502Sroot /*
60249380Skarels  * Initial open of tty, or (re)entry to standard tty line discipline.
6037502Sroot  */
6047502Sroot ttyopen(dev, tp)
6057625Ssam 	dev_t dev;
6067625Ssam 	register struct tty *tp;
6077502Sroot {
6087502Sroot 
6097502Sroot 	tp->t_dev = dev;
61035811Smarc 
6117502Sroot 	tp->t_state &= ~TS_WOPEN;
61217545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
61317545Skarels 		tp->t_state |= TS_ISOPEN;
61417598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
61517545Skarels 	}
6168556Sroot 	return (0);
6177502Sroot }
6187502Sroot 
6197502Sroot /*
62025391Skarels  * "close" a line discipline
62125391Skarels  */
62225391Skarels ttylclose(tp)
62325391Skarels 	register struct tty *tp;
62425391Skarels {
62525391Skarels 
62625391Skarels 	ttywflush(tp);
62725391Skarels }
62825391Skarels 
62925391Skarels /*
63049380Skarels  * Handle close() on a tty line: flush and set to initial state,
63149380Skarels  * bumping generation number so that pending read/write calls
63249380Skarels  * can detect recycling of the tty.
6337502Sroot  */
6347502Sroot ttyclose(tp)
6357625Ssam 	register struct tty *tp;
6367502Sroot {
63730534Skarels 	if (constty == tp)
63830534Skarels 		constty = NULL;
63925391Skarels 	ttyflush(tp, FREAD|FWRITE);
64039555Smarc 	tp->t_session = NULL;
64139555Smarc 	tp->t_pgrp = NULL;
6427502Sroot 	tp->t_state = 0;
64343377Smarc 	tp->t_gen++;
64440712Skarels 	return (0);
6457502Sroot }
6467502Sroot 
6477502Sroot /*
64825391Skarels  * Handle modem control transition on a tty.
64925391Skarels  * Flag indicates new state of carrier.
65025391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
65125391Skarels  */
65225391Skarels ttymodem(tp, flag)
65325391Skarels 	register struct tty *tp;
65425391Skarels {
65525391Skarels 
65642193Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
65725391Skarels 		/*
65825391Skarels 		 * MDMBUF: do flow control according to carrier flag
65925391Skarels 		 */
66025391Skarels 		if (flag) {
66125391Skarels 			tp->t_state &= ~TS_TTSTOP;
66225391Skarels 			ttstart(tp);
66325391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
66425391Skarels 			tp->t_state |= TS_TTSTOP;
66525391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
66625391Skarels 		}
66725391Skarels 	} else if (flag == 0) {
66825391Skarels 		/*
66925391Skarels 		 * Lost carrier.
67025391Skarels 		 */
67125391Skarels 		tp->t_state &= ~TS_CARR_ON;
67242193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
67342193Smarc 			if (tp->t_session && tp->t_session->s_leader)
67442193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
67542193Smarc 			ttyflush(tp, FREAD|FWRITE);
67642193Smarc 			return (0);
67725391Skarels 		}
67825391Skarels 	} else {
67925391Skarels 		/*
68025391Skarels 		 * Carrier now on.
68125391Skarels 		 */
68225391Skarels 		tp->t_state |= TS_CARR_ON;
68337584Smarc 		ttwakeup(tp);
68425391Skarels 	}
68525391Skarels 	return (1);
68625391Skarels }
68725391Skarels 
68825391Skarels /*
68925404Skarels  * Default modem control routine (for other line disciplines).
69025404Skarels  * Return argument flag, to turn off device on carrier drop.
69125404Skarels  */
69225415Skarels nullmodem(tp, flag)
69325415Skarels 	register struct tty *tp;
69425404Skarels 	int flag;
69525404Skarels {
69625404Skarels 
69725404Skarels 	if (flag)
69825404Skarels 		tp->t_state |= TS_CARR_ON;
69939407Smarc 	else {
70025404Skarels 		tp->t_state &= ~TS_CARR_ON;
70142193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
70242193Smarc 			if (tp->t_session && tp->t_session->s_leader)
70342193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
70442193Smarc 			return (0);
70542193Smarc 		}
70639407Smarc 	}
70742193Smarc 	return (1);
70825404Skarels }
70925404Skarels 
71025404Skarels /*
7117502Sroot  * reinput pending characters after state switch
71217545Skarels  * call at spltty().
7137502Sroot  */
7147502Sroot ttypend(tp)
7157625Ssam 	register struct tty *tp;
7167502Sroot {
7177502Sroot 	struct clist tq;
7187502Sroot 	register c;
7197502Sroot 
72035811Smarc 	tp->t_lflag &= ~PENDIN;
7219578Ssam 	tp->t_state |= TS_TYPEN;
7227502Sroot 	tq = tp->t_rawq;
7237502Sroot 	tp->t_rawq.c_cc = 0;
7247502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7257502Sroot 	while ((c = getc(&tq)) >= 0)
7267502Sroot 		ttyinput(c, tp);
7279578Ssam 	tp->t_state &= ~TS_TYPEN;
7287502Sroot }
7297502Sroot 
7307502Sroot /*
73149380Skarels  * Process input of a single character received on a tty.
7327502Sroot  */
7337502Sroot ttyinput(c, tp)
7347625Ssam 	register c;
7357625Ssam 	register struct tty *tp;
7367502Sroot {
73735811Smarc 	register int iflag = tp->t_iflag;
73835811Smarc 	register int lflag = tp->t_lflag;
73935811Smarc 	register u_char *cc = tp->t_cc;
74035811Smarc 	int i, err;
7417502Sroot 
7429578Ssam 	/*
7439578Ssam 	 * If input is pending take it first.
7449578Ssam 	 */
74535811Smarc 	if (lflag&PENDIN)
7467502Sroot 		ttypend(tp);
74735811Smarc 	/*
74835811Smarc 	 * Gather stats.
74935811Smarc 	 */
7507502Sroot 	tk_nin++;
75135811Smarc 	if (lflag&ICANON) {
75235811Smarc 		tk_cancc++;
75335811Smarc 		tp->t_cancc++;
75435811Smarc 	} else {
75535811Smarc 		tk_rawcc++;
75635811Smarc 		tp->t_rawcc++;
75735811Smarc 	}
7589578Ssam 	/*
75935811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7609578Ssam 	 */
76135811Smarc 	if (err = (c&TTY_ERRORMASK)) {
76235811Smarc 		c &= ~TTY_ERRORMASK;
76335811Smarc 		if (err&TTY_FE && !c) {		/* break */
76435811Smarc 			if (iflag&IGNBRK)
76535811Smarc 				goto endcase;
76635811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
76735811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
76835811Smarc 				c = cc[VINTR];
76947545Skarels 			else if (iflag&PARMRK)
77047545Skarels 				goto parmrk;
77135811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
77235811Smarc 			if (iflag&IGNPAR)
77335811Smarc 				goto endcase;
77435811Smarc 			else if (iflag&PARMRK) {
77535811Smarc parmrk:
77635811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
77735811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
77835811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
77935811Smarc 				goto endcase;
78035811Smarc 			} else
78135811Smarc 				c = 0;
7827502Sroot 		}
7839578Ssam 	}
7849578Ssam 	/*
78535811Smarc 	 * In tandem mode, check high water mark.
7869578Ssam 	 */
78735811Smarc 	if (iflag&IXOFF)
78835811Smarc 		ttyblock(tp);
78935811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
79049380Skarels 		c &= ~0x80;
79144419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
79244419Smarc 		/*
79344419Smarc 		 * Check for literal nexting very first
79444419Smarc 		 */
79544419Smarc 		if (tp->t_state&TS_LNCH) {
79644419Smarc 			c |= TTY_QUOTE;
79744419Smarc 			tp->t_state &= ~TS_LNCH;
79844419Smarc 		}
79944419Smarc 		/*
80044419Smarc 		 * Scan for special characters.  This code
80144419Smarc 		 * is really just a big case statement with
80244419Smarc 		 * non-constant cases.  The bottom of the
80344419Smarc 		 * case statement is labeled ``endcase'', so goto
80444419Smarc 		 * it after a case match, or similar.
80544419Smarc 		 */
80644419Smarc 
80744419Smarc 		/*
80844419Smarc 		 * Control chars which aren't controlled
80944419Smarc 		 * by ICANON, ISIG, or IXON.
81044419Smarc 		 */
81144419Smarc 		if (lflag&IEXTEN) {
81244419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
81344419Smarc 				if (lflag&ECHO) {
81444419Smarc 					if (lflag&ECHOE)
81544419Smarc 						ttyoutstr("^\b", tp);
81644419Smarc 					else
81744419Smarc 						ttyecho(c, tp);
81844419Smarc 				}
81944419Smarc 				tp->t_state |= TS_LNCH;
82044419Smarc 				goto endcase;
82144419Smarc 			}
82244419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
82344419Smarc 				if (lflag&FLUSHO)
82444419Smarc 					tp->t_lflag &= ~FLUSHO;
82544419Smarc 				else {
82644419Smarc 					ttyflush(tp, FWRITE);
82735811Smarc 					ttyecho(c, tp);
82844419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
82944419Smarc 						ttyretype(tp);
83044419Smarc 					tp->t_lflag |= FLUSHO;
83144419Smarc 				}
83244419Smarc 				goto startoutput;
83335811Smarc 			}
8349578Ssam 		}
83544419Smarc 		/*
83644419Smarc 		 * Signals.
83744419Smarc 		 */
83844419Smarc 		if (lflag&ISIG) {
83944419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
84044419Smarc 				if ((lflag&NOFLSH) == 0)
84144419Smarc 					ttyflush(tp, FREAD|FWRITE);
8427502Sroot 				ttyecho(c, tp);
84344419Smarc 				pgsignal(tp->t_pgrp,
84444419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
84544419Smarc 				goto endcase;
8467502Sroot 			}
84744419Smarc 			if (CCEQ(cc[VSUSP], c)) {
84844419Smarc 				if ((lflag&NOFLSH) == 0)
84944419Smarc 					ttyflush(tp, FREAD);
85044419Smarc 				ttyecho(c, tp);
85144419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
85244419Smarc 				goto endcase;
85344419Smarc 			}
8549578Ssam 		}
85544419Smarc 		/*
85644419Smarc 		 * Handle start/stop characters.
85744419Smarc 		 */
85844419Smarc 		if (iflag&IXON) {
85944419Smarc 			if (CCEQ(cc[VSTOP], c)) {
86044419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
86144419Smarc 					tp->t_state |= TS_TTSTOP;
86244419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
86344419Smarc 					   0);
86444419Smarc 					return;
86544419Smarc 				}
86644419Smarc 				if (!CCEQ(cc[VSTART], c))
86744419Smarc 					return;
86844419Smarc 				/*
86944419Smarc 				 * if VSTART == VSTOP then toggle
87044419Smarc 				 */
87144419Smarc 				goto endcase;
87235811Smarc 			}
87344419Smarc 			if (CCEQ(cc[VSTART], c))
87444419Smarc 				goto restartoutput;
8759578Ssam 		}
87644419Smarc 		/*
87744419Smarc 		 * IGNCR, ICRNL, & INLCR
87844419Smarc 		 */
87944419Smarc 		if (c == '\r') {
88044419Smarc 			if (iflag&IGNCR)
88144419Smarc 				goto endcase;
88244419Smarc 			else if (iflag&ICRNL)
88344419Smarc 				c = '\n';
88444419Smarc 		} else if (c == '\n' && iflag&INLCR)
88544419Smarc 			c = '\r';
8869578Ssam 	}
88747545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
88844419Smarc 		/*
88944419Smarc 		 * From here on down canonical mode character
89044419Smarc 		 * processing takes place.
89144419Smarc 		 */
89244419Smarc 		/*
89344419Smarc 		 * erase (^H / ^?)
89444419Smarc 		 */
89544419Smarc 		if (CCEQ(cc[VERASE], c)) {
89644419Smarc 			if (tp->t_rawq.c_cc)
8979578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
89844419Smarc 			goto endcase;
8999578Ssam 		}
90044419Smarc 		/*
90144419Smarc 		 * kill (^U)
90244419Smarc 		 */
90344419Smarc 		if (CCEQ(cc[VKILL], c)) {
90444419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
90544419Smarc 			    (lflag&ECHOPRT) == 0) {
90644419Smarc 				while (tp->t_rawq.c_cc)
90744419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
90844419Smarc 			} else {
90944419Smarc 				ttyecho(c, tp);
91044419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
91144419Smarc 					ttyecho('\n', tp);
91244419Smarc 				while (getc(&tp->t_rawq) > 0)
91344419Smarc 					;
91444419Smarc 				tp->t_rocount = 0;
91544419Smarc 			}
91644419Smarc 			tp->t_state &= ~TS_LOCAL;
91744419Smarc 			goto endcase;
91844419Smarc 		}
91944419Smarc 		/*
92044419Smarc 		 * word erase (^W)
92144419Smarc 		 */
92244419Smarc 		if (CCEQ(cc[VWERASE], c)) {
92344419Smarc 			int ctype;
92447545Skarels 			int alt = lflag&ALTWERASE;
92535811Smarc 
92644419Smarc 			/*
92744419Smarc 			 * erase whitespace
92844419Smarc 			 */
92944419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
93044419Smarc 				ttyrub(c, tp);
93144419Smarc 			if (c == -1)
93244419Smarc 				goto endcase;
93344419Smarc 			/*
93447545Skarels 			 * erase last char of word and remember the
93547545Skarels 			 * next chars type (for ALTWERASE)
93644419Smarc 			 */
93735811Smarc 			ttyrub(c, tp);
93844419Smarc 			c = unputc(&tp->t_rawq);
93947545Skarels 			if (c == -1)
94044419Smarc 				goto endcase;
94149380Skarels 			ctype = ISALPHA(c);
94244419Smarc 			/*
94347545Skarels 			 * erase rest of word
94444419Smarc 			 */
94544419Smarc 			do {
94644419Smarc 				ttyrub(c, tp);
94744419Smarc 				c = unputc(&tp->t_rawq);
94844419Smarc 				if (c == -1)
94944419Smarc 					goto endcase;
95047545Skarels 			} while (c != ' ' && c != '\t' &&
95149380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
95244419Smarc 			(void) putc(c, &tp->t_rawq);
95334492Skarels 			goto endcase;
95444419Smarc 		}
95535811Smarc 		/*
95644419Smarc 		 * reprint line (^R)
95735811Smarc 		 */
95844419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
95944419Smarc 			ttyretype(tp);
96034492Skarels 			goto endcase;
96134492Skarels 		}
96235811Smarc 		/*
96344419Smarc 		 * ^T - kernel info and generate SIGINFO
96435811Smarc 		 */
96544419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
96644419Smarc 			pgsignal(tp->t_pgrp, SIGINFO, 1);
96744419Smarc 			if ((lflag&NOKERNINFO) == 0)
96844419Smarc 				ttyinfo(tp);
96944419Smarc 			goto endcase;
97044419Smarc 		}
9719578Ssam 	}
9729578Ssam 	/*
9739578Ssam 	 * Check for input buffer overflow
9749578Ssam 	 */
97547545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
97635811Smarc 		if (iflag&IMAXBEL) {
97735811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
97835811Smarc 				(void) ttyoutput(CTRL('g'), tp);
97935811Smarc 		} else
98035811Smarc 			ttyflush(tp, FREAD | FWRITE);
9819578Ssam 		goto endcase;
98210391Ssam 	}
9839578Ssam 	/*
9849578Ssam 	 * Put data char in q for user and
9859578Ssam 	 * wakeup on seeing a line delimiter.
9869578Ssam 	 */
9879578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
98847545Skarels 		if ((lflag&ICANON) == 0) {
98947545Skarels 			ttwakeup(tp);
99047545Skarels 			ttyecho(c, tp);
99147545Skarels 			goto endcase;
99247545Skarels 		}
99335811Smarc 		if (ttbreakc(c)) {
9949578Ssam 			tp->t_rocount = 0;
9959578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
9967502Sroot 			ttwakeup(tp);
9979578Ssam 		} else if (tp->t_rocount++ == 0)
9989578Ssam 			tp->t_rocol = tp->t_col;
9999578Ssam 		if (tp->t_state&TS_ERASE) {
100035811Smarc 			/*
100135811Smarc 			 * end of prterase \.../
100235811Smarc 			 */
10039578Ssam 			tp->t_state &= ~TS_ERASE;
10049578Ssam 			(void) ttyoutput('/', tp);
10059578Ssam 		}
10069578Ssam 		i = tp->t_col;
10077502Sroot 		ttyecho(c, tp);
100835811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
100935811Smarc 			/*
101035811Smarc 			 * Place the cursor over the '^' of the ^D.
101135811Smarc 			 */
10129578Ssam 			i = MIN(2, tp->t_col - i);
10139578Ssam 			while (i > 0) {
10149578Ssam 				(void) ttyoutput('\b', tp);
10159578Ssam 				i--;
10169578Ssam 			}
10179578Ssam 		}
10187502Sroot 	}
10199578Ssam endcase:
10209578Ssam 	/*
102135811Smarc 	 * IXANY means allow any character to restart output.
10229578Ssam 	 */
102340712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
102440712Skarels 	    cc[VSTART] != cc[VSTOP])
10257502Sroot 		return;
10269578Ssam restartoutput:
10277502Sroot 	tp->t_state &= ~TS_TTSTOP;
102835811Smarc 	tp->t_lflag &= ~FLUSHO;
10299578Ssam startoutput:
10307502Sroot 	ttstart(tp);
10317502Sroot }
10327502Sroot 
10337502Sroot /*
103449380Skarels  * Output a single character on a tty, doing output processing
103549380Skarels  * as needed (expanding tabs, newline processing, etc.).
103649380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10377502Sroot  * Must be recursive.
10387502Sroot  */
10397502Sroot ttyoutput(c, tp)
10407502Sroot 	register c;
10417502Sroot 	register struct tty *tp;
10427502Sroot {
104349380Skarels 	register int col;
104435811Smarc 	register long oflag = tp->t_oflag;
104535811Smarc 
104640712Skarels 	if ((oflag&OPOST) == 0) {
104735811Smarc 		if (tp->t_lflag&FLUSHO)
10487502Sroot 			return (-1);
10497502Sroot 		if (putc(c, &tp->t_outq))
10507625Ssam 			return (c);
10517502Sroot 		tk_nout++;
105235811Smarc 		tp->t_outcc++;
10537502Sroot 		return (-1);
10547502Sroot 	}
105535811Smarc 	c &= TTY_CHARMASK;
10567502Sroot 	/*
105749380Skarels 	 * Do tab expansion if OXTABS is set.
105842882Smarc 	 * Special case if we have external processing, we don't
105942882Smarc 	 * do the tab expansion because we'll probably get it
106042882Smarc 	 * wrong.  If tab expansion needs to be done, let it
106142882Smarc 	 * happen externally.
10627502Sroot 	 */
106347545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
10647502Sroot 		register int s;
10657502Sroot 
10667502Sroot 		c = 8 - (tp->t_col&7);
106735811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
106817545Skarels 			s = spltty();		/* don't interrupt tabs */
10697502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10707502Sroot 			tk_nout += c;
107135811Smarc 			tp->t_outcc += c;
10727502Sroot 			splx(s);
10737502Sroot 		}
10747502Sroot 		tp->t_col += c;
10757502Sroot 		return (c ? -1 : '\t');
10767502Sroot 	}
107735811Smarc 	if (c == CEOT && oflag&ONOEOT)
107847545Skarels 		return (-1);
10797502Sroot 	tk_nout++;
108035811Smarc 	tp->t_outcc++;
10817502Sroot 	/*
108249380Skarels 	 * Newline translation: if ONLCR is set,
108349380Skarels 	 * translate newline into "\r\n".
10847502Sroot 	 */
108535811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
10867502Sroot 		return (c);
108735811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
108835811Smarc 		return (c);
108947545Skarels 
109049380Skarels 	col = tp->t_col;
109149380Skarels 	switch (CCLASS(c)) {
10927502Sroot 
10937502Sroot 	case ORDINARY:
109449380Skarels 		col++;
10957502Sroot 
10967502Sroot 	case CONTROL:
10977502Sroot 		break;
10987502Sroot 
10997502Sroot 	case BACKSPACE:
110049380Skarels 		if (col > 0)
110149380Skarels 			col--;
11027502Sroot 		break;
11037502Sroot 
11047502Sroot 	case NEWLINE:
110549380Skarels 		col = 0;
11067502Sroot 		break;
11077502Sroot 
11087502Sroot 	case TAB:
110949380Skarels 		col = (col + 8) &~ 0x7;
11107502Sroot 		break;
11117502Sroot 
11127502Sroot 	case RETURN:
111349380Skarels 		col = 0;
11147502Sroot 	}
111549380Skarels 	tp->t_col = col;
11167502Sroot 	return (-1);
11177502Sroot }
11187502Sroot 
11197502Sroot /*
112049380Skarels  * Process a read call on a tty device.
11217502Sroot  */
112237584Smarc ttread(tp, uio, flag)
11237625Ssam 	register struct tty *tp;
11247722Swnj 	struct uio *uio;
11257502Sroot {
11267502Sroot 	register struct clist *qp;
112735811Smarc 	register int c;
112841383Smarc 	register long lflag;
112935811Smarc 	register u_char *cc = tp->t_cc;
113047545Skarels 	register struct proc *p = curproc;
11319859Ssam 	int s, first, error = 0;
11327502Sroot 
11337502Sroot loop:
113441383Smarc 	lflag = tp->t_lflag;
113537584Smarc 	s = spltty();
11369578Ssam 	/*
113737584Smarc 	 * take pending input first
11389578Ssam 	 */
113935811Smarc 	if (lflag&PENDIN)
11407502Sroot 		ttypend(tp);
11419859Ssam 	splx(s);
114240712Skarels 
11439578Ssam 	/*
11449578Ssam 	 * Hang process if it's in the background.
11459578Ssam 	 */
114647545Skarels 	if (isbackground(p, tp)) {
114747545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
114847545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
114947545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11508520Sroot 			return (EIO);
115147545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
115243377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
115343377Smarc 		    ttybg, 0))
115440712Skarels 			return (error);
115523165Sbloom 		goto loop;
11567502Sroot 	}
115740712Skarels 
11589578Ssam 	/*
115935811Smarc 	 * If canonical, use the canonical queue,
116035811Smarc 	 * else use the raw queue.
116137584Smarc 	 *
116247545Skarels 	 * (should get rid of clists...)
11639578Ssam 	 */
116435811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
116540712Skarels 
11669578Ssam 	/*
116740712Skarels 	 * If there is no input, sleep on rawq
116840712Skarels 	 * awaiting hardware receipt and notification.
116940712Skarels 	 * If we have data, we don't need to check for carrier.
11709578Ssam 	 */
117117545Skarels 	s = spltty();
11729578Ssam 	if (qp->c_cc <= 0) {
117340712Skarels 		int carrier;
117440712Skarels 
117540712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
117640712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
11779859Ssam 			splx(s);
117840712Skarels 			return (0);	/* EOF */
11797502Sroot 		}
118037728Smckusick 		if (flag & IO_NDELAY) {
118137584Smarc 			splx(s);
118237584Smarc 			return (EWOULDBLOCK);
118337584Smarc 		}
118443377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
118540712Skarels 		    carrier ? ttyin : ttopen, 0);
11869859Ssam 		splx(s);
118743377Smarc 		if (error)
118840712Skarels 			return (error);
11899578Ssam 		goto loop;
11909578Ssam 	}
11919859Ssam 	splx(s);
119240712Skarels 
11939578Ssam 	/*
119435811Smarc 	 * Input present, check for input mapping and processing.
11959578Ssam 	 */
11969578Ssam 	first = 1;
11979578Ssam 	while ((c = getc(qp)) >= 0) {
11989578Ssam 		/*
119935811Smarc 		 * delayed suspend (^Y)
12009578Ssam 		 */
120135811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
120242882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12039578Ssam 			if (first) {
120443377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
120543377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
120640712Skarels 					break;
12079578Ssam 				goto loop;
12089578Ssam 			}
12099578Ssam 			break;
12107502Sroot 		}
12119578Ssam 		/*
121235811Smarc 		 * Interpret EOF only in canonical mode.
12139578Ssam 		 */
121435811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12159578Ssam 			break;
12169578Ssam 		/*
12179578Ssam 		 * Give user character.
12189578Ssam 		 */
121940712Skarels  		error = ureadc(c, uio);
12209578Ssam 		if (error)
12219578Ssam 			break;
122214938Smckusick  		if (uio->uio_resid == 0)
12239578Ssam 			break;
12249578Ssam 		/*
122535811Smarc 		 * In canonical mode check for a "break character"
12269578Ssam 		 * marking the end of a "line of input".
12279578Ssam 		 */
122840712Skarels 		if (lflag&ICANON && ttbreakc(c))
12299578Ssam 			break;
12309578Ssam 		first = 0;
12317502Sroot 	}
12329578Ssam 	/*
12339578Ssam 	 * Look to unblock output now that (presumably)
12349578Ssam 	 * the input queue has gone down.
12359578Ssam 	 */
123635811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
123747545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
123847545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12397502Sroot 			tp->t_state &= ~TS_TBLOCK;
12407502Sroot 			ttstart(tp);
12417502Sroot 		}
124235811Smarc 	}
12438520Sroot 	return (error);
12447502Sroot }
12457502Sroot 
12467502Sroot /*
124725391Skarels  * Check the output queue on tp for space for a kernel message
124825391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
124925391Skarels  * hiwater mark so we don't lose messages due to normal flow
125025391Skarels  * control, but don't let the tty run amok.
125130695Skarels  * Sleeps here are not interruptible, but we return prematurely
125230695Skarels  * if new signals come in.
125325391Skarels  */
125425391Skarels ttycheckoutq(tp, wait)
125525391Skarels 	register struct tty *tp;
125625391Skarels 	int wait;
125725391Skarels {
125830695Skarels 	int hiwat, s, oldsig;
125948439Skarels 	extern int wakeup();
126025391Skarels 
126135811Smarc 	hiwat = tp->t_hiwat;
126225391Skarels 	s = spltty();
126347545Skarels 	oldsig = curproc->p_sig;
126425391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
126529946Skarels 		while (tp->t_outq.c_cc > hiwat) {
126629946Skarels 			ttstart(tp);
126747545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
126829946Skarels 				splx(s);
126929946Skarels 				return (0);
127029946Skarels 			}
127130695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
127229946Skarels 			tp->t_state |= TS_ASLEEP;
127330695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
127425391Skarels 		}
127525391Skarels 	splx(s);
127625391Skarels 	return (1);
127725391Skarels }
127825391Skarels 
127925391Skarels /*
128049380Skarels  * Process a write call on a tty device.
12817502Sroot  */
128237584Smarc ttwrite(tp, uio, flag)
12837625Ssam 	register struct tty *tp;
12849578Ssam 	register struct uio *uio;
12857502Sroot {
12867502Sroot 	register char *cp;
128740712Skarels 	register int cc = 0, ce;
128847545Skarels 	register struct proc *p = curproc;
12899578Ssam 	int i, hiwat, cnt, error, s;
12907502Sroot 	char obuf[OBUFSIZ];
12917502Sroot 
129235811Smarc 	hiwat = tp->t_hiwat;
12939578Ssam 	cnt = uio->uio_resid;
12949578Ssam 	error = 0;
12957502Sroot loop:
129637584Smarc 	s = spltty();
129740712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
129837584Smarc 		if (tp->t_state&TS_ISOPEN) {
129937584Smarc 			splx(s);
130037584Smarc 			return (EIO);
130137728Smckusick 		} else if (flag & IO_NDELAY) {
130237584Smarc 			splx(s);
130340712Skarels 			error = EWOULDBLOCK;
130440712Skarels 			goto out;
130537584Smarc 		} else {
130637584Smarc 			/*
130737584Smarc 			 * sleep awaiting carrier
130837584Smarc 			 */
130943377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
131043377Smarc 					TTIPRI | PCATCH,ttopen, 0);
131137584Smarc 			splx(s);
131243377Smarc 			if (error)
131340712Skarels 				goto out;
131437584Smarc 			goto loop;
131537584Smarc 		}
131637584Smarc 	}
131737584Smarc 	splx(s);
13189578Ssam 	/*
13199578Ssam 	 * Hang the process if it's in the background.
13209578Ssam 	 */
132147545Skarels 	if (isbackground(p, tp) &&
132247545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
132347545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
132447545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
132547545Skarels 	     p->p_pgrp->pg_jobc) {
132647545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
132743377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
132843377Smarc 		    ttybg, 0))
132940712Skarels 			goto out;
133021776Sbloom 		goto loop;
13317502Sroot 	}
13329578Ssam 	/*
13339578Ssam 	 * Process the user's data in at most OBUFSIZ
133440712Skarels 	 * chunks.  Perform any output translation.
133540712Skarels 	 * Keep track of high water mark, sleep on overflow
133640712Skarels 	 * awaiting device aid in acquiring new space.
13379578Ssam 	 */
133840712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
133940712Skarels 		if (tp->t_lflag&FLUSHO) {
134040712Skarels 			uio->uio_resid = 0;
134140712Skarels 			return (0);
134240712Skarels 		}
134340712Skarels 		if (tp->t_outq.c_cc > hiwat)
134432067Skarels 			goto ovhiwat;
13459578Ssam 		/*
134640712Skarels 		 * Grab a hunk of data from the user,
134740712Skarels 		 * unless we have some leftover from last time.
13489578Ssam 		 */
13497822Sroot 		if (cc == 0) {
135040712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
135140712Skarels 			cp = obuf;
135240712Skarels 			error = uiomove(cp, cc, uio);
135340712Skarels 			if (error) {
135440712Skarels 				cc = 0;
135540712Skarels 				break;
135640712Skarels 			}
13577822Sroot 		}
13589578Ssam 		/*
13599578Ssam 		 * If nothing fancy need be done, grab those characters we
13609578Ssam 		 * can handle without any of ttyoutput's processing and
13619578Ssam 		 * just transfer them to the output q.  For those chars
13629578Ssam 		 * which require special processing (as indicated by the
13639578Ssam 		 * bits in partab), call ttyoutput.  After processing
13649578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13659578Ssam 		 * immediately.
13669578Ssam 		 */
13679578Ssam 		while (cc > 0) {
136840712Skarels 			if ((tp->t_oflag&OPOST) == 0)
13697502Sroot 				ce = cc;
13707502Sroot 			else {
137134492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
137249380Skarels 				   (u_char *)partab, CCLASSMASK);
13739578Ssam 				/*
13749578Ssam 				 * If ce is zero, then we're processing
13759578Ssam 				 * a special character through ttyoutput.
13769578Ssam 				 */
13779578Ssam 				if (ce == 0) {
13787502Sroot 					tp->t_rocount = 0;
13797502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
138021776Sbloom 					    /* no c-lists, wait a bit */
138121776Sbloom 					    ttstart(tp);
138243377Smarc 					    if (error = ttysleep(tp,
138343377Smarc 						(caddr_t)&lbolt,
138443377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
138540712Skarels 						    break;
138621776Sbloom 					    goto loop;
13877502Sroot 					}
13889578Ssam 					cp++, cc--;
138935811Smarc 					if ((tp->t_lflag&FLUSHO) ||
13909578Ssam 					    tp->t_outq.c_cc > hiwat)
13917502Sroot 						goto ovhiwat;
13929578Ssam 					continue;
13937502Sroot 				}
13947502Sroot 			}
13959578Ssam 			/*
13969578Ssam 			 * A bunch of normal characters have been found,
13979578Ssam 			 * transfer them en masse to the output queue and
13989578Ssam 			 * continue processing at the top of the loop.
13999578Ssam 			 * If there are any further characters in this
14009578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14019578Ssam 			 * requiring special handling by ttyoutput.
14029578Ssam 			 */
14037502Sroot 			tp->t_rocount = 0;
14049578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14059578Ssam 			ce -= i;
14069578Ssam 			tp->t_col += ce;
14079578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
140835811Smarc 			tp->t_outcc += ce;
14099578Ssam 			if (i > 0) {
14109578Ssam 				/* out of c-lists, wait a bit */
14117502Sroot 				ttstart(tp);
141243377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
141343377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
141440712Skarels 					break;
141521776Sbloom 				goto loop;
14167502Sroot 			}
141735811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
141840712Skarels 				break;
14197502Sroot 		}
142035811Smarc 		ttstart(tp);
14217502Sroot 	}
142240712Skarels out:
142340712Skarels 	/*
142440712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
142540712Skarels 	 * as the offset and iov pointers have moved forward,
142640712Skarels 	 * but it doesn't matter (the call will either return short
142740712Skarels 	 * or restart with a new uio).
142840712Skarels 	 */
142940712Skarels 	uio->uio_resid += cc;
14308520Sroot 	return (error);
143140712Skarels 
14327502Sroot ovhiwat:
143332067Skarels 	ttstart(tp);
143432067Skarels 	s = spltty();
14359578Ssam 	/*
143635811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
143732067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14389578Ssam 	 */
14397502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14409578Ssam 		splx(s);
14417502Sroot 		goto loop;
14427502Sroot 	}
144337728Smckusick 	if (flag & IO_NDELAY) {
144417545Skarels 		splx(s);
144540712Skarels 		uio->uio_resid += cc;
14467822Sroot 		if (uio->uio_resid == cnt)
14478520Sroot 			return (EWOULDBLOCK);
14488520Sroot 		return (0);
14497502Sroot 	}
14507502Sroot 	tp->t_state |= TS_ASLEEP;
145143377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14529578Ssam 	splx(s);
145343377Smarc 	if (error)
145440712Skarels 		goto out;
14557502Sroot 	goto loop;
14567502Sroot }
14577502Sroot 
14587502Sroot /*
14597502Sroot  * Rubout one character from the rawq of tp
14607502Sroot  * as cleanly as possible.
14617502Sroot  */
14627502Sroot ttyrub(c, tp)
14637625Ssam 	register c;
14647625Ssam 	register struct tty *tp;
14657502Sroot {
14667502Sroot 	register char *cp;
14677502Sroot 	register int savecol;
14687502Sroot 	int s;
14697502Sroot 	char *nextc();
14707502Sroot 
147142882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
14727502Sroot 		return;
147335811Smarc 	tp->t_lflag &= ~FLUSHO;
147435811Smarc 	if (tp->t_lflag&ECHOE) {
14757502Sroot 		if (tp->t_rocount == 0) {
14767502Sroot 			/*
14777502Sroot 			 * Screwed by ttwrite; retype
14787502Sroot 			 */
14797502Sroot 			ttyretype(tp);
14807502Sroot 			return;
14817502Sroot 		}
148235811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
14837502Sroot 			ttyrubo(tp, 2);
148449380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
14857502Sroot 
14867502Sroot 		case ORDINARY:
148735811Smarc 			ttyrubo(tp, 1);
14887502Sroot 			break;
14897502Sroot 
14907502Sroot 		case VTAB:
14917502Sroot 		case BACKSPACE:
14927502Sroot 		case CONTROL:
14937502Sroot 		case RETURN:
149447545Skarels 		case NEWLINE:
149535811Smarc 			if (tp->t_lflag&ECHOCTL)
14967502Sroot 				ttyrubo(tp, 2);
14977502Sroot 			break;
14987502Sroot 
149935811Smarc 		case TAB: {
150035811Smarc 			int c;
150135811Smarc 
15027502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15037502Sroot 				ttyretype(tp);
15047502Sroot 				return;
15057502Sroot 			}
150617545Skarels 			s = spltty();
15077502Sroot 			savecol = tp->t_col;
15089578Ssam 			tp->t_state |= TS_CNTTB;
150935811Smarc 			tp->t_lflag |= FLUSHO;
15107502Sroot 			tp->t_col = tp->t_rocol;
15119578Ssam 			cp = tp->t_rawq.c_cf;
151239407Smarc 			if (cp)
151339407Smarc 				c = *cp;	/* XXX FIX NEXTC */
151435811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
151535811Smarc 				ttyecho(c, tp);
151635811Smarc 			tp->t_lflag &= ~FLUSHO;
15179578Ssam 			tp->t_state &= ~TS_CNTTB;
15187502Sroot 			splx(s);
15197502Sroot 			/*
15207502Sroot 			 * savecol will now be length of the tab
15217502Sroot 			 */
15227502Sroot 			savecol -= tp->t_col;
15237502Sroot 			tp->t_col += savecol;
15247502Sroot 			if (savecol > 8)
15257502Sroot 				savecol = 8;		/* overflow screw */
15267502Sroot 			while (--savecol >= 0)
15277502Sroot 				(void) ttyoutput('\b', tp);
15287502Sroot 			break;
152935811Smarc 		}
15307502Sroot 
15317502Sroot 		default:
153237584Smarc 			/* XXX */
153335811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
153449380Skarels 				c, CCLASS(c));
153535811Smarc 			/*panic("ttyrub");*/
15367502Sroot 		}
153735811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15389578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15397502Sroot 			(void) ttyoutput('\\', tp);
15409578Ssam 			tp->t_state |= TS_ERASE;
15417502Sroot 		}
15427502Sroot 		ttyecho(c, tp);
15437502Sroot 	} else
154435811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15457502Sroot 	tp->t_rocount--;
15467502Sroot }
15477502Sroot 
15487502Sroot /*
15497502Sroot  * Crt back over cnt chars perhaps
15507502Sroot  * erasing them.
15517502Sroot  */
15527502Sroot ttyrubo(tp, cnt)
15537625Ssam 	register struct tty *tp;
15547625Ssam 	int cnt;
15557502Sroot {
15567502Sroot 
15577502Sroot 	while (--cnt >= 0)
155840712Skarels 		ttyoutstr("\b \b", tp);
15597502Sroot }
15607502Sroot 
15617502Sroot /*
15627502Sroot  * Reprint the rawq line.
15637502Sroot  * We assume c_cc has already been checked.
15647502Sroot  */
15657502Sroot ttyretype(tp)
15667625Ssam 	register struct tty *tp;
15677502Sroot {
15687502Sroot 	register char *cp;
15697502Sroot 	char *nextc();
157035811Smarc 	int s, c;
15717502Sroot 
157235811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
157335811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
15747502Sroot 	(void) ttyoutput('\n', tp);
157517545Skarels 	s = spltty();
157635811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
157735811Smarc 	  BIT OF FIRST CHAR ****/
157835811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
157935811Smarc 		ttyecho(c, tp);
158035811Smarc 	}
158135811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
158235811Smarc 		ttyecho(c, tp);
158335811Smarc 	}
15849578Ssam 	tp->t_state &= ~TS_ERASE;
15857502Sroot 	splx(s);
15867502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15877502Sroot 	tp->t_rocol = 0;
15887502Sroot }
15897502Sroot 
15907502Sroot /*
159135811Smarc  * Echo a typed character to the terminal.
15927502Sroot  */
15937502Sroot ttyecho(c, tp)
15947625Ssam 	register c;
15957625Ssam 	register struct tty *tp;
15967502Sroot {
15979578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
159835811Smarc 		tp->t_lflag &= ~FLUSHO;
159947545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
160047545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16017502Sroot 		return;
160235811Smarc 	if (tp->t_lflag&ECHOCTL) {
160340712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
160440712Skarels 		    c == 0177) {
16057502Sroot 			(void) ttyoutput('^', tp);
160635811Smarc 			c &= TTY_CHARMASK;
16077502Sroot 			if (c == 0177)
16087502Sroot 				c = '?';
16097502Sroot 			else
16107502Sroot 				c += 'A' - 1;
16117502Sroot 		}
16127502Sroot 	}
161335811Smarc 	(void) ttyoutput(c, tp);
16147502Sroot }
16157502Sroot 
16167502Sroot /*
16177502Sroot  * send string cp to tp
16187502Sroot  */
161940712Skarels ttyoutstr(cp, tp)
16207625Ssam 	register char *cp;
16217625Ssam 	register struct tty *tp;
16227502Sroot {
16237502Sroot 	register char c;
16247502Sroot 
16257502Sroot 	while (c = *cp++)
16267502Sroot 		(void) ttyoutput(c, tp);
16277502Sroot }
16287502Sroot 
162949380Skarels /*
163049380Skarels  * Wake up any readers on a tty.
163149380Skarels  */
16327502Sroot ttwakeup(tp)
163347545Skarels 	register struct tty *tp;
16347502Sroot {
16357502Sroot 
16367502Sroot 	if (tp->t_rsel) {
16377502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16387502Sroot 		tp->t_state &= ~TS_RCOLL;
16397502Sroot 		tp->t_rsel = 0;
16407502Sroot 	}
164112752Ssam 	if (tp->t_state & TS_ASYNC)
164242882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16437502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16447502Sroot }
164535811Smarc 
164635811Smarc /*
164748439Skarels  * Look up a code for a specified speed in a conversion table;
164848439Skarels  * used by drivers to map software speed values to hardware parameters.
164948439Skarels  */
165048439Skarels ttspeedtab(speed, table)
165148439Skarels 	register struct speedtab *table;
165248439Skarels {
165348439Skarels 
165448439Skarels 	for ( ; table->sp_speed != -1; table++)
165548439Skarels 		if (table->sp_speed == speed)
165648439Skarels 			return (table->sp_code);
165748439Skarels 	return (-1);
165848439Skarels }
165948439Skarels 
166048439Skarels /*
166135811Smarc  * set tty hi and low water marks
166235811Smarc  *
166335811Smarc  * Try to arrange the dynamics so there's about one second
166435811Smarc  * from hi to low water.
166535811Smarc  *
166635811Smarc  */
166735811Smarc ttsetwater(tp)
166835811Smarc 	struct tty *tp;
166935811Smarc {
167035811Smarc 	register cps = tp->t_ospeed / 10;
167135811Smarc 	register x;
167235811Smarc 
167335811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
167435811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
167535811Smarc 	x += cps;
167635811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
167735811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
167835811Smarc #undef clamp
167935811Smarc }
168035811Smarc 
168139407Smarc /*
168239407Smarc  * (^T)
168339407Smarc  * Report on state of foreground process group.
168439407Smarc  */
168539407Smarc ttyinfo(tp)
168639407Smarc 	struct tty *tp;
168739407Smarc {
168841177Smarc 	register struct proc *p, *pick = NULL;
168941177Smarc 	int x, s;
169041177Smarc 	struct timeval utime, stime;
169142350Smckusick #define	pgtok(a)	(((a)*NBPG)/1024)
169239407Smarc 
169339407Smarc 	if (ttycheckoutq(tp,0) == 0)
169439407Smarc 		return;
169541177Smarc 	/*
169641177Smarc 	 * load average
169741177Smarc 	 */
169841177Smarc 	x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT;
169941177Smarc 	ttyprintf(tp, "load: %d.", x/100);
170041177Smarc 	ttyoutint(x%100, 10, 2, tp);
170139555Smarc 	if (tp->t_session == NULL)
170241177Smarc 		ttyprintf(tp, " not a controlling terminal\n");
170341177Smarc 	else if (tp->t_pgrp == NULL)
170441177Smarc 		ttyprintf(tp, " no foreground process group\n");
170541177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
170641177Smarc 		ttyprintf(tp, " empty foreground process group\n");
170739407Smarc 	else {
170841177Smarc 		/* pick interesting process */
170939407Smarc 		for (; p != NULL; p = p->p_pgrpnxt) {
171041177Smarc 			if (proc_compare(pick, p))
171141177Smarc 				pick = p;
171239407Smarc 		}
171341177Smarc 		ttyprintf(tp, "  cmd: %s %d [%s] ",
171441177Smarc 			pick->p_comm, pick->p_pid,
171548439Skarels 			pick->p_stat == SRUN ? "running" :
171648439Skarels 			pick->p_wmesg ? pick->p_wmesg : "iowait");
171741177Smarc 		/*
171841177Smarc 		 * cpu time
171941177Smarc 		 */
172047545Skarels 		if (curproc == pick)
172141177Smarc 			s = splclock();
172241177Smarc 		utime = pick->p_utime;
172341177Smarc 		stime = pick->p_stime;
172447545Skarels 		if (curproc == pick)
172541177Smarc 			splx(s);
172641177Smarc 		/* user time */
172741177Smarc 		x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */
172841177Smarc 		ttyoutint(utime.tv_sec, 10, 1, tp);
172941177Smarc 		tputchar('.', tp);
173041177Smarc 		ttyoutint(x, 10, 2, tp);
173141177Smarc 		tputchar('u', tp);
173241177Smarc 		tputchar(' ', tp);
173341177Smarc 		/* system time */
173441177Smarc 		x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */
173541177Smarc 		ttyoutint(stime.tv_sec, 10, 1, tp);
173641177Smarc 		tputchar('.', tp);
173741177Smarc 		ttyoutint(x, 10, 2, tp);
173841177Smarc 		tputchar('s', tp);
173941177Smarc 		tputchar(' ', tp);
174041177Smarc 		/*
174141177Smarc 		 * pctcpu
174241177Smarc 		 */
174341177Smarc 		x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT;
174441177Smarc 		ttyoutint(x/100, 10, 1, tp);
174541177Smarc #ifdef notdef	/* do we really want this ??? */
174641177Smarc 		tputchar('.', tp);
174741177Smarc 		ttyoutint(x%100, 10, 2, tp);
174841177Smarc #endif
174947545Skarels 		ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize));
175039407Smarc 	}
175141177Smarc 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
175239407Smarc }
175339407Smarc 
175441177Smarc ttyoutint(n, base, min, tp)
175541177Smarc 	register int n, base, min;
175641177Smarc 	register struct tty *tp;
175741177Smarc {
175841177Smarc 	char info[16];
175941177Smarc 	register char *p = info;
176041177Smarc 
176141177Smarc 	while (--min >= 0 || n) {
176241177Smarc 		*p++ = "0123456789abcdef"[n%base];
176341177Smarc 		n /= base;
176441177Smarc 	}
176541177Smarc 	while (p > info)
176641177Smarc 		ttyoutput(*--p, tp);
176741177Smarc }
176841177Smarc 
176941177Smarc /*
177041177Smarc  * Returns 1 if p2 is "better" than p1
177141177Smarc  *
177241177Smarc  * The algorithm for picking the "interesting" process is thus:
177341177Smarc  *
177441177Smarc  *	1) (Only foreground processes are eligable - implied)
177541177Smarc  *	2) Runnable processes are favored over anything
177641177Smarc  *	   else.  The runner with the highest cpu
177741177Smarc  *	   utilization is picked (p_cpu).  Ties are
177841177Smarc  *	   broken by picking the highest pid.
177941177Smarc  *	3  Next, the sleeper with the shortest sleep
178041177Smarc  *	   time is favored.  With ties, we pick out
178141177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
178241177Smarc  *	   Further ties are broken by picking the highest
178341177Smarc  *	   pid.
178441177Smarc  *
178541177Smarc  */
178641177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
178745723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
178845723Smckusick #define ONLYA   2
178945723Smckusick #define ONLYB   1
179045723Smckusick #define BOTH    3
179145723Smckusick 
179241177Smarc proc_compare(p1, p2)
179341177Smarc 	register struct proc *p1, *p2;
179441177Smarc {
179541177Smarc 
179641177Smarc 	if (p1 == NULL)
179741177Smarc 		return (1);
179841177Smarc 	/*
179941177Smarc 	 * see if at least one of them is runnable
180041177Smarc 	 */
180145723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
180245723Smckusick 	case ONLYA:
180345723Smckusick 		return (0);
180445723Smckusick 	case ONLYB:
180541177Smarc 		return (1);
180645723Smckusick 	case BOTH:
180741177Smarc 		/*
180841177Smarc 		 * tie - favor one with highest recent cpu utilization
180941177Smarc 		 */
181041177Smarc 		if (p2->p_cpu > p1->p_cpu)
181141177Smarc 			return (1);
181241177Smarc 		if (p1->p_cpu > p2->p_cpu)
181341177Smarc 			return (0);
181441177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
181541177Smarc 	}
181645723Smckusick 	/*
181745723Smckusick  	 * weed out zombies
181845723Smckusick 	 */
181945723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
182045723Smckusick 	case ONLYA:
182145723Smckusick 		return (1);
182245723Smckusick 	case ONLYB:
182345723Smckusick 		return (0);
182445723Smckusick 	case BOTH:
182545723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
182645723Smckusick 	}
182741177Smarc 	/*
182841177Smarc 	 * pick the one with the smallest sleep time
182941177Smarc 	 */
183041177Smarc 	if (p2->p_slptime > p1->p_slptime)
183141177Smarc 		return (0);
183241177Smarc 	if (p1->p_slptime > p2->p_slptime)
183341177Smarc 		return (1);
183441177Smarc 	/*
183541177Smarc 	 * favor one sleeping in a non-interruptible sleep
183641177Smarc 	 */
183741177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
183841177Smarc 		return (1);
183941177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
184041177Smarc 		return (0);
184147545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
184241177Smarc }
184345723Smckusick 
184439555Smarc /*
184539555Smarc  * Output char to tty; console putchar style.
184639555Smarc  */
184739555Smarc tputchar(c, tp)
184839555Smarc 	int c;
184939555Smarc 	struct tty *tp;
185039555Smarc {
185139555Smarc 	register s = spltty();
185239555Smarc 
185347545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
185439555Smarc 		if (c == '\n')
185539555Smarc 			(void) ttyoutput('\r', tp);
185639555Smarc 		(void) ttyoutput(c, tp);
185739555Smarc 		ttstart(tp);
185839555Smarc 		splx(s);
185939555Smarc 		return (0);
186039555Smarc 	}
186139555Smarc 	splx(s);
186239555Smarc 	return (-1);
186339555Smarc }
186443377Smarc 
186544419Smarc /*
186649380Skarels  * Sleep on chan, returning ERESTART if tty changed
186749380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
186849380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
186949380Skarels  * call will redo validation done at the start of the call.
187044419Smarc  */
187143377Smarc ttysleep(tp, chan, pri, wmesg, timo)
187243377Smarc 	struct tty *tp;
187343377Smarc 	caddr_t chan;
187443377Smarc 	int pri;
187543377Smarc 	char *wmesg;
187643377Smarc 	int timo;
187743377Smarc {
187843377Smarc 	int error;
187943377Smarc 	short gen = tp->t_gen;
188043377Smarc 
188143377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
188243377Smarc 		return (error);
188343377Smarc 	if (tp->t_gen != gen)
188443377Smarc 		return (ERESTART);
188543377Smarc 	return (0);
188643377Smarc }
1887