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*51068Smarc * @(#)tty.c 7.47 (Berkeley) 09/09/91 923387Smckusick */ 1039Sbill 1117095Sbloom #include "param.h" 1217095Sbloom #include "systm.h" 1317095Sbloom #include "ioctl.h" 1439407Smarc #define TTYDEFCHARS 1517095Sbloom #include "tty.h" 1635811Smarc #undef TTYDEFCHARS 1717095Sbloom #include "proc.h" 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 16249380Skarels #define flushq(qq) { \ 16349380Skarels register struct clist *q = qq; \ 16449380Skarels if (q->c_cc) \ 16549380Skarels ndflush(q, q->c_cc); \ 16649380Skarels } 16749380Skarels 16839Sbill /* 16949380Skarels * Flush TTY read and/or write queues, 17049380Skarels * notifying anyone waiting. 17139Sbill */ 17212752Ssam ttyflush(tp, rw) 1737625Ssam register struct tty *tp; 17439Sbill { 175903Sbill register 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; 1885426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 18949380Skarels flushq(&tp->t_outq); 19049380Skarels wakeup((caddr_t)&tp->t_outq); 19149380Skarels if (tp->t_wsel) { 19249380Skarels selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 19349380Skarels tp->t_wsel = 0; 19449380Skarels tp->t_state &= ~TS_WCOLL; 19549380Skarels } 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 { 23847545Skarels 23940712Skarels #ifdef DIAGNOSTIC 2409578Ssam if (tp == 0) 2419578Ssam panic("ttrstrt"); 24240712Skarels #endif 2435408Swnj tp->t_state &= ~TS_TIMEOUT; 244903Sbill ttstart(tp); 245121Sbill } 246121Sbill 24739Sbill 24839Sbill /* 24949380Skarels * Common code for ioctls on tty devices. 25049380Skarels * Called after line-discipline-specific ioctl 25149380Skarels * has been called to do discipline-specific functions 25249380Skarels * and/or reject any of these ioctl commands. 25339Sbill */ 2541780Sbill /*ARGSUSED*/ 2557625Ssam ttioctl(tp, com, data, flag) 2567625Ssam register struct tty *tp; 2577625Ssam caddr_t data; 25839Sbill { 25947545Skarels register struct proc *p = curproc; /* XXX */ 26039Sbill extern int nldisp; 26137554Smckusick int s, error; 26239Sbill 263903Sbill /* 264903Sbill * If the ioctl involves modification, 26517545Skarels * hang if in the background. 266903Sbill */ 2677625Ssam switch (com) { 26839Sbill 26935811Smarc case TIOCSETD: 270903Sbill case TIOCFLUSH: 27135811Smarc /*case TIOCSPGRP:*/ 2729325Ssam case TIOCSTI: 27317598Sbloom case TIOCSWINSZ: 27435811Smarc case TIOCSETA: 27535811Smarc case TIOCSETAW: 27635811Smarc case TIOCSETAF: 27740030Smarc #ifdef COMPAT_43 27840030Smarc case TIOCSETP: 27940030Smarc case TIOCSETN: 28040030Smarc case TIOCSETC: 28140030Smarc case TIOCSLTC: 28240030Smarc case TIOCLBIS: 28340030Smarc case TIOCLBIC: 28440030Smarc case TIOCLSET: 28540030Smarc case OTIOCSETD: 28640030Smarc #endif 28747545Skarels while (isbackground(curproc, tp) && 28847545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 28947545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 29047545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 29147545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 29243377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 29343377Smarc TTOPRI | PCATCH, ttybg, 0)) 29440712Skarels return (error); 295903Sbill } 296903Sbill break; 297903Sbill } 298903Sbill 2999578Ssam /* 3009578Ssam * Process the ioctl. 3019578Ssam */ 3027625Ssam switch (com) { 303903Sbill 3048556Sroot /* get discipline number */ 30539Sbill case TIOCGETD: 3067625Ssam *(int *)data = tp->t_line; 30739Sbill break; 30839Sbill 3098556Sroot /* set line discipline */ 3107625Ssam case TIOCSETD: { 3117625Ssam register int t = *(int *)data; 31235811Smarc dev_t dev = tp->t_dev; 3137625Ssam 31435811Smarc if ((unsigned)t >= nldisp) 31510851Ssam return (ENXIO); 31625584Skarels if (t != tp->t_line) { 31725584Skarels s = spltty(); 31849752Smarc (*linesw[tp->t_line].l_close)(tp, flag); 31925584Skarels error = (*linesw[t].l_open)(dev, tp); 32025584Skarels if (error) { 32135811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 32225584Skarels splx(s); 32325584Skarels return (error); 32425584Skarels } 32525584Skarels tp->t_line = t; 32610851Ssam splx(s); 32710851Ssam } 32839Sbill break; 3297625Ssam } 33039Sbill 3318556Sroot /* prevent more opens on channel */ 3325614Swnj case TIOCEXCL: 3335614Swnj tp->t_state |= TS_XCLUDE; 3345614Swnj break; 3355614Swnj 3365614Swnj case TIOCNXCL: 3375614Swnj tp->t_state &= ~TS_XCLUDE; 3385614Swnj break; 3395614Swnj 34039Sbill case TIOCHPCL: 34135811Smarc tp->t_cflag |= HUPCL; 34239Sbill break; 34339Sbill 3443942Sbugs case TIOCFLUSH: { 3457625Ssam register int flags = *(int *)data; 3467625Ssam 3477625Ssam if (flags == 0) 3483942Sbugs flags = FREAD|FWRITE; 3497625Ssam else 3507625Ssam flags &= FREAD|FWRITE; 35112752Ssam ttyflush(tp, flags); 35239Sbill break; 3533944Sbugs } 35439Sbill 35537584Smarc case FIOASYNC: 35637584Smarc if (*(int *)data) 35737584Smarc tp->t_state |= TS_ASYNC; 35837584Smarc else 35937584Smarc tp->t_state &= ~TS_ASYNC; 36037584Smarc break; 36137584Smarc 36237584Smarc case FIONBIO: 36337584Smarc break; /* XXX remove */ 36437584Smarc 3658556Sroot /* return number of characters immediately available */ 3667625Ssam case FIONREAD: 3677625Ssam *(off_t *)data = ttnread(tp); 368174Sbill break; 369174Sbill 37013077Ssam case TIOCOUTQ: 37113077Ssam *(int *)data = tp->t_outq.c_cc; 37213077Ssam break; 37313077Ssam 3748589Sroot case TIOCSTOP: 37517545Skarels s = spltty(); 3769578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3775573Swnj tp->t_state |= TS_TTSTOP; 3785573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3795573Swnj } 3807625Ssam splx(s); 3815573Swnj break; 3825573Swnj 3838589Sroot case TIOCSTART: 38417545Skarels s = spltty(); 38535811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3865573Swnj tp->t_state &= ~TS_TTSTOP; 38735811Smarc tp->t_lflag &= ~FLUSHO; 3885573Swnj ttstart(tp); 3895573Swnj } 3907625Ssam splx(s); 3915573Swnj break; 3925573Swnj 3939325Ssam /* 3949325Ssam * Simulate typing of a character at the terminal. 3959325Ssam */ 3969325Ssam case TIOCSTI: 39747545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 39817183Smckusick return (EPERM); 39947545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 4009325Ssam return (EACCES); 4019578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4029325Ssam break; 4039325Ssam 40435811Smarc case TIOCGETA: { 40535811Smarc struct termios *t = (struct termios *)data; 40612752Ssam 40735811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 40835811Smarc break; 40935811Smarc } 41035811Smarc 41135811Smarc case TIOCSETA: 41235811Smarc case TIOCSETAW: 41337584Smarc case TIOCSETAF: { 41435811Smarc register struct termios *t = (struct termios *)data; 41540712Skarels 41617545Skarels s = spltty(); 41739407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 41840712Skarels if (error = ttywait(tp)) { 41940712Skarels splx(s); 42040712Skarels return (error); 42140712Skarels } 42245007Smarc if (com == TIOCSETAF) 42339407Smarc ttyflush(tp, FREAD); 42439407Smarc } 42540712Skarels if ((t->c_cflag&CIGNORE) == 0) { 42635811Smarc /* 42735811Smarc * set device hardware 42835811Smarc */ 42937584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 43037584Smarc splx(s); 43135811Smarc return (error); 43237584Smarc } else { 43340712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 43437584Smarc (tp->t_cflag&CLOCAL) && 43540712Skarels (t->c_cflag&CLOCAL) == 0) { 43637584Smarc tp->t_state &= ~TS_ISOPEN; 43737584Smarc tp->t_state |= TS_WOPEN; 43837584Smarc ttwakeup(tp); 43937584Smarc } 44035811Smarc tp->t_cflag = t->c_cflag; 44135811Smarc tp->t_ispeed = t->c_ispeed; 44235811Smarc tp->t_ospeed = t->c_ospeed; 44334492Skarels } 44435811Smarc ttsetwater(tp); 44512752Ssam } 44639407Smarc if (com != TIOCSETAF) { 44735811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 44835811Smarc if (t->c_lflag&ICANON) { 44935811Smarc tp->t_lflag |= PENDIN; 45035811Smarc ttwakeup(tp); 45135811Smarc } 45235811Smarc else { 45335811Smarc struct clist tq; 45435811Smarc 45535811Smarc catq(&tp->t_rawq, &tp->t_canq); 45635811Smarc tq = tp->t_rawq; 45735811Smarc tp->t_rawq = tp->t_canq; 45835811Smarc tp->t_canq = tq; 45935811Smarc } 46012752Ssam } 46135811Smarc tp->t_iflag = t->c_iflag; 46235811Smarc tp->t_oflag = t->c_oflag; 46342882Smarc /* 46442882Smarc * Make the EXTPROC bit read only. 46542882Smarc */ 46642882Smarc if (tp->t_lflag&EXTPROC) 46742882Smarc t->c_lflag |= EXTPROC; 46842882Smarc else 46942882Smarc t->c_lflag &= ~EXTPROC; 47035811Smarc tp->t_lflag = t->c_lflag; 47135811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 47212752Ssam splx(s); 47312752Ssam break; 47412752Ssam } 47512752Ssam 47612752Ssam /* 47739555Smarc * Set controlling terminal. 47839555Smarc * Session ctty vnode pointer set in vnode layer. 47934492Skarels */ 48047545Skarels case TIOCSCTTY: 48139555Smarc if (!SESS_LEADER(p) || 48239555Smarc (p->p_session->s_ttyvp || tp->t_session) && 48339555Smarc (tp->t_session != p->p_session)) 48439407Smarc return (EPERM); 48535811Smarc tp->t_session = p->p_session; 48639555Smarc tp->t_pgrp = p->p_pgrp; 48739555Smarc p->p_session->s_ttyp = tp; 48839555Smarc p->p_flag |= SCTTY; 48934492Skarels break; 49039555Smarc 49134492Skarels /* 49235811Smarc * Set terminal process group. 49317545Skarels */ 49418650Sbloom case TIOCSPGRP: { 49535811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 49617545Skarels 49739555Smarc if (!isctty(p, tp)) 49839555Smarc return (ENOTTY); 49940030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 50039555Smarc return (EPERM); 50139555Smarc tp->t_pgrp = pgrp; 50212752Ssam break; 50318650Sbloom } 50412752Ssam 50512752Ssam case TIOCGPGRP: 50647545Skarels if (!isctty(p, tp)) 50739555Smarc return (ENOTTY); 50845007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 50912752Ssam break; 51012752Ssam 51117598Sbloom case TIOCSWINSZ: 51218650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 51318650Sbloom sizeof (struct winsize))) { 51417598Sbloom tp->t_winsize = *(struct winsize *)data; 51542882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 51617598Sbloom } 51717598Sbloom break; 51817598Sbloom 51917598Sbloom case TIOCGWINSZ: 52017598Sbloom *(struct winsize *)data = tp->t_winsize; 52117598Sbloom break; 52217598Sbloom 52330534Skarels case TIOCCONS: 52430534Skarels if (*(int *)data) { 52542141Smckusick if (constty && constty != tp && 52642141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 52742141Smckusick (TS_CARR_ON|TS_ISOPEN)) 52830534Skarels return (EBUSY); 52930534Skarels #ifndef UCONSOLE 53047545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 53137554Smckusick return (error); 53230534Skarels #endif 53330534Skarels constty = tp; 53430534Skarels } else if (tp == constty) 53533404Skarels constty = NULL; 53630534Skarels break; 53730534Skarels 53848439Skarels case TIOCDRAIN: 53948439Skarels if (error = ttywait(tp)) 54048439Skarels return (error); 54148439Skarels break; 54248439Skarels 54347545Skarels default: 54435811Smarc #ifdef COMPAT_43 54547545Skarels return (ttcompat(tp, com, data, flag)); 54647545Skarels #else 54747545Skarels return (-1); 54835811Smarc #endif 54939Sbill } 5508556Sroot return (0); 55139Sbill } 5524484Swnj 5534484Swnj ttnread(tp) 5544484Swnj struct tty *tp; 5554484Swnj { 5564484Swnj int nread = 0; 5574484Swnj 55835811Smarc if (tp->t_lflag & PENDIN) 5594484Swnj ttypend(tp); 5604484Swnj nread = tp->t_canq.c_cc; 56135811Smarc if ((tp->t_lflag & ICANON) == 0) 5624484Swnj nread += tp->t_rawq.c_cc; 5634484Swnj return (nread); 5644484Swnj } 5654484Swnj 5665408Swnj ttselect(dev, rw) 5674484Swnj dev_t dev; 5685408Swnj int rw; 5694484Swnj { 5704484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5714484Swnj int nread; 57217545Skarels int s = spltty(); 5734484Swnj 5745408Swnj switch (rw) { 5754484Swnj 5764484Swnj case FREAD: 5774484Swnj nread = ttnread(tp); 57837584Smarc if (nread > 0 || 57940712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 5805408Swnj goto win; 5814938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5825408Swnj tp->t_state |= TS_RCOLL; 5834484Swnj else 58447545Skarels tp->t_rsel = curproc; 5855408Swnj break; 5864484Swnj 5875408Swnj case FWRITE: 58835811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5895408Swnj goto win; 5905408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5915408Swnj tp->t_state |= TS_WCOLL; 5925408Swnj else 59347545Skarels tp->t_wsel = curproc; 5945408Swnj break; 5954484Swnj } 5965408Swnj splx(s); 5975408Swnj return (0); 5985408Swnj win: 5995408Swnj splx(s); 6005408Swnj return (1); 6014484Swnj } 6027436Skre 6037502Sroot /* 60449380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6057502Sroot */ 6067502Sroot ttyopen(dev, tp) 6077625Ssam dev_t dev; 6087625Ssam register struct tty *tp; 6097502Sroot { 6107502Sroot 6117502Sroot tp->t_dev = dev; 61235811Smarc 6137502Sroot tp->t_state &= ~TS_WOPEN; 61417545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 61517545Skarels tp->t_state |= TS_ISOPEN; 61617598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 61717545Skarels } 6188556Sroot return (0); 6197502Sroot } 6207502Sroot 6217502Sroot /* 62225391Skarels * "close" a line discipline 62325391Skarels */ 62449752Smarc ttylclose(tp, flag) 62549752Smarc struct tty *tp; 62649752Smarc int flag; 62725391Skarels { 62825391Skarels 62949752Smarc if (flag&IO_NDELAY) 63049752Smarc ttyflush(tp, FREAD|FWRITE); 63149752Smarc else 63249752Smarc ttywflush(tp); 63325391Skarels } 63425391Skarels 63525391Skarels /* 63649380Skarels * Handle close() on a tty line: flush and set to initial state, 63749380Skarels * bumping generation number so that pending read/write calls 63849380Skarels * can detect recycling of the tty. 6397502Sroot */ 6407502Sroot ttyclose(tp) 6417625Ssam register struct tty *tp; 6427502Sroot { 64330534Skarels if (constty == tp) 64430534Skarels constty = NULL; 64525391Skarels ttyflush(tp, FREAD|FWRITE); 64639555Smarc tp->t_session = NULL; 64739555Smarc tp->t_pgrp = NULL; 6487502Sroot tp->t_state = 0; 64943377Smarc tp->t_gen++; 65040712Skarels return (0); 6517502Sroot } 6527502Sroot 6537502Sroot /* 65425391Skarels * Handle modem control transition on a tty. 65525391Skarels * Flag indicates new state of carrier. 65625391Skarels * Returns 0 if the line should be turned off, otherwise 1. 65725391Skarels */ 65825391Skarels ttymodem(tp, flag) 65925391Skarels register struct tty *tp; 66025391Skarels { 66125391Skarels 66242193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 66325391Skarels /* 66425391Skarels * MDMBUF: do flow control according to carrier flag 66525391Skarels */ 66625391Skarels if (flag) { 66725391Skarels tp->t_state &= ~TS_TTSTOP; 66825391Skarels ttstart(tp); 66925391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 67025391Skarels tp->t_state |= TS_TTSTOP; 67125391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 67225391Skarels } 67325391Skarels } else if (flag == 0) { 67425391Skarels /* 67525391Skarels * Lost carrier. 67625391Skarels */ 67725391Skarels tp->t_state &= ~TS_CARR_ON; 67842193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 67942193Smarc if (tp->t_session && tp->t_session->s_leader) 68042193Smarc psignal(tp->t_session->s_leader, SIGHUP); 68142193Smarc ttyflush(tp, FREAD|FWRITE); 68242193Smarc return (0); 68325391Skarels } 68425391Skarels } else { 68525391Skarels /* 68625391Skarels * Carrier now on. 68725391Skarels */ 68825391Skarels tp->t_state |= TS_CARR_ON; 68937584Smarc ttwakeup(tp); 69025391Skarels } 69125391Skarels return (1); 69225391Skarels } 69325391Skarels 69425391Skarels /* 69525404Skarels * Default modem control routine (for other line disciplines). 69625404Skarels * Return argument flag, to turn off device on carrier drop. 69725404Skarels */ 69825415Skarels nullmodem(tp, flag) 69925415Skarels register struct tty *tp; 70025404Skarels int flag; 70125404Skarels { 70225404Skarels 70325404Skarels if (flag) 70425404Skarels tp->t_state |= TS_CARR_ON; 70539407Smarc else { 70625404Skarels tp->t_state &= ~TS_CARR_ON; 70742193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 70842193Smarc if (tp->t_session && tp->t_session->s_leader) 70942193Smarc psignal(tp->t_session->s_leader, SIGHUP); 71042193Smarc return (0); 71142193Smarc } 71239407Smarc } 71342193Smarc return (1); 71425404Skarels } 71525404Skarels 71625404Skarels /* 7177502Sroot * reinput pending characters after state switch 71817545Skarels * call at spltty(). 7197502Sroot */ 7207502Sroot ttypend(tp) 7217625Ssam register struct tty *tp; 7227502Sroot { 7237502Sroot struct clist tq; 7247502Sroot register c; 7257502Sroot 72635811Smarc tp->t_lflag &= ~PENDIN; 7279578Ssam tp->t_state |= TS_TYPEN; 7287502Sroot tq = tp->t_rawq; 7297502Sroot tp->t_rawq.c_cc = 0; 7307502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7317502Sroot while ((c = getc(&tq)) >= 0) 7327502Sroot ttyinput(c, tp); 7339578Ssam tp->t_state &= ~TS_TYPEN; 7347502Sroot } 7357502Sroot 7367502Sroot /* 73749380Skarels * Process input of a single character received on a tty. 7387502Sroot */ 7397502Sroot ttyinput(c, tp) 7407625Ssam register c; 7417625Ssam register struct tty *tp; 7427502Sroot { 74335811Smarc register int iflag = tp->t_iflag; 74435811Smarc register int lflag = tp->t_lflag; 74535811Smarc register u_char *cc = tp->t_cc; 74635811Smarc int i, err; 7477502Sroot 7489578Ssam /* 7499578Ssam * If input is pending take it first. 7509578Ssam */ 75135811Smarc if (lflag&PENDIN) 7527502Sroot ttypend(tp); 75335811Smarc /* 75435811Smarc * Gather stats. 75535811Smarc */ 7567502Sroot tk_nin++; 75735811Smarc if (lflag&ICANON) { 75835811Smarc tk_cancc++; 75935811Smarc tp->t_cancc++; 76035811Smarc } else { 76135811Smarc tk_rawcc++; 76235811Smarc tp->t_rawcc++; 76335811Smarc } 7649578Ssam /* 76535811Smarc * Handle exceptional conditions (break, parity, framing). 7669578Ssam */ 76735811Smarc if (err = (c&TTY_ERRORMASK)) { 76835811Smarc c &= ~TTY_ERRORMASK; 76935811Smarc if (err&TTY_FE && !c) { /* break */ 77035811Smarc if (iflag&IGNBRK) 77135811Smarc goto endcase; 77235811Smarc else if (iflag&BRKINT && lflag&ISIG && 77335811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 77435811Smarc c = cc[VINTR]; 77547545Skarels else if (iflag&PARMRK) 77647545Skarels goto parmrk; 77735811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 77835811Smarc if (iflag&IGNPAR) 77935811Smarc goto endcase; 78035811Smarc else if (iflag&PARMRK) { 78135811Smarc parmrk: 78235811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 78335811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 78435811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 78535811Smarc goto endcase; 78635811Smarc } else 78735811Smarc c = 0; 7887502Sroot } 7899578Ssam } 7909578Ssam /* 79135811Smarc * In tandem mode, check high water mark. 7929578Ssam */ 79335811Smarc if (iflag&IXOFF) 79435811Smarc ttyblock(tp); 79535811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 79649380Skarels c &= ~0x80; 79744419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 79844419Smarc /* 79944419Smarc * Check for literal nexting very first 80044419Smarc */ 80144419Smarc if (tp->t_state&TS_LNCH) { 80244419Smarc c |= TTY_QUOTE; 80344419Smarc tp->t_state &= ~TS_LNCH; 80444419Smarc } 80544419Smarc /* 80644419Smarc * Scan for special characters. This code 80744419Smarc * is really just a big case statement with 80844419Smarc * non-constant cases. The bottom of the 80944419Smarc * case statement is labeled ``endcase'', so goto 81044419Smarc * it after a case match, or similar. 81144419Smarc */ 81244419Smarc 81344419Smarc /* 81444419Smarc * Control chars which aren't controlled 81544419Smarc * by ICANON, ISIG, or IXON. 81644419Smarc */ 81744419Smarc if (lflag&IEXTEN) { 81844419Smarc if (CCEQ(cc[VLNEXT], c)) { 81944419Smarc if (lflag&ECHO) { 82044419Smarc if (lflag&ECHOE) 82144419Smarc ttyoutstr("^\b", tp); 82244419Smarc else 82344419Smarc ttyecho(c, tp); 82444419Smarc } 82544419Smarc tp->t_state |= TS_LNCH; 82644419Smarc goto endcase; 82744419Smarc } 82844419Smarc if (CCEQ(cc[VDISCARD], c)) { 82944419Smarc if (lflag&FLUSHO) 83044419Smarc tp->t_lflag &= ~FLUSHO; 83144419Smarc else { 83244419Smarc ttyflush(tp, FWRITE); 83335811Smarc ttyecho(c, tp); 83444419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 83544419Smarc ttyretype(tp); 83644419Smarc tp->t_lflag |= FLUSHO; 83744419Smarc } 83844419Smarc goto startoutput; 83935811Smarc } 8409578Ssam } 84144419Smarc /* 84244419Smarc * Signals. 84344419Smarc */ 84444419Smarc if (lflag&ISIG) { 84544419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 84644419Smarc if ((lflag&NOFLSH) == 0) 84744419Smarc ttyflush(tp, FREAD|FWRITE); 8487502Sroot ttyecho(c, tp); 84944419Smarc pgsignal(tp->t_pgrp, 85044419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 85144419Smarc goto endcase; 8527502Sroot } 85344419Smarc if (CCEQ(cc[VSUSP], c)) { 85444419Smarc if ((lflag&NOFLSH) == 0) 85544419Smarc ttyflush(tp, FREAD); 85644419Smarc ttyecho(c, tp); 85744419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 85844419Smarc goto endcase; 85944419Smarc } 8609578Ssam } 86144419Smarc /* 86244419Smarc * Handle start/stop characters. 86344419Smarc */ 86444419Smarc if (iflag&IXON) { 86544419Smarc if (CCEQ(cc[VSTOP], c)) { 86644419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 86744419Smarc tp->t_state |= TS_TTSTOP; 86844419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 86944419Smarc 0); 87044419Smarc return; 87144419Smarc } 87244419Smarc if (!CCEQ(cc[VSTART], c)) 87344419Smarc return; 87444419Smarc /* 87544419Smarc * if VSTART == VSTOP then toggle 87644419Smarc */ 87744419Smarc goto endcase; 87835811Smarc } 87944419Smarc if (CCEQ(cc[VSTART], c)) 88044419Smarc goto restartoutput; 8819578Ssam } 88244419Smarc /* 88344419Smarc * IGNCR, ICRNL, & INLCR 88444419Smarc */ 88544419Smarc if (c == '\r') { 88644419Smarc if (iflag&IGNCR) 88744419Smarc goto endcase; 88844419Smarc else if (iflag&ICRNL) 88944419Smarc c = '\n'; 89044419Smarc } else if (c == '\n' && iflag&INLCR) 89144419Smarc c = '\r'; 8929578Ssam } 89347545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 89444419Smarc /* 89544419Smarc * From here on down canonical mode character 89644419Smarc * processing takes place. 89744419Smarc */ 89844419Smarc /* 89944419Smarc * erase (^H / ^?) 90044419Smarc */ 90144419Smarc if (CCEQ(cc[VERASE], c)) { 90244419Smarc if (tp->t_rawq.c_cc) 9039578Ssam ttyrub(unputc(&tp->t_rawq), tp); 90444419Smarc goto endcase; 9059578Ssam } 90644419Smarc /* 90744419Smarc * kill (^U) 90844419Smarc */ 90944419Smarc if (CCEQ(cc[VKILL], c)) { 91044419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 91144419Smarc (lflag&ECHOPRT) == 0) { 91244419Smarc while (tp->t_rawq.c_cc) 91344419Smarc ttyrub(unputc(&tp->t_rawq), tp); 91444419Smarc } else { 91544419Smarc ttyecho(c, tp); 91644419Smarc if (lflag&ECHOK || lflag&ECHOKE) 91744419Smarc ttyecho('\n', tp); 91844419Smarc while (getc(&tp->t_rawq) > 0) 91944419Smarc ; 92044419Smarc tp->t_rocount = 0; 92144419Smarc } 92244419Smarc tp->t_state &= ~TS_LOCAL; 92344419Smarc goto endcase; 92444419Smarc } 92544419Smarc /* 92644419Smarc * word erase (^W) 92744419Smarc */ 92844419Smarc if (CCEQ(cc[VWERASE], c)) { 92944419Smarc int ctype; 93047545Skarels int alt = lflag&ALTWERASE; 93135811Smarc 93244419Smarc /* 93344419Smarc * erase whitespace 93444419Smarc */ 93544419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 93644419Smarc ttyrub(c, tp); 93744419Smarc if (c == -1) 93844419Smarc goto endcase; 93944419Smarc /* 94047545Skarels * erase last char of word and remember the 94147545Skarels * next chars type (for ALTWERASE) 94244419Smarc */ 94335811Smarc ttyrub(c, tp); 94444419Smarc c = unputc(&tp->t_rawq); 94547545Skarels if (c == -1) 94644419Smarc goto endcase; 94751003Sbostic if (c == ' ' || c == '\t') { 94851003Sbostic putc(c, &tp->t_rawq); 94951003Sbostic goto endcase; 95051003Sbostic } 95149380Skarels ctype = ISALPHA(c); 95244419Smarc /* 95347545Skarels * erase rest of word 95444419Smarc */ 95544419Smarc do { 95644419Smarc ttyrub(c, tp); 95744419Smarc c = unputc(&tp->t_rawq); 95844419Smarc if (c == -1) 95944419Smarc goto endcase; 96047545Skarels } while (c != ' ' && c != '\t' && 96149380Skarels (alt == 0 || ISALPHA(c) == ctype)); 96244419Smarc (void) putc(c, &tp->t_rawq); 96334492Skarels goto endcase; 96444419Smarc } 96535811Smarc /* 96644419Smarc * reprint line (^R) 96735811Smarc */ 96844419Smarc if (CCEQ(cc[VREPRINT], c)) { 96944419Smarc ttyretype(tp); 97034492Skarels goto endcase; 97134492Skarels } 97235811Smarc /* 97344419Smarc * ^T - kernel info and generate SIGINFO 97435811Smarc */ 97544419Smarc if (CCEQ(cc[VSTATUS], c)) { 976*51068Smarc if (lflag&ISIG) 977*51068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 97844419Smarc if ((lflag&NOKERNINFO) == 0) 97944419Smarc ttyinfo(tp); 98044419Smarc goto endcase; 98144419Smarc } 9829578Ssam } 9839578Ssam /* 9849578Ssam * Check for input buffer overflow 9859578Ssam */ 98647545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 98735811Smarc if (iflag&IMAXBEL) { 98835811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 98935811Smarc (void) ttyoutput(CTRL('g'), tp); 99035811Smarc } else 99135811Smarc ttyflush(tp, FREAD | FWRITE); 9929578Ssam goto endcase; 99310391Ssam } 9949578Ssam /* 9959578Ssam * Put data char in q for user and 9969578Ssam * wakeup on seeing a line delimiter. 9979578Ssam */ 9989578Ssam if (putc(c, &tp->t_rawq) >= 0) { 99947545Skarels if ((lflag&ICANON) == 0) { 100047545Skarels ttwakeup(tp); 100147545Skarels ttyecho(c, tp); 100247545Skarels goto endcase; 100347545Skarels } 100435811Smarc if (ttbreakc(c)) { 10059578Ssam tp->t_rocount = 0; 10069578Ssam catq(&tp->t_rawq, &tp->t_canq); 10077502Sroot ttwakeup(tp); 10089578Ssam } else if (tp->t_rocount++ == 0) 10099578Ssam tp->t_rocol = tp->t_col; 10109578Ssam if (tp->t_state&TS_ERASE) { 101135811Smarc /* 101235811Smarc * end of prterase \.../ 101335811Smarc */ 10149578Ssam tp->t_state &= ~TS_ERASE; 10159578Ssam (void) ttyoutput('/', tp); 10169578Ssam } 10179578Ssam i = tp->t_col; 10187502Sroot ttyecho(c, tp); 101935811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 102035811Smarc /* 102135811Smarc * Place the cursor over the '^' of the ^D. 102235811Smarc */ 10239578Ssam i = MIN(2, tp->t_col - i); 10249578Ssam while (i > 0) { 10259578Ssam (void) ttyoutput('\b', tp); 10269578Ssam i--; 10279578Ssam } 10289578Ssam } 10297502Sroot } 10309578Ssam endcase: 10319578Ssam /* 103235811Smarc * IXANY means allow any character to restart output. 10339578Ssam */ 103440712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 103540712Skarels cc[VSTART] != cc[VSTOP]) 10367502Sroot return; 10379578Ssam restartoutput: 10387502Sroot tp->t_state &= ~TS_TTSTOP; 103935811Smarc tp->t_lflag &= ~FLUSHO; 10409578Ssam startoutput: 10417502Sroot ttstart(tp); 10427502Sroot } 10437502Sroot 10447502Sroot /* 104549380Skarels * Output a single character on a tty, doing output processing 104649380Skarels * as needed (expanding tabs, newline processing, etc.). 104749380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10487502Sroot * Must be recursive. 10497502Sroot */ 10507502Sroot ttyoutput(c, tp) 10517502Sroot register c; 10527502Sroot register struct tty *tp; 10537502Sroot { 105449380Skarels register int col; 105535811Smarc register long oflag = tp->t_oflag; 105635811Smarc 105740712Skarels if ((oflag&OPOST) == 0) { 105835811Smarc if (tp->t_lflag&FLUSHO) 10597502Sroot return (-1); 10607502Sroot if (putc(c, &tp->t_outq)) 10617625Ssam return (c); 10627502Sroot tk_nout++; 106335811Smarc tp->t_outcc++; 10647502Sroot return (-1); 10657502Sroot } 106635811Smarc c &= TTY_CHARMASK; 10677502Sroot /* 106849380Skarels * Do tab expansion if OXTABS is set. 106942882Smarc * Special case if we have external processing, we don't 107042882Smarc * do the tab expansion because we'll probably get it 107142882Smarc * wrong. If tab expansion needs to be done, let it 107242882Smarc * happen externally. 10737502Sroot */ 107447545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 10757502Sroot register int s; 10767502Sroot 10777502Sroot c = 8 - (tp->t_col&7); 107835811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 107917545Skarels s = spltty(); /* don't interrupt tabs */ 10807502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10817502Sroot tk_nout += c; 108235811Smarc tp->t_outcc += c; 10837502Sroot splx(s); 10847502Sroot } 10857502Sroot tp->t_col += c; 10867502Sroot return (c ? -1 : '\t'); 10877502Sroot } 108835811Smarc if (c == CEOT && oflag&ONOEOT) 108947545Skarels return (-1); 10907502Sroot tk_nout++; 109135811Smarc tp->t_outcc++; 10927502Sroot /* 109349380Skarels * Newline translation: if ONLCR is set, 109449380Skarels * translate newline into "\r\n". 10957502Sroot */ 109635811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10977502Sroot return (c); 109835811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 109935811Smarc return (c); 110047545Skarels 110149380Skarels col = tp->t_col; 110249380Skarels switch (CCLASS(c)) { 11037502Sroot 11047502Sroot case ORDINARY: 110549380Skarels col++; 11067502Sroot 11077502Sroot case CONTROL: 11087502Sroot break; 11097502Sroot 11107502Sroot case BACKSPACE: 111149380Skarels if (col > 0) 111249380Skarels col--; 11137502Sroot break; 11147502Sroot 11157502Sroot case NEWLINE: 111649380Skarels col = 0; 11177502Sroot break; 11187502Sroot 11197502Sroot case TAB: 112049380Skarels col = (col + 8) &~ 0x7; 11217502Sroot break; 11227502Sroot 11237502Sroot case RETURN: 112449380Skarels col = 0; 11257502Sroot } 112649380Skarels tp->t_col = col; 11277502Sroot return (-1); 11287502Sroot } 11297502Sroot 11307502Sroot /* 113149380Skarels * Process a read call on a tty device. 11327502Sroot */ 113337584Smarc ttread(tp, uio, flag) 11347625Ssam register struct tty *tp; 11357722Swnj struct uio *uio; 11367502Sroot { 11377502Sroot register struct clist *qp; 113835811Smarc register int c; 113941383Smarc register long lflag; 114035811Smarc register u_char *cc = tp->t_cc; 114147545Skarels register struct proc *p = curproc; 11429859Ssam int s, first, error = 0; 11437502Sroot 11447502Sroot loop: 114541383Smarc lflag = tp->t_lflag; 114637584Smarc s = spltty(); 11479578Ssam /* 114837584Smarc * take pending input first 11499578Ssam */ 115035811Smarc if (lflag&PENDIN) 11517502Sroot ttypend(tp); 11529859Ssam splx(s); 115340712Skarels 11549578Ssam /* 11559578Ssam * Hang process if it's in the background. 11569578Ssam */ 115747545Skarels if (isbackground(p, tp)) { 115847545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 115947545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 116047545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11618520Sroot return (EIO); 116247545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 116343377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 116443377Smarc ttybg, 0)) 116540712Skarels return (error); 116623165Sbloom goto loop; 11677502Sroot } 116840712Skarels 11699578Ssam /* 117035811Smarc * If canonical, use the canonical queue, 117135811Smarc * else use the raw queue. 117237584Smarc * 117347545Skarels * (should get rid of clists...) 11749578Ssam */ 117535811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 117640712Skarels 11779578Ssam /* 117840712Skarels * If there is no input, sleep on rawq 117940712Skarels * awaiting hardware receipt and notification. 118040712Skarels * If we have data, we don't need to check for carrier. 11819578Ssam */ 118217545Skarels s = spltty(); 11839578Ssam if (qp->c_cc <= 0) { 118440712Skarels int carrier; 118540712Skarels 118640712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 118740712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 11889859Ssam splx(s); 118940712Skarels return (0); /* EOF */ 11907502Sroot } 119137728Smckusick if (flag & IO_NDELAY) { 119237584Smarc splx(s); 119337584Smarc return (EWOULDBLOCK); 119437584Smarc } 119543377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 119640712Skarels carrier ? ttyin : ttopen, 0); 11979859Ssam splx(s); 119843377Smarc if (error) 119940712Skarels return (error); 12009578Ssam goto loop; 12019578Ssam } 12029859Ssam splx(s); 120340712Skarels 12049578Ssam /* 120535811Smarc * Input present, check for input mapping and processing. 12069578Ssam */ 12079578Ssam first = 1; 12089578Ssam while ((c = getc(qp)) >= 0) { 12099578Ssam /* 121035811Smarc * delayed suspend (^Y) 12119578Ssam */ 121235811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 121342882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12149578Ssam if (first) { 121543377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 121643377Smarc TTIPRI | PCATCH, ttybg, 0)) 121740712Skarels break; 12189578Ssam goto loop; 12199578Ssam } 12209578Ssam break; 12217502Sroot } 12229578Ssam /* 122335811Smarc * Interpret EOF only in canonical mode. 12249578Ssam */ 122535811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12269578Ssam break; 12279578Ssam /* 12289578Ssam * Give user character. 12299578Ssam */ 123040712Skarels error = ureadc(c, uio); 12319578Ssam if (error) 12329578Ssam break; 123314938Smckusick if (uio->uio_resid == 0) 12349578Ssam break; 12359578Ssam /* 123635811Smarc * In canonical mode check for a "break character" 12379578Ssam * marking the end of a "line of input". 12389578Ssam */ 123940712Skarels if (lflag&ICANON && ttbreakc(c)) 12409578Ssam break; 12419578Ssam first = 0; 12427502Sroot } 12439578Ssam /* 12449578Ssam * Look to unblock output now that (presumably) 12459578Ssam * the input queue has gone down. 12469578Ssam */ 124735811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 124847545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 124947545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12507502Sroot tp->t_state &= ~TS_TBLOCK; 12517502Sroot ttstart(tp); 12527502Sroot } 125335811Smarc } 12548520Sroot return (error); 12557502Sroot } 12567502Sroot 12577502Sroot /* 125825391Skarels * Check the output queue on tp for space for a kernel message 125925391Skarels * (from uprintf/tprintf). Allow some space over the normal 126025391Skarels * hiwater mark so we don't lose messages due to normal flow 126125391Skarels * control, but don't let the tty run amok. 126230695Skarels * Sleeps here are not interruptible, but we return prematurely 126330695Skarels * if new signals come in. 126425391Skarels */ 126525391Skarels ttycheckoutq(tp, wait) 126625391Skarels register struct tty *tp; 126725391Skarels int wait; 126825391Skarels { 126930695Skarels int hiwat, s, oldsig; 127048439Skarels extern int wakeup(); 127125391Skarels 127235811Smarc hiwat = tp->t_hiwat; 127325391Skarels s = spltty(); 127450755Skarels if (wait) 127550755Skarels oldsig = curproc->p_sig; 127625391Skarels if (tp->t_outq.c_cc > hiwat + 200) 127729946Skarels while (tp->t_outq.c_cc > hiwat) { 127829946Skarels ttstart(tp); 127947545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 128029946Skarels splx(s); 128129946Skarels return (0); 128229946Skarels } 128330695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 128429946Skarels tp->t_state |= TS_ASLEEP; 128530695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 128625391Skarels } 128725391Skarels splx(s); 128825391Skarels return (1); 128925391Skarels } 129025391Skarels 129125391Skarels /* 129249380Skarels * Process a write call on a tty device. 12937502Sroot */ 129437584Smarc ttwrite(tp, uio, flag) 12957625Ssam register struct tty *tp; 12969578Ssam register struct uio *uio; 12977502Sroot { 12987502Sroot register char *cp; 129940712Skarels register int cc = 0, ce; 130047545Skarels register struct proc *p = curproc; 13019578Ssam int i, hiwat, cnt, error, s; 13027502Sroot char obuf[OBUFSIZ]; 13037502Sroot 130435811Smarc hiwat = tp->t_hiwat; 13059578Ssam cnt = uio->uio_resid; 13069578Ssam error = 0; 13077502Sroot loop: 130837584Smarc s = spltty(); 130940712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 131037584Smarc if (tp->t_state&TS_ISOPEN) { 131137584Smarc splx(s); 131237584Smarc return (EIO); 131337728Smckusick } else if (flag & IO_NDELAY) { 131437584Smarc splx(s); 131540712Skarels error = EWOULDBLOCK; 131640712Skarels goto out; 131737584Smarc } else { 131837584Smarc /* 131937584Smarc * sleep awaiting carrier 132037584Smarc */ 132143377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 132243377Smarc TTIPRI | PCATCH,ttopen, 0); 132337584Smarc splx(s); 132443377Smarc if (error) 132540712Skarels goto out; 132637584Smarc goto loop; 132737584Smarc } 132837584Smarc } 132937584Smarc splx(s); 13309578Ssam /* 13319578Ssam * Hang the process if it's in the background. 13329578Ssam */ 133347545Skarels if (isbackground(p, tp) && 133447545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 133547545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 133647545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 133747545Skarels p->p_pgrp->pg_jobc) { 133847545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 133943377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 134043377Smarc ttybg, 0)) 134140712Skarels goto out; 134221776Sbloom goto loop; 13437502Sroot } 13449578Ssam /* 13459578Ssam * Process the user's data in at most OBUFSIZ 134640712Skarels * chunks. Perform any output translation. 134740712Skarels * Keep track of high water mark, sleep on overflow 134840712Skarels * awaiting device aid in acquiring new space. 13499578Ssam */ 135040712Skarels while (uio->uio_resid > 0 || cc > 0) { 135140712Skarels if (tp->t_lflag&FLUSHO) { 135240712Skarels uio->uio_resid = 0; 135340712Skarels return (0); 135440712Skarels } 135540712Skarels if (tp->t_outq.c_cc > hiwat) 135632067Skarels goto ovhiwat; 13579578Ssam /* 135840712Skarels * Grab a hunk of data from the user, 135940712Skarels * unless we have some leftover from last time. 13609578Ssam */ 13617822Sroot if (cc == 0) { 136240712Skarels cc = min(uio->uio_resid, OBUFSIZ); 136340712Skarels cp = obuf; 136440712Skarels error = uiomove(cp, cc, uio); 136540712Skarels if (error) { 136640712Skarels cc = 0; 136740712Skarels break; 136840712Skarels } 13697822Sroot } 13709578Ssam /* 13719578Ssam * If nothing fancy need be done, grab those characters we 13729578Ssam * can handle without any of ttyoutput's processing and 13739578Ssam * just transfer them to the output q. For those chars 13749578Ssam * which require special processing (as indicated by the 13759578Ssam * bits in partab), call ttyoutput. After processing 13769578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13779578Ssam * immediately. 13789578Ssam */ 13799578Ssam while (cc > 0) { 138040712Skarels if ((tp->t_oflag&OPOST) == 0) 13817502Sroot ce = cc; 13827502Sroot else { 138334492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 138449380Skarels (u_char *)partab, CCLASSMASK); 13859578Ssam /* 13869578Ssam * If ce is zero, then we're processing 13879578Ssam * a special character through ttyoutput. 13889578Ssam */ 13899578Ssam if (ce == 0) { 13907502Sroot tp->t_rocount = 0; 13917502Sroot if (ttyoutput(*cp, tp) >= 0) { 139221776Sbloom /* no c-lists, wait a bit */ 139321776Sbloom ttstart(tp); 139443377Smarc if (error = ttysleep(tp, 139543377Smarc (caddr_t)&lbolt, 139643377Smarc TTOPRI | PCATCH, ttybuf, 0)) 139740712Skarels break; 139821776Sbloom goto loop; 13997502Sroot } 14009578Ssam cp++, cc--; 140135811Smarc if ((tp->t_lflag&FLUSHO) || 14029578Ssam tp->t_outq.c_cc > hiwat) 14037502Sroot goto ovhiwat; 14049578Ssam continue; 14057502Sroot } 14067502Sroot } 14079578Ssam /* 14089578Ssam * A bunch of normal characters have been found, 14099578Ssam * transfer them en masse to the output queue and 14109578Ssam * continue processing at the top of the loop. 14119578Ssam * If there are any further characters in this 14129578Ssam * <= OBUFSIZ chunk, the first should be a character 14139578Ssam * requiring special handling by ttyoutput. 14149578Ssam */ 14157502Sroot tp->t_rocount = 0; 14169578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14179578Ssam ce -= i; 14189578Ssam tp->t_col += ce; 14199578Ssam cp += ce, cc -= ce, tk_nout += ce; 142035811Smarc tp->t_outcc += ce; 14219578Ssam if (i > 0) { 14229578Ssam /* out of c-lists, wait a bit */ 14237502Sroot ttstart(tp); 142443377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 142543377Smarc TTOPRI | PCATCH, ttybuf, 0)) 142640712Skarels break; 142721776Sbloom goto loop; 14287502Sroot } 142935811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 143040712Skarels break; 14317502Sroot } 143235811Smarc ttstart(tp); 14337502Sroot } 143440712Skarels out: 143540712Skarels /* 143640712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 143740712Skarels * as the offset and iov pointers have moved forward, 143840712Skarels * but it doesn't matter (the call will either return short 143940712Skarels * or restart with a new uio). 144040712Skarels */ 144140712Skarels uio->uio_resid += cc; 14428520Sroot return (error); 144340712Skarels 14447502Sroot ovhiwat: 144532067Skarels ttstart(tp); 144632067Skarels s = spltty(); 14479578Ssam /* 144835811Smarc * This can only occur if FLUSHO is set in t_lflag, 144932067Skarels * or if ttstart/oproc is synchronous (or very fast). 14509578Ssam */ 14517502Sroot if (tp->t_outq.c_cc <= hiwat) { 14529578Ssam splx(s); 14537502Sroot goto loop; 14547502Sroot } 145537728Smckusick if (flag & IO_NDELAY) { 145617545Skarels splx(s); 145740712Skarels uio->uio_resid += cc; 14587822Sroot if (uio->uio_resid == cnt) 14598520Sroot return (EWOULDBLOCK); 14608520Sroot return (0); 14617502Sroot } 14627502Sroot tp->t_state |= TS_ASLEEP; 146343377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14649578Ssam splx(s); 146543377Smarc if (error) 146640712Skarels goto out; 14677502Sroot goto loop; 14687502Sroot } 14697502Sroot 14707502Sroot /* 14717502Sroot * Rubout one character from the rawq of tp 14727502Sroot * as cleanly as possible. 14737502Sroot */ 14747502Sroot ttyrub(c, tp) 14757625Ssam register c; 14767625Ssam register struct tty *tp; 14777502Sroot { 14787502Sroot register char *cp; 14797502Sroot register int savecol; 14807502Sroot int s; 14817502Sroot char *nextc(); 14827502Sroot 148342882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 14847502Sroot return; 148535811Smarc tp->t_lflag &= ~FLUSHO; 148635811Smarc if (tp->t_lflag&ECHOE) { 14877502Sroot if (tp->t_rocount == 0) { 14887502Sroot /* 14897502Sroot * Screwed by ttwrite; retype 14907502Sroot */ 14917502Sroot ttyretype(tp); 14927502Sroot return; 14937502Sroot } 149435811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 14957502Sroot ttyrubo(tp, 2); 149649380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 14977502Sroot 14987502Sroot case ORDINARY: 149935811Smarc ttyrubo(tp, 1); 15007502Sroot break; 15017502Sroot 15027502Sroot case VTAB: 15037502Sroot case BACKSPACE: 15047502Sroot case CONTROL: 15057502Sroot case RETURN: 150647545Skarels case NEWLINE: 150735811Smarc if (tp->t_lflag&ECHOCTL) 15087502Sroot ttyrubo(tp, 2); 15097502Sroot break; 15107502Sroot 151135811Smarc case TAB: { 151235811Smarc int c; 151335811Smarc 15147502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15157502Sroot ttyretype(tp); 15167502Sroot return; 15177502Sroot } 151817545Skarels s = spltty(); 15197502Sroot savecol = tp->t_col; 15209578Ssam tp->t_state |= TS_CNTTB; 152135811Smarc tp->t_lflag |= FLUSHO; 15227502Sroot tp->t_col = tp->t_rocol; 15239578Ssam cp = tp->t_rawq.c_cf; 152439407Smarc if (cp) 152539407Smarc c = *cp; /* XXX FIX NEXTC */ 152635811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 152735811Smarc ttyecho(c, tp); 152835811Smarc tp->t_lflag &= ~FLUSHO; 15299578Ssam tp->t_state &= ~TS_CNTTB; 15307502Sroot splx(s); 15317502Sroot /* 15327502Sroot * savecol will now be length of the tab 15337502Sroot */ 15347502Sroot savecol -= tp->t_col; 15357502Sroot tp->t_col += savecol; 15367502Sroot if (savecol > 8) 15377502Sroot savecol = 8; /* overflow screw */ 15387502Sroot while (--savecol >= 0) 15397502Sroot (void) ttyoutput('\b', tp); 15407502Sroot break; 154135811Smarc } 15427502Sroot 15437502Sroot default: 154437584Smarc /* XXX */ 154535811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 154649380Skarels c, CCLASS(c)); 154735811Smarc /*panic("ttyrub");*/ 15487502Sroot } 154935811Smarc } else if (tp->t_lflag&ECHOPRT) { 15509578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15517502Sroot (void) ttyoutput('\\', tp); 15529578Ssam tp->t_state |= TS_ERASE; 15537502Sroot } 15547502Sroot ttyecho(c, tp); 15557502Sroot } else 155635811Smarc ttyecho(tp->t_cc[VERASE], tp); 15577502Sroot tp->t_rocount--; 15587502Sroot } 15597502Sroot 15607502Sroot /* 15617502Sroot * Crt back over cnt chars perhaps 15627502Sroot * erasing them. 15637502Sroot */ 15647502Sroot ttyrubo(tp, cnt) 15657625Ssam register struct tty *tp; 15667625Ssam int cnt; 15677502Sroot { 15687502Sroot 15697502Sroot while (--cnt >= 0) 157040712Skarels ttyoutstr("\b \b", tp); 15717502Sroot } 15727502Sroot 15737502Sroot /* 15747502Sroot * Reprint the rawq line. 15757502Sroot * We assume c_cc has already been checked. 15767502Sroot */ 15777502Sroot ttyretype(tp) 15787625Ssam register struct tty *tp; 15797502Sroot { 15807502Sroot register char *cp; 15817502Sroot char *nextc(); 158235811Smarc int s, c; 15837502Sroot 158435811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 158535811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15867502Sroot (void) ttyoutput('\n', tp); 158717545Skarels s = spltty(); 158835811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 158935811Smarc BIT OF FIRST CHAR ****/ 159035811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 159135811Smarc ttyecho(c, tp); 159235811Smarc } 159335811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 159435811Smarc ttyecho(c, tp); 159535811Smarc } 15969578Ssam tp->t_state &= ~TS_ERASE; 15977502Sroot splx(s); 15987502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15997502Sroot tp->t_rocol = 0; 16007502Sroot } 16017502Sroot 16027502Sroot /* 160335811Smarc * Echo a typed character to the terminal. 16047502Sroot */ 16057502Sroot ttyecho(c, tp) 16067625Ssam register c; 16077625Ssam register struct tty *tp; 16087502Sroot { 16099578Ssam if ((tp->t_state&TS_CNTTB) == 0) 161035811Smarc tp->t_lflag &= ~FLUSHO; 161147545Skarels if (((tp->t_lflag&ECHO) == 0 && 161247545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16137502Sroot return; 161435811Smarc if (tp->t_lflag&ECHOCTL) { 161540712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 161640712Skarels c == 0177) { 16177502Sroot (void) ttyoutput('^', tp); 161835811Smarc c &= TTY_CHARMASK; 16197502Sroot if (c == 0177) 16207502Sroot c = '?'; 16217502Sroot else 16227502Sroot c += 'A' - 1; 16237502Sroot } 16247502Sroot } 162535811Smarc (void) ttyoutput(c, tp); 16267502Sroot } 16277502Sroot 16287502Sroot /* 16297502Sroot * send string cp to tp 16307502Sroot */ 163140712Skarels ttyoutstr(cp, tp) 16327625Ssam register char *cp; 16337625Ssam register struct tty *tp; 16347502Sroot { 16357502Sroot register char c; 16367502Sroot 16377502Sroot while (c = *cp++) 16387502Sroot (void) ttyoutput(c, tp); 16397502Sroot } 16407502Sroot 164149380Skarels /* 164249380Skarels * Wake up any readers on a tty. 164349380Skarels */ 16447502Sroot ttwakeup(tp) 164547545Skarels register struct tty *tp; 16467502Sroot { 16477502Sroot 16487502Sroot if (tp->t_rsel) { 16497502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16507502Sroot tp->t_state &= ~TS_RCOLL; 16517502Sroot tp->t_rsel = 0; 16527502Sroot } 165312752Ssam if (tp->t_state & TS_ASYNC) 165442882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16557502Sroot wakeup((caddr_t)&tp->t_rawq); 16567502Sroot } 165735811Smarc 165835811Smarc /* 165948439Skarels * Look up a code for a specified speed in a conversion table; 166048439Skarels * used by drivers to map software speed values to hardware parameters. 166148439Skarels */ 166248439Skarels ttspeedtab(speed, table) 166348439Skarels register struct speedtab *table; 166448439Skarels { 166548439Skarels 166648439Skarels for ( ; table->sp_speed != -1; table++) 166748439Skarels if (table->sp_speed == speed) 166848439Skarels return (table->sp_code); 166948439Skarels return (-1); 167048439Skarels } 167148439Skarels 167248439Skarels /* 167335811Smarc * set tty hi and low water marks 167435811Smarc * 167535811Smarc * Try to arrange the dynamics so there's about one second 167635811Smarc * from hi to low water. 167735811Smarc * 167835811Smarc */ 167935811Smarc ttsetwater(tp) 168035811Smarc struct tty *tp; 168135811Smarc { 168235811Smarc register cps = tp->t_ospeed / 10; 168335811Smarc register x; 168435811Smarc 168535811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 168635811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 168735811Smarc x += cps; 168835811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 168935811Smarc tp->t_hiwat = roundup(x, CBSIZE); 169035811Smarc #undef clamp 169135811Smarc } 169235811Smarc 169339407Smarc /* 169439407Smarc * Report on state of foreground process group. 169539407Smarc */ 169639407Smarc ttyinfo(tp) 169749907Sbostic register struct tty *tp; 169839407Smarc { 169949907Sbostic register struct proc *p, *pick; 170041177Smarc struct timeval utime, stime; 170149907Sbostic int tmp; 170239407Smarc 170339407Smarc if (ttycheckoutq(tp,0) == 0) 170439407Smarc return; 170549907Sbostic 170649907Sbostic /* Print load average. */ 170749907Sbostic tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; 170849907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 170949907Sbostic 171039555Smarc if (tp->t_session == NULL) 171149907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 171241177Smarc else if (tp->t_pgrp == NULL) 171349907Sbostic ttyprintf(tp, "no foreground process group\n"); 171441177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 171549907Sbostic ttyprintf(tp, "empty foreground process group\n"); 171639407Smarc else { 171749907Sbostic /* Pick interesting process. */ 171849907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 171941177Smarc if (proc_compare(pick, p)) 172041177Smarc pick = p; 172149907Sbostic 172249907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 172349907Sbostic pick->p_stat == SRUN ? "running" : 172449907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 172549907Sbostic 172649907Sbostic /* 172749907Sbostic * Lock out clock if process is running; get user/system 172849907Sbostic * cpu time. 172941177Smarc */ 173047545Skarels if (curproc == pick) 173149907Sbostic tmp = splclock(); 173241177Smarc utime = pick->p_utime; 173341177Smarc stime = pick->p_stime; 173447545Skarels if (curproc == pick) 173549907Sbostic splx(tmp); 173639407Smarc 173749907Sbostic /* Print user time. */ 173849907Sbostic ttyprintf(tp, "%d.%02du ", 173949907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 174041177Smarc 174149907Sbostic /* Print system time. */ 174249907Sbostic ttyprintf(tp, "%d.%02ds ", 174349907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 174449907Sbostic 174549907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 174649907Sbostic /* Print percentage cpu, resident set size. */ 174749907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 174849907Sbostic ttyprintf(tp, "%d%% %dk\n", 174949907Sbostic tmp / 100, pgtok(pick->p_vmspace->vm_rssize)); 175041177Smarc } 175149907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 175241177Smarc } 175341177Smarc 175441177Smarc /* 175541177Smarc * Returns 1 if p2 is "better" than p1 175641177Smarc * 175741177Smarc * The algorithm for picking the "interesting" process is thus: 175841177Smarc * 175941177Smarc * 1) (Only foreground processes are eligable - implied) 176041177Smarc * 2) Runnable processes are favored over anything 176141177Smarc * else. The runner with the highest cpu 176241177Smarc * utilization is picked (p_cpu). Ties are 176341177Smarc * broken by picking the highest pid. 176441177Smarc * 3 Next, the sleeper with the shortest sleep 176541177Smarc * time is favored. With ties, we pick out 176641177Smarc * just "short-term" sleepers (SSINTR == 0). 176741177Smarc * Further ties are broken by picking the highest 176841177Smarc * pid. 176941177Smarc * 177041177Smarc */ 177141177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 177245723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 177345723Smckusick #define ONLYA 2 177445723Smckusick #define ONLYB 1 177545723Smckusick #define BOTH 3 177645723Smckusick 177749907Sbostic static int 177841177Smarc proc_compare(p1, p2) 177941177Smarc register struct proc *p1, *p2; 178041177Smarc { 178141177Smarc 178241177Smarc if (p1 == NULL) 178341177Smarc return (1); 178441177Smarc /* 178541177Smarc * see if at least one of them is runnable 178641177Smarc */ 178745723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 178845723Smckusick case ONLYA: 178945723Smckusick return (0); 179045723Smckusick case ONLYB: 179141177Smarc return (1); 179245723Smckusick case BOTH: 179341177Smarc /* 179441177Smarc * tie - favor one with highest recent cpu utilization 179541177Smarc */ 179641177Smarc if (p2->p_cpu > p1->p_cpu) 179741177Smarc return (1); 179841177Smarc if (p1->p_cpu > p2->p_cpu) 179941177Smarc return (0); 180041177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 180141177Smarc } 180245723Smckusick /* 180345723Smckusick * weed out zombies 180445723Smckusick */ 180545723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 180645723Smckusick case ONLYA: 180745723Smckusick return (1); 180845723Smckusick case ONLYB: 180945723Smckusick return (0); 181045723Smckusick case BOTH: 181145723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 181245723Smckusick } 181341177Smarc /* 181441177Smarc * pick the one with the smallest sleep time 181541177Smarc */ 181641177Smarc if (p2->p_slptime > p1->p_slptime) 181741177Smarc return (0); 181841177Smarc if (p1->p_slptime > p2->p_slptime) 181941177Smarc return (1); 182041177Smarc /* 182141177Smarc * favor one sleeping in a non-interruptible sleep 182241177Smarc */ 182341177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 182441177Smarc return (1); 182541177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 182641177Smarc return (0); 182747545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182841177Smarc } 182945723Smckusick 183039555Smarc /* 183139555Smarc * Output char to tty; console putchar style. 183239555Smarc */ 183339555Smarc tputchar(c, tp) 183439555Smarc int c; 183539555Smarc struct tty *tp; 183639555Smarc { 183739555Smarc register s = spltty(); 183839555Smarc 183947545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 184039555Smarc if (c == '\n') 184139555Smarc (void) ttyoutput('\r', tp); 184239555Smarc (void) ttyoutput(c, tp); 184339555Smarc ttstart(tp); 184439555Smarc splx(s); 184539555Smarc return (0); 184639555Smarc } 184739555Smarc splx(s); 184839555Smarc return (-1); 184939555Smarc } 185043377Smarc 185144419Smarc /* 185249380Skarels * Sleep on chan, returning ERESTART if tty changed 185349380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 185449380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 185549380Skarels * call will redo validation done at the start of the call. 185644419Smarc */ 185743377Smarc ttysleep(tp, chan, pri, wmesg, timo) 185843377Smarc struct tty *tp; 185943377Smarc caddr_t chan; 186043377Smarc int pri; 186143377Smarc char *wmesg; 186243377Smarc int timo; 186343377Smarc { 186443377Smarc int error; 186543377Smarc short gen = tp->t_gen; 186643377Smarc 186743377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 186843377Smarc return (error); 186943377Smarc if (tp->t_gen != gen) 187043377Smarc return (ERESTART); 187143377Smarc return (0); 187243377Smarc } 1873