xref: /csrg-svn/sys/kern/tty.c (revision 49752)
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*49752Smarc  *	@(#)tty.c	7.43 (Berkeley) 05/16/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();
316*49752Smarc 			(*linesw[tp->t_line].l_close)(tp, flag);
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  */
622*49752Smarc ttylclose(tp, flag)
623*49752Smarc 	struct tty *tp;
624*49752Smarc 	int flag;
62525391Skarels {
62625391Skarels 
627*49752Smarc 	if (flag&IO_NDELAY)
628*49752Smarc 		ttyflush(tp, FREAD|FWRITE);
629*49752Smarc 	else
630*49752Smarc 		ttywflush(tp);
63125391Skarels }
63225391Skarels 
63325391Skarels /*
63449380Skarels  * Handle close() on a tty line: flush and set to initial state,
63549380Skarels  * bumping generation number so that pending read/write calls
63649380Skarels  * can detect recycling of the tty.
6377502Sroot  */
6387502Sroot ttyclose(tp)
6397625Ssam 	register struct tty *tp;
6407502Sroot {
64130534Skarels 	if (constty == tp)
64230534Skarels 		constty = NULL;
64325391Skarels 	ttyflush(tp, FREAD|FWRITE);
64439555Smarc 	tp->t_session = NULL;
64539555Smarc 	tp->t_pgrp = NULL;
6467502Sroot 	tp->t_state = 0;
64743377Smarc 	tp->t_gen++;
64840712Skarels 	return (0);
6497502Sroot }
6507502Sroot 
6517502Sroot /*
65225391Skarels  * Handle modem control transition on a tty.
65325391Skarels  * Flag indicates new state of carrier.
65425391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
65525391Skarels  */
65625391Skarels ttymodem(tp, flag)
65725391Skarels 	register struct tty *tp;
65825391Skarels {
65925391Skarels 
66042193Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
66125391Skarels 		/*
66225391Skarels 		 * MDMBUF: do flow control according to carrier flag
66325391Skarels 		 */
66425391Skarels 		if (flag) {
66525391Skarels 			tp->t_state &= ~TS_TTSTOP;
66625391Skarels 			ttstart(tp);
66725391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
66825391Skarels 			tp->t_state |= TS_TTSTOP;
66925391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
67025391Skarels 		}
67125391Skarels 	} else if (flag == 0) {
67225391Skarels 		/*
67325391Skarels 		 * Lost carrier.
67425391Skarels 		 */
67525391Skarels 		tp->t_state &= ~TS_CARR_ON;
67642193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
67742193Smarc 			if (tp->t_session && tp->t_session->s_leader)
67842193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
67942193Smarc 			ttyflush(tp, FREAD|FWRITE);
68042193Smarc 			return (0);
68125391Skarels 		}
68225391Skarels 	} else {
68325391Skarels 		/*
68425391Skarels 		 * Carrier now on.
68525391Skarels 		 */
68625391Skarels 		tp->t_state |= TS_CARR_ON;
68737584Smarc 		ttwakeup(tp);
68825391Skarels 	}
68925391Skarels 	return (1);
69025391Skarels }
69125391Skarels 
69225391Skarels /*
69325404Skarels  * Default modem control routine (for other line disciplines).
69425404Skarels  * Return argument flag, to turn off device on carrier drop.
69525404Skarels  */
69625415Skarels nullmodem(tp, flag)
69725415Skarels 	register struct tty *tp;
69825404Skarels 	int flag;
69925404Skarels {
70025404Skarels 
70125404Skarels 	if (flag)
70225404Skarels 		tp->t_state |= TS_CARR_ON;
70339407Smarc 	else {
70425404Skarels 		tp->t_state &= ~TS_CARR_ON;
70542193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
70642193Smarc 			if (tp->t_session && tp->t_session->s_leader)
70742193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
70842193Smarc 			return (0);
70942193Smarc 		}
71039407Smarc 	}
71142193Smarc 	return (1);
71225404Skarels }
71325404Skarels 
71425404Skarels /*
7157502Sroot  * reinput pending characters after state switch
71617545Skarels  * call at spltty().
7177502Sroot  */
7187502Sroot ttypend(tp)
7197625Ssam 	register struct tty *tp;
7207502Sroot {
7217502Sroot 	struct clist tq;
7227502Sroot 	register c;
7237502Sroot 
72435811Smarc 	tp->t_lflag &= ~PENDIN;
7259578Ssam 	tp->t_state |= TS_TYPEN;
7267502Sroot 	tq = tp->t_rawq;
7277502Sroot 	tp->t_rawq.c_cc = 0;
7287502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7297502Sroot 	while ((c = getc(&tq)) >= 0)
7307502Sroot 		ttyinput(c, tp);
7319578Ssam 	tp->t_state &= ~TS_TYPEN;
7327502Sroot }
7337502Sroot 
7347502Sroot /*
73549380Skarels  * Process input of a single character received on a tty.
7367502Sroot  */
7377502Sroot ttyinput(c, tp)
7387625Ssam 	register c;
7397625Ssam 	register struct tty *tp;
7407502Sroot {
74135811Smarc 	register int iflag = tp->t_iflag;
74235811Smarc 	register int lflag = tp->t_lflag;
74335811Smarc 	register u_char *cc = tp->t_cc;
74435811Smarc 	int i, err;
7457502Sroot 
7469578Ssam 	/*
7479578Ssam 	 * If input is pending take it first.
7489578Ssam 	 */
74935811Smarc 	if (lflag&PENDIN)
7507502Sroot 		ttypend(tp);
75135811Smarc 	/*
75235811Smarc 	 * Gather stats.
75335811Smarc 	 */
7547502Sroot 	tk_nin++;
75535811Smarc 	if (lflag&ICANON) {
75635811Smarc 		tk_cancc++;
75735811Smarc 		tp->t_cancc++;
75835811Smarc 	} else {
75935811Smarc 		tk_rawcc++;
76035811Smarc 		tp->t_rawcc++;
76135811Smarc 	}
7629578Ssam 	/*
76335811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7649578Ssam 	 */
76535811Smarc 	if (err = (c&TTY_ERRORMASK)) {
76635811Smarc 		c &= ~TTY_ERRORMASK;
76735811Smarc 		if (err&TTY_FE && !c) {		/* break */
76835811Smarc 			if (iflag&IGNBRK)
76935811Smarc 				goto endcase;
77035811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
77135811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
77235811Smarc 				c = cc[VINTR];
77347545Skarels 			else if (iflag&PARMRK)
77447545Skarels 				goto parmrk;
77535811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
77635811Smarc 			if (iflag&IGNPAR)
77735811Smarc 				goto endcase;
77835811Smarc 			else if (iflag&PARMRK) {
77935811Smarc parmrk:
78035811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
78135811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
78235811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
78335811Smarc 				goto endcase;
78435811Smarc 			} else
78535811Smarc 				c = 0;
7867502Sroot 		}
7879578Ssam 	}
7889578Ssam 	/*
78935811Smarc 	 * In tandem mode, check high water mark.
7909578Ssam 	 */
79135811Smarc 	if (iflag&IXOFF)
79235811Smarc 		ttyblock(tp);
79335811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
79449380Skarels 		c &= ~0x80;
79544419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
79644419Smarc 		/*
79744419Smarc 		 * Check for literal nexting very first
79844419Smarc 		 */
79944419Smarc 		if (tp->t_state&TS_LNCH) {
80044419Smarc 			c |= TTY_QUOTE;
80144419Smarc 			tp->t_state &= ~TS_LNCH;
80244419Smarc 		}
80344419Smarc 		/*
80444419Smarc 		 * Scan for special characters.  This code
80544419Smarc 		 * is really just a big case statement with
80644419Smarc 		 * non-constant cases.  The bottom of the
80744419Smarc 		 * case statement is labeled ``endcase'', so goto
80844419Smarc 		 * it after a case match, or similar.
80944419Smarc 		 */
81044419Smarc 
81144419Smarc 		/*
81244419Smarc 		 * Control chars which aren't controlled
81344419Smarc 		 * by ICANON, ISIG, or IXON.
81444419Smarc 		 */
81544419Smarc 		if (lflag&IEXTEN) {
81644419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
81744419Smarc 				if (lflag&ECHO) {
81844419Smarc 					if (lflag&ECHOE)
81944419Smarc 						ttyoutstr("^\b", tp);
82044419Smarc 					else
82144419Smarc 						ttyecho(c, tp);
82244419Smarc 				}
82344419Smarc 				tp->t_state |= TS_LNCH;
82444419Smarc 				goto endcase;
82544419Smarc 			}
82644419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
82744419Smarc 				if (lflag&FLUSHO)
82844419Smarc 					tp->t_lflag &= ~FLUSHO;
82944419Smarc 				else {
83044419Smarc 					ttyflush(tp, FWRITE);
83135811Smarc 					ttyecho(c, tp);
83244419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
83344419Smarc 						ttyretype(tp);
83444419Smarc 					tp->t_lflag |= FLUSHO;
83544419Smarc 				}
83644419Smarc 				goto startoutput;
83735811Smarc 			}
8389578Ssam 		}
83944419Smarc 		/*
84044419Smarc 		 * Signals.
84144419Smarc 		 */
84244419Smarc 		if (lflag&ISIG) {
84344419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
84444419Smarc 				if ((lflag&NOFLSH) == 0)
84544419Smarc 					ttyflush(tp, FREAD|FWRITE);
8467502Sroot 				ttyecho(c, tp);
84744419Smarc 				pgsignal(tp->t_pgrp,
84844419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
84944419Smarc 				goto endcase;
8507502Sroot 			}
85144419Smarc 			if (CCEQ(cc[VSUSP], c)) {
85244419Smarc 				if ((lflag&NOFLSH) == 0)
85344419Smarc 					ttyflush(tp, FREAD);
85444419Smarc 				ttyecho(c, tp);
85544419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
85644419Smarc 				goto endcase;
85744419Smarc 			}
8589578Ssam 		}
85944419Smarc 		/*
86044419Smarc 		 * Handle start/stop characters.
86144419Smarc 		 */
86244419Smarc 		if (iflag&IXON) {
86344419Smarc 			if (CCEQ(cc[VSTOP], c)) {
86444419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
86544419Smarc 					tp->t_state |= TS_TTSTOP;
86644419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
86744419Smarc 					   0);
86844419Smarc 					return;
86944419Smarc 				}
87044419Smarc 				if (!CCEQ(cc[VSTART], c))
87144419Smarc 					return;
87244419Smarc 				/*
87344419Smarc 				 * if VSTART == VSTOP then toggle
87444419Smarc 				 */
87544419Smarc 				goto endcase;
87635811Smarc 			}
87744419Smarc 			if (CCEQ(cc[VSTART], c))
87844419Smarc 				goto restartoutput;
8799578Ssam 		}
88044419Smarc 		/*
88144419Smarc 		 * IGNCR, ICRNL, & INLCR
88244419Smarc 		 */
88344419Smarc 		if (c == '\r') {
88444419Smarc 			if (iflag&IGNCR)
88544419Smarc 				goto endcase;
88644419Smarc 			else if (iflag&ICRNL)
88744419Smarc 				c = '\n';
88844419Smarc 		} else if (c == '\n' && iflag&INLCR)
88944419Smarc 			c = '\r';
8909578Ssam 	}
89147545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
89244419Smarc 		/*
89344419Smarc 		 * From here on down canonical mode character
89444419Smarc 		 * processing takes place.
89544419Smarc 		 */
89644419Smarc 		/*
89744419Smarc 		 * erase (^H / ^?)
89844419Smarc 		 */
89944419Smarc 		if (CCEQ(cc[VERASE], c)) {
90044419Smarc 			if (tp->t_rawq.c_cc)
9019578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
90244419Smarc 			goto endcase;
9039578Ssam 		}
90444419Smarc 		/*
90544419Smarc 		 * kill (^U)
90644419Smarc 		 */
90744419Smarc 		if (CCEQ(cc[VKILL], c)) {
90844419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
90944419Smarc 			    (lflag&ECHOPRT) == 0) {
91044419Smarc 				while (tp->t_rawq.c_cc)
91144419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
91244419Smarc 			} else {
91344419Smarc 				ttyecho(c, tp);
91444419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
91544419Smarc 					ttyecho('\n', tp);
91644419Smarc 				while (getc(&tp->t_rawq) > 0)
91744419Smarc 					;
91844419Smarc 				tp->t_rocount = 0;
91944419Smarc 			}
92044419Smarc 			tp->t_state &= ~TS_LOCAL;
92144419Smarc 			goto endcase;
92244419Smarc 		}
92344419Smarc 		/*
92444419Smarc 		 * word erase (^W)
92544419Smarc 		 */
92644419Smarc 		if (CCEQ(cc[VWERASE], c)) {
92744419Smarc 			int ctype;
92847545Skarels 			int alt = lflag&ALTWERASE;
92935811Smarc 
93044419Smarc 			/*
93144419Smarc 			 * erase whitespace
93244419Smarc 			 */
93344419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
93444419Smarc 				ttyrub(c, tp);
93544419Smarc 			if (c == -1)
93644419Smarc 				goto endcase;
93744419Smarc 			/*
93847545Skarels 			 * erase last char of word and remember the
93947545Skarels 			 * next chars type (for ALTWERASE)
94044419Smarc 			 */
94135811Smarc 			ttyrub(c, tp);
94244419Smarc 			c = unputc(&tp->t_rawq);
94347545Skarels 			if (c == -1)
94444419Smarc 				goto endcase;
94549380Skarels 			ctype = ISALPHA(c);
94644419Smarc 			/*
94747545Skarels 			 * erase rest of word
94844419Smarc 			 */
94944419Smarc 			do {
95044419Smarc 				ttyrub(c, tp);
95144419Smarc 				c = unputc(&tp->t_rawq);
95244419Smarc 				if (c == -1)
95344419Smarc 					goto endcase;
95447545Skarels 			} while (c != ' ' && c != '\t' &&
95549380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
95644419Smarc 			(void) putc(c, &tp->t_rawq);
95734492Skarels 			goto endcase;
95844419Smarc 		}
95935811Smarc 		/*
96044419Smarc 		 * reprint line (^R)
96135811Smarc 		 */
96244419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
96344419Smarc 			ttyretype(tp);
96434492Skarels 			goto endcase;
96534492Skarels 		}
96635811Smarc 		/*
96744419Smarc 		 * ^T - kernel info and generate SIGINFO
96835811Smarc 		 */
96944419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
97044419Smarc 			pgsignal(tp->t_pgrp, SIGINFO, 1);
97144419Smarc 			if ((lflag&NOKERNINFO) == 0)
97244419Smarc 				ttyinfo(tp);
97344419Smarc 			goto endcase;
97444419Smarc 		}
9759578Ssam 	}
9769578Ssam 	/*
9779578Ssam 	 * Check for input buffer overflow
9789578Ssam 	 */
97947545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
98035811Smarc 		if (iflag&IMAXBEL) {
98135811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
98235811Smarc 				(void) ttyoutput(CTRL('g'), tp);
98335811Smarc 		} else
98435811Smarc 			ttyflush(tp, FREAD | FWRITE);
9859578Ssam 		goto endcase;
98610391Ssam 	}
9879578Ssam 	/*
9889578Ssam 	 * Put data char in q for user and
9899578Ssam 	 * wakeup on seeing a line delimiter.
9909578Ssam 	 */
9919578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
99247545Skarels 		if ((lflag&ICANON) == 0) {
99347545Skarels 			ttwakeup(tp);
99447545Skarels 			ttyecho(c, tp);
99547545Skarels 			goto endcase;
99647545Skarels 		}
99735811Smarc 		if (ttbreakc(c)) {
9989578Ssam 			tp->t_rocount = 0;
9999578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
10007502Sroot 			ttwakeup(tp);
10019578Ssam 		} else if (tp->t_rocount++ == 0)
10029578Ssam 			tp->t_rocol = tp->t_col;
10039578Ssam 		if (tp->t_state&TS_ERASE) {
100435811Smarc 			/*
100535811Smarc 			 * end of prterase \.../
100635811Smarc 			 */
10079578Ssam 			tp->t_state &= ~TS_ERASE;
10089578Ssam 			(void) ttyoutput('/', tp);
10099578Ssam 		}
10109578Ssam 		i = tp->t_col;
10117502Sroot 		ttyecho(c, tp);
101235811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
101335811Smarc 			/*
101435811Smarc 			 * Place the cursor over the '^' of the ^D.
101535811Smarc 			 */
10169578Ssam 			i = MIN(2, tp->t_col - i);
10179578Ssam 			while (i > 0) {
10189578Ssam 				(void) ttyoutput('\b', tp);
10199578Ssam 				i--;
10209578Ssam 			}
10219578Ssam 		}
10227502Sroot 	}
10239578Ssam endcase:
10249578Ssam 	/*
102535811Smarc 	 * IXANY means allow any character to restart output.
10269578Ssam 	 */
102740712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
102840712Skarels 	    cc[VSTART] != cc[VSTOP])
10297502Sroot 		return;
10309578Ssam restartoutput:
10317502Sroot 	tp->t_state &= ~TS_TTSTOP;
103235811Smarc 	tp->t_lflag &= ~FLUSHO;
10339578Ssam startoutput:
10347502Sroot 	ttstart(tp);
10357502Sroot }
10367502Sroot 
10377502Sroot /*
103849380Skarels  * Output a single character on a tty, doing output processing
103949380Skarels  * as needed (expanding tabs, newline processing, etc.).
104049380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10417502Sroot  * Must be recursive.
10427502Sroot  */
10437502Sroot ttyoutput(c, tp)
10447502Sroot 	register c;
10457502Sroot 	register struct tty *tp;
10467502Sroot {
104749380Skarels 	register int col;
104835811Smarc 	register long oflag = tp->t_oflag;
104935811Smarc 
105040712Skarels 	if ((oflag&OPOST) == 0) {
105135811Smarc 		if (tp->t_lflag&FLUSHO)
10527502Sroot 			return (-1);
10537502Sroot 		if (putc(c, &tp->t_outq))
10547625Ssam 			return (c);
10557502Sroot 		tk_nout++;
105635811Smarc 		tp->t_outcc++;
10577502Sroot 		return (-1);
10587502Sroot 	}
105935811Smarc 	c &= TTY_CHARMASK;
10607502Sroot 	/*
106149380Skarels 	 * Do tab expansion if OXTABS is set.
106242882Smarc 	 * Special case if we have external processing, we don't
106342882Smarc 	 * do the tab expansion because we'll probably get it
106442882Smarc 	 * wrong.  If tab expansion needs to be done, let it
106542882Smarc 	 * happen externally.
10667502Sroot 	 */
106747545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
10687502Sroot 		register int s;
10697502Sroot 
10707502Sroot 		c = 8 - (tp->t_col&7);
107135811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
107217545Skarels 			s = spltty();		/* don't interrupt tabs */
10737502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10747502Sroot 			tk_nout += c;
107535811Smarc 			tp->t_outcc += c;
10767502Sroot 			splx(s);
10777502Sroot 		}
10787502Sroot 		tp->t_col += c;
10797502Sroot 		return (c ? -1 : '\t');
10807502Sroot 	}
108135811Smarc 	if (c == CEOT && oflag&ONOEOT)
108247545Skarels 		return (-1);
10837502Sroot 	tk_nout++;
108435811Smarc 	tp->t_outcc++;
10857502Sroot 	/*
108649380Skarels 	 * Newline translation: if ONLCR is set,
108749380Skarels 	 * translate newline into "\r\n".
10887502Sroot 	 */
108935811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
10907502Sroot 		return (c);
109135811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
109235811Smarc 		return (c);
109347545Skarels 
109449380Skarels 	col = tp->t_col;
109549380Skarels 	switch (CCLASS(c)) {
10967502Sroot 
10977502Sroot 	case ORDINARY:
109849380Skarels 		col++;
10997502Sroot 
11007502Sroot 	case CONTROL:
11017502Sroot 		break;
11027502Sroot 
11037502Sroot 	case BACKSPACE:
110449380Skarels 		if (col > 0)
110549380Skarels 			col--;
11067502Sroot 		break;
11077502Sroot 
11087502Sroot 	case NEWLINE:
110949380Skarels 		col = 0;
11107502Sroot 		break;
11117502Sroot 
11127502Sroot 	case TAB:
111349380Skarels 		col = (col + 8) &~ 0x7;
11147502Sroot 		break;
11157502Sroot 
11167502Sroot 	case RETURN:
111749380Skarels 		col = 0;
11187502Sroot 	}
111949380Skarels 	tp->t_col = col;
11207502Sroot 	return (-1);
11217502Sroot }
11227502Sroot 
11237502Sroot /*
112449380Skarels  * Process a read call on a tty device.
11257502Sroot  */
112637584Smarc ttread(tp, uio, flag)
11277625Ssam 	register struct tty *tp;
11287722Swnj 	struct uio *uio;
11297502Sroot {
11307502Sroot 	register struct clist *qp;
113135811Smarc 	register int c;
113241383Smarc 	register long lflag;
113335811Smarc 	register u_char *cc = tp->t_cc;
113447545Skarels 	register struct proc *p = curproc;
11359859Ssam 	int s, first, error = 0;
11367502Sroot 
11377502Sroot loop:
113841383Smarc 	lflag = tp->t_lflag;
113937584Smarc 	s = spltty();
11409578Ssam 	/*
114137584Smarc 	 * take pending input first
11429578Ssam 	 */
114335811Smarc 	if (lflag&PENDIN)
11447502Sroot 		ttypend(tp);
11459859Ssam 	splx(s);
114640712Skarels 
11479578Ssam 	/*
11489578Ssam 	 * Hang process if it's in the background.
11499578Ssam 	 */
115047545Skarels 	if (isbackground(p, tp)) {
115147545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
115247545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
115347545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11548520Sroot 			return (EIO);
115547545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
115643377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
115743377Smarc 		    ttybg, 0))
115840712Skarels 			return (error);
115923165Sbloom 		goto loop;
11607502Sroot 	}
116140712Skarels 
11629578Ssam 	/*
116335811Smarc 	 * If canonical, use the canonical queue,
116435811Smarc 	 * else use the raw queue.
116537584Smarc 	 *
116647545Skarels 	 * (should get rid of clists...)
11679578Ssam 	 */
116835811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
116940712Skarels 
11709578Ssam 	/*
117140712Skarels 	 * If there is no input, sleep on rawq
117240712Skarels 	 * awaiting hardware receipt and notification.
117340712Skarels 	 * If we have data, we don't need to check for carrier.
11749578Ssam 	 */
117517545Skarels 	s = spltty();
11769578Ssam 	if (qp->c_cc <= 0) {
117740712Skarels 		int carrier;
117840712Skarels 
117940712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
118040712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
11819859Ssam 			splx(s);
118240712Skarels 			return (0);	/* EOF */
11837502Sroot 		}
118437728Smckusick 		if (flag & IO_NDELAY) {
118537584Smarc 			splx(s);
118637584Smarc 			return (EWOULDBLOCK);
118737584Smarc 		}
118843377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
118940712Skarels 		    carrier ? ttyin : ttopen, 0);
11909859Ssam 		splx(s);
119143377Smarc 		if (error)
119240712Skarels 			return (error);
11939578Ssam 		goto loop;
11949578Ssam 	}
11959859Ssam 	splx(s);
119640712Skarels 
11979578Ssam 	/*
119835811Smarc 	 * Input present, check for input mapping and processing.
11999578Ssam 	 */
12009578Ssam 	first = 1;
12019578Ssam 	while ((c = getc(qp)) >= 0) {
12029578Ssam 		/*
120335811Smarc 		 * delayed suspend (^Y)
12049578Ssam 		 */
120535811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
120642882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12079578Ssam 			if (first) {
120843377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
120943377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
121040712Skarels 					break;
12119578Ssam 				goto loop;
12129578Ssam 			}
12139578Ssam 			break;
12147502Sroot 		}
12159578Ssam 		/*
121635811Smarc 		 * Interpret EOF only in canonical mode.
12179578Ssam 		 */
121835811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12199578Ssam 			break;
12209578Ssam 		/*
12219578Ssam 		 * Give user character.
12229578Ssam 		 */
122340712Skarels  		error = ureadc(c, uio);
12249578Ssam 		if (error)
12259578Ssam 			break;
122614938Smckusick  		if (uio->uio_resid == 0)
12279578Ssam 			break;
12289578Ssam 		/*
122935811Smarc 		 * In canonical mode check for a "break character"
12309578Ssam 		 * marking the end of a "line of input".
12319578Ssam 		 */
123240712Skarels 		if (lflag&ICANON && ttbreakc(c))
12339578Ssam 			break;
12349578Ssam 		first = 0;
12357502Sroot 	}
12369578Ssam 	/*
12379578Ssam 	 * Look to unblock output now that (presumably)
12389578Ssam 	 * the input queue has gone down.
12399578Ssam 	 */
124035811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
124147545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
124247545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12437502Sroot 			tp->t_state &= ~TS_TBLOCK;
12447502Sroot 			ttstart(tp);
12457502Sroot 		}
124635811Smarc 	}
12478520Sroot 	return (error);
12487502Sroot }
12497502Sroot 
12507502Sroot /*
125125391Skarels  * Check the output queue on tp for space for a kernel message
125225391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
125325391Skarels  * hiwater mark so we don't lose messages due to normal flow
125425391Skarels  * control, but don't let the tty run amok.
125530695Skarels  * Sleeps here are not interruptible, but we return prematurely
125630695Skarels  * if new signals come in.
125725391Skarels  */
125825391Skarels ttycheckoutq(tp, wait)
125925391Skarels 	register struct tty *tp;
126025391Skarels 	int wait;
126125391Skarels {
126230695Skarels 	int hiwat, s, oldsig;
126348439Skarels 	extern int wakeup();
126425391Skarels 
126535811Smarc 	hiwat = tp->t_hiwat;
126625391Skarels 	s = spltty();
126747545Skarels 	oldsig = curproc->p_sig;
126825391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
126929946Skarels 		while (tp->t_outq.c_cc > hiwat) {
127029946Skarels 			ttstart(tp);
127147545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
127229946Skarels 				splx(s);
127329946Skarels 				return (0);
127429946Skarels 			}
127530695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
127629946Skarels 			tp->t_state |= TS_ASLEEP;
127730695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
127825391Skarels 		}
127925391Skarels 	splx(s);
128025391Skarels 	return (1);
128125391Skarels }
128225391Skarels 
128325391Skarels /*
128449380Skarels  * Process a write call on a tty device.
12857502Sroot  */
128637584Smarc ttwrite(tp, uio, flag)
12877625Ssam 	register struct tty *tp;
12889578Ssam 	register struct uio *uio;
12897502Sroot {
12907502Sroot 	register char *cp;
129140712Skarels 	register int cc = 0, ce;
129247545Skarels 	register struct proc *p = curproc;
12939578Ssam 	int i, hiwat, cnt, error, s;
12947502Sroot 	char obuf[OBUFSIZ];
12957502Sroot 
129635811Smarc 	hiwat = tp->t_hiwat;
12979578Ssam 	cnt = uio->uio_resid;
12989578Ssam 	error = 0;
12997502Sroot loop:
130037584Smarc 	s = spltty();
130140712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
130237584Smarc 		if (tp->t_state&TS_ISOPEN) {
130337584Smarc 			splx(s);
130437584Smarc 			return (EIO);
130537728Smckusick 		} else if (flag & IO_NDELAY) {
130637584Smarc 			splx(s);
130740712Skarels 			error = EWOULDBLOCK;
130840712Skarels 			goto out;
130937584Smarc 		} else {
131037584Smarc 			/*
131137584Smarc 			 * sleep awaiting carrier
131237584Smarc 			 */
131343377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
131443377Smarc 					TTIPRI | PCATCH,ttopen, 0);
131537584Smarc 			splx(s);
131643377Smarc 			if (error)
131740712Skarels 				goto out;
131837584Smarc 			goto loop;
131937584Smarc 		}
132037584Smarc 	}
132137584Smarc 	splx(s);
13229578Ssam 	/*
13239578Ssam 	 * Hang the process if it's in the background.
13249578Ssam 	 */
132547545Skarels 	if (isbackground(p, tp) &&
132647545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
132747545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
132847545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
132947545Skarels 	     p->p_pgrp->pg_jobc) {
133047545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
133143377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
133243377Smarc 		    ttybg, 0))
133340712Skarels 			goto out;
133421776Sbloom 		goto loop;
13357502Sroot 	}
13369578Ssam 	/*
13379578Ssam 	 * Process the user's data in at most OBUFSIZ
133840712Skarels 	 * chunks.  Perform any output translation.
133940712Skarels 	 * Keep track of high water mark, sleep on overflow
134040712Skarels 	 * awaiting device aid in acquiring new space.
13419578Ssam 	 */
134240712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
134340712Skarels 		if (tp->t_lflag&FLUSHO) {
134440712Skarels 			uio->uio_resid = 0;
134540712Skarels 			return (0);
134640712Skarels 		}
134740712Skarels 		if (tp->t_outq.c_cc > hiwat)
134832067Skarels 			goto ovhiwat;
13499578Ssam 		/*
135040712Skarels 		 * Grab a hunk of data from the user,
135140712Skarels 		 * unless we have some leftover from last time.
13529578Ssam 		 */
13537822Sroot 		if (cc == 0) {
135440712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
135540712Skarels 			cp = obuf;
135640712Skarels 			error = uiomove(cp, cc, uio);
135740712Skarels 			if (error) {
135840712Skarels 				cc = 0;
135940712Skarels 				break;
136040712Skarels 			}
13617822Sroot 		}
13629578Ssam 		/*
13639578Ssam 		 * If nothing fancy need be done, grab those characters we
13649578Ssam 		 * can handle without any of ttyoutput's processing and
13659578Ssam 		 * just transfer them to the output q.  For those chars
13669578Ssam 		 * which require special processing (as indicated by the
13679578Ssam 		 * bits in partab), call ttyoutput.  After processing
13689578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13699578Ssam 		 * immediately.
13709578Ssam 		 */
13719578Ssam 		while (cc > 0) {
137240712Skarels 			if ((tp->t_oflag&OPOST) == 0)
13737502Sroot 				ce = cc;
13747502Sroot 			else {
137534492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
137649380Skarels 				   (u_char *)partab, CCLASSMASK);
13779578Ssam 				/*
13789578Ssam 				 * If ce is zero, then we're processing
13799578Ssam 				 * a special character through ttyoutput.
13809578Ssam 				 */
13819578Ssam 				if (ce == 0) {
13827502Sroot 					tp->t_rocount = 0;
13837502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
138421776Sbloom 					    /* no c-lists, wait a bit */
138521776Sbloom 					    ttstart(tp);
138643377Smarc 					    if (error = ttysleep(tp,
138743377Smarc 						(caddr_t)&lbolt,
138843377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
138940712Skarels 						    break;
139021776Sbloom 					    goto loop;
13917502Sroot 					}
13929578Ssam 					cp++, cc--;
139335811Smarc 					if ((tp->t_lflag&FLUSHO) ||
13949578Ssam 					    tp->t_outq.c_cc > hiwat)
13957502Sroot 						goto ovhiwat;
13969578Ssam 					continue;
13977502Sroot 				}
13987502Sroot 			}
13999578Ssam 			/*
14009578Ssam 			 * A bunch of normal characters have been found,
14019578Ssam 			 * transfer them en masse to the output queue and
14029578Ssam 			 * continue processing at the top of the loop.
14039578Ssam 			 * If there are any further characters in this
14049578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14059578Ssam 			 * requiring special handling by ttyoutput.
14069578Ssam 			 */
14077502Sroot 			tp->t_rocount = 0;
14089578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14099578Ssam 			ce -= i;
14109578Ssam 			tp->t_col += ce;
14119578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
141235811Smarc 			tp->t_outcc += ce;
14139578Ssam 			if (i > 0) {
14149578Ssam 				/* out of c-lists, wait a bit */
14157502Sroot 				ttstart(tp);
141643377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
141743377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
141840712Skarels 					break;
141921776Sbloom 				goto loop;
14207502Sroot 			}
142135811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
142240712Skarels 				break;
14237502Sroot 		}
142435811Smarc 		ttstart(tp);
14257502Sroot 	}
142640712Skarels out:
142740712Skarels 	/*
142840712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
142940712Skarels 	 * as the offset and iov pointers have moved forward,
143040712Skarels 	 * but it doesn't matter (the call will either return short
143140712Skarels 	 * or restart with a new uio).
143240712Skarels 	 */
143340712Skarels 	uio->uio_resid += cc;
14348520Sroot 	return (error);
143540712Skarels 
14367502Sroot ovhiwat:
143732067Skarels 	ttstart(tp);
143832067Skarels 	s = spltty();
14399578Ssam 	/*
144035811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
144132067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14429578Ssam 	 */
14437502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14449578Ssam 		splx(s);
14457502Sroot 		goto loop;
14467502Sroot 	}
144737728Smckusick 	if (flag & IO_NDELAY) {
144817545Skarels 		splx(s);
144940712Skarels 		uio->uio_resid += cc;
14507822Sroot 		if (uio->uio_resid == cnt)
14518520Sroot 			return (EWOULDBLOCK);
14528520Sroot 		return (0);
14537502Sroot 	}
14547502Sroot 	tp->t_state |= TS_ASLEEP;
145543377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14569578Ssam 	splx(s);
145743377Smarc 	if (error)
145840712Skarels 		goto out;
14597502Sroot 	goto loop;
14607502Sroot }
14617502Sroot 
14627502Sroot /*
14637502Sroot  * Rubout one character from the rawq of tp
14647502Sroot  * as cleanly as possible.
14657502Sroot  */
14667502Sroot ttyrub(c, tp)
14677625Ssam 	register c;
14687625Ssam 	register struct tty *tp;
14697502Sroot {
14707502Sroot 	register char *cp;
14717502Sroot 	register int savecol;
14727502Sroot 	int s;
14737502Sroot 	char *nextc();
14747502Sroot 
147542882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
14767502Sroot 		return;
147735811Smarc 	tp->t_lflag &= ~FLUSHO;
147835811Smarc 	if (tp->t_lflag&ECHOE) {
14797502Sroot 		if (tp->t_rocount == 0) {
14807502Sroot 			/*
14817502Sroot 			 * Screwed by ttwrite; retype
14827502Sroot 			 */
14837502Sroot 			ttyretype(tp);
14847502Sroot 			return;
14857502Sroot 		}
148635811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
14877502Sroot 			ttyrubo(tp, 2);
148849380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
14897502Sroot 
14907502Sroot 		case ORDINARY:
149135811Smarc 			ttyrubo(tp, 1);
14927502Sroot 			break;
14937502Sroot 
14947502Sroot 		case VTAB:
14957502Sroot 		case BACKSPACE:
14967502Sroot 		case CONTROL:
14977502Sroot 		case RETURN:
149847545Skarels 		case NEWLINE:
149935811Smarc 			if (tp->t_lflag&ECHOCTL)
15007502Sroot 				ttyrubo(tp, 2);
15017502Sroot 			break;
15027502Sroot 
150335811Smarc 		case TAB: {
150435811Smarc 			int c;
150535811Smarc 
15067502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15077502Sroot 				ttyretype(tp);
15087502Sroot 				return;
15097502Sroot 			}
151017545Skarels 			s = spltty();
15117502Sroot 			savecol = tp->t_col;
15129578Ssam 			tp->t_state |= TS_CNTTB;
151335811Smarc 			tp->t_lflag |= FLUSHO;
15147502Sroot 			tp->t_col = tp->t_rocol;
15159578Ssam 			cp = tp->t_rawq.c_cf;
151639407Smarc 			if (cp)
151739407Smarc 				c = *cp;	/* XXX FIX NEXTC */
151835811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
151935811Smarc 				ttyecho(c, tp);
152035811Smarc 			tp->t_lflag &= ~FLUSHO;
15219578Ssam 			tp->t_state &= ~TS_CNTTB;
15227502Sroot 			splx(s);
15237502Sroot 			/*
15247502Sroot 			 * savecol will now be length of the tab
15257502Sroot 			 */
15267502Sroot 			savecol -= tp->t_col;
15277502Sroot 			tp->t_col += savecol;
15287502Sroot 			if (savecol > 8)
15297502Sroot 				savecol = 8;		/* overflow screw */
15307502Sroot 			while (--savecol >= 0)
15317502Sroot 				(void) ttyoutput('\b', tp);
15327502Sroot 			break;
153335811Smarc 		}
15347502Sroot 
15357502Sroot 		default:
153637584Smarc 			/* XXX */
153735811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
153849380Skarels 				c, CCLASS(c));
153935811Smarc 			/*panic("ttyrub");*/
15407502Sroot 		}
154135811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15429578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15437502Sroot 			(void) ttyoutput('\\', tp);
15449578Ssam 			tp->t_state |= TS_ERASE;
15457502Sroot 		}
15467502Sroot 		ttyecho(c, tp);
15477502Sroot 	} else
154835811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15497502Sroot 	tp->t_rocount--;
15507502Sroot }
15517502Sroot 
15527502Sroot /*
15537502Sroot  * Crt back over cnt chars perhaps
15547502Sroot  * erasing them.
15557502Sroot  */
15567502Sroot ttyrubo(tp, cnt)
15577625Ssam 	register struct tty *tp;
15587625Ssam 	int cnt;
15597502Sroot {
15607502Sroot 
15617502Sroot 	while (--cnt >= 0)
156240712Skarels 		ttyoutstr("\b \b", tp);
15637502Sroot }
15647502Sroot 
15657502Sroot /*
15667502Sroot  * Reprint the rawq line.
15677502Sroot  * We assume c_cc has already been checked.
15687502Sroot  */
15697502Sroot ttyretype(tp)
15707625Ssam 	register struct tty *tp;
15717502Sroot {
15727502Sroot 	register char *cp;
15737502Sroot 	char *nextc();
157435811Smarc 	int s, c;
15757502Sroot 
157635811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
157735811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
15787502Sroot 	(void) ttyoutput('\n', tp);
157917545Skarels 	s = spltty();
158035811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
158135811Smarc 	  BIT OF FIRST CHAR ****/
158235811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
158335811Smarc 		ttyecho(c, tp);
158435811Smarc 	}
158535811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
158635811Smarc 		ttyecho(c, tp);
158735811Smarc 	}
15889578Ssam 	tp->t_state &= ~TS_ERASE;
15897502Sroot 	splx(s);
15907502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15917502Sroot 	tp->t_rocol = 0;
15927502Sroot }
15937502Sroot 
15947502Sroot /*
159535811Smarc  * Echo a typed character to the terminal.
15967502Sroot  */
15977502Sroot ttyecho(c, tp)
15987625Ssam 	register c;
15997625Ssam 	register struct tty *tp;
16007502Sroot {
16019578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
160235811Smarc 		tp->t_lflag &= ~FLUSHO;
160347545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
160447545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16057502Sroot 		return;
160635811Smarc 	if (tp->t_lflag&ECHOCTL) {
160740712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
160840712Skarels 		    c == 0177) {
16097502Sroot 			(void) ttyoutput('^', tp);
161035811Smarc 			c &= TTY_CHARMASK;
16117502Sroot 			if (c == 0177)
16127502Sroot 				c = '?';
16137502Sroot 			else
16147502Sroot 				c += 'A' - 1;
16157502Sroot 		}
16167502Sroot 	}
161735811Smarc 	(void) ttyoutput(c, tp);
16187502Sroot }
16197502Sroot 
16207502Sroot /*
16217502Sroot  * send string cp to tp
16227502Sroot  */
162340712Skarels ttyoutstr(cp, tp)
16247625Ssam 	register char *cp;
16257625Ssam 	register struct tty *tp;
16267502Sroot {
16277502Sroot 	register char c;
16287502Sroot 
16297502Sroot 	while (c = *cp++)
16307502Sroot 		(void) ttyoutput(c, tp);
16317502Sroot }
16327502Sroot 
163349380Skarels /*
163449380Skarels  * Wake up any readers on a tty.
163549380Skarels  */
16367502Sroot ttwakeup(tp)
163747545Skarels 	register struct tty *tp;
16387502Sroot {
16397502Sroot 
16407502Sroot 	if (tp->t_rsel) {
16417502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16427502Sroot 		tp->t_state &= ~TS_RCOLL;
16437502Sroot 		tp->t_rsel = 0;
16447502Sroot 	}
164512752Ssam 	if (tp->t_state & TS_ASYNC)
164642882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16477502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16487502Sroot }
164935811Smarc 
165035811Smarc /*
165148439Skarels  * Look up a code for a specified speed in a conversion table;
165248439Skarels  * used by drivers to map software speed values to hardware parameters.
165348439Skarels  */
165448439Skarels ttspeedtab(speed, table)
165548439Skarels 	register struct speedtab *table;
165648439Skarels {
165748439Skarels 
165848439Skarels 	for ( ; table->sp_speed != -1; table++)
165948439Skarels 		if (table->sp_speed == speed)
166048439Skarels 			return (table->sp_code);
166148439Skarels 	return (-1);
166248439Skarels }
166348439Skarels 
166448439Skarels /*
166535811Smarc  * set tty hi and low water marks
166635811Smarc  *
166735811Smarc  * Try to arrange the dynamics so there's about one second
166835811Smarc  * from hi to low water.
166935811Smarc  *
167035811Smarc  */
167135811Smarc ttsetwater(tp)
167235811Smarc 	struct tty *tp;
167335811Smarc {
167435811Smarc 	register cps = tp->t_ospeed / 10;
167535811Smarc 	register x;
167635811Smarc 
167735811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
167835811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
167935811Smarc 	x += cps;
168035811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
168135811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
168235811Smarc #undef clamp
168335811Smarc }
168435811Smarc 
168539407Smarc /*
168639407Smarc  * (^T)
168739407Smarc  * Report on state of foreground process group.
168839407Smarc  */
168939407Smarc ttyinfo(tp)
169039407Smarc 	struct tty *tp;
169139407Smarc {
169241177Smarc 	register struct proc *p, *pick = NULL;
169341177Smarc 	int x, s;
169441177Smarc 	struct timeval utime, stime;
169542350Smckusick #define	pgtok(a)	(((a)*NBPG)/1024)
169639407Smarc 
169739407Smarc 	if (ttycheckoutq(tp,0) == 0)
169839407Smarc 		return;
169941177Smarc 	/*
170041177Smarc 	 * load average
170141177Smarc 	 */
170241177Smarc 	x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT;
170341177Smarc 	ttyprintf(tp, "load: %d.", x/100);
170441177Smarc 	ttyoutint(x%100, 10, 2, tp);
170539555Smarc 	if (tp->t_session == NULL)
170641177Smarc 		ttyprintf(tp, " not a controlling terminal\n");
170741177Smarc 	else if (tp->t_pgrp == NULL)
170841177Smarc 		ttyprintf(tp, " no foreground process group\n");
170941177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
171041177Smarc 		ttyprintf(tp, " empty foreground process group\n");
171139407Smarc 	else {
171241177Smarc 		/* pick interesting process */
171339407Smarc 		for (; p != NULL; p = p->p_pgrpnxt) {
171441177Smarc 			if (proc_compare(pick, p))
171541177Smarc 				pick = p;
171639407Smarc 		}
171741177Smarc 		ttyprintf(tp, "  cmd: %s %d [%s] ",
171841177Smarc 			pick->p_comm, pick->p_pid,
171948439Skarels 			pick->p_stat == SRUN ? "running" :
172048439Skarels 			pick->p_wmesg ? pick->p_wmesg : "iowait");
172141177Smarc 		/*
172241177Smarc 		 * cpu time
172341177Smarc 		 */
172447545Skarels 		if (curproc == pick)
172541177Smarc 			s = splclock();
172641177Smarc 		utime = pick->p_utime;
172741177Smarc 		stime = pick->p_stime;
172847545Skarels 		if (curproc == pick)
172941177Smarc 			splx(s);
173041177Smarc 		/* user time */
173141177Smarc 		x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */
173241177Smarc 		ttyoutint(utime.tv_sec, 10, 1, tp);
173341177Smarc 		tputchar('.', tp);
173441177Smarc 		ttyoutint(x, 10, 2, tp);
173541177Smarc 		tputchar('u', tp);
173641177Smarc 		tputchar(' ', tp);
173741177Smarc 		/* system time */
173841177Smarc 		x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */
173941177Smarc 		ttyoutint(stime.tv_sec, 10, 1, tp);
174041177Smarc 		tputchar('.', tp);
174141177Smarc 		ttyoutint(x, 10, 2, tp);
174241177Smarc 		tputchar('s', tp);
174341177Smarc 		tputchar(' ', tp);
174441177Smarc 		/*
174541177Smarc 		 * pctcpu
174641177Smarc 		 */
174741177Smarc 		x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT;
174841177Smarc 		ttyoutint(x/100, 10, 1, tp);
174941177Smarc #ifdef notdef	/* do we really want this ??? */
175041177Smarc 		tputchar('.', tp);
175141177Smarc 		ttyoutint(x%100, 10, 2, tp);
175241177Smarc #endif
175347545Skarels 		ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize));
175439407Smarc 	}
175541177Smarc 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
175639407Smarc }
175739407Smarc 
175841177Smarc ttyoutint(n, base, min, tp)
175941177Smarc 	register int n, base, min;
176041177Smarc 	register struct tty *tp;
176141177Smarc {
176241177Smarc 	char info[16];
176341177Smarc 	register char *p = info;
176441177Smarc 
176541177Smarc 	while (--min >= 0 || n) {
176641177Smarc 		*p++ = "0123456789abcdef"[n%base];
176741177Smarc 		n /= base;
176841177Smarc 	}
176941177Smarc 	while (p > info)
177041177Smarc 		ttyoutput(*--p, tp);
177141177Smarc }
177241177Smarc 
177341177Smarc /*
177441177Smarc  * Returns 1 if p2 is "better" than p1
177541177Smarc  *
177641177Smarc  * The algorithm for picking the "interesting" process is thus:
177741177Smarc  *
177841177Smarc  *	1) (Only foreground processes are eligable - implied)
177941177Smarc  *	2) Runnable processes are favored over anything
178041177Smarc  *	   else.  The runner with the highest cpu
178141177Smarc  *	   utilization is picked (p_cpu).  Ties are
178241177Smarc  *	   broken by picking the highest pid.
178341177Smarc  *	3  Next, the sleeper with the shortest sleep
178441177Smarc  *	   time is favored.  With ties, we pick out
178541177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
178641177Smarc  *	   Further ties are broken by picking the highest
178741177Smarc  *	   pid.
178841177Smarc  *
178941177Smarc  */
179041177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179145723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
179245723Smckusick #define ONLYA   2
179345723Smckusick #define ONLYB   1
179445723Smckusick #define BOTH    3
179545723Smckusick 
179641177Smarc proc_compare(p1, p2)
179741177Smarc 	register struct proc *p1, *p2;
179841177Smarc {
179941177Smarc 
180041177Smarc 	if (p1 == NULL)
180141177Smarc 		return (1);
180241177Smarc 	/*
180341177Smarc 	 * see if at least one of them is runnable
180441177Smarc 	 */
180545723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
180645723Smckusick 	case ONLYA:
180745723Smckusick 		return (0);
180845723Smckusick 	case ONLYB:
180941177Smarc 		return (1);
181045723Smckusick 	case BOTH:
181141177Smarc 		/*
181241177Smarc 		 * tie - favor one with highest recent cpu utilization
181341177Smarc 		 */
181441177Smarc 		if (p2->p_cpu > p1->p_cpu)
181541177Smarc 			return (1);
181641177Smarc 		if (p1->p_cpu > p2->p_cpu)
181741177Smarc 			return (0);
181841177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
181941177Smarc 	}
182045723Smckusick 	/*
182145723Smckusick  	 * weed out zombies
182245723Smckusick 	 */
182345723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
182445723Smckusick 	case ONLYA:
182545723Smckusick 		return (1);
182645723Smckusick 	case ONLYB:
182745723Smckusick 		return (0);
182845723Smckusick 	case BOTH:
182945723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183045723Smckusick 	}
183141177Smarc 	/*
183241177Smarc 	 * pick the one with the smallest sleep time
183341177Smarc 	 */
183441177Smarc 	if (p2->p_slptime > p1->p_slptime)
183541177Smarc 		return (0);
183641177Smarc 	if (p1->p_slptime > p2->p_slptime)
183741177Smarc 		return (1);
183841177Smarc 	/*
183941177Smarc 	 * favor one sleeping in a non-interruptible sleep
184041177Smarc 	 */
184141177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
184241177Smarc 		return (1);
184341177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
184441177Smarc 		return (0);
184547545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
184641177Smarc }
184745723Smckusick 
184839555Smarc /*
184939555Smarc  * Output char to tty; console putchar style.
185039555Smarc  */
185139555Smarc tputchar(c, tp)
185239555Smarc 	int c;
185339555Smarc 	struct tty *tp;
185439555Smarc {
185539555Smarc 	register s = spltty();
185639555Smarc 
185747545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
185839555Smarc 		if (c == '\n')
185939555Smarc 			(void) ttyoutput('\r', tp);
186039555Smarc 		(void) ttyoutput(c, tp);
186139555Smarc 		ttstart(tp);
186239555Smarc 		splx(s);
186339555Smarc 		return (0);
186439555Smarc 	}
186539555Smarc 	splx(s);
186639555Smarc 	return (-1);
186739555Smarc }
186843377Smarc 
186944419Smarc /*
187049380Skarels  * Sleep on chan, returning ERESTART if tty changed
187149380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
187249380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
187349380Skarels  * call will redo validation done at the start of the call.
187444419Smarc  */
187543377Smarc ttysleep(tp, chan, pri, wmesg, timo)
187643377Smarc 	struct tty *tp;
187743377Smarc 	caddr_t chan;
187843377Smarc 	int pri;
187943377Smarc 	char *wmesg;
188043377Smarc 	int timo;
188143377Smarc {
188243377Smarc 	int error;
188343377Smarc 	short gen = tp->t_gen;
188443377Smarc 
188543377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
188643377Smarc 		return (error);
188743377Smarc 	if (tp->t_gen != gen)
188843377Smarc 		return (ERESTART);
188943377Smarc 	return (0);
189043377Smarc }
1891