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*64416Sbostic * @(#)tty.c 8.2 (Berkeley) 09/05/93 923387Smckusick */ 1039Sbill 1156517Sbostic #include <sys/param.h> 1256517Sbostic #include <sys/systm.h> 1356517Sbostic #include <sys/ioctl.h> 1456517Sbostic #include <sys/proc.h> 15*64416Sbostic #define TTYDEFCHARS 1656517Sbostic #include <sys/tty.h> 17*64416Sbostic #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 28*64416Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2)); 29*64416Sbostic static int ttnread __P((struct tty *)); 30*64416Sbostic static void ttyblock __P((struct tty *tp)); 31*64416Sbostic static void ttyecho __P((int, struct tty *tp)); 32*64416Sbostic static void ttyrubo __P((struct tty *, int)); 3349907Sbostic 34*64416Sbostic /* Symbolic sleep message strings. */ 35*64416Sbostic char ttclos[] = "ttycls"; 36*64416Sbostic char ttopen[] = "ttyopn"; 37*64416Sbostic char ttybg[] = "ttybg"; 38*64416Sbostic char ttybuf[] = "ttybuf"; 39*64416Sbostic char ttyin[] = "ttyin"; 40*64416Sbostic char ttyout[] = "ttyout"; 4140712Skarels 427436Skre /* 43*64416Sbostic * Table with character classes and parity. The 8th bit indicates parity, 44*64416Sbostic * the 7th bit indicates the character is an alphameric or underscore (for 45*64416Sbostic * ALTWERASE), and the low 6 bits indicate delay type. If the low 6 bits 46*64416Sbostic * are 0 then the character needs no special processing on output; classes 47*64416Sbostic * other than 0 might be translated or (not currently) require delays. 487436Skre */ 49*64416Sbostic #define E 0x00 /* Even parity. */ 50*64416Sbostic #define O 0x80 /* Odd parity. */ 51*64416Sbostic #define PARITY(c) (char_type[c] & O) 52*64416Sbostic 53*64416Sbostic #define ALPHA 0x40 /* Alpha or underscore. */ 54*64416Sbostic #define ISALPHA(c) (char_type[(c) & TTY_CHARMASK] & ALPHA) 55*64416Sbostic 5649380Skarels #define CCLASSMASK 0x3f 57*64416Sbostic #define CCLASS(c) (char_type[c] & CCLASSMASK) 5839Sbill 59*64416Sbostic #define BS BACKSPACE 6049380Skarels #define CC CONTROL 61*64416Sbostic #define CR RETURN 62*64416Sbostic #define NA ORDINARY | ALPHA 6349380Skarels #define NL NEWLINE 64*64416Sbostic #define NO ORDINARY 6549380Skarels #define TB TAB 6649380Skarels #define VT VTAB 6749380Skarels 68*64416Sbostic 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 /* 86*64416Sbostic * Meta chars; should be settable per character set; 87*64416Sbostic * 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 }; 106*64416Sbostic #undef BS 107*64416Sbostic #undef CC 108*64416Sbostic #undef CR 10949380Skarels #undef NA 11049380Skarels #undef NL 111*64416Sbostic #undef NO 11249380Skarels #undef TB 11349380Skarels #undef VT 1147436Skre 115*64416Sbostic /* Macros to clear/set/test flags. */ 116*64416Sbostic #define SET(t, f) (t) |= (f) 117*64416Sbostic #define CLR(t, f) (t) &= ~(f) 118*64416Sbostic #define ISSET(t, f) ((t) & (f)) 11935811Smarc 120146Sbill /* 121*64416Sbostic * Initial open of tty, or (re)entry to standard tty line discipline. 12239Sbill */ 123*64416Sbostic int 124*64416Sbostic ttyopen(device, tp) 125*64416Sbostic dev_t device; 12612752Ssam register struct tty *tp; 12712752Ssam { 12852485Storek int s; 12947545Skarels 13052485Storek s = spltty(); 131*64416Sbostic tp->t_dev = device; 132*64416Sbostic if (!ISSET(tp->t_state, TS_ISOPEN)) { 133*64416Sbostic SET(tp->t_state, TS_ISOPEN); 134*64416Sbostic bzero(&tp->t_winsize, sizeof(tp->t_winsize)); 135903Sbill } 136*64416Sbostic 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 */ 146*64416Sbostic int 1477502Sroot ttyclose(tp) 1487625Ssam register struct tty *tp; 1497502Sroot { 150*64416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 151*64416Sbostic 15230534Skarels if (constty == tp) 15330534Skarels constty = NULL; 154*64416Sbostic 155*64416Sbostic ttyflush(tp, FREAD | FWRITE); 156*64416Sbostic 157*64416Sbostic tp->t_gen++; 158*64416Sbostic tp->t_pgrp = NULL; 15939555Smarc tp->t_session = NULL; 1607502Sroot tp->t_state = 0; 16140712Skarels return (0); 1627502Sroot } 1637502Sroot 164*64416Sbostic #define FLUSHQ(q) { \ 165*64416Sbostic if ((q)->c_cc) \ 166*64416Sbostic ndflush(q, (q)->c_cc); \ 16725391Skarels } 16825391Skarels 169*64416Sbostic /* Is 'c' a line delimiter ("break" character)? */ 170*64416Sbostic #define TTBREAKC(c) \ 171*64416Sbostic ((c) == '\n' || ((c) == cc[VEOF] || \ 172*64416Sbostic (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 17325404Skarels 1747502Sroot 1757502Sroot /* 17649380Skarels * Process input of a single character received on a tty. 1777502Sroot */ 178*64416Sbostic int 1797502Sroot ttyinput(c, tp) 180*64416Sbostic register int c; 1817625Ssam register struct tty *tp; 1827502Sroot { 183*64416Sbostic register int iflag, lflag; 184*64416Sbostic register u_char *cc; 18535811Smarc int i, err; 1867502Sroot 1879578Ssam /* 1889578Ssam * If input is pending take it first. 1899578Ssam */ 190*64416Sbostic lflag = tp->t_lflag; 191*64416Sbostic if (ISSET(lflag, PENDIN)) 1927502Sroot ttypend(tp); 19335811Smarc /* 19435811Smarc * Gather stats. 19535811Smarc */ 196*64416Sbostic if (ISSET(lflag, ICANON)) { 197*64416Sbostic ++tk_cancc; 198*64416Sbostic ++tp->t_cancc; 19935811Smarc } else { 200*64416Sbostic ++tk_rawcc; 201*64416Sbostic ++tp->t_rawcc; 20235811Smarc } 203*64416Sbostic ++tk_nin; 204*64416Sbostic 205*64416Sbostic /* Handle exceptional conditions (break, parity, framing). */ 206*64416Sbostic cc = tp->t_cc; 207*64416Sbostic iflag = tp->t_iflag; 208*64416Sbostic if (err = (c & TTY_ERRORMASK)) { 20935811Smarc c &= ~TTY_ERRORMASK; 210*64416Sbostic if (err & TTY_FE && !c) { /* Break. */ 211*64416Sbostic if (ISSET(iflag, IGNBRK)) 21235811Smarc goto endcase; 213*64416Sbostic else if (ISSET(iflag, BRKINT) && 214*64416Sbostic ISSET(lflag, ISIG) && 215*64416Sbostic (cc[VINTR] != _POSIX_VDISABLE)) 21635811Smarc c = cc[VINTR]; 217*64416Sbostic else if (ISSET(iflag, PARMRK)) 21847545Skarels goto parmrk; 219*64416Sbostic } else if (err & TTY_PE && 220*64416Sbostic ISSET(iflag, INPCK) || err & TTY_FE) { 221*64416Sbostic if (ISSET(iflag, IGNPAR)) 22235811Smarc goto endcase; 223*64416Sbostic else if (ISSET(iflag, PARMRK)) { 224*64416Sbostic parmrk: putc(0377 | TTY_QUOTE, &tp->t_rawq); 225*64416Sbostic putc(0 | TTY_QUOTE, &tp->t_rawq); 226*64416Sbostic 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 */ 235*64416Sbostic if (ISSET(iflag, IXOFF)) 23635811Smarc ttyblock(tp); 237*64416Sbostic if (!ISSET(tp->t_state, TS_TYPEN) && ISSET(iflag, ISTRIP)) 23849380Skarels c &= ~0x80; 239*64416Sbostic if (!ISSET(lflag, EXTPROC)) { 24044419Smarc /* 24144419Smarc * Check for literal nexting very first 24244419Smarc */ 243*64416Sbostic if (ISSET(tp->t_state, TS_LNCH)) { 24444419Smarc c |= TTY_QUOTE; 245*64416Sbostic 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 */ 259*64416Sbostic if (ISSET(lflag, IEXTEN)) { 26044419Smarc if (CCEQ(cc[VLNEXT], c)) { 261*64416Sbostic if (ISSET(lflag, ECHO)) { 262*64416Sbostic if (ISSET(lflag, ECHOE)) { 263*64416Sbostic (void)ttyoutput('^', tp); 264*64416Sbostic (void)ttyoutput('\b', tp); 265*64416Sbostic } else 26644419Smarc ttyecho(c, tp); 26744419Smarc } 268*64416Sbostic SET(tp->t_state, TS_LNCH); 26944419Smarc goto endcase; 27044419Smarc } 27144419Smarc if (CCEQ(cc[VDISCARD], c)) { 272*64416Sbostic if (ISSET(lflag, FLUSHO)) 273*64416Sbostic 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); 279*64416Sbostic SET(tp->t_lflag, FLUSHO); 28044419Smarc } 28144419Smarc goto startoutput; 28235811Smarc } 2839578Ssam } 28444419Smarc /* 28544419Smarc * Signals. 28644419Smarc */ 287*64416Sbostic if (ISSET(lflag, ISIG)) { 28844419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 289*64416Sbostic if (!ISSET(lflag, NOFLSH)) 290*64416Sbostic 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)) { 297*64416Sbostic 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 */ 307*64416Sbostic if (ISSET(iflag, IXON)) { 30844419Smarc if (CCEQ(cc[VSTOP], c)) { 309*64416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 310*64416Sbostic 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 317*64416Sbostic return (0); 31844419Smarc } 31944419Smarc if (!CCEQ(cc[VSTART], c)) 320*64416Sbostic return (0); 321*64416Sbostic /* 322*64416Sbostic * 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') { 333*64416Sbostic if (ISSET(iflag, IGNCR)) 33444419Smarc goto endcase; 335*64416Sbostic else if (ISSET(iflag, ICRNL)) 33644419Smarc c = '\n'; 337*64416Sbostic } else if (c == '\n' && ISSET(iflag, INLCR)) 33844419Smarc c = '\r'; 3399578Ssam } 340*64416Sbostic 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)) { 357*64416Sbostic if (ISSET(lflag, ECHOKE) && 358*64416Sbostic tp->t_rawq.c_cc == tp->t_rocount && 359*64416Sbostic !ISSET(lflag, ECHOPRT)) 36044419Smarc while (tp->t_rawq.c_cc) 36144419Smarc ttyrub(unputc(&tp->t_rawq), tp); 362*64416Sbostic else { 36344419Smarc ttyecho(c, tp); 364*64416Sbostic if (ISSET(lflag, ECHOK) || 365*64416Sbostic ISSET(lflag, ECHOKE)) 36644419Smarc ttyecho('\n', tp); 367*64416Sbostic FLUSHQ(&tp->t_rawq); 36844419Smarc tp->t_rocount = 0; 36944419Smarc } 370*64416Sbostic CLR(tp->t_state, TS_LOCAL); 37144419Smarc goto endcase; 37244419Smarc } 37344419Smarc /* 37444419Smarc * word erase (^W) 37544419Smarc */ 376*64416Sbostic if (CCEQ(cc[VWERASE], c)) { 377*64416Sbostic int alt = ISSET(lflag, ALTWERASE); 37844419Smarc int ctype; 37935811Smarc 380*64416Sbostic /* 381*64416Sbostic * 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') { 39651003Sbostic 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; 408*64416Sbostic } while (c != ' ' && c != '\t' && 409*64416Sbostic (alt == 0 || ISALPHA(c) == ctype)); 410*64416Sbostic (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)) { 424*64416Sbostic if (ISSET(lflag, ISIG)) 42551068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 426*64416Sbostic 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) { 435*64416Sbostic if (ISSET(iflag, IMAXBEL)) { 43635811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 437*64416Sbostic (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) { 447*64416Sbostic if (!ISSET(lflag, ICANON)) { 44847545Skarels ttwakeup(tp); 44947545Skarels ttyecho(c, tp); 45047545Skarels goto endcase; 45147545Skarels } 452*64416Sbostic 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) 4579578Ssam tp->t_rocol = tp->t_col; 458*64416Sbostic if (ISSET(tp->t_state, TS_ERASE)) { 45935811Smarc /* 46035811Smarc * end of prterase \.../ 46135811Smarc */ 462*64416Sbostic CLR(tp->t_state, TS_ERASE); 463*64416Sbostic (void)ttyoutput('/', tp); 4649578Ssam } 4659578Ssam i = tp->t_col; 4667502Sroot ttyecho(c, tp); 467*64416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ECHO)) { 46835811Smarc /* 46935811Smarc * Place the cursor over the '^' of the ^D. 47035811Smarc */ 47155058Spendry i = min(2, tp->t_col - i); 4729578Ssam while (i > 0) { 473*64416Sbostic (void)ttyoutput('\b', tp); 4749578Ssam i--; 4759578Ssam } 4769578Ssam } 4777502Sroot } 4789578Ssam endcase: 4799578Ssam /* 48035811Smarc * IXANY means allow any character to restart output. 4819578Ssam */ 482*64416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) && 483*64416Sbostic !ISSET(iflag, IXANY) && cc[VSTART] != cc[VSTOP]) 484*64416Sbostic return (0); 4859578Ssam restartoutput: 486*64416Sbostic CLR(tp->t_lflag, FLUSHO); 487*64416Sbostic CLR(tp->t_state, TS_TTSTOP); 4889578Ssam startoutput: 489*64416Sbostic 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.). 495*64416Sbostic * Returns < 0 if succeeds, otherwise returns char to resend. 4967502Sroot * Must be recursive. 4977502Sroot */ 498*64416Sbostic int 4997502Sroot ttyoutput(c, tp) 500*64416Sbostic register int c; 5017502Sroot register struct tty *tp; 5027502Sroot { 503*64416Sbostic register long oflag; 504*64416Sbostic register int col, s; 505*64416Sbostic 506*64416Sbostic oflag = tp->t_oflag; 507*64416Sbostic if (!ISSET(oflag, OPOST)) { 508*64416Sbostic 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 /* 517*64416Sbostic * Do tab expansion if OXTABS is set. Special case if we external 518*64416Sbostic * processing, we don't do the tab expansion because we'll probably 519*64416Sbostic * get it wrong. If tab expansion needs to be done, let it happen 520*64416Sbostic * externally. 5217502Sroot */ 522*64416Sbostic c &= TTY_CHARMASK; 523*64416Sbostic if (c == '\t' && 524*64416Sbostic ISSET(oflag, OXTABS) && !ISSET(tp->t_lflag, EXTPROC)) { 525*64416Sbostic c = 8 - (tp->t_col & 7); 526*64416Sbostic if (!ISSET(tp->t_lflag, FLUSHO)) { 527*64416Sbostic 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 } 5337502Sroot tp->t_col += c; 5347502Sroot return (c ? -1 : '\t'); 5357502Sroot } 536*64416Sbostic if (c == CEOT && ISSET(oflag, ONOEOT)) 53747545Skarels return (-1); 5387502Sroot tk_nout++; 53935811Smarc tp->t_outcc++; 5407502Sroot /* 54149380Skarels * Newline translation: if ONLCR is set, 54249380Skarels * translate newline into "\r\n". 5437502Sroot */ 544*64416Sbostic if (c == '\n' && 545*64416Sbostic ISSET(tp->t_oflag, ONLCR) && ttyoutput('\r', tp) >= 0) 5467502Sroot return (c); 547*64416Sbostic if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq)) 54835811Smarc return (c); 54947545Skarels 55049380Skarels col = tp->t_col; 55149380Skarels switch (CCLASS(c)) { 5527502Sroot case BACKSPACE: 55349380Skarels if (col > 0) 554*64416Sbostic --col; 5557502Sroot break; 556*64416Sbostic case CONTROL: 557*64416Sbostic break; 5587502Sroot case NEWLINE: 559*64416Sbostic case RETURN: 56049380Skarels col = 0; 5617502Sroot break; 562*64416Sbostic case ORDINARY: 563*64416Sbostic ++col; 564*64416Sbostic break; 5657502Sroot case TAB: 566*64416Sbostic col = (col + 8) & ~7; 5677502Sroot break; 5687502Sroot } 56949380Skarels tp->t_col = col; 5707502Sroot return (-1); 5717502Sroot } 5727502Sroot 5737502Sroot /* 574*64416Sbostic * Common code for ioctls on all tty devices. Called after line-discipline 575*64416Sbostic * specific ioctl has been called to do discipline-specific functions and/or 576*64416Sbostic * reject any of these ioctl commands. 577*64416Sbostic */ 578*64416Sbostic /* ARGSUSED */ 579*64416Sbostic int 580*64416Sbostic ttioctl(tp, com, data, flag) 581*64416Sbostic register struct tty *tp; 582*64416Sbostic int com, flag; 583*64416Sbostic void *data; 584*64416Sbostic { 585*64416Sbostic extern struct tty *constty; /* Temporary virtual console. */ 586*64416Sbostic extern int nldisp; 587*64416Sbostic register struct proc *p; 588*64416Sbostic int s, error; 589*64416Sbostic 590*64416Sbostic p = curproc; /* XXX */ 591*64416Sbostic 592*64416Sbostic /* If the ioctl involves modification, hang if in the background. */ 593*64416Sbostic switch (com) { 594*64416Sbostic case TIOCFLUSH: 595*64416Sbostic case TIOCSETA: 596*64416Sbostic case TIOCSETD: 597*64416Sbostic case TIOCSETAF: 598*64416Sbostic case TIOCSETAW: 599*64416Sbostic #ifdef notdef 600*64416Sbostic case TIOCSPGRP: 601*64416Sbostic #endif 602*64416Sbostic case TIOCSTI: 603*64416Sbostic case TIOCSWINSZ: 604*64416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 605*64416Sbostic case TIOCLBIC: 606*64416Sbostic case TIOCLBIS: 607*64416Sbostic case TIOCLSET: 608*64416Sbostic case TIOCSETC: 609*64416Sbostic case OTIOCSETD: 610*64416Sbostic case TIOCSETN: 611*64416Sbostic case TIOCSETP: 612*64416Sbostic case TIOCSLTC: 613*64416Sbostic #endif 614*64416Sbostic while (isbackground(curproc, tp) && 615*64416Sbostic p->p_pgrp->pg_jobc && (p->p_flag & SPPWAIT) == 0 && 616*64416Sbostic (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 617*64416Sbostic (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 618*64416Sbostic pgsignal(p->p_pgrp, SIGTTOU, 1); 619*64416Sbostic if (error = ttysleep(tp, 620*64416Sbostic &lbolt, TTOPRI | PCATCH, ttybg, 0)) 621*64416Sbostic return (error); 622*64416Sbostic } 623*64416Sbostic break; 624*64416Sbostic } 625*64416Sbostic 626*64416Sbostic switch (com) { /* Process the ioctl. */ 627*64416Sbostic case FIOASYNC: /* set/clear async i/o */ 628*64416Sbostic s = spltty(); 629*64416Sbostic if (*(int *)data) 630*64416Sbostic SET(tp->t_state, TS_ASYNC); 631*64416Sbostic else 632*64416Sbostic CLR(tp->t_state, TS_ASYNC); 633*64416Sbostic splx(s); 634*64416Sbostic break; 635*64416Sbostic case FIONBIO: /* set/clear non-blocking i/o */ 636*64416Sbostic break; /* XXX: delete. */ 637*64416Sbostic case FIONREAD: /* get # bytes to read */ 638*64416Sbostic *(int *)data = ttnread(tp); 639*64416Sbostic break; 640*64416Sbostic case TIOCEXCL: /* set exclusive use of tty */ 641*64416Sbostic s = spltty(); 642*64416Sbostic SET(tp->t_state, TS_XCLUDE); 643*64416Sbostic splx(s); 644*64416Sbostic break; 645*64416Sbostic case TIOCFLUSH: { /* flush buffers */ 646*64416Sbostic register int flags = *(int *)data; 647*64416Sbostic 648*64416Sbostic if (flags == 0) 649*64416Sbostic flags = FREAD | FWRITE; 650*64416Sbostic else 651*64416Sbostic flags &= FREAD | FWRITE; 652*64416Sbostic ttyflush(tp, flags); 653*64416Sbostic break; 654*64416Sbostic } 655*64416Sbostic case TIOCCONS: /* become virtual console */ 656*64416Sbostic if (*(int *)data) { 657*64416Sbostic if (constty && constty != tp && 658*64416Sbostic ISSET(constty->t_state, TS_CARR_ON | TS_ISOPEN) == 659*64416Sbostic (TS_CARR_ON | TS_ISOPEN)) 660*64416Sbostic return (EBUSY); 661*64416Sbostic #ifndef UCONSOLE 662*64416Sbostic if (error = suser(p->p_ucred, &p->p_acflag)) 663*64416Sbostic return (error); 664*64416Sbostic #endif 665*64416Sbostic constty = tp; 666*64416Sbostic } else if (tp == constty) 667*64416Sbostic constty = NULL; 668*64416Sbostic break; 669*64416Sbostic case TIOCDRAIN: /* wait till output drained */ 670*64416Sbostic if (error = ttywait(tp)) 671*64416Sbostic return (error); 672*64416Sbostic break; 673*64416Sbostic case TIOCGETA: { /* get termios struct */ 674*64416Sbostic struct termios *t = (struct termios *)data; 675*64416Sbostic 676*64416Sbostic bcopy(&tp->t_termios, t, sizeof(struct termios)); 677*64416Sbostic break; 678*64416Sbostic } 679*64416Sbostic case TIOCGETD: /* get line discipline */ 680*64416Sbostic *(int *)data = tp->t_line; 681*64416Sbostic break; 682*64416Sbostic case TIOCGWINSZ: /* get window size */ 683*64416Sbostic *(struct winsize *)data = tp->t_winsize; 684*64416Sbostic break; 685*64416Sbostic case TIOCGPGRP: /* get pgrp of tty */ 686*64416Sbostic if (!isctty(p, tp)) 687*64416Sbostic return (ENOTTY); 688*64416Sbostic *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 689*64416Sbostic break; 690*64416Sbostic #ifdef TIOCHPCL 691*64416Sbostic case TIOCHPCL: /* hang up on last close */ 692*64416Sbostic s = spltty(); 693*64416Sbostic tp->t_cflag |= HUPCL; 694*64416Sbostic splx(s); 695*64416Sbostic break; 696*64416Sbostic #endif 697*64416Sbostic case TIOCNXCL: /* reset exclusive use of tty */ 698*64416Sbostic s = spltty(); 699*64416Sbostic CLR(tp->t_state, TS_XCLUDE); 700*64416Sbostic splx(s); 701*64416Sbostic break; 702*64416Sbostic case TIOCOUTQ: /* output queue size */ 703*64416Sbostic *(int *)data = tp->t_outq.c_cc; 704*64416Sbostic break; 705*64416Sbostic case TIOCSETA: /* set termios struct */ 706*64416Sbostic case TIOCSETAW: /* drain output, set */ 707*64416Sbostic case TIOCSETAF: { /* drn out, fls in, set */ 708*64416Sbostic register struct termios *t = (struct termios *)data; 709*64416Sbostic 710*64416Sbostic s = spltty(); 711*64416Sbostic if (com == TIOCSETAW || com == TIOCSETAF) { 712*64416Sbostic if (error = ttywait(tp)) { 713*64416Sbostic splx(s); 714*64416Sbostic return (error); 715*64416Sbostic } 716*64416Sbostic if (com == TIOCSETAF) 717*64416Sbostic ttyflush(tp, FREAD); 718*64416Sbostic } 719*64416Sbostic if (!ISSET(t->c_cflag, CIGNORE)) { 720*64416Sbostic /* 721*64416Sbostic * Set device hardware. 722*64416Sbostic */ 723*64416Sbostic if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 724*64416Sbostic splx(s); 725*64416Sbostic return (error); 726*64416Sbostic } else { 727*64416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 728*64416Sbostic ISSET(tp->t_cflag, CLOCAL) && 729*64416Sbostic !ISSET(t->c_cflag, CLOCAL)) { 730*64416Sbostic CLR(tp->t_state, TS_ISOPEN); 731*64416Sbostic SET(tp->t_state, TS_WOPEN); 732*64416Sbostic ttwakeup(tp); 733*64416Sbostic } 734*64416Sbostic tp->t_cflag = t->c_cflag; 735*64416Sbostic tp->t_ispeed = t->c_ispeed; 736*64416Sbostic tp->t_ospeed = t->c_ospeed; 737*64416Sbostic } 738*64416Sbostic ttsetwater(tp); 739*64416Sbostic } 740*64416Sbostic if (com != TIOCSETAF) { 741*64416Sbostic if (ISSET(t->c_lflag, ICANON) != 742*64416Sbostic ISSET(tp->t_lflag, ICANON)) 743*64416Sbostic if (ISSET(t->c_lflag, ICANON)) { 744*64416Sbostic tp->t_lflag |= PENDIN; 745*64416Sbostic ttwakeup(tp); 746*64416Sbostic } else { 747*64416Sbostic struct clist tq; 748*64416Sbostic 749*64416Sbostic catq(&tp->t_rawq, &tp->t_canq); 750*64416Sbostic tq = tp->t_rawq; 751*64416Sbostic tp->t_rawq = tp->t_canq; 752*64416Sbostic tp->t_canq = tq; 753*64416Sbostic } 754*64416Sbostic } 755*64416Sbostic tp->t_iflag = t->c_iflag; 756*64416Sbostic tp->t_oflag = t->c_oflag; 757*64416Sbostic /* 758*64416Sbostic * Make the EXTPROC bit read only. 759*64416Sbostic */ 760*64416Sbostic if (ISSET(tp->t_lflag, EXTPROC)) 761*64416Sbostic SET(t->c_lflag, EXTPROC); 762*64416Sbostic else 763*64416Sbostic CLR(t->c_lflag, EXTPROC); 764*64416Sbostic tp->t_lflag = t->c_lflag; 765*64416Sbostic bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 766*64416Sbostic splx(s); 767*64416Sbostic break; 768*64416Sbostic } 769*64416Sbostic case TIOCSETD: { /* set line discipline */ 770*64416Sbostic register int t = *(int *)data; 771*64416Sbostic dev_t device = tp->t_dev; 772*64416Sbostic 773*64416Sbostic if ((u_int)t >= nldisp) 774*64416Sbostic return (ENXIO); 775*64416Sbostic if (t != tp->t_line) { 776*64416Sbostic s = spltty(); 777*64416Sbostic (*linesw[tp->t_line].l_close)(tp, flag); 778*64416Sbostic error = (*linesw[t].l_open)(device, tp); 779*64416Sbostic if (error) { 780*64416Sbostic (void)(*linesw[tp->t_line].l_open)(device, tp); 781*64416Sbostic splx(s); 782*64416Sbostic return (error); 783*64416Sbostic } 784*64416Sbostic tp->t_line = t; 785*64416Sbostic splx(s); 786*64416Sbostic } 787*64416Sbostic break; 788*64416Sbostic } 789*64416Sbostic case TIOCSTART: /* start output, like ^Q */ 790*64416Sbostic s = spltty(); 791*64416Sbostic if (ISSET(tp->t_state, TS_TTSTOP) || 792*64416Sbostic ISSET(tp->t_lflag, FLUSHO)) { 793*64416Sbostic CLR(tp->t_lflag, FLUSHO); 794*64416Sbostic CLR(tp->t_state, TS_TTSTOP); 795*64416Sbostic ttstart(tp); 796*64416Sbostic } 797*64416Sbostic splx(s); 798*64416Sbostic break; 799*64416Sbostic case TIOCSTI: /* simulate terminal input */ 800*64416Sbostic if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 801*64416Sbostic return (EPERM); 802*64416Sbostic if (p->p_ucred->cr_uid && !isctty(p, tp)) 803*64416Sbostic return (EACCES); 804*64416Sbostic (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); 805*64416Sbostic break; 806*64416Sbostic case TIOCSTOP: /* stop output, like ^S */ 807*64416Sbostic s = spltty(); 808*64416Sbostic if (!ISSET(tp->t_state, TS_TTSTOP)) { 809*64416Sbostic SET(tp->t_state, TS_TTSTOP); 810*64416Sbostic #ifdef sun4c /* XXX */ 811*64416Sbostic (*tp->t_stop)(tp, 0); 812*64416Sbostic #else 813*64416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 814*64416Sbostic #endif 815*64416Sbostic } 816*64416Sbostic splx(s); 817*64416Sbostic break; 818*64416Sbostic case TIOCSCTTY: /* become controlling tty */ 819*64416Sbostic /* Session ctty vnode pointer set in vnode layer. */ 820*64416Sbostic if (!SESS_LEADER(p) || 821*64416Sbostic (p->p_session->s_ttyvp || tp->t_session) && 822*64416Sbostic (tp->t_session != p->p_session)) 823*64416Sbostic return (EPERM); 824*64416Sbostic tp->t_session = p->p_session; 825*64416Sbostic tp->t_pgrp = p->p_pgrp; 826*64416Sbostic p->p_session->s_ttyp = tp; 827*64416Sbostic p->p_flag |= SCTTY; 828*64416Sbostic break; 829*64416Sbostic case TIOCSPGRP: { /* set pgrp of tty */ 830*64416Sbostic register struct pgrp *pgrp = pgfind(*(int *)data); 831*64416Sbostic 832*64416Sbostic if (!isctty(p, tp)) 833*64416Sbostic return (ENOTTY); 834*64416Sbostic else if (pgrp == NULL || pgrp->pg_session != p->p_session) 835*64416Sbostic return (EPERM); 836*64416Sbostic tp->t_pgrp = pgrp; 837*64416Sbostic break; 838*64416Sbostic } 839*64416Sbostic case TIOCSWINSZ: /* set window size */ 840*64416Sbostic if (bcmp((caddr_t)&tp->t_winsize, data, 841*64416Sbostic sizeof (struct winsize))) { 842*64416Sbostic tp->t_winsize = *(struct winsize *)data; 843*64416Sbostic pgsignal(tp->t_pgrp, SIGWINCH, 1); 844*64416Sbostic } 845*64416Sbostic break; 846*64416Sbostic default: 847*64416Sbostic #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 848*64416Sbostic return (ttcompat(tp, com, data, flag)); 849*64416Sbostic #else 850*64416Sbostic return (-1); 851*64416Sbostic #endif 852*64416Sbostic } 853*64416Sbostic return (0); 854*64416Sbostic } 855*64416Sbostic 856*64416Sbostic int 857*64416Sbostic ttselect(device, rw, p) 858*64416Sbostic dev_t device; 859*64416Sbostic int rw; 860*64416Sbostic struct proc *p; 861*64416Sbostic { 862*64416Sbostic register struct tty *tp; 863*64416Sbostic int nread, s; 864*64416Sbostic 865*64416Sbostic tp = &cdevsw[major(device)].d_ttys[minor(device)]; 866*64416Sbostic 867*64416Sbostic s = spltty(); 868*64416Sbostic switch (rw) { 869*64416Sbostic case FREAD: 870*64416Sbostic nread = ttnread(tp); 871*64416Sbostic if (nread > 0 || !ISSET(tp->t_cflag, CLOCAL) && 872*64416Sbostic !ISSET(tp->t_state, TS_CARR_ON)) 873*64416Sbostic goto win; 874*64416Sbostic selrecord(p, &tp->t_rsel); 875*64416Sbostic break; 876*64416Sbostic case FWRITE: 877*64416Sbostic if (tp->t_outq.c_cc <= tp->t_lowat) { 878*64416Sbostic win: splx(s); 879*64416Sbostic return (1); 880*64416Sbostic } 881*64416Sbostic selrecord(p, &tp->t_wsel); 882*64416Sbostic break; 883*64416Sbostic } 884*64416Sbostic splx(s); 885*64416Sbostic return (0); 886*64416Sbostic } 887*64416Sbostic 888*64416Sbostic static int 889*64416Sbostic ttnread(tp) 890*64416Sbostic struct tty *tp; 891*64416Sbostic { 892*64416Sbostic int nread; 893*64416Sbostic 894*64416Sbostic if (ISSET(tp->t_lflag, PENDIN)) 895*64416Sbostic ttypend(tp); 896*64416Sbostic nread = tp->t_canq.c_cc; 897*64416Sbostic if (!ISSET(tp->t_lflag, ICANON)) 898*64416Sbostic nread += tp->t_rawq.c_cc; 899*64416Sbostic return (nread); 900*64416Sbostic } 901*64416Sbostic 902*64416Sbostic /* 903*64416Sbostic * Wait for output to drain. 904*64416Sbostic */ 905*64416Sbostic int 906*64416Sbostic ttywait(tp) 907*64416Sbostic register struct tty *tp; 908*64416Sbostic { 909*64416Sbostic int error, s; 910*64416Sbostic 911*64416Sbostic error = 0; 912*64416Sbostic s = spltty(); 913*64416Sbostic while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && 914*64416Sbostic (ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL)) 915*64416Sbostic && tp->t_oproc) { 916*64416Sbostic (*tp->t_oproc)(tp); 917*64416Sbostic SET(tp->t_state, TS_ASLEEP); 918*64416Sbostic if (error = ttysleep(tp, 919*64416Sbostic &tp->t_outq, TTOPRI | PCATCH, ttyout, 0)) 920*64416Sbostic break; 921*64416Sbostic } 922*64416Sbostic splx(s); 923*64416Sbostic return (error); 924*64416Sbostic } 925*64416Sbostic 926*64416Sbostic /* 927*64416Sbostic * Flush if successfully wait. 928*64416Sbostic */ 929*64416Sbostic int 930*64416Sbostic ttywflush(tp) 931*64416Sbostic struct tty *tp; 932*64416Sbostic { 933*64416Sbostic int error; 934*64416Sbostic 935*64416Sbostic if ((error = ttywait(tp)) == 0) 936*64416Sbostic ttyflush(tp, FREAD); 937*64416Sbostic return (error); 938*64416Sbostic } 939*64416Sbostic 940*64416Sbostic /* 941*64416Sbostic * Flush tty read and/or write queues, notifying anyone waiting. 942*64416Sbostic */ 943*64416Sbostic void 944*64416Sbostic ttyflush(tp, rw) 945*64416Sbostic register struct tty *tp; 946*64416Sbostic int rw; 947*64416Sbostic { 948*64416Sbostic register int s; 949*64416Sbostic 950*64416Sbostic s = spltty(); 951*64416Sbostic if (rw & FREAD) { 952*64416Sbostic FLUSHQ(&tp->t_canq); 953*64416Sbostic FLUSHQ(&tp->t_rawq); 954*64416Sbostic tp->t_rocount = 0; 955*64416Sbostic tp->t_rocol = 0; 956*64416Sbostic CLR(tp->t_state, TS_LOCAL); 957*64416Sbostic ttwakeup(tp); 958*64416Sbostic } 959*64416Sbostic if (rw & FWRITE) { 960*64416Sbostic CLR(tp->t_state, TS_TTSTOP); 961*64416Sbostic #ifdef sun4c /* XXX */ 962*64416Sbostic (*tp->t_stop)(tp, rw); 963*64416Sbostic #else 964*64416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 965*64416Sbostic #endif 966*64416Sbostic FLUSHQ(&tp->t_outq); 967*64416Sbostic wakeup((caddr_t)&tp->t_outq); 968*64416Sbostic selwakeup(&tp->t_wsel); 969*64416Sbostic } 970*64416Sbostic splx(s); 971*64416Sbostic } 972*64416Sbostic 973*64416Sbostic /* 974*64416Sbostic * Copy in the default termios characters. 975*64416Sbostic */ 976*64416Sbostic void 977*64416Sbostic ttychars(tp) 978*64416Sbostic struct tty *tp; 979*64416Sbostic { 980*64416Sbostic 981*64416Sbostic bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 982*64416Sbostic } 983*64416Sbostic 984*64416Sbostic /* 985*64416Sbostic * Send stop character on input overflow. 986*64416Sbostic */ 987*64416Sbostic static void 988*64416Sbostic ttyblock(tp) 989*64416Sbostic register struct tty *tp; 990*64416Sbostic { 991*64416Sbostic register int total; 992*64416Sbostic 993*64416Sbostic total = tp->t_rawq.c_cc + tp->t_canq.c_cc; 994*64416Sbostic if (tp->t_rawq.c_cc > TTYHOG) { 995*64416Sbostic ttyflush(tp, FREAD | FWRITE); 996*64416Sbostic CLR(tp->t_state, TS_TBLOCK); 997*64416Sbostic } 998*64416Sbostic /* 999*64416Sbostic * Block further input iff: current input > threshold 1000*64416Sbostic * AND input is available to user program. 1001*64416Sbostic */ 1002*64416Sbostic if (total >= TTYHOG / 2 && 1003*64416Sbostic !ISSET(tp->t_state, TS_TBLOCK) && 1004*64416Sbostic !ISSET(tp->t_lflag, ICANON) || tp->t_canq.c_cc > 0 && 1005*64416Sbostic tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 1006*64416Sbostic if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 1007*64416Sbostic SET(tp->t_state, TS_TBLOCK); 1008*64416Sbostic ttstart(tp); 1009*64416Sbostic } 1010*64416Sbostic } 1011*64416Sbostic } 1012*64416Sbostic 1013*64416Sbostic void 1014*64416Sbostic ttrstrt(tp_arg) 1015*64416Sbostic void *tp_arg; 1016*64416Sbostic { 1017*64416Sbostic struct tty *tp; 1018*64416Sbostic int s; 1019*64416Sbostic 1020*64416Sbostic #ifdef DIAGNOSTIC 1021*64416Sbostic if (tp_arg == NULL) 1022*64416Sbostic panic("ttrstrt"); 1023*64416Sbostic #endif 1024*64416Sbostic tp = tp_arg; 1025*64416Sbostic s = spltty(); 1026*64416Sbostic 1027*64416Sbostic CLR(tp->t_state, TS_TIMEOUT); 1028*64416Sbostic ttstart(tp); 1029*64416Sbostic 1030*64416Sbostic splx(s); 1031*64416Sbostic } 1032*64416Sbostic 1033*64416Sbostic int 1034*64416Sbostic ttstart(tp) 1035*64416Sbostic struct tty *tp; 1036*64416Sbostic { 1037*64416Sbostic 1038*64416Sbostic if (tp->t_oproc != NULL) /* XXX: Kludge for pty. */ 1039*64416Sbostic (*tp->t_oproc)(tp); 1040*64416Sbostic return (0); 1041*64416Sbostic } 1042*64416Sbostic 1043*64416Sbostic /* 1044*64416Sbostic * "close" a line discipline 1045*64416Sbostic */ 1046*64416Sbostic int 1047*64416Sbostic ttylclose(tp, flag) 1048*64416Sbostic struct tty *tp; 1049*64416Sbostic int flag; 1050*64416Sbostic { 1051*64416Sbostic 1052*64416Sbostic if (flag & IO_NDELAY) 1053*64416Sbostic ttyflush(tp, FREAD | FWRITE); 1054*64416Sbostic else 1055*64416Sbostic ttywflush(tp); 1056*64416Sbostic return (0); 1057*64416Sbostic } 1058*64416Sbostic 1059*64416Sbostic /* 1060*64416Sbostic * Handle modem control transition on a tty. 1061*64416Sbostic * Flag indicates new state of carrier. 1062*64416Sbostic * Returns 0 if the line should be turned off, otherwise 1. 1063*64416Sbostic */ 1064*64416Sbostic int 1065*64416Sbostic ttymodem(tp, flag) 1066*64416Sbostic register struct tty *tp; 1067*64416Sbostic int flag; 1068*64416Sbostic { 1069*64416Sbostic 1070*64416Sbostic if (!ISSET(tp->t_state, TS_WOPEN) && ISSET(tp->t_cflag, MDMBUF)) { 1071*64416Sbostic /* 1072*64416Sbostic * MDMBUF: do flow control according to carrier flag 1073*64416Sbostic */ 1074*64416Sbostic if (flag) { 1075*64416Sbostic CLR(tp->t_state, TS_TTSTOP); 1076*64416Sbostic ttstart(tp); 1077*64416Sbostic } else if (!ISSET(tp->t_state, TS_TTSTOP)) { 1078*64416Sbostic SET(tp->t_state, TS_TTSTOP); 1079*64416Sbostic #ifdef sun4c /* XXX */ 1080*64416Sbostic (*tp->t_stop)(tp, 0); 1081*64416Sbostic #else 1082*64416Sbostic (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 1083*64416Sbostic #endif 1084*64416Sbostic } 1085*64416Sbostic } else if (flag == 0) { 1086*64416Sbostic /* 1087*64416Sbostic * Lost carrier. 1088*64416Sbostic */ 1089*64416Sbostic CLR(tp->t_state, TS_CARR_ON); 1090*64416Sbostic if (ISSET(tp->t_state, TS_ISOPEN) && 1091*64416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 1092*64416Sbostic if (tp->t_session && tp->t_session->s_leader) 1093*64416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 1094*64416Sbostic ttyflush(tp, FREAD | FWRITE); 1095*64416Sbostic return (0); 1096*64416Sbostic } 1097*64416Sbostic } else { 1098*64416Sbostic /* 1099*64416Sbostic * Carrier now on. 1100*64416Sbostic */ 1101*64416Sbostic SET(tp->t_state, TS_CARR_ON); 1102*64416Sbostic ttwakeup(tp); 1103*64416Sbostic } 1104*64416Sbostic return (1); 1105*64416Sbostic } 1106*64416Sbostic 1107*64416Sbostic /* 1108*64416Sbostic * Default modem control routine (for other line disciplines). 1109*64416Sbostic * Return argument flag, to turn off device on carrier drop. 1110*64416Sbostic */ 1111*64416Sbostic int 1112*64416Sbostic nullmodem(tp, flag) 1113*64416Sbostic register struct tty *tp; 1114*64416Sbostic int flag; 1115*64416Sbostic { 1116*64416Sbostic 1117*64416Sbostic if (flag) 1118*64416Sbostic SET(tp->t_state, TS_CARR_ON); 1119*64416Sbostic else { 1120*64416Sbostic CLR(tp->t_state, TS_CARR_ON); 1121*64416Sbostic if (!ISSET(tp->t_cflag, CLOCAL)) { 1122*64416Sbostic if (tp->t_session && tp->t_session->s_leader) 1123*64416Sbostic psignal(tp->t_session->s_leader, SIGHUP); 1124*64416Sbostic return (0); 1125*64416Sbostic } 1126*64416Sbostic } 1127*64416Sbostic return (1); 1128*64416Sbostic } 1129*64416Sbostic 1130*64416Sbostic /* 1131*64416Sbostic * Reinput pending characters after state switch 1132*64416Sbostic * call at spltty(). 1133*64416Sbostic */ 1134*64416Sbostic void 1135*64416Sbostic ttypend(tp) 1136*64416Sbostic register struct tty *tp; 1137*64416Sbostic { 1138*64416Sbostic struct clist tq; 1139*64416Sbostic register c; 1140*64416Sbostic 1141*64416Sbostic CLR(tp->t_lflag, PENDIN); 1142*64416Sbostic SET(tp->t_state, TS_TYPEN); 1143*64416Sbostic tq = tp->t_rawq; 1144*64416Sbostic tp->t_rawq.c_cc = 0; 1145*64416Sbostic tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 1146*64416Sbostic while ((c = getc(&tq)) >= 0) 1147*64416Sbostic ttyinput(c, tp); 1148*64416Sbostic CLR(tp->t_state, TS_TYPEN); 1149*64416Sbostic } 1150*64416Sbostic 1151*64416Sbostic /* 115249380Skarels * Process a read call on a tty device. 11537502Sroot */ 1154*64416Sbostic int 115537584Smarc ttread(tp, uio, flag) 11567625Ssam register struct tty *tp; 11577722Swnj struct uio *uio; 115852485Storek int flag; 11597502Sroot { 11607502Sroot register struct clist *qp; 116135811Smarc register int c; 116241383Smarc register long lflag; 116335811Smarc register u_char *cc = tp->t_cc; 116447545Skarels register struct proc *p = curproc; 11659859Ssam int s, first, error = 0; 11667502Sroot 1167*64416Sbostic loop: lflag = tp->t_lflag; 116837584Smarc s = spltty(); 11699578Ssam /* 1170*64416Sbostic * take pending input first 11719578Ssam */ 1172*64416Sbostic if (ISSET(lflag, PENDIN)) 11737502Sroot ttypend(tp); 11749859Ssam splx(s); 117540712Skarels 11769578Ssam /* 11779578Ssam * Hang process if it's in the background. 11789578Ssam */ 117947545Skarels if (isbackground(p, tp)) { 118047545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 118147545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 1182*64416Sbostic p->p_flag & SPPWAIT || p->p_pgrp->pg_jobc == 0) 11838520Sroot return (EIO); 118447545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 1185*64416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 118640712Skarels return (error); 118723165Sbloom goto loop; 11887502Sroot } 118940712Skarels 11909578Ssam /* 119135811Smarc * If canonical, use the canonical queue, 119235811Smarc * else use the raw queue. 119337584Smarc * 119447545Skarels * (should get rid of clists...) 11959578Ssam */ 1196*64416Sbostic qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; 119740712Skarels 11989578Ssam /* 119940712Skarels * If there is no input, sleep on rawq 120040712Skarels * awaiting hardware receipt and notification. 120140712Skarels * If we have data, we don't need to check for carrier. 12029578Ssam */ 120317545Skarels s = spltty(); 12049578Ssam if (qp->c_cc <= 0) { 120540712Skarels int carrier; 120640712Skarels 1207*64416Sbostic carrier = ISSET(tp->t_state, TS_CARR_ON) || 1208*64416Sbostic ISSET(tp->t_cflag, CLOCAL); 1209*64416Sbostic if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { 12109859Ssam splx(s); 121140712Skarels return (0); /* EOF */ 12127502Sroot } 121337728Smckusick if (flag & IO_NDELAY) { 121437584Smarc splx(s); 121537584Smarc return (EWOULDBLOCK); 121637584Smarc } 1217*64416Sbostic error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, 121840712Skarels carrier ? ttyin : ttopen, 0); 12199859Ssam splx(s); 122043377Smarc if (error) 122140712Skarels return (error); 12229578Ssam goto loop; 12239578Ssam } 12249859Ssam splx(s); 122540712Skarels 12269578Ssam /* 122735811Smarc * Input present, check for input mapping and processing. 12289578Ssam */ 12299578Ssam first = 1; 12309578Ssam while ((c = getc(qp)) >= 0) { 12319578Ssam /* 123235811Smarc * delayed suspend (^Y) 12339578Ssam */ 1234*64416Sbostic if (CCEQ(cc[VDSUSP], c) && ISSET(lflag, ISIG)) { 123542882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12369578Ssam if (first) { 1237*64416Sbostic if (error = ttysleep(tp, 1238*64416Sbostic &lbolt, TTIPRI | PCATCH, ttybg, 0)) 123940712Skarels break; 12409578Ssam goto loop; 12419578Ssam } 12429578Ssam break; 12437502Sroot } 12449578Ssam /* 124535811Smarc * Interpret EOF only in canonical mode. 12469578Ssam */ 1247*64416Sbostic if (CCEQ(cc[VEOF], c) && ISSET(lflag, ICANON)) 12489578Ssam break; 12499578Ssam /* 12509578Ssam * Give user character. 12519578Ssam */ 125240712Skarels error = ureadc(c, uio); 12539578Ssam if (error) 12549578Ssam break; 125514938Smckusick if (uio->uio_resid == 0) 12569578Ssam break; 12579578Ssam /* 125835811Smarc * In canonical mode check for a "break character" 12599578Ssam * marking the end of a "line of input". 12609578Ssam */ 1261*64416Sbostic if (ISSET(lflag, ICANON) && TTBREAKC(c)) 12629578Ssam break; 12639578Ssam first = 0; 12647502Sroot } 12659578Ssam /* 12669578Ssam * Look to unblock output now that (presumably) 12679578Ssam * the input queue has gone down. 12689578Ssam */ 126952485Storek s = spltty(); 1270*64416Sbostic if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) { 127147545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 127247545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 1273*64416Sbostic CLR(tp->t_state, TS_TBLOCK); 12747502Sroot ttstart(tp); 12757502Sroot } 127635811Smarc } 127752485Storek splx(s); 12788520Sroot return (error); 12797502Sroot } 12807502Sroot 12817502Sroot /* 1282*64416Sbostic * Check the output queue on tp for space for a kernel message (from uprintf 1283*64416Sbostic * or tprintf). Allow some space over the normal hiwater mark so we don't 1284*64416Sbostic * lose messages due to normal flow control, but don't let the tty run amok. 1285*64416Sbostic * Sleeps here are not interruptible, but we return prematurely if new signals 1286*64416Sbostic * arrive. 128725391Skarels */ 1288*64416Sbostic int 128925391Skarels ttycheckoutq(tp, wait) 129025391Skarels register struct tty *tp; 129125391Skarels int wait; 129225391Skarels { 129330695Skarels int hiwat, s, oldsig; 129425391Skarels 129535811Smarc hiwat = tp->t_hiwat; 129625391Skarels s = spltty(); 129752485Storek oldsig = wait ? curproc->p_sig : 0; 129825391Skarels if (tp->t_outq.c_cc > hiwat + 200) 129929946Skarels while (tp->t_outq.c_cc > hiwat) { 130029946Skarels ttstart(tp); 130147545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 130229946Skarels splx(s); 130329946Skarels return (0); 130429946Skarels } 130554782Storek timeout((void (*)__P((void *)))wakeup, 130654782Storek (void *)&tp->t_outq, hz); 1307*64416Sbostic SET(tp->t_state, TS_ASLEEP); 130830695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 130925391Skarels } 131025391Skarels splx(s); 131125391Skarels return (1); 131225391Skarels } 131325391Skarels 131425391Skarels /* 131549380Skarels * Process a write call on a tty device. 13167502Sroot */ 1317*64416Sbostic int 131837584Smarc ttwrite(tp, uio, flag) 13197625Ssam register struct tty *tp; 13209578Ssam register struct uio *uio; 132152485Storek int flag; 13227502Sroot { 13237502Sroot register char *cp; 1324*64416Sbostic register int cc, ce; 1325*64416Sbostic register struct proc *p; 13269578Ssam int i, hiwat, cnt, error, s; 13277502Sroot char obuf[OBUFSIZ]; 13287502Sroot 132935811Smarc hiwat = tp->t_hiwat; 13309578Ssam cnt = uio->uio_resid; 13319578Ssam error = 0; 13327502Sroot loop: 133337584Smarc s = spltty(); 1334*64416Sbostic if (!ISSET(tp->t_state, TS_CARR_ON) && 1335*64416Sbostic !ISSET(tp->t_cflag, CLOCAL)) { 1336*64416Sbostic if (ISSET(tp->t_state, TS_ISOPEN)) { 133737584Smarc splx(s); 133837584Smarc return (EIO); 133937728Smckusick } else if (flag & IO_NDELAY) { 134037584Smarc splx(s); 134140712Skarels error = EWOULDBLOCK; 134240712Skarels goto out; 134337584Smarc } else { 1344*64416Sbostic /* Sleep awaiting carrier. */ 1345*64416Sbostic error = ttysleep(tp, 1346*64416Sbostic &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0); 134737584Smarc splx(s); 134843377Smarc if (error) 134940712Skarels goto out; 135037584Smarc goto loop; 135137584Smarc } 135237584Smarc } 135337584Smarc splx(s); 13549578Ssam /* 13559578Ssam * Hang the process if it's in the background. 13569578Ssam */ 1357*64416Sbostic p = curproc; 1358*64416Sbostic if (isbackground(p, tp) && 1359*64416Sbostic ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & SPPWAIT) == 0 && 136047545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 136147545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 136247545Skarels p->p_pgrp->pg_jobc) { 136347545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 1364*64416Sbostic if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0)) 136540712Skarels goto out; 136621776Sbloom goto loop; 13677502Sroot } 13689578Ssam /* 1369*64416Sbostic * Process the user's data in at most OBUFSIZ chunks. Perform any 1370*64416Sbostic * output translation. Keep track of high water mark, sleep on 1371*64416Sbostic * overflow awaiting device aid in acquiring new space. 13729578Ssam */ 1373*64416Sbostic for (cc = 0; uio->uio_resid > 0 || cc > 0;) { 1374*64416Sbostic if (ISSET(tp->t_lflag, FLUSHO)) { 137540712Skarels uio->uio_resid = 0; 137640712Skarels return (0); 137740712Skarels } 137840712Skarels if (tp->t_outq.c_cc > hiwat) 137932067Skarels goto ovhiwat; 13809578Ssam /* 1381*64416Sbostic * Grab a hunk of data from the user, unless we have some 1382*64416Sbostic * leftover from last time. 13839578Ssam */ 13847822Sroot if (cc == 0) { 138540712Skarels cc = min(uio->uio_resid, OBUFSIZ); 138640712Skarels cp = obuf; 138740712Skarels error = uiomove(cp, cc, uio); 138840712Skarels if (error) { 138940712Skarels cc = 0; 139040712Skarels break; 139140712Skarels } 13927822Sroot } 13939578Ssam /* 13949578Ssam * If nothing fancy need be done, grab those characters we 13959578Ssam * can handle without any of ttyoutput's processing and 13969578Ssam * just transfer them to the output q. For those chars 13979578Ssam * which require special processing (as indicated by the 1398*64416Sbostic * bits in char_type), call ttyoutput. After processing 13999578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14009578Ssam * immediately. 14019578Ssam */ 14029578Ssam while (cc > 0) { 1403*64416Sbostic if (!ISSET(tp->t_oflag, OPOST)) 14047502Sroot ce = cc; 14057502Sroot else { 1406*64416Sbostic ce = cc - scanc((u_int)cc, (u_char *)cp, 1407*64416Sbostic (u_char *)char_type, CCLASSMASK); 14089578Ssam /* 14099578Ssam * If ce is zero, then we're processing 14109578Ssam * a special character through ttyoutput. 14119578Ssam */ 14129578Ssam if (ce == 0) { 14137502Sroot tp->t_rocount = 0; 14147502Sroot if (ttyoutput(*cp, tp) >= 0) { 1415*64416Sbostic /* No Clists, wait a bit. */ 1416*64416Sbostic ttstart(tp); 1417*64416Sbostic if (error = ttysleep(tp, &lbolt, 1418*64416Sbostic TTOPRI | PCATCH, ttybuf, 0)) 1419*64416Sbostic break; 1420*64416Sbostic goto loop; 14217502Sroot } 1422*64416Sbostic cp++; 1423*64416Sbostic cc--; 1424*64416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 14259578Ssam tp->t_outq.c_cc > hiwat) 14267502Sroot goto ovhiwat; 14279578Ssam continue; 14287502Sroot } 14297502Sroot } 14309578Ssam /* 1431*64416Sbostic * A bunch of normal characters have been found. 1432*64416Sbostic * Transfer them en masse to the output queue and 14339578Ssam * continue processing at the top of the loop. 14349578Ssam * If there are any further characters in this 14359578Ssam * <= OBUFSIZ chunk, the first should be a character 14369578Ssam * requiring special handling by ttyoutput. 14379578Ssam */ 14387502Sroot tp->t_rocount = 0; 14399578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14409578Ssam ce -= i; 14419578Ssam tp->t_col += ce; 14429578Ssam cp += ce, cc -= ce, tk_nout += ce; 144335811Smarc tp->t_outcc += ce; 14449578Ssam if (i > 0) { 1445*64416Sbostic /* No Clists, wait a bit. */ 14467502Sroot ttstart(tp); 1447*64416Sbostic if (error = ttysleep(tp, 1448*64416Sbostic &lbolt, TTOPRI | PCATCH, ttybuf, 0)) 144940712Skarels break; 145021776Sbloom goto loop; 14517502Sroot } 1452*64416Sbostic if (ISSET(tp->t_lflag, FLUSHO) || 1453*64416Sbostic tp->t_outq.c_cc > hiwat) 145440712Skarels break; 14557502Sroot } 145635811Smarc ttstart(tp); 14577502Sroot } 145840712Skarels out: 145940712Skarels /* 1460*64416Sbostic * If cc is nonzero, we leave the uio structure inconsistent, as the 1461*64416Sbostic * offset and iov pointers have moved forward, but it doesn't matter 1462*64416Sbostic * (the call will either return short or restart with a new uio). 146340712Skarels */ 146440712Skarels uio->uio_resid += cc; 14658520Sroot return (error); 146640712Skarels 14677502Sroot ovhiwat: 146832067Skarels ttstart(tp); 146932067Skarels s = spltty(); 14709578Ssam /* 147135811Smarc * This can only occur if FLUSHO is set in t_lflag, 147232067Skarels * or if ttstart/oproc is synchronous (or very fast). 14739578Ssam */ 14747502Sroot if (tp->t_outq.c_cc <= hiwat) { 14759578Ssam splx(s); 14767502Sroot goto loop; 14777502Sroot } 147837728Smckusick if (flag & IO_NDELAY) { 147917545Skarels splx(s); 148040712Skarels uio->uio_resid += cc; 1481*64416Sbostic return (uio->uio_resid == cnt ? EWOULDBLOCK : 0); 14827502Sroot } 1483*64416Sbostic SET(tp->t_state, TS_ASLEEP); 1484*64416Sbostic error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14859578Ssam splx(s); 148643377Smarc if (error) 148740712Skarels goto out; 14887502Sroot goto loop; 14897502Sroot } 14907502Sroot 14917502Sroot /* 14927502Sroot * Rubout one character from the rawq of tp 14937502Sroot * as cleanly as possible. 14947502Sroot */ 1495*64416Sbostic void 14967502Sroot ttyrub(c, tp) 1497*64416Sbostic register int c; 14987625Ssam register struct tty *tp; 14997502Sroot { 15007502Sroot register char *cp; 15017502Sroot register int savecol; 1502*64416Sbostic int tabc, s; 15037502Sroot 1504*64416Sbostic if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) 15057502Sroot return; 1506*64416Sbostic CLR(tp->t_lflag, FLUSHO); 1507*64416Sbostic if (ISSET(tp->t_lflag, ECHOE)) { 15087502Sroot if (tp->t_rocount == 0) { 15097502Sroot /* 15107502Sroot * Screwed by ttwrite; retype 15117502Sroot */ 15127502Sroot ttyretype(tp); 15137502Sroot return; 15147502Sroot } 1515*64416Sbostic if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE)) 15167502Sroot ttyrubo(tp, 2); 151749380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 15187502Sroot case ORDINARY: 151935811Smarc ttyrubo(tp, 1); 15207502Sroot break; 15217502Sroot case BACKSPACE: 15227502Sroot case CONTROL: 1523*64416Sbostic case NEWLINE: 15247502Sroot case RETURN: 1525*64416Sbostic case VTAB: 1526*64416Sbostic if (ISSET(tp->t_lflag, ECHOCTL)) 15277502Sroot ttyrubo(tp, 2); 15287502Sroot break; 1529*64416Sbostic case TAB: 15307502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15317502Sroot ttyretype(tp); 15327502Sroot return; 15337502Sroot } 153417545Skarels s = spltty(); 15357502Sroot savecol = tp->t_col; 1536*64416Sbostic SET(tp->t_state, TS_CNTTB); 1537*64416Sbostic SET(tp->t_lflag, FLUSHO); 15387502Sroot tp->t_col = tp->t_rocol; 15399578Ssam cp = tp->t_rawq.c_cf; 154039407Smarc if (cp) 1541*64416Sbostic tabc = *cp; /* XXX FIX NEXTC */ 1542*64416Sbostic for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc)) 1543*64416Sbostic ttyecho(tabc, tp); 1544*64416Sbostic CLR(tp->t_lflag, FLUSHO); 1545*64416Sbostic CLR(tp->t_state, TS_CNTTB); 15467502Sroot splx(s); 1547*64416Sbostic 1548*64416Sbostic /* savecol will now be length of the tab. */ 15497502Sroot savecol -= tp->t_col; 15507502Sroot tp->t_col += savecol; 15517502Sroot if (savecol > 8) 15527502Sroot savecol = 8; /* overflow screw */ 15537502Sroot while (--savecol >= 0) 1554*64416Sbostic (void)ttyoutput('\b', tp); 15557502Sroot break; 1556*64416Sbostic default: /* XXX */ 1557*64416Sbostic #define PANICSTR "ttyrub: would panic c = %d, val = %d\n" 1558*64416Sbostic (void)printf(PANICSTR, c, CCLASS(c)); 1559*64416Sbostic #ifdef notdef 1560*64416Sbostic panic(PANICSTR, c, CCLASS(c)); 1561*64416Sbostic #endif 156235811Smarc } 1563*64416Sbostic } else if (ISSET(tp->t_lflag, ECHOPRT)) { 1564*64416Sbostic if (!ISSET(tp->t_state, TS_ERASE)) { 1565*64416Sbostic SET(tp->t_state, TS_ERASE); 1566*64416Sbostic (void)ttyoutput('\\', tp); 15677502Sroot } 15687502Sroot ttyecho(c, tp); 15697502Sroot } else 157035811Smarc ttyecho(tp->t_cc[VERASE], tp); 1571*64416Sbostic --tp->t_rocount; 15727502Sroot } 15737502Sroot 15747502Sroot /* 1575*64416Sbostic * Back over cnt characters, erasing them. 15767502Sroot */ 1577*64416Sbostic static void 15787502Sroot ttyrubo(tp, cnt) 15797625Ssam register struct tty *tp; 15807625Ssam int cnt; 15817502Sroot { 15827502Sroot 1583*64416Sbostic while (cnt-- > 0) { 1584*64416Sbostic (void)ttyoutput('\b', tp); 1585*64416Sbostic (void)ttyoutput(' ', tp); 1586*64416Sbostic (void)ttyoutput('\b', tp); 1587*64416Sbostic } 15887502Sroot } 15897502Sroot 15907502Sroot /* 1591*64416Sbostic * ttyretype -- 1592*64416Sbostic * Reprint the rawq line. Note, it is assumed that c_cc has already 1593*64416Sbostic * been checked. 15947502Sroot */ 1595*64416Sbostic void 15967502Sroot ttyretype(tp) 15977625Ssam register struct tty *tp; 15987502Sroot { 15997502Sroot register char *cp; 160035811Smarc int s, c; 16017502Sroot 1602*64416Sbostic /* Echo the reprint character. */ 160335811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 160435811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 1605*64416Sbostic 1606*64416Sbostic (void)ttyoutput('\n', tp); 1607*64416Sbostic 1608*64416Sbostic /* 1609*64416Sbostic * XXX 1610*64416Sbostic * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE 1611*64416Sbostic * BIT OF FIRST CHAR. 1612*64416Sbostic */ 161317545Skarels s = spltty(); 1614*64416Sbostic for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0); 1615*64416Sbostic cp != NULL; cp = nextc(&tp->t_canq, cp, &c)) 161635811Smarc ttyecho(c, tp); 1617*64416Sbostic for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0); 1618*64416Sbostic cp != NULL; cp = nextc(&tp->t_rawq, cp, &c)) 161935811Smarc ttyecho(c, tp); 1620*64416Sbostic CLR(tp->t_state, TS_ERASE); 16217502Sroot splx(s); 1622*64416Sbostic 16237502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16247502Sroot tp->t_rocol = 0; 16257502Sroot } 16267502Sroot 16277502Sroot /* 162835811Smarc * Echo a typed character to the terminal. 16297502Sroot */ 1630*64416Sbostic static void 16317502Sroot ttyecho(c, tp) 1632*64416Sbostic register int c; 16337625Ssam register struct tty *tp; 16347502Sroot { 1635*64416Sbostic 1636*64416Sbostic if (!ISSET(tp->t_state, TS_CNTTB)) 1637*64416Sbostic CLR(tp->t_lflag, FLUSHO); 1638*64416Sbostic if ((!ISSET(tp->t_lflag, ECHO) && 1639*64416Sbostic (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) || 1640*64416Sbostic ISSET(tp->t_lflag, EXTPROC)) 16417502Sroot return; 1642*64416Sbostic if (ISSET(tp->t_lflag, ECHOCTL) && 1643*64416Sbostic ((c & TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 1644*64416Sbostic (c & TTY_CHARMASK) == 0177)) { 1645*64416Sbostic (void)ttyoutput('^', tp); 1646*64416Sbostic c &= TTY_CHARMASK; 1647*64416Sbostic if (c == 0177) 1648*64416Sbostic c = '?'; 1649*64416Sbostic else 1650*64416Sbostic c += 'A' - 1; 16517502Sroot } 1652*64416Sbostic (void)ttyoutput(c, tp); 16537502Sroot } 16547502Sroot 16557502Sroot /* 165649380Skarels * Wake up any readers on a tty. 165749380Skarels */ 1658*64416Sbostic void 16597502Sroot ttwakeup(tp) 166047545Skarels register struct tty *tp; 16617502Sroot { 16627502Sroot 166352522Smckusick selwakeup(&tp->t_rsel); 1664*64416Sbostic if (ISSET(tp->t_state, TS_ASYNC)) 1665*64416Sbostic pgsignal(tp->t_pgrp, SIGIO, 1); 16667502Sroot wakeup((caddr_t)&tp->t_rawq); 16677502Sroot } 166835811Smarc 166935811Smarc /* 167048439Skarels * Look up a code for a specified speed in a conversion table; 167148439Skarels * used by drivers to map software speed values to hardware parameters. 167248439Skarels */ 1673*64416Sbostic int 167448439Skarels ttspeedtab(speed, table) 167552485Storek int speed; 167648439Skarels register struct speedtab *table; 167748439Skarels { 167848439Skarels 167948439Skarels for ( ; table->sp_speed != -1; table++) 168048439Skarels if (table->sp_speed == speed) 168148439Skarels return (table->sp_code); 168248439Skarels return (-1); 168348439Skarels } 168448439Skarels 168548439Skarels /* 1686*64416Sbostic * Set tty hi and low water marks. 168735811Smarc * 168835811Smarc * Try to arrange the dynamics so there's about one second 168935811Smarc * from hi to low water. 1690*64416Sbostic * 169135811Smarc */ 1692*64416Sbostic void 169335811Smarc ttsetwater(tp) 169435811Smarc struct tty *tp; 169535811Smarc { 1696*64416Sbostic register int cps, x; 169735811Smarc 1698*64416Sbostic #define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) 1699*64416Sbostic 1700*64416Sbostic cps = tp->t_ospeed / 10; 1701*64416Sbostic tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT); 170235811Smarc x += cps; 1703*64416Sbostic x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT); 170435811Smarc tp->t_hiwat = roundup(x, CBSIZE); 1705*64416Sbostic #undef CLAMP 170635811Smarc } 170735811Smarc 170839407Smarc /* 170939407Smarc * Report on state of foreground process group. 171039407Smarc */ 1711*64416Sbostic void 171239407Smarc ttyinfo(tp) 171349907Sbostic register struct tty *tp; 171439407Smarc { 171549907Sbostic register struct proc *p, *pick; 171641177Smarc struct timeval utime, stime; 171749907Sbostic int tmp; 171839407Smarc 1719*64416Sbostic if (ttycheckoutq(tp,0) == 0) 172039407Smarc return; 172149907Sbostic 172249907Sbostic /* Print load average. */ 172352666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 172449907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 172549907Sbostic 172639555Smarc if (tp->t_session == NULL) 172749907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 172841177Smarc else if (tp->t_pgrp == NULL) 172949907Sbostic ttyprintf(tp, "no foreground process group\n"); 173041177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 173149907Sbostic ttyprintf(tp, "empty foreground process group\n"); 173239407Smarc else { 173349907Sbostic /* Pick interesting process. */ 173449907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 173541177Smarc if (proc_compare(pick, p)) 173641177Smarc pick = p; 173749907Sbostic 173849907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 173949907Sbostic pick->p_stat == SRUN ? "running" : 174049907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 174149907Sbostic 174254782Storek calcru(pick, &utime, &stime, NULL); 174339407Smarc 174449907Sbostic /* Print user time. */ 174549907Sbostic ttyprintf(tp, "%d.%02du ", 174649907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 174741177Smarc 174849907Sbostic /* Print system time. */ 174949907Sbostic ttyprintf(tp, "%d.%02ds ", 175049907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 175149907Sbostic 175249907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 175349907Sbostic /* Print percentage cpu, resident set size. */ 175449907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 175549907Sbostic ttyprintf(tp, "%d%% %dk\n", 175652485Storek tmp / 100, 175752485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 175852485Storek pgtok(pick->p_vmspace->vm_rssize)); 175941177Smarc } 176049907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 176141177Smarc } 176241177Smarc 176341177Smarc /* 176441177Smarc * Returns 1 if p2 is "better" than p1 176541177Smarc * 176641177Smarc * The algorithm for picking the "interesting" process is thus: 176741177Smarc * 176841177Smarc * 1) (Only foreground processes are eligable - implied) 176941177Smarc * 2) Runnable processes are favored over anything 177041177Smarc * else. The runner with the highest cpu 177141177Smarc * utilization is picked (p_cpu). Ties are 177241177Smarc * broken by picking the highest pid. 177341177Smarc * 3 Next, the sleeper with the shortest sleep 177441177Smarc * time is favored. With ties, we pick out 177541177Smarc * just "short-term" sleepers (SSINTR == 0). 177641177Smarc * Further ties are broken by picking the highest 177741177Smarc * pid. 177841177Smarc * 177941177Smarc */ 178041177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 178145723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 178245723Smckusick #define ONLYA 2 178345723Smckusick #define ONLYB 1 178445723Smckusick #define BOTH 3 178549907Sbostic static int 178641177Smarc proc_compare(p1, p2) 178741177Smarc register struct proc *p1, *p2; 178841177Smarc { 178941177Smarc 179041177Smarc if (p1 == NULL) 179141177Smarc return (1); 179241177Smarc /* 179341177Smarc * see if at least one of them is runnable 179441177Smarc */ 179545723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 179645723Smckusick case ONLYA: 179745723Smckusick return (0); 179845723Smckusick case ONLYB: 179941177Smarc return (1); 180045723Smckusick case BOTH: 180141177Smarc /* 180241177Smarc * tie - favor one with highest recent cpu utilization 180341177Smarc */ 180441177Smarc if (p2->p_cpu > p1->p_cpu) 180541177Smarc return (1); 180641177Smarc if (p1->p_cpu > p2->p_cpu) 180741177Smarc return (0); 180841177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 180941177Smarc } 181045723Smckusick /* 181145723Smckusick * weed out zombies 181245723Smckusick */ 181345723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 181445723Smckusick case ONLYA: 181545723Smckusick return (1); 181645723Smckusick case ONLYB: 181745723Smckusick return (0); 181845723Smckusick case BOTH: 181945723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182045723Smckusick } 1821*64416Sbostic /* 182241177Smarc * pick the one with the smallest sleep time 182341177Smarc */ 182441177Smarc if (p2->p_slptime > p1->p_slptime) 182541177Smarc return (0); 182641177Smarc if (p1->p_slptime > p2->p_slptime) 182741177Smarc return (1); 182841177Smarc /* 182941177Smarc * favor one sleeping in a non-interruptible sleep 183041177Smarc */ 1831*64416Sbostic if (p1->p_flag & SSINTR && (p2->p_flag & SSINTR) == 0) 183241177Smarc return (1); 1833*64416Sbostic if (p2->p_flag & SSINTR && (p1->p_flag & SSINTR) == 0) 183441177Smarc return (0); 183547545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183641177Smarc } 183745723Smckusick 183839555Smarc /* 183939555Smarc * Output char to tty; console putchar style. 184039555Smarc */ 1841*64416Sbostic int 184239555Smarc tputchar(c, tp) 184339555Smarc int c; 184439555Smarc struct tty *tp; 184539555Smarc { 1846*64416Sbostic register int s; 184739555Smarc 1848*64416Sbostic s = spltty(); 1849*64416Sbostic if (ISSET(tp->t_state, 1850*64416Sbostic TS_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) { 185139555Smarc splx(s); 1852*64416Sbostic return (-1); 185339555Smarc } 1854*64416Sbostic if (c == '\n') 1855*64416Sbostic (void)ttyoutput('\r', tp); 1856*64416Sbostic (void)ttyoutput(c, tp); 1857*64416Sbostic ttstart(tp); 185839555Smarc splx(s); 1859*64416Sbostic return (0); 186039555Smarc } 186143377Smarc 186244419Smarc /* 1863*64416Sbostic * Sleep on chan, returning ERESTART if tty changed while we napped and 1864*64416Sbostic * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep. If 1865*64416Sbostic * the tty is revoked, restarting a pending call will redo validation done 1866*64416Sbostic * at the start of the call. 186744419Smarc */ 1868*64416Sbostic int 186943377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187043377Smarc struct tty *tp; 1871*64416Sbostic void *chan; 1872*64416Sbostic int pri, timo; 187343377Smarc char *wmesg; 187443377Smarc { 187543377Smarc int error; 1876*64416Sbostic short gen; 187743377Smarc 1878*64416Sbostic gen = tp->t_gen; 187943377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188043377Smarc return (error); 1881*64416Sbostic return (tp->t_gen == gen ? 0 : ERESTART); 188243377Smarc } 1883