149594Sbostic /*- 263178Sbostic * Copyright (c) 1982, 1986, 1990, 1991, 1993 363178Sbostic * The Regents of the University of California. All rights reserved. 4*65771Sbostic * (c) UNIX System Laboratories, Inc. 5*65771Sbostic * All or some portions of this file are derived from material licensed 6*65771Sbostic * to the University of California by American Telephone and Telegraph 7*65771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8*65771Sbostic * the permission of UNIX System Laboratories, Inc. 923387Smckusick * 1049594Sbostic * %sccs.include.redist.c% 1149594Sbostic * 12*65771Sbostic * @(#)tty.c 8.8 (Berkeley) 01/21/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; 50864416Sbostic register int 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); 53064416Sbostic if (!ISSET(tp->t_lflag, FLUSHO)) { 53164416Sbostic s = spltty(); /* Don't interrupt tabs. */ 5327502Sroot c -= b_to_q(" ", c, &tp->t_outq); 5337502Sroot tk_nout += c; 53435811Smarc tp->t_outcc += c; 5357502Sroot splx(s); 5367502Sroot } 53764530Sbostic tp->t_column += c; 5387502Sroot return (c ? -1 : '\t'); 5397502Sroot } 54064416Sbostic if (c == CEOT && ISSET(oflag, ONOEOT)) 54147545Skarels return (-1); 54264576Sbostic 5437502Sroot /* 54449380Skarels * Newline translation: if ONLCR is set, 54549380Skarels * translate newline into "\r\n". 5467502Sroot */ 54764576Sbostic if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) { 54864576Sbostic tk_nout++; 54964576Sbostic tp->t_outcc++; 55064576Sbostic if (putc('\r', &tp->t_outq)) 55164576Sbostic return (c); 55264576Sbostic } 55364576Sbostic tk_nout++; 55464576Sbostic tp->t_outcc++; 55564416Sbostic if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq)) 55635811Smarc return (c); 55747545Skarels 55864530Sbostic col = tp->t_column; 55949380Skarels switch (CCLASS(c)) { 5607502Sroot case BACKSPACE: 56149380Skarels if (col > 0) 56264416Sbostic --col; 5637502Sroot break; 56464416Sbostic case CONTROL: 56564416Sbostic break; 5667502Sroot case NEWLINE: 56764416Sbostic case RETURN: 56849380Skarels col = 0; 5697502Sroot break; 57064416Sbostic case ORDINARY: 57164416Sbostic ++col; 57264416Sbostic break; 5737502Sroot case TAB: 57464416Sbostic col = (col + 8) & ~7; 5757502Sroot break; 5767502Sroot } 57764530Sbostic tp->t_column = col; 5787502Sroot return (-1); 5797502Sroot } 5807502Sroot 5817502Sroot /* 58264576Sbostic * Ioctls for all tty devices. Called after line-discipline specific ioctl 58364576Sbostic * has been called to do discipline-specific functions and/or reject any 58464576Sbostic * of these ioctl commands. 58564416Sbostic */ 58664416Sbostic /* ARGSUSED */ 58764416Sbostic int 58864576Sbostic ttioctl(tp, cmd, data, flag) 58964416Sbostic register struct tty *tp; 59064576Sbostic int cmd, flag; 59164416Sbostic void *data; 59264416Sbostic { 59364416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 59464576Sbostic extern int nlinesw; 59564416Sbostic register struct proc *p; 59664416Sbostic int s, error; 59764416Sbostic 59864416Sbostic p = curproc; /* XXX */ 59964416Sbostic 60064416Sbostic /* If the ioctl involves modification, hang if in the background. */ 60164576Sbostic switch (cmd) { 60264416Sbostic case TIOCFLUSH: 60364416Sbostic case TIOCSETA: 60464416Sbostic case TIOCSETD: 60564416Sbostic case TIOCSETAF: 60664416Sbostic case TIOCSETAW: 60764416Sbostic #ifdef notdef 60864416Sbostic case TIOCSPGRP: 60964416Sbostic #endif 61064416Sbostic case TIOCSTI: 61164416Sbostic case TIOCSWINSZ: 61264416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 61364416Sbostic case TIOCLBIC: 61464416Sbostic case TIOCLBIS: 61564416Sbostic case TIOCLSET: 61664416Sbostic case TIOCSETC: 61764416Sbostic case OTIOCSETD: 61864416Sbostic case TIOCSETN: 61964416Sbostic case TIOCSETP: 62064416Sbostic case TIOCSLTC: 62164416Sbostic #endif 62264416Sbostic while (isbackground(curproc, tp) && 62364576Sbostic p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 && 62464416Sbostic (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 62564416Sbostic (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 62664416Sbostic pgsignal(p->p_pgrp, SIGTTOU, 1); 62764416Sbostic if (error = ttysleep(tp, 62864416Sbostic &lbolt, TTOPRI | PCATCH, ttybg, 0)) 62964416Sbostic return (error); 63064416Sbostic } 63164416Sbostic break; 63264416Sbostic } 63364416Sbostic 63464576Sbostic switch (cmd) { /* Process the ioctl. */ 63564416Sbostic case FIOASYNC: /* set/clear async i/o */ 63664416Sbostic s = spltty(); 63764416Sbostic if (*(int *)data) 63864416Sbostic SET(tp->t_state, TS_ASYNC); 63964416Sbostic else 64064416Sbostic CLR(tp->t_state, TS_ASYNC); 64164416Sbostic splx(s); 64264416Sbostic break; 64364416Sbostic case FIONBIO: /* set/clear non-blocking i/o */ 64464416Sbostic break; /* XXX: delete. */ 64564416Sbostic case FIONREAD: /* get # bytes to read */ 64664416Sbostic *(int *)data = ttnread(tp); 64764416Sbostic break; 64864416Sbostic case TIOCEXCL: /* set exclusive use of tty */ 64964416Sbostic s = spltty(); 65064416Sbostic SET(tp->t_state, TS_XCLUDE); 65164416Sbostic splx(s); 65264416Sbostic break; 65364416Sbostic case TIOCFLUSH: { /* flush buffers */ 65464416Sbostic register int flags = *(int *)data; 65564416Sbostic 65664416Sbostic if (flags == 0) 65764416Sbostic flags = FREAD | FWRITE; 65864416Sbostic else 65964416Sbostic flags &= FREAD | FWRITE; 66064416Sbostic ttyflush(tp, flags); 66164416Sbostic break; 66264416Sbostic } 66364416Sbostic case TIOCCONS: /* become virtual console */ 66464416Sbostic if (*(int *)data) { 66564416Sbostic if (constty && constty != tp && 66664416Sbostic ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) == 66764416Sbostic (TS_CARR_ON | TS_ISOPEN)) 66864416Sbostic return (EBUSY); 66964416Sbostic #ifndef UCONSOLE 67064416Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 67164416Sbostic return (error); 67264416Sbostic #endif 67364416Sbostic constty = tp; 67464416Sbostic } else if (tp == constty) 67564416Sbostic constty = NULL; 67664416Sbostic break; 67764416Sbostic case TIOCDRAIN: /* wait till output drained */ 67864416Sbostic if (error = ttywait(tp)) 67964416Sbostic return (error); 68064416Sbostic break; 68164416Sbostic case TIOCGETA: { /* get termios struct */ 68264416Sbostic struct termios *t = (struct termios *)data; 68364416Sbostic 68464416Sbostic bcopy(&tp->t_termios, t, sizeof(struct termios)); 68564416Sbostic break; 68664416Sbostic } 68764416Sbostic case TIOCGETD: /* get line discipline */ 68864416Sbostic *(int *)data = tp->t_line; 68964416Sbostic break; 69064416Sbostic case TIOCGWINSZ: /* get window size */ 69164416Sbostic *(struct winsize *)data = tp->t_winsize; 69264416Sbostic break; 69364416Sbostic case TIOCGPGRP: /* get pgrp of tty */ 69464416Sbostic if (!isctty(p, tp)) 69564416Sbostic return (ENOTTY); 69664416Sbostic *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 69764416Sbostic break; 69864416Sbostic #ifdef TIOCHPCL 69964416Sbostic case TIOCHPCL: /* hang up on last close */ 70064416Sbostic s = spltty(); 70164576Sbostic SET(tp->t_cflag, HUPCL); 70264416Sbostic splx(s); 70364416Sbostic break; 70464416Sbostic #endif 70564416Sbostic case TIOCNXCL: /* reset exclusive use of tty */ 70664416Sbostic s = spltty(); 70764416Sbostic CLR(tp->t_state, TS_XCLUDE); 70864416Sbostic splx(s); 70964416Sbostic break; 71064416Sbostic case TIOCOUTQ: /* output queue size */ 71164416Sbostic *(int *)data = tp->t_outq.c_cc; 71264416Sbostic break; 71364416Sbostic case TIOCSETA: /* set termios struct */ 71464416Sbostic case TIOCSETAW: /* drain output, set */ 71564416Sbostic case TIOCSETAF: { /* drn out, fls in, set */ 71664416Sbostic register struct termios *t = (struct termios *)data; 71764416Sbostic 71864416Sbostic s = spltty(); 71964576Sbostic if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 72064416Sbostic if (error = ttywait(tp)) { 72164416Sbostic splx(s); 72264416Sbostic return (error); 72364416Sbostic } 72464576Sbostic if (cmd == TIOCSETAF) 72564416Sbostic ttyflush(tp, FREAD); 72664416Sbostic } 72764416Sbostic if (!ISSET(t->c_cflag, CIGNORE)) { 72864416Sbostic /* 72964416Sbostic * Set device hardware. 73064416Sbostic */ 73164416Sbostic if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 73264416Sbostic splx(s); 73364416Sbostic return (error); 73464416Sbostic } else { 73564416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 73664416Sbostic ISSET(tp->t_cflag, CLOCAL) && 73764416Sbostic !ISSET(t->c_cflag, CLOCAL)) { 73864416Sbostic CLR(tp->t_state, TS_ISOPEN); 73964416Sbostic SET(tp->t_state, TS_WOPEN); 74064416Sbostic ttwakeup(tp); 74164416Sbostic } 74264416Sbostic tp->t_cflag = t->c_cflag; 74364416Sbostic tp->t_ispeed = t->c_ispeed; 74464416Sbostic tp->t_ospeed = t->c_ospeed; 74564416Sbostic } 74664416Sbostic ttsetwater(tp); 74764416Sbostic } 74864576Sbostic if (cmd != TIOCSETAF) { 74964416Sbostic if (ISSET(t->c_lflag, ICANON) != 75064416Sbostic ISSET(tp->t_lflag, ICANON)) 75164416Sbostic if (ISSET(t->c_lflag, ICANON)) { 75264576Sbostic SET(tp->t_lflag, PENDIN); 75364416Sbostic ttwakeup(tp); 75464416Sbostic } else { 75564416Sbostic struct clist tq; 75664416Sbostic 75764416Sbostic catq(&tp->t_rawq, &tp->t_canq); 75864416Sbostic tq = tp->t_rawq; 75964416Sbostic tp->t_rawq = tp->t_canq; 76064416Sbostic tp->t_canq = tq; 76165324Sbostic CLR(tp->t_lflag, PENDIN); 76264416Sbostic } 76364416Sbostic } 76464416Sbostic tp->t_iflag = t->c_iflag; 76564416Sbostic tp->t_oflag = t->c_oflag; 76664416Sbostic /* 76764416Sbostic * Make the EXTPROC bit read only. 76864416Sbostic */ 76964416Sbostic if (ISSET(tp->t_lflag, EXTPROC)) 77064416Sbostic SET(t->c_lflag, EXTPROC); 77164416Sbostic else 77264416Sbostic CLR(t->c_lflag, EXTPROC); 77365324Sbostic tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); 77464416Sbostic bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 77564416Sbostic splx(s); 77664416Sbostic break; 77764416Sbostic } 77864416Sbostic case TIOCSETD: { /* set line discipline */ 77964416Sbostic register int t = *(int *)data; 78064416Sbostic dev_t device = tp->t_dev; 78164416Sbostic 78264576Sbostic if ((u_int)t >= nlinesw) 78364416Sbostic return (ENXIO); 78464416Sbostic if (t != tp->t_line) { 78564416Sbostic s = spltty(); 78664416Sbostic (*linesw[tp->t_line].l_close)(tp, flag); 78764416Sbostic error = (*linesw[t].l_open)(device, tp); 78864416Sbostic if (error) { 78964416Sbostic (void)(*linesw[tp->t_line].l_open)(device, tp); 79064416Sbostic splx(s); 79164416Sbostic return (error); 79264416Sbostic } 79364416Sbostic tp->t_line = t; 79464416Sbostic splx(s); 79564416Sbostic } 79664416Sbostic break; 79764416Sbostic } 79864416Sbostic case TIOCSTART: /* start output, like ^Q */ 79964416Sbostic s = spltty(); 80064416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) || 80164416Sbostic ISSET(tp->t_lflag, FLUSHO)) { 80264416Sbostic CLR(tp->t_lflag, FLUSHO); 80364416Sbostic CLR(tp->t_state, TS_TTSTOP); 80464416Sbostic ttstart(tp); 80564416Sbostic } 80664416Sbostic splx(s); 80764416Sbostic break; 80864416Sbostic case TIOCSTI: /* simulate terminal input */ 80964416Sbostic if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 81064416Sbostic return (EPERM); 81164416Sbostic if (p->p_ucred->cr_uid && !isctty(p, tp)) 81264416Sbostic return (EACCES); 81364416Sbostic (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 81464416Sbostic break; 81564416Sbostic case TIOCSTOP: /* stop output, like ^S */ 81664416Sbostic s = spltty(); 81764416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 81864416Sbostic SET(tp->t_state, TS_TTSTOP); 81964416Sbostic #ifdef sun4c /* XXX */ 82064416Sbostic (*tp->t_stop)(tp, 0); 82164416Sbostic #else 82264416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 82364416Sbostic #endif 82464416Sbostic } 82564416Sbostic splx(s); 82664416Sbostic break; 82764416Sbostic case TIOCSCTTY: /* become controlling tty */ 82864416Sbostic /* Session ctty vnode pointer set in vnode layer. */ 82964416Sbostic if (!SESS_LEADER(p) || 83064416Sbostic (p->p_session->s_ttyvp || tp->t_session) && 83164416Sbostic (tp->t_session != p->p_session)) 83264416Sbostic return (EPERM); 83364416Sbostic tp->t_session = p->p_session; 83464416Sbostic tp->t_pgrp = p->p_pgrp; 83564416Sbostic p->p_session->s_ttyp = tp; 83664576Sbostic p->p_flag |= P_CONTROLT; 83764416Sbostic break; 83864416Sbostic case TIOCSPGRP: { /* set pgrp of tty */ 83964416Sbostic register struct pgrp *pgrp = pgfind(*(int *)data); 84064416Sbostic 84164416Sbostic if (!isctty(p, tp)) 84264416Sbostic return (ENOTTY); 84364416Sbostic else if (pgrp == NULL || pgrp->pg_session != p->p_session) 84464416Sbostic return (EPERM); 84564416Sbostic tp->t_pgrp = pgrp; 84664416Sbostic break; 84764416Sbostic } 84864416Sbostic case TIOCSWINSZ: /* set window size */ 84964416Sbostic if (bcmp((caddr_t)&tp->t_winsize, data, 85064416Sbostic sizeof (struct winsize))) { 85164416Sbostic tp->t_winsize = *(struct winsize *)data; 85264416Sbostic pgsignal(tp->t_pgrp, SIGWINCH, 1); 85364416Sbostic } 85464416Sbostic break; 85564416Sbostic default: 85664416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 85764576Sbostic return (ttcompat(tp, cmd, data, flag)); 85864416Sbostic #else 85964416Sbostic return (-1); 86064416Sbostic #endif 86164416Sbostic } 86264416Sbostic return (0); 86364416Sbostic } 86464416Sbostic 86564416Sbostic int 86664416Sbostic ttselect(device, rw, p) 86764416Sbostic dev_t device; 86864416Sbostic int rw; 86964416Sbostic struct proc *p; 87064416Sbostic { 87164416Sbostic register struct tty *tp; 87264416Sbostic int nread, s; 87364416Sbostic 87464416Sbostic tp = &cdevsw[major(device)].d_ttys[minor(device)]; 87564416Sbostic 87664416Sbostic s = spltty(); 87764416Sbostic switch (rw) { 87864416Sbostic case FREAD: 87964416Sbostic nread = ttnread(tp); 88064416Sbostic if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) && 88164416Sbostic !ISSET(tp->t_state, TS_CARR_ON)) 88264416Sbostic goto win; 88364416Sbostic selrecord(p, &tp->t_rsel); 88464416Sbostic break; 88564416Sbostic case FWRITE: 88664416Sbostic if (tp->t_outq.c_cc <= tp->t_lowat) { 88764416Sbostic win: splx(s); 88864416Sbostic return (1); 88964416Sbostic } 89064416Sbostic selrecord(p, &tp->t_wsel); 89164416Sbostic break; 89264416Sbostic } 89364416Sbostic splx(s); 89464416Sbostic return (0); 89564416Sbostic } 89664416Sbostic 89764416Sbostic static int 89864416Sbostic ttnread(tp) 89964416Sbostic struct tty *tp; 90064416Sbostic { 90164416Sbostic int nread; 90264416Sbostic 90364416Sbostic if (ISSET(tp->t_lflag, PENDIN)) 90464416Sbostic ttypend(tp); 90564416Sbostic nread = tp->t_canq.c_cc; 90664416Sbostic if (!ISSET(tp->t_lflag, ICANON)) 90764416Sbostic nread += tp->t_rawq.c_cc; 90864416Sbostic return (nread); 90964416Sbostic } 91064416Sbostic 91164416Sbostic /* 91264416Sbostic * Wait for output to drain. 91364416Sbostic */ 91464416Sbostic int 91564416Sbostic ttywait(tp) 91664416Sbostic register struct tty *tp; 91764416Sbostic { 91864416Sbostic int error, s; 91964416Sbostic 92064416Sbostic error = 0; 92164416Sbostic s = spltty(); 92264416Sbostic while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 92364416Sbostic (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) 92464416Sbostic && tp->t_oproc) { 92564416Sbostic (*tp->t_oproc)(tp); 92664416Sbostic SET(tp->t_state, TS_ASLEEP); 92764416Sbostic if (error = ttysleep(tp, 92864416Sbostic &tp->t_outq, TTOPRI | PCATCH, ttyout, 0)) 92964416Sbostic break; 93064416Sbostic } 93164416Sbostic splx(s); 93264416Sbostic return (error); 93364416Sbostic } 93464416Sbostic 93564416Sbostic /* 93664416Sbostic * Flush if successfully wait. 93764416Sbostic */ 93864416Sbostic int 93964416Sbostic ttywflush(tp) 94064416Sbostic struct tty *tp; 94164416Sbostic { 94264416Sbostic int error; 94364416Sbostic 94464416Sbostic if ((error = ttywait(tp)) == 0) 94564416Sbostic ttyflush(tp, FREAD); 94664416Sbostic return (error); 94764416Sbostic } 94864416Sbostic 94964416Sbostic /* 95064416Sbostic * Flush tty read and/or write queues, notifying anyone waiting. 95164416Sbostic */ 95264416Sbostic void 95364416Sbostic ttyflush(tp, rw) 95464416Sbostic register struct tty *tp; 95564416Sbostic int rw; 95664416Sbostic { 95764416Sbostic register int s; 95864416Sbostic 95964416Sbostic s = spltty(); 96064416Sbostic if (rw & FREAD) { 96164416Sbostic FLUSHQ(&tp->t_canq); 96264416Sbostic FLUSHQ(&tp->t_rawq); 96364416Sbostic tp->t_rocount = 0; 96464416Sbostic tp->t_rocol = 0; 96564416Sbostic CLR(tp->t_state, TS_LOCAL); 96664416Sbostic ttwakeup(tp); 96764416Sbostic } 96864416Sbostic if (rw & FWRITE) { 96964416Sbostic CLR(tp->t_state, TS_TTSTOP); 97064416Sbostic #ifdef sun4c /* XXX */ 97164416Sbostic (*tp->t_stop)(tp, rw); 97264416Sbostic #else 97364416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 97464416Sbostic #endif 97564416Sbostic FLUSHQ(&tp->t_outq); 97664416Sbostic wakeup((caddr_t)&tp->t_outq); 97764416Sbostic selwakeup(&tp->t_wsel); 97864416Sbostic } 97964416Sbostic splx(s); 98064416Sbostic } 98164416Sbostic 98264416Sbostic /* 98364416Sbostic * Copy in the default termios characters. 98464416Sbostic */ 98564416Sbostic void 98664416Sbostic ttychars(tp) 98764416Sbostic struct tty *tp; 98864416Sbostic { 98964416Sbostic 99064416Sbostic bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 99164416Sbostic } 99264416Sbostic 99364416Sbostic /* 99464416Sbostic * Send stop character on input overflow. 99564416Sbostic */ 99664416Sbostic static void 99764416Sbostic ttyblock(tp) 99864416Sbostic register struct tty *tp; 99964416Sbostic { 100064416Sbostic register int total; 100164416Sbostic 100264416Sbostic total = tp->t_rawq.c_cc + tp->t_canq.c_cc; 100364416Sbostic if (tp->t_rawq.c_cc > TTYHOG) { 100464416Sbostic ttyflush(tp, FREAD | FWRITE); 100564416Sbostic CLR(tp->t_state, TS_TBLOCK); 100664416Sbostic } 100764416Sbostic /* 100864416Sbostic * Block further input iff: current input > threshold 100964416Sbostic * AND input is available to user program. 101064416Sbostic */ 101164416Sbostic if (total >= TTYHOG / 2 && 101264416Sbostic !ISSET(tp->t_state, TS_TBLOCK) && 101364416Sbostic !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 && 101464416Sbostic tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 101564416Sbostic if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 101664416Sbostic SET(tp->t_state, TS_TBLOCK); 101764416Sbostic ttstart(tp); 101864416Sbostic } 101964416Sbostic } 102064416Sbostic } 102164416Sbostic 102264416Sbostic void 102364416Sbostic ttrstrt(tp_arg) 102464416Sbostic void *tp_arg; 102564416Sbostic { 102664416Sbostic struct tty *tp; 102764416Sbostic int s; 102864416Sbostic 102964416Sbostic #ifdef DIAGNOSTIC 103064416Sbostic if (tp_arg == NULL) 103164416Sbostic panic("ttrstrt"); 103264416Sbostic #endif 103364416Sbostic tp = tp_arg; 103464416Sbostic s = spltty(); 103564416Sbostic 103664416Sbostic CLR(tp->t_state, TS_TIMEOUT); 103764416Sbostic ttstart(tp); 103864416Sbostic 103964416Sbostic splx(s); 104064416Sbostic } 104164416Sbostic 104264416Sbostic int 104364416Sbostic ttstart(tp) 104464416Sbostic struct tty *tp; 104564416Sbostic { 104664416Sbostic 104764416Sbostic if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 104864416Sbostic (*tp->t_oproc)(tp); 104964416Sbostic return (0); 105064416Sbostic } 105164416Sbostic 105264416Sbostic /* 105364416Sbostic * "close" a line discipline 105464416Sbostic */ 105564416Sbostic int 105664416Sbostic ttylclose(tp, flag) 105764416Sbostic struct tty *tp; 105864416Sbostic int flag; 105964416Sbostic { 106064416Sbostic 106164416Sbostic if (flag & IO_NDELAY) 106264416Sbostic ttyflush(tp, FREAD | FWRITE); 106364416Sbostic else 106464416Sbostic ttywflush(tp); 106564416Sbostic return (0); 106664416Sbostic } 106764416Sbostic 106864416Sbostic /* 106964416Sbostic * Handle modem control transition on a tty. 107064416Sbostic * Flag indicates new state of carrier. 107164416Sbostic * Returns 0 if the line should be turned off, otherwise 1. 107264416Sbostic */ 107364416Sbostic int 107464416Sbostic ttymodem(tp, flag) 107564416Sbostic register struct tty *tp; 107664416Sbostic int flag; 107764416Sbostic { 107864416Sbostic 107964416Sbostic if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) { 108064416Sbostic /* 108164416Sbostic * MDMBUF: do flow control according to carrier flag 108264416Sbostic */ 108364416Sbostic if (flag) { 108464416Sbostic CLR(tp->t_state, TS_TTSTOP); 108564416Sbostic ttstart(tp); 108664416Sbostic } else if (!ISSET(tp->t_state, TS_TTSTOP)) { 108764416Sbostic SET(tp->t_state, TS_TTSTOP); 108864416Sbostic #ifdef sun4c /* XXX */ 108964416Sbostic (*tp->t_stop)(tp, 0); 109064416Sbostic #else 109164416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 109264416Sbostic #endif 109364416Sbostic } 109464416Sbostic } else if (flag == 0) { 109564416Sbostic /* 109664416Sbostic * Lost carrier. 109764416Sbostic */ 109864416Sbostic CLR(tp->t_state, TS_CARR_ON); 109964416Sbostic if (ISSET(tp->t_state, TS_ISOPEN) && 110064416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 110164416Sbostic if (tp->t_session && tp->t_session->s_leader) 110264416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 110364416Sbostic ttyflush(tp, FREAD | FWRITE); 110464416Sbostic return (0); 110564416Sbostic } 110664416Sbostic } else { 110764416Sbostic /* 110864416Sbostic * Carrier now on. 110964416Sbostic */ 111064416Sbostic SET(tp->t_state, TS_CARR_ON); 111164416Sbostic ttwakeup(tp); 111264416Sbostic } 111364416Sbostic return (1); 111464416Sbostic } 111564416Sbostic 111664416Sbostic /* 111764416Sbostic * Default modem control routine (for other line disciplines). 111864416Sbostic * Return argument flag, to turn off device on carrier drop. 111964416Sbostic */ 112064416Sbostic int 112164416Sbostic nullmodem(tp, flag) 112264416Sbostic register struct tty *tp; 112364416Sbostic int flag; 112464416Sbostic { 112564416Sbostic 112664416Sbostic if (flag) 112764416Sbostic SET(tp->t_state, TS_CARR_ON); 112864416Sbostic else { 112964416Sbostic CLR(tp->t_state, TS_CARR_ON); 113064416Sbostic if (!ISSET(tp->t_cflag, CLOCAL)) { 113164416Sbostic if (tp->t_session && tp->t_session->s_leader) 113264416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 113364416Sbostic return (0); 113464416Sbostic } 113564416Sbostic } 113664416Sbostic return (1); 113764416Sbostic } 113864416Sbostic 113964416Sbostic /* 114064416Sbostic * Reinput pending characters after state switch 114164416Sbostic * call at spltty(). 114264416Sbostic */ 114364416Sbostic void 114464416Sbostic ttypend(tp) 114564416Sbostic register struct tty *tp; 114664416Sbostic { 114764416Sbostic struct clist tq; 114864416Sbostic register c; 114964416Sbostic 115064416Sbostic CLR(tp->t_lflag, PENDIN); 115164416Sbostic SET(tp->t_state, TS_TYPEN); 115264416Sbostic tq = tp->t_rawq; 115364416Sbostic tp->t_rawq.c_cc = 0; 115464416Sbostic tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 115564416Sbostic while ((c = getc(&tq)) >= 0) 115664416Sbostic ttyinput(c, tp); 115764416Sbostic CLR(tp->t_state, TS_TYPEN); 115864416Sbostic } 115964416Sbostic 116064416Sbostic /* 116149380Skarels * Process a read call on a tty device. 11627502Sroot */ 116364416Sbostic int 116437584Smarc ttread(tp, uio, flag) 11657625Ssam register struct tty *tp; 11667722Swnj struct uio *uio; 116752485Storek int flag; 11687502Sroot { 11697502Sroot register struct clist *qp; 117035811Smarc register int c; 117141383Smarc register long lflag; 117235811Smarc register u_char *cc = tp->t_cc; 117347545Skarels register struct proc *p = curproc; 11749859Ssam int s, first, error = 0; 11757502Sroot 117664416Sbostic loop: lflag = tp->t_lflag; 117737584Smarc s = spltty(); 11789578Ssam /* 117964416Sbostic * take pending input first 11809578Ssam */ 118164416Sbostic if (ISSET(lflag, PENDIN)) 11827502Sroot ttypend(tp); 11839859Ssam splx(s); 118440712Skarels 11859578Ssam /* 11869578Ssam * Hang process if it's in the background. 11879578Ssam */ 118847545Skarels if (isbackground(p, tp)) { 118947545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 119047545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 119164576Sbostic p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) 11928520Sroot return (EIO); 119347545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 119464416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 119540712Skarels return (error); 119623165Sbloom goto loop; 11977502Sroot } 119840712Skarels 11999578Ssam /* 120035811Smarc * If canonical, use the canonical queue, 120135811Smarc * else use the raw queue. 120237584Smarc * 120347545Skarels * (should get rid of clists...) 12049578Ssam */ 120564416Sbostic qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 120640712Skarels 12079578Ssam /* 120840712Skarels * If there is no input, sleep on rawq 120940712Skarels * awaiting hardware receipt and notification. 121040712Skarels * If we have data, we don't need to check for carrier. 12119578Ssam */ 121217545Skarels s = spltty(); 12139578Ssam if (qp->c_cc <= 0) { 121440712Skarels int carrier; 121540712Skarels 121664416Sbostic carrier = ISSET(tp->t_state, TS_CARR_ON) || 121764416Sbostic ISSET(tp->t_cflag, CLOCAL); 121864416Sbostic if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { 12199859Ssam splx(s); 122040712Skarels return (0); /* EOF */ 12217502Sroot } 122237728Smckusick if (flag & IO_NDELAY) { 122337584Smarc splx(s); 122437584Smarc return (EWOULDBLOCK); 122537584Smarc } 122664416Sbostic error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, 122740712Skarels carrier ? ttyin : ttopen, 0); 12289859Ssam splx(s); 122943377Smarc if (error) 123040712Skarels return (error); 12319578Ssam goto loop; 12329578Ssam } 12339859Ssam splx(s); 123440712Skarels 12359578Ssam /* 123635811Smarc * Input present, check for input mapping and processing. 12379578Ssam */ 12389578Ssam first = 1; 12399578Ssam while ((c = getc(qp)) >= 0) { 12409578Ssam /* 124135811Smarc * delayed suspend (^Y) 12429578Ssam */ 124364416Sbostic if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) { 124442882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12459578Ssam if (first) { 124664416Sbostic if (error = ttysleep(tp, 124764416Sbostic &lbolt, TTIPRI | PCATCH, ttybg, 0)) 124840712Skarels break; 12499578Ssam goto loop; 12509578Ssam } 12519578Ssam break; 12527502Sroot } 12539578Ssam /* 125435811Smarc * Interpret EOF only in canonical mode. 12559578Ssam */ 125664416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON)) 12579578Ssam break; 12589578Ssam /* 12599578Ssam * Give user character. 12609578Ssam */ 126140712Skarels error = ureadc(c, uio); 12629578Ssam if (error) 12639578Ssam break; 126414938Smckusick if (uio->uio_resid == 0) 12659578Ssam break; 12669578Ssam /* 126735811Smarc * In canonical mode check for a "break character" 12689578Ssam * marking the end of a "line of input". 12699578Ssam */ 127064416Sbostic if (ISSET(lflag, ICANON) && TTBREAKC(c)) 12719578Ssam break; 12729578Ssam first = 0; 12737502Sroot } 12749578Ssam /* 12759578Ssam * Look to unblock output now that (presumably) 12769578Ssam * the input queue has gone down. 12779578Ssam */ 127852485Storek s = spltty(); 127964416Sbostic if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) { 128047545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 128147545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 128264416Sbostic CLR(tp->t_state, TS_TBLOCK); 12837502Sroot ttstart(tp); 12847502Sroot } 128535811Smarc } 128652485Storek splx(s); 12878520Sroot return (error); 12887502Sroot } 12897502Sroot 12907502Sroot /* 129164416Sbostic * Check the output queue on tp for space for a kernel message (from uprintf 129264416Sbostic * or tprintf). Allow some space over the normal hiwater mark so we don't 129364416Sbostic * lose messages due to normal flow control, but don't let the tty run amok. 129464416Sbostic * Sleeps here are not interruptible, but we return prematurely if new signals 129564416Sbostic * arrive. 129625391Skarels */ 129764416Sbostic int 129825391Skarels ttycheckoutq(tp, wait) 129925391Skarels register struct tty *tp; 130025391Skarels int wait; 130125391Skarels { 130230695Skarels int hiwat, s, oldsig; 130325391Skarels 130435811Smarc hiwat = tp->t_hiwat; 130525391Skarels s = spltty(); 130664576Sbostic oldsig = wait ? curproc->p_siglist : 0; 130725391Skarels if (tp->t_outq.c_cc > hiwat + 200) 130829946Skarels while (tp->t_outq.c_cc > hiwat) { 130929946Skarels ttstart(tp); 131064576Sbostic if (wait == 0 || curproc->p_siglist != oldsig) { 131129946Skarels splx(s); 131229946Skarels return (0); 131329946Skarels } 131454782Storek timeout((void (*)__P((void *)))wakeup, 131554782Storek (void *)&tp->t_outq, hz); 131664416Sbostic SET(tp->t_state, TS_ASLEEP); 131730695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 131825391Skarels } 131925391Skarels splx(s); 132025391Skarels return (1); 132125391Skarels } 132225391Skarels 132325391Skarels /* 132449380Skarels * Process a write call on a tty device. 13257502Sroot */ 132664416Sbostic int 132737584Smarc ttwrite(tp, uio, flag) 13287625Ssam register struct tty *tp; 13299578Ssam register struct uio *uio; 133052485Storek int flag; 13317502Sroot { 13327502Sroot register char *cp; 133364416Sbostic register int cc, ce; 133464416Sbostic register struct proc *p; 13359578Ssam int i, hiwat, cnt, error, s; 13367502Sroot char obuf[OBUFSIZ]; 13377502Sroot 133835811Smarc hiwat = tp->t_hiwat; 13399578Ssam cnt = uio->uio_resid; 13409578Ssam error = 0; 134164878Smckusick cc = 0; 13427502Sroot loop: 134337584Smarc s = spltty(); 134464416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 134564416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 134664416Sbostic if (ISSET(tp->t_state, TS_ISOPEN)) { 134737584Smarc splx(s); 134837584Smarc return (EIO); 134937728Smckusick } else if (flag & IO_NDELAY) { 135037584Smarc splx(s); 135140712Skarels error = EWOULDBLOCK; 135240712Skarels goto out; 135337584Smarc } else { 135464416Sbostic /* Sleep awaiting carrier. */ 135564416Sbostic error = ttysleep(tp, 135664416Sbostic &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0); 135737584Smarc splx(s); 135843377Smarc if (error) 135940712Skarels goto out; 136037584Smarc goto loop; 136137584Smarc } 136237584Smarc } 136337584Smarc splx(s); 13649578Ssam /* 13659578Ssam * Hang the process if it's in the background. 13669578Ssam */ 136764416Sbostic p = curproc; 136864416Sbostic if (isbackground(p, tp) && 136964576Sbostic ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 && 137047545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 137147545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 137247545Skarels p->p_pgrp->pg_jobc) { 137347545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 137464416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 137540712Skarels goto out; 137621776Sbloom goto loop; 13777502Sroot } 13789578Ssam /* 137964416Sbostic * Process the user's data in at most OBUFSIZ chunks. Perform any 138064416Sbostic * output translation. Keep track of high water mark, sleep on 138164416Sbostic * overflow awaiting device aid in acquiring new space. 13829578Ssam */ 138364878Smckusick while (uio->uio_resid > 0 || cc > 0) { 138464416Sbostic if (ISSET(tp->t_lflag, FLUSHO)) { 138540712Skarels uio->uio_resid = 0; 138640712Skarels return (0); 138740712Skarels } 138840712Skarels if (tp->t_outq.c_cc > hiwat) 138932067Skarels goto ovhiwat; 13909578Ssam /* 139164416Sbostic * Grab a hunk of data from the user, unless we have some 139264416Sbostic * leftover from last time. 13939578Ssam */ 13947822Sroot if (cc == 0) { 139540712Skarels cc = min(uio->uio_resid, OBUFSIZ); 139640712Skarels cp = obuf; 139740712Skarels error = uiomove(cp, cc, uio); 139840712Skarels if (error) { 139940712Skarels cc = 0; 140040712Skarels break; 140140712Skarels } 14027822Sroot } 14039578Ssam /* 14049578Ssam * If nothing fancy need be done, grab those characters we 14059578Ssam * can handle without any of ttyoutput's processing and 14069578Ssam * just transfer them to the output q. For those chars 14079578Ssam * which require special processing (as indicated by the 140864416Sbostic * bits in char_type), call ttyoutput. After processing 14099578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14109578Ssam * immediately. 14119578Ssam */ 14129578Ssam while (cc > 0) { 141364416Sbostic if (!ISSET(tp->t_oflag, OPOST)) 14147502Sroot ce = cc; 14157502Sroot else { 141664416Sbostic ce = cc - scanc((u_int)cc, (u_char *)cp, 141764416Sbostic (u_char *)char_type, CCLASSMASK); 14189578Ssam /* 14199578Ssam * If ce is zero, then we're processing 14209578Ssam * a special character through ttyoutput. 14219578Ssam */ 14229578Ssam if (ce == 0) { 14237502Sroot tp->t_rocount = 0; 14247502Sroot if (ttyoutput(*cp, tp) >= 0) { 142564416Sbostic /* No Clists, wait a bit. */ 142664416Sbostic ttstart(tp); 142764416Sbostic if (error = ttysleep(tp, &lbolt, 142864416Sbostic TTOPRI | PCATCH, ttybuf, 0)) 142964416Sbostic break; 143064416Sbostic goto loop; 14317502Sroot } 143264416Sbostic cp++; 143364416Sbostic cc--; 143464416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 14359578Ssam tp->t_outq.c_cc > hiwat) 14367502Sroot goto ovhiwat; 14379578Ssam continue; 14387502Sroot } 14397502Sroot } 14409578Ssam /* 144164416Sbostic * A bunch of normal characters have been found. 144264416Sbostic * Transfer them en masse to the output queue and 14439578Ssam * continue processing at the top of the loop. 14449578Ssam * If there are any further characters in this 14459578Ssam * <= OBUFSIZ chunk, the first should be a character 14469578Ssam * requiring special handling by ttyoutput. 14479578Ssam */ 14487502Sroot tp->t_rocount = 0; 14499578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14509578Ssam ce -= i; 145164530Sbostic tp->t_column += ce; 14529578Ssam cp += ce, cc -= ce, tk_nout += ce; 145335811Smarc tp->t_outcc += ce; 14549578Ssam if (i > 0) { 145564416Sbostic /* No Clists, wait a bit. */ 14567502Sroot ttstart(tp); 145764416Sbostic if (error = ttysleep(tp, 145864416Sbostic &lbolt, TTOPRI | PCATCH, ttybuf, 0)) 145940712Skarels break; 146021776Sbloom goto loop; 14617502Sroot } 146264416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 146364416Sbostic tp->t_outq.c_cc > hiwat) 146440712Skarels break; 14657502Sroot } 146635811Smarc ttstart(tp); 14677502Sroot } 146840712Skarels out: 146940712Skarels /* 147064416Sbostic * If cc is nonzero, we leave the uio structure inconsistent, as the 147164416Sbostic * offset and iov pointers have moved forward, but it doesn't matter 147264416Sbostic * (the call will either return short or restart with a new uio). 147340712Skarels */ 147440712Skarels uio->uio_resid += cc; 14758520Sroot return (error); 147640712Skarels 14777502Sroot ovhiwat: 147832067Skarels ttstart(tp); 147932067Skarels s = spltty(); 14809578Ssam /* 148135811Smarc * This can only occur if FLUSHO is set in t_lflag, 148232067Skarels * or if ttstart/oproc is synchronous (or very fast). 14839578Ssam */ 14847502Sroot if (tp->t_outq.c_cc <= hiwat) { 14859578Ssam splx(s); 14867502Sroot goto loop; 14877502Sroot } 148837728Smckusick if (flag & IO_NDELAY) { 148917545Skarels splx(s); 149040712Skarels uio->uio_resid += cc; 149164416Sbostic return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 14927502Sroot } 149364416Sbostic SET(tp->t_state, TS_ASLEEP); 149464416Sbostic error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14959578Ssam splx(s); 149643377Smarc if (error) 149740712Skarels goto out; 14987502Sroot goto loop; 14997502Sroot } 15007502Sroot 15017502Sroot /* 15027502Sroot * Rubout one character from the rawq of tp 15037502Sroot * as cleanly as possible. 15047502Sroot */ 150564416Sbostic void 15067502Sroot ttyrub(c, tp) 150764416Sbostic register int c; 15087625Ssam register struct tty *tp; 15097502Sroot { 15107502Sroot register char *cp; 15117502Sroot register int savecol; 151264416Sbostic int tabc, s; 15137502Sroot 151464416Sbostic if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 15157502Sroot return; 151664416Sbostic CLR(tp->t_lflag, FLUSHO); 151764416Sbostic if (ISSET(tp->t_lflag, ECHOE)) { 15187502Sroot if (tp->t_rocount == 0) { 15197502Sroot /* 15207502Sroot * Screwed by ttwrite; retype 15217502Sroot */ 15227502Sroot ttyretype(tp); 15237502Sroot return; 15247502Sroot } 152564416Sbostic if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 15267502Sroot ttyrubo(tp, 2); 152764576Sbostic else { 152864576Sbostic CLR(c, ~TTY_CHARMASK); 152964576Sbostic switch (CCLASS(c)) { 153064576Sbostic case ORDINARY: 153164576Sbostic ttyrubo(tp, 1); 153264576Sbostic break; 153364576Sbostic case BACKSPACE: 153464576Sbostic case CONTROL: 153564576Sbostic case NEWLINE: 153664576Sbostic case RETURN: 153764576Sbostic case VTAB: 153864576Sbostic if (ISSET(tp->t_lflag, ECHOCTL)) 153964576Sbostic ttyrubo(tp, 2); 154064576Sbostic break; 154164576Sbostic case TAB: 154264576Sbostic if (tp->t_rocount < tp->t_rawq.c_cc) { 154364576Sbostic ttyretype(tp); 154464576Sbostic return; 154564576Sbostic } 154664576Sbostic s = spltty(); 154764576Sbostic savecol = tp->t_column; 154864576Sbostic SET(tp->t_state, TS_CNTTB); 154964576Sbostic SET(tp->t_lflag, FLUSHO); 155064576Sbostic tp->t_column = tp->t_rocol; 155164576Sbostic cp = tp->t_rawq.c_cf; 155264576Sbostic if (cp) 155364576Sbostic tabc = *cp; /* XXX FIX NEXTC */ 155464576Sbostic for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 155564576Sbostic ttyecho(tabc, tp); 155664576Sbostic CLR(tp->t_lflag, FLUSHO); 155764576Sbostic CLR(tp->t_state, TS_CNTTB); 155864576Sbostic splx(s); 155964416Sbostic 156064576Sbostic /* savecol will now be length of the tab. */ 156164576Sbostic savecol -= tp->t_column; 156264576Sbostic tp->t_column += savecol; 156364576Sbostic if (savecol > 8) 156464576Sbostic savecol = 8; /* overflow screw */ 156564576Sbostic while (--savecol >= 0) 156664576Sbostic (void)ttyoutput('\b', tp); 156764576Sbostic break; 156864576Sbostic default: /* XXX */ 156964416Sbostic #define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 157064576Sbostic (void)printf(PANICSTR, c, CCLASS(c)); 157164416Sbostic #ifdef notdef 157264576Sbostic panic(PANICSTR, c, CCLASS(c)); 157364416Sbostic #endif 157464576Sbostic } 157535811Smarc } 157664416Sbostic } else if (ISSET(tp->t_lflag, ECHOPRT)) { 157764416Sbostic if (!ISSET(tp->t_state, TS_ERASE)) { 157864416Sbostic SET(tp->t_state, TS_ERASE); 157964416Sbostic (void)ttyoutput('\\', tp); 15807502Sroot } 15817502Sroot ttyecho(c, tp); 15827502Sroot } else 158335811Smarc ttyecho(tp->t_cc[VERASE], tp); 158464416Sbostic --tp->t_rocount; 15857502Sroot } 15867502Sroot 15877502Sroot /* 158864416Sbostic * Back over cnt characters, erasing them. 15897502Sroot */ 159064416Sbostic static void 15917502Sroot ttyrubo(tp, cnt) 15927625Ssam register struct tty *tp; 15937625Ssam int cnt; 15947502Sroot { 15957502Sroot 159664416Sbostic while (cnt-- > 0) { 159764416Sbostic (void)ttyoutput('\b', tp); 159864416Sbostic (void)ttyoutput(' ', tp); 159964416Sbostic (void)ttyoutput('\b', tp); 160064416Sbostic } 16017502Sroot } 16027502Sroot 16037502Sroot /* 160464416Sbostic * ttyretype -- 160564416Sbostic * Reprint the rawq line. Note, it is assumed that c_cc has already 160664416Sbostic * been checked. 16077502Sroot */ 160864416Sbostic void 16097502Sroot ttyretype(tp) 16107625Ssam register struct tty *tp; 16117502Sroot { 16127502Sroot register char *cp; 161335811Smarc int s, c; 16147502Sroot 161564416Sbostic /* Echo the reprint character. */ 161635811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 161735811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 161864416Sbostic 161964416Sbostic (void)ttyoutput('\n', tp); 162064416Sbostic 162164416Sbostic /* 162264416Sbostic * XXX 162364416Sbostic * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 162464416Sbostic * BIT OF FIRST CHAR. 162564416Sbostic */ 162617545Skarels s = spltty(); 162764416Sbostic for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 162864416Sbostic cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 162935811Smarc ttyecho(c, tp); 163064416Sbostic for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 163164416Sbostic cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 163235811Smarc ttyecho(c, tp); 163364416Sbostic CLR(tp->t_state, TS_ERASE); 16347502Sroot splx(s); 163564416Sbostic 16367502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16377502Sroot tp->t_rocol = 0; 16387502Sroot } 16397502Sroot 16407502Sroot /* 164135811Smarc * Echo a typed character to the terminal. 16427502Sroot */ 164364416Sbostic static void 16447502Sroot ttyecho(c, tp) 164564416Sbostic register int c; 16467625Ssam register struct tty *tp; 16477502Sroot { 164864416Sbostic 164964416Sbostic if (!ISSET(tp->t_state, TS_CNTTB)) 165064416Sbostic CLR(tp->t_lflag, FLUSHO); 165164416Sbostic if ((!ISSET(tp->t_lflag, ECHO) && 165264416Sbostic (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) || 165364416Sbostic ISSET(tp->t_lflag, EXTPROC)) 16547502Sroot return; 165564416Sbostic if (ISSET(tp->t_lflag, ECHOCTL) && 165664576Sbostic (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 165764576Sbostic ISSET(c, TTY_CHARMASK) == 0177)) { 165864416Sbostic (void)ttyoutput('^', tp); 165964576Sbostic CLR(c, ~TTY_CHARMASK); 166064416Sbostic if (c == 0177) 166164416Sbostic c = '?'; 166264416Sbostic else 166364416Sbostic c += 'A' - 1; 16647502Sroot } 166564416Sbostic (void)ttyoutput(c, tp); 16667502Sroot } 16677502Sroot 16687502Sroot /* 166949380Skarels * Wake up any readers on a tty. 167049380Skarels */ 167164416Sbostic void 16727502Sroot ttwakeup(tp) 167347545Skarels register struct tty *tp; 16747502Sroot { 16757502Sroot 167652522Smckusick selwakeup(&tp->t_rsel); 167764416Sbostic if (ISSET(tp->t_state, TS_ASYNC)) 167864416Sbostic pgsignal(tp->t_pgrp, SIGIO, 1); 16797502Sroot wakeup((caddr_t)&tp->t_rawq); 16807502Sroot } 168135811Smarc 168235811Smarc /* 168348439Skarels * Look up a code for a specified speed in a conversion table; 168448439Skarels * used by drivers to map software speed values to hardware parameters. 168548439Skarels */ 168664416Sbostic int 168748439Skarels ttspeedtab(speed, table) 168852485Storek int speed; 168948439Skarels register struct speedtab *table; 169048439Skarels { 169148439Skarels 169248439Skarels for ( ; table->sp_speed != -1; table++) 169348439Skarels if (table->sp_speed == speed) 169448439Skarels return (table->sp_code); 169548439Skarels return (-1); 169648439Skarels } 169748439Skarels 169848439Skarels /* 169964416Sbostic * Set tty hi and low water marks. 170035811Smarc * 170135811Smarc * Try to arrange the dynamics so there's about one second 170235811Smarc * from hi to low water. 170364416Sbostic * 170435811Smarc */ 170564416Sbostic void 170635811Smarc ttsetwater(tp) 170735811Smarc struct tty *tp; 170835811Smarc { 170964416Sbostic register int cps, x; 171035811Smarc 171164416Sbostic #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 171264416Sbostic 171364416Sbostic cps = tp->t_ospeed / 10; 171464416Sbostic tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 171535811Smarc x += cps; 171664416Sbostic x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT); 171735811Smarc tp->t_hiwat = roundup(x, CBSIZE); 171864416Sbostic #undef CLAMP 171935811Smarc } 172035811Smarc 172139407Smarc /* 172239407Smarc * Report on state of foreground process group. 172339407Smarc */ 172464416Sbostic void 172539407Smarc ttyinfo(tp) 172649907Sbostic register struct tty *tp; 172739407Smarc { 172849907Sbostic register struct proc *p, *pick; 172941177Smarc struct timeval utime, stime; 173049907Sbostic int tmp; 173139407Smarc 173264416Sbostic if (ttycheckoutq(tp,0) == 0) 173339407Smarc return; 173449907Sbostic 173549907Sbostic /* Print load average. */ 173652666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 173749907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 173849907Sbostic 173939555Smarc if (tp->t_session == NULL) 174049907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 174141177Smarc else if (tp->t_pgrp == NULL) 174249907Sbostic ttyprintf(tp, "no foreground process group\n"); 174341177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 174449907Sbostic ttyprintf(tp, "empty foreground process group\n"); 174539407Smarc else { 174649907Sbostic /* Pick interesting process. */ 174749907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 174841177Smarc if (proc_compare(pick, p)) 174941177Smarc pick = p; 175049907Sbostic 175149907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 175249907Sbostic pick->p_stat == SRUN ? "running" : 175349907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 175449907Sbostic 175554782Storek calcru(pick, &utime, &stime, NULL); 175639407Smarc 175749907Sbostic /* Print user time. */ 175849907Sbostic ttyprintf(tp, "%d.%02du ", 175949907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 176041177Smarc 176149907Sbostic /* Print system time. */ 176249907Sbostic ttyprintf(tp, "%d.%02ds ", 176349907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 176449907Sbostic 176549907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 176649907Sbostic /* Print percentage cpu, resident set size. */ 176749907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 176849907Sbostic ttyprintf(tp, "%d%% %dk\n", 176952485Storek tmp / 100, 177052485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 177165549Smckusick #ifdef pmap_resident_count 177265549Smckusick pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap)) 177365549Smckusick #else 177465549Smckusick pgtok(pick->p_vmspace->vm_rssize) 177565549Smckusick #endif 177665549Smckusick ); 177741177Smarc } 177849907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 177941177Smarc } 178041177Smarc 178141177Smarc /* 178241177Smarc * Returns 1 if p2 is "better" than p1 178341177Smarc * 178441177Smarc * The algorithm for picking the "interesting" process is thus: 178541177Smarc * 178664576Sbostic * 1) Only foreground processes are eligible - implied. 178764576Sbostic * 2) Runnable processes are favored over anything else. The runner 178864576Sbostic * with the highest cpu utilization is picked (p_estcpu). Ties are 178941177Smarc * broken by picking the highest pid. 179064576Sbostic * 3) The sleeper with the shortest sleep time is next. With ties, 179164576Sbostic * we pick out just "short-term" sleepers (P_SINTR == 0). 179264576Sbostic * 4) Further ties are broken by picking the highest pid. 179341177Smarc */ 179464576Sbostic #define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 179545723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 179645723Smckusick #define ONLYA 2 179745723Smckusick #define ONLYB 1 179845723Smckusick #define BOTH 3 179964576Sbostic 180049907Sbostic static int 180141177Smarc proc_compare(p1, p2) 180241177Smarc register struct proc *p1, *p2; 180341177Smarc { 180441177Smarc 180541177Smarc if (p1 == NULL) 180641177Smarc return (1); 180741177Smarc /* 180841177Smarc * see if at least one of them is runnable 180941177Smarc */ 181064576Sbostic switch (TESTAB(ISRUN(p1), ISRUN(p2))) { 181145723Smckusick case ONLYA: 181245723Smckusick return (0); 181345723Smckusick case ONLYB: 181441177Smarc return (1); 181545723Smckusick case BOTH: 181641177Smarc /* 181741177Smarc * tie - favor one with highest recent cpu utilization 181841177Smarc */ 181964576Sbostic if (p2->p_estcpu > p1->p_estcpu) 182041177Smarc return (1); 182164576Sbostic if (p1->p_estcpu > p2->p_estcpu) 182241177Smarc return (0); 182341177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182441177Smarc } 182545723Smckusick /* 182645723Smckusick * weed out zombies 182745723Smckusick */ 182845723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 182945723Smckusick case ONLYA: 183045723Smckusick return (1); 183145723Smckusick case ONLYB: 183245723Smckusick return (0); 183345723Smckusick case BOTH: 183445723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183545723Smckusick } 183664416Sbostic /* 183741177Smarc * pick the one with the smallest sleep time 183841177Smarc */ 183941177Smarc if (p2->p_slptime > p1->p_slptime) 184041177Smarc return (0); 184141177Smarc if (p1->p_slptime > p2->p_slptime) 184241177Smarc return (1); 184341177Smarc /* 184441177Smarc * favor one sleeping in a non-interruptible sleep 184541177Smarc */ 184664576Sbostic if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0) 184741177Smarc return (1); 184864576Sbostic if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0) 184941177Smarc return (0); 185047545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 185141177Smarc } 185245723Smckusick 185339555Smarc /* 185439555Smarc * Output char to tty; console putchar style. 185539555Smarc */ 185664416Sbostic int 185739555Smarc tputchar(c, tp) 185839555Smarc int c; 185939555Smarc struct tty *tp; 186039555Smarc { 186164416Sbostic register int s; 186239555Smarc 186364416Sbostic s = spltty(); 186464416Sbostic if (ISSET(tp->t_state, 186564416Sbostic TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) { 186639555Smarc splx(s); 186764416Sbostic return (-1); 186839555Smarc } 186964416Sbostic if (c == '\n') 187064416Sbostic (void)ttyoutput('\r', tp); 187164416Sbostic (void)ttyoutput(c, tp); 187264416Sbostic ttstart(tp); 187339555Smarc splx(s); 187464416Sbostic return (0); 187539555Smarc } 187643377Smarc 187744419Smarc /* 187864416Sbostic * Sleep on chan, returning ERESTART if tty changed while we napped and 187964416Sbostic * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If 188064416Sbostic * the tty is revoked, restarting a pending call will redo validation done 188164416Sbostic * at the start of the call. 188244419Smarc */ 188364416Sbostic int 188443377Smarc ttysleep(tp, chan, pri, wmesg, timo) 188543377Smarc struct tty *tp; 188664416Sbostic void *chan; 188764416Sbostic int pri, timo; 188843377Smarc char *wmesg; 188943377Smarc { 189043377Smarc int error; 189164416Sbostic short gen; 189243377Smarc 189364416Sbostic gen = tp->t_gen; 189443377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 189543377Smarc return (error); 189664416Sbostic return (tp->t_gen == gen ? 0 : ERESTART); 189743377Smarc } 1898