149594Sbostic /*-
263178Sbostic * Copyright (c) 1982, 1986, 1990, 1991, 1993
363178Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923387Smckusick *
1049594Sbostic * %sccs.include.redist.c%
1149594Sbostic *
12*68171Scgd * @(#)tty.c 8.13 (Berkeley) 01/09/95
1323387Smckusick */
1439Sbill
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/ioctl.h>
1856517Sbostic #include <sys/proc.h>
1964416Sbostic #define TTYDEFCHARS
2056517Sbostic #include <sys/tty.h>
2164416Sbostic #undef TTYDEFCHARS
2256517Sbostic #include <sys/file.h>
2356517Sbostic #include <sys/conf.h>
2456517Sbostic #include <sys/dkstat.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/kernel.h>
2756517Sbostic #include <sys/vnode.h>
2856517Sbostic #include <sys/syslog.h>
2939Sbill
3056517Sbostic #include <vm/vm.h>
3137525Smckusick
3264416Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2));
3364416Sbostic static int ttnread __P((struct tty *));
3464416Sbostic static void ttyblock __P((struct tty *tp));
3564416Sbostic static void ttyecho __P((int, struct tty *tp));
3664416Sbostic static void ttyrubo __P((struct tty *, int));
3749907Sbostic
3864416Sbostic /* Symbolic sleep message strings. */
3964416Sbostic char ttclos[] = "ttycls";
4064416Sbostic char ttopen[] = "ttyopn";
4164416Sbostic char ttybg[] = "ttybg";
4264416Sbostic char ttybuf[] = "ttybuf";
4364416Sbostic char ttyin[] = "ttyin";
4464416Sbostic char ttyout[] = "ttyout";
4540712Skarels
467436Skre /*
4764416Sbostic * Table with character classes and parity. The 8th bit indicates parity,
4864416Sbostic * the 7th bit indicates the character is an alphameric or underscore (for
4964416Sbostic * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits
5064416Sbostic * are 0 then the character needs no special processing on output; classes
5164416Sbostic * other than 0 might be translated or (not currently) require delays.
527436Skre */
5364416Sbostic #define E 0x00 /* Even parity. */
5464416Sbostic #define O 0x80 /* Odd parity. */
5564416Sbostic #define PARITY(c) (char_type[c] & O)
5664416Sbostic
5764416Sbostic #define ALPHA 0x40 /* Alpha or underscore. */
5864416Sbostic #define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA)
5964416Sbostic
6049380Skarels #define CCLASSMASK 0x3f
6164416Sbostic #define CCLASS(c) (char_type[c] & CCLASSMASK)
6239Sbill
6364416Sbostic #define BS BACKSPACE
6449380Skarels #define CC CONTROL
6564416Sbostic #define CR RETURN
6664416Sbostic #define NA ORDINARY | ALPHA
6749380Skarels #define NL NEWLINE
6864416Sbostic #define NO ORDINARY
6949380Skarels #define TB TAB
7049380Skarels #define VT VTAB
7149380Skarels
7264416Sbostic char const char_type[] = {
7349380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */
7449380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */
7549380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */
7649380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */
7749380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */
7849380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */
7949380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */
8049380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */
8149380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */
8249380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */
8349380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */
8449380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */
8549380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */
8649380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */
8749380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */
8849380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */
897436Skre /*
9064416Sbostic * Meta chars; should be settable per character set;
9164416Sbostic * for now, treat them all as normal characters.
927436Skre */
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,
10349380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
10449380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
10549380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
10649380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
10749380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
10849380Skarels NA, NA, NA, NA, NA, NA, NA, NA,
1097436Skre };
11064416Sbostic #undef BS
11164416Sbostic #undef CC
11264416Sbostic #undef CR
11349380Skarels #undef NA
11449380Skarels #undef NL
11564416Sbostic #undef NO
11649380Skarels #undef TB
11749380Skarels #undef VT
1187436Skre
11964416Sbostic /* Macros to clear/set/test flags. */
12064416Sbostic #define SET(t, f) (t) |= (f)
12164416Sbostic #define CLR(t, f) (t) &= ~(f)
12264416Sbostic #define ISSET(t, f) ((t) & (f))
12335811Smarc
124146Sbill /*
12564416Sbostic * Initial open of tty, or (re)entry to standard tty line discipline.
12639Sbill */
12764416Sbostic int
ttyopen(device,tp)12864416Sbostic ttyopen(device, tp)
12964416Sbostic dev_t device;
13012752Ssam register struct tty *tp;
13112752Ssam {
13252485Storek int s;
13347545Skarels
13452485Storek s = spltty();
13564416Sbostic tp->t_dev = device;
13664416Sbostic if (!ISSET(tp->t_state, TS_ISOPEN)) {
13764416Sbostic SET(tp->t_state, TS_ISOPEN);
13864416Sbostic bzero(&tp->t_winsize, sizeof(tp->t_winsize));
139903Sbill }
14064416Sbostic CLR(tp->t_state, TS_WOPEN);
1415408Swnj splx(s);
1425408Swnj return (0);
1434484Swnj }
1447436Skre
1457502Sroot /*
14649380Skarels * Handle close() on a tty line: flush and set to initial state,
14749380Skarels * bumping generation number so that pending read/write calls
14849380Skarels * can detect recycling of the tty.
1497502Sroot */
15064416Sbostic int
ttyclose(tp)1517502Sroot ttyclose(tp)
1527625Ssam register struct tty *tp;
1537502Sroot {
15464416Sbostic extern struct tty *constty; /* Temporary virtual console. */
15564416Sbostic
15630534Skarels if (constty == tp)
15730534Skarels constty = NULL;
15864416Sbostic
15964416Sbostic ttyflush(tp, FREAD | FWRITE);
16064416Sbostic
16164416Sbostic tp->t_gen++;
16264416Sbostic tp->t_pgrp = NULL;
16339555Smarc tp->t_session = NULL;
1647502Sroot tp->t_state = 0;
16540712Skarels return (0);
1667502Sroot }
1677502Sroot
16864416Sbostic #define FLUSHQ(q) { \
16964416Sbostic if ((q)->c_cc) \
17064416Sbostic ndflush(q, (q)->c_cc); \
17125391Skarels }
17225391Skarels
17364416Sbostic /* Is 'c' a line delimiter ("break" character)? */
17464416Sbostic #define TTBREAKC(c) \
17564416Sbostic ((c) == '\n' || ((c) == cc[VEOF] || \
17664416Sbostic (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
17725404Skarels
1787502Sroot
1797502Sroot /*
18049380Skarels * Process input of a single character received on a tty.
1817502Sroot */
18264416Sbostic int
ttyinput(c,tp)1837502Sroot ttyinput(c, tp)
18464416Sbostic register int c;
1857625Ssam register struct tty *tp;
1867502Sroot {
18764416Sbostic register int iflag, lflag;
18864416Sbostic register u_char *cc;
18935811Smarc int i, err;
1907502Sroot
1919578Ssam /*
1929578Ssam * If input is pending take it first.
1939578Ssam */
19464416Sbostic lflag = tp->t_lflag;
19564416Sbostic if (ISSET(lflag, PENDIN))
1967502Sroot ttypend(tp);
19735811Smarc /*
19835811Smarc * Gather stats.
19935811Smarc */
20064416Sbostic if (ISSET(lflag, ICANON)) {
20164416Sbostic ++tk_cancc;
20264416Sbostic ++tp->t_cancc;
20335811Smarc } else {
20464416Sbostic ++tk_rawcc;
20564416Sbostic ++tp->t_rawcc;
20635811Smarc }
20764416Sbostic ++tk_nin;
20864416Sbostic
20964416Sbostic /* Handle exceptional conditions (break, parity, framing). */
21064416Sbostic cc = tp->t_cc;
21164416Sbostic iflag = tp->t_iflag;
21264576Sbostic if (err = (ISSET(c, TTY_ERRORMASK))) {
21364576Sbostic CLR(c, TTY_ERRORMASK);
21464576Sbostic if (ISSET(err, TTY_FE) && !c) { /* Break. */
21564416Sbostic if (ISSET(iflag, IGNBRK))
21635811Smarc goto endcase;
21764416Sbostic else if (ISSET(iflag, BRKINT) &&
21864416Sbostic ISSET(lflag, ISIG) &&
21964416Sbostic (cc[VINTR] != _POSIX_VDISABLE))
22035811Smarc c = cc[VINTR];
22164416Sbostic else if (ISSET(iflag, PARMRK))
22247545Skarels goto parmrk;
22364576Sbostic } else if (ISSET(err, TTY_PE) &&
22464576Sbostic ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) {
22564416Sbostic if (ISSET(iflag, IGNPAR))
22635811Smarc goto endcase;
22764416Sbostic else if (ISSET(iflag, PARMRK)) {
22864576Sbostic parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
22964576Sbostic (void)putc(0 | TTY_QUOTE, &tp->t_rawq);
23064576Sbostic (void)putc(c | TTY_QUOTE, &tp->t_rawq);
23135811Smarc goto endcase;
23235811Smarc } else
23335811Smarc c = 0;
2347502Sroot }
2359578Ssam }
2369578Ssam /*
23735811Smarc * In tandem mode, check high water mark.
2389578Ssam */
23964416Sbostic if (ISSET(iflag, IXOFF))
24035811Smarc ttyblock(tp);
24164416Sbostic if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP))
24264576Sbostic CLR(c, 0x80);
24364416Sbostic if (!ISSET(lflag, EXTPROC)) {
24444419Smarc /*
24544419Smarc * Check for literal nexting very first
24644419Smarc */
24764416Sbostic if (ISSET(tp->t_state, TS_LNCH)) {
24864576Sbostic SET(c, TTY_QUOTE);
24964416Sbostic CLR(tp->t_state, TS_LNCH);
25044419Smarc }
25144419Smarc /*
25244419Smarc * Scan for special characters. This code
25344419Smarc * is really just a big case statement with
25444419Smarc * non-constant cases. The bottom of the
25544419Smarc * case statement is labeled ``endcase'', so goto
25644419Smarc * it after a case match, or similar.
25744419Smarc */
25844419Smarc
25944419Smarc /*
26044419Smarc * Control chars which aren't controlled
26144419Smarc * by ICANON, ISIG, or IXON.
26244419Smarc */
26364416Sbostic if (ISSET(lflag, IEXTEN)) {
26444419Smarc if (CCEQ(cc[VLNEXT], c)) {
26564416Sbostic if (ISSET(lflag, ECHO)) {
26664416Sbostic if (ISSET(lflag, ECHOE)) {
26764416Sbostic (void)ttyoutput('^', tp);
26864416Sbostic (void)ttyoutput('\b', tp);
26964416Sbostic } else
27044419Smarc ttyecho(c, tp);
27144419Smarc }
27264416Sbostic SET(tp->t_state, TS_LNCH);
27344419Smarc goto endcase;
27444419Smarc }
27544419Smarc if (CCEQ(cc[VDISCARD], c)) {
27664416Sbostic if (ISSET(lflag, FLUSHO))
27764416Sbostic CLR(tp->t_lflag, FLUSHO);
27844419Smarc else {
27944419Smarc ttyflush(tp, FWRITE);
28035811Smarc ttyecho(c, tp);
28144419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc)
28244419Smarc ttyretype(tp);
28364416Sbostic SET(tp->t_lflag, FLUSHO);
28444419Smarc }
28544419Smarc goto startoutput;
28635811Smarc }
2879578Ssam }
28844419Smarc /*
28944419Smarc * Signals.
29044419Smarc */
29164416Sbostic if (ISSET(lflag, ISIG)) {
29244419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) {
29364416Sbostic if (!ISSET(lflag, NOFLSH))
29464416Sbostic ttyflush(tp, FREAD | FWRITE);
2957502Sroot ttyecho(c, tp);
29644419Smarc pgsignal(tp->t_pgrp,
29744419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1);
29844419Smarc goto endcase;
2997502Sroot }
30044419Smarc if (CCEQ(cc[VSUSP], c)) {
30164416Sbostic if (!ISSET(lflag, NOFLSH))
30244419Smarc ttyflush(tp, FREAD);
30344419Smarc ttyecho(c, tp);
30444419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1);
30544419Smarc goto endcase;
30644419Smarc }
3079578Ssam }
30844419Smarc /*
30944419Smarc * Handle start/stop characters.
31044419Smarc */
31164416Sbostic if (ISSET(iflag, IXON)) {
31244419Smarc if (CCEQ(cc[VSTOP], c)) {
31364416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) {
31464416Sbostic SET(tp->t_state, TS_TTSTOP);
31552485Storek #ifdef sun4c /* XXX */
31652485Storek (*tp->t_stop)(tp, 0);
31752485Storek #else
31844419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp,
31944419Smarc 0);
32052485Storek #endif
32164416Sbostic return (0);
32244419Smarc }
32344419Smarc if (!CCEQ(cc[VSTART], c))
32464416Sbostic return (0);
32564416Sbostic /*
32664416Sbostic * if VSTART == VSTOP then toggle
32744419Smarc */
32844419Smarc goto endcase;
32935811Smarc }
33044419Smarc if (CCEQ(cc[VSTART], c))
33144419Smarc goto restartoutput;
3329578Ssam }
33344419Smarc /*
33444419Smarc * IGNCR, ICRNL, & INLCR
33544419Smarc */
33644419Smarc if (c == '\r') {
33764416Sbostic if (ISSET(iflag, IGNCR))
33844419Smarc goto endcase;
33964416Sbostic else if (ISSET(iflag, ICRNL))
34044419Smarc c = '\n';
34164416Sbostic } else if (c == '\n' && ISSET(iflag, INLCR))
34244419Smarc c = '\r';
3439578Ssam }
34464416Sbostic if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) {
34544419Smarc /*
34644419Smarc * From here on down canonical mode character
34744419Smarc * processing takes place.
34844419Smarc */
34944419Smarc /*
35044419Smarc * erase (^H / ^?)
35144419Smarc */
35244419Smarc if (CCEQ(cc[VERASE], c)) {
35344419Smarc if (tp->t_rawq.c_cc)
3549578Ssam ttyrub(unputc(&tp->t_rawq), tp);
35544419Smarc goto endcase;
3569578Ssam }
35744419Smarc /*
35844419Smarc * kill (^U)
35944419Smarc */
36044419Smarc if (CCEQ(cc[VKILL], c)) {
36164416Sbostic if (ISSET(lflag, ECHOKE) &&
36264416Sbostic tp->t_rawq.c_cc == tp->t_rocount &&
36364416Sbostic !ISSET(lflag, ECHOPRT))
36444419Smarc while (tp->t_rawq.c_cc)
36544419Smarc ttyrub(unputc(&tp->t_rawq), tp);
36664416Sbostic else {
36744419Smarc ttyecho(c, tp);
36864416Sbostic if (ISSET(lflag, ECHOK) ||
36964416Sbostic ISSET(lflag, ECHOKE))
37044419Smarc ttyecho('\n', tp);
37164416Sbostic FLUSHQ(&tp->t_rawq);
37244419Smarc tp->t_rocount = 0;
37344419Smarc }
37464416Sbostic CLR(tp->t_state, TS_LOCAL);
37544419Smarc goto endcase;
37644419Smarc }
37744419Smarc /*
37844419Smarc * word erase (^W)
37944419Smarc */
38064416Sbostic if (CCEQ(cc[VWERASE], c)) {
38164416Sbostic int alt = ISSET(lflag, ALTWERASE);
38244419Smarc int ctype;
38335811Smarc
38464416Sbostic /*
38564416Sbostic * erase whitespace
38644419Smarc */
38744419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t')
38844419Smarc ttyrub(c, tp);
38944419Smarc if (c == -1)
39044419Smarc goto endcase;
39144419Smarc /*
39247545Skarels * erase last char of word and remember the
39347545Skarels * next chars type (for ALTWERASE)
39444419Smarc */
39535811Smarc ttyrub(c, tp);
39644419Smarc c = unputc(&tp->t_rawq);
39747545Skarels if (c == -1)
39844419Smarc goto endcase;
39951003Sbostic if (c == ' ' || c == '\t') {
40064576Sbostic (void)putc(c, &tp->t_rawq);
40151003Sbostic goto endcase;
40251003Sbostic }
40349380Skarels ctype = ISALPHA(c);
40444419Smarc /*
40547545Skarels * erase rest of word
40644419Smarc */
40744419Smarc do {
40844419Smarc ttyrub(c, tp);
40944419Smarc c = unputc(&tp->t_rawq);
41044419Smarc if (c == -1)
41144419Smarc goto endcase;
41264416Sbostic } while (c != ' ' && c != '\t' &&
41364416Sbostic (alt == 0 || ISALPHA(c) == ctype));
41464416Sbostic (void)putc(c, &tp->t_rawq);
41534492Skarels goto endcase;
41644419Smarc }
41735811Smarc /*
41844419Smarc * reprint line (^R)
41935811Smarc */
42044419Smarc if (CCEQ(cc[VREPRINT], c)) {
42144419Smarc ttyretype(tp);
42234492Skarels goto endcase;
42334492Skarels }
42435811Smarc /*
42544419Smarc * ^T - kernel info and generate SIGINFO
42635811Smarc */
42744419Smarc if (CCEQ(cc[VSTATUS], c)) {
42864416Sbostic if (ISSET(lflag, ISIG))
42951068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1);
43064416Sbostic if (!ISSET(lflag, NOKERNINFO))
43144419Smarc ttyinfo(tp);
43244419Smarc goto endcase;
43344419Smarc }
4349578Ssam }
4359578Ssam /*
4369578Ssam * Check for input buffer overflow
4379578Ssam */
43847545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) {
43964416Sbostic if (ISSET(iflag, IMAXBEL)) {
44035811Smarc if (tp->t_outq.c_cc < tp->t_hiwat)
44164416Sbostic (void)ttyoutput(CTRL('g'), tp);
44235811Smarc } else
44335811Smarc ttyflush(tp, FREAD | FWRITE);
4449578Ssam goto endcase;
44510391Ssam }
4469578Ssam /*
4479578Ssam * Put data char in q for user and
4489578Ssam * wakeup on seeing a line delimiter.
4499578Ssam */
4509578Ssam if (putc(c, &tp->t_rawq) >= 0) {
45164416Sbostic if (!ISSET(lflag, ICANON)) {
45247545Skarels ttwakeup(tp);
45347545Skarels ttyecho(c, tp);
45447545Skarels goto endcase;
45547545Skarels }
45664416Sbostic if (TTBREAKC(c)) {
4579578Ssam tp->t_rocount = 0;
4589578Ssam catq(&tp->t_rawq, &tp->t_canq);
4597502Sroot ttwakeup(tp);
4609578Ssam } else if (tp->t_rocount++ == 0)
46164530Sbostic tp->t_rocol = tp->t_column;
46264416Sbostic if (ISSET(tp->t_state, TS_ERASE)) {
46335811Smarc /*
46435811Smarc * end of prterase \.../
46535811Smarc */
46664416Sbostic CLR(tp->t_state, TS_ERASE);
46764416Sbostic (void)ttyoutput('/', tp);
4689578Ssam }
46964530Sbostic i = tp->t_column;
4707502Sroot ttyecho(c, tp);
47164416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) {
47235811Smarc /*
47335811Smarc * Place the cursor over the '^' of the ^D.
47435811Smarc */
47564530Sbostic i = min(2, tp->t_column - i);
4769578Ssam while (i > 0) {
47764416Sbostic (void)ttyoutput('\b', tp);
4789578Ssam i--;
4799578Ssam }
4809578Ssam }
4817502Sroot }
4829578Ssam endcase:
4839578Ssam /*
48435811Smarc * IXANY means allow any character to restart output.
4859578Ssam */
48664416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) &&
48764416Sbostic !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP])
48864416Sbostic return (0);
4899578Ssam restartoutput:
49064416Sbostic CLR(tp->t_lflag, FLUSHO);
49164416Sbostic CLR(tp->t_state, TS_TTSTOP);
4929578Ssam startoutput:
49364416Sbostic return (ttstart(tp));
4947502Sroot }
4957502Sroot
4967502Sroot /*
49749380Skarels * Output a single character on a tty, doing output processing
49849380Skarels * as needed (expanding tabs, newline processing, etc.).
49964416Sbostic * Returns < 0 if succeeds, otherwise returns char to resend.
5007502Sroot * Must be recursive.
5017502Sroot */
50264416Sbostic int
ttyoutput(c,tp)5037502Sroot ttyoutput(c, tp)
50464416Sbostic register int c;
5057502Sroot register struct tty *tp;
5067502Sroot {
50764416Sbostic register long oflag;
50867115Smckusick register int notout, col, s;
50964416Sbostic
51064416Sbostic oflag = tp->t_oflag;
51164416Sbostic if (!ISSET(oflag, OPOST)) {
51264416Sbostic if (ISSET(tp->t_lflag, FLUSHO))
5137502Sroot return (-1);
5147502Sroot if (putc(c, &tp->t_outq))
5157625Ssam return (c);
5167502Sroot tk_nout++;
51735811Smarc tp->t_outcc++;
5187502Sroot return (-1);
5197502Sroot }
5207502Sroot /*
52164416Sbostic * Do tab expansion if OXTABS is set. Special case if we external
52264416Sbostic * processing, we don't do the tab expansion because we'll probably
52364416Sbostic * get it wrong. If tab expansion needs to be done, let it happen
52464416Sbostic * externally.
5257502Sroot */
52664576Sbostic CLR(c, ~TTY_CHARMASK);
52764416Sbostic if (c == '\t' &&
52864416Sbostic ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) {
52964530Sbostic c = 8 - (tp->t_column & 7);
53067115Smckusick if (ISSET(tp->t_lflag, FLUSHO)) {
53167115Smckusick notout = 0;
53267115Smckusick } else {
53364416Sbostic s = spltty(); /* Don't interrupt tabs. */
53467115Smckusick notout = b_to_q(" ", c, &tp->t_outq);
53567115Smckusick c -= notout;
5367502Sroot tk_nout += c;
53735811Smarc tp->t_outcc += c;
5387502Sroot splx(s);
5397502Sroot }
54064530Sbostic tp->t_column += c;
54167115Smckusick return (notout ? '\t' : -1);
5427502Sroot }
54364416Sbostic if (c == CEOT && ISSET(oflag, ONOEOT))
54447545Skarels return (-1);
54564576Sbostic
5467502Sroot /*
54749380Skarels * Newline translation: if ONLCR is set,
54849380Skarels * translate newline into "\r\n".
5497502Sroot */
55064576Sbostic if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
55164576Sbostic tk_nout++;
55264576Sbostic tp->t_outcc++;
55364576Sbostic if (putc('\r', &tp->t_outq))
55464576Sbostic return (c);
55564576Sbostic }
55664576Sbostic tk_nout++;
55764576Sbostic tp->t_outcc++;
55864416Sbostic if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
55935811Smarc return (c);
56047545Skarels
56164530Sbostic col = tp->t_column;
56249380Skarels switch (CCLASS(c)) {
5637502Sroot case BACKSPACE:
56449380Skarels if (col > 0)
56564416Sbostic --col;
5667502Sroot break;
56764416Sbostic case CONTROL:
56864416Sbostic break;
5697502Sroot case NEWLINE:
57064416Sbostic case RETURN:
57149380Skarels col = 0;
5727502Sroot break;
57364416Sbostic case ORDINARY:
57464416Sbostic ++col;
57564416Sbostic break;
5767502Sroot case TAB:
57764416Sbostic col = (col + 8) & ~7;
5787502Sroot break;
5797502Sroot }
58064530Sbostic tp->t_column = col;
5817502Sroot return (-1);
5827502Sroot }
5837502Sroot
5847502Sroot /*
58564576Sbostic * Ioctls for all tty devices. Called after line-discipline specific ioctl
58664576Sbostic * has been called to do discipline-specific functions and/or reject any
58764576Sbostic * of these ioctl commands.
58864416Sbostic */
58964416Sbostic /* ARGSUSED */
59064416Sbostic int
ttioctl(tp,cmd,data,flag)59164576Sbostic ttioctl(tp, cmd, data, flag)
59264416Sbostic register struct tty *tp;
593*68171Scgd u_long cmd;
59464416Sbostic void *data;
595*68171Scgd int flag;
59664416Sbostic {
59764416Sbostic extern struct tty *constty; /* Temporary virtual console. */
59864576Sbostic extern int nlinesw;
59964416Sbostic register struct proc *p;
60064416Sbostic int s, error;
60164416Sbostic
60264416Sbostic p = curproc; /* XXX */
60364416Sbostic
60464416Sbostic /* If the ioctl involves modification, hang if in the background. */
60564576Sbostic switch (cmd) {
60664416Sbostic case TIOCFLUSH:
60764416Sbostic case TIOCSETA:
60864416Sbostic case TIOCSETD:
60964416Sbostic case TIOCSETAF:
61064416Sbostic case TIOCSETAW:
61164416Sbostic #ifdef notdef
61264416Sbostic case TIOCSPGRP:
61364416Sbostic #endif
61464416Sbostic case TIOCSTI:
61564416Sbostic case TIOCSWINSZ:
61664416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
61764416Sbostic case TIOCLBIC:
61864416Sbostic case TIOCLBIS:
61964416Sbostic case TIOCLSET:
62064416Sbostic case TIOCSETC:
62164416Sbostic case OTIOCSETD:
62264416Sbostic case TIOCSETN:
62364416Sbostic case TIOCSETP:
62464416Sbostic case TIOCSLTC:
62564416Sbostic #endif
62664416Sbostic while (isbackground(curproc, tp) &&
62764576Sbostic p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 &&
62864416Sbostic (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
62964416Sbostic (p->p_sigmask & sigmask(SIGTTOU)) == 0) {
63064416Sbostic pgsignal(p->p_pgrp, SIGTTOU, 1);
63164416Sbostic if (error = ttysleep(tp,
63264416Sbostic &lbolt, TTOPRI | PCATCH, ttybg, 0))
63364416Sbostic return (error);
63464416Sbostic }
63564416Sbostic break;
63664416Sbostic }
63764416Sbostic
63864576Sbostic switch (cmd) { /* Process the ioctl. */
63964416Sbostic case FIOASYNC: /* set/clear async i/o */
64064416Sbostic s = spltty();
64164416Sbostic if (*(int *)data)
64264416Sbostic SET(tp->t_state, TS_ASYNC);
64364416Sbostic else
64464416Sbostic CLR(tp->t_state, TS_ASYNC);
64564416Sbostic splx(s);
64664416Sbostic break;
64764416Sbostic case FIONBIO: /* set/clear non-blocking i/o */
64864416Sbostic break; /* XXX: delete. */
64964416Sbostic case FIONREAD: /* get # bytes to read */
65064416Sbostic *(int *)data = ttnread(tp);
65164416Sbostic break;
65264416Sbostic case TIOCEXCL: /* set exclusive use of tty */
65364416Sbostic s = spltty();
65464416Sbostic SET(tp->t_state, TS_XCLUDE);
65564416Sbostic splx(s);
65664416Sbostic break;
65764416Sbostic case TIOCFLUSH: { /* flush buffers */
65864416Sbostic register int flags = *(int *)data;
65964416Sbostic
66064416Sbostic if (flags == 0)
66164416Sbostic flags = FREAD | FWRITE;
66264416Sbostic else
66364416Sbostic flags &= FREAD | FWRITE;
66464416Sbostic ttyflush(tp, flags);
66564416Sbostic break;
66664416Sbostic }
66764416Sbostic case TIOCCONS: /* become virtual console */
66864416Sbostic if (*(int *)data) {
66964416Sbostic if (constty && constty != tp &&
67064416Sbostic ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) ==
67164416Sbostic (TS_CARR_ON | TS_ISOPEN))
67264416Sbostic return (EBUSY);
67364416Sbostic #ifndef UCONSOLE
67464416Sbostic if (error = suser(p->p_ucred, &p->p_acflag))
67564416Sbostic return (error);
67664416Sbostic #endif
67764416Sbostic constty = tp;
67864416Sbostic } else if (tp == constty)
67964416Sbostic constty = NULL;
68064416Sbostic break;
68164416Sbostic case TIOCDRAIN: /* wait till output drained */
68264416Sbostic if (error = ttywait(tp))
68364416Sbostic return (error);
68464416Sbostic break;
68564416Sbostic case TIOCGETA: { /* get termios struct */
68664416Sbostic struct termios *t = (struct termios *)data;
68764416Sbostic
68864416Sbostic bcopy(&tp->t_termios, t, sizeof(struct termios));
68964416Sbostic break;
69064416Sbostic }
69164416Sbostic case TIOCGETD: /* get line discipline */
69264416Sbostic *(int *)data = tp->t_line;
69364416Sbostic break;
69464416Sbostic case TIOCGWINSZ: /* get window size */
69564416Sbostic *(struct winsize *)data = tp->t_winsize;
69664416Sbostic break;
69764416Sbostic case TIOCGPGRP: /* get pgrp of tty */
69864416Sbostic if (!isctty(p, tp))
69964416Sbostic return (ENOTTY);
70064416Sbostic *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
70164416Sbostic break;
70264416Sbostic #ifdef TIOCHPCL
70364416Sbostic case TIOCHPCL: /* hang up on last close */
70464416Sbostic s = spltty();
70564576Sbostic SET(tp->t_cflag, HUPCL);
70664416Sbostic splx(s);
70764416Sbostic break;
70864416Sbostic #endif
70964416Sbostic case TIOCNXCL: /* reset exclusive use of tty */
71064416Sbostic s = spltty();
71164416Sbostic CLR(tp->t_state, TS_XCLUDE);
71264416Sbostic splx(s);
71364416Sbostic break;
71464416Sbostic case TIOCOUTQ: /* output queue size */
71564416Sbostic *(int *)data = tp->t_outq.c_cc;
71664416Sbostic break;
71764416Sbostic case TIOCSETA: /* set termios struct */
71864416Sbostic case TIOCSETAW: /* drain output, set */
71964416Sbostic case TIOCSETAF: { /* drn out, fls in, set */
72064416Sbostic register struct termios *t = (struct termios *)data;
72164416Sbostic
72264416Sbostic s = spltty();
72364576Sbostic if (cmd == TIOCSETAW || cmd == TIOCSETAF) {
72464416Sbostic if (error = ttywait(tp)) {
72564416Sbostic splx(s);
72664416Sbostic return (error);
72764416Sbostic }
72864576Sbostic if (cmd == TIOCSETAF)
72964416Sbostic ttyflush(tp, FREAD);
73064416Sbostic }
73164416Sbostic if (!ISSET(t->c_cflag, CIGNORE)) {
73264416Sbostic /*
73364416Sbostic * Set device hardware.
73464416Sbostic */
73564416Sbostic if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
73664416Sbostic splx(s);
73764416Sbostic return (error);
73864416Sbostic } else {
73964416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) &&
74064416Sbostic ISSET(tp->t_cflag, CLOCAL) &&
74164416Sbostic !ISSET(t->c_cflag, CLOCAL)) {
74264416Sbostic CLR(tp->t_state, TS_ISOPEN);
74364416Sbostic SET(tp->t_state, TS_WOPEN);
74464416Sbostic ttwakeup(tp);
74564416Sbostic }
74664416Sbostic tp->t_cflag = t->c_cflag;
74764416Sbostic tp->t_ispeed = t->c_ispeed;
74864416Sbostic tp->t_ospeed = t->c_ospeed;
74964416Sbostic }
75064416Sbostic ttsetwater(tp);
75164416Sbostic }
75264576Sbostic if (cmd != TIOCSETAF) {
75364416Sbostic if (ISSET(t->c_lflag, ICANON) !=
75464416Sbostic ISSET(tp->t_lflag, ICANON))
75564416Sbostic if (ISSET(t->c_lflag, ICANON)) {
75664576Sbostic SET(tp->t_lflag, PENDIN);
75764416Sbostic ttwakeup(tp);
75864416Sbostic } else {
75964416Sbostic struct clist tq;
76064416Sbostic
76164416Sbostic catq(&tp->t_rawq, &tp->t_canq);
76264416Sbostic tq = tp->t_rawq;
76364416Sbostic tp->t_rawq = tp->t_canq;
76464416Sbostic tp->t_canq = tq;
76565324Sbostic CLR(tp->t_lflag, PENDIN);
76664416Sbostic }
76764416Sbostic }
76864416Sbostic tp->t_iflag = t->c_iflag;
76964416Sbostic tp->t_oflag = t->c_oflag;
77064416Sbostic /*
77164416Sbostic * Make the EXTPROC bit read only.
77264416Sbostic */
77364416Sbostic if (ISSET(tp->t_lflag, EXTPROC))
77464416Sbostic SET(t->c_lflag, EXTPROC);
77564416Sbostic else
77664416Sbostic CLR(t->c_lflag, EXTPROC);
77765324Sbostic tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN);
77864416Sbostic bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
77964416Sbostic splx(s);
78064416Sbostic break;
78164416Sbostic }
78264416Sbostic case TIOCSETD: { /* set line discipline */
78364416Sbostic register int t = *(int *)data;
78464416Sbostic dev_t device = tp->t_dev;
78564416Sbostic
78664576Sbostic if ((u_int)t >= nlinesw)
78764416Sbostic return (ENXIO);
78864416Sbostic if (t != tp->t_line) {
78964416Sbostic s = spltty();
79064416Sbostic (*linesw[tp->t_line].l_close)(tp, flag);
79164416Sbostic error = (*linesw[t].l_open)(device, tp);
79264416Sbostic if (error) {
79364416Sbostic (void)(*linesw[tp->t_line].l_open)(device, tp);
79464416Sbostic splx(s);
79564416Sbostic return (error);
79664416Sbostic }
79764416Sbostic tp->t_line = t;
79864416Sbostic splx(s);
79964416Sbostic }
80064416Sbostic break;
80164416Sbostic }
80264416Sbostic case TIOCSTART: /* start output, like ^Q */
80364416Sbostic s = spltty();
80464416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) ||
80564416Sbostic ISSET(tp->t_lflag, FLUSHO)) {
80664416Sbostic CLR(tp->t_lflag, FLUSHO);
80764416Sbostic CLR(tp->t_state, TS_TTSTOP);
80864416Sbostic ttstart(tp);
80964416Sbostic }
81064416Sbostic splx(s);
81164416Sbostic break;
81264416Sbostic case TIOCSTI: /* simulate terminal input */
81364416Sbostic if (p->p_ucred->cr_uid && (flag & FREAD) == 0)
81464416Sbostic return (EPERM);
81564416Sbostic if (p->p_ucred->cr_uid && !isctty(p, tp))
81664416Sbostic return (EACCES);
81764416Sbostic (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
81864416Sbostic break;
81964416Sbostic case TIOCSTOP: /* stop output, like ^S */
82064416Sbostic s = spltty();
82164416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) {
82264416Sbostic SET(tp->t_state, TS_TTSTOP);
82364416Sbostic #ifdef sun4c /* XXX */
82464416Sbostic (*tp->t_stop)(tp, 0);
82564416Sbostic #else
82664416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
82764416Sbostic #endif
82864416Sbostic }
82964416Sbostic splx(s);
83064416Sbostic break;
83164416Sbostic case TIOCSCTTY: /* become controlling tty */
83264416Sbostic /* Session ctty vnode pointer set in vnode layer. */
83364416Sbostic if (!SESS_LEADER(p) ||
83467685Smckusick (p->p_session->s_ttyvp || tp->t_session) &&
83567685Smckusick (tp->t_session != p->p_session))
83664416Sbostic return (EPERM);
83764416Sbostic tp->t_session = p->p_session;
83864416Sbostic tp->t_pgrp = p->p_pgrp;
83964416Sbostic p->p_session->s_ttyp = tp;
84064576Sbostic p->p_flag |= P_CONTROLT;
84164416Sbostic break;
84264416Sbostic case TIOCSPGRP: { /* set pgrp of tty */
84364416Sbostic register struct pgrp *pgrp = pgfind(*(int *)data);
84464416Sbostic
84564416Sbostic if (!isctty(p, tp))
84664416Sbostic return (ENOTTY);
84764416Sbostic else if (pgrp == NULL || pgrp->pg_session != p->p_session)
84864416Sbostic return (EPERM);
84964416Sbostic tp->t_pgrp = pgrp;
85064416Sbostic break;
85164416Sbostic }
85264416Sbostic case TIOCSWINSZ: /* set window size */
85364416Sbostic if (bcmp((caddr_t)&tp->t_winsize, data,
85464416Sbostic sizeof (struct winsize))) {
85564416Sbostic tp->t_winsize = *(struct winsize *)data;
85664416Sbostic pgsignal(tp->t_pgrp, SIGWINCH, 1);
85764416Sbostic }
85864416Sbostic break;
85964416Sbostic default:
86064416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
86164576Sbostic return (ttcompat(tp, cmd, data, flag));
86264416Sbostic #else
86364416Sbostic return (-1);
86464416Sbostic #endif
86564416Sbostic }
86664416Sbostic return (0);
86764416Sbostic }
86864416Sbostic
86964416Sbostic int
ttselect(device,rw,p)87064416Sbostic ttselect(device, rw, p)
87164416Sbostic dev_t device;
87264416Sbostic int rw;
87364416Sbostic struct proc *p;
87464416Sbostic {
87564416Sbostic register struct tty *tp;
87664416Sbostic int nread, s;
87764416Sbostic
87864416Sbostic tp = &cdevsw[major(device)].d_ttys[minor(device)];
87964416Sbostic
88064416Sbostic s = spltty();
88164416Sbostic switch (rw) {
88264416Sbostic case FREAD:
88364416Sbostic nread = ttnread(tp);
88464416Sbostic if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) &&
88564416Sbostic !ISSET(tp->t_state, TS_CARR_ON))
88664416Sbostic goto win;
88764416Sbostic selrecord(p, &tp->t_rsel);
88864416Sbostic break;
88964416Sbostic case FWRITE:
89064416Sbostic if (tp->t_outq.c_cc <= tp->t_lowat) {
89164416Sbostic win: splx(s);
89264416Sbostic return (1);
89364416Sbostic }
89464416Sbostic selrecord(p, &tp->t_wsel);
89564416Sbostic break;
89664416Sbostic }
89764416Sbostic splx(s);
89864416Sbostic return (0);
89964416Sbostic }
90064416Sbostic
90164416Sbostic static int
ttnread(tp)90264416Sbostic ttnread(tp)
90364416Sbostic struct tty *tp;
90464416Sbostic {
90564416Sbostic int nread;
90664416Sbostic
90764416Sbostic if (ISSET(tp->t_lflag, PENDIN))
90864416Sbostic ttypend(tp);
90964416Sbostic nread = tp->t_canq.c_cc;
91064416Sbostic if (!ISSET(tp->t_lflag, ICANON))
91164416Sbostic nread += tp->t_rawq.c_cc;
91264416Sbostic return (nread);
91364416Sbostic }
91464416Sbostic
91564416Sbostic /*
91664416Sbostic * Wait for output to drain.
91764416Sbostic */
91864416Sbostic int
ttywait(tp)91964416Sbostic ttywait(tp)
92064416Sbostic register struct tty *tp;
92164416Sbostic {
92264416Sbostic int error, s;
92364416Sbostic
92464416Sbostic error = 0;
92564416Sbostic s = spltty();
92664416Sbostic while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
92764416Sbostic (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
92864416Sbostic && tp->t_oproc) {
92964416Sbostic (*tp->t_oproc)(tp);
93064416Sbostic SET(tp->t_state, TS_ASLEEP);
93164416Sbostic if (error = ttysleep(tp,
93264416Sbostic &tp->t_outq, TTOPRI | PCATCH, ttyout, 0))
93364416Sbostic break;
93464416Sbostic }
93564416Sbostic splx(s);
93664416Sbostic return (error);
93764416Sbostic }
93864416Sbostic
93964416Sbostic /*
94064416Sbostic * Flush if successfully wait.
94164416Sbostic */
94264416Sbostic int
ttywflush(tp)94364416Sbostic ttywflush(tp)
94464416Sbostic struct tty *tp;
94564416Sbostic {
94664416Sbostic int error;
94764416Sbostic
94864416Sbostic if ((error = ttywait(tp)) == 0)
94964416Sbostic ttyflush(tp, FREAD);
95064416Sbostic return (error);
95164416Sbostic }
95264416Sbostic
95364416Sbostic /*
95464416Sbostic * Flush tty read and/or write queues, notifying anyone waiting.
95564416Sbostic */
95664416Sbostic void
ttyflush(tp,rw)95764416Sbostic ttyflush(tp, rw)
95864416Sbostic register struct tty *tp;
95964416Sbostic int rw;
96064416Sbostic {
96164416Sbostic register int s;
96264416Sbostic
96364416Sbostic s = spltty();
96464416Sbostic if (rw & FREAD) {
96564416Sbostic FLUSHQ(&tp->t_canq);
96664416Sbostic FLUSHQ(&tp->t_rawq);
96764416Sbostic tp->t_rocount = 0;
96864416Sbostic tp->t_rocol = 0;
96964416Sbostic CLR(tp->t_state, TS_LOCAL);
97064416Sbostic ttwakeup(tp);
97164416Sbostic }
97264416Sbostic if (rw & FWRITE) {
97364416Sbostic CLR(tp->t_state, TS_TTSTOP);
97464416Sbostic #ifdef sun4c /* XXX */
97564416Sbostic (*tp->t_stop)(tp, rw);
97664416Sbostic #else
97764416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
97864416Sbostic #endif
97964416Sbostic FLUSHQ(&tp->t_outq);
98064416Sbostic wakeup((caddr_t)&tp->t_outq);
98164416Sbostic selwakeup(&tp->t_wsel);
98264416Sbostic }
98364416Sbostic splx(s);
98464416Sbostic }
98564416Sbostic
98664416Sbostic /*
98764416Sbostic * Copy in the default termios characters.
98864416Sbostic */
98964416Sbostic void
ttychars(tp)99064416Sbostic ttychars(tp)
99164416Sbostic struct tty *tp;
99264416Sbostic {
99364416Sbostic
99464416Sbostic bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
99564416Sbostic }
99664416Sbostic
99764416Sbostic /*
99864416Sbostic * Send stop character on input overflow.
99964416Sbostic */
100064416Sbostic static void
ttyblock(tp)100164416Sbostic ttyblock(tp)
100264416Sbostic register struct tty *tp;
100364416Sbostic {
100464416Sbostic register int total;
100564416Sbostic
100664416Sbostic total = tp->t_rawq.c_cc + tp->t_canq.c_cc;
100764416Sbostic if (tp->t_rawq.c_cc > TTYHOG) {
100864416Sbostic ttyflush(tp, FREAD | FWRITE);
100964416Sbostic CLR(tp->t_state, TS_TBLOCK);
101064416Sbostic }
101164416Sbostic /*
101264416Sbostic * Block further input iff: current input > threshold
101364416Sbostic * AND input is available to user program.
101464416Sbostic */
101564416Sbostic if (total >= TTYHOG / 2 &&
101664416Sbostic !ISSET(tp->t_state, TS_TBLOCK) &&
101764416Sbostic !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 &&
101864416Sbostic tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
101964416Sbostic if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) {
102064416Sbostic SET(tp->t_state, TS_TBLOCK);
102164416Sbostic ttstart(tp);
102264416Sbostic }
102364416Sbostic }
102464416Sbostic }
102564416Sbostic
102664416Sbostic void
ttrstrt(tp_arg)102764416Sbostic ttrstrt(tp_arg)
102864416Sbostic void *tp_arg;
102964416Sbostic {
103064416Sbostic struct tty *tp;
103164416Sbostic int s;
103264416Sbostic
103364416Sbostic #ifdef DIAGNOSTIC
103464416Sbostic if (tp_arg == NULL)
103564416Sbostic panic("ttrstrt");
103664416Sbostic #endif
103764416Sbostic tp = tp_arg;
103864416Sbostic s = spltty();
103964416Sbostic
104064416Sbostic CLR(tp->t_state, TS_TIMEOUT);
104164416Sbostic ttstart(tp);
104264416Sbostic
104364416Sbostic splx(s);
104464416Sbostic }
104564416Sbostic
104664416Sbostic int
ttstart(tp)104764416Sbostic ttstart(tp)
104864416Sbostic struct tty *tp;
104964416Sbostic {
105064416Sbostic
105164416Sbostic if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */
105264416Sbostic (*tp->t_oproc)(tp);
105364416Sbostic return (0);
105464416Sbostic }
105564416Sbostic
105664416Sbostic /*
105764416Sbostic * "close" a line discipline
105864416Sbostic */
105964416Sbostic int
ttylclose(tp,flag)106064416Sbostic ttylclose(tp, flag)
106164416Sbostic struct tty *tp;
106264416Sbostic int flag;
106364416Sbostic {
106464416Sbostic
106564416Sbostic if (flag & IO_NDELAY)
106664416Sbostic ttyflush(tp, FREAD | FWRITE);
106764416Sbostic else
106864416Sbostic ttywflush(tp);
106964416Sbostic return (0);
107064416Sbostic }
107164416Sbostic
107264416Sbostic /*
107364416Sbostic * Handle modem control transition on a tty.
107464416Sbostic * Flag indicates new state of carrier.
107564416Sbostic * Returns 0 if the line should be turned off, otherwise 1.
107664416Sbostic */
107764416Sbostic int
ttymodem(tp,flag)107864416Sbostic ttymodem(tp, flag)
107964416Sbostic register struct tty *tp;
108064416Sbostic int flag;
108164416Sbostic {
108264416Sbostic
108364416Sbostic if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) {
108464416Sbostic /*
108564416Sbostic * MDMBUF: do flow control according to carrier flag
108664416Sbostic */
108764416Sbostic if (flag) {
108864416Sbostic CLR(tp->t_state, TS_TTSTOP);
108964416Sbostic ttstart(tp);
109064416Sbostic } else if (!ISSET(tp->t_state, TS_TTSTOP)) {
109164416Sbostic SET(tp->t_state, TS_TTSTOP);
109264416Sbostic #ifdef sun4c /* XXX */
109364416Sbostic (*tp->t_stop)(tp, 0);
109464416Sbostic #else
109564416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0);
109664416Sbostic #endif
109764416Sbostic }
109864416Sbostic } else if (flag == 0) {
109964416Sbostic /*
110064416Sbostic * Lost carrier.
110164416Sbostic */
110264416Sbostic CLR(tp->t_state, TS_CARR_ON);
110364416Sbostic if (ISSET(tp->t_state, TS_ISOPEN) &&
110464416Sbostic !ISSET(tp->t_cflag, CLOCAL)) {
110564416Sbostic if (tp->t_session && tp->t_session->s_leader)
110664416Sbostic psignal(tp->t_session->s_leader, SIGHUP);
110764416Sbostic ttyflush(tp, FREAD | FWRITE);
110864416Sbostic return (0);
110964416Sbostic }
111064416Sbostic } else {
111164416Sbostic /*
111264416Sbostic * Carrier now on.
111364416Sbostic */
111464416Sbostic SET(tp->t_state, TS_CARR_ON);
111564416Sbostic ttwakeup(tp);
111664416Sbostic }
111764416Sbostic return (1);
111864416Sbostic }
111964416Sbostic
112064416Sbostic /*
112164416Sbostic * Default modem control routine (for other line disciplines).
112264416Sbostic * Return argument flag, to turn off device on carrier drop.
112364416Sbostic */
112464416Sbostic int
nullmodem(tp,flag)112564416Sbostic nullmodem(tp, flag)
112664416Sbostic register struct tty *tp;
112764416Sbostic int flag;
112864416Sbostic {
112964416Sbostic
113064416Sbostic if (flag)
113164416Sbostic SET(tp->t_state, TS_CARR_ON);
113264416Sbostic else {
113364416Sbostic CLR(tp->t_state, TS_CARR_ON);
113464416Sbostic if (!ISSET(tp->t_cflag, CLOCAL)) {
113564416Sbostic if (tp->t_session && tp->t_session->s_leader)
113664416Sbostic psignal(tp->t_session->s_leader, SIGHUP);
113764416Sbostic return (0);
113864416Sbostic }
113964416Sbostic }
114064416Sbostic return (1);
114164416Sbostic }
114264416Sbostic
114364416Sbostic /*
114464416Sbostic * Reinput pending characters after state switch
114564416Sbostic * call at spltty().
114664416Sbostic */
114764416Sbostic void
ttypend(tp)114864416Sbostic ttypend(tp)
114964416Sbostic register struct tty *tp;
115064416Sbostic {
115164416Sbostic struct clist tq;
115264416Sbostic register c;
115364416Sbostic
115464416Sbostic CLR(tp->t_lflag, PENDIN);
115564416Sbostic SET(tp->t_state, TS_TYPEN);
115664416Sbostic tq = tp->t_rawq;
115764416Sbostic tp->t_rawq.c_cc = 0;
115864416Sbostic tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0;
115964416Sbostic while ((c = getc(&tq)) >= 0)
116064416Sbostic ttyinput(c, tp);
116164416Sbostic CLR(tp->t_state, TS_TYPEN);
116264416Sbostic }
116364416Sbostic
116464416Sbostic /*
116549380Skarels * Process a read call on a tty device.
11667502Sroot */
116764416Sbostic int
ttread(tp,uio,flag)116837584Smarc ttread(tp, uio, flag)
11697625Ssam register struct tty *tp;
11707722Swnj struct uio *uio;
117152485Storek int flag;
11727502Sroot {
11737502Sroot register struct clist *qp;
117435811Smarc register int c;
117541383Smarc register long lflag;
117635811Smarc register u_char *cc = tp->t_cc;
117747545Skarels register struct proc *p = curproc;
11789859Ssam int s, first, error = 0;
11797502Sroot
118064416Sbostic loop: lflag = tp->t_lflag;
118137584Smarc s = spltty();
11829578Ssam /*
118364416Sbostic * take pending input first
11849578Ssam */
118564416Sbostic if (ISSET(lflag, PENDIN))
11867502Sroot ttypend(tp);
11879859Ssam splx(s);
118840712Skarels
11899578Ssam /*
11909578Ssam * Hang process if it's in the background.
11919578Ssam */
119247545Skarels if (isbackground(p, tp)) {
119347545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) ||
119447545Skarels (p->p_sigmask & sigmask(SIGTTIN)) ||
119564576Sbostic p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0)
11968520Sroot return (EIO);
119747545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1);
119864416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, 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 */
120964416Sbostic qp = ISSET(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
122064416Sbostic carrier = ISSET(tp->t_state, TS_CARR_ON) ||
122164416Sbostic ISSET(tp->t_cflag, CLOCAL);
122264416Sbostic if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {
12239859Ssam splx(s);
122440712Skarels return (0); /* EOF */
12257502Sroot }
122637728Smckusick if (flag & IO_NDELAY) {
122737584Smarc splx(s);
122837584Smarc return (EWOULDBLOCK);
122937584Smarc }
123064416Sbostic error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH,
123140712Skarels carrier ? ttyin : ttopen, 0);
12329859Ssam splx(s);
123343377Smarc if (error)
123440712Skarels return (error);
12359578Ssam goto loop;
12369578Ssam }
12379859Ssam splx(s);
123840712Skarels
12399578Ssam /*
124035811Smarc * Input present, check for input mapping and processing.
12419578Ssam */
12429578Ssam first = 1;
12439578Ssam while ((c = getc(qp)) >= 0) {
12449578Ssam /*
124535811Smarc * delayed suspend (^Y)
12469578Ssam */
124764416Sbostic if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) {
124842882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1);
12499578Ssam if (first) {
125064416Sbostic if (error = ttysleep(tp,
125164416Sbostic &lbolt, TTIPRI | PCATCH, ttybg, 0))
125240712Skarels break;
12539578Ssam goto loop;
12549578Ssam }
12559578Ssam break;
12567502Sroot }
12579578Ssam /*
125835811Smarc * Interpret EOF only in canonical mode.
12599578Ssam */
126064416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON))
12619578Ssam break;
12629578Ssam /*
12639578Ssam * Give user character.
12649578Ssam */
126540712Skarels error = ureadc(c, uio);
12669578Ssam if (error)
12679578Ssam break;
126814938Smckusick if (uio->uio_resid == 0)
12699578Ssam break;
12709578Ssam /*
127135811Smarc * In canonical mode check for a "break character"
12729578Ssam * marking the end of a "line of input".
12739578Ssam */
127464416Sbostic if (ISSET(lflag, ICANON) && TTBREAKC(c))
12759578Ssam break;
12769578Ssam first = 0;
12777502Sroot }
12789578Ssam /*
12799578Ssam * Look to unblock output now that (presumably)
12809578Ssam * the input queue has gone down.
12819578Ssam */
128252485Storek s = spltty();
128364416Sbostic if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
128447545Skarels if (cc[VSTART] != _POSIX_VDISABLE &&
128547545Skarels putc(cc[VSTART], &tp->t_outq) == 0) {
128664416Sbostic CLR(tp->t_state, TS_TBLOCK);
12877502Sroot ttstart(tp);
12887502Sroot }
128935811Smarc }
129052485Storek splx(s);
12918520Sroot return (error);
12927502Sroot }
12937502Sroot
12947502Sroot /*
129564416Sbostic * Check the output queue on tp for space for a kernel message (from uprintf
129664416Sbostic * or tprintf). Allow some space over the normal hiwater mark so we don't
129764416Sbostic * lose messages due to normal flow control, but don't let the tty run amok.
129864416Sbostic * Sleeps here are not interruptible, but we return prematurely if new signals
129964416Sbostic * arrive.
130025391Skarels */
130164416Sbostic int
ttycheckoutq(tp,wait)130225391Skarels ttycheckoutq(tp, wait)
130325391Skarels register struct tty *tp;
130425391Skarels int wait;
130525391Skarels {
130630695Skarels int hiwat, s, oldsig;
130725391Skarels
130835811Smarc hiwat = tp->t_hiwat;
130925391Skarels s = spltty();
131064576Sbostic oldsig = wait ? curproc->p_siglist : 0;
131125391Skarels if (tp->t_outq.c_cc > hiwat + 200)
131229946Skarels while (tp->t_outq.c_cc > hiwat) {
131329946Skarels ttstart(tp);
131464576Sbostic if (wait == 0 || curproc->p_siglist != oldsig) {
131529946Skarels splx(s);
131629946Skarels return (0);
131729946Skarels }
131854782Storek timeout((void (*)__P((void *)))wakeup,
131954782Storek (void *)&tp->t_outq, hz);
132064416Sbostic SET(tp->t_state, TS_ASLEEP);
132130695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1);
132225391Skarels }
132325391Skarels splx(s);
132425391Skarels return (1);
132525391Skarels }
132625391Skarels
132725391Skarels /*
132849380Skarels * Process a write call on a tty device.
13297502Sroot */
133064416Sbostic int
ttwrite(tp,uio,flag)133137584Smarc ttwrite(tp, uio, flag)
13327625Ssam register struct tty *tp;
13339578Ssam register struct uio *uio;
133452485Storek int flag;
13357502Sroot {
13367502Sroot register char *cp;
133764416Sbostic register int cc, ce;
133864416Sbostic register struct proc *p;
13399578Ssam int i, hiwat, cnt, error, s;
13407502Sroot char obuf[OBUFSIZ];
13417502Sroot
134235811Smarc hiwat = tp->t_hiwat;
13439578Ssam cnt = uio->uio_resid;
13449578Ssam error = 0;
134564878Smckusick cc = 0;
13467502Sroot loop:
134737584Smarc s = spltty();
134864416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) &&
134964416Sbostic !ISSET(tp->t_cflag, CLOCAL)) {
135064416Sbostic if (ISSET(tp->t_state, TS_ISOPEN)) {
135137584Smarc splx(s);
135237584Smarc return (EIO);
135337728Smckusick } else if (flag & IO_NDELAY) {
135437584Smarc splx(s);
135540712Skarels error = EWOULDBLOCK;
135640712Skarels goto out;
135737584Smarc } else {
135864416Sbostic /* Sleep awaiting carrier. */
135964416Sbostic error = ttysleep(tp,
136064416Sbostic &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);
136137584Smarc splx(s);
136243377Smarc if (error)
136340712Skarels goto out;
136437584Smarc goto loop;
136537584Smarc }
136637584Smarc }
136737584Smarc splx(s);
13689578Ssam /*
13699578Ssam * Hang the process if it's in the background.
13709578Ssam */
137164416Sbostic p = curproc;
137264416Sbostic if (isbackground(p, tp) &&
137364576Sbostic ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&
137447545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&
137547545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&
137647545Skarels p->p_pgrp->pg_jobc) {
137747545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1);
137864416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))
137940712Skarels goto out;
138021776Sbloom goto loop;
13817502Sroot }
13829578Ssam /*
138364416Sbostic * Process the user's data in at most OBUFSIZ chunks. Perform any
138464416Sbostic * output translation. Keep track of high water mark, sleep on
138564416Sbostic * overflow awaiting device aid in acquiring new space.
13869578Ssam */
138764878Smckusick while (uio->uio_resid > 0 || cc > 0) {
138864416Sbostic if (ISSET(tp->t_lflag, FLUSHO)) {
138940712Skarels uio->uio_resid = 0;
139040712Skarels return (0);
139140712Skarels }
139240712Skarels if (tp->t_outq.c_cc > hiwat)
139332067Skarels goto ovhiwat;
13949578Ssam /*
139564416Sbostic * Grab a hunk of data from the user, unless we have some
139664416Sbostic * leftover from last time.
13979578Ssam */
13987822Sroot if (cc == 0) {
139940712Skarels cc = min(uio->uio_resid, OBUFSIZ);
140040712Skarels cp = obuf;
140140712Skarels error = uiomove(cp, cc, uio);
140240712Skarels if (error) {
140340712Skarels cc = 0;
140440712Skarels break;
140540712Skarels }
14067822Sroot }
14079578Ssam /*
14089578Ssam * If nothing fancy need be done, grab those characters we
14099578Ssam * can handle without any of ttyoutput's processing and
14109578Ssam * just transfer them to the output q. For those chars
14119578Ssam * which require special processing (as indicated by the
141264416Sbostic * bits in char_type), call ttyoutput. After processing
14139578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect
14149578Ssam * immediately.
14159578Ssam */
14169578Ssam while (cc > 0) {
141764416Sbostic if (!ISSET(tp->t_oflag, OPOST))
14187502Sroot ce = cc;
14197502Sroot else {
142064416Sbostic ce = cc - scanc((u_int)cc, (u_char *)cp,
142164416Sbostic (u_char *)char_type, CCLASSMASK);
14229578Ssam /*
14239578Ssam * If ce is zero, then we're processing
14249578Ssam * a special character through ttyoutput.
14259578Ssam */
14269578Ssam if (ce == 0) {
14277502Sroot tp->t_rocount = 0;
14287502Sroot if (ttyoutput(*cp, tp) >= 0) {
142964416Sbostic /* No Clists, wait a bit. */
143064416Sbostic ttstart(tp);
143164416Sbostic if (error = ttysleep(tp, &lbolt,
143264416Sbostic TTOPRI | PCATCH, ttybuf, 0))
143364416Sbostic break;
143464416Sbostic goto loop;
14357502Sroot }
143664416Sbostic cp++;
143764416Sbostic cc--;
143864416Sbostic if (ISSET(tp->t_lflag, FLUSHO) ||
14399578Ssam tp->t_outq.c_cc > hiwat)
14407502Sroot goto ovhiwat;
14419578Ssam continue;
14427502Sroot }
14437502Sroot }
14449578Ssam /*
144564416Sbostic * A bunch of normal characters have been found.
144664416Sbostic * Transfer them en masse to the output queue and
14479578Ssam * continue processing at the top of the loop.
14489578Ssam * If there are any further characters in this
14499578Ssam * <= OBUFSIZ chunk, the first should be a character
14509578Ssam * requiring special handling by ttyoutput.
14519578Ssam */
14527502Sroot tp->t_rocount = 0;
14539578Ssam i = b_to_q(cp, ce, &tp->t_outq);
14549578Ssam ce -= i;
145564530Sbostic tp->t_column += ce;
14569578Ssam cp += ce, cc -= ce, tk_nout += ce;
145735811Smarc tp->t_outcc += ce;
14589578Ssam if (i > 0) {
145964416Sbostic /* No Clists, wait a bit. */
14607502Sroot ttstart(tp);
146164416Sbostic if (error = ttysleep(tp,
146264416Sbostic &lbolt, TTOPRI | PCATCH, ttybuf, 0))
146340712Skarels break;
146421776Sbloom goto loop;
14657502Sroot }
146664416Sbostic if (ISSET(tp->t_lflag, FLUSHO) ||
146764416Sbostic tp->t_outq.c_cc > hiwat)
146840712Skarels break;
14697502Sroot }
147035811Smarc ttstart(tp);
14717502Sroot }
147240712Skarels out:
147340712Skarels /*
147464416Sbostic * If cc is nonzero, we leave the uio structure inconsistent, as the
147564416Sbostic * offset and iov pointers have moved forward, but it doesn't matter
147664416Sbostic * (the call will either return short or restart with a new uio).
147740712Skarels */
147840712Skarels uio->uio_resid += cc;
14798520Sroot return (error);
148040712Skarels
14817502Sroot ovhiwat:
148232067Skarels ttstart(tp);
148332067Skarels s = spltty();
14849578Ssam /*
148535811Smarc * This can only occur if FLUSHO is set in t_lflag,
148632067Skarels * or if ttstart/oproc is synchronous (or very fast).
14879578Ssam */
14887502Sroot if (tp->t_outq.c_cc <= hiwat) {
14899578Ssam splx(s);
14907502Sroot goto loop;
14917502Sroot }
149237728Smckusick if (flag & IO_NDELAY) {
149317545Skarels splx(s);
149440712Skarels uio->uio_resid += cc;
149564416Sbostic return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
14967502Sroot }
149764416Sbostic SET(tp->t_state, TS_ASLEEP);
149864416Sbostic error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);
14999578Ssam splx(s);
150043377Smarc if (error)
150140712Skarels goto out;
15027502Sroot goto loop;
15037502Sroot }
15047502Sroot
15057502Sroot /*
15067502Sroot * Rubout one character from the rawq of tp
15077502Sroot * as cleanly as possible.
15087502Sroot */
150964416Sbostic void
ttyrub(c,tp)15107502Sroot ttyrub(c, tp)
151164416Sbostic register int c;
15127625Ssam register struct tty *tp;
15137502Sroot {
15147502Sroot register char *cp;
15157502Sroot register int savecol;
151664416Sbostic int tabc, s;
15177502Sroot
151864416Sbostic if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))
15197502Sroot return;
152064416Sbostic CLR(tp->t_lflag, FLUSHO);
152164416Sbostic if (ISSET(tp->t_lflag, ECHOE)) {
15227502Sroot if (tp->t_rocount == 0) {
15237502Sroot /*
15247502Sroot * Screwed by ttwrite; retype
15257502Sroot */
15267502Sroot ttyretype(tp);
15277502Sroot return;
15287502Sroot }
152964416Sbostic if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))
15307502Sroot ttyrubo(tp, 2);
153164576Sbostic else {
153264576Sbostic CLR(c, ~TTY_CHARMASK);
153364576Sbostic switch (CCLASS(c)) {
153464576Sbostic case ORDINARY:
153564576Sbostic ttyrubo(tp, 1);
153664576Sbostic break;
153764576Sbostic case BACKSPACE:
153864576Sbostic case CONTROL:
153964576Sbostic case NEWLINE:
154064576Sbostic case RETURN:
154164576Sbostic case VTAB:
154264576Sbostic if (ISSET(tp->t_lflag, ECHOCTL))
154364576Sbostic ttyrubo(tp, 2);
154464576Sbostic break;
154564576Sbostic case TAB:
154664576Sbostic if (tp->t_rocount < tp->t_rawq.c_cc) {
154764576Sbostic ttyretype(tp);
154864576Sbostic return;
154964576Sbostic }
155064576Sbostic s = spltty();
155164576Sbostic savecol = tp->t_column;
155264576Sbostic SET(tp->t_state, TS_CNTTB);
155364576Sbostic SET(tp->t_lflag, FLUSHO);
155464576Sbostic tp->t_column = tp->t_rocol;
155564576Sbostic cp = tp->t_rawq.c_cf;
155664576Sbostic if (cp)
155764576Sbostic tabc = *cp; /* XXX FIX NEXTC */
155864576Sbostic for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))
155964576Sbostic ttyecho(tabc, tp);
156064576Sbostic CLR(tp->t_lflag, FLUSHO);
156164576Sbostic CLR(tp->t_state, TS_CNTTB);
156264576Sbostic splx(s);
156364416Sbostic
156464576Sbostic /* savecol will now be length of the tab. */
156564576Sbostic savecol -= tp->t_column;
156664576Sbostic tp->t_column += savecol;
156764576Sbostic if (savecol > 8)
156864576Sbostic savecol = 8; /* overflow screw */
156964576Sbostic while (--savecol >= 0)
157064576Sbostic (void)ttyoutput('\b', tp);
157164576Sbostic break;
157264576Sbostic default: /* XXX */
157364416Sbostic #define PANICSTR "ttyrub: would panic c = %d, val = %d\n"
157464576Sbostic (void)printf(PANICSTR, c, CCLASS(c));
157564416Sbostic #ifdef notdef
157664576Sbostic panic(PANICSTR, c, CCLASS(c));
157764416Sbostic #endif
157864576Sbostic }
157935811Smarc }
158064416Sbostic } else if (ISSET(tp->t_lflag, ECHOPRT)) {
158164416Sbostic if (!ISSET(tp->t_state, TS_ERASE)) {
158264416Sbostic SET(tp->t_state, TS_ERASE);
158364416Sbostic (void)ttyoutput('\\', tp);
15847502Sroot }
15857502Sroot ttyecho(c, tp);
15867502Sroot } else
158735811Smarc ttyecho(tp->t_cc[VERASE], tp);
158864416Sbostic --tp->t_rocount;
15897502Sroot }
15907502Sroot
15917502Sroot /*
159264416Sbostic * Back over cnt characters, erasing them.
15937502Sroot */
159464416Sbostic static void
ttyrubo(tp,cnt)15957502Sroot ttyrubo(tp, cnt)
15967625Ssam register struct tty *tp;
15977625Ssam int cnt;
15987502Sroot {
15997502Sroot
160064416Sbostic while (cnt-- > 0) {
160164416Sbostic (void)ttyoutput('\b', tp);
160264416Sbostic (void)ttyoutput(' ', tp);
160364416Sbostic (void)ttyoutput('\b', tp);
160464416Sbostic }
16057502Sroot }
16067502Sroot
16077502Sroot /*
160864416Sbostic * ttyretype --
160964416Sbostic * Reprint the rawq line. Note, it is assumed that c_cc has already
161064416Sbostic * been checked.
16117502Sroot */
161264416Sbostic void
ttyretype(tp)16137502Sroot ttyretype(tp)
16147625Ssam register struct tty *tp;
16157502Sroot {
16167502Sroot register char *cp;
161735811Smarc int s, c;
16187502Sroot
161964416Sbostic /* Echo the reprint character. */
162035811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)
162135811Smarc ttyecho(tp->t_cc[VREPRINT], tp);
162264416Sbostic
162364416Sbostic (void)ttyoutput('\n', tp);
162464416Sbostic
162564416Sbostic /*
162664416Sbostic * XXX
162764416Sbostic * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE
162864416Sbostic * BIT OF FIRST CHAR.
162964416Sbostic */
163017545Skarels s = spltty();
163164416Sbostic for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);
163264416Sbostic cp != NULL; cp = nextc(&tp->t_canq, cp, &c))
163335811Smarc ttyecho(c, tp);
163464416Sbostic for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);
163564416Sbostic cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))
163635811Smarc ttyecho(c, tp);
163764416Sbostic CLR(tp->t_state, TS_ERASE);
16387502Sroot splx(s);
163964416Sbostic
16407502Sroot tp->t_rocount = tp->t_rawq.c_cc;
16417502Sroot tp->t_rocol = 0;
16427502Sroot }
16437502Sroot
16447502Sroot /*
164535811Smarc * Echo a typed character to the terminal.
16467502Sroot */
164764416Sbostic static void
ttyecho(c,tp)16487502Sroot ttyecho(c, tp)
164964416Sbostic register int c;
16507625Ssam register struct tty *tp;
16517502Sroot {
165264416Sbostic
165364416Sbostic if (!ISSET(tp->t_state, TS_CNTTB))
165464416Sbostic CLR(tp->t_lflag, FLUSHO);
165564416Sbostic if ((!ISSET(tp->t_lflag, ECHO) &&
165664416Sbostic (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||
165764416Sbostic ISSET(tp->t_lflag, EXTPROC))
16587502Sroot return;
165964416Sbostic if (ISSET(tp->t_lflag, ECHOCTL) &&
166064576Sbostic (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' ||
166164576Sbostic ISSET(c, TTY_CHARMASK) == 0177)) {
166264416Sbostic (void)ttyoutput('^', tp);
166364576Sbostic CLR(c, ~TTY_CHARMASK);
166464416Sbostic if (c == 0177)
166564416Sbostic c = '?';
166664416Sbostic else
166764416Sbostic c += 'A' - 1;
16687502Sroot }
166964416Sbostic (void)ttyoutput(c, tp);
16707502Sroot }
16717502Sroot
16727502Sroot /*
167349380Skarels * Wake up any readers on a tty.
167449380Skarels */
167564416Sbostic void
ttwakeup(tp)16767502Sroot ttwakeup(tp)
167747545Skarels register struct tty *tp;
16787502Sroot {
16797502Sroot
168052522Smckusick selwakeup(&tp->t_rsel);
168164416Sbostic if (ISSET(tp->t_state, TS_ASYNC))
168264416Sbostic pgsignal(tp->t_pgrp, SIGIO, 1);
16837502Sroot wakeup((caddr_t)&tp->t_rawq);
16847502Sroot }
168535811Smarc
168635811Smarc /*
168748439Skarels * Look up a code for a specified speed in a conversion table;
168848439Skarels * used by drivers to map software speed values to hardware parameters.
168948439Skarels */
169064416Sbostic int
ttspeedtab(speed,table)169148439Skarels ttspeedtab(speed, table)
169252485Storek int speed;
169348439Skarels register struct speedtab *table;
169448439Skarels {
169548439Skarels
169648439Skarels for ( ; table->sp_speed != -1; table++)
169748439Skarels if (table->sp_speed == speed)
169848439Skarels return (table->sp_code);
169948439Skarels return (-1);
170048439Skarels }
170148439Skarels
170248439Skarels /*
170364416Sbostic * Set tty hi and low water marks.
170435811Smarc *
170535811Smarc * Try to arrange the dynamics so there's about one second
170635811Smarc * from hi to low water.
170764416Sbostic *
170835811Smarc */
170964416Sbostic void
ttsetwater(tp)171035811Smarc ttsetwater(tp)
171135811Smarc struct tty *tp;
171235811Smarc {
171364416Sbostic register int cps, x;
171435811Smarc
171564416Sbostic #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x))
171664416Sbostic
171764416Sbostic cps = tp->t_ospeed / 10;
171864416Sbostic tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);
171935811Smarc x += cps;
172064416Sbostic x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);
172135811Smarc tp->t_hiwat = roundup(x, CBSIZE);
172264416Sbostic #undef CLAMP
172335811Smarc }
172435811Smarc
172539407Smarc /*
172639407Smarc * Report on state of foreground process group.
172739407Smarc */
172864416Sbostic void
ttyinfo(tp)172939407Smarc ttyinfo(tp)
173049907Sbostic register struct tty *tp;
173139407Smarc {
173249907Sbostic register struct proc *p, *pick;
173341177Smarc struct timeval utime, stime;
173449907Sbostic int tmp;
173539407Smarc
173664416Sbostic if (ttycheckoutq(tp,0) == 0)
173739407Smarc return;
173849907Sbostic
173949907Sbostic /* Print load average. */
174052666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
174149907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
174249907Sbostic
174339555Smarc if (tp->t_session == NULL)
174449907Sbostic ttyprintf(tp, "not a controlling terminal\n");
174541177Smarc else if (tp->t_pgrp == NULL)
174649907Sbostic ttyprintf(tp, "no foreground process group\n");
174767732Smckusick else if ((p = tp->t_pgrp->pg_members.lh_first) == 0)
174849907Sbostic ttyprintf(tp, "empty foreground process group\n");
174939407Smarc else {
175049907Sbostic /* Pick interesting process. */
175167732Smckusick for (pick = NULL; p != 0; p = p->p_pglist.le_next)
175241177Smarc if (proc_compare(pick, p))
175341177Smarc pick = p;
175449907Sbostic
175549907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid,
175649907Sbostic pick->p_stat == SRUN ? "running" :
175749907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait");
175849907Sbostic
175954782Storek calcru(pick, &utime, &stime, NULL);
176039407Smarc
176149907Sbostic /* Print user time. */
176249907Sbostic ttyprintf(tp, "%d.%02du ",
176349907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000);
176441177Smarc
176549907Sbostic /* Print system time. */
176649907Sbostic ttyprintf(tp, "%d.%02ds ",
176749907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000);
176849907Sbostic
176949907Sbostic #define pgtok(a) (((a) * NBPG) / 1024)
177049907Sbostic /* Print percentage cpu, resident set size. */
177149907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT;
177249907Sbostic ttyprintf(tp, "%d%% %dk\n",
177352485Storek tmp / 100,
177452485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :
177565549Smckusick #ifdef pmap_resident_count
177665549Smckusick pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))
177765549Smckusick #else
177865549Smckusick pgtok(pick->p_vmspace->vm_rssize)
177965549Smckusick #endif
178065549Smckusick );
178141177Smarc }
178249907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */
178341177Smarc }
178441177Smarc
178541177Smarc /*
178641177Smarc * Returns 1 if p2 is "better" than p1
178741177Smarc *
178841177Smarc * The algorithm for picking the "interesting" process is thus:
178941177Smarc *
179064576Sbostic * 1) Only foreground processes are eligible - implied.
179164576Sbostic * 2) Runnable processes are favored over anything else. The runner
179264576Sbostic * with the highest cpu utilization is picked (p_estcpu). Ties are
179341177Smarc * broken by picking the highest pid.
179464576Sbostic * 3) The sleeper with the shortest sleep time is next. With ties,
179564576Sbostic * we pick out just "short-term" sleepers (P_SINTR == 0).
179664576Sbostic * 4) Further ties are broken by picking the highest pid.
179741177Smarc */
179864576Sbostic #define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
179945723Smckusick #define TESTAB(a, b) ((a)<<1 | (b))
180045723Smckusick #define ONLYA 2
180145723Smckusick #define ONLYB 1
180245723Smckusick #define BOTH 3
180364576Sbostic
180449907Sbostic static int
proc_compare(p1,p2)180541177Smarc proc_compare(p1, p2)
180641177Smarc register struct proc *p1, *p2;
180741177Smarc {
180841177Smarc
180941177Smarc if (p1 == NULL)
181041177Smarc return (1);
181141177Smarc /*
181241177Smarc * see if at least one of them is runnable
181341177Smarc */
181464576Sbostic switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
181545723Smckusick case ONLYA:
181645723Smckusick return (0);
181745723Smckusick case ONLYB:
181841177Smarc return (1);
181945723Smckusick case BOTH:
182041177Smarc /*
182141177Smarc * tie - favor one with highest recent cpu utilization
182241177Smarc */
182364576Sbostic if (p2->p_estcpu > p1->p_estcpu)
182441177Smarc return (1);
182564576Sbostic if (p1->p_estcpu > p2->p_estcpu)
182641177Smarc return (0);
182741177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
182841177Smarc }
182945723Smckusick /*
183045723Smckusick * weed out zombies
183145723Smckusick */
183245723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
183345723Smckusick case ONLYA:
183445723Smckusick return (1);
183545723Smckusick case ONLYB:
183645723Smckusick return (0);
183745723Smckusick case BOTH:
183845723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
183945723Smckusick }
184064416Sbostic /*
184141177Smarc * pick the one with the smallest sleep time
184241177Smarc */
184341177Smarc if (p2->p_slptime > p1->p_slptime)
184441177Smarc return (0);
184541177Smarc if (p1->p_slptime > p2->p_slptime)
184641177Smarc return (1);
184741177Smarc /*
184841177Smarc * favor one sleeping in a non-interruptible sleep
184941177Smarc */
185064576Sbostic if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)
185141177Smarc return (1);
185264576Sbostic if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)
185341177Smarc return (0);
185447545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
185541177Smarc }
185645723Smckusick
185739555Smarc /*
185839555Smarc * Output char to tty; console putchar style.
185939555Smarc */
186064416Sbostic int
tputchar(c,tp)186139555Smarc tputchar(c, tp)
186239555Smarc int c;
186339555Smarc struct tty *tp;
186439555Smarc {
186564416Sbostic register int s;
186639555Smarc
186764416Sbostic s = spltty();
186864416Sbostic if (ISSET(tp->t_state,
186964416Sbostic TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {
187039555Smarc splx(s);
187164416Sbostic return (-1);
187239555Smarc }
187364416Sbostic if (c == '\n')
187464416Sbostic (void)ttyoutput('\r', tp);
187564416Sbostic (void)ttyoutput(c, tp);
187664416Sbostic ttstart(tp);
187739555Smarc splx(s);
187864416Sbostic return (0);
187939555Smarc }
188043377Smarc
188144419Smarc /*
188264416Sbostic * Sleep on chan, returning ERESTART if tty changed while we napped and
188364416Sbostic * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If
188464416Sbostic * the tty is revoked, restarting a pending call will redo validation done
188564416Sbostic * at the start of the call.
188644419Smarc */
188764416Sbostic int
ttysleep(tp,chan,pri,wmesg,timo)188843377Smarc ttysleep(tp, chan, pri, wmesg, timo)
188943377Smarc struct tty *tp;
189064416Sbostic void *chan;
189164416Sbostic int pri, timo;
189243377Smarc char *wmesg;
189343377Smarc {
189443377Smarc int error;
189564416Sbostic short gen;
189643377Smarc
189764416Sbostic gen = tp->t_gen;
189843377Smarc if (error = tsleep(chan, pri, wmesg, timo))
189943377Smarc return (error);
190064416Sbostic return (tp->t_gen == gen ? 0 : ERESTART);
190143377Smarc }
1902