123387Smckusick /* 240712Skarels * Copyright (c) 1982, 1986, 1990 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*49380Skarels * @(#)tty.c 7.41 (Berkeley) 05/07/91 723387Smckusick */ 839Sbill 917095Sbloom #include "param.h" 1017095Sbloom #include "systm.h" 1117095Sbloom #include "ioctl.h" 1239407Smarc #define TTYDEFCHARS 1317095Sbloom #include "tty.h" 1435811Smarc #undef TTYDEFCHARS 1517095Sbloom #include "proc.h" 1617095Sbloom #include "file.h" 1717095Sbloom #include "conf.h" 1829946Skarels #include "dkstat.h" 1917095Sbloom #include "uio.h" 2017095Sbloom #include "kernel.h" 2137728Smckusick #include "vnode.h" 2235811Smarc #include "syslog.h" 2339Sbill 2448439Skarels #include "vm/vm.h" 2537525Smckusick 2640712Skarels /* symbolic sleep message strings */ 2740712Skarels char ttyin[] = "ttyin"; 2840712Skarels char ttyout[] = "ttyout"; 2941370Smarc char ttopen[] = "ttyopn"; 3041370Smarc char ttclos[] = "ttycls"; 3140712Skarels char ttybg[] = "ttybg"; 3240712Skarels char ttybuf[] = "ttybuf"; 3340712Skarels 347436Skre /* 357436Skre * Table giving parity for characters and indicating 3635811Smarc * character classes to tty driver. The 8th bit 3735811Smarc * indicates parity, the 7th bit indicates the character 3835811Smarc * is an alphameric or underscore (for ALTWERASE), and the 3935811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 40*49380Skarels * then the character needs no special processing on output; 41*49380Skarels * classes other than 0 might be translated or (not currently) 42*49380Skarels * require delays. 437436Skre */ 44*49380Skarels #define PARITY(c) (partab[c] & 0x80) 45*49380Skarels #define ISALPHA(c) (partab[(c)&TTY_CHARMASK] & 0x40) 46*49380Skarels #define CCLASSMASK 0x3f 47*49380Skarels #define CCLASS(c) (partab[c] & CCLASSMASK) 4839Sbill 49*49380Skarels #define E 0x00 /* even parity */ 50*49380Skarels #define O 0x80 /* odd parity */ 51*49380Skarels #define ALPHA 0x40 /* alpha or underscore */ 52*49380Skarels 53*49380Skarels #define NO ORDINARY 54*49380Skarels #define NA ORDINARY|ALPHA 55*49380Skarels #define CC CONTROL 56*49380Skarels #define BS BACKSPACE 57*49380Skarels #define NL NEWLINE 58*49380Skarels #define TB TAB 59*49380Skarels #define VT VTAB 60*49380Skarels #define CR RETURN 61*49380Skarels 627436Skre char partab[] = { 63*49380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 64*49380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 65*49380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 66*49380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 67*49380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 68*49380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 69*49380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 70*49380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 71*49380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 72*49380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 73*49380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 74*49380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 75*49380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 76*49380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 77*49380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 78*49380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 797436Skre /* 80*49380Skarels * "meta" chars; should be settable per charset. 81*49380Skarels * For now, treat all as normal characters. 827436Skre */ 83*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 84*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 85*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 86*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 87*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 88*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 89*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 90*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 91*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 92*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 93*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 94*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 95*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 96*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 97*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 98*49380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 997436Skre }; 100*49380Skarels #undef NO 101*49380Skarels #undef NA 102*49380Skarels #undef CC 103*49380Skarels #undef BS 104*49380Skarels #undef NL 105*49380Skarels #undef TB 106*49380Skarels #undef VT 107*49380Skarels #undef CR 1087436Skre 10935811Smarc extern struct tty *constty; /* temporary virtual console */ 11035811Smarc 111146Sbill /* 11235811Smarc * Is 'c' a line delimiter ("break" character)? 11339Sbill */ 11440712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ 11540712Skarels (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 11639Sbill 11739Sbill ttychars(tp) 1189578Ssam struct tty *tp; 11939Sbill { 12047545Skarels 12135811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 12239Sbill } 12339Sbill 12439Sbill /* 125*49380Skarels * Flush tty after output has drained. 12639Sbill */ 12712752Ssam ttywflush(tp) 12837584Smarc struct tty *tp; 12939Sbill { 13040712Skarels int error; 13139Sbill 13240712Skarels if ((error = ttywait(tp)) == 0) 13340712Skarels ttyflush(tp, FREAD); 13440712Skarels return (error); 13512752Ssam } 13612752Ssam 13735811Smarc /* 13835811Smarc * Wait for output to drain. 13935811Smarc */ 14012752Ssam ttywait(tp) 14112752Ssam register struct tty *tp; 14212752Ssam { 14340712Skarels int error = 0, s = spltty(); 14412752Ssam 14513809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 14637584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 14737584Smarc tp->t_oproc) { 148903Sbill (*tp->t_oproc)(tp); 1495408Swnj tp->t_state |= TS_ASLEEP; 15043377Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_outq, 15143377Smarc TTOPRI | PCATCH, ttyout, 0)) 15240712Skarels break; 153903Sbill } 1549859Ssam splx(s); 15540712Skarels return (error); 15639Sbill } 15739Sbill 158*49380Skarels #define flushq(qq) { \ 159*49380Skarels register struct clist *q = qq; \ 160*49380Skarels if (q->c_cc) \ 161*49380Skarels ndflush(q, q->c_cc); \ 162*49380Skarels } 163*49380Skarels 16439Sbill /* 165*49380Skarels * Flush TTY read and/or write queues, 166*49380Skarels * notifying anyone waiting. 16739Sbill */ 16812752Ssam ttyflush(tp, rw) 1697625Ssam register struct tty *tp; 17039Sbill { 171903Sbill register s; 172903Sbill 17317545Skarels s = spltty(); 174903Sbill if (rw & FREAD) { 175*49380Skarels flushq(&tp->t_canq); 176*49380Skarels flushq(&tp->t_rawq); 177*49380Skarels tp->t_rocount = 0; 178*49380Skarels tp->t_rocol = 0; 179*49380Skarels tp->t_state &= ~TS_LOCAL; 18037584Smarc ttwakeup(tp); 181903Sbill } 182903Sbill if (rw & FWRITE) { 1835408Swnj tp->t_state &= ~TS_TTSTOP; 1845426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 185*49380Skarels flushq(&tp->t_outq); 186*49380Skarels wakeup((caddr_t)&tp->t_outq); 187*49380Skarels if (tp->t_wsel) { 188*49380Skarels selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 189*49380Skarels tp->t_wsel = 0; 190*49380Skarels tp->t_state &= ~TS_WCOLL; 191*49380Skarels } 192903Sbill } 193903Sbill splx(s); 19439Sbill } 19539Sbill 196903Sbill /* 197903Sbill * Send stop character on input overflow. 198903Sbill */ 199903Sbill ttyblock(tp) 2007625Ssam register struct tty *tp; 20139Sbill { 202903Sbill register x; 2039578Ssam 204903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 205903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 20612752Ssam ttyflush(tp, FREAD|FWRITE); 2075408Swnj tp->t_state &= ~TS_TBLOCK; 208903Sbill } 20915118Skarels /* 21015118Skarels * Block further input iff: 21115118Skarels * Current input > threshold AND input is available to user program 21215118Skarels */ 21342350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 21440712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 21535811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 21642350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 21715118Skarels tp->t_state |= TS_TBLOCK; 21815118Skarels ttstart(tp); 21915118Skarels } 220903Sbill } 22139Sbill } 22239Sbill 22347545Skarels ttstart(tp) 22437584Smarc struct tty *tp; 225121Sbill { 226121Sbill 22747545Skarels if (tp->t_oproc) /* kludge for pty */ 22847545Skarels (*tp->t_oproc)(tp); 22947545Skarels } 23047545Skarels 23147545Skarels ttrstrt(tp) /* XXX */ 23247545Skarels struct tty *tp; 23347545Skarels { 23447545Skarels 23540712Skarels #ifdef DIAGNOSTIC 2369578Ssam if (tp == 0) 2379578Ssam panic("ttrstrt"); 23840712Skarels #endif 2395408Swnj tp->t_state &= ~TS_TIMEOUT; 240903Sbill ttstart(tp); 241121Sbill } 242121Sbill 24339Sbill 24439Sbill /* 245*49380Skarels * Common code for ioctls on tty devices. 246*49380Skarels * Called after line-discipline-specific ioctl 247*49380Skarels * has been called to do discipline-specific functions 248*49380Skarels * and/or reject any of these ioctl commands. 24939Sbill */ 2501780Sbill /*ARGSUSED*/ 2517625Ssam ttioctl(tp, com, data, flag) 2527625Ssam register struct tty *tp; 2537625Ssam caddr_t data; 25439Sbill { 25547545Skarels register struct proc *p = curproc; /* XXX */ 25639Sbill extern int nldisp; 25737554Smckusick int s, error; 25839Sbill 259903Sbill /* 260903Sbill * If the ioctl involves modification, 26117545Skarels * hang if in the background. 262903Sbill */ 2637625Ssam switch (com) { 26439Sbill 26535811Smarc case TIOCSETD: 266903Sbill case TIOCFLUSH: 26735811Smarc /*case TIOCSPGRP:*/ 2689325Ssam case TIOCSTI: 26917598Sbloom case TIOCSWINSZ: 27035811Smarc case TIOCSETA: 27135811Smarc case TIOCSETAW: 27235811Smarc case TIOCSETAF: 27340030Smarc #ifdef COMPAT_43 27440030Smarc case TIOCSETP: 27540030Smarc case TIOCSETN: 27640030Smarc case TIOCSETC: 27740030Smarc case TIOCSLTC: 27840030Smarc case TIOCLBIS: 27940030Smarc case TIOCLBIC: 28040030Smarc case TIOCLSET: 28140030Smarc case OTIOCSETD: 28240030Smarc #endif 28347545Skarels while (isbackground(curproc, tp) && 28447545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 28547545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 28647545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 28747545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 28843377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 28943377Smarc TTOPRI | PCATCH, ttybg, 0)) 29040712Skarels return (error); 291903Sbill } 292903Sbill break; 293903Sbill } 294903Sbill 2959578Ssam /* 2969578Ssam * Process the ioctl. 2979578Ssam */ 2987625Ssam switch (com) { 299903Sbill 3008556Sroot /* get discipline number */ 30139Sbill case TIOCGETD: 3027625Ssam *(int *)data = tp->t_line; 30339Sbill break; 30439Sbill 3058556Sroot /* set line discipline */ 3067625Ssam case TIOCSETD: { 3077625Ssam register int t = *(int *)data; 30835811Smarc dev_t dev = tp->t_dev; 3097625Ssam 31035811Smarc if ((unsigned)t >= nldisp) 31110851Ssam return (ENXIO); 31225584Skarels if (t != tp->t_line) { 31325584Skarels s = spltty(); 31425584Skarels (*linesw[tp->t_line].l_close)(tp); 31525584Skarels error = (*linesw[t].l_open)(dev, tp); 31625584Skarels if (error) { 31735811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 31825584Skarels splx(s); 31925584Skarels return (error); 32025584Skarels } 32125584Skarels tp->t_line = t; 32210851Ssam splx(s); 32310851Ssam } 32439Sbill break; 3257625Ssam } 32639Sbill 3278556Sroot /* prevent more opens on channel */ 3285614Swnj case TIOCEXCL: 3295614Swnj tp->t_state |= TS_XCLUDE; 3305614Swnj break; 3315614Swnj 3325614Swnj case TIOCNXCL: 3335614Swnj tp->t_state &= ~TS_XCLUDE; 3345614Swnj break; 3355614Swnj 33639Sbill case TIOCHPCL: 33735811Smarc tp->t_cflag |= HUPCL; 33839Sbill break; 33939Sbill 3403942Sbugs case TIOCFLUSH: { 3417625Ssam register int flags = *(int *)data; 3427625Ssam 3437625Ssam if (flags == 0) 3443942Sbugs flags = FREAD|FWRITE; 3457625Ssam else 3467625Ssam flags &= FREAD|FWRITE; 34712752Ssam ttyflush(tp, flags); 34839Sbill break; 3493944Sbugs } 35039Sbill 35137584Smarc case FIOASYNC: 35237584Smarc if (*(int *)data) 35337584Smarc tp->t_state |= TS_ASYNC; 35437584Smarc else 35537584Smarc tp->t_state &= ~TS_ASYNC; 35637584Smarc break; 35737584Smarc 35837584Smarc case FIONBIO: 35937584Smarc break; /* XXX remove */ 36037584Smarc 3618556Sroot /* return number of characters immediately available */ 3627625Ssam case FIONREAD: 3637625Ssam *(off_t *)data = ttnread(tp); 364174Sbill break; 365174Sbill 36613077Ssam case TIOCOUTQ: 36713077Ssam *(int *)data = tp->t_outq.c_cc; 36813077Ssam break; 36913077Ssam 3708589Sroot case TIOCSTOP: 37117545Skarels s = spltty(); 3729578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3735573Swnj tp->t_state |= TS_TTSTOP; 3745573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3755573Swnj } 3767625Ssam splx(s); 3775573Swnj break; 3785573Swnj 3798589Sroot case TIOCSTART: 38017545Skarels s = spltty(); 38135811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3825573Swnj tp->t_state &= ~TS_TTSTOP; 38335811Smarc tp->t_lflag &= ~FLUSHO; 3845573Swnj ttstart(tp); 3855573Swnj } 3867625Ssam splx(s); 3875573Swnj break; 3885573Swnj 3899325Ssam /* 3909325Ssam * Simulate typing of a character at the terminal. 3919325Ssam */ 3929325Ssam case TIOCSTI: 39347545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 39417183Smckusick return (EPERM); 39547545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 3969325Ssam return (EACCES); 3979578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3989325Ssam break; 3999325Ssam 40035811Smarc case TIOCGETA: { 40135811Smarc struct termios *t = (struct termios *)data; 40212752Ssam 40335811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 40435811Smarc break; 40535811Smarc } 40635811Smarc 40735811Smarc case TIOCSETA: 40835811Smarc case TIOCSETAW: 40937584Smarc case TIOCSETAF: { 41035811Smarc register struct termios *t = (struct termios *)data; 41140712Skarels 41217545Skarels s = spltty(); 41339407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 41440712Skarels if (error = ttywait(tp)) { 41540712Skarels splx(s); 41640712Skarels return (error); 41740712Skarels } 41845007Smarc if (com == TIOCSETAF) 41939407Smarc ttyflush(tp, FREAD); 42039407Smarc } 42140712Skarels if ((t->c_cflag&CIGNORE) == 0) { 42235811Smarc /* 42335811Smarc * set device hardware 42435811Smarc */ 42537584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 42637584Smarc splx(s); 42735811Smarc return (error); 42837584Smarc } else { 42940712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 43037584Smarc (tp->t_cflag&CLOCAL) && 43140712Skarels (t->c_cflag&CLOCAL) == 0) { 43237584Smarc tp->t_state &= ~TS_ISOPEN; 43337584Smarc tp->t_state |= TS_WOPEN; 43437584Smarc ttwakeup(tp); 43537584Smarc } 43635811Smarc tp->t_cflag = t->c_cflag; 43735811Smarc tp->t_ispeed = t->c_ispeed; 43835811Smarc tp->t_ospeed = t->c_ospeed; 43934492Skarels } 44035811Smarc ttsetwater(tp); 44112752Ssam } 44239407Smarc if (com != TIOCSETAF) { 44335811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 44435811Smarc if (t->c_lflag&ICANON) { 44535811Smarc tp->t_lflag |= PENDIN; 44635811Smarc ttwakeup(tp); 44735811Smarc } 44835811Smarc else { 44935811Smarc struct clist tq; 45035811Smarc 45135811Smarc catq(&tp->t_rawq, &tp->t_canq); 45235811Smarc tq = tp->t_rawq; 45335811Smarc tp->t_rawq = tp->t_canq; 45435811Smarc tp->t_canq = tq; 45535811Smarc } 45612752Ssam } 45735811Smarc tp->t_iflag = t->c_iflag; 45835811Smarc tp->t_oflag = t->c_oflag; 45942882Smarc /* 46042882Smarc * Make the EXTPROC bit read only. 46142882Smarc */ 46242882Smarc if (tp->t_lflag&EXTPROC) 46342882Smarc t->c_lflag |= EXTPROC; 46442882Smarc else 46542882Smarc t->c_lflag &= ~EXTPROC; 46635811Smarc tp->t_lflag = t->c_lflag; 46735811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 46812752Ssam splx(s); 46912752Ssam break; 47012752Ssam } 47112752Ssam 47212752Ssam /* 47339555Smarc * Set controlling terminal. 47439555Smarc * Session ctty vnode pointer set in vnode layer. 47534492Skarels */ 47647545Skarels case TIOCSCTTY: 47739555Smarc if (!SESS_LEADER(p) || 47839555Smarc (p->p_session->s_ttyvp || tp->t_session) && 47939555Smarc (tp->t_session != p->p_session)) 48039407Smarc return (EPERM); 48135811Smarc tp->t_session = p->p_session; 48239555Smarc tp->t_pgrp = p->p_pgrp; 48339555Smarc p->p_session->s_ttyp = tp; 48439555Smarc p->p_flag |= SCTTY; 48534492Skarels break; 48639555Smarc 48734492Skarels /* 48835811Smarc * Set terminal process group. 48917545Skarels */ 49018650Sbloom case TIOCSPGRP: { 49135811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 49217545Skarels 49339555Smarc if (!isctty(p, tp)) 49439555Smarc return (ENOTTY); 49540030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 49639555Smarc return (EPERM); 49739555Smarc tp->t_pgrp = pgrp; 49812752Ssam break; 49918650Sbloom } 50012752Ssam 50112752Ssam case TIOCGPGRP: 50247545Skarels if (!isctty(p, tp)) 50339555Smarc return (ENOTTY); 50445007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 50512752Ssam break; 50612752Ssam 50717598Sbloom case TIOCSWINSZ: 50818650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 50918650Sbloom sizeof (struct winsize))) { 51017598Sbloom tp->t_winsize = *(struct winsize *)data; 51142882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 51217598Sbloom } 51317598Sbloom break; 51417598Sbloom 51517598Sbloom case TIOCGWINSZ: 51617598Sbloom *(struct winsize *)data = tp->t_winsize; 51717598Sbloom break; 51817598Sbloom 51930534Skarels case TIOCCONS: 52030534Skarels if (*(int *)data) { 52142141Smckusick if (constty && constty != tp && 52242141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 52342141Smckusick (TS_CARR_ON|TS_ISOPEN)) 52430534Skarels return (EBUSY); 52530534Skarels #ifndef UCONSOLE 52647545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 52737554Smckusick return (error); 52830534Skarels #endif 52930534Skarels constty = tp; 53030534Skarels } else if (tp == constty) 53133404Skarels constty = NULL; 53230534Skarels break; 53330534Skarels 53448439Skarels case TIOCDRAIN: 53548439Skarels if (error = ttywait(tp)) 53648439Skarels return (error); 53748439Skarels break; 53848439Skarels 53947545Skarels default: 54035811Smarc #ifdef COMPAT_43 54147545Skarels return (ttcompat(tp, com, data, flag)); 54247545Skarels #else 54347545Skarels return (-1); 54435811Smarc #endif 54539Sbill } 5468556Sroot return (0); 54739Sbill } 5484484Swnj 5494484Swnj ttnread(tp) 5504484Swnj struct tty *tp; 5514484Swnj { 5524484Swnj int nread = 0; 5534484Swnj 55435811Smarc if (tp->t_lflag & PENDIN) 5554484Swnj ttypend(tp); 5564484Swnj nread = tp->t_canq.c_cc; 55735811Smarc if ((tp->t_lflag & ICANON) == 0) 5584484Swnj nread += tp->t_rawq.c_cc; 5594484Swnj return (nread); 5604484Swnj } 5614484Swnj 5625408Swnj ttselect(dev, rw) 5634484Swnj dev_t dev; 5645408Swnj int rw; 5654484Swnj { 5664484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5674484Swnj int nread; 56817545Skarels int s = spltty(); 5694484Swnj 5705408Swnj switch (rw) { 5714484Swnj 5724484Swnj case FREAD: 5734484Swnj nread = ttnread(tp); 57437584Smarc if (nread > 0 || 57540712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 5765408Swnj goto win; 5774938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5785408Swnj tp->t_state |= TS_RCOLL; 5794484Swnj else 58047545Skarels tp->t_rsel = curproc; 5815408Swnj break; 5824484Swnj 5835408Swnj case FWRITE: 58435811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5855408Swnj goto win; 5865408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5875408Swnj tp->t_state |= TS_WCOLL; 5885408Swnj else 58947545Skarels tp->t_wsel = curproc; 5905408Swnj break; 5914484Swnj } 5925408Swnj splx(s); 5935408Swnj return (0); 5945408Swnj win: 5955408Swnj splx(s); 5965408Swnj return (1); 5974484Swnj } 5987436Skre 5997502Sroot /* 600*49380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6017502Sroot */ 6027502Sroot ttyopen(dev, tp) 6037625Ssam dev_t dev; 6047625Ssam register struct tty *tp; 6057502Sroot { 6067502Sroot 6077502Sroot tp->t_dev = dev; 60835811Smarc 6097502Sroot tp->t_state &= ~TS_WOPEN; 61017545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 61117545Skarels tp->t_state |= TS_ISOPEN; 61217598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 61317545Skarels } 6148556Sroot return (0); 6157502Sroot } 6167502Sroot 6177502Sroot /* 61825391Skarels * "close" a line discipline 61925391Skarels */ 62025391Skarels ttylclose(tp) 62125391Skarels register struct tty *tp; 62225391Skarels { 62325391Skarels 62425391Skarels ttywflush(tp); 62525391Skarels } 62625391Skarels 62725391Skarels /* 628*49380Skarels * Handle close() on a tty line: flush and set to initial state, 629*49380Skarels * bumping generation number so that pending read/write calls 630*49380Skarels * can detect recycling of the tty. 6317502Sroot */ 6327502Sroot ttyclose(tp) 6337625Ssam register struct tty *tp; 6347502Sroot { 63530534Skarels if (constty == tp) 63630534Skarels constty = NULL; 63725391Skarels ttyflush(tp, FREAD|FWRITE); 63839555Smarc tp->t_session = NULL; 63939555Smarc tp->t_pgrp = NULL; 6407502Sroot tp->t_state = 0; 64143377Smarc tp->t_gen++; 64240712Skarels return (0); 6437502Sroot } 6447502Sroot 6457502Sroot /* 64625391Skarels * Handle modem control transition on a tty. 64725391Skarels * Flag indicates new state of carrier. 64825391Skarels * Returns 0 if the line should be turned off, otherwise 1. 64925391Skarels */ 65025391Skarels ttymodem(tp, flag) 65125391Skarels register struct tty *tp; 65225391Skarels { 65325391Skarels 65442193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 65525391Skarels /* 65625391Skarels * MDMBUF: do flow control according to carrier flag 65725391Skarels */ 65825391Skarels if (flag) { 65925391Skarels tp->t_state &= ~TS_TTSTOP; 66025391Skarels ttstart(tp); 66125391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 66225391Skarels tp->t_state |= TS_TTSTOP; 66325391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 66425391Skarels } 66525391Skarels } else if (flag == 0) { 66625391Skarels /* 66725391Skarels * Lost carrier. 66825391Skarels */ 66925391Skarels tp->t_state &= ~TS_CARR_ON; 67042193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 67142193Smarc if (tp->t_session && tp->t_session->s_leader) 67242193Smarc psignal(tp->t_session->s_leader, SIGHUP); 67342193Smarc ttyflush(tp, FREAD|FWRITE); 67442193Smarc return (0); 67525391Skarels } 67625391Skarels } else { 67725391Skarels /* 67825391Skarels * Carrier now on. 67925391Skarels */ 68025391Skarels tp->t_state |= TS_CARR_ON; 68137584Smarc ttwakeup(tp); 68225391Skarels } 68325391Skarels return (1); 68425391Skarels } 68525391Skarels 68625391Skarels /* 68725404Skarels * Default modem control routine (for other line disciplines). 68825404Skarels * Return argument flag, to turn off device on carrier drop. 68925404Skarels */ 69025415Skarels nullmodem(tp, flag) 69125415Skarels register struct tty *tp; 69225404Skarels int flag; 69325404Skarels { 69425404Skarels 69525404Skarels if (flag) 69625404Skarels tp->t_state |= TS_CARR_ON; 69739407Smarc else { 69825404Skarels tp->t_state &= ~TS_CARR_ON; 69942193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 70042193Smarc if (tp->t_session && tp->t_session->s_leader) 70142193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70242193Smarc return (0); 70342193Smarc } 70439407Smarc } 70542193Smarc return (1); 70625404Skarels } 70725404Skarels 70825404Skarels /* 7097502Sroot * reinput pending characters after state switch 71017545Skarels * call at spltty(). 7117502Sroot */ 7127502Sroot ttypend(tp) 7137625Ssam register struct tty *tp; 7147502Sroot { 7157502Sroot struct clist tq; 7167502Sroot register c; 7177502Sroot 71835811Smarc tp->t_lflag &= ~PENDIN; 7199578Ssam tp->t_state |= TS_TYPEN; 7207502Sroot tq = tp->t_rawq; 7217502Sroot tp->t_rawq.c_cc = 0; 7227502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7237502Sroot while ((c = getc(&tq)) >= 0) 7247502Sroot ttyinput(c, tp); 7259578Ssam tp->t_state &= ~TS_TYPEN; 7267502Sroot } 7277502Sroot 7287502Sroot /* 729*49380Skarels * Process input of a single character received on a tty. 7307502Sroot */ 7317502Sroot ttyinput(c, tp) 7327625Ssam register c; 7337625Ssam register struct tty *tp; 7347502Sroot { 73535811Smarc register int iflag = tp->t_iflag; 73635811Smarc register int lflag = tp->t_lflag; 73735811Smarc register u_char *cc = tp->t_cc; 73835811Smarc int i, err; 7397502Sroot 7409578Ssam /* 7419578Ssam * If input is pending take it first. 7429578Ssam */ 74335811Smarc if (lflag&PENDIN) 7447502Sroot ttypend(tp); 74535811Smarc /* 74635811Smarc * Gather stats. 74735811Smarc */ 7487502Sroot tk_nin++; 74935811Smarc if (lflag&ICANON) { 75035811Smarc tk_cancc++; 75135811Smarc tp->t_cancc++; 75235811Smarc } else { 75335811Smarc tk_rawcc++; 75435811Smarc tp->t_rawcc++; 75535811Smarc } 7569578Ssam /* 75735811Smarc * Handle exceptional conditions (break, parity, framing). 7589578Ssam */ 75935811Smarc if (err = (c&TTY_ERRORMASK)) { 76035811Smarc c &= ~TTY_ERRORMASK; 76135811Smarc if (err&TTY_FE && !c) { /* break */ 76235811Smarc if (iflag&IGNBRK) 76335811Smarc goto endcase; 76435811Smarc else if (iflag&BRKINT && lflag&ISIG && 76535811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 76635811Smarc c = cc[VINTR]; 76747545Skarels else if (iflag&PARMRK) 76847545Skarels goto parmrk; 76935811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 77035811Smarc if (iflag&IGNPAR) 77135811Smarc goto endcase; 77235811Smarc else if (iflag&PARMRK) { 77335811Smarc parmrk: 77435811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 77535811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 77635811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 77735811Smarc goto endcase; 77835811Smarc } else 77935811Smarc c = 0; 7807502Sroot } 7819578Ssam } 7829578Ssam /* 78335811Smarc * In tandem mode, check high water mark. 7849578Ssam */ 78535811Smarc if (iflag&IXOFF) 78635811Smarc ttyblock(tp); 78735811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 788*49380Skarels c &= ~0x80; 78944419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 79044419Smarc /* 79144419Smarc * Check for literal nexting very first 79244419Smarc */ 79344419Smarc if (tp->t_state&TS_LNCH) { 79444419Smarc c |= TTY_QUOTE; 79544419Smarc tp->t_state &= ~TS_LNCH; 79644419Smarc } 79744419Smarc /* 79844419Smarc * Scan for special characters. This code 79944419Smarc * is really just a big case statement with 80044419Smarc * non-constant cases. The bottom of the 80144419Smarc * case statement is labeled ``endcase'', so goto 80244419Smarc * it after a case match, or similar. 80344419Smarc */ 80444419Smarc 80544419Smarc /* 80644419Smarc * Control chars which aren't controlled 80744419Smarc * by ICANON, ISIG, or IXON. 80844419Smarc */ 80944419Smarc if (lflag&IEXTEN) { 81044419Smarc if (CCEQ(cc[VLNEXT], c)) { 81144419Smarc if (lflag&ECHO) { 81244419Smarc if (lflag&ECHOE) 81344419Smarc ttyoutstr("^\b", tp); 81444419Smarc else 81544419Smarc ttyecho(c, tp); 81644419Smarc } 81744419Smarc tp->t_state |= TS_LNCH; 81844419Smarc goto endcase; 81944419Smarc } 82044419Smarc if (CCEQ(cc[VDISCARD], c)) { 82144419Smarc if (lflag&FLUSHO) 82244419Smarc tp->t_lflag &= ~FLUSHO; 82344419Smarc else { 82444419Smarc ttyflush(tp, FWRITE); 82535811Smarc ttyecho(c, tp); 82644419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 82744419Smarc ttyretype(tp); 82844419Smarc tp->t_lflag |= FLUSHO; 82944419Smarc } 83044419Smarc goto startoutput; 83135811Smarc } 8329578Ssam } 83344419Smarc /* 83444419Smarc * Signals. 83544419Smarc */ 83644419Smarc if (lflag&ISIG) { 83744419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 83844419Smarc if ((lflag&NOFLSH) == 0) 83944419Smarc ttyflush(tp, FREAD|FWRITE); 8407502Sroot ttyecho(c, tp); 84144419Smarc pgsignal(tp->t_pgrp, 84244419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 84344419Smarc goto endcase; 8447502Sroot } 84544419Smarc if (CCEQ(cc[VSUSP], c)) { 84644419Smarc if ((lflag&NOFLSH) == 0) 84744419Smarc ttyflush(tp, FREAD); 84844419Smarc ttyecho(c, tp); 84944419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 85044419Smarc goto endcase; 85144419Smarc } 8529578Ssam } 85344419Smarc /* 85444419Smarc * Handle start/stop characters. 85544419Smarc */ 85644419Smarc if (iflag&IXON) { 85744419Smarc if (CCEQ(cc[VSTOP], c)) { 85844419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 85944419Smarc tp->t_state |= TS_TTSTOP; 86044419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 86144419Smarc 0); 86244419Smarc return; 86344419Smarc } 86444419Smarc if (!CCEQ(cc[VSTART], c)) 86544419Smarc return; 86644419Smarc /* 86744419Smarc * if VSTART == VSTOP then toggle 86844419Smarc */ 86944419Smarc goto endcase; 87035811Smarc } 87144419Smarc if (CCEQ(cc[VSTART], c)) 87244419Smarc goto restartoutput; 8739578Ssam } 87444419Smarc /* 87544419Smarc * IGNCR, ICRNL, & INLCR 87644419Smarc */ 87744419Smarc if (c == '\r') { 87844419Smarc if (iflag&IGNCR) 87944419Smarc goto endcase; 88044419Smarc else if (iflag&ICRNL) 88144419Smarc c = '\n'; 88244419Smarc } else if (c == '\n' && iflag&INLCR) 88344419Smarc c = '\r'; 8849578Ssam } 88547545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 88644419Smarc /* 88744419Smarc * From here on down canonical mode character 88844419Smarc * processing takes place. 88944419Smarc */ 89044419Smarc /* 89144419Smarc * erase (^H / ^?) 89244419Smarc */ 89344419Smarc if (CCEQ(cc[VERASE], c)) { 89444419Smarc if (tp->t_rawq.c_cc) 8959578Ssam ttyrub(unputc(&tp->t_rawq), tp); 89644419Smarc goto endcase; 8979578Ssam } 89844419Smarc /* 89944419Smarc * kill (^U) 90044419Smarc */ 90144419Smarc if (CCEQ(cc[VKILL], c)) { 90244419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 90344419Smarc (lflag&ECHOPRT) == 0) { 90444419Smarc while (tp->t_rawq.c_cc) 90544419Smarc ttyrub(unputc(&tp->t_rawq), tp); 90644419Smarc } else { 90744419Smarc ttyecho(c, tp); 90844419Smarc if (lflag&ECHOK || lflag&ECHOKE) 90944419Smarc ttyecho('\n', tp); 91044419Smarc while (getc(&tp->t_rawq) > 0) 91144419Smarc ; 91244419Smarc tp->t_rocount = 0; 91344419Smarc } 91444419Smarc tp->t_state &= ~TS_LOCAL; 91544419Smarc goto endcase; 91644419Smarc } 91744419Smarc /* 91844419Smarc * word erase (^W) 91944419Smarc */ 92044419Smarc if (CCEQ(cc[VWERASE], c)) { 92144419Smarc int ctype; 92247545Skarels int alt = lflag&ALTWERASE; 92335811Smarc 92444419Smarc /* 92544419Smarc * erase whitespace 92644419Smarc */ 92744419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 92844419Smarc ttyrub(c, tp); 92944419Smarc if (c == -1) 93044419Smarc goto endcase; 93144419Smarc /* 93247545Skarels * erase last char of word and remember the 93347545Skarels * next chars type (for ALTWERASE) 93444419Smarc */ 93535811Smarc ttyrub(c, tp); 93644419Smarc c = unputc(&tp->t_rawq); 93747545Skarels if (c == -1) 93844419Smarc goto endcase; 939*49380Skarels ctype = ISALPHA(c); 94044419Smarc /* 94147545Skarels * erase rest of word 94244419Smarc */ 94344419Smarc do { 94444419Smarc ttyrub(c, tp); 94544419Smarc c = unputc(&tp->t_rawq); 94644419Smarc if (c == -1) 94744419Smarc goto endcase; 94847545Skarels } while (c != ' ' && c != '\t' && 949*49380Skarels (alt == 0 || ISALPHA(c) == ctype)); 95044419Smarc (void) putc(c, &tp->t_rawq); 95134492Skarels goto endcase; 95244419Smarc } 95335811Smarc /* 95444419Smarc * reprint line (^R) 95535811Smarc */ 95644419Smarc if (CCEQ(cc[VREPRINT], c)) { 95744419Smarc ttyretype(tp); 95834492Skarels goto endcase; 95934492Skarels } 96035811Smarc /* 96144419Smarc * ^T - kernel info and generate SIGINFO 96235811Smarc */ 96344419Smarc if (CCEQ(cc[VSTATUS], c)) { 96444419Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 96544419Smarc if ((lflag&NOKERNINFO) == 0) 96644419Smarc ttyinfo(tp); 96744419Smarc goto endcase; 96844419Smarc } 9699578Ssam } 9709578Ssam /* 9719578Ssam * Check for input buffer overflow 9729578Ssam */ 97347545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 97435811Smarc if (iflag&IMAXBEL) { 97535811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 97635811Smarc (void) ttyoutput(CTRL('g'), tp); 97735811Smarc } else 97835811Smarc ttyflush(tp, FREAD | FWRITE); 9799578Ssam goto endcase; 98010391Ssam } 9819578Ssam /* 9829578Ssam * Put data char in q for user and 9839578Ssam * wakeup on seeing a line delimiter. 9849578Ssam */ 9859578Ssam if (putc(c, &tp->t_rawq) >= 0) { 98647545Skarels if ((lflag&ICANON) == 0) { 98747545Skarels ttwakeup(tp); 98847545Skarels ttyecho(c, tp); 98947545Skarels goto endcase; 99047545Skarels } 99135811Smarc if (ttbreakc(c)) { 9929578Ssam tp->t_rocount = 0; 9939578Ssam catq(&tp->t_rawq, &tp->t_canq); 9947502Sroot ttwakeup(tp); 9959578Ssam } else if (tp->t_rocount++ == 0) 9969578Ssam tp->t_rocol = tp->t_col; 9979578Ssam if (tp->t_state&TS_ERASE) { 99835811Smarc /* 99935811Smarc * end of prterase \.../ 100035811Smarc */ 10019578Ssam tp->t_state &= ~TS_ERASE; 10029578Ssam (void) ttyoutput('/', tp); 10039578Ssam } 10049578Ssam i = tp->t_col; 10057502Sroot ttyecho(c, tp); 100635811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 100735811Smarc /* 100835811Smarc * Place the cursor over the '^' of the ^D. 100935811Smarc */ 10109578Ssam i = MIN(2, tp->t_col - i); 10119578Ssam while (i > 0) { 10129578Ssam (void) ttyoutput('\b', tp); 10139578Ssam i--; 10149578Ssam } 10159578Ssam } 10167502Sroot } 10179578Ssam endcase: 10189578Ssam /* 101935811Smarc * IXANY means allow any character to restart output. 10209578Ssam */ 102140712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 102240712Skarels cc[VSTART] != cc[VSTOP]) 10237502Sroot return; 10249578Ssam restartoutput: 10257502Sroot tp->t_state &= ~TS_TTSTOP; 102635811Smarc tp->t_lflag &= ~FLUSHO; 10279578Ssam startoutput: 10287502Sroot ttstart(tp); 10297502Sroot } 10307502Sroot 10317502Sroot /* 1032*49380Skarels * Output a single character on a tty, doing output processing 1033*49380Skarels * as needed (expanding tabs, newline processing, etc.). 1034*49380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10357502Sroot * Must be recursive. 10367502Sroot */ 10377502Sroot ttyoutput(c, tp) 10387502Sroot register c; 10397502Sroot register struct tty *tp; 10407502Sroot { 1041*49380Skarels register int col; 104235811Smarc register long oflag = tp->t_oflag; 104335811Smarc 104440712Skarels if ((oflag&OPOST) == 0) { 104535811Smarc if (tp->t_lflag&FLUSHO) 10467502Sroot return (-1); 10477502Sroot if (putc(c, &tp->t_outq)) 10487625Ssam return (c); 10497502Sroot tk_nout++; 105035811Smarc tp->t_outcc++; 10517502Sroot return (-1); 10527502Sroot } 105335811Smarc c &= TTY_CHARMASK; 10547502Sroot /* 1055*49380Skarels * Do tab expansion if OXTABS is set. 105642882Smarc * Special case if we have external processing, we don't 105742882Smarc * do the tab expansion because we'll probably get it 105842882Smarc * wrong. If tab expansion needs to be done, let it 105942882Smarc * happen externally. 10607502Sroot */ 106147545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 10627502Sroot register int s; 10637502Sroot 10647502Sroot c = 8 - (tp->t_col&7); 106535811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 106617545Skarels s = spltty(); /* don't interrupt tabs */ 10677502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10687502Sroot tk_nout += c; 106935811Smarc tp->t_outcc += c; 10707502Sroot splx(s); 10717502Sroot } 10727502Sroot tp->t_col += c; 10737502Sroot return (c ? -1 : '\t'); 10747502Sroot } 107535811Smarc if (c == CEOT && oflag&ONOEOT) 107647545Skarels return (-1); 10777502Sroot tk_nout++; 107835811Smarc tp->t_outcc++; 10797502Sroot /* 1080*49380Skarels * Newline translation: if ONLCR is set, 1081*49380Skarels * translate newline into "\r\n". 10827502Sroot */ 108335811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10847502Sroot return (c); 108535811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 108635811Smarc return (c); 108747545Skarels 1088*49380Skarels col = tp->t_col; 1089*49380Skarels switch (CCLASS(c)) { 10907502Sroot 10917502Sroot case ORDINARY: 1092*49380Skarels col++; 10937502Sroot 10947502Sroot case CONTROL: 10957502Sroot break; 10967502Sroot 10977502Sroot case BACKSPACE: 1098*49380Skarels if (col > 0) 1099*49380Skarels col--; 11007502Sroot break; 11017502Sroot 11027502Sroot case NEWLINE: 1103*49380Skarels col = 0; 11047502Sroot break; 11057502Sroot 11067502Sroot case TAB: 1107*49380Skarels col = (col + 8) &~ 0x7; 11087502Sroot break; 11097502Sroot 11107502Sroot case RETURN: 1111*49380Skarels col = 0; 11127502Sroot } 1113*49380Skarels tp->t_col = col; 11147502Sroot return (-1); 11157502Sroot } 11167502Sroot 11177502Sroot /* 1118*49380Skarels * Process a read call on a tty device. 11197502Sroot */ 112037584Smarc ttread(tp, uio, flag) 11217625Ssam register struct tty *tp; 11227722Swnj struct uio *uio; 11237502Sroot { 11247502Sroot register struct clist *qp; 112535811Smarc register int c; 112641383Smarc register long lflag; 112735811Smarc register u_char *cc = tp->t_cc; 112847545Skarels register struct proc *p = curproc; 11299859Ssam int s, first, error = 0; 11307502Sroot 11317502Sroot loop: 113241383Smarc lflag = tp->t_lflag; 113337584Smarc s = spltty(); 11349578Ssam /* 113537584Smarc * take pending input first 11369578Ssam */ 113735811Smarc if (lflag&PENDIN) 11387502Sroot ttypend(tp); 11399859Ssam splx(s); 114040712Skarels 11419578Ssam /* 11429578Ssam * Hang process if it's in the background. 11439578Ssam */ 114447545Skarels if (isbackground(p, tp)) { 114547545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 114647545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 114747545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11488520Sroot return (EIO); 114947545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 115043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 115143377Smarc ttybg, 0)) 115240712Skarels return (error); 115323165Sbloom goto loop; 11547502Sroot } 115540712Skarels 11569578Ssam /* 115735811Smarc * If canonical, use the canonical queue, 115835811Smarc * else use the raw queue. 115937584Smarc * 116047545Skarels * (should get rid of clists...) 11619578Ssam */ 116235811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 116340712Skarels 11649578Ssam /* 116540712Skarels * If there is no input, sleep on rawq 116640712Skarels * awaiting hardware receipt and notification. 116740712Skarels * If we have data, we don't need to check for carrier. 11689578Ssam */ 116917545Skarels s = spltty(); 11709578Ssam if (qp->c_cc <= 0) { 117140712Skarels int carrier; 117240712Skarels 117340712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 117440712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 11759859Ssam splx(s); 117640712Skarels return (0); /* EOF */ 11777502Sroot } 117837728Smckusick if (flag & IO_NDELAY) { 117937584Smarc splx(s); 118037584Smarc return (EWOULDBLOCK); 118137584Smarc } 118243377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 118340712Skarels carrier ? ttyin : ttopen, 0); 11849859Ssam splx(s); 118543377Smarc if (error) 118640712Skarels return (error); 11879578Ssam goto loop; 11889578Ssam } 11899859Ssam splx(s); 119040712Skarels 11919578Ssam /* 119235811Smarc * Input present, check for input mapping and processing. 11939578Ssam */ 11949578Ssam first = 1; 11959578Ssam while ((c = getc(qp)) >= 0) { 11969578Ssam /* 119735811Smarc * delayed suspend (^Y) 11989578Ssam */ 119935811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 120042882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12019578Ssam if (first) { 120243377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 120343377Smarc TTIPRI | PCATCH, ttybg, 0)) 120440712Skarels break; 12059578Ssam goto loop; 12069578Ssam } 12079578Ssam break; 12087502Sroot } 12099578Ssam /* 121035811Smarc * Interpret EOF only in canonical mode. 12119578Ssam */ 121235811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12139578Ssam break; 12149578Ssam /* 12159578Ssam * Give user character. 12169578Ssam */ 121740712Skarels error = ureadc(c, uio); 12189578Ssam if (error) 12199578Ssam break; 122014938Smckusick if (uio->uio_resid == 0) 12219578Ssam break; 12229578Ssam /* 122335811Smarc * In canonical mode check for a "break character" 12249578Ssam * marking the end of a "line of input". 12259578Ssam */ 122640712Skarels if (lflag&ICANON && ttbreakc(c)) 12279578Ssam break; 12289578Ssam first = 0; 12297502Sroot } 12309578Ssam /* 12319578Ssam * Look to unblock output now that (presumably) 12329578Ssam * the input queue has gone down. 12339578Ssam */ 123435811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 123547545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 123647545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12377502Sroot tp->t_state &= ~TS_TBLOCK; 12387502Sroot ttstart(tp); 12397502Sroot } 124035811Smarc } 12418520Sroot return (error); 12427502Sroot } 12437502Sroot 12447502Sroot /* 124525391Skarels * Check the output queue on tp for space for a kernel message 124625391Skarels * (from uprintf/tprintf). Allow some space over the normal 124725391Skarels * hiwater mark so we don't lose messages due to normal flow 124825391Skarels * control, but don't let the tty run amok. 124930695Skarels * Sleeps here are not interruptible, but we return prematurely 125030695Skarels * if new signals come in. 125125391Skarels */ 125225391Skarels ttycheckoutq(tp, wait) 125325391Skarels register struct tty *tp; 125425391Skarels int wait; 125525391Skarels { 125630695Skarels int hiwat, s, oldsig; 125748439Skarels extern int wakeup(); 125825391Skarels 125935811Smarc hiwat = tp->t_hiwat; 126025391Skarels s = spltty(); 126147545Skarels oldsig = curproc->p_sig; 126225391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126329946Skarels while (tp->t_outq.c_cc > hiwat) { 126429946Skarels ttstart(tp); 126547545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 126629946Skarels splx(s); 126729946Skarels return (0); 126829946Skarels } 126930695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 127029946Skarels tp->t_state |= TS_ASLEEP; 127130695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 127225391Skarels } 127325391Skarels splx(s); 127425391Skarels return (1); 127525391Skarels } 127625391Skarels 127725391Skarels /* 1278*49380Skarels * Process a write call on a tty device. 12797502Sroot */ 128037584Smarc ttwrite(tp, uio, flag) 12817625Ssam register struct tty *tp; 12829578Ssam register struct uio *uio; 12837502Sroot { 12847502Sroot register char *cp; 128540712Skarels register int cc = 0, ce; 128647545Skarels register struct proc *p = curproc; 12879578Ssam int i, hiwat, cnt, error, s; 12887502Sroot char obuf[OBUFSIZ]; 12897502Sroot 129035811Smarc hiwat = tp->t_hiwat; 12919578Ssam cnt = uio->uio_resid; 12929578Ssam error = 0; 12937502Sroot loop: 129437584Smarc s = spltty(); 129540712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 129637584Smarc if (tp->t_state&TS_ISOPEN) { 129737584Smarc splx(s); 129837584Smarc return (EIO); 129937728Smckusick } else if (flag & IO_NDELAY) { 130037584Smarc splx(s); 130140712Skarels error = EWOULDBLOCK; 130240712Skarels goto out; 130337584Smarc } else { 130437584Smarc /* 130537584Smarc * sleep awaiting carrier 130637584Smarc */ 130743377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 130843377Smarc TTIPRI | PCATCH,ttopen, 0); 130937584Smarc splx(s); 131043377Smarc if (error) 131140712Skarels goto out; 131237584Smarc goto loop; 131337584Smarc } 131437584Smarc } 131537584Smarc splx(s); 13169578Ssam /* 13179578Ssam * Hang the process if it's in the background. 13189578Ssam */ 131947545Skarels if (isbackground(p, tp) && 132047545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 132147545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 132247545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 132347545Skarels p->p_pgrp->pg_jobc) { 132447545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 132543377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 132643377Smarc ttybg, 0)) 132740712Skarels goto out; 132821776Sbloom goto loop; 13297502Sroot } 13309578Ssam /* 13319578Ssam * Process the user's data in at most OBUFSIZ 133240712Skarels * chunks. Perform any output translation. 133340712Skarels * Keep track of high water mark, sleep on overflow 133440712Skarels * awaiting device aid in acquiring new space. 13359578Ssam */ 133640712Skarels while (uio->uio_resid > 0 || cc > 0) { 133740712Skarels if (tp->t_lflag&FLUSHO) { 133840712Skarels uio->uio_resid = 0; 133940712Skarels return (0); 134040712Skarels } 134140712Skarels if (tp->t_outq.c_cc > hiwat) 134232067Skarels goto ovhiwat; 13439578Ssam /* 134440712Skarels * Grab a hunk of data from the user, 134540712Skarels * unless we have some leftover from last time. 13469578Ssam */ 13477822Sroot if (cc == 0) { 134840712Skarels cc = min(uio->uio_resid, OBUFSIZ); 134940712Skarels cp = obuf; 135040712Skarels error = uiomove(cp, cc, uio); 135140712Skarels if (error) { 135240712Skarels cc = 0; 135340712Skarels break; 135440712Skarels } 13557822Sroot } 13569578Ssam /* 13579578Ssam * If nothing fancy need be done, grab those characters we 13589578Ssam * can handle without any of ttyoutput's processing and 13599578Ssam * just transfer them to the output q. For those chars 13609578Ssam * which require special processing (as indicated by the 13619578Ssam * bits in partab), call ttyoutput. After processing 13629578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13639578Ssam * immediately. 13649578Ssam */ 13659578Ssam while (cc > 0) { 136640712Skarels if ((tp->t_oflag&OPOST) == 0) 13677502Sroot ce = cc; 13687502Sroot else { 136934492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 1370*49380Skarels (u_char *)partab, CCLASSMASK); 13719578Ssam /* 13729578Ssam * If ce is zero, then we're processing 13739578Ssam * a special character through ttyoutput. 13749578Ssam */ 13759578Ssam if (ce == 0) { 13767502Sroot tp->t_rocount = 0; 13777502Sroot if (ttyoutput(*cp, tp) >= 0) { 137821776Sbloom /* no c-lists, wait a bit */ 137921776Sbloom ttstart(tp); 138043377Smarc if (error = ttysleep(tp, 138143377Smarc (caddr_t)&lbolt, 138243377Smarc TTOPRI | PCATCH, ttybuf, 0)) 138340712Skarels break; 138421776Sbloom goto loop; 13857502Sroot } 13869578Ssam cp++, cc--; 138735811Smarc if ((tp->t_lflag&FLUSHO) || 13889578Ssam tp->t_outq.c_cc > hiwat) 13897502Sroot goto ovhiwat; 13909578Ssam continue; 13917502Sroot } 13927502Sroot } 13939578Ssam /* 13949578Ssam * A bunch of normal characters have been found, 13959578Ssam * transfer them en masse to the output queue and 13969578Ssam * continue processing at the top of the loop. 13979578Ssam * If there are any further characters in this 13989578Ssam * <= OBUFSIZ chunk, the first should be a character 13999578Ssam * requiring special handling by ttyoutput. 14009578Ssam */ 14017502Sroot tp->t_rocount = 0; 14029578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14039578Ssam ce -= i; 14049578Ssam tp->t_col += ce; 14059578Ssam cp += ce, cc -= ce, tk_nout += ce; 140635811Smarc tp->t_outcc += ce; 14079578Ssam if (i > 0) { 14089578Ssam /* out of c-lists, wait a bit */ 14097502Sroot ttstart(tp); 141043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 141143377Smarc TTOPRI | PCATCH, ttybuf, 0)) 141240712Skarels break; 141321776Sbloom goto loop; 14147502Sroot } 141535811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 141640712Skarels break; 14177502Sroot } 141835811Smarc ttstart(tp); 14197502Sroot } 142040712Skarels out: 142140712Skarels /* 142240712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 142340712Skarels * as the offset and iov pointers have moved forward, 142440712Skarels * but it doesn't matter (the call will either return short 142540712Skarels * or restart with a new uio). 142640712Skarels */ 142740712Skarels uio->uio_resid += cc; 14288520Sroot return (error); 142940712Skarels 14307502Sroot ovhiwat: 143132067Skarels ttstart(tp); 143232067Skarels s = spltty(); 14339578Ssam /* 143435811Smarc * This can only occur if FLUSHO is set in t_lflag, 143532067Skarels * or if ttstart/oproc is synchronous (or very fast). 14369578Ssam */ 14377502Sroot if (tp->t_outq.c_cc <= hiwat) { 14389578Ssam splx(s); 14397502Sroot goto loop; 14407502Sroot } 144137728Smckusick if (flag & IO_NDELAY) { 144217545Skarels splx(s); 144340712Skarels uio->uio_resid += cc; 14447822Sroot if (uio->uio_resid == cnt) 14458520Sroot return (EWOULDBLOCK); 14468520Sroot return (0); 14477502Sroot } 14487502Sroot tp->t_state |= TS_ASLEEP; 144943377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14509578Ssam splx(s); 145143377Smarc if (error) 145240712Skarels goto out; 14537502Sroot goto loop; 14547502Sroot } 14557502Sroot 14567502Sroot /* 14577502Sroot * Rubout one character from the rawq of tp 14587502Sroot * as cleanly as possible. 14597502Sroot */ 14607502Sroot ttyrub(c, tp) 14617625Ssam register c; 14627625Ssam register struct tty *tp; 14637502Sroot { 14647502Sroot register char *cp; 14657502Sroot register int savecol; 14667502Sroot int s; 14677502Sroot char *nextc(); 14687502Sroot 146942882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 14707502Sroot return; 147135811Smarc tp->t_lflag &= ~FLUSHO; 147235811Smarc if (tp->t_lflag&ECHOE) { 14737502Sroot if (tp->t_rocount == 0) { 14747502Sroot /* 14757502Sroot * Screwed by ttwrite; retype 14767502Sroot */ 14777502Sroot ttyretype(tp); 14787502Sroot return; 14797502Sroot } 148035811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 14817502Sroot ttyrubo(tp, 2); 1482*49380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 14837502Sroot 14847502Sroot case ORDINARY: 148535811Smarc ttyrubo(tp, 1); 14867502Sroot break; 14877502Sroot 14887502Sroot case VTAB: 14897502Sroot case BACKSPACE: 14907502Sroot case CONTROL: 14917502Sroot case RETURN: 149247545Skarels case NEWLINE: 149335811Smarc if (tp->t_lflag&ECHOCTL) 14947502Sroot ttyrubo(tp, 2); 14957502Sroot break; 14967502Sroot 149735811Smarc case TAB: { 149835811Smarc int c; 149935811Smarc 15007502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15017502Sroot ttyretype(tp); 15027502Sroot return; 15037502Sroot } 150417545Skarels s = spltty(); 15057502Sroot savecol = tp->t_col; 15069578Ssam tp->t_state |= TS_CNTTB; 150735811Smarc tp->t_lflag |= FLUSHO; 15087502Sroot tp->t_col = tp->t_rocol; 15099578Ssam cp = tp->t_rawq.c_cf; 151039407Smarc if (cp) 151139407Smarc c = *cp; /* XXX FIX NEXTC */ 151235811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 151335811Smarc ttyecho(c, tp); 151435811Smarc tp->t_lflag &= ~FLUSHO; 15159578Ssam tp->t_state &= ~TS_CNTTB; 15167502Sroot splx(s); 15177502Sroot /* 15187502Sroot * savecol will now be length of the tab 15197502Sroot */ 15207502Sroot savecol -= tp->t_col; 15217502Sroot tp->t_col += savecol; 15227502Sroot if (savecol > 8) 15237502Sroot savecol = 8; /* overflow screw */ 15247502Sroot while (--savecol >= 0) 15257502Sroot (void) ttyoutput('\b', tp); 15267502Sroot break; 152735811Smarc } 15287502Sroot 15297502Sroot default: 153037584Smarc /* XXX */ 153135811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 1532*49380Skarels c, CCLASS(c)); 153335811Smarc /*panic("ttyrub");*/ 15347502Sroot } 153535811Smarc } else if (tp->t_lflag&ECHOPRT) { 15369578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15377502Sroot (void) ttyoutput('\\', tp); 15389578Ssam tp->t_state |= TS_ERASE; 15397502Sroot } 15407502Sroot ttyecho(c, tp); 15417502Sroot } else 154235811Smarc ttyecho(tp->t_cc[VERASE], tp); 15437502Sroot tp->t_rocount--; 15447502Sroot } 15457502Sroot 15467502Sroot /* 15477502Sroot * Crt back over cnt chars perhaps 15487502Sroot * erasing them. 15497502Sroot */ 15507502Sroot ttyrubo(tp, cnt) 15517625Ssam register struct tty *tp; 15527625Ssam int cnt; 15537502Sroot { 15547502Sroot 15557502Sroot while (--cnt >= 0) 155640712Skarels ttyoutstr("\b \b", tp); 15577502Sroot } 15587502Sroot 15597502Sroot /* 15607502Sroot * Reprint the rawq line. 15617502Sroot * We assume c_cc has already been checked. 15627502Sroot */ 15637502Sroot ttyretype(tp) 15647625Ssam register struct tty *tp; 15657502Sroot { 15667502Sroot register char *cp; 15677502Sroot char *nextc(); 156835811Smarc int s, c; 15697502Sroot 157035811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 157135811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15727502Sroot (void) ttyoutput('\n', tp); 157317545Skarels s = spltty(); 157435811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 157535811Smarc BIT OF FIRST CHAR ****/ 157635811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 157735811Smarc ttyecho(c, tp); 157835811Smarc } 157935811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 158035811Smarc ttyecho(c, tp); 158135811Smarc } 15829578Ssam tp->t_state &= ~TS_ERASE; 15837502Sroot splx(s); 15847502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15857502Sroot tp->t_rocol = 0; 15867502Sroot } 15877502Sroot 15887502Sroot /* 158935811Smarc * Echo a typed character to the terminal. 15907502Sroot */ 15917502Sroot ttyecho(c, tp) 15927625Ssam register c; 15937625Ssam register struct tty *tp; 15947502Sroot { 15959578Ssam if ((tp->t_state&TS_CNTTB) == 0) 159635811Smarc tp->t_lflag &= ~FLUSHO; 159747545Skarels if (((tp->t_lflag&ECHO) == 0 && 159847545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 15997502Sroot return; 160035811Smarc if (tp->t_lflag&ECHOCTL) { 160140712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 160240712Skarels c == 0177) { 16037502Sroot (void) ttyoutput('^', tp); 160435811Smarc c &= TTY_CHARMASK; 16057502Sroot if (c == 0177) 16067502Sroot c = '?'; 16077502Sroot else 16087502Sroot c += 'A' - 1; 16097502Sroot } 16107502Sroot } 161135811Smarc (void) ttyoutput(c, tp); 16127502Sroot } 16137502Sroot 16147502Sroot /* 16157502Sroot * send string cp to tp 16167502Sroot */ 161740712Skarels ttyoutstr(cp, tp) 16187625Ssam register char *cp; 16197625Ssam register struct tty *tp; 16207502Sroot { 16217502Sroot register char c; 16227502Sroot 16237502Sroot while (c = *cp++) 16247502Sroot (void) ttyoutput(c, tp); 16257502Sroot } 16267502Sroot 1627*49380Skarels /* 1628*49380Skarels * Wake up any readers on a tty. 1629*49380Skarels */ 16307502Sroot ttwakeup(tp) 163147545Skarels register struct tty *tp; 16327502Sroot { 16337502Sroot 16347502Sroot if (tp->t_rsel) { 16357502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16367502Sroot tp->t_state &= ~TS_RCOLL; 16377502Sroot tp->t_rsel = 0; 16387502Sroot } 163912752Ssam if (tp->t_state & TS_ASYNC) 164042882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16417502Sroot wakeup((caddr_t)&tp->t_rawq); 16427502Sroot } 164335811Smarc 164435811Smarc /* 164548439Skarels * Look up a code for a specified speed in a conversion table; 164648439Skarels * used by drivers to map software speed values to hardware parameters. 164748439Skarels */ 164848439Skarels ttspeedtab(speed, table) 164948439Skarels register struct speedtab *table; 165048439Skarels { 165148439Skarels 165248439Skarels for ( ; table->sp_speed != -1; table++) 165348439Skarels if (table->sp_speed == speed) 165448439Skarels return (table->sp_code); 165548439Skarels return (-1); 165648439Skarels } 165748439Skarels 165848439Skarels /* 165935811Smarc * set tty hi and low water marks 166035811Smarc * 166135811Smarc * Try to arrange the dynamics so there's about one second 166235811Smarc * from hi to low water. 166335811Smarc * 166435811Smarc */ 166535811Smarc ttsetwater(tp) 166635811Smarc struct tty *tp; 166735811Smarc { 166835811Smarc register cps = tp->t_ospeed / 10; 166935811Smarc register x; 167035811Smarc 167135811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 167235811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 167335811Smarc x += cps; 167435811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 167535811Smarc tp->t_hiwat = roundup(x, CBSIZE); 167635811Smarc #undef clamp 167735811Smarc } 167835811Smarc 167939407Smarc /* 168039407Smarc * (^T) 168139407Smarc * Report on state of foreground process group. 168239407Smarc */ 168339407Smarc ttyinfo(tp) 168439407Smarc struct tty *tp; 168539407Smarc { 168641177Smarc register struct proc *p, *pick = NULL; 168741177Smarc int x, s; 168841177Smarc struct timeval utime, stime; 168942350Smckusick #define pgtok(a) (((a)*NBPG)/1024) 169039407Smarc 169139407Smarc if (ttycheckoutq(tp,0) == 0) 169239407Smarc return; 169341177Smarc /* 169441177Smarc * load average 169541177Smarc */ 169641177Smarc x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT; 169741177Smarc ttyprintf(tp, "load: %d.", x/100); 169841177Smarc ttyoutint(x%100, 10, 2, tp); 169939555Smarc if (tp->t_session == NULL) 170041177Smarc ttyprintf(tp, " not a controlling terminal\n"); 170141177Smarc else if (tp->t_pgrp == NULL) 170241177Smarc ttyprintf(tp, " no foreground process group\n"); 170341177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 170441177Smarc ttyprintf(tp, " empty foreground process group\n"); 170539407Smarc else { 170641177Smarc /* pick interesting process */ 170739407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 170841177Smarc if (proc_compare(pick, p)) 170941177Smarc pick = p; 171039407Smarc } 171141177Smarc ttyprintf(tp, " cmd: %s %d [%s] ", 171241177Smarc pick->p_comm, pick->p_pid, 171348439Skarels pick->p_stat == SRUN ? "running" : 171448439Skarels pick->p_wmesg ? pick->p_wmesg : "iowait"); 171541177Smarc /* 171641177Smarc * cpu time 171741177Smarc */ 171847545Skarels if (curproc == pick) 171941177Smarc s = splclock(); 172041177Smarc utime = pick->p_utime; 172141177Smarc stime = pick->p_stime; 172247545Skarels if (curproc == pick) 172341177Smarc splx(s); 172441177Smarc /* user time */ 172541177Smarc x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */ 172641177Smarc ttyoutint(utime.tv_sec, 10, 1, tp); 172741177Smarc tputchar('.', tp); 172841177Smarc ttyoutint(x, 10, 2, tp); 172941177Smarc tputchar('u', tp); 173041177Smarc tputchar(' ', tp); 173141177Smarc /* system time */ 173241177Smarc x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */ 173341177Smarc ttyoutint(stime.tv_sec, 10, 1, tp); 173441177Smarc tputchar('.', tp); 173541177Smarc ttyoutint(x, 10, 2, tp); 173641177Smarc tputchar('s', tp); 173741177Smarc tputchar(' ', tp); 173841177Smarc /* 173941177Smarc * pctcpu 174041177Smarc */ 174141177Smarc x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT; 174241177Smarc ttyoutint(x/100, 10, 1, tp); 174341177Smarc #ifdef notdef /* do we really want this ??? */ 174441177Smarc tputchar('.', tp); 174541177Smarc ttyoutint(x%100, 10, 2, tp); 174641177Smarc #endif 174747545Skarels ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize)); 174839407Smarc } 174941177Smarc tp->t_rocount = 0; /* so pending input will be retyped if BS */ 175039407Smarc } 175139407Smarc 175241177Smarc ttyoutint(n, base, min, tp) 175341177Smarc register int n, base, min; 175441177Smarc register struct tty *tp; 175541177Smarc { 175641177Smarc char info[16]; 175741177Smarc register char *p = info; 175841177Smarc 175941177Smarc while (--min >= 0 || n) { 176041177Smarc *p++ = "0123456789abcdef"[n%base]; 176141177Smarc n /= base; 176241177Smarc } 176341177Smarc while (p > info) 176441177Smarc ttyoutput(*--p, tp); 176541177Smarc } 176641177Smarc 176741177Smarc /* 176841177Smarc * Returns 1 if p2 is "better" than p1 176941177Smarc * 177041177Smarc * The algorithm for picking the "interesting" process is thus: 177141177Smarc * 177241177Smarc * 1) (Only foreground processes are eligable - implied) 177341177Smarc * 2) Runnable processes are favored over anything 177441177Smarc * else. The runner with the highest cpu 177541177Smarc * utilization is picked (p_cpu). Ties are 177641177Smarc * broken by picking the highest pid. 177741177Smarc * 3 Next, the sleeper with the shortest sleep 177841177Smarc * time is favored. With ties, we pick out 177941177Smarc * just "short-term" sleepers (SSINTR == 0). 178041177Smarc * Further ties are broken by picking the highest 178141177Smarc * pid. 178241177Smarc * 178341177Smarc */ 178441177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 178545723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 178645723Smckusick #define ONLYA 2 178745723Smckusick #define ONLYB 1 178845723Smckusick #define BOTH 3 178945723Smckusick 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 */ 179945723Smckusick 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 */ 180841177Smarc if (p2->p_cpu > p1->p_cpu) 180941177Smarc return (1); 181041177Smarc if (p1->p_cpu > p2->p_cpu) 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 } 182541177Smarc /* 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 */ 183541177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 183641177Smarc return (1); 183741177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 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 */ 184539555Smarc tputchar(c, tp) 184639555Smarc int c; 184739555Smarc struct tty *tp; 184839555Smarc { 184939555Smarc register s = spltty(); 185039555Smarc 185147545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 185239555Smarc if (c == '\n') 185339555Smarc (void) ttyoutput('\r', tp); 185439555Smarc (void) ttyoutput(c, tp); 185539555Smarc ttstart(tp); 185639555Smarc splx(s); 185739555Smarc return (0); 185839555Smarc } 185939555Smarc splx(s); 186039555Smarc return (-1); 186139555Smarc } 186243377Smarc 186344419Smarc /* 1864*49380Skarels * Sleep on chan, returning ERESTART if tty changed 1865*49380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 1866*49380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 1867*49380Skarels * call will redo validation done at the start of the call. 186844419Smarc */ 186943377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187043377Smarc struct tty *tp; 187143377Smarc caddr_t chan; 187243377Smarc int pri; 187343377Smarc char *wmesg; 187443377Smarc int timo; 187543377Smarc { 187643377Smarc int error; 187743377Smarc short gen = tp->t_gen; 187843377Smarc 187943377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188043377Smarc return (error); 188143377Smarc if (tp->t_gen != gen) 188243377Smarc return (ERESTART); 188343377Smarc return (0); 188443377Smarc } 1885