xref: /csrg-svn/sys/kern/tty.c (revision 52485)
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*52485Storek  *	@(#)tty.c	7.48 (Berkeley) 02/14/92
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 
162*52485Storek #define	flushq(q) { \
163*52485Storek 	if ((q)->c_cc) \
164*52485Storek 		ndflush(q, (q)->c_cc); \
16549380Skarels }
16649380Skarels 
16739Sbill /*
16849380Skarels  * Flush TTY read and/or write queues,
16949380Skarels  * notifying anyone waiting.
17039Sbill  */
17112752Ssam ttyflush(tp, rw)
1727625Ssam 	register struct tty *tp;
173*52485Storek 	int rw;
17439Sbill {
175*52485Storek 	register int s;
176903Sbill 
17717545Skarels 	s = spltty();
178903Sbill 	if (rw & FREAD) {
17949380Skarels 		flushq(&tp->t_canq);
18049380Skarels 		flushq(&tp->t_rawq);
18149380Skarels 		tp->t_rocount = 0;
18249380Skarels 		tp->t_rocol = 0;
18349380Skarels 		tp->t_state &= ~TS_LOCAL;
18437584Smarc 		ttwakeup(tp);
185903Sbill 	}
186903Sbill 	if (rw & FWRITE) {
1875408Swnj 		tp->t_state &= ~TS_TTSTOP;
188*52485Storek #ifdef sun4c						/* XXX */
189*52485Storek 		(*tp->t_stop)(tp, rw);
190*52485Storek #else
1915426Swnj 		(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
192*52485Storek #endif
19349380Skarels 		flushq(&tp->t_outq);
19449380Skarels 		wakeup((caddr_t)&tp->t_outq);
19549380Skarels 		if (tp->t_wsel) {
19649380Skarels 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
19749380Skarels 			tp->t_wsel = 0;
19849380Skarels 			tp->t_state &= ~TS_WCOLL;
19949380Skarels 		}
200903Sbill 	}
201903Sbill 	splx(s);
20239Sbill }
20339Sbill 
204903Sbill /*
205903Sbill  * Send stop character on input overflow.
206903Sbill  */
207903Sbill ttyblock(tp)
2087625Ssam 	register struct tty *tp;
20939Sbill {
210903Sbill 	register x;
2119578Ssam 
212903Sbill 	x = tp->t_rawq.c_cc + tp->t_canq.c_cc;
213903Sbill 	if (tp->t_rawq.c_cc > TTYHOG) {
21412752Ssam 		ttyflush(tp, FREAD|FWRITE);
2155408Swnj 		tp->t_state &= ~TS_TBLOCK;
216903Sbill 	}
21715118Skarels 	/*
21815118Skarels 	 * Block further input iff:
21915118Skarels 	 * Current input > threshold AND input is available to user program
22015118Skarels 	 */
22142350Smckusick 	if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 &&
22240712Skarels 	    ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) &&
22335811Smarc 	    tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
22442350Smckusick 		if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
22515118Skarels 			tp->t_state |= TS_TBLOCK;
22615118Skarels 			ttstart(tp);
22715118Skarels 		}
228903Sbill 	}
22939Sbill }
23039Sbill 
23147545Skarels ttstart(tp)
23237584Smarc 	struct tty *tp;
233121Sbill {
234121Sbill 
23547545Skarels 	if (tp->t_oproc)		/* kludge for pty */
23647545Skarels 		(*tp->t_oproc)(tp);
23747545Skarels }
23847545Skarels 
23947545Skarels ttrstrt(tp)				/* XXX */
24047545Skarels 	struct tty *tp;
24147545Skarels {
242*52485Storek 	int s;
24347545Skarels 
24440712Skarels #ifdef DIAGNOSTIC
2459578Ssam 	if (tp == 0)
2469578Ssam 		panic("ttrstrt");
24740712Skarels #endif
248*52485Storek 	s = spltty();
2495408Swnj 	tp->t_state &= ~TS_TIMEOUT;
250903Sbill 	ttstart(tp);
251*52485Storek 	splx(s);
252121Sbill }
253121Sbill 
25439Sbill 
25539Sbill /*
25649380Skarels  * Common code for ioctls on tty devices.
25749380Skarels  * Called after line-discipline-specific ioctl
25849380Skarels  * has been called to do discipline-specific functions
25949380Skarels  * and/or reject any of these ioctl commands.
26039Sbill  */
2611780Sbill /*ARGSUSED*/
2627625Ssam ttioctl(tp, com, data, flag)
2637625Ssam 	register struct tty *tp;
264*52485Storek 	int com;
2657625Ssam 	caddr_t data;
266*52485Storek 	int flag;
26739Sbill {
26847545Skarels 	register struct proc *p = curproc;		/* XXX */
26939Sbill 	extern int nldisp;
27037554Smckusick 	int s, error;
27139Sbill 
272903Sbill 	/*
273903Sbill 	 * If the ioctl involves modification,
27417545Skarels 	 * hang if in the background.
275903Sbill 	 */
2767625Ssam 	switch (com) {
27739Sbill 
27835811Smarc 	case TIOCSETD:
279903Sbill 	case TIOCFLUSH:
28035811Smarc 	/*case TIOCSPGRP:*/
2819325Ssam 	case TIOCSTI:
28217598Sbloom 	case TIOCSWINSZ:
28335811Smarc 	case TIOCSETA:
28435811Smarc 	case TIOCSETAW:
28535811Smarc 	case TIOCSETAF:
286*52485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
28740030Smarc 	case TIOCSETP:
28840030Smarc 	case TIOCSETN:
28940030Smarc 	case TIOCSETC:
29040030Smarc 	case TIOCSLTC:
29140030Smarc 	case TIOCLBIS:
29240030Smarc 	case TIOCLBIC:
29340030Smarc 	case TIOCLSET:
29440030Smarc 	case OTIOCSETD:
29540030Smarc #endif
29647545Skarels 		while (isbackground(curproc, tp) &&
29747545Skarels 		   p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 &&
29847545Skarels 		   (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
29947545Skarels 		   (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
30047545Skarels 			pgsignal(p->p_pgrp, SIGTTOU, 1);
30143377Smarc 			if (error = ttysleep(tp, (caddr_t)&lbolt,
30243377Smarc 			    TTOPRI | PCATCH, ttybg, 0))
30340712Skarels 				return (error);
304903Sbill 		}
305903Sbill 		break;
306903Sbill 	}
307903Sbill 
3089578Ssam 	/*
3099578Ssam 	 * Process the ioctl.
3109578Ssam 	 */
3117625Ssam 	switch (com) {
312903Sbill 
3138556Sroot 	/* get discipline number */
31439Sbill 	case TIOCGETD:
3157625Ssam 		*(int *)data = tp->t_line;
31639Sbill 		break;
31739Sbill 
3188556Sroot 	/* set line discipline */
3197625Ssam 	case TIOCSETD: {
3207625Ssam 		register int t = *(int *)data;
32135811Smarc 		dev_t dev = tp->t_dev;
3227625Ssam 
32335811Smarc 		if ((unsigned)t >= nldisp)
32410851Ssam 			return (ENXIO);
32525584Skarels 		if (t != tp->t_line) {
32625584Skarels 			s = spltty();
32749752Smarc 			(*linesw[tp->t_line].l_close)(tp, flag);
32825584Skarels 			error = (*linesw[t].l_open)(dev, tp);
32925584Skarels 			if (error) {
33035811Smarc 				(void)(*linesw[tp->t_line].l_open)(dev, tp);
33125584Skarels 				splx(s);
33225584Skarels 				return (error);
33325584Skarels 			}
33425584Skarels 			tp->t_line = t;
33510851Ssam 			splx(s);
33610851Ssam 		}
33739Sbill 		break;
3387625Ssam 	}
33939Sbill 
3408556Sroot 	/* prevent more opens on channel */
3415614Swnj 	case TIOCEXCL:
342*52485Storek 		s = spltty();
3435614Swnj 		tp->t_state |= TS_XCLUDE;
344*52485Storek 		splx(s);
3455614Swnj 		break;
3465614Swnj 
3475614Swnj 	case TIOCNXCL:
348*52485Storek 		s = spltty();
3495614Swnj 		tp->t_state &= ~TS_XCLUDE;
350*52485Storek 		splx(s);
3515614Swnj 		break;
3525614Swnj 
353*52485Storek #ifdef TIOCHPCL
35439Sbill 	case TIOCHPCL:
355*52485Storek 		s = spltty();
35635811Smarc 		tp->t_cflag |= HUPCL;
357*52485Storek 		splx(s);
35839Sbill 		break;
359*52485Storek #endif
36039Sbill 
3613942Sbugs 	case TIOCFLUSH: {
3627625Ssam 		register int flags = *(int *)data;
3637625Ssam 
3647625Ssam 		if (flags == 0)
3653942Sbugs 			flags = FREAD|FWRITE;
3667625Ssam 		else
3677625Ssam 			flags &= FREAD|FWRITE;
36812752Ssam 		ttyflush(tp, flags);
36939Sbill 		break;
3703944Sbugs 	}
37139Sbill 
37237584Smarc 	case FIOASYNC:
373*52485Storek 		s = spltty();
37437584Smarc 		if (*(int *)data)
37537584Smarc 			tp->t_state |= TS_ASYNC;
37637584Smarc 		else
37737584Smarc 			tp->t_state &= ~TS_ASYNC;
378*52485Storek 		splx(s);
37937584Smarc 		break;
38037584Smarc 
38137584Smarc 	case FIONBIO:
38237584Smarc 		break;	/* XXX remove */
38337584Smarc 
3848556Sroot 	/* return number of characters immediately available */
3857625Ssam 	case FIONREAD:
3867625Ssam 		*(off_t *)data = ttnread(tp);
387174Sbill 		break;
388174Sbill 
38913077Ssam 	case TIOCOUTQ:
39013077Ssam 		*(int *)data = tp->t_outq.c_cc;
39113077Ssam 		break;
39213077Ssam 
3938589Sroot 	case TIOCSTOP:
39417545Skarels 		s = spltty();
3959578Ssam 		if ((tp->t_state&TS_TTSTOP) == 0) {
3965573Swnj 			tp->t_state |= TS_TTSTOP;
397*52485Storek #ifdef sun4c						/* XXX */
398*52485Storek 			(*tp->t_stop)(tp, 0);
399*52485Storek #else
4005573Swnj 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
401*52485Storek #endif
4025573Swnj 		}
4037625Ssam 		splx(s);
4045573Swnj 		break;
4055573Swnj 
4068589Sroot 	case TIOCSTART:
40717545Skarels 		s = spltty();
40835811Smarc 		if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) {
4095573Swnj 			tp->t_state &= ~TS_TTSTOP;
41035811Smarc 			tp->t_lflag &= ~FLUSHO;
4115573Swnj 			ttstart(tp);
4125573Swnj 		}
4137625Ssam 		splx(s);
4145573Swnj 		break;
4155573Swnj 
4169325Ssam 	/*
4179325Ssam 	 * Simulate typing of a character at the terminal.
4189325Ssam 	 */
4199325Ssam 	case TIOCSTI:
42047545Skarels 		if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
42117183Smckusick 			return (EPERM);
42247545Skarels 		if (p->p_ucred->cr_uid && !isctty(p, tp))
4239325Ssam 			return (EACCES);
4249578Ssam 		(*linesw[tp->t_line].l_rint)(*(char *)data, tp);
4259325Ssam 		break;
4269325Ssam 
42735811Smarc 	case TIOCGETA: {
42835811Smarc 		struct termios *t = (struct termios *)data;
42912752Ssam 
43035811Smarc 		bcopy(&tp->t_termios, t, sizeof(struct termios));
43135811Smarc 		break;
43235811Smarc 	}
43335811Smarc 
43435811Smarc 	case TIOCSETA:
43535811Smarc 	case TIOCSETAW:
43637584Smarc 	case TIOCSETAF: {
43735811Smarc 		register struct termios *t = (struct termios *)data;
43840712Skarels 
43917545Skarels 		s = spltty();
44039407Smarc 		if (com == TIOCSETAW || com == TIOCSETAF) {
44140712Skarels 			if (error = ttywait(tp)) {
44240712Skarels 				splx(s);
44340712Skarels 				return (error);
44440712Skarels 			}
44545007Smarc 			if (com == TIOCSETAF)
44639407Smarc 				ttyflush(tp, FREAD);
44739407Smarc 		}
44840712Skarels 		if ((t->c_cflag&CIGNORE) == 0) {
44935811Smarc 			/*
45035811Smarc 			 * set device hardware
45135811Smarc 			 */
45237584Smarc 			if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
45337584Smarc 				splx(s);
45435811Smarc 				return (error);
45537584Smarc 			} else {
45640712Skarels 				if ((tp->t_state&TS_CARR_ON) == 0 &&
45737584Smarc 				    (tp->t_cflag&CLOCAL) &&
45840712Skarels 				    (t->c_cflag&CLOCAL) == 0) {
45937584Smarc 					tp->t_state &= ~TS_ISOPEN;
46037584Smarc 					tp->t_state |= TS_WOPEN;
46137584Smarc 					ttwakeup(tp);
46237584Smarc 				}
46335811Smarc 				tp->t_cflag = t->c_cflag;
46435811Smarc 				tp->t_ispeed = t->c_ispeed;
46535811Smarc 				tp->t_ospeed = t->c_ospeed;
46634492Skarels 			}
46735811Smarc 			ttsetwater(tp);
46812752Ssam 		}
46939407Smarc 		if (com != TIOCSETAF) {
47035811Smarc 			if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
47135811Smarc 				if (t->c_lflag&ICANON) {
47235811Smarc 					tp->t_lflag |= PENDIN;
47335811Smarc 					ttwakeup(tp);
47435811Smarc 				}
47535811Smarc 				else {
47635811Smarc 					struct clist tq;
47735811Smarc 
47835811Smarc 					catq(&tp->t_rawq, &tp->t_canq);
47935811Smarc 					tq = tp->t_rawq;
48035811Smarc 					tp->t_rawq = tp->t_canq;
48135811Smarc 					tp->t_canq = tq;
48235811Smarc 				}
48312752Ssam 		}
48435811Smarc 		tp->t_iflag = t->c_iflag;
48535811Smarc 		tp->t_oflag = t->c_oflag;
48642882Smarc 		/*
48742882Smarc 		 * Make the EXTPROC bit read only.
48842882Smarc 		 */
48942882Smarc 		if (tp->t_lflag&EXTPROC)
49042882Smarc 			t->c_lflag |= EXTPROC;
49142882Smarc 		else
49242882Smarc 			t->c_lflag &= ~EXTPROC;
49335811Smarc 		tp->t_lflag = t->c_lflag;
49435811Smarc 		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
49512752Ssam 		splx(s);
49612752Ssam 		break;
49712752Ssam 	}
49812752Ssam 
49912752Ssam 	/*
50039555Smarc 	 * Set controlling terminal.
50139555Smarc 	 * Session ctty vnode pointer set in vnode layer.
50234492Skarels 	 */
50347545Skarels 	case TIOCSCTTY:
50439555Smarc 		if (!SESS_LEADER(p) ||
50539555Smarc 		   (p->p_session->s_ttyvp || tp->t_session) &&
50639555Smarc 		   (tp->t_session != p->p_session))
50739407Smarc 			return (EPERM);
50835811Smarc 		tp->t_session = p->p_session;
50939555Smarc 		tp->t_pgrp = p->p_pgrp;
51039555Smarc 		p->p_session->s_ttyp = tp;
51139555Smarc 		p->p_flag |= SCTTY;
51234492Skarels 		break;
51339555Smarc 
51434492Skarels 	/*
51535811Smarc 	 * Set terminal process group.
51617545Skarels 	 */
51718650Sbloom 	case TIOCSPGRP: {
51835811Smarc 		register struct pgrp *pgrp = pgfind(*(int *)data);
51917545Skarels 
52039555Smarc 		if (!isctty(p, tp))
52139555Smarc 			return (ENOTTY);
52240030Smarc 		else if (pgrp == NULL || pgrp->pg_session != p->p_session)
52339555Smarc 			return (EPERM);
52439555Smarc 		tp->t_pgrp = pgrp;
52512752Ssam 		break;
52618650Sbloom 	}
52712752Ssam 
52812752Ssam 	case TIOCGPGRP:
52947545Skarels 		if (!isctty(p, tp))
53039555Smarc 			return (ENOTTY);
53145007Smarc 		*(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
53212752Ssam 		break;
53312752Ssam 
53417598Sbloom 	case TIOCSWINSZ:
53518650Sbloom 		if (bcmp((caddr_t)&tp->t_winsize, data,
53618650Sbloom 		    sizeof (struct winsize))) {
53717598Sbloom 			tp->t_winsize = *(struct winsize *)data;
53842882Smarc 			pgsignal(tp->t_pgrp, SIGWINCH, 1);
53917598Sbloom 		}
54017598Sbloom 		break;
54117598Sbloom 
54217598Sbloom 	case TIOCGWINSZ:
54317598Sbloom 		*(struct winsize *)data = tp->t_winsize;
54417598Sbloom 		break;
54517598Sbloom 
54630534Skarels 	case TIOCCONS:
54730534Skarels 		if (*(int *)data) {
54842141Smckusick 			if (constty && constty != tp &&
54942141Smckusick 			    (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
55042141Smckusick 			    (TS_CARR_ON|TS_ISOPEN))
55130534Skarels 				return (EBUSY);
55230534Skarels #ifndef	UCONSOLE
55347545Skarels 			if (error = suser(p->p_ucred, &p->p_acflag))
55437554Smckusick 				return (error);
55530534Skarels #endif
55630534Skarels 			constty = tp;
55730534Skarels 		} else if (tp == constty)
55833404Skarels 			constty = NULL;
55930534Skarels 		break;
56030534Skarels 
56148439Skarels 	case TIOCDRAIN:
56248439Skarels 		if (error = ttywait(tp))
56348439Skarels 			return (error);
56448439Skarels 		break;
56548439Skarels 
56647545Skarels 	default:
567*52485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
56847545Skarels 		return (ttcompat(tp, com, data, flag));
56947545Skarels #else
57047545Skarels 		return (-1);
57135811Smarc #endif
57239Sbill 	}
5738556Sroot 	return (0);
57439Sbill }
5754484Swnj 
5764484Swnj ttnread(tp)
5774484Swnj 	struct tty *tp;
5784484Swnj {
5794484Swnj 	int nread = 0;
5804484Swnj 
58135811Smarc 	if (tp->t_lflag & PENDIN)
5824484Swnj 		ttypend(tp);
5834484Swnj 	nread = tp->t_canq.c_cc;
58435811Smarc 	if ((tp->t_lflag & ICANON) == 0)
5854484Swnj 		nread += tp->t_rawq.c_cc;
5864484Swnj 	return (nread);
5874484Swnj }
5884484Swnj 
5895408Swnj ttselect(dev, rw)
5904484Swnj 	dev_t dev;
5915408Swnj 	int rw;
5924484Swnj {
5934484Swnj 	register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
5944484Swnj 	int nread;
59517545Skarels 	int s = spltty();
5964484Swnj 
5975408Swnj 	switch (rw) {
5984484Swnj 
5994484Swnj 	case FREAD:
6004484Swnj 		nread = ttnread(tp);
60137584Smarc 		if (nread > 0 ||
60240712Skarels 		   ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
6035408Swnj 			goto win;
6044938Swnj 		if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
6055408Swnj 			tp->t_state |= TS_RCOLL;
6064484Swnj 		else
60747545Skarels 			tp->t_rsel = curproc;
6085408Swnj 		break;
6094484Swnj 
6105408Swnj 	case FWRITE:
61135811Smarc 		if (tp->t_outq.c_cc <= tp->t_lowat)
6125408Swnj 			goto win;
6135408Swnj 		if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
6145408Swnj 			tp->t_state |= TS_WCOLL;
6155408Swnj 		else
61647545Skarels 			tp->t_wsel = curproc;
6175408Swnj 		break;
6184484Swnj 	}
6195408Swnj 	splx(s);
6205408Swnj 	return (0);
6215408Swnj win:
6225408Swnj 	splx(s);
6235408Swnj 	return (1);
6244484Swnj }
6257436Skre 
6267502Sroot /*
62749380Skarels  * Initial open of tty, or (re)entry to standard tty line discipline.
6287502Sroot  */
6297502Sroot ttyopen(dev, tp)
6307625Ssam 	dev_t dev;
6317625Ssam 	register struct tty *tp;
6327502Sroot {
633*52485Storek 	int s = spltty();
6347502Sroot 
6357502Sroot 	tp->t_dev = dev;
63635811Smarc 
6377502Sroot 	tp->t_state &= ~TS_WOPEN;
63817545Skarels 	if ((tp->t_state & TS_ISOPEN) == 0) {
63917545Skarels 		tp->t_state |= TS_ISOPEN;
64017598Sbloom 		bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
64117545Skarels 	}
642*52485Storek 	splx(s);
6438556Sroot 	return (0);
6447502Sroot }
6457502Sroot 
6467502Sroot /*
64725391Skarels  * "close" a line discipline
64825391Skarels  */
64949752Smarc ttylclose(tp, flag)
65049752Smarc 	struct tty *tp;
65149752Smarc 	int flag;
65225391Skarels {
65325391Skarels 
65449752Smarc 	if (flag&IO_NDELAY)
65549752Smarc 		ttyflush(tp, FREAD|FWRITE);
65649752Smarc 	else
65749752Smarc 		ttywflush(tp);
65825391Skarels }
65925391Skarels 
66025391Skarels /*
66149380Skarels  * Handle close() on a tty line: flush and set to initial state,
66249380Skarels  * bumping generation number so that pending read/write calls
66349380Skarels  * can detect recycling of the tty.
6647502Sroot  */
6657502Sroot ttyclose(tp)
6667625Ssam 	register struct tty *tp;
6677502Sroot {
66830534Skarels 	if (constty == tp)
66930534Skarels 		constty = NULL;
67025391Skarels 	ttyflush(tp, FREAD|FWRITE);
67139555Smarc 	tp->t_session = NULL;
67239555Smarc 	tp->t_pgrp = NULL;
6737502Sroot 	tp->t_state = 0;
67443377Smarc 	tp->t_gen++;
67540712Skarels 	return (0);
6767502Sroot }
6777502Sroot 
6787502Sroot /*
67925391Skarels  * Handle modem control transition on a tty.
68025391Skarels  * Flag indicates new state of carrier.
68125391Skarels  * Returns 0 if the line should be turned off, otherwise 1.
68225391Skarels  */
68325391Skarels ttymodem(tp, flag)
68425391Skarels 	register struct tty *tp;
685*52485Storek 	int flag;
68625391Skarels {
68725391Skarels 
68842193Smarc 	if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
68925391Skarels 		/*
69025391Skarels 		 * MDMBUF: do flow control according to carrier flag
69125391Skarels 		 */
69225391Skarels 		if (flag) {
69325391Skarels 			tp->t_state &= ~TS_TTSTOP;
69425391Skarels 			ttstart(tp);
69525391Skarels 		} else if ((tp->t_state&TS_TTSTOP) == 0) {
69625391Skarels 			tp->t_state |= TS_TTSTOP;
697*52485Storek #ifdef sun4c						/* XXX */
698*52485Storek 			(*tp->t_stop)(tp, 0);
699*52485Storek #else
70025391Skarels 			(*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
701*52485Storek #endif
70225391Skarels 		}
70325391Skarels 	} else if (flag == 0) {
70425391Skarels 		/*
70525391Skarels 		 * Lost carrier.
70625391Skarels 		 */
70725391Skarels 		tp->t_state &= ~TS_CARR_ON;
70842193Smarc 		if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
70942193Smarc 			if (tp->t_session && tp->t_session->s_leader)
71042193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
71142193Smarc 			ttyflush(tp, FREAD|FWRITE);
71242193Smarc 			return (0);
71325391Skarels 		}
71425391Skarels 	} else {
71525391Skarels 		/*
71625391Skarels 		 * Carrier now on.
71725391Skarels 		 */
71825391Skarels 		tp->t_state |= TS_CARR_ON;
71937584Smarc 		ttwakeup(tp);
72025391Skarels 	}
72125391Skarels 	return (1);
72225391Skarels }
72325391Skarels 
72425391Skarels /*
72525404Skarels  * Default modem control routine (for other line disciplines).
72625404Skarels  * Return argument flag, to turn off device on carrier drop.
72725404Skarels  */
72825415Skarels nullmodem(tp, flag)
72925415Skarels 	register struct tty *tp;
73025404Skarels 	int flag;
73125404Skarels {
73225404Skarels 
73325404Skarels 	if (flag)
73425404Skarels 		tp->t_state |= TS_CARR_ON;
73539407Smarc 	else {
73625404Skarels 		tp->t_state &= ~TS_CARR_ON;
73742193Smarc 		if ((tp->t_cflag&CLOCAL) == 0) {
73842193Smarc 			if (tp->t_session && tp->t_session->s_leader)
73942193Smarc 				psignal(tp->t_session->s_leader, SIGHUP);
74042193Smarc 			return (0);
74142193Smarc 		}
74239407Smarc 	}
74342193Smarc 	return (1);
74425404Skarels }
74525404Skarels 
74625404Skarels /*
7477502Sroot  * reinput pending characters after state switch
74817545Skarels  * call at spltty().
7497502Sroot  */
7507502Sroot ttypend(tp)
7517625Ssam 	register struct tty *tp;
7527502Sroot {
7537502Sroot 	struct clist tq;
7547502Sroot 	register c;
7557502Sroot 
75635811Smarc 	tp->t_lflag &= ~PENDIN;
7579578Ssam 	tp->t_state |= TS_TYPEN;
7587502Sroot 	tq = tp->t_rawq;
7597502Sroot 	tp->t_rawq.c_cc = 0;
7607502Sroot 	tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
7617502Sroot 	while ((c = getc(&tq)) >= 0)
7627502Sroot 		ttyinput(c, tp);
7639578Ssam 	tp->t_state &= ~TS_TYPEN;
7647502Sroot }
7657502Sroot 
7667502Sroot /*
76749380Skarels  * Process input of a single character received on a tty.
7687502Sroot  */
7697502Sroot ttyinput(c, tp)
7707625Ssam 	register c;
7717625Ssam 	register struct tty *tp;
7727502Sroot {
77335811Smarc 	register int iflag = tp->t_iflag;
77435811Smarc 	register int lflag = tp->t_lflag;
77535811Smarc 	register u_char *cc = tp->t_cc;
77635811Smarc 	int i, err;
7777502Sroot 
7789578Ssam 	/*
7799578Ssam 	 * If input is pending take it first.
7809578Ssam 	 */
78135811Smarc 	if (lflag&PENDIN)
7827502Sroot 		ttypend(tp);
78335811Smarc 	/*
78435811Smarc 	 * Gather stats.
78535811Smarc 	 */
7867502Sroot 	tk_nin++;
78735811Smarc 	if (lflag&ICANON) {
78835811Smarc 		tk_cancc++;
78935811Smarc 		tp->t_cancc++;
79035811Smarc 	} else {
79135811Smarc 		tk_rawcc++;
79235811Smarc 		tp->t_rawcc++;
79335811Smarc 	}
7949578Ssam 	/*
79535811Smarc 	 * Handle exceptional conditions (break, parity, framing).
7969578Ssam 	 */
79735811Smarc 	if (err = (c&TTY_ERRORMASK)) {
79835811Smarc 		c &= ~TTY_ERRORMASK;
79935811Smarc 		if (err&TTY_FE && !c) {		/* break */
80035811Smarc 			if (iflag&IGNBRK)
80135811Smarc 				goto endcase;
80235811Smarc 			else if (iflag&BRKINT && lflag&ISIG &&
80335811Smarc 				(cc[VINTR] != _POSIX_VDISABLE))
80435811Smarc 				c = cc[VINTR];
80547545Skarels 			else if (iflag&PARMRK)
80647545Skarels 				goto parmrk;
80735811Smarc 		} else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) {
80835811Smarc 			if (iflag&IGNPAR)
80935811Smarc 				goto endcase;
81035811Smarc 			else if (iflag&PARMRK) {
81135811Smarc parmrk:
81235811Smarc 				putc(0377|TTY_QUOTE, &tp->t_rawq);
81335811Smarc 				putc(0|TTY_QUOTE, &tp->t_rawq);
81435811Smarc 				putc(c|TTY_QUOTE, &tp->t_rawq);
81535811Smarc 				goto endcase;
81635811Smarc 			} else
81735811Smarc 				c = 0;
8187502Sroot 		}
8199578Ssam 	}
8209578Ssam 	/*
82135811Smarc 	 * In tandem mode, check high water mark.
8229578Ssam 	 */
82335811Smarc 	if (iflag&IXOFF)
82435811Smarc 		ttyblock(tp);
82535811Smarc 	if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP))
82649380Skarels 		c &= ~0x80;
82744419Smarc 	if ((tp->t_lflag&EXTPROC) == 0) {
82844419Smarc 		/*
82944419Smarc 		 * Check for literal nexting very first
83044419Smarc 		 */
83144419Smarc 		if (tp->t_state&TS_LNCH) {
83244419Smarc 			c |= TTY_QUOTE;
83344419Smarc 			tp->t_state &= ~TS_LNCH;
83444419Smarc 		}
83544419Smarc 		/*
83644419Smarc 		 * Scan for special characters.  This code
83744419Smarc 		 * is really just a big case statement with
83844419Smarc 		 * non-constant cases.  The bottom of the
83944419Smarc 		 * case statement is labeled ``endcase'', so goto
84044419Smarc 		 * it after a case match, or similar.
84144419Smarc 		 */
84244419Smarc 
84344419Smarc 		/*
84444419Smarc 		 * Control chars which aren't controlled
84544419Smarc 		 * by ICANON, ISIG, or IXON.
84644419Smarc 		 */
84744419Smarc 		if (lflag&IEXTEN) {
84844419Smarc 			if (CCEQ(cc[VLNEXT], c)) {
84944419Smarc 				if (lflag&ECHO) {
85044419Smarc 					if (lflag&ECHOE)
85144419Smarc 						ttyoutstr("^\b", tp);
85244419Smarc 					else
85344419Smarc 						ttyecho(c, tp);
85444419Smarc 				}
85544419Smarc 				tp->t_state |= TS_LNCH;
85644419Smarc 				goto endcase;
85744419Smarc 			}
85844419Smarc 			if (CCEQ(cc[VDISCARD], c)) {
85944419Smarc 				if (lflag&FLUSHO)
86044419Smarc 					tp->t_lflag &= ~FLUSHO;
86144419Smarc 				else {
86244419Smarc 					ttyflush(tp, FWRITE);
86335811Smarc 					ttyecho(c, tp);
86444419Smarc 					if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
86544419Smarc 						ttyretype(tp);
86644419Smarc 					tp->t_lflag |= FLUSHO;
86744419Smarc 				}
86844419Smarc 				goto startoutput;
86935811Smarc 			}
8709578Ssam 		}
87144419Smarc 		/*
87244419Smarc 		 * Signals.
87344419Smarc 		 */
87444419Smarc 		if (lflag&ISIG) {
87544419Smarc 			if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
87644419Smarc 				if ((lflag&NOFLSH) == 0)
87744419Smarc 					ttyflush(tp, FREAD|FWRITE);
8787502Sroot 				ttyecho(c, tp);
87944419Smarc 				pgsignal(tp->t_pgrp,
88044419Smarc 				    CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
88144419Smarc 				goto endcase;
8827502Sroot 			}
88344419Smarc 			if (CCEQ(cc[VSUSP], c)) {
88444419Smarc 				if ((lflag&NOFLSH) == 0)
88544419Smarc 					ttyflush(tp, FREAD);
88644419Smarc 				ttyecho(c, tp);
88744419Smarc 				pgsignal(tp->t_pgrp, SIGTSTP, 1);
88844419Smarc 				goto endcase;
88944419Smarc 			}
8909578Ssam 		}
89144419Smarc 		/*
89244419Smarc 		 * Handle start/stop characters.
89344419Smarc 		 */
89444419Smarc 		if (iflag&IXON) {
89544419Smarc 			if (CCEQ(cc[VSTOP], c)) {
89644419Smarc 				if ((tp->t_state&TS_TTSTOP) == 0) {
89744419Smarc 					tp->t_state |= TS_TTSTOP;
898*52485Storek #ifdef sun4c						/* XXX */
899*52485Storek 					(*tp->t_stop)(tp, 0);
900*52485Storek #else
90144419Smarc 					(*cdevsw[major(tp->t_dev)].d_stop)(tp,
90244419Smarc 					   0);
903*52485Storek #endif
90444419Smarc 					return;
90544419Smarc 				}
90644419Smarc 				if (!CCEQ(cc[VSTART], c))
90744419Smarc 					return;
90844419Smarc 				/*
90944419Smarc 				 * if VSTART == VSTOP then toggle
91044419Smarc 				 */
91144419Smarc 				goto endcase;
91235811Smarc 			}
91344419Smarc 			if (CCEQ(cc[VSTART], c))
91444419Smarc 				goto restartoutput;
9159578Ssam 		}
91644419Smarc 		/*
91744419Smarc 		 * IGNCR, ICRNL, & INLCR
91844419Smarc 		 */
91944419Smarc 		if (c == '\r') {
92044419Smarc 			if (iflag&IGNCR)
92144419Smarc 				goto endcase;
92244419Smarc 			else if (iflag&ICRNL)
92344419Smarc 				c = '\n';
92444419Smarc 		} else if (c == '\n' && iflag&INLCR)
92544419Smarc 			c = '\r';
9269578Ssam 	}
92747545Skarels 	if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) {
92844419Smarc 		/*
92944419Smarc 		 * From here on down canonical mode character
93044419Smarc 		 * processing takes place.
93144419Smarc 		 */
93244419Smarc 		/*
93344419Smarc 		 * erase (^H / ^?)
93444419Smarc 		 */
93544419Smarc 		if (CCEQ(cc[VERASE], c)) {
93644419Smarc 			if (tp->t_rawq.c_cc)
9379578Ssam 				ttyrub(unputc(&tp->t_rawq), tp);
93844419Smarc 			goto endcase;
9399578Ssam 		}
94044419Smarc 		/*
94144419Smarc 		 * kill (^U)
94244419Smarc 		 */
94344419Smarc 		if (CCEQ(cc[VKILL], c)) {
94444419Smarc 			if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount &&
94544419Smarc 			    (lflag&ECHOPRT) == 0) {
94644419Smarc 				while (tp->t_rawq.c_cc)
94744419Smarc 					ttyrub(unputc(&tp->t_rawq), tp);
94844419Smarc 			} else {
94944419Smarc 				ttyecho(c, tp);
95044419Smarc 				if (lflag&ECHOK || lflag&ECHOKE)
95144419Smarc 					ttyecho('\n', tp);
952*52485Storek 				flushq(&tp->t_rawq);
95344419Smarc 				tp->t_rocount = 0;
95444419Smarc 			}
95544419Smarc 			tp->t_state &= ~TS_LOCAL;
95644419Smarc 			goto endcase;
95744419Smarc 		}
95844419Smarc 		/*
95944419Smarc 		 * word erase (^W)
96044419Smarc 		 */
96144419Smarc 		if (CCEQ(cc[VWERASE], c)) {
96244419Smarc 			int ctype;
96347545Skarels 			int alt = lflag&ALTWERASE;
96435811Smarc 
96544419Smarc 			/*
96644419Smarc 			 * erase whitespace
96744419Smarc 			 */
96844419Smarc 			while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
96944419Smarc 				ttyrub(c, tp);
97044419Smarc 			if (c == -1)
97144419Smarc 				goto endcase;
97244419Smarc 			/*
97347545Skarels 			 * erase last char of word and remember the
97447545Skarels 			 * next chars type (for ALTWERASE)
97544419Smarc 			 */
97635811Smarc 			ttyrub(c, tp);
97744419Smarc 			c = unputc(&tp->t_rawq);
97847545Skarels 			if (c == -1)
97944419Smarc 				goto endcase;
98051003Sbostic 			if (c == ' ' || c == '\t') {
98151003Sbostic 				putc(c, &tp->t_rawq);
98251003Sbostic 				goto endcase;
98351003Sbostic 			}
98449380Skarels 			ctype = ISALPHA(c);
98544419Smarc 			/*
98647545Skarels 			 * erase rest of word
98744419Smarc 			 */
98844419Smarc 			do {
98944419Smarc 				ttyrub(c, tp);
99044419Smarc 				c = unputc(&tp->t_rawq);
99144419Smarc 				if (c == -1)
99244419Smarc 					goto endcase;
99347545Skarels 			} while (c != ' ' && c != '\t' &&
99449380Skarels 				(alt == 0 || ISALPHA(c) == ctype));
99544419Smarc 			(void) putc(c, &tp->t_rawq);
99634492Skarels 			goto endcase;
99744419Smarc 		}
99835811Smarc 		/*
99944419Smarc 		 * reprint line (^R)
100035811Smarc 		 */
100144419Smarc 		if (CCEQ(cc[VREPRINT], c)) {
100244419Smarc 			ttyretype(tp);
100334492Skarels 			goto endcase;
100434492Skarels 		}
100535811Smarc 		/*
100644419Smarc 		 * ^T - kernel info and generate SIGINFO
100735811Smarc 		 */
100844419Smarc 		if (CCEQ(cc[VSTATUS], c)) {
100951068Smarc 			if (lflag&ISIG)
101051068Smarc 				pgsignal(tp->t_pgrp, SIGINFO, 1);
101144419Smarc 			if ((lflag&NOKERNINFO) == 0)
101244419Smarc 				ttyinfo(tp);
101344419Smarc 			goto endcase;
101444419Smarc 		}
10159578Ssam 	}
10169578Ssam 	/*
10179578Ssam 	 * Check for input buffer overflow
10189578Ssam 	 */
101947545Skarels 	if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
102035811Smarc 		if (iflag&IMAXBEL) {
102135811Smarc 			if (tp->t_outq.c_cc < tp->t_hiwat)
102235811Smarc 				(void) ttyoutput(CTRL('g'), tp);
102335811Smarc 		} else
102435811Smarc 			ttyflush(tp, FREAD | FWRITE);
10259578Ssam 		goto endcase;
102610391Ssam 	}
10279578Ssam 	/*
10289578Ssam 	 * Put data char in q for user and
10299578Ssam 	 * wakeup on seeing a line delimiter.
10309578Ssam 	 */
10319578Ssam 	if (putc(c, &tp->t_rawq) >= 0) {
103247545Skarels 		if ((lflag&ICANON) == 0) {
103347545Skarels 			ttwakeup(tp);
103447545Skarels 			ttyecho(c, tp);
103547545Skarels 			goto endcase;
103647545Skarels 		}
103735811Smarc 		if (ttbreakc(c)) {
10389578Ssam 			tp->t_rocount = 0;
10399578Ssam 			catq(&tp->t_rawq, &tp->t_canq);
10407502Sroot 			ttwakeup(tp);
10419578Ssam 		} else if (tp->t_rocount++ == 0)
10429578Ssam 			tp->t_rocol = tp->t_col;
10439578Ssam 		if (tp->t_state&TS_ERASE) {
104435811Smarc 			/*
104535811Smarc 			 * end of prterase \.../
104635811Smarc 			 */
10479578Ssam 			tp->t_state &= ~TS_ERASE;
10489578Ssam 			(void) ttyoutput('/', tp);
10499578Ssam 		}
10509578Ssam 		i = tp->t_col;
10517502Sroot 		ttyecho(c, tp);
105235811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ECHO) {
105335811Smarc 			/*
105435811Smarc 			 * Place the cursor over the '^' of the ^D.
105535811Smarc 			 */
10569578Ssam 			i = MIN(2, tp->t_col - i);
10579578Ssam 			while (i > 0) {
10589578Ssam 				(void) ttyoutput('\b', tp);
10599578Ssam 				i--;
10609578Ssam 			}
10619578Ssam 		}
10627502Sroot 	}
10639578Ssam endcase:
10649578Ssam 	/*
106535811Smarc 	 * IXANY means allow any character to restart output.
10669578Ssam 	 */
106740712Skarels 	if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 &&
106840712Skarels 	    cc[VSTART] != cc[VSTOP])
10697502Sroot 		return;
10709578Ssam restartoutput:
10717502Sroot 	tp->t_state &= ~TS_TTSTOP;
107235811Smarc 	tp->t_lflag &= ~FLUSHO;
10739578Ssam startoutput:
10747502Sroot 	ttstart(tp);
10757502Sroot }
10767502Sroot 
10777502Sroot /*
107849380Skarels  * Output a single character on a tty, doing output processing
107949380Skarels  * as needed (expanding tabs, newline processing, etc.).
108049380Skarels  * Returns < 0 if putc succeeds, otherwise returns char to resend.
10817502Sroot  * Must be recursive.
10827502Sroot  */
10837502Sroot ttyoutput(c, tp)
10847502Sroot 	register c;
10857502Sroot 	register struct tty *tp;
10867502Sroot {
108749380Skarels 	register int col;
108835811Smarc 	register long oflag = tp->t_oflag;
108935811Smarc 
109040712Skarels 	if ((oflag&OPOST) == 0) {
109135811Smarc 		if (tp->t_lflag&FLUSHO)
10927502Sroot 			return (-1);
10937502Sroot 		if (putc(c, &tp->t_outq))
10947625Ssam 			return (c);
10957502Sroot 		tk_nout++;
109635811Smarc 		tp->t_outcc++;
10977502Sroot 		return (-1);
10987502Sroot 	}
109935811Smarc 	c &= TTY_CHARMASK;
11007502Sroot 	/*
110149380Skarels 	 * Do tab expansion if OXTABS is set.
110242882Smarc 	 * Special case if we have external processing, we don't
110342882Smarc 	 * do the tab expansion because we'll probably get it
110442882Smarc 	 * wrong.  If tab expansion needs to be done, let it
110542882Smarc 	 * happen externally.
11067502Sroot 	 */
110747545Skarels 	if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) {
11087502Sroot 		register int s;
11097502Sroot 
11107502Sroot 		c = 8 - (tp->t_col&7);
111135811Smarc 		if ((tp->t_lflag&FLUSHO) == 0) {
111217545Skarels 			s = spltty();		/* don't interrupt tabs */
11137502Sroot 			c -= b_to_q("        ", c, &tp->t_outq);
11147502Sroot 			tk_nout += c;
111535811Smarc 			tp->t_outcc += c;
11167502Sroot 			splx(s);
11177502Sroot 		}
11187502Sroot 		tp->t_col += c;
11197502Sroot 		return (c ? -1 : '\t');
11207502Sroot 	}
112135811Smarc 	if (c == CEOT && oflag&ONOEOT)
112247545Skarels 		return (-1);
11237502Sroot 	tk_nout++;
112435811Smarc 	tp->t_outcc++;
11257502Sroot 	/*
112649380Skarels 	 * Newline translation: if ONLCR is set,
112749380Skarels 	 * translate newline into "\r\n".
11287502Sroot 	 */
112935811Smarc 	if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
11307502Sroot 		return (c);
113135811Smarc 	if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq))
113235811Smarc 		return (c);
113347545Skarels 
113449380Skarels 	col = tp->t_col;
113549380Skarels 	switch (CCLASS(c)) {
11367502Sroot 
11377502Sroot 	case ORDINARY:
113849380Skarels 		col++;
11397502Sroot 
11407502Sroot 	case CONTROL:
11417502Sroot 		break;
11427502Sroot 
11437502Sroot 	case BACKSPACE:
114449380Skarels 		if (col > 0)
114549380Skarels 			col--;
11467502Sroot 		break;
11477502Sroot 
11487502Sroot 	case NEWLINE:
114949380Skarels 		col = 0;
11507502Sroot 		break;
11517502Sroot 
11527502Sroot 	case TAB:
115349380Skarels 		col = (col + 8) &~ 0x7;
11547502Sroot 		break;
11557502Sroot 
11567502Sroot 	case RETURN:
115749380Skarels 		col = 0;
11587502Sroot 	}
115949380Skarels 	tp->t_col = col;
11607502Sroot 	return (-1);
11617502Sroot }
11627502Sroot 
11637502Sroot /*
116449380Skarels  * Process a read call on a tty device.
11657502Sroot  */
116637584Smarc ttread(tp, uio, flag)
11677625Ssam 	register struct tty *tp;
11687722Swnj 	struct uio *uio;
1169*52485Storek 	int flag;
11707502Sroot {
11717502Sroot 	register struct clist *qp;
117235811Smarc 	register int c;
117341383Smarc 	register long lflag;
117435811Smarc 	register u_char *cc = tp->t_cc;
117547545Skarels 	register struct proc *p = curproc;
11769859Ssam 	int s, first, error = 0;
11777502Sroot 
11787502Sroot loop:
117941383Smarc 	lflag = tp->t_lflag;
118037584Smarc 	s = spltty();
11819578Ssam 	/*
118237584Smarc 	 * take pending input first
11839578Ssam 	 */
118435811Smarc 	if (lflag&PENDIN)
11857502Sroot 		ttypend(tp);
11869859Ssam 	splx(s);
118740712Skarels 
11889578Ssam 	/*
11899578Ssam 	 * Hang process if it's in the background.
11909578Ssam 	 */
119147545Skarels 	if (isbackground(p, tp)) {
119247545Skarels 		if ((p->p_sigignore & sigmask(SIGTTIN)) ||
119347545Skarels 		   (p->p_sigmask & sigmask(SIGTTIN)) ||
119447545Skarels 		    p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0)
11958520Sroot 			return (EIO);
119647545Skarels 		pgsignal(p->p_pgrp, SIGTTIN, 1);
119743377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
119843377Smarc 		    ttybg, 0))
119940712Skarels 			return (error);
120023165Sbloom 		goto loop;
12017502Sroot 	}
120240712Skarels 
12039578Ssam 	/*
120435811Smarc 	 * If canonical, use the canonical queue,
120535811Smarc 	 * else use the raw queue.
120637584Smarc 	 *
120747545Skarels 	 * (should get rid of clists...)
12089578Ssam 	 */
120935811Smarc 	qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq;
121040712Skarels 
12119578Ssam 	/*
121240712Skarels 	 * If there is no input, sleep on rawq
121340712Skarels 	 * awaiting hardware receipt and notification.
121440712Skarels 	 * If we have data, we don't need to check for carrier.
12159578Ssam 	 */
121617545Skarels 	s = spltty();
12179578Ssam 	if (qp->c_cc <= 0) {
121840712Skarels 		int carrier;
121940712Skarels 
122040712Skarels 		carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
122140712Skarels 		if (!carrier && tp->t_state&TS_ISOPEN) {
12229859Ssam 			splx(s);
122340712Skarels 			return (0);	/* EOF */
12247502Sroot 		}
122537728Smckusick 		if (flag & IO_NDELAY) {
122637584Smarc 			splx(s);
122737584Smarc 			return (EWOULDBLOCK);
122837584Smarc 		}
122943377Smarc 		error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
123040712Skarels 		    carrier ? ttyin : ttopen, 0);
12319859Ssam 		splx(s);
123243377Smarc 		if (error)
123340712Skarels 			return (error);
12349578Ssam 		goto loop;
12359578Ssam 	}
12369859Ssam 	splx(s);
123740712Skarels 
12389578Ssam 	/*
123935811Smarc 	 * Input present, check for input mapping and processing.
12409578Ssam 	 */
12419578Ssam 	first = 1;
12429578Ssam 	while ((c = getc(qp)) >= 0) {
12439578Ssam 		/*
124435811Smarc 		 * delayed suspend (^Y)
12459578Ssam 		 */
124635811Smarc 		if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) {
124742882Smarc 			pgsignal(tp->t_pgrp, SIGTSTP, 1);
12489578Ssam 			if (first) {
124943377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
125043377Smarc 				    TTIPRI | PCATCH, ttybg, 0))
125140712Skarels 					break;
12529578Ssam 				goto loop;
12539578Ssam 			}
12549578Ssam 			break;
12557502Sroot 		}
12569578Ssam 		/*
125735811Smarc 		 * Interpret EOF only in canonical mode.
12589578Ssam 		 */
125935811Smarc 		if (CCEQ(cc[VEOF], c) && lflag&ICANON)
12609578Ssam 			break;
12619578Ssam 		/*
12629578Ssam 		 * Give user character.
12639578Ssam 		 */
126440712Skarels  		error = ureadc(c, uio);
12659578Ssam 		if (error)
12669578Ssam 			break;
126714938Smckusick  		if (uio->uio_resid == 0)
12689578Ssam 			break;
12699578Ssam 		/*
127035811Smarc 		 * In canonical mode check for a "break character"
12719578Ssam 		 * marking the end of a "line of input".
12729578Ssam 		 */
127340712Skarels 		if (lflag&ICANON && ttbreakc(c))
12749578Ssam 			break;
12759578Ssam 		first = 0;
12767502Sroot 	}
12779578Ssam 	/*
12789578Ssam 	 * Look to unblock output now that (presumably)
12799578Ssam 	 * the input queue has gone down.
12809578Ssam 	 */
1281*52485Storek 	s = spltty();
128235811Smarc 	if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) {
128347545Skarels 		if (cc[VSTART] != _POSIX_VDISABLE &&
128447545Skarels 		    putc(cc[VSTART], &tp->t_outq) == 0) {
12857502Sroot 			tp->t_state &= ~TS_TBLOCK;
12867502Sroot 			ttstart(tp);
12877502Sroot 		}
128835811Smarc 	}
1289*52485Storek 	splx(s);
12908520Sroot 	return (error);
12917502Sroot }
12927502Sroot 
12937502Sroot /*
129425391Skarels  * Check the output queue on tp for space for a kernel message
129525391Skarels  * (from uprintf/tprintf).  Allow some space over the normal
129625391Skarels  * hiwater mark so we don't lose messages due to normal flow
129725391Skarels  * control, but don't let the tty run amok.
129830695Skarels  * Sleeps here are not interruptible, but we return prematurely
129930695Skarels  * if new signals come in.
130025391Skarels  */
130125391Skarels ttycheckoutq(tp, wait)
130225391Skarels 	register struct tty *tp;
130325391Skarels 	int wait;
130425391Skarels {
130530695Skarels 	int hiwat, s, oldsig;
130648439Skarels 	extern int wakeup();
130725391Skarels 
130835811Smarc 	hiwat = tp->t_hiwat;
130925391Skarels 	s = spltty();
1310*52485Storek 	oldsig = wait ? curproc->p_sig : 0;
131125391Skarels 	if (tp->t_outq.c_cc > hiwat + 200)
131229946Skarels 		while (tp->t_outq.c_cc > hiwat) {
131329946Skarels 			ttstart(tp);
131447545Skarels 			if (wait == 0 || curproc->p_sig != oldsig) {
131529946Skarels 				splx(s);
131629946Skarels 				return (0);
131729946Skarels 			}
131830695Skarels 			timeout(wakeup, (caddr_t)&tp->t_outq, hz);
131929946Skarels 			tp->t_state |= TS_ASLEEP;
132030695Skarels 			sleep((caddr_t)&tp->t_outq, PZERO - 1);
132125391Skarels 		}
132225391Skarels 	splx(s);
132325391Skarels 	return (1);
132425391Skarels }
132525391Skarels 
132625391Skarels /*
132749380Skarels  * Process a write call on a tty device.
13287502Sroot  */
132937584Smarc ttwrite(tp, uio, flag)
13307625Ssam 	register struct tty *tp;
13319578Ssam 	register struct uio *uio;
1332*52485Storek 	int flag;
13337502Sroot {
13347502Sroot 	register char *cp;
133540712Skarels 	register int cc = 0, ce;
133647545Skarels 	register struct proc *p = curproc;
13379578Ssam 	int i, hiwat, cnt, error, s;
13387502Sroot 	char obuf[OBUFSIZ];
13397502Sroot 
134035811Smarc 	hiwat = tp->t_hiwat;
13419578Ssam 	cnt = uio->uio_resid;
13429578Ssam 	error = 0;
13437502Sroot loop:
134437584Smarc 	s = spltty();
134540712Skarels 	if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
134637584Smarc 		if (tp->t_state&TS_ISOPEN) {
134737584Smarc 			splx(s);
134837584Smarc 			return (EIO);
134937728Smckusick 		} else if (flag & IO_NDELAY) {
135037584Smarc 			splx(s);
135140712Skarels 			error = EWOULDBLOCK;
135240712Skarels 			goto out;
135337584Smarc 		} else {
135437584Smarc 			/*
135537584Smarc 			 * sleep awaiting carrier
135637584Smarc 			 */
135743377Smarc 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
135843377Smarc 					TTIPRI | PCATCH,ttopen, 0);
135937584Smarc 			splx(s);
136043377Smarc 			if (error)
136140712Skarels 				goto out;
136237584Smarc 			goto loop;
136337584Smarc 		}
136437584Smarc 	}
136537584Smarc 	splx(s);
13669578Ssam 	/*
13679578Ssam 	 * Hang the process if it's in the background.
13689578Ssam 	 */
136947545Skarels 	if (isbackground(p, tp) &&
137047545Skarels 	    tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 &&
137147545Skarels 	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
137247545Skarels 	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
137347545Skarels 	     p->p_pgrp->pg_jobc) {
137447545Skarels 		pgsignal(p->p_pgrp, SIGTTOU, 1);
137543377Smarc 		if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
137643377Smarc 		    ttybg, 0))
137740712Skarels 			goto out;
137821776Sbloom 		goto loop;
13797502Sroot 	}
13809578Ssam 	/*
13819578Ssam 	 * Process the user's data in at most OBUFSIZ
138240712Skarels 	 * chunks.  Perform any output translation.
138340712Skarels 	 * Keep track of high water mark, sleep on overflow
138440712Skarels 	 * awaiting device aid in acquiring new space.
13859578Ssam 	 */
138640712Skarels 	while (uio->uio_resid > 0 || cc > 0) {
138740712Skarels 		if (tp->t_lflag&FLUSHO) {
138840712Skarels 			uio->uio_resid = 0;
138940712Skarels 			return (0);
139040712Skarels 		}
139140712Skarels 		if (tp->t_outq.c_cc > hiwat)
139232067Skarels 			goto ovhiwat;
13939578Ssam 		/*
139440712Skarels 		 * Grab a hunk of data from the user,
139540712Skarels 		 * unless we have some leftover from last time.
13969578Ssam 		 */
13977822Sroot 		if (cc == 0) {
139840712Skarels 			cc = min(uio->uio_resid, OBUFSIZ);
139940712Skarels 			cp = obuf;
140040712Skarels 			error = uiomove(cp, cc, uio);
140140712Skarels 			if (error) {
140240712Skarels 				cc = 0;
140340712Skarels 				break;
140440712Skarels 			}
14057822Sroot 		}
14069578Ssam 		/*
14079578Ssam 		 * If nothing fancy need be done, grab those characters we
14089578Ssam 		 * can handle without any of ttyoutput's processing and
14099578Ssam 		 * just transfer them to the output q.  For those chars
14109578Ssam 		 * which require special processing (as indicated by the
14119578Ssam 		 * bits in partab), call ttyoutput.  After processing
14129578Ssam 		 * a hunk of data, look for FLUSHO so ^O's will take effect
14139578Ssam 		 * immediately.
14149578Ssam 		 */
14159578Ssam 		while (cc > 0) {
141640712Skarels 			if ((tp->t_oflag&OPOST) == 0)
14177502Sroot 				ce = cc;
14187502Sroot 			else {
141934492Skarels 				ce = cc - scanc((unsigned)cc, (u_char *)cp,
142049380Skarels 				   (u_char *)partab, CCLASSMASK);
14219578Ssam 				/*
14229578Ssam 				 * If ce is zero, then we're processing
14239578Ssam 				 * a special character through ttyoutput.
14249578Ssam 				 */
14259578Ssam 				if (ce == 0) {
14267502Sroot 					tp->t_rocount = 0;
14277502Sroot 					if (ttyoutput(*cp, tp) >= 0) {
142821776Sbloom 					    /* no c-lists, wait a bit */
142921776Sbloom 					    ttstart(tp);
143043377Smarc 					    if (error = ttysleep(tp,
143143377Smarc 						(caddr_t)&lbolt,
143243377Smarc 						 TTOPRI | PCATCH, ttybuf, 0))
143340712Skarels 						    break;
143421776Sbloom 					    goto loop;
14357502Sroot 					}
14369578Ssam 					cp++, cc--;
143735811Smarc 					if ((tp->t_lflag&FLUSHO) ||
14389578Ssam 					    tp->t_outq.c_cc > hiwat)
14397502Sroot 						goto ovhiwat;
14409578Ssam 					continue;
14417502Sroot 				}
14427502Sroot 			}
14439578Ssam 			/*
14449578Ssam 			 * A bunch of normal characters have been found,
14459578Ssam 			 * transfer them en masse to the output queue and
14469578Ssam 			 * continue processing at the top of the loop.
14479578Ssam 			 * If there are any further characters in this
14489578Ssam 			 * <= OBUFSIZ chunk, the first should be a character
14499578Ssam 			 * requiring special handling by ttyoutput.
14509578Ssam 			 */
14517502Sroot 			tp->t_rocount = 0;
14529578Ssam 			i = b_to_q(cp, ce, &tp->t_outq);
14539578Ssam 			ce -= i;
14549578Ssam 			tp->t_col += ce;
14559578Ssam 			cp += ce, cc -= ce, tk_nout += ce;
145635811Smarc 			tp->t_outcc += ce;
14579578Ssam 			if (i > 0) {
14589578Ssam 				/* out of c-lists, wait a bit */
14597502Sroot 				ttstart(tp);
146043377Smarc 				if (error = ttysleep(tp, (caddr_t)&lbolt,
146143377Smarc 					    TTOPRI | PCATCH, ttybuf, 0))
146240712Skarels 					break;
146321776Sbloom 				goto loop;
14647502Sroot 			}
146535811Smarc 			if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat)
146640712Skarels 				break;
14677502Sroot 		}
146835811Smarc 		ttstart(tp);
14697502Sroot 	}
147040712Skarels out:
147140712Skarels 	/*
147240712Skarels 	 * If cc is nonzero, we leave the uio structure inconsistent,
147340712Skarels 	 * as the offset and iov pointers have moved forward,
147440712Skarels 	 * but it doesn't matter (the call will either return short
147540712Skarels 	 * or restart with a new uio).
147640712Skarels 	 */
147740712Skarels 	uio->uio_resid += cc;
14788520Sroot 	return (error);
147940712Skarels 
14807502Sroot ovhiwat:
148132067Skarels 	ttstart(tp);
148232067Skarels 	s = spltty();
14839578Ssam 	/*
148435811Smarc 	 * This can only occur if FLUSHO is set in t_lflag,
148532067Skarels 	 * or if ttstart/oproc is synchronous (or very fast).
14869578Ssam 	 */
14877502Sroot 	if (tp->t_outq.c_cc <= hiwat) {
14889578Ssam 		splx(s);
14897502Sroot 		goto loop;
14907502Sroot 	}
149137728Smckusick 	if (flag & IO_NDELAY) {
149217545Skarels 		splx(s);
149340712Skarels 		uio->uio_resid += cc;
14947822Sroot 		if (uio->uio_resid == cnt)
14958520Sroot 			return (EWOULDBLOCK);
14968520Sroot 		return (0);
14977502Sroot 	}
14987502Sroot 	tp->t_state |= TS_ASLEEP;
149943377Smarc 	error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
15009578Ssam 	splx(s);
150143377Smarc 	if (error)
150240712Skarels 		goto out;
15037502Sroot 	goto loop;
15047502Sroot }
15057502Sroot 
15067502Sroot /*
15077502Sroot  * Rubout one character from the rawq of tp
15087502Sroot  * as cleanly as possible.
15097502Sroot  */
15107502Sroot ttyrub(c, tp)
15117625Ssam 	register c;
15127625Ssam 	register struct tty *tp;
15137502Sroot {
15147502Sroot 	register char *cp;
15157502Sroot 	register int savecol;
15167502Sroot 	int s;
15177502Sroot 	char *nextc();
15187502Sroot 
151942882Smarc 	if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC))
15207502Sroot 		return;
152135811Smarc 	tp->t_lflag &= ~FLUSHO;
152235811Smarc 	if (tp->t_lflag&ECHOE) {
15237502Sroot 		if (tp->t_rocount == 0) {
15247502Sroot 			/*
15257502Sroot 			 * Screwed by ttwrite; retype
15267502Sroot 			 */
15277502Sroot 			ttyretype(tp);
15287502Sroot 			return;
15297502Sroot 		}
153035811Smarc 		if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE))
15317502Sroot 			ttyrubo(tp, 2);
153249380Skarels 		else switch (CCLASS(c &= TTY_CHARMASK)) {
15337502Sroot 
15347502Sroot 		case ORDINARY:
153535811Smarc 			ttyrubo(tp, 1);
15367502Sroot 			break;
15377502Sroot 
15387502Sroot 		case VTAB:
15397502Sroot 		case BACKSPACE:
15407502Sroot 		case CONTROL:
15417502Sroot 		case RETURN:
154247545Skarels 		case NEWLINE:
154335811Smarc 			if (tp->t_lflag&ECHOCTL)
15447502Sroot 				ttyrubo(tp, 2);
15457502Sroot 			break;
15467502Sroot 
154735811Smarc 		case TAB: {
154835811Smarc 			int c;
154935811Smarc 
15507502Sroot 			if (tp->t_rocount < tp->t_rawq.c_cc) {
15517502Sroot 				ttyretype(tp);
15527502Sroot 				return;
15537502Sroot 			}
155417545Skarels 			s = spltty();
15557502Sroot 			savecol = tp->t_col;
15569578Ssam 			tp->t_state |= TS_CNTTB;
155735811Smarc 			tp->t_lflag |= FLUSHO;
15587502Sroot 			tp->t_col = tp->t_rocol;
15599578Ssam 			cp = tp->t_rawq.c_cf;
156039407Smarc 			if (cp)
156139407Smarc 				c = *cp;	/* XXX FIX NEXTC */
156235811Smarc 			for (; cp; cp = nextc(&tp->t_rawq, cp, &c))
156335811Smarc 				ttyecho(c, tp);
156435811Smarc 			tp->t_lflag &= ~FLUSHO;
15659578Ssam 			tp->t_state &= ~TS_CNTTB;
15667502Sroot 			splx(s);
15677502Sroot 			/*
15687502Sroot 			 * savecol will now be length of the tab
15697502Sroot 			 */
15707502Sroot 			savecol -= tp->t_col;
15717502Sroot 			tp->t_col += savecol;
15727502Sroot 			if (savecol > 8)
15737502Sroot 				savecol = 8;		/* overflow screw */
15747502Sroot 			while (--savecol >= 0)
15757502Sroot 				(void) ttyoutput('\b', tp);
15767502Sroot 			break;
157735811Smarc 		}
15787502Sroot 
15797502Sroot 		default:
158037584Smarc 			/* XXX */
158135811Smarc 			printf("ttyrub: would panic c = %d, val = %d\n",
158249380Skarels 				c, CCLASS(c));
158335811Smarc 			/*panic("ttyrub");*/
15847502Sroot 		}
158535811Smarc 	} else if (tp->t_lflag&ECHOPRT) {
15869578Ssam 		if ((tp->t_state&TS_ERASE) == 0) {
15877502Sroot 			(void) ttyoutput('\\', tp);
15889578Ssam 			tp->t_state |= TS_ERASE;
15897502Sroot 		}
15907502Sroot 		ttyecho(c, tp);
15917502Sroot 	} else
159235811Smarc 		ttyecho(tp->t_cc[VERASE], tp);
15937502Sroot 	tp->t_rocount--;
15947502Sroot }
15957502Sroot 
15967502Sroot /*
15977502Sroot  * Crt back over cnt chars perhaps
15987502Sroot  * erasing them.
15997502Sroot  */
16007502Sroot ttyrubo(tp, cnt)
16017625Ssam 	register struct tty *tp;
16027625Ssam 	int cnt;
16037502Sroot {
16047502Sroot 
16057502Sroot 	while (--cnt >= 0)
160640712Skarels 		ttyoutstr("\b \b", tp);
16077502Sroot }
16087502Sroot 
16097502Sroot /*
16107502Sroot  * Reprint the rawq line.
16117502Sroot  * We assume c_cc has already been checked.
16127502Sroot  */
16137502Sroot ttyretype(tp)
16147625Ssam 	register struct tty *tp;
16157502Sroot {
16167502Sroot 	register char *cp;
16177502Sroot 	char *nextc();
161835811Smarc 	int s, c;
16197502Sroot 
162035811Smarc 	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
162135811Smarc 		ttyecho(tp->t_cc[VREPRINT], tp);
16227502Sroot 	(void) ttyoutput('\n', tp);
162317545Skarels 	s = spltty();
162435811Smarc 	/*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162535811Smarc 	  BIT OF FIRST CHAR ****/
162635811Smarc 	for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) {
162735811Smarc 		ttyecho(c, tp);
162835811Smarc 	}
162935811Smarc 	for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) {
163035811Smarc 		ttyecho(c, tp);
163135811Smarc 	}
16329578Ssam 	tp->t_state &= ~TS_ERASE;
16337502Sroot 	splx(s);
16347502Sroot 	tp->t_rocount = tp->t_rawq.c_cc;
16357502Sroot 	tp->t_rocol = 0;
16367502Sroot }
16377502Sroot 
16387502Sroot /*
163935811Smarc  * Echo a typed character to the terminal.
16407502Sroot  */
16417502Sroot ttyecho(c, tp)
16427625Ssam 	register c;
16437625Ssam 	register struct tty *tp;
16447502Sroot {
16459578Ssam 	if ((tp->t_state&TS_CNTTB) == 0)
164635811Smarc 		tp->t_lflag &= ~FLUSHO;
164747545Skarels 	if (((tp->t_lflag&ECHO) == 0 &&
164847545Skarels 	    ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC))
16497502Sroot 		return;
165035811Smarc 	if (tp->t_lflag&ECHOCTL) {
165140712Skarels 		if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
165240712Skarels 		    c == 0177) {
16537502Sroot 			(void) ttyoutput('^', tp);
165435811Smarc 			c &= TTY_CHARMASK;
16557502Sroot 			if (c == 0177)
16567502Sroot 				c = '?';
16577502Sroot 			else
16587502Sroot 				c += 'A' - 1;
16597502Sroot 		}
16607502Sroot 	}
166135811Smarc 	(void) ttyoutput(c, tp);
16627502Sroot }
16637502Sroot 
16647502Sroot /*
16657502Sroot  * send string cp to tp
16667502Sroot  */
166740712Skarels ttyoutstr(cp, tp)
16687625Ssam 	register char *cp;
16697625Ssam 	register struct tty *tp;
16707502Sroot {
16717502Sroot 	register char c;
16727502Sroot 
16737502Sroot 	while (c = *cp++)
16747502Sroot 		(void) ttyoutput(c, tp);
16757502Sroot }
16767502Sroot 
167749380Skarels /*
167849380Skarels  * Wake up any readers on a tty.
167949380Skarels  */
16807502Sroot ttwakeup(tp)
168147545Skarels 	register struct tty *tp;
16827502Sroot {
16837502Sroot 
16847502Sroot 	if (tp->t_rsel) {
16857502Sroot 		selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
16867502Sroot 		tp->t_state &= ~TS_RCOLL;
16877502Sroot 		tp->t_rsel = 0;
16887502Sroot 	}
168912752Ssam 	if (tp->t_state & TS_ASYNC)
169042882Smarc 		pgsignal(tp->t_pgrp, SIGIO, 1);
16917502Sroot 	wakeup((caddr_t)&tp->t_rawq);
16927502Sroot }
169335811Smarc 
169435811Smarc /*
169548439Skarels  * Look up a code for a specified speed in a conversion table;
169648439Skarels  * used by drivers to map software speed values to hardware parameters.
169748439Skarels  */
169848439Skarels ttspeedtab(speed, table)
1699*52485Storek 	int speed;
170048439Skarels 	register struct speedtab *table;
170148439Skarels {
170248439Skarels 
170348439Skarels 	for ( ; table->sp_speed != -1; table++)
170448439Skarels 		if (table->sp_speed == speed)
170548439Skarels 			return (table->sp_code);
170648439Skarels 	return (-1);
170748439Skarels }
170848439Skarels 
170948439Skarels /*
171035811Smarc  * set tty hi and low water marks
171135811Smarc  *
171235811Smarc  * Try to arrange the dynamics so there's about one second
171335811Smarc  * from hi to low water.
171435811Smarc  *
171535811Smarc  */
171635811Smarc ttsetwater(tp)
171735811Smarc 	struct tty *tp;
171835811Smarc {
171935811Smarc 	register cps = tp->t_ospeed / 10;
172035811Smarc 	register x;
172135811Smarc 
172235811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x))
172335811Smarc 	tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT);
172435811Smarc 	x += cps;
172535811Smarc 	x = clamp(x, TTMAXHIWAT, TTMINHIWAT);
172635811Smarc 	tp->t_hiwat = roundup(x, CBSIZE);
172735811Smarc #undef clamp
172835811Smarc }
172935811Smarc 
173039407Smarc /*
173139407Smarc  * Report on state of foreground process group.
173239407Smarc  */
173339407Smarc ttyinfo(tp)
173449907Sbostic 	register struct tty *tp;
173539407Smarc {
173649907Sbostic 	register struct proc *p, *pick;
173741177Smarc 	struct timeval utime, stime;
173849907Sbostic 	int tmp;
173939407Smarc 
174039407Smarc 	if (ttycheckoutq(tp,0) == 0)
174139407Smarc 		return;
174249907Sbostic 
174349907Sbostic 	/* Print load average. */
174449907Sbostic 	tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT;
174549907Sbostic 	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
174649907Sbostic 
174739555Smarc 	if (tp->t_session == NULL)
174849907Sbostic 		ttyprintf(tp, "not a controlling terminal\n");
174941177Smarc 	else if (tp->t_pgrp == NULL)
175049907Sbostic 		ttyprintf(tp, "no foreground process group\n");
175141177Smarc 	else if ((p = tp->t_pgrp->pg_mem) == NULL)
175249907Sbostic 		ttyprintf(tp, "empty foreground process group\n");
175339407Smarc 	else {
175449907Sbostic 		/* Pick interesting process. */
175549907Sbostic 		for (pick = NULL; p != NULL; p = p->p_pgrpnxt)
175641177Smarc 			if (proc_compare(pick, p))
175741177Smarc 				pick = p;
175849907Sbostic 
175949907Sbostic 		ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
176049907Sbostic 		    pick->p_stat == SRUN ? "running" :
176149907Sbostic 		    pick->p_wmesg ? pick->p_wmesg : "iowait");
176249907Sbostic 
176349907Sbostic 		/*
176449907Sbostic 		 * Lock out clock if process is running; get user/system
176549907Sbostic 		 * cpu time.
176641177Smarc 		 */
176747545Skarels 		if (curproc == pick)
176849907Sbostic 			tmp = splclock();
176941177Smarc 		utime = pick->p_utime;
177041177Smarc 		stime = pick->p_stime;
177147545Skarels 		if (curproc == pick)
177249907Sbostic 			splx(tmp);
177339407Smarc 
177449907Sbostic 		/* Print user time. */
177549907Sbostic 		ttyprintf(tp, "%d.%02du ",
177649907Sbostic 		    utime.tv_sec, (utime.tv_usec + 5000) / 10000);
177741177Smarc 
177849907Sbostic 		/* Print system time. */
177949907Sbostic 		ttyprintf(tp, "%d.%02ds ",
178049907Sbostic 		    stime.tv_sec, (stime.tv_usec + 5000) / 10000);
178149907Sbostic 
178249907Sbostic #define	pgtok(a)	(((a) * NBPG) / 1024)
178349907Sbostic 		/* Print percentage cpu, resident set size. */
178449907Sbostic 		tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
178549907Sbostic 		ttyprintf(tp, "%d%% %dk\n",
1786*52485Storek 		    tmp / 100,
1787*52485Storek 		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
1788*52485Storek 			pgtok(pick->p_vmspace->vm_rssize));
178941177Smarc 	}
179049907Sbostic 	tp->t_rocount = 0;	/* so pending input will be retyped if BS */
179141177Smarc }
179241177Smarc 
179341177Smarc /*
179441177Smarc  * Returns 1 if p2 is "better" than p1
179541177Smarc  *
179641177Smarc  * The algorithm for picking the "interesting" process is thus:
179741177Smarc  *
179841177Smarc  *	1) (Only foreground processes are eligable - implied)
179941177Smarc  *	2) Runnable processes are favored over anything
180041177Smarc  *	   else.  The runner with the highest cpu
180141177Smarc  *	   utilization is picked (p_cpu).  Ties are
180241177Smarc  *	   broken by picking the highest pid.
180341177Smarc  *	3  Next, the sleeper with the shortest sleep
180441177Smarc  *	   time is favored.  With ties, we pick out
180541177Smarc  *	   just "short-term" sleepers (SSINTR == 0).
180641177Smarc  *	   Further ties are broken by picking the highest
180741177Smarc  *	   pid.
180841177Smarc  *
180941177Smarc  */
181041177Smarc #define isrun(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
181145723Smckusick #define TESTAB(a, b)    ((a)<<1 | (b))
181245723Smckusick #define ONLYA   2
181345723Smckusick #define ONLYB   1
181445723Smckusick #define BOTH    3
181545723Smckusick 
181649907Sbostic static int
181741177Smarc proc_compare(p1, p2)
181841177Smarc 	register struct proc *p1, *p2;
181941177Smarc {
182041177Smarc 
182141177Smarc 	if (p1 == NULL)
182241177Smarc 		return (1);
182341177Smarc 	/*
182441177Smarc 	 * see if at least one of them is runnable
182541177Smarc 	 */
182645723Smckusick 	switch (TESTAB(isrun(p1), isrun(p2))) {
182745723Smckusick 	case ONLYA:
182845723Smckusick 		return (0);
182945723Smckusick 	case ONLYB:
183041177Smarc 		return (1);
183145723Smckusick 	case BOTH:
183241177Smarc 		/*
183341177Smarc 		 * tie - favor one with highest recent cpu utilization
183441177Smarc 		 */
183541177Smarc 		if (p2->p_cpu > p1->p_cpu)
183641177Smarc 			return (1);
183741177Smarc 		if (p1->p_cpu > p2->p_cpu)
183841177Smarc 			return (0);
183941177Smarc 		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */
184041177Smarc 	}
184145723Smckusick 	/*
184245723Smckusick  	 * weed out zombies
184345723Smckusick 	 */
184445723Smckusick 	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
184545723Smckusick 	case ONLYA:
184645723Smckusick 		return (1);
184745723Smckusick 	case ONLYB:
184845723Smckusick 		return (0);
184945723Smckusick 	case BOTH:
185045723Smckusick 		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
185145723Smckusick 	}
185241177Smarc 	/*
185341177Smarc 	 * pick the one with the smallest sleep time
185441177Smarc 	 */
185541177Smarc 	if (p2->p_slptime > p1->p_slptime)
185641177Smarc 		return (0);
185741177Smarc 	if (p1->p_slptime > p2->p_slptime)
185841177Smarc 		return (1);
185941177Smarc 	/*
186041177Smarc 	 * favor one sleeping in a non-interruptible sleep
186141177Smarc 	 */
186241177Smarc 	if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0)
186341177Smarc 		return (1);
186441177Smarc 	if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0)
186541177Smarc 		return (0);
186647545Skarels 	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */
186741177Smarc }
186845723Smckusick 
186939555Smarc /*
187039555Smarc  * Output char to tty; console putchar style.
187139555Smarc  */
187239555Smarc tputchar(c, tp)
187339555Smarc 	int c;
187439555Smarc 	struct tty *tp;
187539555Smarc {
187639555Smarc 	register s = spltty();
187739555Smarc 
187847545Skarels 	if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
187939555Smarc 		if (c == '\n')
188039555Smarc 			(void) ttyoutput('\r', tp);
188139555Smarc 		(void) ttyoutput(c, tp);
188239555Smarc 		ttstart(tp);
188339555Smarc 		splx(s);
188439555Smarc 		return (0);
188539555Smarc 	}
188639555Smarc 	splx(s);
188739555Smarc 	return (-1);
188839555Smarc }
188943377Smarc 
189044419Smarc /*
189149380Skarels  * Sleep on chan, returning ERESTART if tty changed
189249380Skarels  * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT)
189349380Skarels  * reported by tsleep.  If the tty is revoked, restarting a pending
189449380Skarels  * call will redo validation done at the start of the call.
189544419Smarc  */
189643377Smarc ttysleep(tp, chan, pri, wmesg, timo)
189743377Smarc 	struct tty *tp;
189843377Smarc 	caddr_t chan;
189943377Smarc 	int pri;
190043377Smarc 	char *wmesg;
190143377Smarc 	int timo;
190243377Smarc {
190343377Smarc 	int error;
190443377Smarc 	short gen = tp->t_gen;
190543377Smarc 
190643377Smarc 	if (error = tsleep(chan, pri, wmesg, timo))
190743377Smarc 		return (error);
190843377Smarc 	if (tp->t_gen != gen)
190943377Smarc 		return (ERESTART);
191043377Smarc 	return (0);
191143377Smarc }
1912