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*67732Smckusick * @(#)tty.c 8.12 (Berkeley) 08/22/94 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 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 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 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 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 59164576Sbostic ttioctl(tp, cmd, data, flag) 59264416Sbostic register struct tty *tp; 59364576Sbostic int cmd, flag; 59464416Sbostic void *data; 59564416Sbostic { 59664416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 59764576Sbostic extern int nlinesw; 59864416Sbostic register struct proc *p; 59964416Sbostic int s, error; 60064416Sbostic 60164416Sbostic p = curproc; /* XXX */ 60264416Sbostic 60364416Sbostic /* If the ioctl involves modification, hang if in the background. */ 60464576Sbostic switch (cmd) { 60564416Sbostic case TIOCFLUSH: 60664416Sbostic case TIOCSETA: 60764416Sbostic case TIOCSETD: 60864416Sbostic case TIOCSETAF: 60964416Sbostic case TIOCSETAW: 61064416Sbostic #ifdef notdef 61164416Sbostic case TIOCSPGRP: 61264416Sbostic #endif 61364416Sbostic case TIOCSTI: 61464416Sbostic case TIOCSWINSZ: 61564416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 61664416Sbostic case TIOCLBIC: 61764416Sbostic case TIOCLBIS: 61864416Sbostic case TIOCLSET: 61964416Sbostic case TIOCSETC: 62064416Sbostic case OTIOCSETD: 62164416Sbostic case TIOCSETN: 62264416Sbostic case TIOCSETP: 62364416Sbostic case TIOCSLTC: 62464416Sbostic #endif 62564416Sbostic while (isbackground(curproc, tp) && 62664576Sbostic p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 && 62764416Sbostic (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 62864416Sbostic (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 62964416Sbostic pgsignal(p->p_pgrp, SIGTTOU, 1); 63064416Sbostic if (error = ttysleep(tp, 63164416Sbostic &lbolt, TTOPRI | PCATCH, ttybg, 0)) 63264416Sbostic return (error); 63364416Sbostic } 63464416Sbostic break; 63564416Sbostic } 63664416Sbostic 63764576Sbostic switch (cmd) { /* Process the ioctl. */ 63864416Sbostic case FIOASYNC: /* set/clear async i/o */ 63964416Sbostic s = spltty(); 64064416Sbostic if (*(int *)data) 64164416Sbostic SET(tp->t_state, TS_ASYNC); 64264416Sbostic else 64364416Sbostic CLR(tp->t_state, TS_ASYNC); 64464416Sbostic splx(s); 64564416Sbostic break; 64664416Sbostic case FIONBIO: /* set/clear non-blocking i/o */ 64764416Sbostic break; /* XXX: delete. */ 64864416Sbostic case FIONREAD: /* get # bytes to read */ 64964416Sbostic *(int *)data = ttnread(tp); 65064416Sbostic break; 65164416Sbostic case TIOCEXCL: /* set exclusive use of tty */ 65264416Sbostic s = spltty(); 65364416Sbostic SET(tp->t_state, TS_XCLUDE); 65464416Sbostic splx(s); 65564416Sbostic break; 65664416Sbostic case TIOCFLUSH: { /* flush buffers */ 65764416Sbostic register int flags = *(int *)data; 65864416Sbostic 65964416Sbostic if (flags == 0) 66064416Sbostic flags = FREAD | FWRITE; 66164416Sbostic else 66264416Sbostic flags &= FREAD | FWRITE; 66364416Sbostic ttyflush(tp, flags); 66464416Sbostic break; 66564416Sbostic } 66664416Sbostic case TIOCCONS: /* become virtual console */ 66764416Sbostic if (*(int *)data) { 66864416Sbostic if (constty && constty != tp && 66964416Sbostic ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) == 67064416Sbostic (TS_CARR_ON | TS_ISOPEN)) 67164416Sbostic return (EBUSY); 67264416Sbostic #ifndef UCONSOLE 67364416Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 67464416Sbostic return (error); 67564416Sbostic #endif 67664416Sbostic constty = tp; 67764416Sbostic } else if (tp == constty) 67864416Sbostic constty = NULL; 67964416Sbostic break; 68064416Sbostic case TIOCDRAIN: /* wait till output drained */ 68164416Sbostic if (error = ttywait(tp)) 68264416Sbostic return (error); 68364416Sbostic break; 68464416Sbostic case TIOCGETA: { /* get termios struct */ 68564416Sbostic struct termios *t = (struct termios *)data; 68664416Sbostic 68764416Sbostic bcopy(&tp->t_termios, t, sizeof(struct termios)); 68864416Sbostic break; 68964416Sbostic } 69064416Sbostic case TIOCGETD: /* get line discipline */ 69164416Sbostic *(int *)data = tp->t_line; 69264416Sbostic break; 69364416Sbostic case TIOCGWINSZ: /* get window size */ 69464416Sbostic *(struct winsize *)data = tp->t_winsize; 69564416Sbostic break; 69664416Sbostic case TIOCGPGRP: /* get pgrp of tty */ 69764416Sbostic if (!isctty(p, tp)) 69864416Sbostic return (ENOTTY); 69964416Sbostic *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 70064416Sbostic break; 70164416Sbostic #ifdef TIOCHPCL 70264416Sbostic case TIOCHPCL: /* hang up on last close */ 70364416Sbostic s = spltty(); 70464576Sbostic SET(tp->t_cflag, HUPCL); 70564416Sbostic splx(s); 70664416Sbostic break; 70764416Sbostic #endif 70864416Sbostic case TIOCNXCL: /* reset exclusive use of tty */ 70964416Sbostic s = spltty(); 71064416Sbostic CLR(tp->t_state, TS_XCLUDE); 71164416Sbostic splx(s); 71264416Sbostic break; 71364416Sbostic case TIOCOUTQ: /* output queue size */ 71464416Sbostic *(int *)data = tp->t_outq.c_cc; 71564416Sbostic break; 71664416Sbostic case TIOCSETA: /* set termios struct */ 71764416Sbostic case TIOCSETAW: /* drain output, set */ 71864416Sbostic case TIOCSETAF: { /* drn out, fls in, set */ 71964416Sbostic register struct termios *t = (struct termios *)data; 72064416Sbostic 72164416Sbostic s = spltty(); 72264576Sbostic if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 72364416Sbostic if (error = ttywait(tp)) { 72464416Sbostic splx(s); 72564416Sbostic return (error); 72664416Sbostic } 72764576Sbostic if (cmd == TIOCSETAF) 72864416Sbostic ttyflush(tp, FREAD); 72964416Sbostic } 73064416Sbostic if (!ISSET(t->c_cflag, CIGNORE)) { 73164416Sbostic /* 73264416Sbostic * Set device hardware. 73364416Sbostic */ 73464416Sbostic if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 73564416Sbostic splx(s); 73664416Sbostic return (error); 73764416Sbostic } else { 73864416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 73964416Sbostic ISSET(tp->t_cflag, CLOCAL) && 74064416Sbostic !ISSET(t->c_cflag, CLOCAL)) { 74164416Sbostic CLR(tp->t_state, TS_ISOPEN); 74264416Sbostic SET(tp->t_state, TS_WOPEN); 74364416Sbostic ttwakeup(tp); 74464416Sbostic } 74564416Sbostic tp->t_cflag = t->c_cflag; 74664416Sbostic tp->t_ispeed = t->c_ispeed; 74764416Sbostic tp->t_ospeed = t->c_ospeed; 74864416Sbostic } 74964416Sbostic ttsetwater(tp); 75064416Sbostic } 75164576Sbostic if (cmd != TIOCSETAF) { 75264416Sbostic if (ISSET(t->c_lflag, ICANON) != 75364416Sbostic ISSET(tp->t_lflag, ICANON)) 75464416Sbostic if (ISSET(t->c_lflag, ICANON)) { 75564576Sbostic SET(tp->t_lflag, PENDIN); 75664416Sbostic ttwakeup(tp); 75764416Sbostic } else { 75864416Sbostic struct clist tq; 75964416Sbostic 76064416Sbostic catq(&tp->t_rawq, &tp->t_canq); 76164416Sbostic tq = tp->t_rawq; 76264416Sbostic tp->t_rawq = tp->t_canq; 76364416Sbostic tp->t_canq = tq; 76465324Sbostic CLR(tp->t_lflag, PENDIN); 76564416Sbostic } 76664416Sbostic } 76764416Sbostic tp->t_iflag = t->c_iflag; 76864416Sbostic tp->t_oflag = t->c_oflag; 76964416Sbostic /* 77064416Sbostic * Make the EXTPROC bit read only. 77164416Sbostic */ 77264416Sbostic if (ISSET(tp->t_lflag, EXTPROC)) 77364416Sbostic SET(t->c_lflag, EXTPROC); 77464416Sbostic else 77564416Sbostic CLR(t->c_lflag, EXTPROC); 77665324Sbostic tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); 77764416Sbostic bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 77864416Sbostic splx(s); 77964416Sbostic break; 78064416Sbostic } 78164416Sbostic case TIOCSETD: { /* set line discipline */ 78264416Sbostic register int t = *(int *)data; 78364416Sbostic dev_t device = tp->t_dev; 78464416Sbostic 78564576Sbostic if ((u_int)t >= nlinesw) 78664416Sbostic return (ENXIO); 78764416Sbostic if (t != tp->t_line) { 78864416Sbostic s = spltty(); 78964416Sbostic (*linesw[tp->t_line].l_close)(tp, flag); 79064416Sbostic error = (*linesw[t].l_open)(device, tp); 79164416Sbostic if (error) { 79264416Sbostic (void)(*linesw[tp->t_line].l_open)(device, tp); 79364416Sbostic splx(s); 79464416Sbostic return (error); 79564416Sbostic } 79664416Sbostic tp->t_line = t; 79764416Sbostic splx(s); 79864416Sbostic } 79964416Sbostic break; 80064416Sbostic } 80164416Sbostic case TIOCSTART: /* start output, like ^Q */ 80264416Sbostic s = spltty(); 80364416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) || 80464416Sbostic ISSET(tp->t_lflag, FLUSHO)) { 80564416Sbostic CLR(tp->t_lflag, FLUSHO); 80664416Sbostic CLR(tp->t_state, TS_TTSTOP); 80764416Sbostic ttstart(tp); 80864416Sbostic } 80964416Sbostic splx(s); 81064416Sbostic break; 81164416Sbostic case TIOCSTI: /* simulate terminal input */ 81264416Sbostic if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 81364416Sbostic return (EPERM); 81464416Sbostic if (p->p_ucred->cr_uid && !isctty(p, tp)) 81564416Sbostic return (EACCES); 81664416Sbostic (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 81764416Sbostic break; 81864416Sbostic case TIOCSTOP: /* stop output, like ^S */ 81964416Sbostic s = spltty(); 82064416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 82164416Sbostic SET(tp->t_state, TS_TTSTOP); 82264416Sbostic #ifdef sun4c /* XXX */ 82364416Sbostic (*tp->t_stop)(tp, 0); 82464416Sbostic #else 82564416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 82664416Sbostic #endif 82764416Sbostic } 82864416Sbostic splx(s); 82964416Sbostic break; 83064416Sbostic case TIOCSCTTY: /* become controlling tty */ 83164416Sbostic /* Session ctty vnode pointer set in vnode layer. */ 83264416Sbostic if (!SESS_LEADER(p) || 83367685Smckusick (p->p_session->s_ttyvp || tp->t_session) && 83467685Smckusick (tp->t_session != p->p_session)) 83564416Sbostic return (EPERM); 83664416Sbostic tp->t_session = p->p_session; 83764416Sbostic tp->t_pgrp = p->p_pgrp; 83864416Sbostic p->p_session->s_ttyp = tp; 83964576Sbostic p->p_flag |= P_CONTROLT; 84064416Sbostic break; 84164416Sbostic case TIOCSPGRP: { /* set pgrp of tty */ 84264416Sbostic register struct pgrp *pgrp = pgfind(*(int *)data); 84364416Sbostic 84464416Sbostic if (!isctty(p, tp)) 84564416Sbostic return (ENOTTY); 84664416Sbostic else if (pgrp == NULL || pgrp->pg_session != p->p_session) 84764416Sbostic return (EPERM); 84864416Sbostic tp->t_pgrp = pgrp; 84964416Sbostic break; 85064416Sbostic } 85164416Sbostic case TIOCSWINSZ: /* set window size */ 85264416Sbostic if (bcmp((caddr_t)&tp->t_winsize, data, 85364416Sbostic sizeof (struct winsize))) { 85464416Sbostic tp->t_winsize = *(struct winsize *)data; 85564416Sbostic pgsignal(tp->t_pgrp, SIGWINCH, 1); 85664416Sbostic } 85764416Sbostic break; 85864416Sbostic default: 85964416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 86064576Sbostic return (ttcompat(tp, cmd, data, flag)); 86164416Sbostic #else 86264416Sbostic return (-1); 86364416Sbostic #endif 86464416Sbostic } 86564416Sbostic return (0); 86664416Sbostic } 86764416Sbostic 86864416Sbostic int 86964416Sbostic ttselect(device, rw, p) 87064416Sbostic dev_t device; 87164416Sbostic int rw; 87264416Sbostic struct proc *p; 87364416Sbostic { 87464416Sbostic register struct tty *tp; 87564416Sbostic int nread, s; 87664416Sbostic 87764416Sbostic tp = &cdevsw[major(device)].d_ttys[minor(device)]; 87864416Sbostic 87964416Sbostic s = spltty(); 88064416Sbostic switch (rw) { 88164416Sbostic case FREAD: 88264416Sbostic nread = ttnread(tp); 88364416Sbostic if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) && 88464416Sbostic !ISSET(tp->t_state, TS_CARR_ON)) 88564416Sbostic goto win; 88664416Sbostic selrecord(p, &tp->t_rsel); 88764416Sbostic break; 88864416Sbostic case FWRITE: 88964416Sbostic if (tp->t_outq.c_cc <= tp->t_lowat) { 89064416Sbostic win: splx(s); 89164416Sbostic return (1); 89264416Sbostic } 89364416Sbostic selrecord(p, &tp->t_wsel); 89464416Sbostic break; 89564416Sbostic } 89664416Sbostic splx(s); 89764416Sbostic return (0); 89864416Sbostic } 89964416Sbostic 90064416Sbostic static int 90164416Sbostic ttnread(tp) 90264416Sbostic struct tty *tp; 90364416Sbostic { 90464416Sbostic int nread; 90564416Sbostic 90664416Sbostic if (ISSET(tp->t_lflag, PENDIN)) 90764416Sbostic ttypend(tp); 90864416Sbostic nread = tp->t_canq.c_cc; 90964416Sbostic if (!ISSET(tp->t_lflag, ICANON)) 91064416Sbostic nread += tp->t_rawq.c_cc; 91164416Sbostic return (nread); 91264416Sbostic } 91364416Sbostic 91464416Sbostic /* 91564416Sbostic * Wait for output to drain. 91664416Sbostic */ 91764416Sbostic int 91864416Sbostic ttywait(tp) 91964416Sbostic register struct tty *tp; 92064416Sbostic { 92164416Sbostic int error, s; 92264416Sbostic 92364416Sbostic error = 0; 92464416Sbostic s = spltty(); 92564416Sbostic while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 92664416Sbostic (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) 92764416Sbostic && tp->t_oproc) { 92864416Sbostic (*tp->t_oproc)(tp); 92964416Sbostic SET(tp->t_state, TS_ASLEEP); 93064416Sbostic if (error = ttysleep(tp, 93164416Sbostic &tp->t_outq, TTOPRI | PCATCH, ttyout, 0)) 93264416Sbostic break; 93364416Sbostic } 93464416Sbostic splx(s); 93564416Sbostic return (error); 93664416Sbostic } 93764416Sbostic 93864416Sbostic /* 93964416Sbostic * Flush if successfully wait. 94064416Sbostic */ 94164416Sbostic int 94264416Sbostic ttywflush(tp) 94364416Sbostic struct tty *tp; 94464416Sbostic { 94564416Sbostic int error; 94664416Sbostic 94764416Sbostic if ((error = ttywait(tp)) == 0) 94864416Sbostic ttyflush(tp, FREAD); 94964416Sbostic return (error); 95064416Sbostic } 95164416Sbostic 95264416Sbostic /* 95364416Sbostic * Flush tty read and/or write queues, notifying anyone waiting. 95464416Sbostic */ 95564416Sbostic void 95664416Sbostic ttyflush(tp, rw) 95764416Sbostic register struct tty *tp; 95864416Sbostic int rw; 95964416Sbostic { 96064416Sbostic register int s; 96164416Sbostic 96264416Sbostic s = spltty(); 96364416Sbostic if (rw & FREAD) { 96464416Sbostic FLUSHQ(&tp->t_canq); 96564416Sbostic FLUSHQ(&tp->t_rawq); 96664416Sbostic tp->t_rocount = 0; 96764416Sbostic tp->t_rocol = 0; 96864416Sbostic CLR(tp->t_state, TS_LOCAL); 96964416Sbostic ttwakeup(tp); 97064416Sbostic } 97164416Sbostic if (rw & FWRITE) { 97264416Sbostic CLR(tp->t_state, TS_TTSTOP); 97364416Sbostic #ifdef sun4c /* XXX */ 97464416Sbostic (*tp->t_stop)(tp, rw); 97564416Sbostic #else 97664416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 97764416Sbostic #endif 97864416Sbostic FLUSHQ(&tp->t_outq); 97964416Sbostic wakeup((caddr_t)&tp->t_outq); 98064416Sbostic selwakeup(&tp->t_wsel); 98164416Sbostic } 98264416Sbostic splx(s); 98364416Sbostic } 98464416Sbostic 98564416Sbostic /* 98664416Sbostic * Copy in the default termios characters. 98764416Sbostic */ 98864416Sbostic void 98964416Sbostic ttychars(tp) 99064416Sbostic struct tty *tp; 99164416Sbostic { 99264416Sbostic 99364416Sbostic bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 99464416Sbostic } 99564416Sbostic 99664416Sbostic /* 99764416Sbostic * Send stop character on input overflow. 99864416Sbostic */ 99964416Sbostic static void 100064416Sbostic ttyblock(tp) 100164416Sbostic register struct tty *tp; 100264416Sbostic { 100364416Sbostic register int total; 100464416Sbostic 100564416Sbostic total = tp->t_rawq.c_cc + tp->t_canq.c_cc; 100664416Sbostic if (tp->t_rawq.c_cc > TTYHOG) { 100764416Sbostic ttyflush(tp, FREAD | FWRITE); 100864416Sbostic CLR(tp->t_state, TS_TBLOCK); 100964416Sbostic } 101064416Sbostic /* 101164416Sbostic * Block further input iff: current input > threshold 101264416Sbostic * AND input is available to user program. 101364416Sbostic */ 101464416Sbostic if (total >= TTYHOG / 2 && 101564416Sbostic !ISSET(tp->t_state, TS_TBLOCK) && 101664416Sbostic !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 && 101764416Sbostic tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 101864416Sbostic if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 101964416Sbostic SET(tp->t_state, TS_TBLOCK); 102064416Sbostic ttstart(tp); 102164416Sbostic } 102264416Sbostic } 102364416Sbostic } 102464416Sbostic 102564416Sbostic void 102664416Sbostic ttrstrt(tp_arg) 102764416Sbostic void *tp_arg; 102864416Sbostic { 102964416Sbostic struct tty *tp; 103064416Sbostic int s; 103164416Sbostic 103264416Sbostic #ifdef DIAGNOSTIC 103364416Sbostic if (tp_arg == NULL) 103464416Sbostic panic("ttrstrt"); 103564416Sbostic #endif 103664416Sbostic tp = tp_arg; 103764416Sbostic s = spltty(); 103864416Sbostic 103964416Sbostic CLR(tp->t_state, TS_TIMEOUT); 104064416Sbostic ttstart(tp); 104164416Sbostic 104264416Sbostic splx(s); 104364416Sbostic } 104464416Sbostic 104564416Sbostic int 104664416Sbostic ttstart(tp) 104764416Sbostic struct tty *tp; 104864416Sbostic { 104964416Sbostic 105064416Sbostic if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 105164416Sbostic (*tp->t_oproc)(tp); 105264416Sbostic return (0); 105364416Sbostic } 105464416Sbostic 105564416Sbostic /* 105664416Sbostic * "close" a line discipline 105764416Sbostic */ 105864416Sbostic int 105964416Sbostic ttylclose(tp, flag) 106064416Sbostic struct tty *tp; 106164416Sbostic int flag; 106264416Sbostic { 106364416Sbostic 106464416Sbostic if (flag & IO_NDELAY) 106564416Sbostic ttyflush(tp, FREAD | FWRITE); 106664416Sbostic else 106764416Sbostic ttywflush(tp); 106864416Sbostic return (0); 106964416Sbostic } 107064416Sbostic 107164416Sbostic /* 107264416Sbostic * Handle modem control transition on a tty. 107364416Sbostic * Flag indicates new state of carrier. 107464416Sbostic * Returns 0 if the line should be turned off, otherwise 1. 107564416Sbostic */ 107664416Sbostic int 107764416Sbostic ttymodem(tp, flag) 107864416Sbostic register struct tty *tp; 107964416Sbostic int flag; 108064416Sbostic { 108164416Sbostic 108264416Sbostic if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) { 108364416Sbostic /* 108464416Sbostic * MDMBUF: do flow control according to carrier flag 108564416Sbostic */ 108664416Sbostic if (flag) { 108764416Sbostic CLR(tp->t_state, TS_TTSTOP); 108864416Sbostic ttstart(tp); 108964416Sbostic } else if (!ISSET(tp->t_state, TS_TTSTOP)) { 109064416Sbostic SET(tp->t_state, TS_TTSTOP); 109164416Sbostic #ifdef sun4c /* XXX */ 109264416Sbostic (*tp->t_stop)(tp, 0); 109364416Sbostic #else 109464416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 109564416Sbostic #endif 109664416Sbostic } 109764416Sbostic } else if (flag == 0) { 109864416Sbostic /* 109964416Sbostic * Lost carrier. 110064416Sbostic */ 110164416Sbostic CLR(tp->t_state, TS_CARR_ON); 110264416Sbostic if (ISSET(tp->t_state, TS_ISOPEN) && 110364416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 110464416Sbostic if (tp->t_session && tp->t_session->s_leader) 110564416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 110664416Sbostic ttyflush(tp, FREAD | FWRITE); 110764416Sbostic return (0); 110864416Sbostic } 110964416Sbostic } else { 111064416Sbostic /* 111164416Sbostic * Carrier now on. 111264416Sbostic */ 111364416Sbostic SET(tp->t_state, TS_CARR_ON); 111464416Sbostic ttwakeup(tp); 111564416Sbostic } 111664416Sbostic return (1); 111764416Sbostic } 111864416Sbostic 111964416Sbostic /* 112064416Sbostic * Default modem control routine (for other line disciplines). 112164416Sbostic * Return argument flag, to turn off device on carrier drop. 112264416Sbostic */ 112364416Sbostic int 112464416Sbostic nullmodem(tp, flag) 112564416Sbostic register struct tty *tp; 112664416Sbostic int flag; 112764416Sbostic { 112864416Sbostic 112964416Sbostic if (flag) 113064416Sbostic SET(tp->t_state, TS_CARR_ON); 113164416Sbostic else { 113264416Sbostic CLR(tp->t_state, TS_CARR_ON); 113364416Sbostic if (!ISSET(tp->t_cflag, CLOCAL)) { 113464416Sbostic if (tp->t_session && tp->t_session->s_leader) 113564416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 113664416Sbostic return (0); 113764416Sbostic } 113864416Sbostic } 113964416Sbostic return (1); 114064416Sbostic } 114164416Sbostic 114264416Sbostic /* 114364416Sbostic * Reinput pending characters after state switch 114464416Sbostic * call at spltty(). 114564416Sbostic */ 114664416Sbostic void 114764416Sbostic ttypend(tp) 114864416Sbostic register struct tty *tp; 114964416Sbostic { 115064416Sbostic struct clist tq; 115164416Sbostic register c; 115264416Sbostic 115364416Sbostic CLR(tp->t_lflag, PENDIN); 115464416Sbostic SET(tp->t_state, TS_TYPEN); 115564416Sbostic tq = tp->t_rawq; 115664416Sbostic tp->t_rawq.c_cc = 0; 115764416Sbostic tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 115864416Sbostic while ((c = getc(&tq)) >= 0) 115964416Sbostic ttyinput(c, tp); 116064416Sbostic CLR(tp->t_state, TS_TYPEN); 116164416Sbostic } 116264416Sbostic 116364416Sbostic /* 116449380Skarels * Process a read call on a tty device. 11657502Sroot */ 116664416Sbostic int 116737584Smarc ttread(tp, uio, flag) 11687625Ssam register struct tty *tp; 11697722Swnj struct uio *uio; 117052485Storek int flag; 11717502Sroot { 11727502Sroot register struct clist *qp; 117335811Smarc register int c; 117441383Smarc register long lflag; 117535811Smarc register u_char *cc = tp->t_cc; 117647545Skarels register struct proc *p = curproc; 11779859Ssam int s, first, error = 0; 11787502Sroot 117964416Sbostic loop: lflag = tp->t_lflag; 118037584Smarc s = spltty(); 11819578Ssam /* 118264416Sbostic * take pending input first 11839578Ssam */ 118464416Sbostic if (ISSET(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)) || 119464576Sbostic p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) 11958520Sroot return (EIO); 119647545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 119764416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 119840712Skarels return (error); 119923165Sbloom goto loop; 12007502Sroot } 120140712Skarels 12029578Ssam /* 120335811Smarc * If canonical, use the canonical queue, 120435811Smarc * else use the raw queue. 120537584Smarc * 120647545Skarels * (should get rid of clists...) 12079578Ssam */ 120864416Sbostic qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 120940712Skarels 12109578Ssam /* 121140712Skarels * If there is no input, sleep on rawq 121240712Skarels * awaiting hardware receipt and notification. 121340712Skarels * If we have data, we don't need to check for carrier. 12149578Ssam */ 121517545Skarels s = spltty(); 12169578Ssam if (qp->c_cc <= 0) { 121740712Skarels int carrier; 121840712Skarels 121964416Sbostic carrier = ISSET(tp->t_state, TS_CARR_ON) || 122064416Sbostic ISSET(tp->t_cflag, CLOCAL); 122164416Sbostic if (!carrier && ISSET(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 } 122964416Sbostic error = ttysleep(tp, &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 */ 124664416Sbostic if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) { 124742882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12489578Ssam if (first) { 124964416Sbostic if (error = ttysleep(tp, 125064416Sbostic &lbolt, TTIPRI | PCATCH, ttybg, 0)) 125140712Skarels break; 12529578Ssam goto loop; 12539578Ssam } 12549578Ssam break; 12557502Sroot } 12569578Ssam /* 125735811Smarc * Interpret EOF only in canonical mode. 12589578Ssam */ 125964416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(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 */ 127364416Sbostic if (ISSET(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 */ 128152485Storek s = spltty(); 128264416Sbostic if (ISSET(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) { 128564416Sbostic CLR(tp->t_state, TS_TBLOCK); 12867502Sroot ttstart(tp); 12877502Sroot } 128835811Smarc } 128952485Storek splx(s); 12908520Sroot return (error); 12917502Sroot } 12927502Sroot 12937502Sroot /* 129464416Sbostic * Check the output queue on tp for space for a kernel message (from uprintf 129564416Sbostic * or tprintf). Allow some space over the normal hiwater mark so we don't 129664416Sbostic * lose messages due to normal flow control, but don't let the tty run amok. 129764416Sbostic * Sleeps here are not interruptible, but we return prematurely if new signals 129864416Sbostic * arrive. 129925391Skarels */ 130064416Sbostic int 130125391Skarels ttycheckoutq(tp, wait) 130225391Skarels register struct tty *tp; 130325391Skarels int wait; 130425391Skarels { 130530695Skarels int hiwat, s, oldsig; 130625391Skarels 130735811Smarc hiwat = tp->t_hiwat; 130825391Skarels s = spltty(); 130964576Sbostic oldsig = wait ? curproc->p_siglist : 0; 131025391Skarels if (tp->t_outq.c_cc > hiwat + 200) 131129946Skarels while (tp->t_outq.c_cc > hiwat) { 131229946Skarels ttstart(tp); 131364576Sbostic if (wait == 0 || curproc->p_siglist != oldsig) { 131429946Skarels splx(s); 131529946Skarels return (0); 131629946Skarels } 131754782Storek timeout((void (*)__P((void *)))wakeup, 131854782Storek (void *)&tp->t_outq, hz); 131964416Sbostic SET(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 */ 132964416Sbostic int 133037584Smarc ttwrite(tp, uio, flag) 13317625Ssam register struct tty *tp; 13329578Ssam register struct uio *uio; 133352485Storek int flag; 13347502Sroot { 13357502Sroot register char *cp; 133664416Sbostic register int cc, ce; 133764416Sbostic register struct proc *p; 13389578Ssam int i, hiwat, cnt, error, s; 13397502Sroot char obuf[OBUFSIZ]; 13407502Sroot 134135811Smarc hiwat = tp->t_hiwat; 13429578Ssam cnt = uio->uio_resid; 13439578Ssam error = 0; 134464878Smckusick cc = 0; 13457502Sroot loop: 134637584Smarc s = spltty(); 134764416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 134864416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 134964416Sbostic if (ISSET(tp->t_state, TS_ISOPEN)) { 135037584Smarc splx(s); 135137584Smarc return (EIO); 135237728Smckusick } else if (flag & IO_NDELAY) { 135337584Smarc splx(s); 135440712Skarels error = EWOULDBLOCK; 135540712Skarels goto out; 135637584Smarc } else { 135764416Sbostic /* Sleep awaiting carrier. */ 135864416Sbostic error = ttysleep(tp, 135964416Sbostic &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0); 136037584Smarc splx(s); 136143377Smarc if (error) 136240712Skarels goto out; 136337584Smarc goto loop; 136437584Smarc } 136537584Smarc } 136637584Smarc splx(s); 13679578Ssam /* 13689578Ssam * Hang the process if it's in the background. 13699578Ssam */ 137064416Sbostic p = curproc; 137164416Sbostic if (isbackground(p, tp) && 137264576Sbostic ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 && 137347545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 137447545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 137547545Skarels p->p_pgrp->pg_jobc) { 137647545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 137764416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 137840712Skarels goto out; 137921776Sbloom goto loop; 13807502Sroot } 13819578Ssam /* 138264416Sbostic * Process the user's data in at most OBUFSIZ chunks. Perform any 138364416Sbostic * output translation. Keep track of high water mark, sleep on 138464416Sbostic * overflow awaiting device aid in acquiring new space. 13859578Ssam */ 138664878Smckusick while (uio->uio_resid > 0 || cc > 0) { 138764416Sbostic if (ISSET(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 /* 139464416Sbostic * Grab a hunk of data from the user, unless we have some 139564416Sbostic * 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 141164416Sbostic * bits in char_type), 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) { 141664416Sbostic if (!ISSET(tp->t_oflag, OPOST)) 14177502Sroot ce = cc; 14187502Sroot else { 141964416Sbostic ce = cc - scanc((u_int)cc, (u_char *)cp, 142064416Sbostic (u_char *)char_type, 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) { 142864416Sbostic /* No Clists, wait a bit. */ 142964416Sbostic ttstart(tp); 143064416Sbostic if (error = ttysleep(tp, &lbolt, 143164416Sbostic TTOPRI | PCATCH, ttybuf, 0)) 143264416Sbostic break; 143364416Sbostic goto loop; 14347502Sroot } 143564416Sbostic cp++; 143664416Sbostic cc--; 143764416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 14389578Ssam tp->t_outq.c_cc > hiwat) 14397502Sroot goto ovhiwat; 14409578Ssam continue; 14417502Sroot } 14427502Sroot } 14439578Ssam /* 144464416Sbostic * A bunch of normal characters have been found. 144564416Sbostic * 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; 145464530Sbostic tp->t_column += ce; 14559578Ssam cp += ce, cc -= ce, tk_nout += ce; 145635811Smarc tp->t_outcc += ce; 14579578Ssam if (i > 0) { 145864416Sbostic /* No Clists, wait a bit. */ 14597502Sroot ttstart(tp); 146064416Sbostic if (error = ttysleep(tp, 146164416Sbostic &lbolt, TTOPRI | PCATCH, ttybuf, 0)) 146240712Skarels break; 146321776Sbloom goto loop; 14647502Sroot } 146564416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 146664416Sbostic tp->t_outq.c_cc > hiwat) 146740712Skarels break; 14687502Sroot } 146935811Smarc ttstart(tp); 14707502Sroot } 147140712Skarels out: 147240712Skarels /* 147364416Sbostic * If cc is nonzero, we leave the uio structure inconsistent, as the 147464416Sbostic * offset and iov pointers have moved forward, but it doesn't matter 147564416Sbostic * (the call will either return short 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; 149464416Sbostic return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 14957502Sroot } 149664416Sbostic SET(tp->t_state, TS_ASLEEP); 149764416Sbostic error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14989578Ssam splx(s); 149943377Smarc if (error) 150040712Skarels goto out; 15017502Sroot goto loop; 15027502Sroot } 15037502Sroot 15047502Sroot /* 15057502Sroot * Rubout one character from the rawq of tp 15067502Sroot * as cleanly as possible. 15077502Sroot */ 150864416Sbostic void 15097502Sroot ttyrub(c, tp) 151064416Sbostic register int c; 15117625Ssam register struct tty *tp; 15127502Sroot { 15137502Sroot register char *cp; 15147502Sroot register int savecol; 151564416Sbostic int tabc, s; 15167502Sroot 151764416Sbostic if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 15187502Sroot return; 151964416Sbostic CLR(tp->t_lflag, FLUSHO); 152064416Sbostic if (ISSET(tp->t_lflag, ECHOE)) { 15217502Sroot if (tp->t_rocount == 0) { 15227502Sroot /* 15237502Sroot * Screwed by ttwrite; retype 15247502Sroot */ 15257502Sroot ttyretype(tp); 15267502Sroot return; 15277502Sroot } 152864416Sbostic if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 15297502Sroot ttyrubo(tp, 2); 153064576Sbostic else { 153164576Sbostic CLR(c, ~TTY_CHARMASK); 153264576Sbostic switch (CCLASS(c)) { 153364576Sbostic case ORDINARY: 153464576Sbostic ttyrubo(tp, 1); 153564576Sbostic break; 153664576Sbostic case BACKSPACE: 153764576Sbostic case CONTROL: 153864576Sbostic case NEWLINE: 153964576Sbostic case RETURN: 154064576Sbostic case VTAB: 154164576Sbostic if (ISSET(tp->t_lflag, ECHOCTL)) 154264576Sbostic ttyrubo(tp, 2); 154364576Sbostic break; 154464576Sbostic case TAB: 154564576Sbostic if (tp->t_rocount < tp->t_rawq.c_cc) { 154664576Sbostic ttyretype(tp); 154764576Sbostic return; 154864576Sbostic } 154964576Sbostic s = spltty(); 155064576Sbostic savecol = tp->t_column; 155164576Sbostic SET(tp->t_state, TS_CNTTB); 155264576Sbostic SET(tp->t_lflag, FLUSHO); 155364576Sbostic tp->t_column = tp->t_rocol; 155464576Sbostic cp = tp->t_rawq.c_cf; 155564576Sbostic if (cp) 155664576Sbostic tabc = *cp; /* XXX FIX NEXTC */ 155764576Sbostic for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 155864576Sbostic ttyecho(tabc, tp); 155964576Sbostic CLR(tp->t_lflag, FLUSHO); 156064576Sbostic CLR(tp->t_state, TS_CNTTB); 156164576Sbostic splx(s); 156264416Sbostic 156364576Sbostic /* savecol will now be length of the tab. */ 156464576Sbostic savecol -= tp->t_column; 156564576Sbostic tp->t_column += savecol; 156664576Sbostic if (savecol > 8) 156764576Sbostic savecol = 8; /* overflow screw */ 156864576Sbostic while (--savecol >= 0) 156964576Sbostic (void)ttyoutput('\b', tp); 157064576Sbostic break; 157164576Sbostic default: /* XXX */ 157264416Sbostic #define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 157364576Sbostic (void)printf(PANICSTR, c, CCLASS(c)); 157464416Sbostic #ifdef notdef 157564576Sbostic panic(PANICSTR, c, CCLASS(c)); 157664416Sbostic #endif 157764576Sbostic } 157835811Smarc } 157964416Sbostic } else if (ISSET(tp->t_lflag, ECHOPRT)) { 158064416Sbostic if (!ISSET(tp->t_state, TS_ERASE)) { 158164416Sbostic SET(tp->t_state, TS_ERASE); 158264416Sbostic (void)ttyoutput('\\', tp); 15837502Sroot } 15847502Sroot ttyecho(c, tp); 15857502Sroot } else 158635811Smarc ttyecho(tp->t_cc[VERASE], tp); 158764416Sbostic --tp->t_rocount; 15887502Sroot } 15897502Sroot 15907502Sroot /* 159164416Sbostic * Back over cnt characters, erasing them. 15927502Sroot */ 159364416Sbostic static void 15947502Sroot ttyrubo(tp, cnt) 15957625Ssam register struct tty *tp; 15967625Ssam int cnt; 15977502Sroot { 15987502Sroot 159964416Sbostic while (cnt-- > 0) { 160064416Sbostic (void)ttyoutput('\b', tp); 160164416Sbostic (void)ttyoutput(' ', tp); 160264416Sbostic (void)ttyoutput('\b', tp); 160364416Sbostic } 16047502Sroot } 16057502Sroot 16067502Sroot /* 160764416Sbostic * ttyretype -- 160864416Sbostic * Reprint the rawq line. Note, it is assumed that c_cc has already 160964416Sbostic * been checked. 16107502Sroot */ 161164416Sbostic void 16127502Sroot ttyretype(tp) 16137625Ssam register struct tty *tp; 16147502Sroot { 16157502Sroot register char *cp; 161635811Smarc int s, c; 16177502Sroot 161864416Sbostic /* Echo the reprint character. */ 161935811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 162035811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 162164416Sbostic 162264416Sbostic (void)ttyoutput('\n', tp); 162364416Sbostic 162464416Sbostic /* 162564416Sbostic * XXX 162664416Sbostic * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 162764416Sbostic * BIT OF FIRST CHAR. 162864416Sbostic */ 162917545Skarels s = spltty(); 163064416Sbostic for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 163164416Sbostic cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 163235811Smarc ttyecho(c, tp); 163364416Sbostic for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 163464416Sbostic cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 163535811Smarc ttyecho(c, tp); 163664416Sbostic CLR(tp->t_state, TS_ERASE); 16377502Sroot splx(s); 163864416Sbostic 16397502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16407502Sroot tp->t_rocol = 0; 16417502Sroot } 16427502Sroot 16437502Sroot /* 164435811Smarc * Echo a typed character to the terminal. 16457502Sroot */ 164664416Sbostic static void 16477502Sroot ttyecho(c, tp) 164864416Sbostic register int c; 16497625Ssam register struct tty *tp; 16507502Sroot { 165164416Sbostic 165264416Sbostic if (!ISSET(tp->t_state, TS_CNTTB)) 165364416Sbostic CLR(tp->t_lflag, FLUSHO); 165464416Sbostic if ((!ISSET(tp->t_lflag, ECHO) && 165564416Sbostic (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) || 165664416Sbostic ISSET(tp->t_lflag, EXTPROC)) 16577502Sroot return; 165864416Sbostic if (ISSET(tp->t_lflag, ECHOCTL) && 165964576Sbostic (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 166064576Sbostic ISSET(c, TTY_CHARMASK) == 0177)) { 166164416Sbostic (void)ttyoutput('^', tp); 166264576Sbostic CLR(c, ~TTY_CHARMASK); 166364416Sbostic if (c == 0177) 166464416Sbostic c = '?'; 166564416Sbostic else 166664416Sbostic c += 'A' - 1; 16677502Sroot } 166864416Sbostic (void)ttyoutput(c, tp); 16697502Sroot } 16707502Sroot 16717502Sroot /* 167249380Skarels * Wake up any readers on a tty. 167349380Skarels */ 167464416Sbostic void 16757502Sroot ttwakeup(tp) 167647545Skarels register struct tty *tp; 16777502Sroot { 16787502Sroot 167952522Smckusick selwakeup(&tp->t_rsel); 168064416Sbostic if (ISSET(tp->t_state, TS_ASYNC)) 168164416Sbostic pgsignal(tp->t_pgrp, SIGIO, 1); 16827502Sroot wakeup((caddr_t)&tp->t_rawq); 16837502Sroot } 168435811Smarc 168535811Smarc /* 168648439Skarels * Look up a code for a specified speed in a conversion table; 168748439Skarels * used by drivers to map software speed values to hardware parameters. 168848439Skarels */ 168964416Sbostic int 169048439Skarels ttspeedtab(speed, table) 169152485Storek int speed; 169248439Skarels register struct speedtab *table; 169348439Skarels { 169448439Skarels 169548439Skarels for ( ; table->sp_speed != -1; table++) 169648439Skarels if (table->sp_speed == speed) 169748439Skarels return (table->sp_code); 169848439Skarels return (-1); 169948439Skarels } 170048439Skarels 170148439Skarels /* 170264416Sbostic * Set tty hi and low water marks. 170335811Smarc * 170435811Smarc * Try to arrange the dynamics so there's about one second 170535811Smarc * from hi to low water. 170664416Sbostic * 170735811Smarc */ 170864416Sbostic void 170935811Smarc ttsetwater(tp) 171035811Smarc struct tty *tp; 171135811Smarc { 171264416Sbostic register int cps, x; 171335811Smarc 171464416Sbostic #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 171564416Sbostic 171664416Sbostic cps = tp->t_ospeed / 10; 171764416Sbostic tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 171835811Smarc x += cps; 171964416Sbostic x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT); 172035811Smarc tp->t_hiwat = roundup(x, CBSIZE); 172164416Sbostic #undef CLAMP 172235811Smarc } 172335811Smarc 172439407Smarc /* 172539407Smarc * Report on state of foreground process group. 172639407Smarc */ 172764416Sbostic void 172839407Smarc ttyinfo(tp) 172949907Sbostic register struct tty *tp; 173039407Smarc { 173149907Sbostic register struct proc *p, *pick; 173241177Smarc struct timeval utime, stime; 173349907Sbostic int tmp; 173439407Smarc 173564416Sbostic if (ttycheckoutq(tp,0) == 0) 173639407Smarc return; 173749907Sbostic 173849907Sbostic /* Print load average. */ 173952666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 174049907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 174149907Sbostic 174239555Smarc if (tp->t_session == NULL) 174349907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 174441177Smarc else if (tp->t_pgrp == NULL) 174549907Sbostic ttyprintf(tp, "no foreground process group\n"); 1746*67732Smckusick else if ((p = tp->t_pgrp->pg_members.lh_first) == 0) 174749907Sbostic ttyprintf(tp, "empty foreground process group\n"); 174839407Smarc else { 174949907Sbostic /* Pick interesting process. */ 1750*67732Smckusick for (pick = NULL; p != 0; p = p->p_pglist.le_next) 175141177Smarc if (proc_compare(pick, p)) 175241177Smarc pick = p; 175349907Sbostic 175449907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 175549907Sbostic pick->p_stat == SRUN ? "running" : 175649907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 175749907Sbostic 175854782Storek calcru(pick, &utime, &stime, NULL); 175939407Smarc 176049907Sbostic /* Print user time. */ 176149907Sbostic ttyprintf(tp, "%d.%02du ", 176249907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 176341177Smarc 176449907Sbostic /* Print system time. */ 176549907Sbostic ttyprintf(tp, "%d.%02ds ", 176649907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 176749907Sbostic 176849907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 176949907Sbostic /* Print percentage cpu, resident set size. */ 177049907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 177149907Sbostic ttyprintf(tp, "%d%% %dk\n", 177252485Storek tmp / 100, 177352485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 177465549Smckusick #ifdef pmap_resident_count 177565549Smckusick pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap)) 177665549Smckusick #else 177765549Smckusick pgtok(pick->p_vmspace->vm_rssize) 177865549Smckusick #endif 177965549Smckusick ); 178041177Smarc } 178149907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 178241177Smarc } 178341177Smarc 178441177Smarc /* 178541177Smarc * Returns 1 if p2 is "better" than p1 178641177Smarc * 178741177Smarc * The algorithm for picking the "interesting" process is thus: 178841177Smarc * 178964576Sbostic * 1) Only foreground processes are eligible - implied. 179064576Sbostic * 2) Runnable processes are favored over anything else. The runner 179164576Sbostic * with the highest cpu utilization is picked (p_estcpu). Ties are 179241177Smarc * broken by picking the highest pid. 179364576Sbostic * 3) The sleeper with the shortest sleep time is next. With ties, 179464576Sbostic * we pick out just "short-term" sleepers (P_SINTR == 0). 179564576Sbostic * 4) Further ties are broken by picking the highest pid. 179641177Smarc */ 179764576Sbostic #define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 179845723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 179945723Smckusick #define ONLYA 2 180045723Smckusick #define ONLYB 1 180145723Smckusick #define BOTH 3 180264576Sbostic 180349907Sbostic static int 180441177Smarc proc_compare(p1, p2) 180541177Smarc register struct proc *p1, *p2; 180641177Smarc { 180741177Smarc 180841177Smarc if (p1 == NULL) 180941177Smarc return (1); 181041177Smarc /* 181141177Smarc * see if at least one of them is runnable 181241177Smarc */ 181364576Sbostic switch (TESTAB(ISRUN(p1), ISRUN(p2))) { 181445723Smckusick case ONLYA: 181545723Smckusick return (0); 181645723Smckusick case ONLYB: 181741177Smarc return (1); 181845723Smckusick case BOTH: 181941177Smarc /* 182041177Smarc * tie - favor one with highest recent cpu utilization 182141177Smarc */ 182264576Sbostic if (p2->p_estcpu > p1->p_estcpu) 182341177Smarc return (1); 182464576Sbostic if (p1->p_estcpu > p2->p_estcpu) 182541177Smarc return (0); 182641177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182741177Smarc } 182845723Smckusick /* 182945723Smckusick * weed out zombies 183045723Smckusick */ 183145723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 183245723Smckusick case ONLYA: 183345723Smckusick return (1); 183445723Smckusick case ONLYB: 183545723Smckusick return (0); 183645723Smckusick case BOTH: 183745723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183845723Smckusick } 183964416Sbostic /* 184041177Smarc * pick the one with the smallest sleep time 184141177Smarc */ 184241177Smarc if (p2->p_slptime > p1->p_slptime) 184341177Smarc return (0); 184441177Smarc if (p1->p_slptime > p2->p_slptime) 184541177Smarc return (1); 184641177Smarc /* 184741177Smarc * favor one sleeping in a non-interruptible sleep 184841177Smarc */ 184964576Sbostic if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0) 185041177Smarc return (1); 185164576Sbostic if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0) 185241177Smarc return (0); 185347545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 185441177Smarc } 185545723Smckusick 185639555Smarc /* 185739555Smarc * Output char to tty; console putchar style. 185839555Smarc */ 185964416Sbostic int 186039555Smarc tputchar(c, tp) 186139555Smarc int c; 186239555Smarc struct tty *tp; 186339555Smarc { 186464416Sbostic register int s; 186539555Smarc 186664416Sbostic s = spltty(); 186764416Sbostic if (ISSET(tp->t_state, 186864416Sbostic TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) { 186939555Smarc splx(s); 187064416Sbostic return (-1); 187139555Smarc } 187264416Sbostic if (c == '\n') 187364416Sbostic (void)ttyoutput('\r', tp); 187464416Sbostic (void)ttyoutput(c, tp); 187564416Sbostic ttstart(tp); 187639555Smarc splx(s); 187764416Sbostic return (0); 187839555Smarc } 187943377Smarc 188044419Smarc /* 188164416Sbostic * Sleep on chan, returning ERESTART if tty changed while we napped and 188264416Sbostic * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If 188364416Sbostic * the tty is revoked, restarting a pending call will redo validation done 188464416Sbostic * at the start of the call. 188544419Smarc */ 188664416Sbostic int 188743377Smarc ttysleep(tp, chan, pri, wmesg, timo) 188843377Smarc struct tty *tp; 188964416Sbostic void *chan; 189064416Sbostic int pri, timo; 189143377Smarc char *wmesg; 189243377Smarc { 189343377Smarc int error; 189464416Sbostic short gen; 189543377Smarc 189664416Sbostic gen = tp->t_gen; 189743377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 189843377Smarc return (error); 189964416Sbostic return (tp->t_gen == gen ? 0 : ERESTART); 190043377Smarc } 1901