149594Sbostic /*- 263178Sbostic * Copyright (c) 1982, 1986, 1990, 1991, 1993 363178Sbostic * The Regents of the University of California. All rights reserved. 449594Sbostic * All rights reserved. 523387Smckusick * 649594Sbostic * %sccs.include.redist.c% 749594Sbostic * 8*64576Sbostic * @(#)tty.c 8.4 (Berkeley) 09/23/93 923387Smckusick */ 1039Sbill 1156517Sbostic #include <sys/param.h> 1256517Sbostic #include <sys/systm.h> 1356517Sbostic #include <sys/ioctl.h> 1456517Sbostic #include <sys/proc.h> 1564416Sbostic #define TTYDEFCHARS 1656517Sbostic #include <sys/tty.h> 1764416Sbostic #undef TTYDEFCHARS 1856517Sbostic #include <sys/file.h> 1956517Sbostic #include <sys/conf.h> 2056517Sbostic #include <sys/dkstat.h> 2156517Sbostic #include <sys/uio.h> 2256517Sbostic #include <sys/kernel.h> 2356517Sbostic #include <sys/vnode.h> 2456517Sbostic #include <sys/syslog.h> 2539Sbill 2656517Sbostic #include <vm/vm.h> 2737525Smckusick 2864416Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2)); 2964416Sbostic static int ttnread __P((struct tty *)); 3064416Sbostic static void ttyblock __P((struct tty *tp)); 3164416Sbostic static void ttyecho __P((int, struct tty *tp)); 3264416Sbostic static void ttyrubo __P((struct tty *, int)); 3349907Sbostic 3464416Sbostic /* Symbolic sleep message strings. */ 3564416Sbostic char ttclos[] = "ttycls"; 3664416Sbostic char ttopen[] = "ttyopn"; 3764416Sbostic char ttybg[] = "ttybg"; 3864416Sbostic char ttybuf[] = "ttybuf"; 3964416Sbostic char ttyin[] = "ttyin"; 4064416Sbostic char ttyout[] = "ttyout"; 4140712Skarels 427436Skre /* 4364416Sbostic * Table with character classes and parity. The 8th bit indicates parity, 4464416Sbostic * the 7th bit indicates the character is an alphameric or underscore (for 4564416Sbostic * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits 4664416Sbostic * are 0 then the character needs no special processing on output; classes 4764416Sbostic * other than 0 might be translated or (not currently) require delays. 487436Skre */ 4964416Sbostic #define E 0x00 /* Even parity. */ 5064416Sbostic #define O 0x80 /* Odd parity. */ 5164416Sbostic #define PARITY(c) (char_type[c] & O) 5264416Sbostic 5364416Sbostic #define ALPHA 0x40 /* Alpha or underscore. */ 5464416Sbostic #define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA) 5564416Sbostic 5649380Skarels #define CCLASSMASK 0x3f 5764416Sbostic #define CCLASS(c) (char_type[c] & CCLASSMASK) 5839Sbill 5964416Sbostic #define BS BACKSPACE 6049380Skarels #define CC CONTROL 6164416Sbostic #define CR RETURN 6264416Sbostic #define NA ORDINARY | ALPHA 6349380Skarels #define NL NEWLINE 6464416Sbostic #define NO ORDINARY 6549380Skarels #define TB TAB 6649380Skarels #define VT VTAB 6749380Skarels 6864416Sbostic char const char_type[] = { 6949380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 7049380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 7149380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 7249380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 7349380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 7449380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 7549380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 7649380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 7749380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 7849380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 7949380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 8049380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 8149380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 8249380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 8349380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 8449380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 857436Skre /* 8664416Sbostic * Meta chars; should be settable per character set; 8764416Sbostic * for now, treat them all as normal characters. 887436Skre */ 8949380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9049380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9149380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9249380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9349380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9449380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9549380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9649380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9749380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9849380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9949380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10049380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10149380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10249380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10349380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10449380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 1057436Skre }; 10664416Sbostic #undef BS 10764416Sbostic #undef CC 10864416Sbostic #undef CR 10949380Skarels #undef NA 11049380Skarels #undef NL 11164416Sbostic #undef NO 11249380Skarels #undef TB 11349380Skarels #undef VT 1147436Skre 11564416Sbostic /* Macros to clear/set/test flags. */ 11664416Sbostic #define SET(t, f) (t) |= (f) 11764416Sbostic #define CLR(t, f) (t) &= ~(f) 11864416Sbostic #define ISSET(t, f) ((t) & (f)) 11935811Smarc 120146Sbill /* 12164416Sbostic * Initial open of tty, or (re)entry to standard tty line discipline. 12239Sbill */ 12364416Sbostic int 12464416Sbostic ttyopen(device, tp) 12564416Sbostic dev_t device; 12612752Ssam register struct tty *tp; 12712752Ssam { 12852485Storek int s; 12947545Skarels 13052485Storek s = spltty(); 13164416Sbostic tp->t_dev = device; 13264416Sbostic if (!ISSET(tp->t_state, TS_ISOPEN)) { 13364416Sbostic SET(tp->t_state, TS_ISOPEN); 13464416Sbostic bzero(&tp->t_winsize, sizeof(tp->t_winsize)); 135903Sbill } 13664416Sbostic CLR(tp->t_state, TS_WOPEN); 1375408Swnj splx(s); 1385408Swnj return (0); 1394484Swnj } 1407436Skre 1417502Sroot /* 14249380Skarels * Handle close() on a tty line: flush and set to initial state, 14349380Skarels * bumping generation number so that pending read/write calls 14449380Skarels * can detect recycling of the tty. 1457502Sroot */ 14664416Sbostic int 1477502Sroot ttyclose(tp) 1487625Ssam register struct tty *tp; 1497502Sroot { 15064416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 15164416Sbostic 15230534Skarels if (constty == tp) 15330534Skarels constty = NULL; 15464416Sbostic 15564416Sbostic ttyflush(tp, FREAD | FWRITE); 15664416Sbostic 15764416Sbostic tp->t_gen++; 15864416Sbostic tp->t_pgrp = NULL; 15939555Smarc tp->t_session = NULL; 1607502Sroot tp->t_state = 0; 16140712Skarels return (0); 1627502Sroot } 1637502Sroot 16464416Sbostic #define FLUSHQ(q) { \ 16564416Sbostic if ((q)->c_cc) \ 16664416Sbostic ndflush(q, (q)->c_cc); \ 16725391Skarels } 16825391Skarels 16964416Sbostic /* Is 'c' a line delimiter ("break" character)? */ 17064416Sbostic #define TTBREAKC(c) \ 17164416Sbostic ((c) == '\n' || ((c) == cc[VEOF] || \ 17264416Sbostic (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 17325404Skarels 1747502Sroot 1757502Sroot /* 17649380Skarels * Process input of a single character received on a tty. 1777502Sroot */ 17864416Sbostic int 1797502Sroot ttyinput(c, tp) 18064416Sbostic register int c; 1817625Ssam register struct tty *tp; 1827502Sroot { 18364416Sbostic register int iflag, lflag; 18464416Sbostic register u_char *cc; 18535811Smarc int i, err; 1867502Sroot 1879578Ssam /* 1889578Ssam * If input is pending take it first. 1899578Ssam */ 19064416Sbostic lflag = tp->t_lflag; 19164416Sbostic if (ISSET(lflag, PENDIN)) 1927502Sroot ttypend(tp); 19335811Smarc /* 19435811Smarc * Gather stats. 19535811Smarc */ 19664416Sbostic if (ISSET(lflag, ICANON)) { 19764416Sbostic ++tk_cancc; 19864416Sbostic ++tp->t_cancc; 19935811Smarc } else { 20064416Sbostic ++tk_rawcc; 20164416Sbostic ++tp->t_rawcc; 20235811Smarc } 20364416Sbostic ++tk_nin; 20464416Sbostic 20564416Sbostic /* Handle exceptional conditions (break, parity, framing). */ 20664416Sbostic cc = tp->t_cc; 20764416Sbostic iflag = tp->t_iflag; 208*64576Sbostic if (err = (ISSET(c, TTY_ERRORMASK))) { 209*64576Sbostic CLR(c, TTY_ERRORMASK); 210*64576Sbostic if (ISSET(err, TTY_FE) && !c) { /* Break. */ 21164416Sbostic if (ISSET(iflag, IGNBRK)) 21235811Smarc goto endcase; 21364416Sbostic else if (ISSET(iflag, BRKINT) && 21464416Sbostic ISSET(lflag, ISIG) && 21564416Sbostic (cc[VINTR] != _POSIX_VDISABLE)) 21635811Smarc c = cc[VINTR]; 21764416Sbostic else if (ISSET(iflag, PARMRK)) 21847545Skarels goto parmrk; 219*64576Sbostic } else if (ISSET(err, TTY_PE) && 220*64576Sbostic ISSET(iflag, INPCK) || ISSET(err, TTY_FE)) { 22164416Sbostic if (ISSET(iflag, IGNPAR)) 22235811Smarc goto endcase; 22364416Sbostic else if (ISSET(iflag, PARMRK)) { 224*64576Sbostic parmrk: (void)putc(0377 | TTY_QUOTE, &tp->t_rawq); 225*64576Sbostic (void)putc(0 | TTY_QUOTE, &tp->t_rawq); 226*64576Sbostic (void)putc(c | TTY_QUOTE, &tp->t_rawq); 22735811Smarc goto endcase; 22835811Smarc } else 22935811Smarc c = 0; 2307502Sroot } 2319578Ssam } 2329578Ssam /* 23335811Smarc * In tandem mode, check high water mark. 2349578Ssam */ 23564416Sbostic if (ISSET(iflag, IXOFF)) 23635811Smarc ttyblock(tp); 23764416Sbostic if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP)) 238*64576Sbostic CLR(c, 0x80); 23964416Sbostic if (!ISSET(lflag, EXTPROC)) { 24044419Smarc /* 24144419Smarc * Check for literal nexting very first 24244419Smarc */ 24364416Sbostic if (ISSET(tp->t_state, TS_LNCH)) { 244*64576Sbostic SET(c, TTY_QUOTE); 24564416Sbostic CLR(tp->t_state, TS_LNCH); 24644419Smarc } 24744419Smarc /* 24844419Smarc * Scan for special characters. This code 24944419Smarc * is really just a big case statement with 25044419Smarc * non-constant cases. The bottom of the 25144419Smarc * case statement is labeled ``endcase'', so goto 25244419Smarc * it after a case match, or similar. 25344419Smarc */ 25444419Smarc 25544419Smarc /* 25644419Smarc * Control chars which aren't controlled 25744419Smarc * by ICANON, ISIG, or IXON. 25844419Smarc */ 25964416Sbostic if (ISSET(lflag, IEXTEN)) { 26044419Smarc if (CCEQ(cc[VLNEXT], c)) { 26164416Sbostic if (ISSET(lflag, ECHO)) { 26264416Sbostic if (ISSET(lflag, ECHOE)) { 26364416Sbostic (void)ttyoutput('^', tp); 26464416Sbostic (void)ttyoutput('\b', tp); 26564416Sbostic } else 26644419Smarc ttyecho(c, tp); 26744419Smarc } 26864416Sbostic SET(tp->t_state, TS_LNCH); 26944419Smarc goto endcase; 27044419Smarc } 27144419Smarc if (CCEQ(cc[VDISCARD], c)) { 27264416Sbostic if (ISSET(lflag, FLUSHO)) 27364416Sbostic CLR(tp->t_lflag, FLUSHO); 27444419Smarc else { 27544419Smarc ttyflush(tp, FWRITE); 27635811Smarc ttyecho(c, tp); 27744419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 27844419Smarc ttyretype(tp); 27964416Sbostic SET(tp->t_lflag, FLUSHO); 28044419Smarc } 28144419Smarc goto startoutput; 28235811Smarc } 2839578Ssam } 28444419Smarc /* 28544419Smarc * Signals. 28644419Smarc */ 28764416Sbostic if (ISSET(lflag, ISIG)) { 28844419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 28964416Sbostic if (!ISSET(lflag, NOFLSH)) 29064416Sbostic ttyflush(tp, FREAD | FWRITE); 2917502Sroot ttyecho(c, tp); 29244419Smarc pgsignal(tp->t_pgrp, 29344419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 29444419Smarc goto endcase; 2957502Sroot } 29644419Smarc if (CCEQ(cc[VSUSP], c)) { 29764416Sbostic if (!ISSET(lflag, NOFLSH)) 29844419Smarc ttyflush(tp, FREAD); 29944419Smarc ttyecho(c, tp); 30044419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 30144419Smarc goto endcase; 30244419Smarc } 3039578Ssam } 30444419Smarc /* 30544419Smarc * Handle start/stop characters. 30644419Smarc */ 30764416Sbostic if (ISSET(iflag, IXON)) { 30844419Smarc if (CCEQ(cc[VSTOP], c)) { 30964416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 31064416Sbostic SET(tp->t_state, TS_TTSTOP); 31152485Storek #ifdef sun4c /* XXX */ 31252485Storek (*tp->t_stop)(tp, 0); 31352485Storek #else 31444419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 31544419Smarc 0); 31652485Storek #endif 31764416Sbostic return (0); 31844419Smarc } 31944419Smarc if (!CCEQ(cc[VSTART], c)) 32064416Sbostic return (0); 32164416Sbostic /* 32264416Sbostic * if VSTART == VSTOP then toggle 32344419Smarc */ 32444419Smarc goto endcase; 32535811Smarc } 32644419Smarc if (CCEQ(cc[VSTART], c)) 32744419Smarc goto restartoutput; 3289578Ssam } 32944419Smarc /* 33044419Smarc * IGNCR, ICRNL, & INLCR 33144419Smarc */ 33244419Smarc if (c == '\r') { 33364416Sbostic if (ISSET(iflag, IGNCR)) 33444419Smarc goto endcase; 33564416Sbostic else if (ISSET(iflag, ICRNL)) 33644419Smarc c = '\n'; 33764416Sbostic } else if (c == '\n' && ISSET(iflag, INLCR)) 33844419Smarc c = '\r'; 3399578Ssam } 34064416Sbostic if (!ISSET(tp->t_lflag, EXTPROC) && ISSET(lflag, ICANON)) { 34144419Smarc /* 34244419Smarc * From here on down canonical mode character 34344419Smarc * processing takes place. 34444419Smarc */ 34544419Smarc /* 34644419Smarc * erase (^H / ^?) 34744419Smarc */ 34844419Smarc if (CCEQ(cc[VERASE], c)) { 34944419Smarc if (tp->t_rawq.c_cc) 3509578Ssam ttyrub(unputc(&tp->t_rawq), tp); 35144419Smarc goto endcase; 3529578Ssam } 35344419Smarc /* 35444419Smarc * kill (^U) 35544419Smarc */ 35644419Smarc if (CCEQ(cc[VKILL], c)) { 35764416Sbostic if (ISSET(lflag, ECHOKE) && 35864416Sbostic tp->t_rawq.c_cc == tp->t_rocount && 35964416Sbostic !ISSET(lflag, ECHOPRT)) 36044419Smarc while (tp->t_rawq.c_cc) 36144419Smarc ttyrub(unputc(&tp->t_rawq), tp); 36264416Sbostic else { 36344419Smarc ttyecho(c, tp); 36464416Sbostic if (ISSET(lflag, ECHOK) || 36564416Sbostic ISSET(lflag, ECHOKE)) 36644419Smarc ttyecho('\n', tp); 36764416Sbostic FLUSHQ(&tp->t_rawq); 36844419Smarc tp->t_rocount = 0; 36944419Smarc } 37064416Sbostic CLR(tp->t_state, TS_LOCAL); 37144419Smarc goto endcase; 37244419Smarc } 37344419Smarc /* 37444419Smarc * word erase (^W) 37544419Smarc */ 37664416Sbostic if (CCEQ(cc[VWERASE], c)) { 37764416Sbostic int alt = ISSET(lflag, ALTWERASE); 37844419Smarc int ctype; 37935811Smarc 38064416Sbostic /* 38164416Sbostic * erase whitespace 38244419Smarc */ 38344419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 38444419Smarc ttyrub(c, tp); 38544419Smarc if (c == -1) 38644419Smarc goto endcase; 38744419Smarc /* 38847545Skarels * erase last char of word and remember the 38947545Skarels * next chars type (for ALTWERASE) 39044419Smarc */ 39135811Smarc ttyrub(c, tp); 39244419Smarc c = unputc(&tp->t_rawq); 39347545Skarels if (c == -1) 39444419Smarc goto endcase; 39551003Sbostic if (c == ' ' || c == '\t') { 396*64576Sbostic (void)putc(c, &tp->t_rawq); 39751003Sbostic goto endcase; 39851003Sbostic } 39949380Skarels ctype = ISALPHA(c); 40044419Smarc /* 40147545Skarels * erase rest of word 40244419Smarc */ 40344419Smarc do { 40444419Smarc ttyrub(c, tp); 40544419Smarc c = unputc(&tp->t_rawq); 40644419Smarc if (c == -1) 40744419Smarc goto endcase; 40864416Sbostic } while (c != ' ' && c != '\t' && 40964416Sbostic (alt == 0 || ISALPHA(c) == ctype)); 41064416Sbostic (void)putc(c, &tp->t_rawq); 41134492Skarels goto endcase; 41244419Smarc } 41335811Smarc /* 41444419Smarc * reprint line (^R) 41535811Smarc */ 41644419Smarc if (CCEQ(cc[VREPRINT], c)) { 41744419Smarc ttyretype(tp); 41834492Skarels goto endcase; 41934492Skarels } 42035811Smarc /* 42144419Smarc * ^T - kernel info and generate SIGINFO 42235811Smarc */ 42344419Smarc if (CCEQ(cc[VSTATUS], c)) { 42464416Sbostic if (ISSET(lflag, ISIG)) 42551068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 42664416Sbostic if (!ISSET(lflag, NOKERNINFO)) 42744419Smarc ttyinfo(tp); 42844419Smarc goto endcase; 42944419Smarc } 4309578Ssam } 4319578Ssam /* 4329578Ssam * Check for input buffer overflow 4339578Ssam */ 43447545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 43564416Sbostic if (ISSET(iflag, IMAXBEL)) { 43635811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 43764416Sbostic (void)ttyoutput(CTRL('g'), tp); 43835811Smarc } else 43935811Smarc ttyflush(tp, FREAD | FWRITE); 4409578Ssam goto endcase; 44110391Ssam } 4429578Ssam /* 4439578Ssam * Put data char in q for user and 4449578Ssam * wakeup on seeing a line delimiter. 4459578Ssam */ 4469578Ssam if (putc(c, &tp->t_rawq) >= 0) { 44764416Sbostic if (!ISSET(lflag, ICANON)) { 44847545Skarels ttwakeup(tp); 44947545Skarels ttyecho(c, tp); 45047545Skarels goto endcase; 45147545Skarels } 45264416Sbostic if (TTBREAKC(c)) { 4539578Ssam tp->t_rocount = 0; 4549578Ssam catq(&tp->t_rawq, &tp->t_canq); 4557502Sroot ttwakeup(tp); 4569578Ssam } else if (tp->t_rocount++ == 0) 45764530Sbostic tp->t_rocol = tp->t_column; 45864416Sbostic if (ISSET(tp->t_state, TS_ERASE)) { 45935811Smarc /* 46035811Smarc * end of prterase \.../ 46135811Smarc */ 46264416Sbostic CLR(tp->t_state, TS_ERASE); 46364416Sbostic (void)ttyoutput('/', tp); 4649578Ssam } 46564530Sbostic i = tp->t_column; 4667502Sroot ttyecho(c, tp); 46764416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) { 46835811Smarc /* 46935811Smarc * Place the cursor over the '^' of the ^D. 47035811Smarc */ 47164530Sbostic i = min(2, tp->t_column - i); 4729578Ssam while (i > 0) { 47364416Sbostic (void)ttyoutput('\b', tp); 4749578Ssam i--; 4759578Ssam } 4769578Ssam } 4777502Sroot } 4789578Ssam endcase: 4799578Ssam /* 48035811Smarc * IXANY means allow any character to restart output. 4819578Ssam */ 48264416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) && 48364416Sbostic !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) 48464416Sbostic return (0); 4859578Ssam restartoutput: 48664416Sbostic CLR(tp->t_lflag, FLUSHO); 48764416Sbostic CLR(tp->t_state, TS_TTSTOP); 4889578Ssam startoutput: 48964416Sbostic return (ttstart(tp)); 4907502Sroot } 4917502Sroot 4927502Sroot /* 49349380Skarels * Output a single character on a tty, doing output processing 49449380Skarels * as needed (expanding tabs, newline processing, etc.). 49564416Sbostic * Returns < 0 if succeeds, otherwise returns char to resend. 4967502Sroot * Must be recursive. 4977502Sroot */ 49864416Sbostic int 4997502Sroot ttyoutput(c, tp) 50064416Sbostic register int c; 5017502Sroot register struct tty *tp; 5027502Sroot { 50364416Sbostic register long oflag; 50464416Sbostic register int col, s; 50564416Sbostic 50664416Sbostic oflag = tp->t_oflag; 50764416Sbostic if (!ISSET(oflag, OPOST)) { 50864416Sbostic if (ISSET(tp->t_lflag, FLUSHO)) 5097502Sroot return (-1); 5107502Sroot if (putc(c, &tp->t_outq)) 5117625Ssam return (c); 5127502Sroot tk_nout++; 51335811Smarc tp->t_outcc++; 5147502Sroot return (-1); 5157502Sroot } 5167502Sroot /* 51764416Sbostic * Do tab expansion if OXTABS is set. Special case if we external 51864416Sbostic * processing, we don't do the tab expansion because we'll probably 51964416Sbostic * get it wrong. If tab expansion needs to be done, let it happen 52064416Sbostic * externally. 5217502Sroot */ 522*64576Sbostic CLR(c, ~TTY_CHARMASK); 52364416Sbostic if (c == '\t' && 52464416Sbostic ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) { 52564530Sbostic c = 8 - (tp->t_column & 7); 52664416Sbostic if (!ISSET(tp->t_lflag, FLUSHO)) { 52764416Sbostic s = spltty(); /* Don't interrupt tabs. */ 5287502Sroot c -= b_to_q(" ", c, &tp->t_outq); 5297502Sroot tk_nout += c; 53035811Smarc tp->t_outcc += c; 5317502Sroot splx(s); 5327502Sroot } 53364530Sbostic tp->t_column += c; 5347502Sroot return (c ? -1 : '\t'); 5357502Sroot } 53664416Sbostic if (c == CEOT && ISSET(oflag, ONOEOT)) 53747545Skarels return (-1); 538*64576Sbostic 5397502Sroot /* 54049380Skarels * Newline translation: if ONLCR is set, 54149380Skarels * translate newline into "\r\n". 5427502Sroot */ 543*64576Sbostic if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) { 544*64576Sbostic tk_nout++; 545*64576Sbostic tp->t_outcc++; 546*64576Sbostic if (putc('\r', &tp->t_outq)) 547*64576Sbostic return (c); 548*64576Sbostic } 549*64576Sbostic tk_nout++; 550*64576Sbostic tp->t_outcc++; 55164416Sbostic if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq)) 55235811Smarc return (c); 55347545Skarels 55464530Sbostic col = tp->t_column; 55549380Skarels switch (CCLASS(c)) { 5567502Sroot case BACKSPACE: 55749380Skarels if (col > 0) 55864416Sbostic --col; 5597502Sroot break; 56064416Sbostic case CONTROL: 56164416Sbostic break; 5627502Sroot case NEWLINE: 56364416Sbostic case RETURN: 56449380Skarels col = 0; 5657502Sroot break; 56664416Sbostic case ORDINARY: 56764416Sbostic ++col; 56864416Sbostic break; 5697502Sroot case TAB: 57064416Sbostic col = (col + 8) & ~7; 5717502Sroot break; 5727502Sroot } 57364530Sbostic tp->t_column = col; 5747502Sroot return (-1); 5757502Sroot } 5767502Sroot 5777502Sroot /* 578*64576Sbostic * Ioctls for all tty devices. Called after line-discipline specific ioctl 579*64576Sbostic * has been called to do discipline-specific functions and/or reject any 580*64576Sbostic * of these ioctl commands. 58164416Sbostic */ 58264416Sbostic /* ARGSUSED */ 58364416Sbostic int 584*64576Sbostic ttioctl(tp, cmd, data, flag) 58564416Sbostic register struct tty *tp; 586*64576Sbostic int cmd, flag; 58764416Sbostic void *data; 58864416Sbostic { 58964416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 590*64576Sbostic extern int nlinesw; 59164416Sbostic register struct proc *p; 59264416Sbostic int s, error; 59364416Sbostic 59464416Sbostic p = curproc; /* XXX */ 59564416Sbostic 59664416Sbostic /* If the ioctl involves modification, hang if in the background. */ 597*64576Sbostic switch (cmd) { 59864416Sbostic case TIOCFLUSH: 59964416Sbostic case TIOCSETA: 60064416Sbostic case TIOCSETD: 60164416Sbostic case TIOCSETAF: 60264416Sbostic case TIOCSETAW: 60364416Sbostic #ifdef notdef 60464416Sbostic case TIOCSPGRP: 60564416Sbostic #endif 60664416Sbostic case TIOCSTI: 60764416Sbostic case TIOCSWINSZ: 60864416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 60964416Sbostic case TIOCLBIC: 61064416Sbostic case TIOCLBIS: 61164416Sbostic case TIOCLSET: 61264416Sbostic case TIOCSETC: 61364416Sbostic case OTIOCSETD: 61464416Sbostic case TIOCSETN: 61564416Sbostic case TIOCSETP: 61664416Sbostic case TIOCSLTC: 61764416Sbostic #endif 61864416Sbostic while (isbackground(curproc, tp) && 619*64576Sbostic p->p_pgrp->pg_jobc && (p->p_flag & P_PPWAIT) == 0 && 62064416Sbostic (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 62164416Sbostic (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 62264416Sbostic pgsignal(p->p_pgrp, SIGTTOU, 1); 62364416Sbostic if (error = ttysleep(tp, 62464416Sbostic &lbolt, TTOPRI | PCATCH, ttybg, 0)) 62564416Sbostic return (error); 62664416Sbostic } 62764416Sbostic break; 62864416Sbostic } 62964416Sbostic 630*64576Sbostic switch (cmd) { /* Process the ioctl. */ 63164416Sbostic case FIOASYNC: /* set/clear async i/o */ 63264416Sbostic s = spltty(); 63364416Sbostic if (*(int *)data) 63464416Sbostic SET(tp->t_state, TS_ASYNC); 63564416Sbostic else 63664416Sbostic CLR(tp->t_state, TS_ASYNC); 63764416Sbostic splx(s); 63864416Sbostic break; 63964416Sbostic case FIONBIO: /* set/clear non-blocking i/o */ 64064416Sbostic break; /* XXX: delete. */ 64164416Sbostic case FIONREAD: /* get # bytes to read */ 64264416Sbostic *(int *)data = ttnread(tp); 64364416Sbostic break; 64464416Sbostic case TIOCEXCL: /* set exclusive use of tty */ 64564416Sbostic s = spltty(); 64664416Sbostic SET(tp->t_state, TS_XCLUDE); 64764416Sbostic splx(s); 64864416Sbostic break; 64964416Sbostic case TIOCFLUSH: { /* flush buffers */ 65064416Sbostic register int flags = *(int *)data; 65164416Sbostic 65264416Sbostic if (flags == 0) 65364416Sbostic flags = FREAD | FWRITE; 65464416Sbostic else 65564416Sbostic flags &= FREAD | FWRITE; 65664416Sbostic ttyflush(tp, flags); 65764416Sbostic break; 65864416Sbostic } 65964416Sbostic case TIOCCONS: /* become virtual console */ 66064416Sbostic if (*(int *)data) { 66164416Sbostic if (constty && constty != tp && 66264416Sbostic ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) == 66364416Sbostic (TS_CARR_ON | TS_ISOPEN)) 66464416Sbostic return (EBUSY); 66564416Sbostic #ifndef UCONSOLE 66664416Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 66764416Sbostic return (error); 66864416Sbostic #endif 66964416Sbostic constty = tp; 67064416Sbostic } else if (tp == constty) 67164416Sbostic constty = NULL; 67264416Sbostic break; 67364416Sbostic case TIOCDRAIN: /* wait till output drained */ 67464416Sbostic if (error = ttywait(tp)) 67564416Sbostic return (error); 67664416Sbostic break; 67764416Sbostic case TIOCGETA: { /* get termios struct */ 67864416Sbostic struct termios *t = (struct termios *)data; 67964416Sbostic 68064416Sbostic bcopy(&tp->t_termios, t, sizeof(struct termios)); 68164416Sbostic break; 68264416Sbostic } 68364416Sbostic case TIOCGETD: /* get line discipline */ 68464416Sbostic *(int *)data = tp->t_line; 68564416Sbostic break; 68664416Sbostic case TIOCGWINSZ: /* get window size */ 68764416Sbostic *(struct winsize *)data = tp->t_winsize; 68864416Sbostic break; 68964416Sbostic case TIOCGPGRP: /* get pgrp of tty */ 69064416Sbostic if (!isctty(p, tp)) 69164416Sbostic return (ENOTTY); 69264416Sbostic *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 69364416Sbostic break; 69464416Sbostic #ifdef TIOCHPCL 69564416Sbostic case TIOCHPCL: /* hang up on last close */ 69664416Sbostic s = spltty(); 697*64576Sbostic SET(tp->t_cflag, HUPCL); 69864416Sbostic splx(s); 69964416Sbostic break; 70064416Sbostic #endif 70164416Sbostic case TIOCNXCL: /* reset exclusive use of tty */ 70264416Sbostic s = spltty(); 70364416Sbostic CLR(tp->t_state, TS_XCLUDE); 70464416Sbostic splx(s); 70564416Sbostic break; 70664416Sbostic case TIOCOUTQ: /* output queue size */ 70764416Sbostic *(int *)data = tp->t_outq.c_cc; 70864416Sbostic break; 70964416Sbostic case TIOCSETA: /* set termios struct */ 71064416Sbostic case TIOCSETAW: /* drain output, set */ 71164416Sbostic case TIOCSETAF: { /* drn out, fls in, set */ 71264416Sbostic register struct termios *t = (struct termios *)data; 71364416Sbostic 71464416Sbostic s = spltty(); 715*64576Sbostic if (cmd == TIOCSETAW || cmd == TIOCSETAF) { 71664416Sbostic if (error = ttywait(tp)) { 71764416Sbostic splx(s); 71864416Sbostic return (error); 71964416Sbostic } 720*64576Sbostic if (cmd == TIOCSETAF) 72164416Sbostic ttyflush(tp, FREAD); 72264416Sbostic } 72364416Sbostic if (!ISSET(t->c_cflag, CIGNORE)) { 72464416Sbostic /* 72564416Sbostic * Set device hardware. 72664416Sbostic */ 72764416Sbostic if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 72864416Sbostic splx(s); 72964416Sbostic return (error); 73064416Sbostic } else { 73164416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 73264416Sbostic ISSET(tp->t_cflag, CLOCAL) && 73364416Sbostic !ISSET(t->c_cflag, CLOCAL)) { 73464416Sbostic CLR(tp->t_state, TS_ISOPEN); 73564416Sbostic SET(tp->t_state, TS_WOPEN); 73664416Sbostic ttwakeup(tp); 73764416Sbostic } 73864416Sbostic tp->t_cflag = t->c_cflag; 73964416Sbostic tp->t_ispeed = t->c_ispeed; 74064416Sbostic tp->t_ospeed = t->c_ospeed; 74164416Sbostic } 74264416Sbostic ttsetwater(tp); 74364416Sbostic } 744*64576Sbostic if (cmd != TIOCSETAF) { 74564416Sbostic if (ISSET(t->c_lflag, ICANON) != 74664416Sbostic ISSET(tp->t_lflag, ICANON)) 74764416Sbostic if (ISSET(t->c_lflag, ICANON)) { 748*64576Sbostic SET(tp->t_lflag, PENDIN); 74964416Sbostic ttwakeup(tp); 75064416Sbostic } else { 75164416Sbostic struct clist tq; 75264416Sbostic 75364416Sbostic catq(&tp->t_rawq, &tp->t_canq); 75464416Sbostic tq = tp->t_rawq; 75564416Sbostic tp->t_rawq = tp->t_canq; 75664416Sbostic tp->t_canq = tq; 75764416Sbostic } 75864416Sbostic } 75964416Sbostic tp->t_iflag = t->c_iflag; 76064416Sbostic tp->t_oflag = t->c_oflag; 76164416Sbostic /* 76264416Sbostic * Make the EXTPROC bit read only. 76364416Sbostic */ 76464416Sbostic if (ISSET(tp->t_lflag, EXTPROC)) 76564416Sbostic SET(t->c_lflag, EXTPROC); 76664416Sbostic else 76764416Sbostic CLR(t->c_lflag, EXTPROC); 76864416Sbostic tp->t_lflag = t->c_lflag; 76964416Sbostic bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 77064416Sbostic splx(s); 77164416Sbostic break; 77264416Sbostic } 77364416Sbostic case TIOCSETD: { /* set line discipline */ 77464416Sbostic register int t = *(int *)data; 77564416Sbostic dev_t device = tp->t_dev; 77664416Sbostic 777*64576Sbostic if ((u_int)t >= nlinesw) 77864416Sbostic return (ENXIO); 77964416Sbostic if (t != tp->t_line) { 78064416Sbostic s = spltty(); 78164416Sbostic (*linesw[tp->t_line].l_close)(tp, flag); 78264416Sbostic error = (*linesw[t].l_open)(device, tp); 78364416Sbostic if (error) { 78464416Sbostic (void)(*linesw[tp->t_line].l_open)(device, tp); 78564416Sbostic splx(s); 78664416Sbostic return (error); 78764416Sbostic } 78864416Sbostic tp->t_line = t; 78964416Sbostic splx(s); 79064416Sbostic } 79164416Sbostic break; 79264416Sbostic } 79364416Sbostic case TIOCSTART: /* start output, like ^Q */ 79464416Sbostic s = spltty(); 79564416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) || 79664416Sbostic ISSET(tp->t_lflag, FLUSHO)) { 79764416Sbostic CLR(tp->t_lflag, FLUSHO); 79864416Sbostic CLR(tp->t_state, TS_TTSTOP); 79964416Sbostic ttstart(tp); 80064416Sbostic } 80164416Sbostic splx(s); 80264416Sbostic break; 80364416Sbostic case TIOCSTI: /* simulate terminal input */ 80464416Sbostic if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 80564416Sbostic return (EPERM); 80664416Sbostic if (p->p_ucred->cr_uid && !isctty(p, tp)) 80764416Sbostic return (EACCES); 80864416Sbostic (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 80964416Sbostic break; 81064416Sbostic case TIOCSTOP: /* stop output, like ^S */ 81164416Sbostic s = spltty(); 81264416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 81364416Sbostic SET(tp->t_state, TS_TTSTOP); 81464416Sbostic #ifdef sun4c /* XXX */ 81564416Sbostic (*tp->t_stop)(tp, 0); 81664416Sbostic #else 81764416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 81864416Sbostic #endif 81964416Sbostic } 82064416Sbostic splx(s); 82164416Sbostic break; 82264416Sbostic case TIOCSCTTY: /* become controlling tty */ 82364416Sbostic /* Session ctty vnode pointer set in vnode layer. */ 82464416Sbostic if (!SESS_LEADER(p) || 82564416Sbostic (p->p_session->s_ttyvp || tp->t_session) && 82664416Sbostic (tp->t_session != p->p_session)) 82764416Sbostic return (EPERM); 82864416Sbostic tp->t_session = p->p_session; 82964416Sbostic tp->t_pgrp = p->p_pgrp; 83064416Sbostic p->p_session->s_ttyp = tp; 831*64576Sbostic p->p_flag |= P_CONTROLT; 83264416Sbostic break; 83364416Sbostic case TIOCSPGRP: { /* set pgrp of tty */ 83464416Sbostic register struct pgrp *pgrp = pgfind(*(int *)data); 83564416Sbostic 83664416Sbostic if (!isctty(p, tp)) 83764416Sbostic return (ENOTTY); 83864416Sbostic else if (pgrp == NULL || pgrp->pg_session != p->p_session) 83964416Sbostic return (EPERM); 84064416Sbostic tp->t_pgrp = pgrp; 84164416Sbostic break; 84264416Sbostic } 84364416Sbostic case TIOCSWINSZ: /* set window size */ 84464416Sbostic if (bcmp((caddr_t)&tp->t_winsize, data, 84564416Sbostic sizeof (struct winsize))) { 84664416Sbostic tp->t_winsize = *(struct winsize *)data; 84764416Sbostic pgsignal(tp->t_pgrp, SIGWINCH, 1); 84864416Sbostic } 84964416Sbostic break; 85064416Sbostic default: 85164416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 852*64576Sbostic return (ttcompat(tp, cmd, data, flag)); 85364416Sbostic #else 85464416Sbostic return (-1); 85564416Sbostic #endif 85664416Sbostic } 85764416Sbostic return (0); 85864416Sbostic } 85964416Sbostic 86064416Sbostic int 86164416Sbostic ttselect(device, rw, p) 86264416Sbostic dev_t device; 86364416Sbostic int rw; 86464416Sbostic struct proc *p; 86564416Sbostic { 86664416Sbostic register struct tty *tp; 86764416Sbostic int nread, s; 86864416Sbostic 86964416Sbostic tp = &cdevsw[major(device)].d_ttys[minor(device)]; 87064416Sbostic 87164416Sbostic s = spltty(); 87264416Sbostic switch (rw) { 87364416Sbostic case FREAD: 87464416Sbostic nread = ttnread(tp); 87564416Sbostic if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) && 87664416Sbostic !ISSET(tp->t_state, TS_CARR_ON)) 87764416Sbostic goto win; 87864416Sbostic selrecord(p, &tp->t_rsel); 87964416Sbostic break; 88064416Sbostic case FWRITE: 88164416Sbostic if (tp->t_outq.c_cc <= tp->t_lowat) { 88264416Sbostic win: splx(s); 88364416Sbostic return (1); 88464416Sbostic } 88564416Sbostic selrecord(p, &tp->t_wsel); 88664416Sbostic break; 88764416Sbostic } 88864416Sbostic splx(s); 88964416Sbostic return (0); 89064416Sbostic } 89164416Sbostic 89264416Sbostic static int 89364416Sbostic ttnread(tp) 89464416Sbostic struct tty *tp; 89564416Sbostic { 89664416Sbostic int nread; 89764416Sbostic 89864416Sbostic if (ISSET(tp->t_lflag, PENDIN)) 89964416Sbostic ttypend(tp); 90064416Sbostic nread = tp->t_canq.c_cc; 90164416Sbostic if (!ISSET(tp->t_lflag, ICANON)) 90264416Sbostic nread += tp->t_rawq.c_cc; 90364416Sbostic return (nread); 90464416Sbostic } 90564416Sbostic 90664416Sbostic /* 90764416Sbostic * Wait for output to drain. 90864416Sbostic */ 90964416Sbostic int 91064416Sbostic ttywait(tp) 91164416Sbostic register struct tty *tp; 91264416Sbostic { 91364416Sbostic int error, s; 91464416Sbostic 91564416Sbostic error = 0; 91664416Sbostic s = spltty(); 91764416Sbostic while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 91864416Sbostic (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) 91964416Sbostic && tp->t_oproc) { 92064416Sbostic (*tp->t_oproc)(tp); 92164416Sbostic SET(tp->t_state, TS_ASLEEP); 92264416Sbostic if (error = ttysleep(tp, 92364416Sbostic &tp->t_outq, TTOPRI | PCATCH, ttyout, 0)) 92464416Sbostic break; 92564416Sbostic } 92664416Sbostic splx(s); 92764416Sbostic return (error); 92864416Sbostic } 92964416Sbostic 93064416Sbostic /* 93164416Sbostic * Flush if successfully wait. 93264416Sbostic */ 93364416Sbostic int 93464416Sbostic ttywflush(tp) 93564416Sbostic struct tty *tp; 93664416Sbostic { 93764416Sbostic int error; 93864416Sbostic 93964416Sbostic if ((error = ttywait(tp)) == 0) 94064416Sbostic ttyflush(tp, FREAD); 94164416Sbostic return (error); 94264416Sbostic } 94364416Sbostic 94464416Sbostic /* 94564416Sbostic * Flush tty read and/or write queues, notifying anyone waiting. 94664416Sbostic */ 94764416Sbostic void 94864416Sbostic ttyflush(tp, rw) 94964416Sbostic register struct tty *tp; 95064416Sbostic int rw; 95164416Sbostic { 95264416Sbostic register int s; 95364416Sbostic 95464416Sbostic s = spltty(); 95564416Sbostic if (rw & FREAD) { 95664416Sbostic FLUSHQ(&tp->t_canq); 95764416Sbostic FLUSHQ(&tp->t_rawq); 95864416Sbostic tp->t_rocount = 0; 95964416Sbostic tp->t_rocol = 0; 96064416Sbostic CLR(tp->t_state, TS_LOCAL); 96164416Sbostic ttwakeup(tp); 96264416Sbostic } 96364416Sbostic if (rw & FWRITE) { 96464416Sbostic CLR(tp->t_state, TS_TTSTOP); 96564416Sbostic #ifdef sun4c /* XXX */ 96664416Sbostic (*tp->t_stop)(tp, rw); 96764416Sbostic #else 96864416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 96964416Sbostic #endif 97064416Sbostic FLUSHQ(&tp->t_outq); 97164416Sbostic wakeup((caddr_t)&tp->t_outq); 97264416Sbostic selwakeup(&tp->t_wsel); 97364416Sbostic } 97464416Sbostic splx(s); 97564416Sbostic } 97664416Sbostic 97764416Sbostic /* 97864416Sbostic * Copy in the default termios characters. 97964416Sbostic */ 98064416Sbostic void 98164416Sbostic ttychars(tp) 98264416Sbostic struct tty *tp; 98364416Sbostic { 98464416Sbostic 98564416Sbostic bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 98664416Sbostic } 98764416Sbostic 98864416Sbostic /* 98964416Sbostic * Send stop character on input overflow. 99064416Sbostic */ 99164416Sbostic static void 99264416Sbostic ttyblock(tp) 99364416Sbostic register struct tty *tp; 99464416Sbostic { 99564416Sbostic register int total; 99664416Sbostic 99764416Sbostic total = tp->t_rawq.c_cc + tp->t_canq.c_cc; 99864416Sbostic if (tp->t_rawq.c_cc > TTYHOG) { 99964416Sbostic ttyflush(tp, FREAD | FWRITE); 100064416Sbostic CLR(tp->t_state, TS_TBLOCK); 100164416Sbostic } 100264416Sbostic /* 100364416Sbostic * Block further input iff: current input > threshold 100464416Sbostic * AND input is available to user program. 100564416Sbostic */ 100664416Sbostic if (total >= TTYHOG / 2 && 100764416Sbostic !ISSET(tp->t_state, TS_TBLOCK) && 100864416Sbostic !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 && 100964416Sbostic tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 101064416Sbostic if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 101164416Sbostic SET(tp->t_state, TS_TBLOCK); 101264416Sbostic ttstart(tp); 101364416Sbostic } 101464416Sbostic } 101564416Sbostic } 101664416Sbostic 101764416Sbostic void 101864416Sbostic ttrstrt(tp_arg) 101964416Sbostic void *tp_arg; 102064416Sbostic { 102164416Sbostic struct tty *tp; 102264416Sbostic int s; 102364416Sbostic 102464416Sbostic #ifdef DIAGNOSTIC 102564416Sbostic if (tp_arg == NULL) 102664416Sbostic panic("ttrstrt"); 102764416Sbostic #endif 102864416Sbostic tp = tp_arg; 102964416Sbostic s = spltty(); 103064416Sbostic 103164416Sbostic CLR(tp->t_state, TS_TIMEOUT); 103264416Sbostic ttstart(tp); 103364416Sbostic 103464416Sbostic splx(s); 103564416Sbostic } 103664416Sbostic 103764416Sbostic int 103864416Sbostic ttstart(tp) 103964416Sbostic struct tty *tp; 104064416Sbostic { 104164416Sbostic 104264416Sbostic if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 104364416Sbostic (*tp->t_oproc)(tp); 104464416Sbostic return (0); 104564416Sbostic } 104664416Sbostic 104764416Sbostic /* 104864416Sbostic * "close" a line discipline 104964416Sbostic */ 105064416Sbostic int 105164416Sbostic ttylclose(tp, flag) 105264416Sbostic struct tty *tp; 105364416Sbostic int flag; 105464416Sbostic { 105564416Sbostic 105664416Sbostic if (flag & IO_NDELAY) 105764416Sbostic ttyflush(tp, FREAD | FWRITE); 105864416Sbostic else 105964416Sbostic ttywflush(tp); 106064416Sbostic return (0); 106164416Sbostic } 106264416Sbostic 106364416Sbostic /* 106464416Sbostic * Handle modem control transition on a tty. 106564416Sbostic * Flag indicates new state of carrier. 106664416Sbostic * Returns 0 if the line should be turned off, otherwise 1. 106764416Sbostic */ 106864416Sbostic int 106964416Sbostic ttymodem(tp, flag) 107064416Sbostic register struct tty *tp; 107164416Sbostic int flag; 107264416Sbostic { 107364416Sbostic 107464416Sbostic if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) { 107564416Sbostic /* 107664416Sbostic * MDMBUF: do flow control according to carrier flag 107764416Sbostic */ 107864416Sbostic if (flag) { 107964416Sbostic CLR(tp->t_state, TS_TTSTOP); 108064416Sbostic ttstart(tp); 108164416Sbostic } else if (!ISSET(tp->t_state, TS_TTSTOP)) { 108264416Sbostic SET(tp->t_state, TS_TTSTOP); 108364416Sbostic #ifdef sun4c /* XXX */ 108464416Sbostic (*tp->t_stop)(tp, 0); 108564416Sbostic #else 108664416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 108764416Sbostic #endif 108864416Sbostic } 108964416Sbostic } else if (flag == 0) { 109064416Sbostic /* 109164416Sbostic * Lost carrier. 109264416Sbostic */ 109364416Sbostic CLR(tp->t_state, TS_CARR_ON); 109464416Sbostic if (ISSET(tp->t_state, TS_ISOPEN) && 109564416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 109664416Sbostic if (tp->t_session && tp->t_session->s_leader) 109764416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 109864416Sbostic ttyflush(tp, FREAD | FWRITE); 109964416Sbostic return (0); 110064416Sbostic } 110164416Sbostic } else { 110264416Sbostic /* 110364416Sbostic * Carrier now on. 110464416Sbostic */ 110564416Sbostic SET(tp->t_state, TS_CARR_ON); 110664416Sbostic ttwakeup(tp); 110764416Sbostic } 110864416Sbostic return (1); 110964416Sbostic } 111064416Sbostic 111164416Sbostic /* 111264416Sbostic * Default modem control routine (for other line disciplines). 111364416Sbostic * Return argument flag, to turn off device on carrier drop. 111464416Sbostic */ 111564416Sbostic int 111664416Sbostic nullmodem(tp, flag) 111764416Sbostic register struct tty *tp; 111864416Sbostic int flag; 111964416Sbostic { 112064416Sbostic 112164416Sbostic if (flag) 112264416Sbostic SET(tp->t_state, TS_CARR_ON); 112364416Sbostic else { 112464416Sbostic CLR(tp->t_state, TS_CARR_ON); 112564416Sbostic if (!ISSET(tp->t_cflag, CLOCAL)) { 112664416Sbostic if (tp->t_session && tp->t_session->s_leader) 112764416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 112864416Sbostic return (0); 112964416Sbostic } 113064416Sbostic } 113164416Sbostic return (1); 113264416Sbostic } 113364416Sbostic 113464416Sbostic /* 113564416Sbostic * Reinput pending characters after state switch 113664416Sbostic * call at spltty(). 113764416Sbostic */ 113864416Sbostic void 113964416Sbostic ttypend(tp) 114064416Sbostic register struct tty *tp; 114164416Sbostic { 114264416Sbostic struct clist tq; 114364416Sbostic register c; 114464416Sbostic 114564416Sbostic CLR(tp->t_lflag, PENDIN); 114664416Sbostic SET(tp->t_state, TS_TYPEN); 114764416Sbostic tq = tp->t_rawq; 114864416Sbostic tp->t_rawq.c_cc = 0; 114964416Sbostic tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 115064416Sbostic while ((c = getc(&tq)) >= 0) 115164416Sbostic ttyinput(c, tp); 115264416Sbostic CLR(tp->t_state, TS_TYPEN); 115364416Sbostic } 115464416Sbostic 115564416Sbostic /* 115649380Skarels * Process a read call on a tty device. 11577502Sroot */ 115864416Sbostic int 115937584Smarc ttread(tp, uio, flag) 11607625Ssam register struct tty *tp; 11617722Swnj struct uio *uio; 116252485Storek int flag; 11637502Sroot { 11647502Sroot register struct clist *qp; 116535811Smarc register int c; 116641383Smarc register long lflag; 116735811Smarc register u_char *cc = tp->t_cc; 116847545Skarels register struct proc *p = curproc; 11699859Ssam int s, first, error = 0; 11707502Sroot 117164416Sbostic loop: lflag = tp->t_lflag; 117237584Smarc s = spltty(); 11739578Ssam /* 117464416Sbostic * take pending input first 11759578Ssam */ 117664416Sbostic if (ISSET(lflag, PENDIN)) 11777502Sroot ttypend(tp); 11789859Ssam splx(s); 117940712Skarels 11809578Ssam /* 11819578Ssam * Hang process if it's in the background. 11829578Ssam */ 118347545Skarels if (isbackground(p, tp)) { 118447545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 118547545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 1186*64576Sbostic p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) 11878520Sroot return (EIO); 118847545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 118964416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 119040712Skarels return (error); 119123165Sbloom goto loop; 11927502Sroot } 119340712Skarels 11949578Ssam /* 119535811Smarc * If canonical, use the canonical queue, 119635811Smarc * else use the raw queue. 119737584Smarc * 119847545Skarels * (should get rid of clists...) 11999578Ssam */ 120064416Sbostic qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 120140712Skarels 12029578Ssam /* 120340712Skarels * If there is no input, sleep on rawq 120440712Skarels * awaiting hardware receipt and notification. 120540712Skarels * If we have data, we don't need to check for carrier. 12069578Ssam */ 120717545Skarels s = spltty(); 12089578Ssam if (qp->c_cc <= 0) { 120940712Skarels int carrier; 121040712Skarels 121164416Sbostic carrier = ISSET(tp->t_state, TS_CARR_ON) || 121264416Sbostic ISSET(tp->t_cflag, CLOCAL); 121364416Sbostic if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { 12149859Ssam splx(s); 121540712Skarels return (0); /* EOF */ 12167502Sroot } 121737728Smckusick if (flag & IO_NDELAY) { 121837584Smarc splx(s); 121937584Smarc return (EWOULDBLOCK); 122037584Smarc } 122164416Sbostic error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, 122240712Skarels carrier ? ttyin : ttopen, 0); 12239859Ssam splx(s); 122443377Smarc if (error) 122540712Skarels return (error); 12269578Ssam goto loop; 12279578Ssam } 12289859Ssam splx(s); 122940712Skarels 12309578Ssam /* 123135811Smarc * Input present, check for input mapping and processing. 12329578Ssam */ 12339578Ssam first = 1; 12349578Ssam while ((c = getc(qp)) >= 0) { 12359578Ssam /* 123635811Smarc * delayed suspend (^Y) 12379578Ssam */ 123864416Sbostic if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) { 123942882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12409578Ssam if (first) { 124164416Sbostic if (error = ttysleep(tp, 124264416Sbostic &lbolt, TTIPRI | PCATCH, ttybg, 0)) 124340712Skarels break; 12449578Ssam goto loop; 12459578Ssam } 12469578Ssam break; 12477502Sroot } 12489578Ssam /* 124935811Smarc * Interpret EOF only in canonical mode. 12509578Ssam */ 125164416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON)) 12529578Ssam break; 12539578Ssam /* 12549578Ssam * Give user character. 12559578Ssam */ 125640712Skarels error = ureadc(c, uio); 12579578Ssam if (error) 12589578Ssam break; 125914938Smckusick if (uio->uio_resid == 0) 12609578Ssam break; 12619578Ssam /* 126235811Smarc * In canonical mode check for a "break character" 12639578Ssam * marking the end of a "line of input". 12649578Ssam */ 126564416Sbostic if (ISSET(lflag, ICANON) && TTBREAKC(c)) 12669578Ssam break; 12679578Ssam first = 0; 12687502Sroot } 12699578Ssam /* 12709578Ssam * Look to unblock output now that (presumably) 12719578Ssam * the input queue has gone down. 12729578Ssam */ 127352485Storek s = spltty(); 127464416Sbostic if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) { 127547545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 127647545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 127764416Sbostic CLR(tp->t_state, TS_TBLOCK); 12787502Sroot ttstart(tp); 12797502Sroot } 128035811Smarc } 128152485Storek splx(s); 12828520Sroot return (error); 12837502Sroot } 12847502Sroot 12857502Sroot /* 128664416Sbostic * Check the output queue on tp for space for a kernel message (from uprintf 128764416Sbostic * or tprintf). Allow some space over the normal hiwater mark so we don't 128864416Sbostic * lose messages due to normal flow control, but don't let the tty run amok. 128964416Sbostic * Sleeps here are not interruptible, but we return prematurely if new signals 129064416Sbostic * arrive. 129125391Skarels */ 129264416Sbostic int 129325391Skarels ttycheckoutq(tp, wait) 129425391Skarels register struct tty *tp; 129525391Skarels int wait; 129625391Skarels { 129730695Skarels int hiwat, s, oldsig; 129825391Skarels 129935811Smarc hiwat = tp->t_hiwat; 130025391Skarels s = spltty(); 1301*64576Sbostic oldsig = wait ? curproc->p_siglist : 0; 130225391Skarels if (tp->t_outq.c_cc > hiwat + 200) 130329946Skarels while (tp->t_outq.c_cc > hiwat) { 130429946Skarels ttstart(tp); 1305*64576Sbostic if (wait == 0 || curproc->p_siglist != oldsig) { 130629946Skarels splx(s); 130729946Skarels return (0); 130829946Skarels } 130954782Storek timeout((void (*)__P((void *)))wakeup, 131054782Storek (void *)&tp->t_outq, hz); 131164416Sbostic SET(tp->t_state, TS_ASLEEP); 131230695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 131325391Skarels } 131425391Skarels splx(s); 131525391Skarels return (1); 131625391Skarels } 131725391Skarels 131825391Skarels /* 131949380Skarels * Process a write call on a tty device. 13207502Sroot */ 132164416Sbostic int 132237584Smarc ttwrite(tp, uio, flag) 13237625Ssam register struct tty *tp; 13249578Ssam register struct uio *uio; 132552485Storek int flag; 13267502Sroot { 13277502Sroot register char *cp; 132864416Sbostic register int cc, ce; 132964416Sbostic register struct proc *p; 13309578Ssam int i, hiwat, cnt, error, s; 13317502Sroot char obuf[OBUFSIZ]; 13327502Sroot 133335811Smarc hiwat = tp->t_hiwat; 13349578Ssam cnt = uio->uio_resid; 13359578Ssam error = 0; 13367502Sroot loop: 133737584Smarc s = spltty(); 133864416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 133964416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 134064416Sbostic if (ISSET(tp->t_state, TS_ISOPEN)) { 134137584Smarc splx(s); 134237584Smarc return (EIO); 134337728Smckusick } else if (flag & IO_NDELAY) { 134437584Smarc splx(s); 134540712Skarels error = EWOULDBLOCK; 134640712Skarels goto out; 134737584Smarc } else { 134864416Sbostic /* Sleep awaiting carrier. */ 134964416Sbostic error = ttysleep(tp, 135064416Sbostic &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0); 135137584Smarc splx(s); 135243377Smarc if (error) 135340712Skarels goto out; 135437584Smarc goto loop; 135537584Smarc } 135637584Smarc } 135737584Smarc splx(s); 13589578Ssam /* 13599578Ssam * Hang the process if it's in the background. 13609578Ssam */ 136164416Sbostic p = curproc; 136264416Sbostic if (isbackground(p, tp) && 1363*64576Sbostic ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 && 136447545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 136547545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 136647545Skarels p->p_pgrp->pg_jobc) { 136747545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 136864416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 136940712Skarels goto out; 137021776Sbloom goto loop; 13717502Sroot } 13729578Ssam /* 137364416Sbostic * Process the user's data in at most OBUFSIZ chunks. Perform any 137464416Sbostic * output translation. Keep track of high water mark, sleep on 137564416Sbostic * overflow awaiting device aid in acquiring new space. 13769578Ssam */ 137764416Sbostic for (cc = 0; uio->uio_resid > 0 || cc > 0;) { 137864416Sbostic if (ISSET(tp->t_lflag, FLUSHO)) { 137940712Skarels uio->uio_resid = 0; 138040712Skarels return (0); 138140712Skarels } 138240712Skarels if (tp->t_outq.c_cc > hiwat) 138332067Skarels goto ovhiwat; 13849578Ssam /* 138564416Sbostic * Grab a hunk of data from the user, unless we have some 138664416Sbostic * leftover from last time. 13879578Ssam */ 13887822Sroot if (cc == 0) { 138940712Skarels cc = min(uio->uio_resid, OBUFSIZ); 139040712Skarels cp = obuf; 139140712Skarels error = uiomove(cp, cc, uio); 139240712Skarels if (error) { 139340712Skarels cc = 0; 139440712Skarels break; 139540712Skarels } 13967822Sroot } 13979578Ssam /* 13989578Ssam * If nothing fancy need be done, grab those characters we 13999578Ssam * can handle without any of ttyoutput's processing and 14009578Ssam * just transfer them to the output q. For those chars 14019578Ssam * which require special processing (as indicated by the 140264416Sbostic * bits in char_type), call ttyoutput. After processing 14039578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14049578Ssam * immediately. 14059578Ssam */ 14069578Ssam while (cc > 0) { 140764416Sbostic if (!ISSET(tp->t_oflag, OPOST)) 14087502Sroot ce = cc; 14097502Sroot else { 141064416Sbostic ce = cc - scanc((u_int)cc, (u_char *)cp, 141164416Sbostic (u_char *)char_type, CCLASSMASK); 14129578Ssam /* 14139578Ssam * If ce is zero, then we're processing 14149578Ssam * a special character through ttyoutput. 14159578Ssam */ 14169578Ssam if (ce == 0) { 14177502Sroot tp->t_rocount = 0; 14187502Sroot if (ttyoutput(*cp, tp) >= 0) { 141964416Sbostic /* No Clists, wait a bit. */ 142064416Sbostic ttstart(tp); 142164416Sbostic if (error = ttysleep(tp, &lbolt, 142264416Sbostic TTOPRI | PCATCH, ttybuf, 0)) 142364416Sbostic break; 142464416Sbostic goto loop; 14257502Sroot } 142664416Sbostic cp++; 142764416Sbostic cc--; 142864416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 14299578Ssam tp->t_outq.c_cc > hiwat) 14307502Sroot goto ovhiwat; 14319578Ssam continue; 14327502Sroot } 14337502Sroot } 14349578Ssam /* 143564416Sbostic * A bunch of normal characters have been found. 143664416Sbostic * Transfer them en masse to the output queue and 14379578Ssam * continue processing at the top of the loop. 14389578Ssam * If there are any further characters in this 14399578Ssam * <= OBUFSIZ chunk, the first should be a character 14409578Ssam * requiring special handling by ttyoutput. 14419578Ssam */ 14427502Sroot tp->t_rocount = 0; 14439578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14449578Ssam ce -= i; 144564530Sbostic tp->t_column += ce; 14469578Ssam cp += ce, cc -= ce, tk_nout += ce; 144735811Smarc tp->t_outcc += ce; 14489578Ssam if (i > 0) { 144964416Sbostic /* No Clists, wait a bit. */ 14507502Sroot ttstart(tp); 145164416Sbostic if (error = ttysleep(tp, 145264416Sbostic &lbolt, TTOPRI | PCATCH, ttybuf, 0)) 145340712Skarels break; 145421776Sbloom goto loop; 14557502Sroot } 145664416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 145764416Sbostic tp->t_outq.c_cc > hiwat) 145840712Skarels break; 14597502Sroot } 146035811Smarc ttstart(tp); 14617502Sroot } 146240712Skarels out: 146340712Skarels /* 146464416Sbostic * If cc is nonzero, we leave the uio structure inconsistent, as the 146564416Sbostic * offset and iov pointers have moved forward, but it doesn't matter 146664416Sbostic * (the call will either return short or restart with a new uio). 146740712Skarels */ 146840712Skarels uio->uio_resid += cc; 14698520Sroot return (error); 147040712Skarels 14717502Sroot ovhiwat: 147232067Skarels ttstart(tp); 147332067Skarels s = spltty(); 14749578Ssam /* 147535811Smarc * This can only occur if FLUSHO is set in t_lflag, 147632067Skarels * or if ttstart/oproc is synchronous (or very fast). 14779578Ssam */ 14787502Sroot if (tp->t_outq.c_cc <= hiwat) { 14799578Ssam splx(s); 14807502Sroot goto loop; 14817502Sroot } 148237728Smckusick if (flag & IO_NDELAY) { 148317545Skarels splx(s); 148440712Skarels uio->uio_resid += cc; 148564416Sbostic return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 14867502Sroot } 148764416Sbostic SET(tp->t_state, TS_ASLEEP); 148864416Sbostic error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14899578Ssam splx(s); 149043377Smarc if (error) 149140712Skarels goto out; 14927502Sroot goto loop; 14937502Sroot } 14947502Sroot 14957502Sroot /* 14967502Sroot * Rubout one character from the rawq of tp 14977502Sroot * as cleanly as possible. 14987502Sroot */ 149964416Sbostic void 15007502Sroot ttyrub(c, tp) 150164416Sbostic register int c; 15027625Ssam register struct tty *tp; 15037502Sroot { 15047502Sroot register char *cp; 15057502Sroot register int savecol; 150664416Sbostic int tabc, s; 15077502Sroot 150864416Sbostic if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 15097502Sroot return; 151064416Sbostic CLR(tp->t_lflag, FLUSHO); 151164416Sbostic if (ISSET(tp->t_lflag, ECHOE)) { 15127502Sroot if (tp->t_rocount == 0) { 15137502Sroot /* 15147502Sroot * Screwed by ttwrite; retype 15157502Sroot */ 15167502Sroot ttyretype(tp); 15177502Sroot return; 15187502Sroot } 151964416Sbostic if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 15207502Sroot ttyrubo(tp, 2); 1521*64576Sbostic else { 1522*64576Sbostic CLR(c, ~TTY_CHARMASK); 1523*64576Sbostic switch (CCLASS(c)) { 1524*64576Sbostic case ORDINARY: 1525*64576Sbostic ttyrubo(tp, 1); 1526*64576Sbostic break; 1527*64576Sbostic case BACKSPACE: 1528*64576Sbostic case CONTROL: 1529*64576Sbostic case NEWLINE: 1530*64576Sbostic case RETURN: 1531*64576Sbostic case VTAB: 1532*64576Sbostic if (ISSET(tp->t_lflag, ECHOCTL)) 1533*64576Sbostic ttyrubo(tp, 2); 1534*64576Sbostic break; 1535*64576Sbostic case TAB: 1536*64576Sbostic if (tp->t_rocount < tp->t_rawq.c_cc) { 1537*64576Sbostic ttyretype(tp); 1538*64576Sbostic return; 1539*64576Sbostic } 1540*64576Sbostic s = spltty(); 1541*64576Sbostic savecol = tp->t_column; 1542*64576Sbostic SET(tp->t_state, TS_CNTTB); 1543*64576Sbostic SET(tp->t_lflag, FLUSHO); 1544*64576Sbostic tp->t_column = tp->t_rocol; 1545*64576Sbostic cp = tp->t_rawq.c_cf; 1546*64576Sbostic if (cp) 1547*64576Sbostic tabc = *cp; /* XXX FIX NEXTC */ 1548*64576Sbostic for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 1549*64576Sbostic ttyecho(tabc, tp); 1550*64576Sbostic CLR(tp->t_lflag, FLUSHO); 1551*64576Sbostic CLR(tp->t_state, TS_CNTTB); 1552*64576Sbostic splx(s); 155364416Sbostic 1554*64576Sbostic /* savecol will now be length of the tab. */ 1555*64576Sbostic savecol -= tp->t_column; 1556*64576Sbostic tp->t_column += savecol; 1557*64576Sbostic if (savecol > 8) 1558*64576Sbostic savecol = 8; /* overflow screw */ 1559*64576Sbostic while (--savecol >= 0) 1560*64576Sbostic (void)ttyoutput('\b', tp); 1561*64576Sbostic break; 1562*64576Sbostic default: /* XXX */ 156364416Sbostic #define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 1564*64576Sbostic (void)printf(PANICSTR, c, CCLASS(c)); 156564416Sbostic #ifdef notdef 1566*64576Sbostic panic(PANICSTR, c, CCLASS(c)); 156764416Sbostic #endif 1568*64576Sbostic } 156935811Smarc } 157064416Sbostic } else if (ISSET(tp->t_lflag, ECHOPRT)) { 157164416Sbostic if (!ISSET(tp->t_state, TS_ERASE)) { 157264416Sbostic SET(tp->t_state, TS_ERASE); 157364416Sbostic (void)ttyoutput('\\', tp); 15747502Sroot } 15757502Sroot ttyecho(c, tp); 15767502Sroot } else 157735811Smarc ttyecho(tp->t_cc[VERASE], tp); 157864416Sbostic --tp->t_rocount; 15797502Sroot } 15807502Sroot 15817502Sroot /* 158264416Sbostic * Back over cnt characters, erasing them. 15837502Sroot */ 158464416Sbostic static void 15857502Sroot ttyrubo(tp, cnt) 15867625Ssam register struct tty *tp; 15877625Ssam int cnt; 15887502Sroot { 15897502Sroot 159064416Sbostic while (cnt-- > 0) { 159164416Sbostic (void)ttyoutput('\b', tp); 159264416Sbostic (void)ttyoutput(' ', tp); 159364416Sbostic (void)ttyoutput('\b', tp); 159464416Sbostic } 15957502Sroot } 15967502Sroot 15977502Sroot /* 159864416Sbostic * ttyretype -- 159964416Sbostic * Reprint the rawq line. Note, it is assumed that c_cc has already 160064416Sbostic * been checked. 16017502Sroot */ 160264416Sbostic void 16037502Sroot ttyretype(tp) 16047625Ssam register struct tty *tp; 16057502Sroot { 16067502Sroot register char *cp; 160735811Smarc int s, c; 16087502Sroot 160964416Sbostic /* Echo the reprint character. */ 161035811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 161135811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 161264416Sbostic 161364416Sbostic (void)ttyoutput('\n', tp); 161464416Sbostic 161564416Sbostic /* 161664416Sbostic * XXX 161764416Sbostic * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 161864416Sbostic * BIT OF FIRST CHAR. 161964416Sbostic */ 162017545Skarels s = spltty(); 162164416Sbostic for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 162264416Sbostic cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 162335811Smarc ttyecho(c, tp); 162464416Sbostic for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 162564416Sbostic cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 162635811Smarc ttyecho(c, tp); 162764416Sbostic CLR(tp->t_state, TS_ERASE); 16287502Sroot splx(s); 162964416Sbostic 16307502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16317502Sroot tp->t_rocol = 0; 16327502Sroot } 16337502Sroot 16347502Sroot /* 163535811Smarc * Echo a typed character to the terminal. 16367502Sroot */ 163764416Sbostic static void 16387502Sroot ttyecho(c, tp) 163964416Sbostic register int c; 16407625Ssam register struct tty *tp; 16417502Sroot { 164264416Sbostic 164364416Sbostic if (!ISSET(tp->t_state, TS_CNTTB)) 164464416Sbostic CLR(tp->t_lflag, FLUSHO); 164564416Sbostic if ((!ISSET(tp->t_lflag, ECHO) && 164664416Sbostic (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) || 164764416Sbostic ISSET(tp->t_lflag, EXTPROC)) 16487502Sroot return; 164964416Sbostic if (ISSET(tp->t_lflag, ECHOCTL) && 1650*64576Sbostic (ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 1651*64576Sbostic ISSET(c, TTY_CHARMASK) == 0177)) { 165264416Sbostic (void)ttyoutput('^', tp); 1653*64576Sbostic CLR(c, ~TTY_CHARMASK); 165464416Sbostic if (c == 0177) 165564416Sbostic c = '?'; 165664416Sbostic else 165764416Sbostic c += 'A' - 1; 16587502Sroot } 165964416Sbostic (void)ttyoutput(c, tp); 16607502Sroot } 16617502Sroot 16627502Sroot /* 166349380Skarels * Wake up any readers on a tty. 166449380Skarels */ 166564416Sbostic void 16667502Sroot ttwakeup(tp) 166747545Skarels register struct tty *tp; 16687502Sroot { 16697502Sroot 167052522Smckusick selwakeup(&tp->t_rsel); 167164416Sbostic if (ISSET(tp->t_state, TS_ASYNC)) 167264416Sbostic pgsignal(tp->t_pgrp, SIGIO, 1); 16737502Sroot wakeup((caddr_t)&tp->t_rawq); 16747502Sroot } 167535811Smarc 167635811Smarc /* 167748439Skarels * Look up a code for a specified speed in a conversion table; 167848439Skarels * used by drivers to map software speed values to hardware parameters. 167948439Skarels */ 168064416Sbostic int 168148439Skarels ttspeedtab(speed, table) 168252485Storek int speed; 168348439Skarels register struct speedtab *table; 168448439Skarels { 168548439Skarels 168648439Skarels for ( ; table->sp_speed != -1; table++) 168748439Skarels if (table->sp_speed == speed) 168848439Skarels return (table->sp_code); 168948439Skarels return (-1); 169048439Skarels } 169148439Skarels 169248439Skarels /* 169364416Sbostic * Set tty hi and low water marks. 169435811Smarc * 169535811Smarc * Try to arrange the dynamics so there's about one second 169635811Smarc * from hi to low water. 169764416Sbostic * 169835811Smarc */ 169964416Sbostic void 170035811Smarc ttsetwater(tp) 170135811Smarc struct tty *tp; 170235811Smarc { 170364416Sbostic register int cps, x; 170435811Smarc 170564416Sbostic #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 170664416Sbostic 170764416Sbostic cps = tp->t_ospeed / 10; 170864416Sbostic tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 170935811Smarc x += cps; 171064416Sbostic x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT); 171135811Smarc tp->t_hiwat = roundup(x, CBSIZE); 171264416Sbostic #undef CLAMP 171335811Smarc } 171435811Smarc 171539407Smarc /* 171639407Smarc * Report on state of foreground process group. 171739407Smarc */ 171864416Sbostic void 171939407Smarc ttyinfo(tp) 172049907Sbostic register struct tty *tp; 172139407Smarc { 172249907Sbostic register struct proc *p, *pick; 172341177Smarc struct timeval utime, stime; 172449907Sbostic int tmp; 172539407Smarc 172664416Sbostic if (ttycheckoutq(tp,0) == 0) 172739407Smarc return; 172849907Sbostic 172949907Sbostic /* Print load average. */ 173052666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 173149907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 173249907Sbostic 173339555Smarc if (tp->t_session == NULL) 173449907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 173541177Smarc else if (tp->t_pgrp == NULL) 173649907Sbostic ttyprintf(tp, "no foreground process group\n"); 173741177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 173849907Sbostic ttyprintf(tp, "empty foreground process group\n"); 173939407Smarc else { 174049907Sbostic /* Pick interesting process. */ 174149907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 174241177Smarc if (proc_compare(pick, p)) 174341177Smarc pick = p; 174449907Sbostic 174549907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 174649907Sbostic pick->p_stat == SRUN ? "running" : 174749907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 174849907Sbostic 174954782Storek calcru(pick, &utime, &stime, NULL); 175039407Smarc 175149907Sbostic /* Print user time. */ 175249907Sbostic ttyprintf(tp, "%d.%02du ", 175349907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 175441177Smarc 175549907Sbostic /* Print system time. */ 175649907Sbostic ttyprintf(tp, "%d.%02ds ", 175749907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 175849907Sbostic 175949907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 176049907Sbostic /* Print percentage cpu, resident set size. */ 176149907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 176249907Sbostic ttyprintf(tp, "%d%% %dk\n", 176352485Storek tmp / 100, 176452485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 176552485Storek pgtok(pick->p_vmspace->vm_rssize)); 176641177Smarc } 176749907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 176841177Smarc } 176941177Smarc 177041177Smarc /* 177141177Smarc * Returns 1 if p2 is "better" than p1 177241177Smarc * 177341177Smarc * The algorithm for picking the "interesting" process is thus: 177441177Smarc * 1775*64576Sbostic * 1) Only foreground processes are eligible - implied. 1776*64576Sbostic * 2) Runnable processes are favored over anything else. The runner 1777*64576Sbostic * with the highest cpu utilization is picked (p_estcpu). Ties are 177841177Smarc * broken by picking the highest pid. 1779*64576Sbostic * 3) The sleeper with the shortest sleep time is next. With ties, 1780*64576Sbostic * we pick out just "short-term" sleepers (P_SINTR == 0). 1781*64576Sbostic * 4) Further ties are broken by picking the highest pid. 178241177Smarc */ 1783*64576Sbostic #define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 178445723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 178545723Smckusick #define ONLYA 2 178645723Smckusick #define ONLYB 1 178745723Smckusick #define BOTH 3 1788*64576Sbostic 178949907Sbostic static int 179041177Smarc proc_compare(p1, p2) 179141177Smarc register struct proc *p1, *p2; 179241177Smarc { 179341177Smarc 179441177Smarc if (p1 == NULL) 179541177Smarc return (1); 179641177Smarc /* 179741177Smarc * see if at least one of them is runnable 179841177Smarc */ 1799*64576Sbostic switch (TESTAB(ISRUN(p1), ISRUN(p2))) { 180045723Smckusick case ONLYA: 180145723Smckusick return (0); 180245723Smckusick case ONLYB: 180341177Smarc return (1); 180445723Smckusick case BOTH: 180541177Smarc /* 180641177Smarc * tie - favor one with highest recent cpu utilization 180741177Smarc */ 1808*64576Sbostic if (p2->p_estcpu > p1->p_estcpu) 180941177Smarc return (1); 1810*64576Sbostic if (p1->p_estcpu > p2->p_estcpu) 181141177Smarc return (0); 181241177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 181341177Smarc } 181445723Smckusick /* 181545723Smckusick * weed out zombies 181645723Smckusick */ 181745723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 181845723Smckusick case ONLYA: 181945723Smckusick return (1); 182045723Smckusick case ONLYB: 182145723Smckusick return (0); 182245723Smckusick case BOTH: 182345723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182445723Smckusick } 182564416Sbostic /* 182641177Smarc * pick the one with the smallest sleep time 182741177Smarc */ 182841177Smarc if (p2->p_slptime > p1->p_slptime) 182941177Smarc return (0); 183041177Smarc if (p1->p_slptime > p2->p_slptime) 183141177Smarc return (1); 183241177Smarc /* 183341177Smarc * favor one sleeping in a non-interruptible sleep 183441177Smarc */ 1835*64576Sbostic if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0) 183641177Smarc return (1); 1837*64576Sbostic if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0) 183841177Smarc return (0); 183947545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 184041177Smarc } 184145723Smckusick 184239555Smarc /* 184339555Smarc * Output char to tty; console putchar style. 184439555Smarc */ 184564416Sbostic int 184639555Smarc tputchar(c, tp) 184739555Smarc int c; 184839555Smarc struct tty *tp; 184939555Smarc { 185064416Sbostic register int s; 185139555Smarc 185264416Sbostic s = spltty(); 185364416Sbostic if (ISSET(tp->t_state, 185464416Sbostic TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) { 185539555Smarc splx(s); 185664416Sbostic return (-1); 185739555Smarc } 185864416Sbostic if (c == '\n') 185964416Sbostic (void)ttyoutput('\r', tp); 186064416Sbostic (void)ttyoutput(c, tp); 186164416Sbostic ttstart(tp); 186239555Smarc splx(s); 186364416Sbostic return (0); 186439555Smarc } 186543377Smarc 186644419Smarc /* 186764416Sbostic * Sleep on chan, returning ERESTART if tty changed while we napped and 186864416Sbostic * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If 186964416Sbostic * the tty is revoked, restarting a pending call will redo validation done 187064416Sbostic * at the start of the call. 187144419Smarc */ 187264416Sbostic int 187343377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187443377Smarc struct tty *tp; 187564416Sbostic void *chan; 187664416Sbostic int pri, timo; 187743377Smarc char *wmesg; 187843377Smarc { 187943377Smarc int error; 188064416Sbostic short gen; 188143377Smarc 188264416Sbostic gen = tp->t_gen; 188343377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188443377Smarc return (error); 188564416Sbostic return (tp->t_gen == gen ? 0 : ERESTART); 188643377Smarc } 1887