149594Sbostic /*- 249594Sbostic * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 349594Sbostic * Copyright (c) 1991 The Regents of the University of California. 449594Sbostic * All rights reserved. 523387Smckusick * 649594Sbostic * %sccs.include.redist.c% 749594Sbostic * 8*52666Smckusick * @(#)tty.c 7.50 (Berkeley) 02/25/92 923387Smckusick */ 1039Sbill 1117095Sbloom #include "param.h" 1217095Sbloom #include "systm.h" 1317095Sbloom #include "ioctl.h" 1452522Smckusick #include "proc.h" 1539407Smarc #define TTYDEFCHARS 1617095Sbloom #include "tty.h" 1735811Smarc #undef TTYDEFCHARS 1817095Sbloom #include "file.h" 1917095Sbloom #include "conf.h" 2029946Skarels #include "dkstat.h" 2117095Sbloom #include "uio.h" 2217095Sbloom #include "kernel.h" 2337728Smckusick #include "vnode.h" 2435811Smarc #include "syslog.h" 2539Sbill 2648439Skarels #include "vm/vm.h" 2737525Smckusick 2849907Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2)); 2949907Sbostic 3040712Skarels /* symbolic sleep message strings */ 3140712Skarels char ttyin[] = "ttyin"; 3240712Skarels char ttyout[] = "ttyout"; 3341370Smarc char ttopen[] = "ttyopn"; 3441370Smarc char ttclos[] = "ttycls"; 3540712Skarels char ttybg[] = "ttybg"; 3640712Skarels char ttybuf[] = "ttybuf"; 3740712Skarels 387436Skre /* 397436Skre * Table giving parity for characters and indicating 4035811Smarc * character classes to tty driver. The 8th bit 4135811Smarc * indicates parity, the 7th bit indicates the character 4235811Smarc * is an alphameric or underscore (for ALTWERASE), and the 4335811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 4449380Skarels * then the character needs no special processing on output; 4549380Skarels * classes other than 0 might be translated or (not currently) 4649380Skarels * require delays. 477436Skre */ 4849380Skarels #define PARITY(c) (partab[c] & 0x80) 4949380Skarels #define ISALPHA(c) (partab[(c)&TTY_CHARMASK] & 0x40) 5049380Skarels #define CCLASSMASK 0x3f 5149380Skarels #define CCLASS(c) (partab[c] & CCLASSMASK) 5239Sbill 5349380Skarels #define E 0x00 /* even parity */ 5449380Skarels #define O 0x80 /* odd parity */ 5549380Skarels #define ALPHA 0x40 /* alpha or underscore */ 5649380Skarels 5749380Skarels #define NO ORDINARY 5849380Skarels #define NA ORDINARY|ALPHA 5949380Skarels #define CC CONTROL 6049380Skarels #define BS BACKSPACE 6149380Skarels #define NL NEWLINE 6249380Skarels #define TB TAB 6349380Skarels #define VT VTAB 6449380Skarels #define CR RETURN 6549380Skarels 667436Skre char partab[] = { 6749380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 6849380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 6949380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 7049380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 7149380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 7249380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 7349380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 7449380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 7549380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 7649380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 7749380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 7849380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 7949380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 8049380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 8149380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 8249380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 837436Skre /* 8449380Skarels * "meta" chars; should be settable per charset. 8549380Skarels * For now, treat all as normal characters. 867436Skre */ 8749380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 8849380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 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, 1037436Skre }; 10449380Skarels #undef NO 10549380Skarels #undef NA 10649380Skarels #undef CC 10749380Skarels #undef BS 10849380Skarels #undef NL 10949380Skarels #undef TB 11049380Skarels #undef VT 11149380Skarels #undef CR 1127436Skre 11335811Smarc extern struct tty *constty; /* temporary virtual console */ 11435811Smarc 115146Sbill /* 11635811Smarc * Is 'c' a line delimiter ("break" character)? 11739Sbill */ 11840712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ 11940712Skarels (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 12039Sbill 12139Sbill ttychars(tp) 1229578Ssam struct tty *tp; 12339Sbill { 12447545Skarels 12535811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 12639Sbill } 12739Sbill 12839Sbill /* 12949380Skarels * Flush tty after output has drained. 13039Sbill */ 13112752Ssam ttywflush(tp) 13237584Smarc struct tty *tp; 13339Sbill { 13440712Skarels int error; 13539Sbill 13640712Skarels if ((error = ttywait(tp)) == 0) 13740712Skarels ttyflush(tp, FREAD); 13840712Skarels return (error); 13912752Ssam } 14012752Ssam 14135811Smarc /* 14235811Smarc * Wait for output to drain. 14335811Smarc */ 14412752Ssam ttywait(tp) 14512752Ssam register struct tty *tp; 14612752Ssam { 14740712Skarels int error = 0, s = spltty(); 14812752Ssam 14913809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 15037584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 15137584Smarc tp->t_oproc) { 152903Sbill (*tp->t_oproc)(tp); 1535408Swnj tp->t_state |= TS_ASLEEP; 15443377Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_outq, 15543377Smarc TTOPRI | PCATCH, ttyout, 0)) 15640712Skarels break; 157903Sbill } 1589859Ssam splx(s); 15940712Skarels return (error); 16039Sbill } 16139Sbill 16252485Storek #define flushq(q) { \ 16352485Storek if ((q)->c_cc) \ 16452485Storek ndflush(q, (q)->c_cc); \ 16549380Skarels } 16649380Skarels 16739Sbill /* 16849380Skarels * Flush TTY read and/or write queues, 16949380Skarels * notifying anyone waiting. 17039Sbill */ 17112752Ssam ttyflush(tp, rw) 1727625Ssam register struct tty *tp; 17352485Storek int rw; 17439Sbill { 17552485Storek register int s; 176903Sbill 17717545Skarels s = spltty(); 178903Sbill if (rw & FREAD) { 17949380Skarels flushq(&tp->t_canq); 18049380Skarels flushq(&tp->t_rawq); 18149380Skarels tp->t_rocount = 0; 18249380Skarels tp->t_rocol = 0; 18349380Skarels tp->t_state &= ~TS_LOCAL; 18437584Smarc ttwakeup(tp); 185903Sbill } 186903Sbill if (rw & FWRITE) { 1875408Swnj tp->t_state &= ~TS_TTSTOP; 18852485Storek #ifdef sun4c /* XXX */ 18952485Storek (*tp->t_stop)(tp, rw); 19052485Storek #else 1915426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 19252485Storek #endif 19349380Skarels flushq(&tp->t_outq); 19449380Skarels wakeup((caddr_t)&tp->t_outq); 19552522Smckusick selwakeup(&tp->t_wsel); 196903Sbill } 197903Sbill splx(s); 19839Sbill } 19939Sbill 200903Sbill /* 201903Sbill * Send stop character on input overflow. 202903Sbill */ 203903Sbill ttyblock(tp) 2047625Ssam register struct tty *tp; 20539Sbill { 206903Sbill register x; 2079578Ssam 208903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 209903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 21012752Ssam ttyflush(tp, FREAD|FWRITE); 2115408Swnj tp->t_state &= ~TS_TBLOCK; 212903Sbill } 21315118Skarels /* 21415118Skarels * Block further input iff: 21515118Skarels * Current input > threshold AND input is available to user program 21615118Skarels */ 21742350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 21840712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 21935811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 22042350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 22115118Skarels tp->t_state |= TS_TBLOCK; 22215118Skarels ttstart(tp); 22315118Skarels } 224903Sbill } 22539Sbill } 22639Sbill 22747545Skarels ttstart(tp) 22837584Smarc struct tty *tp; 229121Sbill { 230121Sbill 23147545Skarels if (tp->t_oproc) /* kludge for pty */ 23247545Skarels (*tp->t_oproc)(tp); 23347545Skarels } 23447545Skarels 23547545Skarels ttrstrt(tp) /* XXX */ 23647545Skarels struct tty *tp; 23747545Skarels { 23852485Storek int s; 23947545Skarels 24040712Skarels #ifdef DIAGNOSTIC 2419578Ssam if (tp == 0) 2429578Ssam panic("ttrstrt"); 24340712Skarels #endif 24452485Storek s = spltty(); 2455408Swnj tp->t_state &= ~TS_TIMEOUT; 246903Sbill ttstart(tp); 24752485Storek splx(s); 248121Sbill } 249121Sbill 25039Sbill 25139Sbill /* 25249380Skarels * Common code for ioctls on tty devices. 25349380Skarels * Called after line-discipline-specific ioctl 25449380Skarels * has been called to do discipline-specific functions 25549380Skarels * and/or reject any of these ioctl commands. 25639Sbill */ 2571780Sbill /*ARGSUSED*/ 2587625Ssam ttioctl(tp, com, data, flag) 2597625Ssam register struct tty *tp; 26052485Storek int com; 2617625Ssam caddr_t data; 26252485Storek int flag; 26339Sbill { 26447545Skarels register struct proc *p = curproc; /* XXX */ 26539Sbill extern int nldisp; 26637554Smckusick int s, error; 26739Sbill 268903Sbill /* 269903Sbill * If the ioctl involves modification, 27017545Skarels * hang if in the background. 271903Sbill */ 2727625Ssam switch (com) { 27339Sbill 27435811Smarc case TIOCSETD: 275903Sbill case TIOCFLUSH: 27635811Smarc /*case TIOCSPGRP:*/ 2779325Ssam case TIOCSTI: 27817598Sbloom case TIOCSWINSZ: 27935811Smarc case TIOCSETA: 28035811Smarc case TIOCSETAW: 28135811Smarc case TIOCSETAF: 28252485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 28340030Smarc case TIOCSETP: 28440030Smarc case TIOCSETN: 28540030Smarc case TIOCSETC: 28640030Smarc case TIOCSLTC: 28740030Smarc case TIOCLBIS: 28840030Smarc case TIOCLBIC: 28940030Smarc case TIOCLSET: 29040030Smarc case OTIOCSETD: 29140030Smarc #endif 29247545Skarels while (isbackground(curproc, tp) && 29347545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 29447545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 29547545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 29647545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 29743377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 29843377Smarc TTOPRI | PCATCH, ttybg, 0)) 29940712Skarels return (error); 300903Sbill } 301903Sbill break; 302903Sbill } 303903Sbill 3049578Ssam /* 3059578Ssam * Process the ioctl. 3069578Ssam */ 3077625Ssam switch (com) { 308903Sbill 3098556Sroot /* get discipline number */ 31039Sbill case TIOCGETD: 3117625Ssam *(int *)data = tp->t_line; 31239Sbill break; 31339Sbill 3148556Sroot /* set line discipline */ 3157625Ssam case TIOCSETD: { 3167625Ssam register int t = *(int *)data; 31735811Smarc dev_t dev = tp->t_dev; 3187625Ssam 31935811Smarc if ((unsigned)t >= nldisp) 32010851Ssam return (ENXIO); 32125584Skarels if (t != tp->t_line) { 32225584Skarels s = spltty(); 32349752Smarc (*linesw[tp->t_line].l_close)(tp, flag); 32425584Skarels error = (*linesw[t].l_open)(dev, tp); 32525584Skarels if (error) { 32635811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 32725584Skarels splx(s); 32825584Skarels return (error); 32925584Skarels } 33025584Skarels tp->t_line = t; 33110851Ssam splx(s); 33210851Ssam } 33339Sbill break; 3347625Ssam } 33539Sbill 3368556Sroot /* prevent more opens on channel */ 3375614Swnj case TIOCEXCL: 33852485Storek s = spltty(); 3395614Swnj tp->t_state |= TS_XCLUDE; 34052485Storek splx(s); 3415614Swnj break; 3425614Swnj 3435614Swnj case TIOCNXCL: 34452485Storek s = spltty(); 3455614Swnj tp->t_state &= ~TS_XCLUDE; 34652485Storek splx(s); 3475614Swnj break; 3485614Swnj 34952485Storek #ifdef TIOCHPCL 35039Sbill case TIOCHPCL: 35152485Storek s = spltty(); 35235811Smarc tp->t_cflag |= HUPCL; 35352485Storek splx(s); 35439Sbill break; 35552485Storek #endif 35639Sbill 3573942Sbugs case TIOCFLUSH: { 3587625Ssam register int flags = *(int *)data; 3597625Ssam 3607625Ssam if (flags == 0) 3613942Sbugs flags = FREAD|FWRITE; 3627625Ssam else 3637625Ssam flags &= FREAD|FWRITE; 36412752Ssam ttyflush(tp, flags); 36539Sbill break; 3663944Sbugs } 36739Sbill 36837584Smarc case FIOASYNC: 36952485Storek s = spltty(); 37037584Smarc if (*(int *)data) 37137584Smarc tp->t_state |= TS_ASYNC; 37237584Smarc else 37337584Smarc tp->t_state &= ~TS_ASYNC; 37452485Storek splx(s); 37537584Smarc break; 37637584Smarc 37737584Smarc case FIONBIO: 37837584Smarc break; /* XXX remove */ 37937584Smarc 3808556Sroot /* return number of characters immediately available */ 3817625Ssam case FIONREAD: 3827625Ssam *(off_t *)data = ttnread(tp); 383174Sbill break; 384174Sbill 38513077Ssam case TIOCOUTQ: 38613077Ssam *(int *)data = tp->t_outq.c_cc; 38713077Ssam break; 38813077Ssam 3898589Sroot case TIOCSTOP: 39017545Skarels s = spltty(); 3919578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3925573Swnj tp->t_state |= TS_TTSTOP; 39352485Storek #ifdef sun4c /* XXX */ 39452485Storek (*tp->t_stop)(tp, 0); 39552485Storek #else 3965573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 39752485Storek #endif 3985573Swnj } 3997625Ssam splx(s); 4005573Swnj break; 4015573Swnj 4028589Sroot case TIOCSTART: 40317545Skarels s = spltty(); 40435811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 4055573Swnj tp->t_state &= ~TS_TTSTOP; 40635811Smarc tp->t_lflag &= ~FLUSHO; 4075573Swnj ttstart(tp); 4085573Swnj } 4097625Ssam splx(s); 4105573Swnj break; 4115573Swnj 4129325Ssam /* 4139325Ssam * Simulate typing of a character at the terminal. 4149325Ssam */ 4159325Ssam case TIOCSTI: 41647545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 41717183Smckusick return (EPERM); 41847545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 4199325Ssam return (EACCES); 4209578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4219325Ssam break; 4229325Ssam 42335811Smarc case TIOCGETA: { 42435811Smarc struct termios *t = (struct termios *)data; 42512752Ssam 42635811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 42735811Smarc break; 42835811Smarc } 42935811Smarc 43035811Smarc case TIOCSETA: 43135811Smarc case TIOCSETAW: 43237584Smarc case TIOCSETAF: { 43335811Smarc register struct termios *t = (struct termios *)data; 43440712Skarels 43517545Skarels s = spltty(); 43639407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 43740712Skarels if (error = ttywait(tp)) { 43840712Skarels splx(s); 43940712Skarels return (error); 44040712Skarels } 44145007Smarc if (com == TIOCSETAF) 44239407Smarc ttyflush(tp, FREAD); 44339407Smarc } 44440712Skarels if ((t->c_cflag&CIGNORE) == 0) { 44535811Smarc /* 44635811Smarc * set device hardware 44735811Smarc */ 44837584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 44937584Smarc splx(s); 45035811Smarc return (error); 45137584Smarc } else { 45240712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 45337584Smarc (tp->t_cflag&CLOCAL) && 45440712Skarels (t->c_cflag&CLOCAL) == 0) { 45537584Smarc tp->t_state &= ~TS_ISOPEN; 45637584Smarc tp->t_state |= TS_WOPEN; 45737584Smarc ttwakeup(tp); 45837584Smarc } 45935811Smarc tp->t_cflag = t->c_cflag; 46035811Smarc tp->t_ispeed = t->c_ispeed; 46135811Smarc tp->t_ospeed = t->c_ospeed; 46234492Skarels } 46335811Smarc ttsetwater(tp); 46412752Ssam } 46539407Smarc if (com != TIOCSETAF) { 46635811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 46735811Smarc if (t->c_lflag&ICANON) { 46835811Smarc tp->t_lflag |= PENDIN; 46935811Smarc ttwakeup(tp); 47035811Smarc } 47135811Smarc else { 47235811Smarc struct clist tq; 47335811Smarc 47435811Smarc catq(&tp->t_rawq, &tp->t_canq); 47535811Smarc tq = tp->t_rawq; 47635811Smarc tp->t_rawq = tp->t_canq; 47735811Smarc tp->t_canq = tq; 47835811Smarc } 47912752Ssam } 48035811Smarc tp->t_iflag = t->c_iflag; 48135811Smarc tp->t_oflag = t->c_oflag; 48242882Smarc /* 48342882Smarc * Make the EXTPROC bit read only. 48442882Smarc */ 48542882Smarc if (tp->t_lflag&EXTPROC) 48642882Smarc t->c_lflag |= EXTPROC; 48742882Smarc else 48842882Smarc t->c_lflag &= ~EXTPROC; 48935811Smarc tp->t_lflag = t->c_lflag; 49035811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 49112752Ssam splx(s); 49212752Ssam break; 49312752Ssam } 49412752Ssam 49512752Ssam /* 49639555Smarc * Set controlling terminal. 49739555Smarc * Session ctty vnode pointer set in vnode layer. 49834492Skarels */ 49947545Skarels case TIOCSCTTY: 50039555Smarc if (!SESS_LEADER(p) || 50139555Smarc (p->p_session->s_ttyvp || tp->t_session) && 50239555Smarc (tp->t_session != p->p_session)) 50339407Smarc return (EPERM); 50435811Smarc tp->t_session = p->p_session; 50539555Smarc tp->t_pgrp = p->p_pgrp; 50639555Smarc p->p_session->s_ttyp = tp; 50739555Smarc p->p_flag |= SCTTY; 50834492Skarels break; 50939555Smarc 51034492Skarels /* 51135811Smarc * Set terminal process group. 51217545Skarels */ 51318650Sbloom case TIOCSPGRP: { 51435811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 51517545Skarels 51639555Smarc if (!isctty(p, tp)) 51739555Smarc return (ENOTTY); 51840030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 51939555Smarc return (EPERM); 52039555Smarc tp->t_pgrp = pgrp; 52112752Ssam break; 52218650Sbloom } 52312752Ssam 52412752Ssam case TIOCGPGRP: 52547545Skarels if (!isctty(p, tp)) 52639555Smarc return (ENOTTY); 52745007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 52812752Ssam break; 52912752Ssam 53017598Sbloom case TIOCSWINSZ: 53118650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 53218650Sbloom sizeof (struct winsize))) { 53317598Sbloom tp->t_winsize = *(struct winsize *)data; 53442882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 53517598Sbloom } 53617598Sbloom break; 53717598Sbloom 53817598Sbloom case TIOCGWINSZ: 53917598Sbloom *(struct winsize *)data = tp->t_winsize; 54017598Sbloom break; 54117598Sbloom 54230534Skarels case TIOCCONS: 54330534Skarels if (*(int *)data) { 54442141Smckusick if (constty && constty != tp && 54542141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 54642141Smckusick (TS_CARR_ON|TS_ISOPEN)) 54730534Skarels return (EBUSY); 54830534Skarels #ifndef UCONSOLE 54947545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55037554Smckusick return (error); 55130534Skarels #endif 55230534Skarels constty = tp; 55330534Skarels } else if (tp == constty) 55433404Skarels constty = NULL; 55530534Skarels break; 55630534Skarels 55748439Skarels case TIOCDRAIN: 55848439Skarels if (error = ttywait(tp)) 55948439Skarels return (error); 56048439Skarels break; 56148439Skarels 56247545Skarels default: 56352485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 56447545Skarels return (ttcompat(tp, com, data, flag)); 56547545Skarels #else 56647545Skarels return (-1); 56735811Smarc #endif 56839Sbill } 5698556Sroot return (0); 57039Sbill } 5714484Swnj 5724484Swnj ttnread(tp) 5734484Swnj struct tty *tp; 5744484Swnj { 5754484Swnj int nread = 0; 5764484Swnj 57735811Smarc if (tp->t_lflag & PENDIN) 5784484Swnj ttypend(tp); 5794484Swnj nread = tp->t_canq.c_cc; 58035811Smarc if ((tp->t_lflag & ICANON) == 0) 5814484Swnj nread += tp->t_rawq.c_cc; 5824484Swnj return (nread); 5834484Swnj } 5844484Swnj 58552522Smckusick ttselect(dev, rw, p) 5864484Swnj dev_t dev; 5875408Swnj int rw; 58852522Smckusick struct proc *p; 5894484Swnj { 5904484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5914484Swnj int nread; 59217545Skarels int s = spltty(); 5934484Swnj 5945408Swnj switch (rw) { 5954484Swnj 5964484Swnj case FREAD: 5974484Swnj nread = ttnread(tp); 59837584Smarc if (nread > 0 || 59940712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 6005408Swnj goto win; 60152522Smckusick selrecord(p, &tp->t_rsel); 6025408Swnj break; 6034484Swnj 6045408Swnj case FWRITE: 60535811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 6065408Swnj goto win; 60752522Smckusick selrecord(p, &tp->t_wsel); 6085408Swnj break; 6094484Swnj } 6105408Swnj splx(s); 6115408Swnj return (0); 6125408Swnj win: 6135408Swnj splx(s); 6145408Swnj return (1); 6154484Swnj } 6167436Skre 6177502Sroot /* 61849380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6197502Sroot */ 6207502Sroot ttyopen(dev, tp) 6217625Ssam dev_t dev; 6227625Ssam register struct tty *tp; 6237502Sroot { 62452485Storek int s = spltty(); 6257502Sroot 6267502Sroot tp->t_dev = dev; 62735811Smarc 6287502Sroot tp->t_state &= ~TS_WOPEN; 62917545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 63017545Skarels tp->t_state |= TS_ISOPEN; 63117598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 63217545Skarels } 63352485Storek splx(s); 6348556Sroot return (0); 6357502Sroot } 6367502Sroot 6377502Sroot /* 63825391Skarels * "close" a line discipline 63925391Skarels */ 64049752Smarc ttylclose(tp, flag) 64149752Smarc struct tty *tp; 64249752Smarc int flag; 64325391Skarels { 64425391Skarels 64549752Smarc if (flag&IO_NDELAY) 64649752Smarc ttyflush(tp, FREAD|FWRITE); 64749752Smarc else 64849752Smarc ttywflush(tp); 64925391Skarels } 65025391Skarels 65125391Skarels /* 65249380Skarels * Handle close() on a tty line: flush and set to initial state, 65349380Skarels * bumping generation number so that pending read/write calls 65449380Skarels * can detect recycling of the tty. 6557502Sroot */ 6567502Sroot ttyclose(tp) 6577625Ssam register struct tty *tp; 6587502Sroot { 65930534Skarels if (constty == tp) 66030534Skarels constty = NULL; 66125391Skarels ttyflush(tp, FREAD|FWRITE); 66239555Smarc tp->t_session = NULL; 66339555Smarc tp->t_pgrp = NULL; 6647502Sroot tp->t_state = 0; 66543377Smarc tp->t_gen++; 66640712Skarels return (0); 6677502Sroot } 6687502Sroot 6697502Sroot /* 67025391Skarels * Handle modem control transition on a tty. 67125391Skarels * Flag indicates new state of carrier. 67225391Skarels * Returns 0 if the line should be turned off, otherwise 1. 67325391Skarels */ 67425391Skarels ttymodem(tp, flag) 67525391Skarels register struct tty *tp; 67652485Storek int flag; 67725391Skarels { 67825391Skarels 67942193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 68025391Skarels /* 68125391Skarels * MDMBUF: do flow control according to carrier flag 68225391Skarels */ 68325391Skarels if (flag) { 68425391Skarels tp->t_state &= ~TS_TTSTOP; 68525391Skarels ttstart(tp); 68625391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 68725391Skarels tp->t_state |= TS_TTSTOP; 68852485Storek #ifdef sun4c /* XXX */ 68952485Storek (*tp->t_stop)(tp, 0); 69052485Storek #else 69125391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 69252485Storek #endif 69325391Skarels } 69425391Skarels } else if (flag == 0) { 69525391Skarels /* 69625391Skarels * Lost carrier. 69725391Skarels */ 69825391Skarels tp->t_state &= ~TS_CARR_ON; 69942193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 70042193Smarc if (tp->t_session && tp->t_session->s_leader) 70142193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70242193Smarc ttyflush(tp, FREAD|FWRITE); 70342193Smarc return (0); 70425391Skarels } 70525391Skarels } else { 70625391Skarels /* 70725391Skarels * Carrier now on. 70825391Skarels */ 70925391Skarels tp->t_state |= TS_CARR_ON; 71037584Smarc ttwakeup(tp); 71125391Skarels } 71225391Skarels return (1); 71325391Skarels } 71425391Skarels 71525391Skarels /* 71625404Skarels * Default modem control routine (for other line disciplines). 71725404Skarels * Return argument flag, to turn off device on carrier drop. 71825404Skarels */ 71925415Skarels nullmodem(tp, flag) 72025415Skarels register struct tty *tp; 72125404Skarels int flag; 72225404Skarels { 72325404Skarels 72425404Skarels if (flag) 72525404Skarels tp->t_state |= TS_CARR_ON; 72639407Smarc else { 72725404Skarels tp->t_state &= ~TS_CARR_ON; 72842193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 72942193Smarc if (tp->t_session && tp->t_session->s_leader) 73042193Smarc psignal(tp->t_session->s_leader, SIGHUP); 73142193Smarc return (0); 73242193Smarc } 73339407Smarc } 73442193Smarc return (1); 73525404Skarels } 73625404Skarels 73725404Skarels /* 7387502Sroot * reinput pending characters after state switch 73917545Skarels * call at spltty(). 7407502Sroot */ 7417502Sroot ttypend(tp) 7427625Ssam register struct tty *tp; 7437502Sroot { 7447502Sroot struct clist tq; 7457502Sroot register c; 7467502Sroot 74735811Smarc tp->t_lflag &= ~PENDIN; 7489578Ssam tp->t_state |= TS_TYPEN; 7497502Sroot tq = tp->t_rawq; 7507502Sroot tp->t_rawq.c_cc = 0; 7517502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7527502Sroot while ((c = getc(&tq)) >= 0) 7537502Sroot ttyinput(c, tp); 7549578Ssam tp->t_state &= ~TS_TYPEN; 7557502Sroot } 7567502Sroot 7577502Sroot /* 75849380Skarels * Process input of a single character received on a tty. 7597502Sroot */ 7607502Sroot ttyinput(c, tp) 7617625Ssam register c; 7627625Ssam register struct tty *tp; 7637502Sroot { 76435811Smarc register int iflag = tp->t_iflag; 76535811Smarc register int lflag = tp->t_lflag; 76635811Smarc register u_char *cc = tp->t_cc; 76735811Smarc int i, err; 7687502Sroot 7699578Ssam /* 7709578Ssam * If input is pending take it first. 7719578Ssam */ 77235811Smarc if (lflag&PENDIN) 7737502Sroot ttypend(tp); 77435811Smarc /* 77535811Smarc * Gather stats. 77635811Smarc */ 7777502Sroot tk_nin++; 77835811Smarc if (lflag&ICANON) { 77935811Smarc tk_cancc++; 78035811Smarc tp->t_cancc++; 78135811Smarc } else { 78235811Smarc tk_rawcc++; 78335811Smarc tp->t_rawcc++; 78435811Smarc } 7859578Ssam /* 78635811Smarc * Handle exceptional conditions (break, parity, framing). 7879578Ssam */ 78835811Smarc if (err = (c&TTY_ERRORMASK)) { 78935811Smarc c &= ~TTY_ERRORMASK; 79035811Smarc if (err&TTY_FE && !c) { /* break */ 79135811Smarc if (iflag&IGNBRK) 79235811Smarc goto endcase; 79335811Smarc else if (iflag&BRKINT && lflag&ISIG && 79435811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 79535811Smarc c = cc[VINTR]; 79647545Skarels else if (iflag&PARMRK) 79747545Skarels goto parmrk; 79835811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 79935811Smarc if (iflag&IGNPAR) 80035811Smarc goto endcase; 80135811Smarc else if (iflag&PARMRK) { 80235811Smarc parmrk: 80335811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 80435811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 80535811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 80635811Smarc goto endcase; 80735811Smarc } else 80835811Smarc c = 0; 8097502Sroot } 8109578Ssam } 8119578Ssam /* 81235811Smarc * In tandem mode, check high water mark. 8139578Ssam */ 81435811Smarc if (iflag&IXOFF) 81535811Smarc ttyblock(tp); 81635811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 81749380Skarels c &= ~0x80; 81844419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 81944419Smarc /* 82044419Smarc * Check for literal nexting very first 82144419Smarc */ 82244419Smarc if (tp->t_state&TS_LNCH) { 82344419Smarc c |= TTY_QUOTE; 82444419Smarc tp->t_state &= ~TS_LNCH; 82544419Smarc } 82644419Smarc /* 82744419Smarc * Scan for special characters. This code 82844419Smarc * is really just a big case statement with 82944419Smarc * non-constant cases. The bottom of the 83044419Smarc * case statement is labeled ``endcase'', so goto 83144419Smarc * it after a case match, or similar. 83244419Smarc */ 83344419Smarc 83444419Smarc /* 83544419Smarc * Control chars which aren't controlled 83644419Smarc * by ICANON, ISIG, or IXON. 83744419Smarc */ 83844419Smarc if (lflag&IEXTEN) { 83944419Smarc if (CCEQ(cc[VLNEXT], c)) { 84044419Smarc if (lflag&ECHO) { 84144419Smarc if (lflag&ECHOE) 84244419Smarc ttyoutstr("^\b", tp); 84344419Smarc else 84444419Smarc ttyecho(c, tp); 84544419Smarc } 84644419Smarc tp->t_state |= TS_LNCH; 84744419Smarc goto endcase; 84844419Smarc } 84944419Smarc if (CCEQ(cc[VDISCARD], c)) { 85044419Smarc if (lflag&FLUSHO) 85144419Smarc tp->t_lflag &= ~FLUSHO; 85244419Smarc else { 85344419Smarc ttyflush(tp, FWRITE); 85435811Smarc ttyecho(c, tp); 85544419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 85644419Smarc ttyretype(tp); 85744419Smarc tp->t_lflag |= FLUSHO; 85844419Smarc } 85944419Smarc goto startoutput; 86035811Smarc } 8619578Ssam } 86244419Smarc /* 86344419Smarc * Signals. 86444419Smarc */ 86544419Smarc if (lflag&ISIG) { 86644419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 86744419Smarc if ((lflag&NOFLSH) == 0) 86844419Smarc ttyflush(tp, FREAD|FWRITE); 8697502Sroot ttyecho(c, tp); 87044419Smarc pgsignal(tp->t_pgrp, 87144419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 87244419Smarc goto endcase; 8737502Sroot } 87444419Smarc if (CCEQ(cc[VSUSP], c)) { 87544419Smarc if ((lflag&NOFLSH) == 0) 87644419Smarc ttyflush(tp, FREAD); 87744419Smarc ttyecho(c, tp); 87844419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 87944419Smarc goto endcase; 88044419Smarc } 8819578Ssam } 88244419Smarc /* 88344419Smarc * Handle start/stop characters. 88444419Smarc */ 88544419Smarc if (iflag&IXON) { 88644419Smarc if (CCEQ(cc[VSTOP], c)) { 88744419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 88844419Smarc tp->t_state |= TS_TTSTOP; 88952485Storek #ifdef sun4c /* XXX */ 89052485Storek (*tp->t_stop)(tp, 0); 89152485Storek #else 89244419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 89344419Smarc 0); 89452485Storek #endif 89544419Smarc return; 89644419Smarc } 89744419Smarc if (!CCEQ(cc[VSTART], c)) 89844419Smarc return; 89944419Smarc /* 90044419Smarc * if VSTART == VSTOP then toggle 90144419Smarc */ 90244419Smarc goto endcase; 90335811Smarc } 90444419Smarc if (CCEQ(cc[VSTART], c)) 90544419Smarc goto restartoutput; 9069578Ssam } 90744419Smarc /* 90844419Smarc * IGNCR, ICRNL, & INLCR 90944419Smarc */ 91044419Smarc if (c == '\r') { 91144419Smarc if (iflag&IGNCR) 91244419Smarc goto endcase; 91344419Smarc else if (iflag&ICRNL) 91444419Smarc c = '\n'; 91544419Smarc } else if (c == '\n' && iflag&INLCR) 91644419Smarc c = '\r'; 9179578Ssam } 91847545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 91944419Smarc /* 92044419Smarc * From here on down canonical mode character 92144419Smarc * processing takes place. 92244419Smarc */ 92344419Smarc /* 92444419Smarc * erase (^H / ^?) 92544419Smarc */ 92644419Smarc if (CCEQ(cc[VERASE], c)) { 92744419Smarc if (tp->t_rawq.c_cc) 9289578Ssam ttyrub(unputc(&tp->t_rawq), tp); 92944419Smarc goto endcase; 9309578Ssam } 93144419Smarc /* 93244419Smarc * kill (^U) 93344419Smarc */ 93444419Smarc if (CCEQ(cc[VKILL], c)) { 93544419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 93644419Smarc (lflag&ECHOPRT) == 0) { 93744419Smarc while (tp->t_rawq.c_cc) 93844419Smarc ttyrub(unputc(&tp->t_rawq), tp); 93944419Smarc } else { 94044419Smarc ttyecho(c, tp); 94144419Smarc if (lflag&ECHOK || lflag&ECHOKE) 94244419Smarc ttyecho('\n', tp); 94352485Storek flushq(&tp->t_rawq); 94444419Smarc tp->t_rocount = 0; 94544419Smarc } 94644419Smarc tp->t_state &= ~TS_LOCAL; 94744419Smarc goto endcase; 94844419Smarc } 94944419Smarc /* 95044419Smarc * word erase (^W) 95144419Smarc */ 95244419Smarc if (CCEQ(cc[VWERASE], c)) { 95344419Smarc int ctype; 95447545Skarels int alt = lflag&ALTWERASE; 95535811Smarc 95644419Smarc /* 95744419Smarc * erase whitespace 95844419Smarc */ 95944419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 96044419Smarc ttyrub(c, tp); 96144419Smarc if (c == -1) 96244419Smarc goto endcase; 96344419Smarc /* 96447545Skarels * erase last char of word and remember the 96547545Skarels * next chars type (for ALTWERASE) 96644419Smarc */ 96735811Smarc ttyrub(c, tp); 96844419Smarc c = unputc(&tp->t_rawq); 96947545Skarels if (c == -1) 97044419Smarc goto endcase; 97151003Sbostic if (c == ' ' || c == '\t') { 97251003Sbostic putc(c, &tp->t_rawq); 97351003Sbostic goto endcase; 97451003Sbostic } 97549380Skarels ctype = ISALPHA(c); 97644419Smarc /* 97747545Skarels * erase rest of word 97844419Smarc */ 97944419Smarc do { 98044419Smarc ttyrub(c, tp); 98144419Smarc c = unputc(&tp->t_rawq); 98244419Smarc if (c == -1) 98344419Smarc goto endcase; 98447545Skarels } while (c != ' ' && c != '\t' && 98549380Skarels (alt == 0 || ISALPHA(c) == ctype)); 98644419Smarc (void) putc(c, &tp->t_rawq); 98734492Skarels goto endcase; 98844419Smarc } 98935811Smarc /* 99044419Smarc * reprint line (^R) 99135811Smarc */ 99244419Smarc if (CCEQ(cc[VREPRINT], c)) { 99344419Smarc ttyretype(tp); 99434492Skarels goto endcase; 99534492Skarels } 99635811Smarc /* 99744419Smarc * ^T - kernel info and generate SIGINFO 99835811Smarc */ 99944419Smarc if (CCEQ(cc[VSTATUS], c)) { 100051068Smarc if (lflag&ISIG) 100151068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 100244419Smarc if ((lflag&NOKERNINFO) == 0) 100344419Smarc ttyinfo(tp); 100444419Smarc goto endcase; 100544419Smarc } 10069578Ssam } 10079578Ssam /* 10089578Ssam * Check for input buffer overflow 10099578Ssam */ 101047545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 101135811Smarc if (iflag&IMAXBEL) { 101235811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 101335811Smarc (void) ttyoutput(CTRL('g'), tp); 101435811Smarc } else 101535811Smarc ttyflush(tp, FREAD | FWRITE); 10169578Ssam goto endcase; 101710391Ssam } 10189578Ssam /* 10199578Ssam * Put data char in q for user and 10209578Ssam * wakeup on seeing a line delimiter. 10219578Ssam */ 10229578Ssam if (putc(c, &tp->t_rawq) >= 0) { 102347545Skarels if ((lflag&ICANON) == 0) { 102447545Skarels ttwakeup(tp); 102547545Skarels ttyecho(c, tp); 102647545Skarels goto endcase; 102747545Skarels } 102835811Smarc if (ttbreakc(c)) { 10299578Ssam tp->t_rocount = 0; 10309578Ssam catq(&tp->t_rawq, &tp->t_canq); 10317502Sroot ttwakeup(tp); 10329578Ssam } else if (tp->t_rocount++ == 0) 10339578Ssam tp->t_rocol = tp->t_col; 10349578Ssam if (tp->t_state&TS_ERASE) { 103535811Smarc /* 103635811Smarc * end of prterase \.../ 103735811Smarc */ 10389578Ssam tp->t_state &= ~TS_ERASE; 10399578Ssam (void) ttyoutput('/', tp); 10409578Ssam } 10419578Ssam i = tp->t_col; 10427502Sroot ttyecho(c, tp); 104335811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 104435811Smarc /* 104535811Smarc * Place the cursor over the '^' of the ^D. 104635811Smarc */ 10479578Ssam i = MIN(2, tp->t_col - i); 10489578Ssam while (i > 0) { 10499578Ssam (void) ttyoutput('\b', tp); 10509578Ssam i--; 10519578Ssam } 10529578Ssam } 10537502Sroot } 10549578Ssam endcase: 10559578Ssam /* 105635811Smarc * IXANY means allow any character to restart output. 10579578Ssam */ 105840712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 105940712Skarels cc[VSTART] != cc[VSTOP]) 10607502Sroot return; 10619578Ssam restartoutput: 10627502Sroot tp->t_state &= ~TS_TTSTOP; 106335811Smarc tp->t_lflag &= ~FLUSHO; 10649578Ssam startoutput: 10657502Sroot ttstart(tp); 10667502Sroot } 10677502Sroot 10687502Sroot /* 106949380Skarels * Output a single character on a tty, doing output processing 107049380Skarels * as needed (expanding tabs, newline processing, etc.). 107149380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10727502Sroot * Must be recursive. 10737502Sroot */ 10747502Sroot ttyoutput(c, tp) 10757502Sroot register c; 10767502Sroot register struct tty *tp; 10777502Sroot { 107849380Skarels register int col; 107935811Smarc register long oflag = tp->t_oflag; 108035811Smarc 108140712Skarels if ((oflag&OPOST) == 0) { 108235811Smarc if (tp->t_lflag&FLUSHO) 10837502Sroot return (-1); 10847502Sroot if (putc(c, &tp->t_outq)) 10857625Ssam return (c); 10867502Sroot tk_nout++; 108735811Smarc tp->t_outcc++; 10887502Sroot return (-1); 10897502Sroot } 109035811Smarc c &= TTY_CHARMASK; 10917502Sroot /* 109249380Skarels * Do tab expansion if OXTABS is set. 109342882Smarc * Special case if we have external processing, we don't 109442882Smarc * do the tab expansion because we'll probably get it 109542882Smarc * wrong. If tab expansion needs to be done, let it 109642882Smarc * happen externally. 10977502Sroot */ 109847545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 10997502Sroot register int s; 11007502Sroot 11017502Sroot c = 8 - (tp->t_col&7); 110235811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 110317545Skarels s = spltty(); /* don't interrupt tabs */ 11047502Sroot c -= b_to_q(" ", c, &tp->t_outq); 11057502Sroot tk_nout += c; 110635811Smarc tp->t_outcc += c; 11077502Sroot splx(s); 11087502Sroot } 11097502Sroot tp->t_col += c; 11107502Sroot return (c ? -1 : '\t'); 11117502Sroot } 111235811Smarc if (c == CEOT && oflag&ONOEOT) 111347545Skarels return (-1); 11147502Sroot tk_nout++; 111535811Smarc tp->t_outcc++; 11167502Sroot /* 111749380Skarels * Newline translation: if ONLCR is set, 111849380Skarels * translate newline into "\r\n". 11197502Sroot */ 112035811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 11217502Sroot return (c); 112235811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 112335811Smarc return (c); 112447545Skarels 112549380Skarels col = tp->t_col; 112649380Skarels switch (CCLASS(c)) { 11277502Sroot 11287502Sroot case ORDINARY: 112949380Skarels col++; 11307502Sroot 11317502Sroot case CONTROL: 11327502Sroot break; 11337502Sroot 11347502Sroot case BACKSPACE: 113549380Skarels if (col > 0) 113649380Skarels col--; 11377502Sroot break; 11387502Sroot 11397502Sroot case NEWLINE: 114049380Skarels col = 0; 11417502Sroot break; 11427502Sroot 11437502Sroot case TAB: 114449380Skarels col = (col + 8) &~ 0x7; 11457502Sroot break; 11467502Sroot 11477502Sroot case RETURN: 114849380Skarels col = 0; 11497502Sroot } 115049380Skarels tp->t_col = col; 11517502Sroot return (-1); 11527502Sroot } 11537502Sroot 11547502Sroot /* 115549380Skarels * Process a read call on a tty device. 11567502Sroot */ 115737584Smarc ttread(tp, uio, flag) 11587625Ssam register struct tty *tp; 11597722Swnj struct uio *uio; 116052485Storek int flag; 11617502Sroot { 11627502Sroot register struct clist *qp; 116335811Smarc register int c; 116441383Smarc register long lflag; 116535811Smarc register u_char *cc = tp->t_cc; 116647545Skarels register struct proc *p = curproc; 11679859Ssam int s, first, error = 0; 11687502Sroot 11697502Sroot loop: 117041383Smarc lflag = tp->t_lflag; 117137584Smarc s = spltty(); 11729578Ssam /* 117337584Smarc * take pending input first 11749578Ssam */ 117535811Smarc if (lflag&PENDIN) 11767502Sroot ttypend(tp); 11779859Ssam splx(s); 117840712Skarels 11799578Ssam /* 11809578Ssam * Hang process if it's in the background. 11819578Ssam */ 118247545Skarels if (isbackground(p, tp)) { 118347545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 118447545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 118547545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11868520Sroot return (EIO); 118747545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 118843377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 118943377Smarc ttybg, 0)) 119040712Skarels return (error); 119123165Sbloom goto loop; 11927502Sroot } 119340712Skarels 11949578Ssam /* 119535811Smarc * If canonical, use the canonical queue, 119635811Smarc * else use the raw queue. 119737584Smarc * 119847545Skarels * (should get rid of clists...) 11999578Ssam */ 120035811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 120140712Skarels 12029578Ssam /* 120340712Skarels * If there is no input, sleep on rawq 120440712Skarels * awaiting hardware receipt and notification. 120540712Skarels * If we have data, we don't need to check for carrier. 12069578Ssam */ 120717545Skarels s = spltty(); 12089578Ssam if (qp->c_cc <= 0) { 120940712Skarels int carrier; 121040712Skarels 121140712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 121240712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 12139859Ssam splx(s); 121440712Skarels return (0); /* EOF */ 12157502Sroot } 121637728Smckusick if (flag & IO_NDELAY) { 121737584Smarc splx(s); 121837584Smarc return (EWOULDBLOCK); 121937584Smarc } 122043377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 122140712Skarels carrier ? ttyin : ttopen, 0); 12229859Ssam splx(s); 122343377Smarc if (error) 122440712Skarels return (error); 12259578Ssam goto loop; 12269578Ssam } 12279859Ssam splx(s); 122840712Skarels 12299578Ssam /* 123035811Smarc * Input present, check for input mapping and processing. 12319578Ssam */ 12329578Ssam first = 1; 12339578Ssam while ((c = getc(qp)) >= 0) { 12349578Ssam /* 123535811Smarc * delayed suspend (^Y) 12369578Ssam */ 123735811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 123842882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12399578Ssam if (first) { 124043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 124143377Smarc TTIPRI | PCATCH, ttybg, 0)) 124240712Skarels break; 12439578Ssam goto loop; 12449578Ssam } 12459578Ssam break; 12467502Sroot } 12479578Ssam /* 124835811Smarc * Interpret EOF only in canonical mode. 12499578Ssam */ 125035811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12519578Ssam break; 12529578Ssam /* 12539578Ssam * Give user character. 12549578Ssam */ 125540712Skarels error = ureadc(c, uio); 12569578Ssam if (error) 12579578Ssam break; 125814938Smckusick if (uio->uio_resid == 0) 12599578Ssam break; 12609578Ssam /* 126135811Smarc * In canonical mode check for a "break character" 12629578Ssam * marking the end of a "line of input". 12639578Ssam */ 126440712Skarels if (lflag&ICANON && ttbreakc(c)) 12659578Ssam break; 12669578Ssam first = 0; 12677502Sroot } 12689578Ssam /* 12699578Ssam * Look to unblock output now that (presumably) 12709578Ssam * the input queue has gone down. 12719578Ssam */ 127252485Storek s = spltty(); 127335811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 127447545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 127547545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12767502Sroot tp->t_state &= ~TS_TBLOCK; 12777502Sroot ttstart(tp); 12787502Sroot } 127935811Smarc } 128052485Storek splx(s); 12818520Sroot return (error); 12827502Sroot } 12837502Sroot 12847502Sroot /* 128525391Skarels * Check the output queue on tp for space for a kernel message 128625391Skarels * (from uprintf/tprintf). Allow some space over the normal 128725391Skarels * hiwater mark so we don't lose messages due to normal flow 128825391Skarels * control, but don't let the tty run amok. 128930695Skarels * Sleeps here are not interruptible, but we return prematurely 129030695Skarels * if new signals come in. 129125391Skarels */ 129225391Skarels ttycheckoutq(tp, wait) 129325391Skarels register struct tty *tp; 129425391Skarels int wait; 129525391Skarels { 129630695Skarels int hiwat, s, oldsig; 129748439Skarels extern int wakeup(); 129825391Skarels 129935811Smarc hiwat = tp->t_hiwat; 130025391Skarels s = spltty(); 130152485Storek oldsig = wait ? curproc->p_sig : 0; 130225391Skarels if (tp->t_outq.c_cc > hiwat + 200) 130329946Skarels while (tp->t_outq.c_cc > hiwat) { 130429946Skarels ttstart(tp); 130547545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 130629946Skarels splx(s); 130729946Skarels return (0); 130829946Skarels } 130930695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 131029946Skarels tp->t_state |= TS_ASLEEP; 131130695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 131225391Skarels } 131325391Skarels splx(s); 131425391Skarels return (1); 131525391Skarels } 131625391Skarels 131725391Skarels /* 131849380Skarels * Process a write call on a tty device. 13197502Sroot */ 132037584Smarc ttwrite(tp, uio, flag) 13217625Ssam register struct tty *tp; 13229578Ssam register struct uio *uio; 132352485Storek int flag; 13247502Sroot { 13257502Sroot register char *cp; 132640712Skarels register int cc = 0, ce; 132747545Skarels register struct proc *p = curproc; 13289578Ssam int i, hiwat, cnt, error, s; 13297502Sroot char obuf[OBUFSIZ]; 13307502Sroot 133135811Smarc hiwat = tp->t_hiwat; 13329578Ssam cnt = uio->uio_resid; 13339578Ssam error = 0; 13347502Sroot loop: 133537584Smarc s = spltty(); 133640712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 133737584Smarc if (tp->t_state&TS_ISOPEN) { 133837584Smarc splx(s); 133937584Smarc return (EIO); 134037728Smckusick } else if (flag & IO_NDELAY) { 134137584Smarc splx(s); 134240712Skarels error = EWOULDBLOCK; 134340712Skarels goto out; 134437584Smarc } else { 134537584Smarc /* 134637584Smarc * sleep awaiting carrier 134737584Smarc */ 134843377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 134943377Smarc TTIPRI | PCATCH,ttopen, 0); 135037584Smarc splx(s); 135143377Smarc if (error) 135240712Skarels goto out; 135337584Smarc goto loop; 135437584Smarc } 135537584Smarc } 135637584Smarc splx(s); 13579578Ssam /* 13589578Ssam * Hang the process if it's in the background. 13599578Ssam */ 136047545Skarels if (isbackground(p, tp) && 136147545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 136247545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 136347545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 136447545Skarels p->p_pgrp->pg_jobc) { 136547545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 136643377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 136743377Smarc ttybg, 0)) 136840712Skarels goto out; 136921776Sbloom goto loop; 13707502Sroot } 13719578Ssam /* 13729578Ssam * Process the user's data in at most OBUFSIZ 137340712Skarels * chunks. Perform any output translation. 137440712Skarels * Keep track of high water mark, sleep on overflow 137540712Skarels * awaiting device aid in acquiring new space. 13769578Ssam */ 137740712Skarels while (uio->uio_resid > 0 || cc > 0) { 137840712Skarels if (tp->t_lflag&FLUSHO) { 137940712Skarels uio->uio_resid = 0; 138040712Skarels return (0); 138140712Skarels } 138240712Skarels if (tp->t_outq.c_cc > hiwat) 138332067Skarels goto ovhiwat; 13849578Ssam /* 138540712Skarels * Grab a hunk of data from the user, 138640712Skarels * unless we have some leftover from last time. 13879578Ssam */ 13887822Sroot if (cc == 0) { 138940712Skarels cc = min(uio->uio_resid, OBUFSIZ); 139040712Skarels cp = obuf; 139140712Skarels error = uiomove(cp, cc, uio); 139240712Skarels if (error) { 139340712Skarels cc = 0; 139440712Skarels break; 139540712Skarels } 13967822Sroot } 13979578Ssam /* 13989578Ssam * If nothing fancy need be done, grab those characters we 13999578Ssam * can handle without any of ttyoutput's processing and 14009578Ssam * just transfer them to the output q. For those chars 14019578Ssam * which require special processing (as indicated by the 14029578Ssam * bits in partab), call ttyoutput. After processing 14039578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14049578Ssam * immediately. 14059578Ssam */ 14069578Ssam while (cc > 0) { 140740712Skarels if ((tp->t_oflag&OPOST) == 0) 14087502Sroot ce = cc; 14097502Sroot else { 141034492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 141149380Skarels (u_char *)partab, CCLASSMASK); 14129578Ssam /* 14139578Ssam * If ce is zero, then we're processing 14149578Ssam * a special character through ttyoutput. 14159578Ssam */ 14169578Ssam if (ce == 0) { 14177502Sroot tp->t_rocount = 0; 14187502Sroot if (ttyoutput(*cp, tp) >= 0) { 141921776Sbloom /* no c-lists, wait a bit */ 142021776Sbloom ttstart(tp); 142143377Smarc if (error = ttysleep(tp, 142243377Smarc (caddr_t)&lbolt, 142343377Smarc TTOPRI | PCATCH, ttybuf, 0)) 142440712Skarels break; 142521776Sbloom goto loop; 14267502Sroot } 14279578Ssam cp++, cc--; 142835811Smarc if ((tp->t_lflag&FLUSHO) || 14299578Ssam tp->t_outq.c_cc > hiwat) 14307502Sroot goto ovhiwat; 14319578Ssam continue; 14327502Sroot } 14337502Sroot } 14349578Ssam /* 14359578Ssam * A bunch of normal characters have been found, 14369578Ssam * transfer them en masse to the output queue and 14379578Ssam * continue processing at the top of the loop. 14389578Ssam * If there are any further characters in this 14399578Ssam * <= OBUFSIZ chunk, the first should be a character 14409578Ssam * requiring special handling by ttyoutput. 14419578Ssam */ 14427502Sroot tp->t_rocount = 0; 14439578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14449578Ssam ce -= i; 14459578Ssam tp->t_col += ce; 14469578Ssam cp += ce, cc -= ce, tk_nout += ce; 144735811Smarc tp->t_outcc += ce; 14489578Ssam if (i > 0) { 14499578Ssam /* out of c-lists, wait a bit */ 14507502Sroot ttstart(tp); 145143377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 145243377Smarc TTOPRI | PCATCH, ttybuf, 0)) 145340712Skarels break; 145421776Sbloom goto loop; 14557502Sroot } 145635811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 145740712Skarels break; 14587502Sroot } 145935811Smarc ttstart(tp); 14607502Sroot } 146140712Skarels out: 146240712Skarels /* 146340712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 146440712Skarels * as the offset and iov pointers have moved forward, 146540712Skarels * but it doesn't matter (the call will either return short 146640712Skarels * or restart with a new uio). 146740712Skarels */ 146840712Skarels uio->uio_resid += cc; 14698520Sroot return (error); 147040712Skarels 14717502Sroot ovhiwat: 147232067Skarels ttstart(tp); 147332067Skarels s = spltty(); 14749578Ssam /* 147535811Smarc * This can only occur if FLUSHO is set in t_lflag, 147632067Skarels * or if ttstart/oproc is synchronous (or very fast). 14779578Ssam */ 14787502Sroot if (tp->t_outq.c_cc <= hiwat) { 14799578Ssam splx(s); 14807502Sroot goto loop; 14817502Sroot } 148237728Smckusick if (flag & IO_NDELAY) { 148317545Skarels splx(s); 148440712Skarels uio->uio_resid += cc; 14857822Sroot if (uio->uio_resid == cnt) 14868520Sroot return (EWOULDBLOCK); 14878520Sroot return (0); 14887502Sroot } 14897502Sroot tp->t_state |= TS_ASLEEP; 149043377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14919578Ssam splx(s); 149243377Smarc if (error) 149340712Skarels goto out; 14947502Sroot goto loop; 14957502Sroot } 14967502Sroot 14977502Sroot /* 14987502Sroot * Rubout one character from the rawq of tp 14997502Sroot * as cleanly as possible. 15007502Sroot */ 15017502Sroot ttyrub(c, tp) 15027625Ssam register c; 15037625Ssam register struct tty *tp; 15047502Sroot { 15057502Sroot register char *cp; 15067502Sroot register int savecol; 15077502Sroot int s; 15087502Sroot char *nextc(); 15097502Sroot 151042882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 15117502Sroot return; 151235811Smarc tp->t_lflag &= ~FLUSHO; 151335811Smarc if (tp->t_lflag&ECHOE) { 15147502Sroot if (tp->t_rocount == 0) { 15157502Sroot /* 15167502Sroot * Screwed by ttwrite; retype 15177502Sroot */ 15187502Sroot ttyretype(tp); 15197502Sroot return; 15207502Sroot } 152135811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15227502Sroot ttyrubo(tp, 2); 152349380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 15247502Sroot 15257502Sroot case ORDINARY: 152635811Smarc ttyrubo(tp, 1); 15277502Sroot break; 15287502Sroot 15297502Sroot case VTAB: 15307502Sroot case BACKSPACE: 15317502Sroot case CONTROL: 15327502Sroot case RETURN: 153347545Skarels case NEWLINE: 153435811Smarc if (tp->t_lflag&ECHOCTL) 15357502Sroot ttyrubo(tp, 2); 15367502Sroot break; 15377502Sroot 153835811Smarc case TAB: { 153935811Smarc int c; 154035811Smarc 15417502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15427502Sroot ttyretype(tp); 15437502Sroot return; 15447502Sroot } 154517545Skarels s = spltty(); 15467502Sroot savecol = tp->t_col; 15479578Ssam tp->t_state |= TS_CNTTB; 154835811Smarc tp->t_lflag |= FLUSHO; 15497502Sroot tp->t_col = tp->t_rocol; 15509578Ssam cp = tp->t_rawq.c_cf; 155139407Smarc if (cp) 155239407Smarc c = *cp; /* XXX FIX NEXTC */ 155335811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 155435811Smarc ttyecho(c, tp); 155535811Smarc tp->t_lflag &= ~FLUSHO; 15569578Ssam tp->t_state &= ~TS_CNTTB; 15577502Sroot splx(s); 15587502Sroot /* 15597502Sroot * savecol will now be length of the tab 15607502Sroot */ 15617502Sroot savecol -= tp->t_col; 15627502Sroot tp->t_col += savecol; 15637502Sroot if (savecol > 8) 15647502Sroot savecol = 8; /* overflow screw */ 15657502Sroot while (--savecol >= 0) 15667502Sroot (void) ttyoutput('\b', tp); 15677502Sroot break; 156835811Smarc } 15697502Sroot 15707502Sroot default: 157137584Smarc /* XXX */ 157235811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 157349380Skarels c, CCLASS(c)); 157435811Smarc /*panic("ttyrub");*/ 15757502Sroot } 157635811Smarc } else if (tp->t_lflag&ECHOPRT) { 15779578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15787502Sroot (void) ttyoutput('\\', tp); 15799578Ssam tp->t_state |= TS_ERASE; 15807502Sroot } 15817502Sroot ttyecho(c, tp); 15827502Sroot } else 158335811Smarc ttyecho(tp->t_cc[VERASE], tp); 15847502Sroot tp->t_rocount--; 15857502Sroot } 15867502Sroot 15877502Sroot /* 15887502Sroot * Crt back over cnt chars perhaps 15897502Sroot * erasing them. 15907502Sroot */ 15917502Sroot ttyrubo(tp, cnt) 15927625Ssam register struct tty *tp; 15937625Ssam int cnt; 15947502Sroot { 15957502Sroot 15967502Sroot while (--cnt >= 0) 159740712Skarels ttyoutstr("\b \b", tp); 15987502Sroot } 15997502Sroot 16007502Sroot /* 16017502Sroot * Reprint the rawq line. 16027502Sroot * We assume c_cc has already been checked. 16037502Sroot */ 16047502Sroot ttyretype(tp) 16057625Ssam register struct tty *tp; 16067502Sroot { 16077502Sroot register char *cp; 16087502Sroot char *nextc(); 160935811Smarc int s, c; 16107502Sroot 161135811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 161235811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16137502Sroot (void) ttyoutput('\n', tp); 161417545Skarels s = spltty(); 161535811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 161635811Smarc BIT OF FIRST CHAR ****/ 161735811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 161835811Smarc ttyecho(c, tp); 161935811Smarc } 162035811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 162135811Smarc ttyecho(c, tp); 162235811Smarc } 16239578Ssam tp->t_state &= ~TS_ERASE; 16247502Sroot splx(s); 16257502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16267502Sroot tp->t_rocol = 0; 16277502Sroot } 16287502Sroot 16297502Sroot /* 163035811Smarc * Echo a typed character to the terminal. 16317502Sroot */ 16327502Sroot ttyecho(c, tp) 16337625Ssam register c; 16347625Ssam register struct tty *tp; 16357502Sroot { 16369578Ssam if ((tp->t_state&TS_CNTTB) == 0) 163735811Smarc tp->t_lflag &= ~FLUSHO; 163847545Skarels if (((tp->t_lflag&ECHO) == 0 && 163947545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16407502Sroot return; 164135811Smarc if (tp->t_lflag&ECHOCTL) { 164240712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 164340712Skarels c == 0177) { 16447502Sroot (void) ttyoutput('^', tp); 164535811Smarc c &= TTY_CHARMASK; 16467502Sroot if (c == 0177) 16477502Sroot c = '?'; 16487502Sroot else 16497502Sroot c += 'A' - 1; 16507502Sroot } 16517502Sroot } 165235811Smarc (void) ttyoutput(c, tp); 16537502Sroot } 16547502Sroot 16557502Sroot /* 16567502Sroot * send string cp to tp 16577502Sroot */ 165840712Skarels ttyoutstr(cp, tp) 16597625Ssam register char *cp; 16607625Ssam register struct tty *tp; 16617502Sroot { 16627502Sroot register char c; 16637502Sroot 16647502Sroot while (c = *cp++) 16657502Sroot (void) ttyoutput(c, tp); 16667502Sroot } 16677502Sroot 166849380Skarels /* 166949380Skarels * Wake up any readers on a tty. 167049380Skarels */ 16717502Sroot ttwakeup(tp) 167247545Skarels register struct tty *tp; 16737502Sroot { 16747502Sroot 167552522Smckusick selwakeup(&tp->t_rsel); 167612752Ssam if (tp->t_state & TS_ASYNC) 167742882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16787502Sroot wakeup((caddr_t)&tp->t_rawq); 16797502Sroot } 168035811Smarc 168135811Smarc /* 168248439Skarels * Look up a code for a specified speed in a conversion table; 168348439Skarels * used by drivers to map software speed values to hardware parameters. 168448439Skarels */ 168548439Skarels ttspeedtab(speed, table) 168652485Storek int speed; 168748439Skarels register struct speedtab *table; 168848439Skarels { 168948439Skarels 169048439Skarels for ( ; table->sp_speed != -1; table++) 169148439Skarels if (table->sp_speed == speed) 169248439Skarels return (table->sp_code); 169348439Skarels return (-1); 169448439Skarels } 169548439Skarels 169648439Skarels /* 169735811Smarc * set tty hi and low water marks 169835811Smarc * 169935811Smarc * Try to arrange the dynamics so there's about one second 170035811Smarc * from hi to low water. 170135811Smarc * 170235811Smarc */ 170335811Smarc ttsetwater(tp) 170435811Smarc struct tty *tp; 170535811Smarc { 170635811Smarc register cps = tp->t_ospeed / 10; 170735811Smarc register x; 170835811Smarc 170935811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 171035811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 171135811Smarc x += cps; 171235811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 171335811Smarc tp->t_hiwat = roundup(x, CBSIZE); 171435811Smarc #undef clamp 171535811Smarc } 171635811Smarc 171739407Smarc /* 171839407Smarc * Report on state of foreground process group. 171939407Smarc */ 172039407Smarc ttyinfo(tp) 172149907Sbostic register struct tty *tp; 172239407Smarc { 172349907Sbostic register struct proc *p, *pick; 172441177Smarc struct timeval utime, stime; 172549907Sbostic int tmp; 172639407Smarc 172739407Smarc if (ttycheckoutq(tp,0) == 0) 172839407Smarc return; 172949907Sbostic 173049907Sbostic /* Print load average. */ 1731*52666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 173249907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 173349907Sbostic 173439555Smarc if (tp->t_session == NULL) 173549907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 173641177Smarc else if (tp->t_pgrp == NULL) 173749907Sbostic ttyprintf(tp, "no foreground process group\n"); 173841177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 173949907Sbostic ttyprintf(tp, "empty foreground process group\n"); 174039407Smarc else { 174149907Sbostic /* Pick interesting process. */ 174249907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 174341177Smarc if (proc_compare(pick, p)) 174441177Smarc pick = p; 174549907Sbostic 174649907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 174749907Sbostic pick->p_stat == SRUN ? "running" : 174849907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 174949907Sbostic 175049907Sbostic /* 175149907Sbostic * Lock out clock if process is running; get user/system 175249907Sbostic * cpu time. 175341177Smarc */ 175447545Skarels if (curproc == pick) 175549907Sbostic tmp = splclock(); 175641177Smarc utime = pick->p_utime; 175741177Smarc stime = pick->p_stime; 175847545Skarels if (curproc == pick) 175949907Sbostic splx(tmp); 176039407Smarc 176149907Sbostic /* Print user time. */ 176249907Sbostic ttyprintf(tp, "%d.%02du ", 176349907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 176441177Smarc 176549907Sbostic /* Print system time. */ 176649907Sbostic ttyprintf(tp, "%d.%02ds ", 176749907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 176849907Sbostic 176949907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 177049907Sbostic /* Print percentage cpu, resident set size. */ 177149907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 177249907Sbostic ttyprintf(tp, "%d%% %dk\n", 177352485Storek tmp / 100, 177452485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 177552485Storek pgtok(pick->p_vmspace->vm_rssize)); 177641177Smarc } 177749907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 177841177Smarc } 177941177Smarc 178041177Smarc /* 178141177Smarc * Returns 1 if p2 is "better" than p1 178241177Smarc * 178341177Smarc * The algorithm for picking the "interesting" process is thus: 178441177Smarc * 178541177Smarc * 1) (Only foreground processes are eligable - implied) 178641177Smarc * 2) Runnable processes are favored over anything 178741177Smarc * else. The runner with the highest cpu 178841177Smarc * utilization is picked (p_cpu). Ties are 178941177Smarc * broken by picking the highest pid. 179041177Smarc * 3 Next, the sleeper with the shortest sleep 179141177Smarc * time is favored. With ties, we pick out 179241177Smarc * just "short-term" sleepers (SSINTR == 0). 179341177Smarc * Further ties are broken by picking the highest 179441177Smarc * pid. 179541177Smarc * 179641177Smarc */ 179741177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 179845723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 179945723Smckusick #define ONLYA 2 180045723Smckusick #define ONLYB 1 180145723Smckusick #define BOTH 3 180245723Smckusick 180349907Sbostic static int 180441177Smarc proc_compare(p1, p2) 180541177Smarc register struct proc *p1, *p2; 180641177Smarc { 180741177Smarc 180841177Smarc if (p1 == NULL) 180941177Smarc return (1); 181041177Smarc /* 181141177Smarc * see if at least one of them is runnable 181241177Smarc */ 181345723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 181445723Smckusick case ONLYA: 181545723Smckusick return (0); 181645723Smckusick case ONLYB: 181741177Smarc return (1); 181845723Smckusick case BOTH: 181941177Smarc /* 182041177Smarc * tie - favor one with highest recent cpu utilization 182141177Smarc */ 182241177Smarc if (p2->p_cpu > p1->p_cpu) 182341177Smarc return (1); 182441177Smarc if (p1->p_cpu > p2->p_cpu) 182541177Smarc return (0); 182641177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182741177Smarc } 182845723Smckusick /* 182945723Smckusick * weed out zombies 183045723Smckusick */ 183145723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 183245723Smckusick case ONLYA: 183345723Smckusick return (1); 183445723Smckusick case ONLYB: 183545723Smckusick return (0); 183645723Smckusick case BOTH: 183745723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183845723Smckusick } 183941177Smarc /* 184041177Smarc * pick the one with the smallest sleep time 184141177Smarc */ 184241177Smarc if (p2->p_slptime > p1->p_slptime) 184341177Smarc return (0); 184441177Smarc if (p1->p_slptime > p2->p_slptime) 184541177Smarc return (1); 184641177Smarc /* 184741177Smarc * favor one sleeping in a non-interruptible sleep 184841177Smarc */ 184941177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 185041177Smarc return (1); 185141177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 185241177Smarc return (0); 185347545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 185441177Smarc } 185545723Smckusick 185639555Smarc /* 185739555Smarc * Output char to tty; console putchar style. 185839555Smarc */ 185939555Smarc tputchar(c, tp) 186039555Smarc int c; 186139555Smarc struct tty *tp; 186239555Smarc { 186339555Smarc register s = spltty(); 186439555Smarc 186547545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 186639555Smarc if (c == '\n') 186739555Smarc (void) ttyoutput('\r', tp); 186839555Smarc (void) ttyoutput(c, tp); 186939555Smarc ttstart(tp); 187039555Smarc splx(s); 187139555Smarc return (0); 187239555Smarc } 187339555Smarc splx(s); 187439555Smarc return (-1); 187539555Smarc } 187643377Smarc 187744419Smarc /* 187849380Skarels * Sleep on chan, returning ERESTART if tty changed 187949380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 188049380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 188149380Skarels * call will redo validation done at the start of the call. 188244419Smarc */ 188343377Smarc ttysleep(tp, chan, pri, wmesg, timo) 188443377Smarc struct tty *tp; 188543377Smarc caddr_t chan; 188643377Smarc int pri; 188743377Smarc char *wmesg; 188843377Smarc int timo; 188943377Smarc { 189043377Smarc int error; 189143377Smarc short gen = tp->t_gen; 189243377Smarc 189343377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 189443377Smarc return (error); 189543377Smarc if (tp->t_gen != gen) 189643377Smarc return (ERESTART); 189743377Smarc return (0); 189843377Smarc } 1899