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*56013Smarc * @(#)tty.c 7.54 (Berkeley) 08/24/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 23554782Storek void 23654782Storek ttrstrt(tp0) 23754782Storek void *tp0; 23854782Storek { 23947545Skarels struct tty *tp; 24052485Storek int s; 24147545Skarels 24254782Storek tp = (struct tty *)tp0; 24340712Skarels #ifdef DIAGNOSTIC 2449578Ssam if (tp == 0) 2459578Ssam panic("ttrstrt"); 24640712Skarels #endif 24752485Storek s = spltty(); 2485408Swnj tp->t_state &= ~TS_TIMEOUT; 249903Sbill ttstart(tp); 25052485Storek splx(s); 251121Sbill } 252121Sbill 25339Sbill 25439Sbill /* 25549380Skarels * Common code for ioctls on tty devices. 25649380Skarels * Called after line-discipline-specific ioctl 25749380Skarels * has been called to do discipline-specific functions 25849380Skarels * and/or reject any of these ioctl commands. 25939Sbill */ 2601780Sbill /*ARGSUSED*/ 2617625Ssam ttioctl(tp, com, data, flag) 2627625Ssam register struct tty *tp; 26352485Storek int com; 2647625Ssam caddr_t data; 26552485Storek int flag; 26639Sbill { 26747545Skarels register struct proc *p = curproc; /* XXX */ 26839Sbill extern int nldisp; 26937554Smckusick int s, error; 27039Sbill 271903Sbill /* 272903Sbill * If the ioctl involves modification, 27317545Skarels * hang if in the background. 274903Sbill */ 2757625Ssam switch (com) { 27639Sbill 27735811Smarc case TIOCSETD: 278903Sbill case TIOCFLUSH: 27935811Smarc /*case TIOCSPGRP:*/ 2809325Ssam case TIOCSTI: 28117598Sbloom case TIOCSWINSZ: 28235811Smarc case TIOCSETA: 28335811Smarc case TIOCSETAW: 28435811Smarc case TIOCSETAF: 28552485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 28640030Smarc case TIOCSETP: 28740030Smarc case TIOCSETN: 28840030Smarc case TIOCSETC: 28940030Smarc case TIOCSLTC: 29040030Smarc case TIOCLBIS: 29140030Smarc case TIOCLBIC: 29240030Smarc case TIOCLSET: 29340030Smarc case OTIOCSETD: 29440030Smarc #endif 29547545Skarels while (isbackground(curproc, tp) && 29647545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 29747545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 29847545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 29947545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 30043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 30143377Smarc TTOPRI | PCATCH, ttybg, 0)) 30240712Skarels return (error); 303903Sbill } 304903Sbill break; 305903Sbill } 306903Sbill 3079578Ssam /* 3089578Ssam * Process the ioctl. 3099578Ssam */ 3107625Ssam switch (com) { 311903Sbill 3128556Sroot /* get discipline number */ 31339Sbill case TIOCGETD: 3147625Ssam *(int *)data = tp->t_line; 31539Sbill break; 31639Sbill 3178556Sroot /* set line discipline */ 3187625Ssam case TIOCSETD: { 3197625Ssam register int t = *(int *)data; 32035811Smarc dev_t dev = tp->t_dev; 3217625Ssam 32235811Smarc if ((unsigned)t >= nldisp) 32310851Ssam return (ENXIO); 32425584Skarels if (t != tp->t_line) { 32525584Skarels s = spltty(); 32649752Smarc (*linesw[tp->t_line].l_close)(tp, flag); 32725584Skarels error = (*linesw[t].l_open)(dev, tp); 32825584Skarels if (error) { 32935811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 33025584Skarels splx(s); 33125584Skarels return (error); 33225584Skarels } 33325584Skarels tp->t_line = t; 33410851Ssam splx(s); 33510851Ssam } 33639Sbill break; 3377625Ssam } 33839Sbill 3398556Sroot /* prevent more opens on channel */ 3405614Swnj case TIOCEXCL: 34152485Storek s = spltty(); 3425614Swnj tp->t_state |= TS_XCLUDE; 34352485Storek splx(s); 3445614Swnj break; 3455614Swnj 3465614Swnj case TIOCNXCL: 34752485Storek s = spltty(); 3485614Swnj tp->t_state &= ~TS_XCLUDE; 34952485Storek splx(s); 3505614Swnj break; 3515614Swnj 35252485Storek #ifdef TIOCHPCL 35339Sbill case TIOCHPCL: 35452485Storek s = spltty(); 35535811Smarc tp->t_cflag |= HUPCL; 35652485Storek splx(s); 35739Sbill break; 35852485Storek #endif 35939Sbill 3603942Sbugs case TIOCFLUSH: { 3617625Ssam register int flags = *(int *)data; 3627625Ssam 3637625Ssam if (flags == 0) 3643942Sbugs flags = FREAD|FWRITE; 3657625Ssam else 3667625Ssam flags &= FREAD|FWRITE; 36712752Ssam ttyflush(tp, flags); 36839Sbill break; 3693944Sbugs } 37039Sbill 37137584Smarc case FIOASYNC: 37252485Storek s = spltty(); 37337584Smarc if (*(int *)data) 37437584Smarc tp->t_state |= TS_ASYNC; 37537584Smarc else 37637584Smarc tp->t_state &= ~TS_ASYNC; 37752485Storek splx(s); 37837584Smarc break; 37937584Smarc 38037584Smarc case FIONBIO: 38137584Smarc break; /* XXX remove */ 38237584Smarc 3838556Sroot /* return number of characters immediately available */ 3847625Ssam case FIONREAD: 38554782Storek *(int *)data = ttnread(tp); 386174Sbill break; 387174Sbill 38813077Ssam case TIOCOUTQ: 38913077Ssam *(int *)data = tp->t_outq.c_cc; 39013077Ssam break; 39113077Ssam 3928589Sroot case TIOCSTOP: 39317545Skarels s = spltty(); 3949578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3955573Swnj tp->t_state |= TS_TTSTOP; 39652485Storek #ifdef sun4c /* XXX */ 39752485Storek (*tp->t_stop)(tp, 0); 39852485Storek #else 3995573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 40052485Storek #endif 4015573Swnj } 4027625Ssam splx(s); 4035573Swnj break; 4045573Swnj 4058589Sroot case TIOCSTART: 40617545Skarels s = spltty(); 40735811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 4085573Swnj tp->t_state &= ~TS_TTSTOP; 40935811Smarc tp->t_lflag &= ~FLUSHO; 4105573Swnj ttstart(tp); 4115573Swnj } 4127625Ssam splx(s); 4135573Swnj break; 4145573Swnj 4159325Ssam /* 4169325Ssam * Simulate typing of a character at the terminal. 4179325Ssam */ 4189325Ssam case TIOCSTI: 41947545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 42017183Smckusick return (EPERM); 42147545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 4229325Ssam return (EACCES); 4239578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4249325Ssam break; 4259325Ssam 42635811Smarc case TIOCGETA: { 42735811Smarc struct termios *t = (struct termios *)data; 42812752Ssam 42935811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 43035811Smarc break; 43135811Smarc } 43235811Smarc 43335811Smarc case TIOCSETA: 43435811Smarc case TIOCSETAW: 43537584Smarc case TIOCSETAF: { 43635811Smarc register struct termios *t = (struct termios *)data; 43740712Skarels 43817545Skarels s = spltty(); 43939407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 44040712Skarels if (error = ttywait(tp)) { 44140712Skarels splx(s); 44240712Skarels return (error); 44340712Skarels } 44445007Smarc if (com == TIOCSETAF) 44539407Smarc ttyflush(tp, FREAD); 44639407Smarc } 44740712Skarels if ((t->c_cflag&CIGNORE) == 0) { 44835811Smarc /* 44935811Smarc * set device hardware 45035811Smarc */ 45137584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 45237584Smarc splx(s); 45335811Smarc return (error); 45437584Smarc } else { 45540712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 45637584Smarc (tp->t_cflag&CLOCAL) && 45740712Skarels (t->c_cflag&CLOCAL) == 0) { 45837584Smarc tp->t_state &= ~TS_ISOPEN; 45937584Smarc tp->t_state |= TS_WOPEN; 46037584Smarc ttwakeup(tp); 46137584Smarc } 46235811Smarc tp->t_cflag = t->c_cflag; 46335811Smarc tp->t_ispeed = t->c_ispeed; 46435811Smarc tp->t_ospeed = t->c_ospeed; 46534492Skarels } 46635811Smarc ttsetwater(tp); 46712752Ssam } 46839407Smarc if (com != TIOCSETAF) { 46935811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 47035811Smarc if (t->c_lflag&ICANON) { 47135811Smarc tp->t_lflag |= PENDIN; 47235811Smarc ttwakeup(tp); 47335811Smarc } 47435811Smarc else { 47535811Smarc struct clist tq; 47635811Smarc 47735811Smarc catq(&tp->t_rawq, &tp->t_canq); 47835811Smarc tq = tp->t_rawq; 47935811Smarc tp->t_rawq = tp->t_canq; 48035811Smarc tp->t_canq = tq; 48135811Smarc } 48212752Ssam } 48335811Smarc tp->t_iflag = t->c_iflag; 48435811Smarc tp->t_oflag = t->c_oflag; 48542882Smarc /* 48642882Smarc * Make the EXTPROC bit read only. 48742882Smarc */ 48842882Smarc if (tp->t_lflag&EXTPROC) 48942882Smarc t->c_lflag |= EXTPROC; 49042882Smarc else 49142882Smarc t->c_lflag &= ~EXTPROC; 49235811Smarc tp->t_lflag = t->c_lflag; 49335811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 49412752Ssam splx(s); 49512752Ssam break; 49612752Ssam } 49712752Ssam 49812752Ssam /* 49939555Smarc * Set controlling terminal. 50039555Smarc * Session ctty vnode pointer set in vnode layer. 50134492Skarels */ 50247545Skarels case TIOCSCTTY: 50339555Smarc if (!SESS_LEADER(p) || 50439555Smarc (p->p_session->s_ttyvp || tp->t_session) && 50539555Smarc (tp->t_session != p->p_session)) 50639407Smarc return (EPERM); 50735811Smarc tp->t_session = p->p_session; 50839555Smarc tp->t_pgrp = p->p_pgrp; 50939555Smarc p->p_session->s_ttyp = tp; 51039555Smarc p->p_flag |= SCTTY; 51134492Skarels break; 51239555Smarc 51334492Skarels /* 51435811Smarc * Set terminal process group. 51517545Skarels */ 51618650Sbloom case TIOCSPGRP: { 51735811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 51817545Skarels 51939555Smarc if (!isctty(p, tp)) 52039555Smarc return (ENOTTY); 52140030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 52239555Smarc return (EPERM); 52339555Smarc tp->t_pgrp = pgrp; 52412752Ssam break; 52518650Sbloom } 52612752Ssam 52712752Ssam case TIOCGPGRP: 52847545Skarels if (!isctty(p, tp)) 52939555Smarc return (ENOTTY); 53045007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 53112752Ssam break; 53212752Ssam 53317598Sbloom case TIOCSWINSZ: 53418650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 53518650Sbloom sizeof (struct winsize))) { 53617598Sbloom tp->t_winsize = *(struct winsize *)data; 53742882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 53817598Sbloom } 53917598Sbloom break; 54017598Sbloom 54117598Sbloom case TIOCGWINSZ: 54217598Sbloom *(struct winsize *)data = tp->t_winsize; 54317598Sbloom break; 54417598Sbloom 54530534Skarels case TIOCCONS: 54630534Skarels if (*(int *)data) { 54742141Smckusick if (constty && constty != tp && 54842141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 54942141Smckusick (TS_CARR_ON|TS_ISOPEN)) 55030534Skarels return (EBUSY); 55130534Skarels #ifndef UCONSOLE 55247545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55337554Smckusick return (error); 55430534Skarels #endif 55530534Skarels constty = tp; 55630534Skarels } else if (tp == constty) 55733404Skarels constty = NULL; 55830534Skarels break; 55930534Skarels 56048439Skarels case TIOCDRAIN: 56148439Skarels if (error = ttywait(tp)) 56248439Skarels return (error); 56348439Skarels break; 56448439Skarels 56547545Skarels default: 56652485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 56747545Skarels return (ttcompat(tp, com, data, flag)); 56847545Skarels #else 56947545Skarels return (-1); 57035811Smarc #endif 57139Sbill } 5728556Sroot return (0); 57339Sbill } 5744484Swnj 5754484Swnj ttnread(tp) 5764484Swnj struct tty *tp; 5774484Swnj { 5784484Swnj int nread = 0; 5794484Swnj 58035811Smarc if (tp->t_lflag & PENDIN) 5814484Swnj ttypend(tp); 5824484Swnj nread = tp->t_canq.c_cc; 58335811Smarc if ((tp->t_lflag & ICANON) == 0) 5844484Swnj nread += tp->t_rawq.c_cc; 5854484Swnj return (nread); 5864484Swnj } 5874484Swnj 58852522Smckusick ttselect(dev, rw, p) 5894484Swnj dev_t dev; 5905408Swnj int rw; 59152522Smckusick struct proc *p; 5924484Swnj { 5934484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5944484Swnj int nread; 59517545Skarels int s = spltty(); 5964484Swnj 5975408Swnj switch (rw) { 5984484Swnj 5994484Swnj case FREAD: 6004484Swnj nread = ttnread(tp); 60137584Smarc if (nread > 0 || 60240712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 6035408Swnj goto win; 60452522Smckusick selrecord(p, &tp->t_rsel); 6055408Swnj break; 6064484Swnj 6075408Swnj case FWRITE: 60835811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 6095408Swnj goto win; 61052522Smckusick selrecord(p, &tp->t_wsel); 6115408Swnj break; 6124484Swnj } 6135408Swnj splx(s); 6145408Swnj return (0); 6155408Swnj win: 6165408Swnj splx(s); 6175408Swnj return (1); 6184484Swnj } 6197436Skre 6207502Sroot /* 62149380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6227502Sroot */ 6237502Sroot ttyopen(dev, tp) 6247625Ssam dev_t dev; 6257625Ssam register struct tty *tp; 6267502Sroot { 62752485Storek int s = spltty(); 6287502Sroot 6297502Sroot tp->t_dev = dev; 63035811Smarc 6317502Sroot tp->t_state &= ~TS_WOPEN; 63217545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 63317545Skarels tp->t_state |= TS_ISOPEN; 63417598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 63517545Skarels } 63652485Storek splx(s); 6378556Sroot return (0); 6387502Sroot } 6397502Sroot 6407502Sroot /* 64125391Skarels * "close" a line discipline 64225391Skarels */ 64349752Smarc ttylclose(tp, flag) 64449752Smarc struct tty *tp; 64549752Smarc int flag; 64625391Skarels { 64725391Skarels 64849752Smarc if (flag&IO_NDELAY) 64949752Smarc ttyflush(tp, FREAD|FWRITE); 65049752Smarc else 65149752Smarc ttywflush(tp); 65225391Skarels } 65325391Skarels 65425391Skarels /* 65549380Skarels * Handle close() on a tty line: flush and set to initial state, 65649380Skarels * bumping generation number so that pending read/write calls 65749380Skarels * can detect recycling of the tty. 6587502Sroot */ 6597502Sroot ttyclose(tp) 6607625Ssam register struct tty *tp; 6617502Sroot { 66230534Skarels if (constty == tp) 66330534Skarels constty = NULL; 66425391Skarels ttyflush(tp, FREAD|FWRITE); 66539555Smarc tp->t_session = NULL; 66639555Smarc tp->t_pgrp = NULL; 6677502Sroot tp->t_state = 0; 66843377Smarc tp->t_gen++; 66940712Skarels return (0); 6707502Sroot } 6717502Sroot 6727502Sroot /* 67325391Skarels * Handle modem control transition on a tty. 67425391Skarels * Flag indicates new state of carrier. 67525391Skarels * Returns 0 if the line should be turned off, otherwise 1. 67625391Skarels */ 67725391Skarels ttymodem(tp, flag) 67825391Skarels register struct tty *tp; 67952485Storek int flag; 68025391Skarels { 68125391Skarels 68256012Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_cflag&MDMBUF)) { 68325391Skarels /* 68425391Skarels * MDMBUF: do flow control according to carrier flag 68525391Skarels */ 68625391Skarels if (flag) { 68725391Skarels tp->t_state &= ~TS_TTSTOP; 68825391Skarels ttstart(tp); 68925391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 69025391Skarels tp->t_state |= TS_TTSTOP; 69152485Storek #ifdef sun4c /* XXX */ 69252485Storek (*tp->t_stop)(tp, 0); 69352485Storek #else 69425391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 69552485Storek #endif 69625391Skarels } 69725391Skarels } else if (flag == 0) { 69825391Skarels /* 69925391Skarels * Lost carrier. 70025391Skarels */ 70125391Skarels tp->t_state &= ~TS_CARR_ON; 70242193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 70342193Smarc if (tp->t_session && tp->t_session->s_leader) 70442193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70542193Smarc ttyflush(tp, FREAD|FWRITE); 70642193Smarc return (0); 70725391Skarels } 70825391Skarels } else { 70925391Skarels /* 71025391Skarels * Carrier now on. 71125391Skarels */ 71225391Skarels tp->t_state |= TS_CARR_ON; 71337584Smarc ttwakeup(tp); 71425391Skarels } 71525391Skarels return (1); 71625391Skarels } 71725391Skarels 71825391Skarels /* 71925404Skarels * Default modem control routine (for other line disciplines). 72025404Skarels * Return argument flag, to turn off device on carrier drop. 72125404Skarels */ 72225415Skarels nullmodem(tp, flag) 72325415Skarels register struct tty *tp; 72425404Skarels int flag; 72525404Skarels { 72625404Skarels 72725404Skarels if (flag) 72825404Skarels tp->t_state |= TS_CARR_ON; 72939407Smarc else { 73025404Skarels tp->t_state &= ~TS_CARR_ON; 73142193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 73242193Smarc if (tp->t_session && tp->t_session->s_leader) 73342193Smarc psignal(tp->t_session->s_leader, SIGHUP); 73442193Smarc return (0); 73542193Smarc } 73639407Smarc } 73742193Smarc return (1); 73825404Skarels } 73925404Skarels 74025404Skarels /* 7417502Sroot * reinput pending characters after state switch 74217545Skarels * call at spltty(). 7437502Sroot */ 7447502Sroot ttypend(tp) 7457625Ssam register struct tty *tp; 7467502Sroot { 7477502Sroot struct clist tq; 7487502Sroot register c; 7497502Sroot 75035811Smarc tp->t_lflag &= ~PENDIN; 7519578Ssam tp->t_state |= TS_TYPEN; 7527502Sroot tq = tp->t_rawq; 7537502Sroot tp->t_rawq.c_cc = 0; 7547502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7557502Sroot while ((c = getc(&tq)) >= 0) 7567502Sroot ttyinput(c, tp); 7579578Ssam tp->t_state &= ~TS_TYPEN; 7587502Sroot } 7597502Sroot 7607502Sroot /* 76149380Skarels * Process input of a single character received on a tty. 7627502Sroot */ 7637502Sroot ttyinput(c, tp) 7647625Ssam register c; 7657625Ssam register struct tty *tp; 7667502Sroot { 76735811Smarc register int iflag = tp->t_iflag; 76835811Smarc register int lflag = tp->t_lflag; 76935811Smarc register u_char *cc = tp->t_cc; 77035811Smarc int i, err; 7717502Sroot 7729578Ssam /* 7739578Ssam * If input is pending take it first. 7749578Ssam */ 77535811Smarc if (lflag&PENDIN) 7767502Sroot ttypend(tp); 77735811Smarc /* 77835811Smarc * Gather stats. 77935811Smarc */ 7807502Sroot tk_nin++; 78135811Smarc if (lflag&ICANON) { 78235811Smarc tk_cancc++; 78335811Smarc tp->t_cancc++; 78435811Smarc } else { 78535811Smarc tk_rawcc++; 78635811Smarc tp->t_rawcc++; 78735811Smarc } 7889578Ssam /* 78935811Smarc * Handle exceptional conditions (break, parity, framing). 7909578Ssam */ 79135811Smarc if (err = (c&TTY_ERRORMASK)) { 79235811Smarc c &= ~TTY_ERRORMASK; 79335811Smarc if (err&TTY_FE && !c) { /* break */ 79435811Smarc if (iflag&IGNBRK) 79535811Smarc goto endcase; 79635811Smarc else if (iflag&BRKINT && lflag&ISIG && 79735811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 79835811Smarc c = cc[VINTR]; 79947545Skarels else if (iflag&PARMRK) 80047545Skarels goto parmrk; 80135811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 80235811Smarc if (iflag&IGNPAR) 80335811Smarc goto endcase; 80435811Smarc else if (iflag&PARMRK) { 80535811Smarc parmrk: 80635811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 80735811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 80835811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 80935811Smarc goto endcase; 81035811Smarc } else 81135811Smarc c = 0; 8127502Sroot } 8139578Ssam } 8149578Ssam /* 81535811Smarc * In tandem mode, check high water mark. 8169578Ssam */ 81735811Smarc if (iflag&IXOFF) 81835811Smarc ttyblock(tp); 81935811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 82049380Skarels c &= ~0x80; 82144419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 82244419Smarc /* 82344419Smarc * Check for literal nexting very first 82444419Smarc */ 82544419Smarc if (tp->t_state&TS_LNCH) { 82644419Smarc c |= TTY_QUOTE; 82744419Smarc tp->t_state &= ~TS_LNCH; 82844419Smarc } 82944419Smarc /* 83044419Smarc * Scan for special characters. This code 83144419Smarc * is really just a big case statement with 83244419Smarc * non-constant cases. The bottom of the 83344419Smarc * case statement is labeled ``endcase'', so goto 83444419Smarc * it after a case match, or similar. 83544419Smarc */ 83644419Smarc 83744419Smarc /* 83844419Smarc * Control chars which aren't controlled 83944419Smarc * by ICANON, ISIG, or IXON. 84044419Smarc */ 84144419Smarc if (lflag&IEXTEN) { 84244419Smarc if (CCEQ(cc[VLNEXT], c)) { 84344419Smarc if (lflag&ECHO) { 84444419Smarc if (lflag&ECHOE) 84544419Smarc ttyoutstr("^\b", tp); 84644419Smarc else 84744419Smarc ttyecho(c, tp); 84844419Smarc } 84944419Smarc tp->t_state |= TS_LNCH; 85044419Smarc goto endcase; 85144419Smarc } 85244419Smarc if (CCEQ(cc[VDISCARD], c)) { 85344419Smarc if (lflag&FLUSHO) 85444419Smarc tp->t_lflag &= ~FLUSHO; 85544419Smarc else { 85644419Smarc ttyflush(tp, FWRITE); 85735811Smarc ttyecho(c, tp); 85844419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 85944419Smarc ttyretype(tp); 86044419Smarc tp->t_lflag |= FLUSHO; 86144419Smarc } 86244419Smarc goto startoutput; 86335811Smarc } 8649578Ssam } 86544419Smarc /* 86644419Smarc * Signals. 86744419Smarc */ 86844419Smarc if (lflag&ISIG) { 86944419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 87044419Smarc if ((lflag&NOFLSH) == 0) 87144419Smarc ttyflush(tp, FREAD|FWRITE); 8727502Sroot ttyecho(c, tp); 87344419Smarc pgsignal(tp->t_pgrp, 87444419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 87544419Smarc goto endcase; 8767502Sroot } 87744419Smarc if (CCEQ(cc[VSUSP], c)) { 87844419Smarc if ((lflag&NOFLSH) == 0) 87944419Smarc ttyflush(tp, FREAD); 88044419Smarc ttyecho(c, tp); 88144419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 88244419Smarc goto endcase; 88344419Smarc } 8849578Ssam } 88544419Smarc /* 88644419Smarc * Handle start/stop characters. 88744419Smarc */ 88844419Smarc if (iflag&IXON) { 88944419Smarc if (CCEQ(cc[VSTOP], c)) { 89044419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 89144419Smarc tp->t_state |= TS_TTSTOP; 89252485Storek #ifdef sun4c /* XXX */ 89352485Storek (*tp->t_stop)(tp, 0); 89452485Storek #else 89544419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 89644419Smarc 0); 89752485Storek #endif 89844419Smarc return; 89944419Smarc } 90044419Smarc if (!CCEQ(cc[VSTART], c)) 90144419Smarc return; 90244419Smarc /* 90344419Smarc * if VSTART == VSTOP then toggle 90444419Smarc */ 90544419Smarc goto endcase; 90635811Smarc } 90744419Smarc if (CCEQ(cc[VSTART], c)) 90844419Smarc goto restartoutput; 9099578Ssam } 91044419Smarc /* 91144419Smarc * IGNCR, ICRNL, & INLCR 91244419Smarc */ 91344419Smarc if (c == '\r') { 91444419Smarc if (iflag&IGNCR) 91544419Smarc goto endcase; 91644419Smarc else if (iflag&ICRNL) 91744419Smarc c = '\n'; 91844419Smarc } else if (c == '\n' && iflag&INLCR) 91944419Smarc c = '\r'; 9209578Ssam } 92147545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 92244419Smarc /* 92344419Smarc * From here on down canonical mode character 92444419Smarc * processing takes place. 92544419Smarc */ 92644419Smarc /* 92744419Smarc * erase (^H / ^?) 92844419Smarc */ 92944419Smarc if (CCEQ(cc[VERASE], c)) { 93044419Smarc if (tp->t_rawq.c_cc) 9319578Ssam ttyrub(unputc(&tp->t_rawq), tp); 93244419Smarc goto endcase; 9339578Ssam } 93444419Smarc /* 93544419Smarc * kill (^U) 93644419Smarc */ 93744419Smarc if (CCEQ(cc[VKILL], c)) { 93844419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 93944419Smarc (lflag&ECHOPRT) == 0) { 94044419Smarc while (tp->t_rawq.c_cc) 94144419Smarc ttyrub(unputc(&tp->t_rawq), tp); 94244419Smarc } else { 94344419Smarc ttyecho(c, tp); 94444419Smarc if (lflag&ECHOK || lflag&ECHOKE) 94544419Smarc ttyecho('\n', tp); 94652485Storek flushq(&tp->t_rawq); 94744419Smarc tp->t_rocount = 0; 94844419Smarc } 94944419Smarc tp->t_state &= ~TS_LOCAL; 95044419Smarc goto endcase; 95144419Smarc } 95244419Smarc /* 95344419Smarc * word erase (^W) 95444419Smarc */ 95544419Smarc if (CCEQ(cc[VWERASE], c)) { 95644419Smarc int ctype; 95747545Skarels int alt = lflag&ALTWERASE; 95835811Smarc 95944419Smarc /* 96044419Smarc * erase whitespace 96144419Smarc */ 96244419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 96344419Smarc ttyrub(c, tp); 96444419Smarc if (c == -1) 96544419Smarc goto endcase; 96644419Smarc /* 96747545Skarels * erase last char of word and remember the 96847545Skarels * next chars type (for ALTWERASE) 96944419Smarc */ 97035811Smarc ttyrub(c, tp); 97144419Smarc c = unputc(&tp->t_rawq); 97247545Skarels if (c == -1) 97344419Smarc goto endcase; 97451003Sbostic if (c == ' ' || c == '\t') { 97551003Sbostic putc(c, &tp->t_rawq); 97651003Sbostic goto endcase; 97751003Sbostic } 97849380Skarels ctype = ISALPHA(c); 97944419Smarc /* 98047545Skarels * erase rest of word 98144419Smarc */ 98244419Smarc do { 98344419Smarc ttyrub(c, tp); 98444419Smarc c = unputc(&tp->t_rawq); 98544419Smarc if (c == -1) 98644419Smarc goto endcase; 98747545Skarels } while (c != ' ' && c != '\t' && 98849380Skarels (alt == 0 || ISALPHA(c) == ctype)); 98944419Smarc (void) putc(c, &tp->t_rawq); 99034492Skarels goto endcase; 99144419Smarc } 99235811Smarc /* 99344419Smarc * reprint line (^R) 99435811Smarc */ 99544419Smarc if (CCEQ(cc[VREPRINT], c)) { 99644419Smarc ttyretype(tp); 99734492Skarels goto endcase; 99834492Skarels } 99935811Smarc /* 100044419Smarc * ^T - kernel info and generate SIGINFO 100135811Smarc */ 100244419Smarc if (CCEQ(cc[VSTATUS], c)) { 100351068Smarc if (lflag&ISIG) 100451068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 100544419Smarc if ((lflag&NOKERNINFO) == 0) 100644419Smarc ttyinfo(tp); 100744419Smarc goto endcase; 100844419Smarc } 10099578Ssam } 10109578Ssam /* 10119578Ssam * Check for input buffer overflow 10129578Ssam */ 101347545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 101435811Smarc if (iflag&IMAXBEL) { 101535811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 101635811Smarc (void) ttyoutput(CTRL('g'), tp); 101735811Smarc } else 101835811Smarc ttyflush(tp, FREAD | FWRITE); 10199578Ssam goto endcase; 102010391Ssam } 10219578Ssam /* 10229578Ssam * Put data char in q for user and 10239578Ssam * wakeup on seeing a line delimiter. 10249578Ssam */ 10259578Ssam if (putc(c, &tp->t_rawq) >= 0) { 102647545Skarels if ((lflag&ICANON) == 0) { 102747545Skarels ttwakeup(tp); 102847545Skarels ttyecho(c, tp); 102947545Skarels goto endcase; 103047545Skarels } 103135811Smarc if (ttbreakc(c)) { 10329578Ssam tp->t_rocount = 0; 10339578Ssam catq(&tp->t_rawq, &tp->t_canq); 10347502Sroot ttwakeup(tp); 10359578Ssam } else if (tp->t_rocount++ == 0) 10369578Ssam tp->t_rocol = tp->t_col; 10379578Ssam if (tp->t_state&TS_ERASE) { 103835811Smarc /* 103935811Smarc * end of prterase \.../ 104035811Smarc */ 10419578Ssam tp->t_state &= ~TS_ERASE; 10429578Ssam (void) ttyoutput('/', tp); 10439578Ssam } 10449578Ssam i = tp->t_col; 10457502Sroot ttyecho(c, tp); 104635811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 104735811Smarc /* 104835811Smarc * Place the cursor over the '^' of the ^D. 104935811Smarc */ 105055058Spendry i = min(2, tp->t_col - i); 10519578Ssam while (i > 0) { 10529578Ssam (void) ttyoutput('\b', tp); 10539578Ssam i--; 10549578Ssam } 10559578Ssam } 10567502Sroot } 10579578Ssam endcase: 10589578Ssam /* 105935811Smarc * IXANY means allow any character to restart output. 10609578Ssam */ 106140712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 106240712Skarels cc[VSTART] != cc[VSTOP]) 10637502Sroot return; 10649578Ssam restartoutput: 10657502Sroot tp->t_state &= ~TS_TTSTOP; 106635811Smarc tp->t_lflag &= ~FLUSHO; 10679578Ssam startoutput: 10687502Sroot ttstart(tp); 10697502Sroot } 10707502Sroot 10717502Sroot /* 107249380Skarels * Output a single character on a tty, doing output processing 107349380Skarels * as needed (expanding tabs, newline processing, etc.). 107449380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10757502Sroot * Must be recursive. 10767502Sroot */ 10777502Sroot ttyoutput(c, tp) 10787502Sroot register c; 10797502Sroot register struct tty *tp; 10807502Sroot { 108149380Skarels register int col; 108235811Smarc register long oflag = tp->t_oflag; 108335811Smarc 108440712Skarels if ((oflag&OPOST) == 0) { 108535811Smarc if (tp->t_lflag&FLUSHO) 10867502Sroot return (-1); 10877502Sroot if (putc(c, &tp->t_outq)) 10887625Ssam return (c); 10897502Sroot tk_nout++; 109035811Smarc tp->t_outcc++; 10917502Sroot return (-1); 10927502Sroot } 109335811Smarc c &= TTY_CHARMASK; 10947502Sroot /* 109549380Skarels * Do tab expansion if OXTABS is set. 109642882Smarc * Special case if we have external processing, we don't 109742882Smarc * do the tab expansion because we'll probably get it 109842882Smarc * wrong. If tab expansion needs to be done, let it 109942882Smarc * happen externally. 11007502Sroot */ 110147545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 11027502Sroot register int s; 11037502Sroot 11047502Sroot c = 8 - (tp->t_col&7); 110535811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 110617545Skarels s = spltty(); /* don't interrupt tabs */ 11077502Sroot c -= b_to_q(" ", c, &tp->t_outq); 11087502Sroot tk_nout += c; 110935811Smarc tp->t_outcc += c; 11107502Sroot splx(s); 11117502Sroot } 11127502Sroot tp->t_col += c; 11137502Sroot return (c ? -1 : '\t'); 11147502Sroot } 111535811Smarc if (c == CEOT && oflag&ONOEOT) 111647545Skarels return (-1); 11177502Sroot tk_nout++; 111835811Smarc tp->t_outcc++; 11197502Sroot /* 112049380Skarels * Newline translation: if ONLCR is set, 112149380Skarels * translate newline into "\r\n". 11227502Sroot */ 112335811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 11247502Sroot return (c); 112535811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 112635811Smarc return (c); 112747545Skarels 112849380Skarels col = tp->t_col; 112949380Skarels switch (CCLASS(c)) { 11307502Sroot 11317502Sroot case ORDINARY: 113249380Skarels col++; 11337502Sroot 11347502Sroot case CONTROL: 11357502Sroot break; 11367502Sroot 11377502Sroot case BACKSPACE: 113849380Skarels if (col > 0) 113949380Skarels col--; 11407502Sroot break; 11417502Sroot 11427502Sroot case NEWLINE: 114349380Skarels col = 0; 11447502Sroot break; 11457502Sroot 11467502Sroot case TAB: 114749380Skarels col = (col + 8) &~ 0x7; 11487502Sroot break; 11497502Sroot 11507502Sroot case RETURN: 115149380Skarels col = 0; 11527502Sroot } 115349380Skarels tp->t_col = col; 11547502Sroot return (-1); 11557502Sroot } 11567502Sroot 11577502Sroot /* 115849380Skarels * Process a read call on a tty device. 11597502Sroot */ 116037584Smarc ttread(tp, uio, flag) 11617625Ssam register struct tty *tp; 11627722Swnj struct uio *uio; 116352485Storek int flag; 11647502Sroot { 11657502Sroot register struct clist *qp; 116635811Smarc register int c; 116741383Smarc register long lflag; 116835811Smarc register u_char *cc = tp->t_cc; 116947545Skarels register struct proc *p = curproc; 11709859Ssam int s, first, error = 0; 11717502Sroot 11727502Sroot loop: 117341383Smarc lflag = tp->t_lflag; 117437584Smarc s = spltty(); 11759578Ssam /* 117637584Smarc * take pending input first 11779578Ssam */ 117835811Smarc if (lflag&PENDIN) 11797502Sroot ttypend(tp); 11809859Ssam splx(s); 118140712Skarels 11829578Ssam /* 11839578Ssam * Hang process if it's in the background. 11849578Ssam */ 118547545Skarels if (isbackground(p, tp)) { 118647545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 118747545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 118847545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11898520Sroot return (EIO); 119047545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 119143377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 119243377Smarc ttybg, 0)) 119340712Skarels return (error); 119423165Sbloom goto loop; 11957502Sroot } 119640712Skarels 11979578Ssam /* 119835811Smarc * If canonical, use the canonical queue, 119935811Smarc * else use the raw queue. 120037584Smarc * 120147545Skarels * (should get rid of clists...) 12029578Ssam */ 120335811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 120440712Skarels 12059578Ssam /* 120640712Skarels * If there is no input, sleep on rawq 120740712Skarels * awaiting hardware receipt and notification. 120840712Skarels * If we have data, we don't need to check for carrier. 12099578Ssam */ 121017545Skarels s = spltty(); 12119578Ssam if (qp->c_cc <= 0) { 121240712Skarels int carrier; 121340712Skarels 121440712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 121540712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 12169859Ssam splx(s); 121740712Skarels return (0); /* EOF */ 12187502Sroot } 121937728Smckusick if (flag & IO_NDELAY) { 122037584Smarc splx(s); 122137584Smarc return (EWOULDBLOCK); 122237584Smarc } 122343377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 122440712Skarels carrier ? ttyin : ttopen, 0); 12259859Ssam splx(s); 122643377Smarc if (error) 122740712Skarels return (error); 12289578Ssam goto loop; 12299578Ssam } 12309859Ssam splx(s); 123140712Skarels 12329578Ssam /* 123335811Smarc * Input present, check for input mapping and processing. 12349578Ssam */ 12359578Ssam first = 1; 12369578Ssam while ((c = getc(qp)) >= 0) { 12379578Ssam /* 123835811Smarc * delayed suspend (^Y) 12399578Ssam */ 124035811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 124142882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12429578Ssam if (first) { 124343377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 124443377Smarc TTIPRI | PCATCH, ttybg, 0)) 124540712Skarels break; 12469578Ssam goto loop; 12479578Ssam } 12489578Ssam break; 12497502Sroot } 12509578Ssam /* 125135811Smarc * Interpret EOF only in canonical mode. 12529578Ssam */ 125335811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12549578Ssam break; 12559578Ssam /* 12569578Ssam * Give user character. 12579578Ssam */ 125840712Skarels error = ureadc(c, uio); 12599578Ssam if (error) 12609578Ssam break; 126114938Smckusick if (uio->uio_resid == 0) 12629578Ssam break; 12639578Ssam /* 126435811Smarc * In canonical mode check for a "break character" 12659578Ssam * marking the end of a "line of input". 12669578Ssam */ 126740712Skarels if (lflag&ICANON && ttbreakc(c)) 12689578Ssam break; 12699578Ssam first = 0; 12707502Sroot } 12719578Ssam /* 12729578Ssam * Look to unblock output now that (presumably) 12739578Ssam * the input queue has gone down. 12749578Ssam */ 127552485Storek s = spltty(); 127635811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 127747545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 127847545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12797502Sroot tp->t_state &= ~TS_TBLOCK; 12807502Sroot ttstart(tp); 12817502Sroot } 128235811Smarc } 128352485Storek splx(s); 12848520Sroot return (error); 12857502Sroot } 12867502Sroot 12877502Sroot /* 128825391Skarels * Check the output queue on tp for space for a kernel message 128925391Skarels * (from uprintf/tprintf). Allow some space over the normal 129025391Skarels * hiwater mark so we don't lose messages due to normal flow 129125391Skarels * control, but don't let the tty run amok. 129230695Skarels * Sleeps here are not interruptible, but we return prematurely 129330695Skarels * if new signals come in. 129425391Skarels */ 129525391Skarels ttycheckoutq(tp, wait) 129625391Skarels register struct tty *tp; 129725391Skarels int wait; 129825391Skarels { 129930695Skarels int hiwat, s, oldsig; 130025391Skarels 130135811Smarc hiwat = tp->t_hiwat; 130225391Skarels s = spltty(); 130352485Storek oldsig = wait ? curproc->p_sig : 0; 130425391Skarels if (tp->t_outq.c_cc > hiwat + 200) 130529946Skarels while (tp->t_outq.c_cc > hiwat) { 130629946Skarels ttstart(tp); 130747545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 130829946Skarels splx(s); 130929946Skarels return (0); 131029946Skarels } 131154782Storek timeout((void (*)__P((void *)))wakeup, 131254782Storek (void *)&tp->t_outq, hz); 131329946Skarels tp->t_state |= TS_ASLEEP; 131430695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 131525391Skarels } 131625391Skarels splx(s); 131725391Skarels return (1); 131825391Skarels } 131925391Skarels 132025391Skarels /* 132149380Skarels * Process a write call on a tty device. 13227502Sroot */ 132337584Smarc ttwrite(tp, uio, flag) 13247625Ssam register struct tty *tp; 13259578Ssam register struct uio *uio; 132652485Storek int flag; 13277502Sroot { 13287502Sroot register char *cp; 132940712Skarels register int cc = 0, ce; 133047545Skarels register struct proc *p = curproc; 13319578Ssam int i, hiwat, cnt, error, s; 13327502Sroot char obuf[OBUFSIZ]; 13337502Sroot 133435811Smarc hiwat = tp->t_hiwat; 13359578Ssam cnt = uio->uio_resid; 13369578Ssam error = 0; 13377502Sroot loop: 133837584Smarc s = spltty(); 133940712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 134037584Smarc if (tp->t_state&TS_ISOPEN) { 134137584Smarc splx(s); 134237584Smarc return (EIO); 134337728Smckusick } else if (flag & IO_NDELAY) { 134437584Smarc splx(s); 134540712Skarels error = EWOULDBLOCK; 134640712Skarels goto out; 134737584Smarc } else { 134837584Smarc /* 134937584Smarc * sleep awaiting carrier 135037584Smarc */ 135143377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 135243377Smarc TTIPRI | PCATCH,ttopen, 0); 135337584Smarc splx(s); 135443377Smarc if (error) 135540712Skarels goto out; 135637584Smarc goto loop; 135737584Smarc } 135837584Smarc } 135937584Smarc splx(s); 13609578Ssam /* 13619578Ssam * Hang the process if it's in the background. 13629578Ssam */ 136347545Skarels if (isbackground(p, tp) && 136447545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 136547545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 136647545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 136747545Skarels p->p_pgrp->pg_jobc) { 136847545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 136943377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 137043377Smarc ttybg, 0)) 137140712Skarels goto out; 137221776Sbloom goto loop; 13737502Sroot } 13749578Ssam /* 13759578Ssam * Process the user's data in at most OBUFSIZ 137640712Skarels * chunks. Perform any output translation. 137740712Skarels * Keep track of high water mark, sleep on overflow 137840712Skarels * awaiting device aid in acquiring new space. 13799578Ssam */ 138040712Skarels while (uio->uio_resid > 0 || cc > 0) { 138140712Skarels if (tp->t_lflag&FLUSHO) { 138240712Skarels uio->uio_resid = 0; 138340712Skarels return (0); 138440712Skarels } 138540712Skarels if (tp->t_outq.c_cc > hiwat) 138632067Skarels goto ovhiwat; 13879578Ssam /* 138840712Skarels * Grab a hunk of data from the user, 138940712Skarels * unless we have some leftover from last time. 13909578Ssam */ 13917822Sroot if (cc == 0) { 139240712Skarels cc = min(uio->uio_resid, OBUFSIZ); 139340712Skarels cp = obuf; 139440712Skarels error = uiomove(cp, cc, uio); 139540712Skarels if (error) { 139640712Skarels cc = 0; 139740712Skarels break; 139840712Skarels } 13997822Sroot } 14009578Ssam /* 14019578Ssam * If nothing fancy need be done, grab those characters we 14029578Ssam * can handle without any of ttyoutput's processing and 14039578Ssam * just transfer them to the output q. For those chars 14049578Ssam * which require special processing (as indicated by the 14059578Ssam * bits in partab), call ttyoutput. After processing 14069578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14079578Ssam * immediately. 14089578Ssam */ 14099578Ssam while (cc > 0) { 141040712Skarels if ((tp->t_oflag&OPOST) == 0) 14117502Sroot ce = cc; 14127502Sroot else { 141334492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 141449380Skarels (u_char *)partab, CCLASSMASK); 14159578Ssam /* 14169578Ssam * If ce is zero, then we're processing 14179578Ssam * a special character through ttyoutput. 14189578Ssam */ 14199578Ssam if (ce == 0) { 14207502Sroot tp->t_rocount = 0; 14217502Sroot if (ttyoutput(*cp, tp) >= 0) { 142221776Sbloom /* no c-lists, wait a bit */ 142321776Sbloom ttstart(tp); 142443377Smarc if (error = ttysleep(tp, 142543377Smarc (caddr_t)&lbolt, 142643377Smarc TTOPRI | PCATCH, ttybuf, 0)) 142740712Skarels break; 142821776Sbloom goto loop; 14297502Sroot } 14309578Ssam cp++, cc--; 143135811Smarc if ((tp->t_lflag&FLUSHO) || 14329578Ssam tp->t_outq.c_cc > hiwat) 14337502Sroot goto ovhiwat; 14349578Ssam continue; 14357502Sroot } 14367502Sroot } 14379578Ssam /* 14389578Ssam * A bunch of normal characters have been found, 14399578Ssam * transfer them en masse to the output queue and 14409578Ssam * continue processing at the top of the loop. 14419578Ssam * If there are any further characters in this 14429578Ssam * <= OBUFSIZ chunk, the first should be a character 14439578Ssam * requiring special handling by ttyoutput. 14449578Ssam */ 14457502Sroot tp->t_rocount = 0; 14469578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14479578Ssam ce -= i; 14489578Ssam tp->t_col += ce; 14499578Ssam cp += ce, cc -= ce, tk_nout += ce; 145035811Smarc tp->t_outcc += ce; 14519578Ssam if (i > 0) { 14529578Ssam /* out of c-lists, wait a bit */ 14537502Sroot ttstart(tp); 145443377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 145543377Smarc TTOPRI | PCATCH, ttybuf, 0)) 145640712Skarels break; 145721776Sbloom goto loop; 14587502Sroot } 145935811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 146040712Skarels break; 14617502Sroot } 146235811Smarc ttstart(tp); 14637502Sroot } 146440712Skarels out: 146540712Skarels /* 146640712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 146740712Skarels * as the offset and iov pointers have moved forward, 146840712Skarels * but it doesn't matter (the call will either return short 146940712Skarels * or restart with a new uio). 147040712Skarels */ 147140712Skarels uio->uio_resid += cc; 14728520Sroot return (error); 147340712Skarels 14747502Sroot ovhiwat: 147532067Skarels ttstart(tp); 147632067Skarels s = spltty(); 14779578Ssam /* 147835811Smarc * This can only occur if FLUSHO is set in t_lflag, 147932067Skarels * or if ttstart/oproc is synchronous (or very fast). 14809578Ssam */ 14817502Sroot if (tp->t_outq.c_cc <= hiwat) { 14829578Ssam splx(s); 14837502Sroot goto loop; 14847502Sroot } 148537728Smckusick if (flag & IO_NDELAY) { 148617545Skarels splx(s); 148740712Skarels uio->uio_resid += cc; 14887822Sroot if (uio->uio_resid == cnt) 14898520Sroot return (EWOULDBLOCK); 14908520Sroot return (0); 14917502Sroot } 14927502Sroot tp->t_state |= TS_ASLEEP; 149343377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14949578Ssam splx(s); 149543377Smarc if (error) 149640712Skarels goto out; 14977502Sroot goto loop; 14987502Sroot } 14997502Sroot 15007502Sroot /* 15017502Sroot * Rubout one character from the rawq of tp 15027502Sroot * as cleanly as possible. 15037502Sroot */ 15047502Sroot ttyrub(c, tp) 15057625Ssam register c; 15067625Ssam register struct tty *tp; 15077502Sroot { 15087502Sroot register char *cp; 15097502Sroot register int savecol; 15107502Sroot int s; 15117502Sroot char *nextc(); 15127502Sroot 151342882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 15147502Sroot return; 151535811Smarc tp->t_lflag &= ~FLUSHO; 151635811Smarc if (tp->t_lflag&ECHOE) { 15177502Sroot if (tp->t_rocount == 0) { 15187502Sroot /* 15197502Sroot * Screwed by ttwrite; retype 15207502Sroot */ 15217502Sroot ttyretype(tp); 15227502Sroot return; 15237502Sroot } 152435811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15257502Sroot ttyrubo(tp, 2); 152649380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 15277502Sroot 15287502Sroot case ORDINARY: 152935811Smarc ttyrubo(tp, 1); 15307502Sroot break; 15317502Sroot 15327502Sroot case VTAB: 15337502Sroot case BACKSPACE: 15347502Sroot case CONTROL: 15357502Sroot case RETURN: 153647545Skarels case NEWLINE: 153735811Smarc if (tp->t_lflag&ECHOCTL) 15387502Sroot ttyrubo(tp, 2); 15397502Sroot break; 15407502Sroot 154135811Smarc case TAB: { 154235811Smarc int c; 154335811Smarc 15447502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15457502Sroot ttyretype(tp); 15467502Sroot return; 15477502Sroot } 154817545Skarels s = spltty(); 15497502Sroot savecol = tp->t_col; 15509578Ssam tp->t_state |= TS_CNTTB; 155135811Smarc tp->t_lflag |= FLUSHO; 15527502Sroot tp->t_col = tp->t_rocol; 15539578Ssam cp = tp->t_rawq.c_cf; 155439407Smarc if (cp) 155539407Smarc c = *cp; /* XXX FIX NEXTC */ 155635811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 155735811Smarc ttyecho(c, tp); 155835811Smarc tp->t_lflag &= ~FLUSHO; 15599578Ssam tp->t_state &= ~TS_CNTTB; 15607502Sroot splx(s); 15617502Sroot /* 15627502Sroot * savecol will now be length of the tab 15637502Sroot */ 15647502Sroot savecol -= tp->t_col; 15657502Sroot tp->t_col += savecol; 15667502Sroot if (savecol > 8) 15677502Sroot savecol = 8; /* overflow screw */ 15687502Sroot while (--savecol >= 0) 15697502Sroot (void) ttyoutput('\b', tp); 15707502Sroot break; 157135811Smarc } 15727502Sroot 15737502Sroot default: 157437584Smarc /* XXX */ 157535811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 157649380Skarels c, CCLASS(c)); 157735811Smarc /*panic("ttyrub");*/ 15787502Sroot } 157935811Smarc } else if (tp->t_lflag&ECHOPRT) { 15809578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15817502Sroot (void) ttyoutput('\\', tp); 15829578Ssam tp->t_state |= TS_ERASE; 15837502Sroot } 15847502Sroot ttyecho(c, tp); 15857502Sroot } else 158635811Smarc ttyecho(tp->t_cc[VERASE], tp); 15877502Sroot tp->t_rocount--; 15887502Sroot } 15897502Sroot 15907502Sroot /* 15917502Sroot * Crt back over cnt chars perhaps 15927502Sroot * erasing them. 15937502Sroot */ 15947502Sroot ttyrubo(tp, cnt) 15957625Ssam register struct tty *tp; 15967625Ssam int cnt; 15977502Sroot { 15987502Sroot 15997502Sroot while (--cnt >= 0) 160040712Skarels ttyoutstr("\b \b", tp); 16017502Sroot } 16027502Sroot 16037502Sroot /* 16047502Sroot * Reprint the rawq line. 16057502Sroot * We assume c_cc has already been checked. 16067502Sroot */ 16077502Sroot ttyretype(tp) 16087625Ssam register struct tty *tp; 16097502Sroot { 16107502Sroot register char *cp; 16117502Sroot char *nextc(); 161235811Smarc int s, c; 16137502Sroot 161435811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 161535811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16167502Sroot (void) ttyoutput('\n', tp); 161717545Skarels s = spltty(); 161835811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 161935811Smarc BIT OF FIRST CHAR ****/ 162035811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 162135811Smarc ttyecho(c, tp); 162235811Smarc } 162335811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 162435811Smarc ttyecho(c, tp); 162535811Smarc } 16269578Ssam tp->t_state &= ~TS_ERASE; 16277502Sroot splx(s); 16287502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16297502Sroot tp->t_rocol = 0; 16307502Sroot } 16317502Sroot 16327502Sroot /* 163335811Smarc * Echo a typed character to the terminal. 16347502Sroot */ 16357502Sroot ttyecho(c, tp) 16367625Ssam register c; 16377625Ssam register struct tty *tp; 16387502Sroot { 16399578Ssam if ((tp->t_state&TS_CNTTB) == 0) 164035811Smarc tp->t_lflag &= ~FLUSHO; 164147545Skarels if (((tp->t_lflag&ECHO) == 0 && 164247545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16437502Sroot return; 164435811Smarc if (tp->t_lflag&ECHOCTL) { 164540712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 1646*56013Smarc (c&TTY_CHARMASK) == 0177) { 16477502Sroot (void) ttyoutput('^', tp); 164835811Smarc c &= TTY_CHARMASK; 16497502Sroot if (c == 0177) 16507502Sroot c = '?'; 16517502Sroot else 16527502Sroot c += 'A' - 1; 16537502Sroot } 16547502Sroot } 165535811Smarc (void) ttyoutput(c, tp); 16567502Sroot } 16577502Sroot 16587502Sroot /* 16597502Sroot * send string cp to tp 16607502Sroot */ 166140712Skarels ttyoutstr(cp, tp) 16627625Ssam register char *cp; 16637625Ssam register struct tty *tp; 16647502Sroot { 16657502Sroot register char c; 16667502Sroot 16677502Sroot while (c = *cp++) 16687502Sroot (void) ttyoutput(c, tp); 16697502Sroot } 16707502Sroot 167149380Skarels /* 167249380Skarels * Wake up any readers on a tty. 167349380Skarels */ 16747502Sroot ttwakeup(tp) 167547545Skarels register struct tty *tp; 16767502Sroot { 16777502Sroot 167852522Smckusick selwakeup(&tp->t_rsel); 167912752Ssam if (tp->t_state & TS_ASYNC) 168042882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16817502Sroot wakeup((caddr_t)&tp->t_rawq); 16827502Sroot } 168335811Smarc 168435811Smarc /* 168548439Skarels * Look up a code for a specified speed in a conversion table; 168648439Skarels * used by drivers to map software speed values to hardware parameters. 168748439Skarels */ 168848439Skarels ttspeedtab(speed, table) 168952485Storek int speed; 169048439Skarels register struct speedtab *table; 169148439Skarels { 169248439Skarels 169348439Skarels for ( ; table->sp_speed != -1; table++) 169448439Skarels if (table->sp_speed == speed) 169548439Skarels return (table->sp_code); 169648439Skarels return (-1); 169748439Skarels } 169848439Skarels 169948439Skarels /* 170035811Smarc * set tty hi and low water marks 170135811Smarc * 170235811Smarc * Try to arrange the dynamics so there's about one second 170335811Smarc * from hi to low water. 170435811Smarc * 170535811Smarc */ 170635811Smarc ttsetwater(tp) 170735811Smarc struct tty *tp; 170835811Smarc { 170935811Smarc register cps = tp->t_ospeed / 10; 171035811Smarc register x; 171135811Smarc 171235811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 171335811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 171435811Smarc x += cps; 171535811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 171635811Smarc tp->t_hiwat = roundup(x, CBSIZE); 171735811Smarc #undef clamp 171835811Smarc } 171935811Smarc 172039407Smarc /* 172139407Smarc * Report on state of foreground process group. 172239407Smarc */ 172339407Smarc ttyinfo(tp) 172449907Sbostic register struct tty *tp; 172539407Smarc { 172649907Sbostic register struct proc *p, *pick; 172741177Smarc struct timeval utime, stime; 172849907Sbostic int tmp; 172939407Smarc 173039407Smarc if (ttycheckoutq(tp,0) == 0) 173139407Smarc return; 173249907Sbostic 173349907Sbostic /* Print load average. */ 173452666Smckusick tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; 173549907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 173649907Sbostic 173739555Smarc if (tp->t_session == NULL) 173849907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 173941177Smarc else if (tp->t_pgrp == NULL) 174049907Sbostic ttyprintf(tp, "no foreground process group\n"); 174141177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 174249907Sbostic ttyprintf(tp, "empty foreground process group\n"); 174339407Smarc else { 174449907Sbostic /* Pick interesting process. */ 174549907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 174641177Smarc if (proc_compare(pick, p)) 174741177Smarc pick = p; 174849907Sbostic 174949907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 175049907Sbostic pick->p_stat == SRUN ? "running" : 175149907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 175249907Sbostic 175354782Storek calcru(pick, &utime, &stime, NULL); 175439407Smarc 175549907Sbostic /* Print user time. */ 175649907Sbostic ttyprintf(tp, "%d.%02du ", 175749907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 175841177Smarc 175949907Sbostic /* Print system time. */ 176049907Sbostic ttyprintf(tp, "%d.%02ds ", 176149907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 176249907Sbostic 176349907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 176449907Sbostic /* Print percentage cpu, resident set size. */ 176549907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 176649907Sbostic ttyprintf(tp, "%d%% %dk\n", 176752485Storek tmp / 100, 176852485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 176952485Storek pgtok(pick->p_vmspace->vm_rssize)); 177041177Smarc } 177149907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 177241177Smarc } 177341177Smarc 177441177Smarc /* 177541177Smarc * Returns 1 if p2 is "better" than p1 177641177Smarc * 177741177Smarc * The algorithm for picking the "interesting" process is thus: 177841177Smarc * 177941177Smarc * 1) (Only foreground processes are eligable - implied) 178041177Smarc * 2) Runnable processes are favored over anything 178141177Smarc * else. The runner with the highest cpu 178241177Smarc * utilization is picked (p_cpu). Ties are 178341177Smarc * broken by picking the highest pid. 178441177Smarc * 3 Next, the sleeper with the shortest sleep 178541177Smarc * time is favored. With ties, we pick out 178641177Smarc * just "short-term" sleepers (SSINTR == 0). 178741177Smarc * Further ties are broken by picking the highest 178841177Smarc * pid. 178941177Smarc * 179041177Smarc */ 179141177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 179245723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 179345723Smckusick #define ONLYA 2 179445723Smckusick #define ONLYB 1 179545723Smckusick #define BOTH 3 179645723Smckusick 179749907Sbostic static int 179841177Smarc proc_compare(p1, p2) 179941177Smarc register struct proc *p1, *p2; 180041177Smarc { 180141177Smarc 180241177Smarc if (p1 == NULL) 180341177Smarc return (1); 180441177Smarc /* 180541177Smarc * see if at least one of them is runnable 180641177Smarc */ 180745723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 180845723Smckusick case ONLYA: 180945723Smckusick return (0); 181045723Smckusick case ONLYB: 181141177Smarc return (1); 181245723Smckusick case BOTH: 181341177Smarc /* 181441177Smarc * tie - favor one with highest recent cpu utilization 181541177Smarc */ 181641177Smarc if (p2->p_cpu > p1->p_cpu) 181741177Smarc return (1); 181841177Smarc if (p1->p_cpu > p2->p_cpu) 181941177Smarc return (0); 182041177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182141177Smarc } 182245723Smckusick /* 182345723Smckusick * weed out zombies 182445723Smckusick */ 182545723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 182645723Smckusick case ONLYA: 182745723Smckusick return (1); 182845723Smckusick case ONLYB: 182945723Smckusick return (0); 183045723Smckusick case BOTH: 183145723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183245723Smckusick } 183341177Smarc /* 183441177Smarc * pick the one with the smallest sleep time 183541177Smarc */ 183641177Smarc if (p2->p_slptime > p1->p_slptime) 183741177Smarc return (0); 183841177Smarc if (p1->p_slptime > p2->p_slptime) 183941177Smarc return (1); 184041177Smarc /* 184141177Smarc * favor one sleeping in a non-interruptible sleep 184241177Smarc */ 184341177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 184441177Smarc return (1); 184541177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 184641177Smarc return (0); 184747545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 184841177Smarc } 184945723Smckusick 185039555Smarc /* 185139555Smarc * Output char to tty; console putchar style. 185239555Smarc */ 185339555Smarc tputchar(c, tp) 185439555Smarc int c; 185539555Smarc struct tty *tp; 185639555Smarc { 185739555Smarc register s = spltty(); 185839555Smarc 185947545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 186039555Smarc if (c == '\n') 186139555Smarc (void) ttyoutput('\r', tp); 186239555Smarc (void) ttyoutput(c, tp); 186339555Smarc ttstart(tp); 186439555Smarc splx(s); 186539555Smarc return (0); 186639555Smarc } 186739555Smarc splx(s); 186839555Smarc return (-1); 186939555Smarc } 187043377Smarc 187144419Smarc /* 187249380Skarels * Sleep on chan, returning ERESTART if tty changed 187349380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 187449380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 187549380Skarels * call will redo validation done at the start of the call. 187644419Smarc */ 187743377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187843377Smarc struct tty *tp; 187943377Smarc caddr_t chan; 188043377Smarc int pri; 188143377Smarc char *wmesg; 188243377Smarc int timo; 188343377Smarc { 188443377Smarc int error; 188543377Smarc short gen = tp->t_gen; 188643377Smarc 188743377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188843377Smarc return (error); 188943377Smarc if (tp->t_gen != gen) 189043377Smarc return (ERESTART); 189143377Smarc return (0); 189243377Smarc } 1893