xref: /csrg-svn/sys/kern/tty.c (revision 51068)
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*51068Smarc  *	@(#)tty.c	7.47 (Berkeley) 09/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 
2849907Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2));
2949907Sbostic 
3040712Skarels /* symbolic sleep message strings */
3140712Skarels char ttyin[] = "ttyin";
3240712Skarels char ttyout[] = "ttyout";
3341370Smarc char ttopen[] = "ttyopn";
3441370Smarc char ttclos[] = "ttycls";
3540712Skarels char ttybg[] = "ttybg";
3640712Skarels char ttybuf[] = "ttybuf";
3740712Skarels 
387436Skre /*
397436Skre  * Table giving parity for characters and indicating
4035811Smarc  * character classes to tty driver. The 8th bit
4135811Smarc  * indicates parity, the 7th bit indicates the character
4235811Smarc  * is an alphameric or underscore (for ALTWERASE), and the
4335811Smarc  * low 6 bits indicate delay type.  If the low 6 bits are 0
4449380Skarels  * then the character needs no special processing on output;
4549380Skarels  * classes other than 0 might be translated or (not currently)
4649380Skarels  * require delays.
477436Skre  */
4849380Skarels #define	PARITY(c)	(partab[c] & 0x80)
4949380Skarels #define	ISALPHA(c)	(partab[(c)&TTY_CHARMASK] & 0x40)
5049380Skarels #define	CCLASSMASK	0x3f
5149380Skarels #define	CCLASS(c)	(partab[c] & CCLASSMASK)
5239Sbill 
5349380Skarels #define	E	0x00	/* even parity */
5449380Skarels #define	O	0x80	/* odd parity */
5549380Skarels #define	ALPHA	0x40	/* alpha or underscore */
5649380Skarels 
5749380Skarels #define	NO	ORDINARY
5849380Skarels #define	NA	ORDINARY|ALPHA
5949380Skarels #define	CC	CONTROL
6049380Skarels #define	BS	BACKSPACE
6149380Skarels #define	NL	NEWLINE
6249380Skarels #define	TB	TAB
6349380Skarels #define	VT	VTAB
6449380Skarels #define	CR	RETURN
6549380Skarels 
667436Skre char partab[] = {
6749380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC,	/* nul - bel */
6849380Skarels 	O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
6949380Skarels 	O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
7049380Skarels 	E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
7149380Skarels 	O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7249380Skarels 	E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7349380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
7449380Skarels 	O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
7549380Skarels 	O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
7649380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
7749380Skarels 	E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
7849380Skarels 	O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
7949380Skarels 	E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
8049380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
8149380Skarels 	O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8249380Skarels 	E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
837436Skre 	/*
8449380Skarels 	 * "meta" chars; should be settable per charset.
8549380Skarels 	 * For now, treat all as normal characters.
867436Skre 	 */
8749380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
8849380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
8949380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9049380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9149380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9249380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9349380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9449380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9549380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9649380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9749380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9849380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
9949380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10049380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10149380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
10249380Skarels 	NA,   NA,   NA,   NA,   NA,   NA,   NA,   NA,
1037436Skre };
10449380Skarels #undef	NO
10549380Skarels #undef	NA
10649380Skarels #undef	CC
10749380Skarels #undef	BS
10849380Skarels #undef	NL
10949380Skarels #undef	TB
11049380Skarels #undef	VT
11149380Skarels #undef	CR
1127436Skre 
11335811Smarc extern struct tty *constty;		/* temporary virtual console */
11435811Smarc 
115146Sbill /*
11635811Smarc  * Is 'c' a line delimiter ("break" character)?
11739Sbill  */
11840712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \
11940712Skarels 	(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
12039Sbill 
12139Sbill ttychars(tp)
1229578Ssam 	struct tty *tp;
12339Sbill {
12447545Skarels 
12535811Smarc 	bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
12639Sbill }
12739Sbill 
12839Sbill /*
12949380Skarels  * Flush tty after output has drained.
13039Sbill  */
13112752Ssam ttywflush(tp)
13237584Smarc 	struct tty *tp;
13339Sbill {
13440712Skarels 	int error;
13539Sbill 
13640712Skarels 	if ((error = ttywait(tp)) == 0)
13740712Skarels 		ttyflush(tp, FREAD);
13840712Skarels 	return (error);
13912752Ssam }
14012752Ssam 
14135811Smarc /*
14235811Smarc  * Wait for output to drain.
14335811Smarc  */
14412752Ssam ttywait(tp)
14512752Ssam 	register struct tty *tp;
14612752Ssam {
14740712Skarels 	int error = 0, s = spltty();
14812752Ssam 
14913809Ssam 	while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) &&
15037584Smarc 	    (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
15137584Smarc 	    tp->t_oproc) {
152903Sbill 		(*tp->t_oproc)(tp);
1535408Swnj 		tp->t_state |= TS_ASLEEP;
15443377Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_outq,
15543377Smarc 		    TTOPRI | PCATCH, ttyout, 0))
15640712Skarels 			break;
157903Sbill 	}
1589859Ssam 	splx(s);
15940712Skarels 	return (error);
16039Sbill }
16139Sbill 
16249380Skarels #define	flushq(qq) { \
16349380Skarels 	register struct clist *q = qq; \
16449380Skarels 	if (q->c_cc) \
16549380Skarels 		ndflush(q, q->c_cc); \
16649380Skarels }
16749380Skarels 
16839Sbill /*
16949380Skarels  * Flush TTY read and/or write queues,
17049380Skarels  * notifying anyone waiting.
17139Sbill  */
17212752Ssam ttyflush(tp, rw)
1737625Ssam 	register struct tty *tp;
17439Sbill {
175903Sbill 	register s;
176903Sbill 
17717545Skarels 	s = spltty();
178903Sbill 	if (rw & FREAD) {
17949380Skarels 		flushq(&tp->t_canq);
18049380Skarels 		flushq(&tp->t_rawq);
18149380Skarels 		tp->t_rocount = 0;
18249380Skarels 		tp->t_rocol = 0;
18349380Skarels 		tp->t_state &= ~TS_LOCAL;
18437584Smarc 		ttwakeup(tp);
185903Sbill 	}
186903Sbill 	if (rw & FWRITE) {
1875408Swnj 		tp->t_state &= ~TS_TTSTOP;
1885426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
18949380Skarels 		flushq(&tp->t_outq);
19049380Skarels 		wakeup((caddr_t)&tp->t_outq);
19149380Skarels 		if (tp->t_wsel) {
19249380Skarels 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
19349380Skarels 			tp->t_wsel = 0;
19449380Skarels 			tp->t_state &= ~TS_WCOLL;
19549380Skarels 		}
196903Sbill 	}
197903Sbill 	splx(s);
19839Sbill }
19939Sbill 
200903Sbill /*
201903Sbill  * Send stop character on input overflow.
202903Sbill  */
203903Sbill ttyblock(tp)
2047625Ssam 	register struct tty *tp;
20539Sbill {
206903Sbill 	register x;
2079578Ssam 
208903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
209903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
21012752Ssam 		ttyflush(tp, FREAD|FWRITE);
2115408Swnj 		tp->t_state &= ~TS_TBLOCK;
212903Sbill 	}
21315118Skarels 	/*
21415118Skarels 	 * Block further input iff:
21515118Skarels 	 * Current input > threshold AND input is available to user program
21615118Skarels 	 */
21742350Smckusick 	if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
21840712Skarels 	    ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) &&
21935811Smarc 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
22042350Smckusick 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
22115118Skarels 			tp->t_state |= TS_TBLOCK;
22215118Skarels 			ttstart(tp);
22315118Skarels 		}
224903Sbill 	}
22539Sbill }
22639Sbill 
22747545Skarels ttstart(tp)
22837584Smarc 	struct tty *tp;
229121Sbill {
230121Sbill 
23147545Skarels 	if (tp->t_oproc)		/* kludge for pty */
23247545Skarels 		(*tp->t_oproc)(tp);
23347545Skarels }
23447545Skarels 
23547545Skarels ttrstrt(tp)				/* XXX */
23647545Skarels 	struct tty *tp;
23747545Skarels {
23847545Skarels 
23940712Skarels #ifdef DIAGNOSTIC
2409578Ssam 	if (tp == 0)
2419578Ssam 		panic("ttrstrt");
24240712Skarels #endif
2435408Swnj 	tp->t_state &= ~TS_TIMEOUT;
244903Sbill 	ttstart(tp);
245121Sbill }
246121Sbill 
24739Sbill 
24839Sbill /*
24949380Skarels  * Common code for ioctls on tty devices.
25049380Skarels  * Called after line-discipline-specific ioctl
25149380Skarels  * has been called to do discipline-specific functions
25249380Skarels  * and/or reject any of these ioctl commands.
25339Sbill  */
2541780Sbill /*ARGSUSED*/
2557625Ssam ttioctl(tp, com, data, flag)
2567625Ssam 	register struct tty *tp;
2577625Ssam 	caddr_t data;
25839Sbill {
25947545Skarels 	register struct proc *p = curproc;		/* XXX */
26039Sbill 	extern int nldisp;
26137554Smckusick 	int s, error;
26239Sbill 
263903Sbill 	/*
264903Sbill 	 * If the ioctl involves modification,
26517545Skarels 	 * hang if in the background.
266903Sbill 	 */
2677625Ssam 	switch (com) {
26839Sbill 
26935811Smarc 	case TIOCSETD:
270903Sbill 	case TIOCFLUSH:
27135811Smarc 	/*case TIOCSPGRP:*/
2729325Ssam 	case TIOCSTI:
27317598Sbloom 	case TIOCSWINSZ:
27435811Smarc 	case TIOCSETA:
27535811Smarc 	case TIOCSETAW:
27635811Smarc 	case TIOCSETAF:
27740030Smarc #ifdef COMPAT_43
27840030Smarc 	case TIOCSETP:
27940030Smarc 	case TIOCSETN:
28040030Smarc 	case TIOCSETC:
28140030Smarc 	case TIOCSLTC:
28240030Smarc 	case TIOCLBIS:
28340030Smarc 	case TIOCLBIC:
28440030Smarc 	case TIOCLSET:
28540030Smarc 	case OTIOCSETD:
28640030Smarc #endif
28747545Skarels 		while (isbackground(curproc, tp) &&
28847545Skarels 		   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
28947545Skarels 		   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
29047545Skarels 		   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
29147545Skarels 			pgsignal(p->p_pgrp, SIGTTOU, 1);
29243377Smarc 			if (error = ttysleep(tp, (caddr_t)&lbolt,
29343377Smarc 			    TTOPRI | PCATCH, ttybg, 0))
29440712Skarels 				return (error);
295903Sbill 		}
296903Sbill 		break;
297903Sbill 	}
298903Sbill 
2999578Ssam 	/*
3009578Ssam 	 * Process the ioctl.
3019578Ssam 	 */
3027625Ssam 	switch (com) {
303903Sbill 
3048556Sroot 	/* get discipline number */
30539Sbill 	case TIOCGETD:
3067625Ssam 		*(int *)data = tp->t_line;
30739Sbill 		break;
30839Sbill 
3098556Sroot 	/* set line discipline */
3107625Ssam 	case TIOCSETD: {
3117625Ssam 		register int t = *(int *)data;
31235811Smarc 		dev_t dev = tp->t_dev;
3137625Ssam 
31435811Smarc 		if ((unsigned)t >= nldisp)
31510851Ssam 			return (ENXIO);
31625584Skarels 		if (t != tp->t_line) {
31725584Skarels 			s = spltty();
31849752Smarc 			(*linesw[tp->t_line].l_close)(tp, flag);
31925584Skarels 			error = (*linesw[t].l_open)(dev, tp);
32025584Skarels 			if (error) {
32135811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
32225584Skarels 				splx(s);
32325584Skarels 				return (error);
32425584Skarels 			}
32525584Skarels 			tp->t_line = t;
32610851Ssam 			splx(s);
32710851Ssam 		}
32839Sbill 		break;
3297625Ssam 	}
33039Sbill 
3318556Sroot 	/* prevent more opens on channel */
3325614Swnj 	case TIOCEXCL:
3335614Swnj 		tp->t_state |= TS_XCLUDE;
3345614Swnj 		break;
3355614Swnj 
3365614Swnj 	case TIOCNXCL:
3375614Swnj 		tp->t_state &= ~TS_XCLUDE;
3385614Swnj 		break;
3395614Swnj 
34039Sbill 	case TIOCHPCL:
34135811Smarc 		tp->t_cflag |= HUPCL;
34239Sbill 		break;
34339Sbill 
3443942Sbugs 	case TIOCFLUSH: {
3457625Ssam 		register int flags = *(int *)data;
3467625Ssam 
3477625Ssam 		if (flags == 0)
3483942Sbugs 			flags = FREAD|FWRITE;
3497625Ssam 		else
3507625Ssam 			flags &= FREAD|FWRITE;
35112752Ssam 		ttyflush(tp, flags);
35239Sbill 		break;
3533944Sbugs 	}
35439Sbill 
35537584Smarc 	case FIOASYNC:
35637584Smarc 		if (*(int *)data)
35737584Smarc 			tp->t_state |= TS_ASYNC;
35837584Smarc 		else
35937584Smarc 			tp->t_state &= ~TS_ASYNC;
36037584Smarc 		break;
36137584Smarc 
36237584Smarc 	case FIONBIO:
36337584Smarc 		break;	/* XXX remove */
36437584Smarc 
3658556Sroot 	/* return number of characters immediately available */
3667625Ssam 	case FIONREAD:
3677625Ssam 		*(off_t *)data = ttnread(tp);
368174Sbill 		break;
369174Sbill 
37013077Ssam 	case TIOCOUTQ:
37113077Ssam 		*(int *)data = tp->t_outq.c_cc;
37213077Ssam 		break;
37313077Ssam 
3748589Sroot 	case TIOCSTOP:
37517545Skarels 		s = spltty();
3769578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3775573Swnj 			tp->t_state |= TS_TTSTOP;
3785573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
3795573Swnj 		}
3807625Ssam 		splx(s);
3815573Swnj 		break;
3825573Swnj 
3838589Sroot 	case TIOCSTART:
38417545Skarels 		s = spltty();
38535811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
3865573Swnj 			tp->t_state &= ~TS_TTSTOP;
38735811Smarc 			tp->t_lflag &= ~FLUSHO;
3885573Swnj 			ttstart(tp);
3895573Swnj 		}
3907625Ssam 		splx(s);
3915573Swnj 		break;
3925573Swnj 
3939325Ssam 	/*
3949325Ssam 	 * Simulate typing of a character at the terminal.
3959325Ssam 	 */
3969325Ssam 	case TIOCSTI:
39747545Skarels 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
39817183Smckusick 			return (EPERM);
39947545Skarels 		if (p->p_ucred->cr_uid && !isctty(p, tp))
4009325Ssam 			return (EACCES);
4019578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4029325Ssam 		break;
4039325Ssam 
40435811Smarc 	case TIOCGETA: {
40535811Smarc 		struct termios *t = (struct termios *)data;
40612752Ssam 
40735811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
40835811Smarc 		break;
40935811Smarc 	}
41035811Smarc 
41135811Smarc 	case TIOCSETA:
41235811Smarc 	case TIOCSETAW:
41337584Smarc 	case TIOCSETAF: {
41435811Smarc 		register struct termios *t = (struct termios *)data;
41540712Skarels 
41617545Skarels 		s = spltty();
41739407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
41840712Skarels 			if (error = ttywait(tp)) {
41940712Skarels 				splx(s);
42040712Skarels 				return (error);
42140712Skarels 			}
42245007Smarc 			if (com == TIOCSETAF)
42339407Smarc 				ttyflush(tp, FREAD);
42439407Smarc 		}
42540712Skarels 		if ((t->c_cflag&CIGNORE) == 0) {
42635811Smarc 			/*
42735811Smarc 			 * set device hardware
42835811Smarc 			 */
42937584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
43037584Smarc 				splx(s);
43135811Smarc 				return (error);
43237584Smarc 			} else {
43340712Skarels 				if ((tp->t_state&TS_CARR_ON) == 0 &&
43437584Smarc 				    (tp->t_cflag&CLOCAL) &&
43540712Skarels 				    (t->c_cflag&CLOCAL) == 0) {
43637584Smarc 					tp->t_state &= ~TS_ISOPEN;
43737584Smarc 					tp->t_state |= TS_WOPEN;
43837584Smarc 					ttwakeup(tp);
43937584Smarc 				}
44035811Smarc 				tp->t_cflag = t->c_cflag;
44135811Smarc 				tp->t_ispeed = t->c_ispeed;
44235811Smarc 				tp->t_ospeed = t->c_ospeed;
44334492Skarels 			}
44435811Smarc 			ttsetwater(tp);
44512752Ssam 		}
44639407Smarc 		if (com != TIOCSETAF) {
44735811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
44835811Smarc 				if (t->c_lflag&ICANON) {
44935811Smarc 					tp->t_lflag |= PENDIN;
45035811Smarc 					ttwakeup(tp);
45135811Smarc 				}
45235811Smarc 				else {
45335811Smarc 					struct clist tq;
45435811Smarc 
45535811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
45635811Smarc 					tq = tp->t_rawq;
45735811Smarc 					tp->t_rawq = tp->t_canq;
45835811Smarc 					tp->t_canq = tq;
45935811Smarc 				}
46012752Ssam 		}
46135811Smarc 		tp->t_iflag = t->c_iflag;
46235811Smarc 		tp->t_oflag = t->c_oflag;
46342882Smarc 		/*
46442882Smarc 		 * Make the EXTPROC bit read only.
46542882Smarc 		 */
46642882Smarc 		if (tp->t_lflag&EXTPROC)
46742882Smarc 			t->c_lflag |= EXTPROC;
46842882Smarc 		else
46942882Smarc 			t->c_lflag &= ~EXTPROC;
47035811Smarc 		tp->t_lflag = t->c_lflag;
47135811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
47212752Ssam 		splx(s);
47312752Ssam 		break;
47412752Ssam 	}
47512752Ssam 
47612752Ssam 	/*
47739555Smarc 	 * Set controlling terminal.
47839555Smarc 	 * Session ctty vnode pointer set in vnode layer.
47934492Skarels 	 */
48047545Skarels 	case TIOCSCTTY:
48139555Smarc 		if (!SESS_LEADER(p) ||
48239555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
48339555Smarc 		   (tp->t_session != p->p_session))
48439407Smarc 			return (EPERM);
48535811Smarc 		tp->t_session = p->p_session;
48639555Smarc 		tp->t_pgrp = p->p_pgrp;
48739555Smarc 		p->p_session->s_ttyp = tp;
48839555Smarc 		p->p_flag |= SCTTY;
48934492Skarels 		break;
49039555Smarc 
49134492Skarels 	/*
49235811Smarc 	 * Set terminal process group.
49317545Skarels 	 */
49418650Sbloom 	case TIOCSPGRP: {
49535811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
49617545Skarels 
49739555Smarc 		if (!isctty(p, tp))
49839555Smarc 			return (ENOTTY);
49940030Smarc 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
50039555Smarc 			return (EPERM);
50139555Smarc 		tp->t_pgrp = pgrp;
50212752Ssam 		break;
50318650Sbloom 	}
50412752Ssam 
50512752Ssam 	case TIOCGPGRP:
50647545Skarels 		if (!isctty(p, tp))
50739555Smarc 			return (ENOTTY);
50845007Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
50912752Ssam 		break;
51012752Ssam 
51117598Sbloom 	case TIOCSWINSZ:
51218650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
51318650Sbloom 		    sizeof (struct winsize))) {
51417598Sbloom 			tp->t_winsize = *(struct winsize *)data;
51542882Smarc 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
51617598Sbloom 		}
51717598Sbloom 		break;
51817598Sbloom 
51917598Sbloom 	case TIOCGWINSZ:
52017598Sbloom 		*(struct winsize *)data = tp->t_winsize;
52117598Sbloom 		break;
52217598Sbloom 
52330534Skarels 	case TIOCCONS:
52430534Skarels 		if (*(int *)data) {
52542141Smckusick 			if (constty && constty != tp &&
52642141Smckusick 			    (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
52742141Smckusick 			    (TS_CARR_ON|TS_ISOPEN))
52830534Skarels 				return (EBUSY);
52930534Skarels #ifndef	UCONSOLE
53047545Skarels 			if (error = suser(p->p_ucred, &p->p_acflag))
53137554Smckusick 				return (error);
53230534Skarels #endif
53330534Skarels 			constty = tp;
53430534Skarels 		} else if (tp == constty)
53533404Skarels 			constty = NULL;
53630534Skarels 		break;
53730534Skarels 
53848439Skarels 	case TIOCDRAIN:
53948439Skarels 		if (error = ttywait(tp))
54048439Skarels 			return (error);
54148439Skarels 		break;
54248439Skarels 
54347545Skarels 	default:
54435811Smarc #ifdef COMPAT_43
54547545Skarels 		return (ttcompat(tp, com, data, flag));
54647545Skarels #else
54747545Skarels 		return (-1);
54835811Smarc #endif
54939Sbill 	}
5508556Sroot 	return (0);
55139Sbill }
5524484Swnj 
5534484Swnj ttnread(tp)
5544484Swnj 	struct tty *tp;
5554484Swnj {
5564484Swnj 	int nread = 0;
5574484Swnj 
55835811Smarc 	if (tp->t_lflag & PENDIN)
5594484Swnj 		ttypend(tp);
5604484Swnj 	nread = tp->t_canq.c_cc;
56135811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5624484Swnj 		nread += tp->t_rawq.c_cc;
5634484Swnj 	return (nread);
5644484Swnj }
5654484Swnj 
5665408Swnj ttselect(dev, rw)
5674484Swnj 	dev_t dev;
5685408Swnj 	int rw;
5694484Swnj {
5704484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5714484Swnj 	int nread;
57217545Skarels 	int s = spltty();
5734484Swnj 
5745408Swnj 	switch (rw) {
5754484Swnj 
5764484Swnj 	case FREAD:
5774484Swnj 		nread = ttnread(tp);
57837584Smarc 		if (nread > 0 ||
57940712Skarels 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
5805408Swnj 			goto win;
5814938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
5825408Swnj 			tp->t_state |= TS_RCOLL;
5834484Swnj 		else
58447545Skarels 			tp->t_rsel = curproc;
5855408Swnj 		break;
5864484Swnj 
5875408Swnj 	case FWRITE:
58835811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
5895408Swnj 			goto win;
5905408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
5915408Swnj 			tp->t_state |= TS_WCOLL;
5925408Swnj 		else
59347545Skarels 			tp->t_wsel = curproc;
5945408Swnj 		break;
5954484Swnj 	}
5965408Swnj 	splx(s);
5975408Swnj 	return (0);
5985408Swnj win:
5995408Swnj 	splx(s);
6005408Swnj 	return (1);
6014484Swnj }
6027436Skre 
6037502Sroot /*
60449380Skarels  * Initial open of tty, or (re)entry to standard tty line discipline.
6057502Sroot  */
6067502Sroot ttyopen(dev, tp)
6077625Ssam 	dev_t dev;
6087625Ssam 	register struct tty *tp;
6097502Sroot {
6107502Sroot 
6117502Sroot 	tp->t_dev = dev;
61235811Smarc 
6137502Sroot 	tp->t_state &= ~TS_WOPEN;
61417545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
61517545Skarels 		tp->t_state |= TS_ISOPEN;
61617598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
61717545Skarels 	}
6188556Sroot 	return (0);
6197502Sroot }
6207502Sroot 
6217502Sroot /*
62225391Skarels  * "close" a line discipline
62325391Skarels  */
62449752Smarc ttylclose(tp, flag)
62549752Smarc 	struct tty *tp;
62649752Smarc 	int flag;
62725391Skarels {
62825391Skarels 
62949752Smarc 	if (flag&IO_NDELAY)
63049752Smarc 		ttyflush(tp, FREAD|FWRITE);
63149752Smarc 	else
63249752Smarc 		ttywflush(tp);
63325391Skarels }
63425391Skarels 
63525391Skarels /*
63649380Skarels  * Handle close() on a tty line: flush and set to initial state,
63749380Skarels  * bumping generation number so that pending read/write calls
63849380Skarels  * can detect recycling of the tty.
6397502Sroot  */
6407502Sroot ttyclose(tp)
6417625Ssam 	register struct tty *tp;
6427502Sroot {
64330534Skarels 	if (constty == tp)
64430534Skarels 		constty = NULL;
64525391Skarels 	ttyflush(tp, FREAD|FWRITE);
64639555Smarc 	tp->t_session = NULL;
64739555Smarc 	tp->t_pgrp = NULL;
6487502Sroot 	tp->t_state = 0;
64943377Smarc 	tp->t_gen++;
65040712Skarels 	return (0);
6517502Sroot }
6527502Sroot 
6537502Sroot /*
65425391Skarels  * Handle modem control transition on a tty.
65525391Skarels  * Flag indicates new state of carrier.
65625391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
65725391Skarels  */
65825391Skarels ttymodem(tp, flag)
65925391Skarels 	register struct tty *tp;
66025391Skarels {
66125391Skarels 
66242193Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
66325391Skarels 		/*
66425391Skarels 		 * MDMBUF: do flow control according to carrier flag
66525391Skarels 		 */
66625391Skarels 		if (flag) {
66725391Skarels 			tp->t_state &= ~TS_TTSTOP;
66825391Skarels 			ttstart(tp);
66925391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
67025391Skarels 			tp->t_state |= TS_TTSTOP;
67125391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
67225391Skarels 		}
67325391Skarels 	} else if (flag == 0) {
67425391Skarels 		/*
67525391Skarels 		 * Lost carrier.
67625391Skarels 		 */
67725391Skarels 		tp->t_state &= ~TS_CARR_ON;
67842193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
67942193Smarc 			if (tp->t_session && tp->t_session->s_leader)
68042193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
68142193Smarc 			ttyflush(tp, FREAD|FWRITE);
68242193Smarc 			return (0);
68325391Skarels 		}
68425391Skarels 	} else {
68525391Skarels 		/*
68625391Skarels 		 * Carrier now on.
68725391Skarels 		 */
68825391Skarels 		tp->t_state |= TS_CARR_ON;
68937584Smarc 		ttwakeup(tp);
69025391Skarels 	}
69125391Skarels 	return (1);
69225391Skarels }
69325391Skarels 
69425391Skarels /*
69525404Skarels  * Default modem control routine (for other line disciplines).
69625404Skarels  * Return argument flag, to turn off device on carrier drop.
69725404Skarels  */
69825415Skarels nullmodem(tp, flag)
69925415Skarels 	register struct tty *tp;
70025404Skarels 	int flag;
70125404Skarels {
70225404Skarels 
70325404Skarels 	if (flag)
70425404Skarels 		tp->t_state |= TS_CARR_ON;
70539407Smarc 	else {
70625404Skarels 		tp->t_state &= ~TS_CARR_ON;
70742193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
70842193Smarc 			if (tp->t_session && tp->t_session->s_leader)
70942193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
71042193Smarc 			return (0);
71142193Smarc 		}
71239407Smarc 	}
71342193Smarc 	return (1);
71425404Skarels }
71525404Skarels 
71625404Skarels /*
7177502Sroot  * reinput pending characters after state switch
71817545Skarels  * call at spltty().
7197502Sroot  */
7207502Sroot ttypend(tp)
7217625Ssam 	register struct tty *tp;
7227502Sroot {
7237502Sroot 	struct clist tq;
7247502Sroot 	register c;
7257502Sroot 
72635811Smarc 	tp->t_lflag &= ~PENDIN;
7279578Ssam 	tp->t_state |= TS_TYPEN;
7287502Sroot 	tq = tp->t_rawq;
7297502Sroot 	tp->t_rawq.c_cc = 0;
7307502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7317502Sroot 	while ((c = getc(&tq)) >= 0)
7327502Sroot 		ttyinput(c, tp);
7339578Ssam 	tp->t_state &= ~TS_TYPEN;
7347502Sroot }
7357502Sroot 
7367502Sroot /*
73749380Skarels  * Process input of a single character received on a tty.
7387502Sroot  */
7397502Sroot ttyinput(c, tp)
7407625Ssam 	register c;
7417625Ssam 	register struct tty *tp;
7427502Sroot {
74335811Smarc 	register int iflag = tp->t_iflag;
74435811Smarc 	register int lflag = tp->t_lflag;
74535811Smarc 	register u_char *cc = tp->t_cc;
74635811Smarc 	int i, err;
7477502Sroot 
7489578Ssam 	/*
7499578Ssam 	 * If input is pending take it first.
7509578Ssam 	 */
75135811Smarc 	if (lflag&PENDIN)
7527502Sroot 		ttypend(tp);
75335811Smarc 	/*
75435811Smarc 	 * Gather stats.
75535811Smarc 	 */
7567502Sroot 	tk_nin++;
75735811Smarc 	if (lflag&ICANON) {
75835811Smarc 		tk_cancc++;
75935811Smarc 		tp->t_cancc++;
76035811Smarc 	} else {
76135811Smarc 		tk_rawcc++;
76235811Smarc 		tp->t_rawcc++;
76335811Smarc 	}
7649578Ssam 	/*
76535811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7669578Ssam 	 */
76735811Smarc 	if (err = (c&TTY_ERRORMASK)) {
76835811Smarc 		c &= ~TTY_ERRORMASK;
76935811Smarc 		if (err&TTY_FE && !c) {		/* break */
77035811Smarc 			if (iflag&IGNBRK)
77135811Smarc 				goto endcase;
77235811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
77335811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
77435811Smarc 				c = cc[VINTR];
77547545Skarels 			else if (iflag&PARMRK)
77647545Skarels 				goto parmrk;
77735811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
77835811Smarc 			if (iflag&IGNPAR)
77935811Smarc 				goto endcase;
78035811Smarc 			else if (iflag&PARMRK) {
78135811Smarc parmrk:
78235811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
78335811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
78435811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
78535811Smarc 				goto endcase;
78635811Smarc 			} else
78735811Smarc 				c = 0;
7887502Sroot 		}
7899578Ssam 	}
7909578Ssam 	/*
79135811Smarc 	 * In tandem mode, check high water mark.
7929578Ssam 	 */
79335811Smarc 	if (iflag&IXOFF)
79435811Smarc 		ttyblock(tp);
79535811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
79649380Skarels 		c &= ~0x80;
79744419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
79844419Smarc 		/*
79944419Smarc 		 * Check for literal nexting very first
80044419Smarc 		 */
80144419Smarc 		if (tp->t_state&TS_LNCH) {
80244419Smarc 			c |= TTY_QUOTE;
80344419Smarc 			tp->t_state &= ~TS_LNCH;
80444419Smarc 		}
80544419Smarc 		/*
80644419Smarc 		 * Scan for special characters.  This code
80744419Smarc 		 * is really just a big case statement with
80844419Smarc 		 * non-constant cases.  The bottom of the
80944419Smarc 		 * case statement is labeled ``endcase'', so goto
81044419Smarc 		 * it after a case match, or similar.
81144419Smarc 		 */
81244419Smarc 
81344419Smarc 		/*
81444419Smarc 		 * Control chars which aren't controlled
81544419Smarc 		 * by ICANON, ISIG, or IXON.
81644419Smarc 		 */
81744419Smarc 		if (lflag&IEXTEN) {
81844419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
81944419Smarc 				if (lflag&ECHO) {
82044419Smarc 					if (lflag&ECHOE)
82144419Smarc 						ttyoutstr("^\b", tp);
82244419Smarc 					else
82344419Smarc 						ttyecho(c, tp);
82444419Smarc 				}
82544419Smarc 				tp->t_state |= TS_LNCH;
82644419Smarc 				goto endcase;
82744419Smarc 			}
82844419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
82944419Smarc 				if (lflag&FLUSHO)
83044419Smarc 					tp->t_lflag &= ~FLUSHO;
83144419Smarc 				else {
83244419Smarc 					ttyflush(tp, FWRITE);
83335811Smarc 					ttyecho(c, tp);
83444419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
83544419Smarc 						ttyretype(tp);
83644419Smarc 					tp->t_lflag |= FLUSHO;
83744419Smarc 				}
83844419Smarc 				goto startoutput;
83935811Smarc 			}
8409578Ssam 		}
84144419Smarc 		/*
84244419Smarc 		 * Signals.
84344419Smarc 		 */
84444419Smarc 		if (lflag&ISIG) {
84544419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
84644419Smarc 				if ((lflag&NOFLSH) == 0)
84744419Smarc 					ttyflush(tp, FREAD|FWRITE);
8487502Sroot 				ttyecho(c, tp);
84944419Smarc 				pgsignal(tp->t_pgrp,
85044419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
85144419Smarc 				goto endcase;
8527502Sroot 			}
85344419Smarc 			if (CCEQ(cc[VSUSP], c)) {
85444419Smarc 				if ((lflag&NOFLSH) == 0)
85544419Smarc 					ttyflush(tp, FREAD);
85644419Smarc 				ttyecho(c, tp);
85744419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
85844419Smarc 				goto endcase;
85944419Smarc 			}
8609578Ssam 		}
86144419Smarc 		/*
86244419Smarc 		 * Handle start/stop characters.
86344419Smarc 		 */
86444419Smarc 		if (iflag&IXON) {
86544419Smarc 			if (CCEQ(cc[VSTOP], c)) {
86644419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
86744419Smarc 					tp->t_state |= TS_TTSTOP;
86844419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
86944419Smarc 					   0);
87044419Smarc 					return;
87144419Smarc 				}
87244419Smarc 				if (!CCEQ(cc[VSTART], c))
87344419Smarc 					return;
87444419Smarc 				/*
87544419Smarc 				 * if VSTART == VSTOP then toggle
87644419Smarc 				 */
87744419Smarc 				goto endcase;
87835811Smarc 			}
87944419Smarc 			if (CCEQ(cc[VSTART], c))
88044419Smarc 				goto restartoutput;
8819578Ssam 		}
88244419Smarc 		/*
88344419Smarc 		 * IGNCR, ICRNL, & INLCR
88444419Smarc 		 */
88544419Smarc 		if (c == '\r') {
88644419Smarc 			if (iflag&IGNCR)
88744419Smarc 				goto endcase;
88844419Smarc 			else if (iflag&ICRNL)
88944419Smarc 				c = '\n';
89044419Smarc 		} else if (c == '\n' && iflag&INLCR)
89144419Smarc 			c = '\r';
8929578Ssam 	}
89347545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
89444419Smarc 		/*
89544419Smarc 		 * From here on down canonical mode character
89644419Smarc 		 * processing takes place.
89744419Smarc 		 */
89844419Smarc 		/*
89944419Smarc 		 * erase (^H / ^?)
90044419Smarc 		 */
90144419Smarc 		if (CCEQ(cc[VERASE], c)) {
90244419Smarc 			if (tp->t_rawq.c_cc)
9039578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
90444419Smarc 			goto endcase;
9059578Ssam 		}
90644419Smarc 		/*
90744419Smarc 		 * kill (^U)
90844419Smarc 		 */
90944419Smarc 		if (CCEQ(cc[VKILL], c)) {
91044419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
91144419Smarc 			    (lflag&ECHOPRT) == 0) {
91244419Smarc 				while (tp->t_rawq.c_cc)
91344419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
91444419Smarc 			} else {
91544419Smarc 				ttyecho(c, tp);
91644419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
91744419Smarc 					ttyecho('\n', tp);
91844419Smarc 				while (getc(&tp->t_rawq) > 0)
91944419Smarc 					;
92044419Smarc 				tp->t_rocount = 0;
92144419Smarc 			}
92244419Smarc 			tp->t_state &= ~TS_LOCAL;
92344419Smarc 			goto endcase;
92444419Smarc 		}
92544419Smarc 		/*
92644419Smarc 		 * word erase (^W)
92744419Smarc 		 */
92844419Smarc 		if (CCEQ(cc[VWERASE], c)) {
92944419Smarc 			int ctype;
93047545Skarels 			int alt = lflag&ALTWERASE;
93135811Smarc 
93244419Smarc 			/*
93344419Smarc 			 * erase whitespace
93444419Smarc 			 */
93544419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
93644419Smarc 				ttyrub(c, tp);
93744419Smarc 			if (c == -1)
93844419Smarc 				goto endcase;
93944419Smarc 			/*
94047545Skarels 			 * erase last char of word and remember the
94147545Skarels 			 * next chars type (for ALTWERASE)
94244419Smarc 			 */
94335811Smarc 			ttyrub(c, tp);
94444419Smarc 			c = unputc(&tp->t_rawq);
94547545Skarels 			if (c == -1)
94644419Smarc 				goto endcase;
94751003Sbostic 			if (c == ' ' || c == '\t') {
94851003Sbostic 				putc(c, &tp->t_rawq);
94951003Sbostic 				goto endcase;
95051003Sbostic 			}
95149380Skarels 			ctype = ISALPHA(c);
95244419Smarc 			/*
95347545Skarels 			 * erase rest of word
95444419Smarc 			 */
95544419Smarc 			do {
95644419Smarc 				ttyrub(c, tp);
95744419Smarc 				c = unputc(&tp->t_rawq);
95844419Smarc 				if (c == -1)
95944419Smarc 					goto endcase;
96047545Skarels 			} while (c != ' ' && c != '\t' &&
96149380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
96244419Smarc 			(void) putc(c, &tp->t_rawq);
96334492Skarels 			goto endcase;
96444419Smarc 		}
96535811Smarc 		/*
96644419Smarc 		 * reprint line (^R)
96735811Smarc 		 */
96844419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
96944419Smarc 			ttyretype(tp);
97034492Skarels 			goto endcase;
97134492Skarels 		}
97235811Smarc 		/*
97344419Smarc 		 * ^T - kernel info and generate SIGINFO
97435811Smarc 		 */
97544419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
976*51068Smarc 			if (lflag&ISIG)
977*51068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
97844419Smarc 			if ((lflag&NOKERNINFO) == 0)
97944419Smarc 				ttyinfo(tp);
98044419Smarc 			goto endcase;
98144419Smarc 		}
9829578Ssam 	}
9839578Ssam 	/*
9849578Ssam 	 * Check for input buffer overflow
9859578Ssam 	 */
98647545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
98735811Smarc 		if (iflag&IMAXBEL) {
98835811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
98935811Smarc 				(void) ttyoutput(CTRL('g'), tp);
99035811Smarc 		} else
99135811Smarc 			ttyflush(tp, FREAD | FWRITE);
9929578Ssam 		goto endcase;
99310391Ssam 	}
9949578Ssam 	/*
9959578Ssam 	 * Put data char in q for user and
9969578Ssam 	 * wakeup on seeing a line delimiter.
9979578Ssam 	 */
9989578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
99947545Skarels 		if ((lflag&ICANON) == 0) {
100047545Skarels 			ttwakeup(tp);
100147545Skarels 			ttyecho(c, tp);
100247545Skarels 			goto endcase;
100347545Skarels 		}
100435811Smarc 		if (ttbreakc(c)) {
10059578Ssam 			tp->t_rocount = 0;
10069578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
10077502Sroot 			ttwakeup(tp);
10089578Ssam 		} else if (tp->t_rocount++ == 0)
10099578Ssam 			tp->t_rocol = tp->t_col;
10109578Ssam 		if (tp->t_state&TS_ERASE) {
101135811Smarc 			/*
101235811Smarc 			 * end of prterase \.../
101335811Smarc 			 */
10149578Ssam 			tp->t_state &= ~TS_ERASE;
10159578Ssam 			(void) ttyoutput('/', tp);
10169578Ssam 		}
10179578Ssam 		i = tp->t_col;
10187502Sroot 		ttyecho(c, tp);
101935811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
102035811Smarc 			/*
102135811Smarc 			 * Place the cursor over the '^' of the ^D.
102235811Smarc 			 */
10239578Ssam 			i = MIN(2, tp->t_col - i);
10249578Ssam 			while (i > 0) {
10259578Ssam 				(void) ttyoutput('\b', tp);
10269578Ssam 				i--;
10279578Ssam 			}
10289578Ssam 		}
10297502Sroot 	}
10309578Ssam endcase:
10319578Ssam 	/*
103235811Smarc 	 * IXANY means allow any character to restart output.
10339578Ssam 	 */
103440712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
103540712Skarels 	    cc[VSTART] != cc[VSTOP])
10367502Sroot 		return;
10379578Ssam restartoutput:
10387502Sroot 	tp->t_state &= ~TS_TTSTOP;
103935811Smarc 	tp->t_lflag &= ~FLUSHO;
10409578Ssam startoutput:
10417502Sroot 	ttstart(tp);
10427502Sroot }
10437502Sroot 
10447502Sroot /*
104549380Skarels  * Output a single character on a tty, doing output processing
104649380Skarels  * as needed (expanding tabs, newline processing, etc.).
104749380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10487502Sroot  * Must be recursive.
10497502Sroot  */
10507502Sroot ttyoutput(c, tp)
10517502Sroot 	register c;
10527502Sroot 	register struct tty *tp;
10537502Sroot {
105449380Skarels 	register int col;
105535811Smarc 	register long oflag = tp->t_oflag;
105635811Smarc 
105740712Skarels 	if ((oflag&OPOST) == 0) {
105835811Smarc 		if (tp->t_lflag&FLUSHO)
10597502Sroot 			return (-1);
10607502Sroot 		if (putc(c, &tp->t_outq))
10617625Ssam 			return (c);
10627502Sroot 		tk_nout++;
106335811Smarc 		tp->t_outcc++;
10647502Sroot 		return (-1);
10657502Sroot 	}
106635811Smarc 	c &= TTY_CHARMASK;
10677502Sroot 	/*
106849380Skarels 	 * Do tab expansion if OXTABS is set.
106942882Smarc 	 * Special case if we have external processing, we don't
107042882Smarc 	 * do the tab expansion because we'll probably get it
107142882Smarc 	 * wrong.  If tab expansion needs to be done, let it
107242882Smarc 	 * happen externally.
10737502Sroot 	 */
107447545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
10757502Sroot 		register int s;
10767502Sroot 
10777502Sroot 		c = 8 - (tp->t_col&7);
107835811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
107917545Skarels 			s = spltty();		/* don't interrupt tabs */
10807502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
10817502Sroot 			tk_nout += c;
108235811Smarc 			tp->t_outcc += c;
10837502Sroot 			splx(s);
10847502Sroot 		}
10857502Sroot 		tp->t_col += c;
10867502Sroot 		return (c ? -1 : '\t');
10877502Sroot 	}
108835811Smarc 	if (c == CEOT && oflag&ONOEOT)
108947545Skarels 		return (-1);
10907502Sroot 	tk_nout++;
109135811Smarc 	tp->t_outcc++;
10927502Sroot 	/*
109349380Skarels 	 * Newline translation: if ONLCR is set,
109449380Skarels 	 * translate newline into "\r\n".
10957502Sroot 	 */
109635811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
10977502Sroot 		return (c);
109835811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
109935811Smarc 		return (c);
110047545Skarels 
110149380Skarels 	col = tp->t_col;
110249380Skarels 	switch (CCLASS(c)) {
11037502Sroot 
11047502Sroot 	case ORDINARY:
110549380Skarels 		col++;
11067502Sroot 
11077502Sroot 	case CONTROL:
11087502Sroot 		break;
11097502Sroot 
11107502Sroot 	case BACKSPACE:
111149380Skarels 		if (col > 0)
111249380Skarels 			col--;
11137502Sroot 		break;
11147502Sroot 
11157502Sroot 	case NEWLINE:
111649380Skarels 		col = 0;
11177502Sroot 		break;
11187502Sroot 
11197502Sroot 	case TAB:
112049380Skarels 		col = (col + 8) &~ 0x7;
11217502Sroot 		break;
11227502Sroot 
11237502Sroot 	case RETURN:
112449380Skarels 		col = 0;
11257502Sroot 	}
112649380Skarels 	tp->t_col = col;
11277502Sroot 	return (-1);
11287502Sroot }
11297502Sroot 
11307502Sroot /*
113149380Skarels  * Process a read call on a tty device.
11327502Sroot  */
113337584Smarc ttread(tp, uio, flag)
11347625Ssam 	register struct tty *tp;
11357722Swnj 	struct uio *uio;
11367502Sroot {
11377502Sroot 	register struct clist *qp;
113835811Smarc 	register int c;
113941383Smarc 	register long lflag;
114035811Smarc 	register u_char *cc = tp->t_cc;
114147545Skarels 	register struct proc *p = curproc;
11429859Ssam 	int s, first, error = 0;
11437502Sroot 
11447502Sroot loop:
114541383Smarc 	lflag = tp->t_lflag;
114637584Smarc 	s = spltty();
11479578Ssam 	/*
114837584Smarc 	 * take pending input first
11499578Ssam 	 */
115035811Smarc 	if (lflag&PENDIN)
11517502Sroot 		ttypend(tp);
11529859Ssam 	splx(s);
115340712Skarels 
11549578Ssam 	/*
11559578Ssam 	 * Hang process if it's in the background.
11569578Ssam 	 */
115747545Skarels 	if (isbackground(p, tp)) {
115847545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
115947545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
116047545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11618520Sroot 			return (EIO);
116247545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
116343377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
116443377Smarc 		    ttybg, 0))
116540712Skarels 			return (error);
116623165Sbloom 		goto loop;
11677502Sroot 	}
116840712Skarels 
11699578Ssam 	/*
117035811Smarc 	 * If canonical, use the canonical queue,
117135811Smarc 	 * else use the raw queue.
117237584Smarc 	 *
117347545Skarels 	 * (should get rid of clists...)
11749578Ssam 	 */
117535811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
117640712Skarels 
11779578Ssam 	/*
117840712Skarels 	 * If there is no input, sleep on rawq
117940712Skarels 	 * awaiting hardware receipt and notification.
118040712Skarels 	 * If we have data, we don't need to check for carrier.
11819578Ssam 	 */
118217545Skarels 	s = spltty();
11839578Ssam 	if (qp->c_cc <= 0) {
118440712Skarels 		int carrier;
118540712Skarels 
118640712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
118740712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
11889859Ssam 			splx(s);
118940712Skarels 			return (0);	/* EOF */
11907502Sroot 		}
119137728Smckusick 		if (flag & IO_NDELAY) {
119237584Smarc 			splx(s);
119337584Smarc 			return (EWOULDBLOCK);
119437584Smarc 		}
119543377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
119640712Skarels 		    carrier ? ttyin : ttopen, 0);
11979859Ssam 		splx(s);
119843377Smarc 		if (error)
119940712Skarels 			return (error);
12009578Ssam 		goto loop;
12019578Ssam 	}
12029859Ssam 	splx(s);
120340712Skarels 
12049578Ssam 	/*
120535811Smarc 	 * Input present, check for input mapping and processing.
12069578Ssam 	 */
12079578Ssam 	first = 1;
12089578Ssam 	while ((c = getc(qp)) >= 0) {
12099578Ssam 		/*
121035811Smarc 		 * delayed suspend (^Y)
12119578Ssam 		 */
121235811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
121342882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12149578Ssam 			if (first) {
121543377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
121643377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
121740712Skarels 					break;
12189578Ssam 				goto loop;
12199578Ssam 			}
12209578Ssam 			break;
12217502Sroot 		}
12229578Ssam 		/*
122335811Smarc 		 * Interpret EOF only in canonical mode.
12249578Ssam 		 */
122535811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12269578Ssam 			break;
12279578Ssam 		/*
12289578Ssam 		 * Give user character.
12299578Ssam 		 */
123040712Skarels  		error = ureadc(c, uio);
12319578Ssam 		if (error)
12329578Ssam 			break;
123314938Smckusick  		if (uio->uio_resid == 0)
12349578Ssam 			break;
12359578Ssam 		/*
123635811Smarc 		 * In canonical mode check for a "break character"
12379578Ssam 		 * marking the end of a "line of input".
12389578Ssam 		 */
123940712Skarels 		if (lflag&ICANON && ttbreakc(c))
12409578Ssam 			break;
12419578Ssam 		first = 0;
12427502Sroot 	}
12439578Ssam 	/*
12449578Ssam 	 * Look to unblock output now that (presumably)
12459578Ssam 	 * the input queue has gone down.
12469578Ssam 	 */
124735811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
124847545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
124947545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12507502Sroot 			tp->t_state &= ~TS_TBLOCK;
12517502Sroot 			ttstart(tp);
12527502Sroot 		}
125335811Smarc 	}
12548520Sroot 	return (error);
12557502Sroot }
12567502Sroot 
12577502Sroot /*
125825391Skarels  * Check the output queue on tp for space for a kernel message
125925391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
126025391Skarels  * hiwater mark so we don't lose messages due to normal flow
126125391Skarels  * control, but don't let the tty run amok.
126230695Skarels  * Sleeps here are not interruptible, but we return prematurely
126330695Skarels  * if new signals come in.
126425391Skarels  */
126525391Skarels ttycheckoutq(tp, wait)
126625391Skarels 	register struct tty *tp;
126725391Skarels 	int wait;
126825391Skarels {
126930695Skarels 	int hiwat, s, oldsig;
127048439Skarels 	extern int wakeup();
127125391Skarels 
127235811Smarc 	hiwat = tp->t_hiwat;
127325391Skarels 	s = spltty();
127450755Skarels 	if (wait)
127550755Skarels 		oldsig = curproc->p_sig;
127625391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
127729946Skarels 		while (tp->t_outq.c_cc > hiwat) {
127829946Skarels 			ttstart(tp);
127947545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
128029946Skarels 				splx(s);
128129946Skarels 				return (0);
128229946Skarels 			}
128330695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
128429946Skarels 			tp->t_state |= TS_ASLEEP;
128530695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
128625391Skarels 		}
128725391Skarels 	splx(s);
128825391Skarels 	return (1);
128925391Skarels }
129025391Skarels 
129125391Skarels /*
129249380Skarels  * Process a write call on a tty device.
12937502Sroot  */
129437584Smarc ttwrite(tp, uio, flag)
12957625Ssam 	register struct tty *tp;
12969578Ssam 	register struct uio *uio;
12977502Sroot {
12987502Sroot 	register char *cp;
129940712Skarels 	register int cc = 0, ce;
130047545Skarels 	register struct proc *p = curproc;
13019578Ssam 	int i, hiwat, cnt, error, s;
13027502Sroot 	char obuf[OBUFSIZ];
13037502Sroot 
130435811Smarc 	hiwat = tp->t_hiwat;
13059578Ssam 	cnt = uio->uio_resid;
13069578Ssam 	error = 0;
13077502Sroot loop:
130837584Smarc 	s = spltty();
130940712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
131037584Smarc 		if (tp->t_state&TS_ISOPEN) {
131137584Smarc 			splx(s);
131237584Smarc 			return (EIO);
131337728Smckusick 		} else if (flag & IO_NDELAY) {
131437584Smarc 			splx(s);
131540712Skarels 			error = EWOULDBLOCK;
131640712Skarels 			goto out;
131737584Smarc 		} else {
131837584Smarc 			/*
131937584Smarc 			 * sleep awaiting carrier
132037584Smarc 			 */
132143377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
132243377Smarc 					TTIPRI | PCATCH,ttopen, 0);
132337584Smarc 			splx(s);
132443377Smarc 			if (error)
132540712Skarels 				goto out;
132637584Smarc 			goto loop;
132737584Smarc 		}
132837584Smarc 	}
132937584Smarc 	splx(s);
13309578Ssam 	/*
13319578Ssam 	 * Hang the process if it's in the background.
13329578Ssam 	 */
133347545Skarels 	if (isbackground(p, tp) &&
133447545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
133547545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
133647545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
133747545Skarels 	     p->p_pgrp->pg_jobc) {
133847545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
133943377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
134043377Smarc 		    ttybg, 0))
134140712Skarels 			goto out;
134221776Sbloom 		goto loop;
13437502Sroot 	}
13449578Ssam 	/*
13459578Ssam 	 * Process the user's data in at most OBUFSIZ
134640712Skarels 	 * chunks.  Perform any output translation.
134740712Skarels 	 * Keep track of high water mark, sleep on overflow
134840712Skarels 	 * awaiting device aid in acquiring new space.
13499578Ssam 	 */
135040712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
135140712Skarels 		if (tp->t_lflag&FLUSHO) {
135240712Skarels 			uio->uio_resid = 0;
135340712Skarels 			return (0);
135440712Skarels 		}
135540712Skarels 		if (tp->t_outq.c_cc > hiwat)
135632067Skarels 			goto ovhiwat;
13579578Ssam 		/*
135840712Skarels 		 * Grab a hunk of data from the user,
135940712Skarels 		 * unless we have some leftover from last time.
13609578Ssam 		 */
13617822Sroot 		if (cc == 0) {
136240712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
136340712Skarels 			cp = obuf;
136440712Skarels 			error = uiomove(cp, cc, uio);
136540712Skarels 			if (error) {
136640712Skarels 				cc = 0;
136740712Skarels 				break;
136840712Skarels 			}
13697822Sroot 		}
13709578Ssam 		/*
13719578Ssam 		 * If nothing fancy need be done, grab those characters we
13729578Ssam 		 * can handle without any of ttyoutput's processing and
13739578Ssam 		 * just transfer them to the output q.  For those chars
13749578Ssam 		 * which require special processing (as indicated by the
13759578Ssam 		 * bits in partab), call ttyoutput.  After processing
13769578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
13779578Ssam 		 * immediately.
13789578Ssam 		 */
13799578Ssam 		while (cc > 0) {
138040712Skarels 			if ((tp->t_oflag&OPOST) == 0)
13817502Sroot 				ce = cc;
13827502Sroot 			else {
138334492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
138449380Skarels 				   (u_char *)partab, CCLASSMASK);
13859578Ssam 				/*
13869578Ssam 				 * If ce is zero, then we're processing
13879578Ssam 				 * a special character through ttyoutput.
13889578Ssam 				 */
13899578Ssam 				if (ce == 0) {
13907502Sroot 					tp->t_rocount = 0;
13917502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
139221776Sbloom 					    /* no c-lists, wait a bit */
139321776Sbloom 					    ttstart(tp);
139443377Smarc 					    if (error = ttysleep(tp,
139543377Smarc 						(caddr_t)&lbolt,
139643377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
139740712Skarels 						    break;
139821776Sbloom 					    goto loop;
13997502Sroot 					}
14009578Ssam 					cp++, cc--;
140135811Smarc 					if ((tp->t_lflag&FLUSHO) ||
14029578Ssam 					    tp->t_outq.c_cc > hiwat)
14037502Sroot 						goto ovhiwat;
14049578Ssam 					continue;
14057502Sroot 				}
14067502Sroot 			}
14079578Ssam 			/*
14089578Ssam 			 * A bunch of normal characters have been found,
14099578Ssam 			 * transfer them en masse to the output queue and
14109578Ssam 			 * continue processing at the top of the loop.
14119578Ssam 			 * If there are any further characters in this
14129578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14139578Ssam 			 * requiring special handling by ttyoutput.
14149578Ssam 			 */
14157502Sroot 			tp->t_rocount = 0;
14169578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14179578Ssam 			ce -= i;
14189578Ssam 			tp->t_col += ce;
14199578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
142035811Smarc 			tp->t_outcc += ce;
14219578Ssam 			if (i > 0) {
14229578Ssam 				/* out of c-lists, wait a bit */
14237502Sroot 				ttstart(tp);
142443377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
142543377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
142640712Skarels 					break;
142721776Sbloom 				goto loop;
14287502Sroot 			}
142935811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
143040712Skarels 				break;
14317502Sroot 		}
143235811Smarc 		ttstart(tp);
14337502Sroot 	}
143440712Skarels out:
143540712Skarels 	/*
143640712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
143740712Skarels 	 * as the offset and iov pointers have moved forward,
143840712Skarels 	 * but it doesn't matter (the call will either return short
143940712Skarels 	 * or restart with a new uio).
144040712Skarels 	 */
144140712Skarels 	uio->uio_resid += cc;
14428520Sroot 	return (error);
144340712Skarels 
14447502Sroot ovhiwat:
144532067Skarels 	ttstart(tp);
144632067Skarels 	s = spltty();
14479578Ssam 	/*
144835811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
144932067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14509578Ssam 	 */
14517502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14529578Ssam 		splx(s);
14537502Sroot 		goto loop;
14547502Sroot 	}
145537728Smckusick 	if (flag & IO_NDELAY) {
145617545Skarels 		splx(s);
145740712Skarels 		uio->uio_resid += cc;
14587822Sroot 		if (uio->uio_resid == cnt)
14598520Sroot 			return (EWOULDBLOCK);
14608520Sroot 		return (0);
14617502Sroot 	}
14627502Sroot 	tp->t_state |= TS_ASLEEP;
146343377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14649578Ssam 	splx(s);
146543377Smarc 	if (error)
146640712Skarels 		goto out;
14677502Sroot 	goto loop;
14687502Sroot }
14697502Sroot 
14707502Sroot /*
14717502Sroot  * Rubout one character from the rawq of tp
14727502Sroot  * as cleanly as possible.
14737502Sroot  */
14747502Sroot ttyrub(c, tp)
14757625Ssam 	register c;
14767625Ssam 	register struct tty *tp;
14777502Sroot {
14787502Sroot 	register char *cp;
14797502Sroot 	register int savecol;
14807502Sroot 	int s;
14817502Sroot 	char *nextc();
14827502Sroot 
148342882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
14847502Sroot 		return;
148535811Smarc 	tp->t_lflag &= ~FLUSHO;
148635811Smarc 	if (tp->t_lflag&ECHOE) {
14877502Sroot 		if (tp->t_rocount == 0) {
14887502Sroot 			/*
14897502Sroot 			 * Screwed by ttwrite; retype
14907502Sroot 			 */
14917502Sroot 			ttyretype(tp);
14927502Sroot 			return;
14937502Sroot 		}
149435811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
14957502Sroot 			ttyrubo(tp, 2);
149649380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
14977502Sroot 
14987502Sroot 		case ORDINARY:
149935811Smarc 			ttyrubo(tp, 1);
15007502Sroot 			break;
15017502Sroot 
15027502Sroot 		case VTAB:
15037502Sroot 		case BACKSPACE:
15047502Sroot 		case CONTROL:
15057502Sroot 		case RETURN:
150647545Skarels 		case NEWLINE:
150735811Smarc 			if (tp->t_lflag&ECHOCTL)
15087502Sroot 				ttyrubo(tp, 2);
15097502Sroot 			break;
15107502Sroot 
151135811Smarc 		case TAB: {
151235811Smarc 			int c;
151335811Smarc 
15147502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15157502Sroot 				ttyretype(tp);
15167502Sroot 				return;
15177502Sroot 			}
151817545Skarels 			s = spltty();
15197502Sroot 			savecol = tp->t_col;
15209578Ssam 			tp->t_state |= TS_CNTTB;
152135811Smarc 			tp->t_lflag |= FLUSHO;
15227502Sroot 			tp->t_col = tp->t_rocol;
15239578Ssam 			cp = tp->t_rawq.c_cf;
152439407Smarc 			if (cp)
152539407Smarc 				c = *cp;	/* XXX FIX NEXTC */
152635811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
152735811Smarc 				ttyecho(c, tp);
152835811Smarc 			tp->t_lflag &= ~FLUSHO;
15299578Ssam 			tp->t_state &= ~TS_CNTTB;
15307502Sroot 			splx(s);
15317502Sroot 			/*
15327502Sroot 			 * savecol will now be length of the tab
15337502Sroot 			 */
15347502Sroot 			savecol -= tp->t_col;
15357502Sroot 			tp->t_col += savecol;
15367502Sroot 			if (savecol > 8)
15377502Sroot 				savecol = 8;		/* overflow screw */
15387502Sroot 			while (--savecol >= 0)
15397502Sroot 				(void) ttyoutput('\b', tp);
15407502Sroot 			break;
154135811Smarc 		}
15427502Sroot 
15437502Sroot 		default:
154437584Smarc 			/* XXX */
154535811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
154649380Skarels 				c, CCLASS(c));
154735811Smarc 			/*panic("ttyrub");*/
15487502Sroot 		}
154935811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15509578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15517502Sroot 			(void) ttyoutput('\\', tp);
15529578Ssam 			tp->t_state |= TS_ERASE;
15537502Sroot 		}
15547502Sroot 		ttyecho(c, tp);
15557502Sroot 	} else
155635811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15577502Sroot 	tp->t_rocount--;
15587502Sroot }
15597502Sroot 
15607502Sroot /*
15617502Sroot  * Crt back over cnt chars perhaps
15627502Sroot  * erasing them.
15637502Sroot  */
15647502Sroot ttyrubo(tp, cnt)
15657625Ssam 	register struct tty *tp;
15667625Ssam 	int cnt;
15677502Sroot {
15687502Sroot 
15697502Sroot 	while (--cnt >= 0)
157040712Skarels 		ttyoutstr("\b \b", tp);
15717502Sroot }
15727502Sroot 
15737502Sroot /*
15747502Sroot  * Reprint the rawq line.
15757502Sroot  * We assume c_cc has already been checked.
15767502Sroot  */
15777502Sroot ttyretype(tp)
15787625Ssam 	register struct tty *tp;
15797502Sroot {
15807502Sroot 	register char *cp;
15817502Sroot 	char *nextc();
158235811Smarc 	int s, c;
15837502Sroot 
158435811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
158535811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
15867502Sroot 	(void) ttyoutput('\n', tp);
158717545Skarels 	s = spltty();
158835811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
158935811Smarc 	  BIT OF FIRST CHAR ****/
159035811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
159135811Smarc 		ttyecho(c, tp);
159235811Smarc 	}
159335811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
159435811Smarc 		ttyecho(c, tp);
159535811Smarc 	}
15969578Ssam 	tp->t_state &= ~TS_ERASE;
15977502Sroot 	splx(s);
15987502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
15997502Sroot 	tp->t_rocol = 0;
16007502Sroot }
16017502Sroot 
16027502Sroot /*
160335811Smarc  * Echo a typed character to the terminal.
16047502Sroot  */
16057502Sroot ttyecho(c, tp)
16067625Ssam 	register c;
16077625Ssam 	register struct tty *tp;
16087502Sroot {
16099578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
161035811Smarc 		tp->t_lflag &= ~FLUSHO;
161147545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
161247545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16137502Sroot 		return;
161435811Smarc 	if (tp->t_lflag&ECHOCTL) {
161540712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
161640712Skarels 		    c == 0177) {
16177502Sroot 			(void) ttyoutput('^', tp);
161835811Smarc 			c &= TTY_CHARMASK;
16197502Sroot 			if (c == 0177)
16207502Sroot 				c = '?';
16217502Sroot 			else
16227502Sroot 				c += 'A' - 1;
16237502Sroot 		}
16247502Sroot 	}
162535811Smarc 	(void) ttyoutput(c, tp);
16267502Sroot }
16277502Sroot 
16287502Sroot /*
16297502Sroot  * send string cp to tp
16307502Sroot  */
163140712Skarels ttyoutstr(cp, tp)
16327625Ssam 	register char *cp;
16337625Ssam 	register struct tty *tp;
16347502Sroot {
16357502Sroot 	register char c;
16367502Sroot 
16377502Sroot 	while (c = *cp++)
16387502Sroot 		(void) ttyoutput(c, tp);
16397502Sroot }
16407502Sroot 
164149380Skarels /*
164249380Skarels  * Wake up any readers on a tty.
164349380Skarels  */
16447502Sroot ttwakeup(tp)
164547545Skarels 	register struct tty *tp;
16467502Sroot {
16477502Sroot 
16487502Sroot 	if (tp->t_rsel) {
16497502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16507502Sroot 		tp->t_state &= ~TS_RCOLL;
16517502Sroot 		tp->t_rsel = 0;
16527502Sroot 	}
165312752Ssam 	if (tp->t_state & TS_ASYNC)
165442882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16557502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16567502Sroot }
165735811Smarc 
165835811Smarc /*
165948439Skarels  * Look up a code for a specified speed in a conversion table;
166048439Skarels  * used by drivers to map software speed values to hardware parameters.
166148439Skarels  */
166248439Skarels ttspeedtab(speed, table)
166348439Skarels 	register struct speedtab *table;
166448439Skarels {
166548439Skarels 
166648439Skarels 	for ( ; table->sp_speed != -1; table++)
166748439Skarels 		if (table->sp_speed == speed)
166848439Skarels 			return (table->sp_code);
166948439Skarels 	return (-1);
167048439Skarels }
167148439Skarels 
167248439Skarels /*
167335811Smarc  * set tty hi and low water marks
167435811Smarc  *
167535811Smarc  * Try to arrange the dynamics so there's about one second
167635811Smarc  * from hi to low water.
167735811Smarc  *
167835811Smarc  */
167935811Smarc ttsetwater(tp)
168035811Smarc 	struct tty *tp;
168135811Smarc {
168235811Smarc 	register cps = tp->t_ospeed / 10;
168335811Smarc 	register x;
168435811Smarc 
168535811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
168635811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
168735811Smarc 	x += cps;
168835811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
168935811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
169035811Smarc #undef clamp
169135811Smarc }
169235811Smarc 
169339407Smarc /*
169439407Smarc  * Report on state of foreground process group.
169539407Smarc  */
169639407Smarc ttyinfo(tp)
169749907Sbostic 	register struct tty *tp;
169839407Smarc {
169949907Sbostic 	register struct proc *p, *pick;
170041177Smarc 	struct timeval utime, stime;
170149907Sbostic 	int tmp;
170239407Smarc 
170339407Smarc 	if (ttycheckoutq(tp,0) == 0)
170439407Smarc 		return;
170549907Sbostic 
170649907Sbostic 	/* Print load average. */
170749907Sbostic 	tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
170849907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
170949907Sbostic 
171039555Smarc 	if (tp->t_session == NULL)
171149907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
171241177Smarc 	else if (tp->t_pgrp == NULL)
171349907Sbostic 		ttyprintf(tp, "no foreground process group\n");
171441177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
171549907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
171639407Smarc 	else {
171749907Sbostic 		/* Pick interesting process. */
171849907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
171941177Smarc 			if (proc_compare(pick, p))
172041177Smarc 				pick = p;
172149907Sbostic 
172249907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
172349907Sbostic 		    pick->p_stat == SRUN ? "running" :
172449907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
172549907Sbostic 
172649907Sbostic 		/*
172749907Sbostic 		 * Lock out clock if process is running; get user/system
172849907Sbostic 		 * cpu time.
172941177Smarc 		 */
173047545Skarels 		if (curproc == pick)
173149907Sbostic 			tmp = splclock();
173241177Smarc 		utime = pick->p_utime;
173341177Smarc 		stime = pick->p_stime;
173447545Skarels 		if (curproc == pick)
173549907Sbostic 			splx(tmp);
173639407Smarc 
173749907Sbostic 		/* Print user time. */
173849907Sbostic 		ttyprintf(tp, "%d.%02du ",
173949907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
174041177Smarc 
174149907Sbostic 		/* Print system time. */
174249907Sbostic 		ttyprintf(tp, "%d.%02ds ",
174349907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
174449907Sbostic 
174549907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
174649907Sbostic 		/* Print percentage cpu, resident set size. */
174749907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
174849907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
174949907Sbostic 		   tmp / 100, pgtok(pick->p_vmspace->vm_rssize));
175041177Smarc 	}
175149907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
175241177Smarc }
175341177Smarc 
175441177Smarc /*
175541177Smarc  * Returns 1 if p2 is "better" than p1
175641177Smarc  *
175741177Smarc  * The algorithm for picking the "interesting" process is thus:
175841177Smarc  *
175941177Smarc  *	1) (Only foreground processes are eligable - implied)
176041177Smarc  *	2) Runnable processes are favored over anything
176141177Smarc  *	   else.  The runner with the highest cpu
176241177Smarc  *	   utilization is picked (p_cpu).  Ties are
176341177Smarc  *	   broken by picking the highest pid.
176441177Smarc  *	3  Next, the sleeper with the shortest sleep
176541177Smarc  *	   time is favored.  With ties, we pick out
176641177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
176741177Smarc  *	   Further ties are broken by picking the highest
176841177Smarc  *	   pid.
176941177Smarc  *
177041177Smarc  */
177141177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
177245723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
177345723Smckusick #define ONLYA   2
177445723Smckusick #define ONLYB   1
177545723Smckusick #define BOTH    3
177645723Smckusick 
177749907Sbostic static int
177841177Smarc proc_compare(p1, p2)
177941177Smarc 	register struct proc *p1, *p2;
178041177Smarc {
178141177Smarc 
178241177Smarc 	if (p1 == NULL)
178341177Smarc 		return (1);
178441177Smarc 	/*
178541177Smarc 	 * see if at least one of them is runnable
178641177Smarc 	 */
178745723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
178845723Smckusick 	case ONLYA:
178945723Smckusick 		return (0);
179045723Smckusick 	case ONLYB:
179141177Smarc 		return (1);
179245723Smckusick 	case BOTH:
179341177Smarc 		/*
179441177Smarc 		 * tie - favor one with highest recent cpu utilization
179541177Smarc 		 */
179641177Smarc 		if (p2->p_cpu > p1->p_cpu)
179741177Smarc 			return (1);
179841177Smarc 		if (p1->p_cpu > p2->p_cpu)
179941177Smarc 			return (0);
180041177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
180141177Smarc 	}
180245723Smckusick 	/*
180345723Smckusick  	 * weed out zombies
180445723Smckusick 	 */
180545723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
180645723Smckusick 	case ONLYA:
180745723Smckusick 		return (1);
180845723Smckusick 	case ONLYB:
180945723Smckusick 		return (0);
181045723Smckusick 	case BOTH:
181145723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
181245723Smckusick 	}
181341177Smarc 	/*
181441177Smarc 	 * pick the one with the smallest sleep time
181541177Smarc 	 */
181641177Smarc 	if (p2->p_slptime > p1->p_slptime)
181741177Smarc 		return (0);
181841177Smarc 	if (p1->p_slptime > p2->p_slptime)
181941177Smarc 		return (1);
182041177Smarc 	/*
182141177Smarc 	 * favor one sleeping in a non-interruptible sleep
182241177Smarc 	 */
182341177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
182441177Smarc 		return (1);
182541177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
182641177Smarc 		return (0);
182747545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
182841177Smarc }
182945723Smckusick 
183039555Smarc /*
183139555Smarc  * Output char to tty; console putchar style.
183239555Smarc  */
183339555Smarc tputchar(c, tp)
183439555Smarc 	int c;
183539555Smarc 	struct tty *tp;
183639555Smarc {
183739555Smarc 	register s = spltty();
183839555Smarc 
183947545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
184039555Smarc 		if (c == '\n')
184139555Smarc 			(void) ttyoutput('\r', tp);
184239555Smarc 		(void) ttyoutput(c, tp);
184339555Smarc 		ttstart(tp);
184439555Smarc 		splx(s);
184539555Smarc 		return (0);
184639555Smarc 	}
184739555Smarc 	splx(s);
184839555Smarc 	return (-1);
184939555Smarc }
185043377Smarc 
185144419Smarc /*
185249380Skarels  * Sleep on chan, returning ERESTART if tty changed
185349380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
185449380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
185549380Skarels  * call will redo validation done at the start of the call.
185644419Smarc  */
185743377Smarc ttysleep(tp, chan, pri, wmesg, timo)
185843377Smarc 	struct tty *tp;
185943377Smarc 	caddr_t chan;
186043377Smarc 	int pri;
186143377Smarc 	char *wmesg;
186243377Smarc 	int timo;
186343377Smarc {
186443377Smarc 	int error;
186543377Smarc 	short gen = tp->t_gen;
186643377Smarc 
186743377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
186843377Smarc 		return (error);
186943377Smarc 	if (tp->t_gen != gen)
187043377Smarc 		return (ERESTART);
187143377Smarc 	return (0);
187243377Smarc }
1873