1*49594Sbostic /*- 2*49594Sbostic * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 3*49594Sbostic * Copyright (c) 1991 The Regents of the University of California. 4*49594Sbostic * All rights reserved. 523387Smckusick * 6*49594Sbostic * %sccs.include.redist.c% 7*49594Sbostic * 8*49594Sbostic * @(#)tty.c 7.42 (Berkeley) 05/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 2840712Skarels /* symbolic sleep message strings */ 2940712Skarels char ttyin[] = "ttyin"; 3040712Skarels char ttyout[] = "ttyout"; 3141370Smarc char ttopen[] = "ttyopn"; 3241370Smarc char ttclos[] = "ttycls"; 3340712Skarels char ttybg[] = "ttybg"; 3440712Skarels char ttybuf[] = "ttybuf"; 3540712Skarels 367436Skre /* 377436Skre * Table giving parity for characters and indicating 3835811Smarc * character classes to tty driver. The 8th bit 3935811Smarc * indicates parity, the 7th bit indicates the character 4035811Smarc * is an alphameric or underscore (for ALTWERASE), and the 4135811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 4249380Skarels * then the character needs no special processing on output; 4349380Skarels * classes other than 0 might be translated or (not currently) 4449380Skarels * require delays. 457436Skre */ 4649380Skarels #define PARITY(c) (partab[c] & 0x80) 4749380Skarels #define ISALPHA(c) (partab[(c)&TTY_CHARMASK] & 0x40) 4849380Skarels #define CCLASSMASK 0x3f 4949380Skarels #define CCLASS(c) (partab[c] & CCLASSMASK) 5039Sbill 5149380Skarels #define E 0x00 /* even parity */ 5249380Skarels #define O 0x80 /* odd parity */ 5349380Skarels #define ALPHA 0x40 /* alpha or underscore */ 5449380Skarels 5549380Skarels #define NO ORDINARY 5649380Skarels #define NA ORDINARY|ALPHA 5749380Skarels #define CC CONTROL 5849380Skarels #define BS BACKSPACE 5949380Skarels #define NL NEWLINE 6049380Skarels #define TB TAB 6149380Skarels #define VT VTAB 6249380Skarels #define CR RETURN 6349380Skarels 647436Skre char partab[] = { 6549380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 6649380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 6749380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 6849380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 6949380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 7049380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 7149380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 7249380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 7349380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 7449380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 7549380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 7649380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 7749380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 7849380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 7949380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 8049380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 817436Skre /* 8249380Skarels * "meta" chars; should be settable per charset. 8349380Skarels * For now, treat all as normal characters. 847436Skre */ 8549380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 8649380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 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, 1017436Skre }; 10249380Skarels #undef NO 10349380Skarels #undef NA 10449380Skarels #undef CC 10549380Skarels #undef BS 10649380Skarels #undef NL 10749380Skarels #undef TB 10849380Skarels #undef VT 10949380Skarels #undef CR 1107436Skre 11135811Smarc extern struct tty *constty; /* temporary virtual console */ 11235811Smarc 113146Sbill /* 11435811Smarc * Is 'c' a line delimiter ("break" character)? 11539Sbill */ 11640712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ 11740712Skarels (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 11839Sbill 11939Sbill ttychars(tp) 1209578Ssam struct tty *tp; 12139Sbill { 12247545Skarels 12335811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 12439Sbill } 12539Sbill 12639Sbill /* 12749380Skarels * Flush tty after output has drained. 12839Sbill */ 12912752Ssam ttywflush(tp) 13037584Smarc struct tty *tp; 13139Sbill { 13240712Skarels int error; 13339Sbill 13440712Skarels if ((error = ttywait(tp)) == 0) 13540712Skarels ttyflush(tp, FREAD); 13640712Skarels return (error); 13712752Ssam } 13812752Ssam 13935811Smarc /* 14035811Smarc * Wait for output to drain. 14135811Smarc */ 14212752Ssam ttywait(tp) 14312752Ssam register struct tty *tp; 14412752Ssam { 14540712Skarels int error = 0, s = spltty(); 14612752Ssam 14713809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 14837584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 14937584Smarc tp->t_oproc) { 150903Sbill (*tp->t_oproc)(tp); 1515408Swnj tp->t_state |= TS_ASLEEP; 15243377Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_outq, 15343377Smarc TTOPRI | PCATCH, ttyout, 0)) 15440712Skarels break; 155903Sbill } 1569859Ssam splx(s); 15740712Skarels return (error); 15839Sbill } 15939Sbill 16049380Skarels #define flushq(qq) { \ 16149380Skarels register struct clist *q = qq; \ 16249380Skarels if (q->c_cc) \ 16349380Skarels ndflush(q, q->c_cc); \ 16449380Skarels } 16549380Skarels 16639Sbill /* 16749380Skarels * Flush TTY read and/or write queues, 16849380Skarels * notifying anyone waiting. 16939Sbill */ 17012752Ssam ttyflush(tp, rw) 1717625Ssam register struct tty *tp; 17239Sbill { 173903Sbill register s; 174903Sbill 17517545Skarels s = spltty(); 176903Sbill if (rw & FREAD) { 17749380Skarels flushq(&tp->t_canq); 17849380Skarels flushq(&tp->t_rawq); 17949380Skarels tp->t_rocount = 0; 18049380Skarels tp->t_rocol = 0; 18149380Skarels tp->t_state &= ~TS_LOCAL; 18237584Smarc ttwakeup(tp); 183903Sbill } 184903Sbill if (rw & FWRITE) { 1855408Swnj tp->t_state &= ~TS_TTSTOP; 1865426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 18749380Skarels flushq(&tp->t_outq); 18849380Skarels wakeup((caddr_t)&tp->t_outq); 18949380Skarels if (tp->t_wsel) { 19049380Skarels selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 19149380Skarels tp->t_wsel = 0; 19249380Skarels tp->t_state &= ~TS_WCOLL; 19349380Skarels } 194903Sbill } 195903Sbill splx(s); 19639Sbill } 19739Sbill 198903Sbill /* 199903Sbill * Send stop character on input overflow. 200903Sbill */ 201903Sbill ttyblock(tp) 2027625Ssam register struct tty *tp; 20339Sbill { 204903Sbill register x; 2059578Ssam 206903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 207903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 20812752Ssam ttyflush(tp, FREAD|FWRITE); 2095408Swnj tp->t_state &= ~TS_TBLOCK; 210903Sbill } 21115118Skarels /* 21215118Skarels * Block further input iff: 21315118Skarels * Current input > threshold AND input is available to user program 21415118Skarels */ 21542350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 21640712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 21735811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 21842350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 21915118Skarels tp->t_state |= TS_TBLOCK; 22015118Skarels ttstart(tp); 22115118Skarels } 222903Sbill } 22339Sbill } 22439Sbill 22547545Skarels ttstart(tp) 22637584Smarc struct tty *tp; 227121Sbill { 228121Sbill 22947545Skarels if (tp->t_oproc) /* kludge for pty */ 23047545Skarels (*tp->t_oproc)(tp); 23147545Skarels } 23247545Skarels 23347545Skarels ttrstrt(tp) /* XXX */ 23447545Skarels struct tty *tp; 23547545Skarels { 23647545Skarels 23740712Skarels #ifdef DIAGNOSTIC 2389578Ssam if (tp == 0) 2399578Ssam panic("ttrstrt"); 24040712Skarels #endif 2415408Swnj tp->t_state &= ~TS_TIMEOUT; 242903Sbill ttstart(tp); 243121Sbill } 244121Sbill 24539Sbill 24639Sbill /* 24749380Skarels * Common code for ioctls on tty devices. 24849380Skarels * Called after line-discipline-specific ioctl 24949380Skarels * has been called to do discipline-specific functions 25049380Skarels * and/or reject any of these ioctl commands. 25139Sbill */ 2521780Sbill /*ARGSUSED*/ 2537625Ssam ttioctl(tp, com, data, flag) 2547625Ssam register struct tty *tp; 2557625Ssam caddr_t data; 25639Sbill { 25747545Skarels register struct proc *p = curproc; /* XXX */ 25839Sbill extern int nldisp; 25937554Smckusick int s, error; 26039Sbill 261903Sbill /* 262903Sbill * If the ioctl involves modification, 26317545Skarels * hang if in the background. 264903Sbill */ 2657625Ssam switch (com) { 26639Sbill 26735811Smarc case TIOCSETD: 268903Sbill case TIOCFLUSH: 26935811Smarc /*case TIOCSPGRP:*/ 2709325Ssam case TIOCSTI: 27117598Sbloom case TIOCSWINSZ: 27235811Smarc case TIOCSETA: 27335811Smarc case TIOCSETAW: 27435811Smarc case TIOCSETAF: 27540030Smarc #ifdef COMPAT_43 27640030Smarc case TIOCSETP: 27740030Smarc case TIOCSETN: 27840030Smarc case TIOCSETC: 27940030Smarc case TIOCSLTC: 28040030Smarc case TIOCLBIS: 28140030Smarc case TIOCLBIC: 28240030Smarc case TIOCLSET: 28340030Smarc case OTIOCSETD: 28440030Smarc #endif 28547545Skarels while (isbackground(curproc, tp) && 28647545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 28747545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 28847545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 28947545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 29043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 29143377Smarc TTOPRI | PCATCH, ttybg, 0)) 29240712Skarels return (error); 293903Sbill } 294903Sbill break; 295903Sbill } 296903Sbill 2979578Ssam /* 2989578Ssam * Process the ioctl. 2999578Ssam */ 3007625Ssam switch (com) { 301903Sbill 3028556Sroot /* get discipline number */ 30339Sbill case TIOCGETD: 3047625Ssam *(int *)data = tp->t_line; 30539Sbill break; 30639Sbill 3078556Sroot /* set line discipline */ 3087625Ssam case TIOCSETD: { 3097625Ssam register int t = *(int *)data; 31035811Smarc dev_t dev = tp->t_dev; 3117625Ssam 31235811Smarc if ((unsigned)t >= nldisp) 31310851Ssam return (ENXIO); 31425584Skarels if (t != tp->t_line) { 31525584Skarels s = spltty(); 31625584Skarels (*linesw[tp->t_line].l_close)(tp); 31725584Skarels error = (*linesw[t].l_open)(dev, tp); 31825584Skarels if (error) { 31935811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 32025584Skarels splx(s); 32125584Skarels return (error); 32225584Skarels } 32325584Skarels tp->t_line = t; 32410851Ssam splx(s); 32510851Ssam } 32639Sbill break; 3277625Ssam } 32839Sbill 3298556Sroot /* prevent more opens on channel */ 3305614Swnj case TIOCEXCL: 3315614Swnj tp->t_state |= TS_XCLUDE; 3325614Swnj break; 3335614Swnj 3345614Swnj case TIOCNXCL: 3355614Swnj tp->t_state &= ~TS_XCLUDE; 3365614Swnj break; 3375614Swnj 33839Sbill case TIOCHPCL: 33935811Smarc tp->t_cflag |= HUPCL; 34039Sbill break; 34139Sbill 3423942Sbugs case TIOCFLUSH: { 3437625Ssam register int flags = *(int *)data; 3447625Ssam 3457625Ssam if (flags == 0) 3463942Sbugs flags = FREAD|FWRITE; 3477625Ssam else 3487625Ssam flags &= FREAD|FWRITE; 34912752Ssam ttyflush(tp, flags); 35039Sbill break; 3513944Sbugs } 35239Sbill 35337584Smarc case FIOASYNC: 35437584Smarc if (*(int *)data) 35537584Smarc tp->t_state |= TS_ASYNC; 35637584Smarc else 35737584Smarc tp->t_state &= ~TS_ASYNC; 35837584Smarc break; 35937584Smarc 36037584Smarc case FIONBIO: 36137584Smarc break; /* XXX remove */ 36237584Smarc 3638556Sroot /* return number of characters immediately available */ 3647625Ssam case FIONREAD: 3657625Ssam *(off_t *)data = ttnread(tp); 366174Sbill break; 367174Sbill 36813077Ssam case TIOCOUTQ: 36913077Ssam *(int *)data = tp->t_outq.c_cc; 37013077Ssam break; 37113077Ssam 3728589Sroot case TIOCSTOP: 37317545Skarels s = spltty(); 3749578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3755573Swnj tp->t_state |= TS_TTSTOP; 3765573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3775573Swnj } 3787625Ssam splx(s); 3795573Swnj break; 3805573Swnj 3818589Sroot case TIOCSTART: 38217545Skarels s = spltty(); 38335811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3845573Swnj tp->t_state &= ~TS_TTSTOP; 38535811Smarc tp->t_lflag &= ~FLUSHO; 3865573Swnj ttstart(tp); 3875573Swnj } 3887625Ssam splx(s); 3895573Swnj break; 3905573Swnj 3919325Ssam /* 3929325Ssam * Simulate typing of a character at the terminal. 3939325Ssam */ 3949325Ssam case TIOCSTI: 39547545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 39617183Smckusick return (EPERM); 39747545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 3989325Ssam return (EACCES); 3999578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4009325Ssam break; 4019325Ssam 40235811Smarc case TIOCGETA: { 40335811Smarc struct termios *t = (struct termios *)data; 40412752Ssam 40535811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 40635811Smarc break; 40735811Smarc } 40835811Smarc 40935811Smarc case TIOCSETA: 41035811Smarc case TIOCSETAW: 41137584Smarc case TIOCSETAF: { 41235811Smarc register struct termios *t = (struct termios *)data; 41340712Skarels 41417545Skarels s = spltty(); 41539407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 41640712Skarels if (error = ttywait(tp)) { 41740712Skarels splx(s); 41840712Skarels return (error); 41940712Skarels } 42045007Smarc if (com == TIOCSETAF) 42139407Smarc ttyflush(tp, FREAD); 42239407Smarc } 42340712Skarels if ((t->c_cflag&CIGNORE) == 0) { 42435811Smarc /* 42535811Smarc * set device hardware 42635811Smarc */ 42737584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 42837584Smarc splx(s); 42935811Smarc return (error); 43037584Smarc } else { 43140712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 43237584Smarc (tp->t_cflag&CLOCAL) && 43340712Skarels (t->c_cflag&CLOCAL) == 0) { 43437584Smarc tp->t_state &= ~TS_ISOPEN; 43537584Smarc tp->t_state |= TS_WOPEN; 43637584Smarc ttwakeup(tp); 43737584Smarc } 43835811Smarc tp->t_cflag = t->c_cflag; 43935811Smarc tp->t_ispeed = t->c_ispeed; 44035811Smarc tp->t_ospeed = t->c_ospeed; 44134492Skarels } 44235811Smarc ttsetwater(tp); 44312752Ssam } 44439407Smarc if (com != TIOCSETAF) { 44535811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 44635811Smarc if (t->c_lflag&ICANON) { 44735811Smarc tp->t_lflag |= PENDIN; 44835811Smarc ttwakeup(tp); 44935811Smarc } 45035811Smarc else { 45135811Smarc struct clist tq; 45235811Smarc 45335811Smarc catq(&tp->t_rawq, &tp->t_canq); 45435811Smarc tq = tp->t_rawq; 45535811Smarc tp->t_rawq = tp->t_canq; 45635811Smarc tp->t_canq = tq; 45735811Smarc } 45812752Ssam } 45935811Smarc tp->t_iflag = t->c_iflag; 46035811Smarc tp->t_oflag = t->c_oflag; 46142882Smarc /* 46242882Smarc * Make the EXTPROC bit read only. 46342882Smarc */ 46442882Smarc if (tp->t_lflag&EXTPROC) 46542882Smarc t->c_lflag |= EXTPROC; 46642882Smarc else 46742882Smarc t->c_lflag &= ~EXTPROC; 46835811Smarc tp->t_lflag = t->c_lflag; 46935811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 47012752Ssam splx(s); 47112752Ssam break; 47212752Ssam } 47312752Ssam 47412752Ssam /* 47539555Smarc * Set controlling terminal. 47639555Smarc * Session ctty vnode pointer set in vnode layer. 47734492Skarels */ 47847545Skarels case TIOCSCTTY: 47939555Smarc if (!SESS_LEADER(p) || 48039555Smarc (p->p_session->s_ttyvp || tp->t_session) && 48139555Smarc (tp->t_session != p->p_session)) 48239407Smarc return (EPERM); 48335811Smarc tp->t_session = p->p_session; 48439555Smarc tp->t_pgrp = p->p_pgrp; 48539555Smarc p->p_session->s_ttyp = tp; 48639555Smarc p->p_flag |= SCTTY; 48734492Skarels break; 48839555Smarc 48934492Skarels /* 49035811Smarc * Set terminal process group. 49117545Skarels */ 49218650Sbloom case TIOCSPGRP: { 49335811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 49417545Skarels 49539555Smarc if (!isctty(p, tp)) 49639555Smarc return (ENOTTY); 49740030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 49839555Smarc return (EPERM); 49939555Smarc tp->t_pgrp = pgrp; 50012752Ssam break; 50118650Sbloom } 50212752Ssam 50312752Ssam case TIOCGPGRP: 50447545Skarels if (!isctty(p, tp)) 50539555Smarc return (ENOTTY); 50645007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 50712752Ssam break; 50812752Ssam 50917598Sbloom case TIOCSWINSZ: 51018650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 51118650Sbloom sizeof (struct winsize))) { 51217598Sbloom tp->t_winsize = *(struct winsize *)data; 51342882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 51417598Sbloom } 51517598Sbloom break; 51617598Sbloom 51717598Sbloom case TIOCGWINSZ: 51817598Sbloom *(struct winsize *)data = tp->t_winsize; 51917598Sbloom break; 52017598Sbloom 52130534Skarels case TIOCCONS: 52230534Skarels if (*(int *)data) { 52342141Smckusick if (constty && constty != tp && 52442141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 52542141Smckusick (TS_CARR_ON|TS_ISOPEN)) 52630534Skarels return (EBUSY); 52730534Skarels #ifndef UCONSOLE 52847545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 52937554Smckusick return (error); 53030534Skarels #endif 53130534Skarels constty = tp; 53230534Skarels } else if (tp == constty) 53333404Skarels constty = NULL; 53430534Skarels break; 53530534Skarels 53648439Skarels case TIOCDRAIN: 53748439Skarels if (error = ttywait(tp)) 53848439Skarels return (error); 53948439Skarels break; 54048439Skarels 54147545Skarels default: 54235811Smarc #ifdef COMPAT_43 54347545Skarels return (ttcompat(tp, com, data, flag)); 54447545Skarels #else 54547545Skarels return (-1); 54635811Smarc #endif 54739Sbill } 5488556Sroot return (0); 54939Sbill } 5504484Swnj 5514484Swnj ttnread(tp) 5524484Swnj struct tty *tp; 5534484Swnj { 5544484Swnj int nread = 0; 5554484Swnj 55635811Smarc if (tp->t_lflag & PENDIN) 5574484Swnj ttypend(tp); 5584484Swnj nread = tp->t_canq.c_cc; 55935811Smarc if ((tp->t_lflag & ICANON) == 0) 5604484Swnj nread += tp->t_rawq.c_cc; 5614484Swnj return (nread); 5624484Swnj } 5634484Swnj 5645408Swnj ttselect(dev, rw) 5654484Swnj dev_t dev; 5665408Swnj int rw; 5674484Swnj { 5684484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5694484Swnj int nread; 57017545Skarels int s = spltty(); 5714484Swnj 5725408Swnj switch (rw) { 5734484Swnj 5744484Swnj case FREAD: 5754484Swnj nread = ttnread(tp); 57637584Smarc if (nread > 0 || 57740712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 5785408Swnj goto win; 5794938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5805408Swnj tp->t_state |= TS_RCOLL; 5814484Swnj else 58247545Skarels tp->t_rsel = curproc; 5835408Swnj break; 5844484Swnj 5855408Swnj case FWRITE: 58635811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5875408Swnj goto win; 5885408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5895408Swnj tp->t_state |= TS_WCOLL; 5905408Swnj else 59147545Skarels tp->t_wsel = curproc; 5925408Swnj break; 5934484Swnj } 5945408Swnj splx(s); 5955408Swnj return (0); 5965408Swnj win: 5975408Swnj splx(s); 5985408Swnj return (1); 5994484Swnj } 6007436Skre 6017502Sroot /* 60249380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6037502Sroot */ 6047502Sroot ttyopen(dev, tp) 6057625Ssam dev_t dev; 6067625Ssam register struct tty *tp; 6077502Sroot { 6087502Sroot 6097502Sroot tp->t_dev = dev; 61035811Smarc 6117502Sroot tp->t_state &= ~TS_WOPEN; 61217545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 61317545Skarels tp->t_state |= TS_ISOPEN; 61417598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 61517545Skarels } 6168556Sroot return (0); 6177502Sroot } 6187502Sroot 6197502Sroot /* 62025391Skarels * "close" a line discipline 62125391Skarels */ 62225391Skarels ttylclose(tp) 62325391Skarels register struct tty *tp; 62425391Skarels { 62525391Skarels 62625391Skarels ttywflush(tp); 62725391Skarels } 62825391Skarels 62925391Skarels /* 63049380Skarels * Handle close() on a tty line: flush and set to initial state, 63149380Skarels * bumping generation number so that pending read/write calls 63249380Skarels * can detect recycling of the tty. 6337502Sroot */ 6347502Sroot ttyclose(tp) 6357625Ssam register struct tty *tp; 6367502Sroot { 63730534Skarels if (constty == tp) 63830534Skarels constty = NULL; 63925391Skarels ttyflush(tp, FREAD|FWRITE); 64039555Smarc tp->t_session = NULL; 64139555Smarc tp->t_pgrp = NULL; 6427502Sroot tp->t_state = 0; 64343377Smarc tp->t_gen++; 64440712Skarels return (0); 6457502Sroot } 6467502Sroot 6477502Sroot /* 64825391Skarels * Handle modem control transition on a tty. 64925391Skarels * Flag indicates new state of carrier. 65025391Skarels * Returns 0 if the line should be turned off, otherwise 1. 65125391Skarels */ 65225391Skarels ttymodem(tp, flag) 65325391Skarels register struct tty *tp; 65425391Skarels { 65525391Skarels 65642193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 65725391Skarels /* 65825391Skarels * MDMBUF: do flow control according to carrier flag 65925391Skarels */ 66025391Skarels if (flag) { 66125391Skarels tp->t_state &= ~TS_TTSTOP; 66225391Skarels ttstart(tp); 66325391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 66425391Skarels tp->t_state |= TS_TTSTOP; 66525391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 66625391Skarels } 66725391Skarels } else if (flag == 0) { 66825391Skarels /* 66925391Skarels * Lost carrier. 67025391Skarels */ 67125391Skarels tp->t_state &= ~TS_CARR_ON; 67242193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 67342193Smarc if (tp->t_session && tp->t_session->s_leader) 67442193Smarc psignal(tp->t_session->s_leader, SIGHUP); 67542193Smarc ttyflush(tp, FREAD|FWRITE); 67642193Smarc return (0); 67725391Skarels } 67825391Skarels } else { 67925391Skarels /* 68025391Skarels * Carrier now on. 68125391Skarels */ 68225391Skarels tp->t_state |= TS_CARR_ON; 68337584Smarc ttwakeup(tp); 68425391Skarels } 68525391Skarels return (1); 68625391Skarels } 68725391Skarels 68825391Skarels /* 68925404Skarels * Default modem control routine (for other line disciplines). 69025404Skarels * Return argument flag, to turn off device on carrier drop. 69125404Skarels */ 69225415Skarels nullmodem(tp, flag) 69325415Skarels register struct tty *tp; 69425404Skarels int flag; 69525404Skarels { 69625404Skarels 69725404Skarels if (flag) 69825404Skarels tp->t_state |= TS_CARR_ON; 69939407Smarc else { 70025404Skarels tp->t_state &= ~TS_CARR_ON; 70142193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 70242193Smarc if (tp->t_session && tp->t_session->s_leader) 70342193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70442193Smarc return (0); 70542193Smarc } 70639407Smarc } 70742193Smarc return (1); 70825404Skarels } 70925404Skarels 71025404Skarels /* 7117502Sroot * reinput pending characters after state switch 71217545Skarels * call at spltty(). 7137502Sroot */ 7147502Sroot ttypend(tp) 7157625Ssam register struct tty *tp; 7167502Sroot { 7177502Sroot struct clist tq; 7187502Sroot register c; 7197502Sroot 72035811Smarc tp->t_lflag &= ~PENDIN; 7219578Ssam tp->t_state |= TS_TYPEN; 7227502Sroot tq = tp->t_rawq; 7237502Sroot tp->t_rawq.c_cc = 0; 7247502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7257502Sroot while ((c = getc(&tq)) >= 0) 7267502Sroot ttyinput(c, tp); 7279578Ssam tp->t_state &= ~TS_TYPEN; 7287502Sroot } 7297502Sroot 7307502Sroot /* 73149380Skarels * Process input of a single character received on a tty. 7327502Sroot */ 7337502Sroot ttyinput(c, tp) 7347625Ssam register c; 7357625Ssam register struct tty *tp; 7367502Sroot { 73735811Smarc register int iflag = tp->t_iflag; 73835811Smarc register int lflag = tp->t_lflag; 73935811Smarc register u_char *cc = tp->t_cc; 74035811Smarc int i, err; 7417502Sroot 7429578Ssam /* 7439578Ssam * If input is pending take it first. 7449578Ssam */ 74535811Smarc if (lflag&PENDIN) 7467502Sroot ttypend(tp); 74735811Smarc /* 74835811Smarc * Gather stats. 74935811Smarc */ 7507502Sroot tk_nin++; 75135811Smarc if (lflag&ICANON) { 75235811Smarc tk_cancc++; 75335811Smarc tp->t_cancc++; 75435811Smarc } else { 75535811Smarc tk_rawcc++; 75635811Smarc tp->t_rawcc++; 75735811Smarc } 7589578Ssam /* 75935811Smarc * Handle exceptional conditions (break, parity, framing). 7609578Ssam */ 76135811Smarc if (err = (c&TTY_ERRORMASK)) { 76235811Smarc c &= ~TTY_ERRORMASK; 76335811Smarc if (err&TTY_FE && !c) { /* break */ 76435811Smarc if (iflag&IGNBRK) 76535811Smarc goto endcase; 76635811Smarc else if (iflag&BRKINT && lflag&ISIG && 76735811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 76835811Smarc c = cc[VINTR]; 76947545Skarels else if (iflag&PARMRK) 77047545Skarels goto parmrk; 77135811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 77235811Smarc if (iflag&IGNPAR) 77335811Smarc goto endcase; 77435811Smarc else if (iflag&PARMRK) { 77535811Smarc parmrk: 77635811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 77735811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 77835811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 77935811Smarc goto endcase; 78035811Smarc } else 78135811Smarc c = 0; 7827502Sroot } 7839578Ssam } 7849578Ssam /* 78535811Smarc * In tandem mode, check high water mark. 7869578Ssam */ 78735811Smarc if (iflag&IXOFF) 78835811Smarc ttyblock(tp); 78935811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 79049380Skarels c &= ~0x80; 79144419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 79244419Smarc /* 79344419Smarc * Check for literal nexting very first 79444419Smarc */ 79544419Smarc if (tp->t_state&TS_LNCH) { 79644419Smarc c |= TTY_QUOTE; 79744419Smarc tp->t_state &= ~TS_LNCH; 79844419Smarc } 79944419Smarc /* 80044419Smarc * Scan for special characters. This code 80144419Smarc * is really just a big case statement with 80244419Smarc * non-constant cases. The bottom of the 80344419Smarc * case statement is labeled ``endcase'', so goto 80444419Smarc * it after a case match, or similar. 80544419Smarc */ 80644419Smarc 80744419Smarc /* 80844419Smarc * Control chars which aren't controlled 80944419Smarc * by ICANON, ISIG, or IXON. 81044419Smarc */ 81144419Smarc if (lflag&IEXTEN) { 81244419Smarc if (CCEQ(cc[VLNEXT], c)) { 81344419Smarc if (lflag&ECHO) { 81444419Smarc if (lflag&ECHOE) 81544419Smarc ttyoutstr("^\b", tp); 81644419Smarc else 81744419Smarc ttyecho(c, tp); 81844419Smarc } 81944419Smarc tp->t_state |= TS_LNCH; 82044419Smarc goto endcase; 82144419Smarc } 82244419Smarc if (CCEQ(cc[VDISCARD], c)) { 82344419Smarc if (lflag&FLUSHO) 82444419Smarc tp->t_lflag &= ~FLUSHO; 82544419Smarc else { 82644419Smarc ttyflush(tp, FWRITE); 82735811Smarc ttyecho(c, tp); 82844419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 82944419Smarc ttyretype(tp); 83044419Smarc tp->t_lflag |= FLUSHO; 83144419Smarc } 83244419Smarc goto startoutput; 83335811Smarc } 8349578Ssam } 83544419Smarc /* 83644419Smarc * Signals. 83744419Smarc */ 83844419Smarc if (lflag&ISIG) { 83944419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 84044419Smarc if ((lflag&NOFLSH) == 0) 84144419Smarc ttyflush(tp, FREAD|FWRITE); 8427502Sroot ttyecho(c, tp); 84344419Smarc pgsignal(tp->t_pgrp, 84444419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 84544419Smarc goto endcase; 8467502Sroot } 84744419Smarc if (CCEQ(cc[VSUSP], c)) { 84844419Smarc if ((lflag&NOFLSH) == 0) 84944419Smarc ttyflush(tp, FREAD); 85044419Smarc ttyecho(c, tp); 85144419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 85244419Smarc goto endcase; 85344419Smarc } 8549578Ssam } 85544419Smarc /* 85644419Smarc * Handle start/stop characters. 85744419Smarc */ 85844419Smarc if (iflag&IXON) { 85944419Smarc if (CCEQ(cc[VSTOP], c)) { 86044419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 86144419Smarc tp->t_state |= TS_TTSTOP; 86244419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 86344419Smarc 0); 86444419Smarc return; 86544419Smarc } 86644419Smarc if (!CCEQ(cc[VSTART], c)) 86744419Smarc return; 86844419Smarc /* 86944419Smarc * if VSTART == VSTOP then toggle 87044419Smarc */ 87144419Smarc goto endcase; 87235811Smarc } 87344419Smarc if (CCEQ(cc[VSTART], c)) 87444419Smarc goto restartoutput; 8759578Ssam } 87644419Smarc /* 87744419Smarc * IGNCR, ICRNL, & INLCR 87844419Smarc */ 87944419Smarc if (c == '\r') { 88044419Smarc if (iflag&IGNCR) 88144419Smarc goto endcase; 88244419Smarc else if (iflag&ICRNL) 88344419Smarc c = '\n'; 88444419Smarc } else if (c == '\n' && iflag&INLCR) 88544419Smarc c = '\r'; 8869578Ssam } 88747545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 88844419Smarc /* 88944419Smarc * From here on down canonical mode character 89044419Smarc * processing takes place. 89144419Smarc */ 89244419Smarc /* 89344419Smarc * erase (^H / ^?) 89444419Smarc */ 89544419Smarc if (CCEQ(cc[VERASE], c)) { 89644419Smarc if (tp->t_rawq.c_cc) 8979578Ssam ttyrub(unputc(&tp->t_rawq), tp); 89844419Smarc goto endcase; 8999578Ssam } 90044419Smarc /* 90144419Smarc * kill (^U) 90244419Smarc */ 90344419Smarc if (CCEQ(cc[VKILL], c)) { 90444419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 90544419Smarc (lflag&ECHOPRT) == 0) { 90644419Smarc while (tp->t_rawq.c_cc) 90744419Smarc ttyrub(unputc(&tp->t_rawq), tp); 90844419Smarc } else { 90944419Smarc ttyecho(c, tp); 91044419Smarc if (lflag&ECHOK || lflag&ECHOKE) 91144419Smarc ttyecho('\n', tp); 91244419Smarc while (getc(&tp->t_rawq) > 0) 91344419Smarc ; 91444419Smarc tp->t_rocount = 0; 91544419Smarc } 91644419Smarc tp->t_state &= ~TS_LOCAL; 91744419Smarc goto endcase; 91844419Smarc } 91944419Smarc /* 92044419Smarc * word erase (^W) 92144419Smarc */ 92244419Smarc if (CCEQ(cc[VWERASE], c)) { 92344419Smarc int ctype; 92447545Skarels int alt = lflag&ALTWERASE; 92535811Smarc 92644419Smarc /* 92744419Smarc * erase whitespace 92844419Smarc */ 92944419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 93044419Smarc ttyrub(c, tp); 93144419Smarc if (c == -1) 93244419Smarc goto endcase; 93344419Smarc /* 93447545Skarels * erase last char of word and remember the 93547545Skarels * next chars type (for ALTWERASE) 93644419Smarc */ 93735811Smarc ttyrub(c, tp); 93844419Smarc c = unputc(&tp->t_rawq); 93947545Skarels if (c == -1) 94044419Smarc goto endcase; 94149380Skarels ctype = ISALPHA(c); 94244419Smarc /* 94347545Skarels * erase rest of word 94444419Smarc */ 94544419Smarc do { 94644419Smarc ttyrub(c, tp); 94744419Smarc c = unputc(&tp->t_rawq); 94844419Smarc if (c == -1) 94944419Smarc goto endcase; 95047545Skarels } while (c != ' ' && c != '\t' && 95149380Skarels (alt == 0 || ISALPHA(c) == ctype)); 95244419Smarc (void) putc(c, &tp->t_rawq); 95334492Skarels goto endcase; 95444419Smarc } 95535811Smarc /* 95644419Smarc * reprint line (^R) 95735811Smarc */ 95844419Smarc if (CCEQ(cc[VREPRINT], c)) { 95944419Smarc ttyretype(tp); 96034492Skarels goto endcase; 96134492Skarels } 96235811Smarc /* 96344419Smarc * ^T - kernel info and generate SIGINFO 96435811Smarc */ 96544419Smarc if (CCEQ(cc[VSTATUS], c)) { 96644419Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 96744419Smarc if ((lflag&NOKERNINFO) == 0) 96844419Smarc ttyinfo(tp); 96944419Smarc goto endcase; 97044419Smarc } 9719578Ssam } 9729578Ssam /* 9739578Ssam * Check for input buffer overflow 9749578Ssam */ 97547545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 97635811Smarc if (iflag&IMAXBEL) { 97735811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 97835811Smarc (void) ttyoutput(CTRL('g'), tp); 97935811Smarc } else 98035811Smarc ttyflush(tp, FREAD | FWRITE); 9819578Ssam goto endcase; 98210391Ssam } 9839578Ssam /* 9849578Ssam * Put data char in q for user and 9859578Ssam * wakeup on seeing a line delimiter. 9869578Ssam */ 9879578Ssam if (putc(c, &tp->t_rawq) >= 0) { 98847545Skarels if ((lflag&ICANON) == 0) { 98947545Skarels ttwakeup(tp); 99047545Skarels ttyecho(c, tp); 99147545Skarels goto endcase; 99247545Skarels } 99335811Smarc if (ttbreakc(c)) { 9949578Ssam tp->t_rocount = 0; 9959578Ssam catq(&tp->t_rawq, &tp->t_canq); 9967502Sroot ttwakeup(tp); 9979578Ssam } else if (tp->t_rocount++ == 0) 9989578Ssam tp->t_rocol = tp->t_col; 9999578Ssam if (tp->t_state&TS_ERASE) { 100035811Smarc /* 100135811Smarc * end of prterase \.../ 100235811Smarc */ 10039578Ssam tp->t_state &= ~TS_ERASE; 10049578Ssam (void) ttyoutput('/', tp); 10059578Ssam } 10069578Ssam i = tp->t_col; 10077502Sroot ttyecho(c, tp); 100835811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 100935811Smarc /* 101035811Smarc * Place the cursor over the '^' of the ^D. 101135811Smarc */ 10129578Ssam i = MIN(2, tp->t_col - i); 10139578Ssam while (i > 0) { 10149578Ssam (void) ttyoutput('\b', tp); 10159578Ssam i--; 10169578Ssam } 10179578Ssam } 10187502Sroot } 10199578Ssam endcase: 10209578Ssam /* 102135811Smarc * IXANY means allow any character to restart output. 10229578Ssam */ 102340712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 102440712Skarels cc[VSTART] != cc[VSTOP]) 10257502Sroot return; 10269578Ssam restartoutput: 10277502Sroot tp->t_state &= ~TS_TTSTOP; 102835811Smarc tp->t_lflag &= ~FLUSHO; 10299578Ssam startoutput: 10307502Sroot ttstart(tp); 10317502Sroot } 10327502Sroot 10337502Sroot /* 103449380Skarels * Output a single character on a tty, doing output processing 103549380Skarels * as needed (expanding tabs, newline processing, etc.). 103649380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10377502Sroot * Must be recursive. 10387502Sroot */ 10397502Sroot ttyoutput(c, tp) 10407502Sroot register c; 10417502Sroot register struct tty *tp; 10427502Sroot { 104349380Skarels register int col; 104435811Smarc register long oflag = tp->t_oflag; 104535811Smarc 104640712Skarels if ((oflag&OPOST) == 0) { 104735811Smarc if (tp->t_lflag&FLUSHO) 10487502Sroot return (-1); 10497502Sroot if (putc(c, &tp->t_outq)) 10507625Ssam return (c); 10517502Sroot tk_nout++; 105235811Smarc tp->t_outcc++; 10537502Sroot return (-1); 10547502Sroot } 105535811Smarc c &= TTY_CHARMASK; 10567502Sroot /* 105749380Skarels * Do tab expansion if OXTABS is set. 105842882Smarc * Special case if we have external processing, we don't 105942882Smarc * do the tab expansion because we'll probably get it 106042882Smarc * wrong. If tab expansion needs to be done, let it 106142882Smarc * happen externally. 10627502Sroot */ 106347545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 10647502Sroot register int s; 10657502Sroot 10667502Sroot c = 8 - (tp->t_col&7); 106735811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 106817545Skarels s = spltty(); /* don't interrupt tabs */ 10697502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10707502Sroot tk_nout += c; 107135811Smarc tp->t_outcc += c; 10727502Sroot splx(s); 10737502Sroot } 10747502Sroot tp->t_col += c; 10757502Sroot return (c ? -1 : '\t'); 10767502Sroot } 107735811Smarc if (c == CEOT && oflag&ONOEOT) 107847545Skarels return (-1); 10797502Sroot tk_nout++; 108035811Smarc tp->t_outcc++; 10817502Sroot /* 108249380Skarels * Newline translation: if ONLCR is set, 108349380Skarels * translate newline into "\r\n". 10847502Sroot */ 108535811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10867502Sroot return (c); 108735811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 108835811Smarc return (c); 108947545Skarels 109049380Skarels col = tp->t_col; 109149380Skarels switch (CCLASS(c)) { 10927502Sroot 10937502Sroot case ORDINARY: 109449380Skarels col++; 10957502Sroot 10967502Sroot case CONTROL: 10977502Sroot break; 10987502Sroot 10997502Sroot case BACKSPACE: 110049380Skarels if (col > 0) 110149380Skarels col--; 11027502Sroot break; 11037502Sroot 11047502Sroot case NEWLINE: 110549380Skarels col = 0; 11067502Sroot break; 11077502Sroot 11087502Sroot case TAB: 110949380Skarels col = (col + 8) &~ 0x7; 11107502Sroot break; 11117502Sroot 11127502Sroot case RETURN: 111349380Skarels col = 0; 11147502Sroot } 111549380Skarels tp->t_col = col; 11167502Sroot return (-1); 11177502Sroot } 11187502Sroot 11197502Sroot /* 112049380Skarels * Process a read call on a tty device. 11217502Sroot */ 112237584Smarc ttread(tp, uio, flag) 11237625Ssam register struct tty *tp; 11247722Swnj struct uio *uio; 11257502Sroot { 11267502Sroot register struct clist *qp; 112735811Smarc register int c; 112841383Smarc register long lflag; 112935811Smarc register u_char *cc = tp->t_cc; 113047545Skarels register struct proc *p = curproc; 11319859Ssam int s, first, error = 0; 11327502Sroot 11337502Sroot loop: 113441383Smarc lflag = tp->t_lflag; 113537584Smarc s = spltty(); 11369578Ssam /* 113737584Smarc * take pending input first 11389578Ssam */ 113935811Smarc if (lflag&PENDIN) 11407502Sroot ttypend(tp); 11419859Ssam splx(s); 114240712Skarels 11439578Ssam /* 11449578Ssam * Hang process if it's in the background. 11459578Ssam */ 114647545Skarels if (isbackground(p, tp)) { 114747545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 114847545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 114947545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11508520Sroot return (EIO); 115147545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 115243377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 115343377Smarc ttybg, 0)) 115440712Skarels return (error); 115523165Sbloom goto loop; 11567502Sroot } 115740712Skarels 11589578Ssam /* 115935811Smarc * If canonical, use the canonical queue, 116035811Smarc * else use the raw queue. 116137584Smarc * 116247545Skarels * (should get rid of clists...) 11639578Ssam */ 116435811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 116540712Skarels 11669578Ssam /* 116740712Skarels * If there is no input, sleep on rawq 116840712Skarels * awaiting hardware receipt and notification. 116940712Skarels * If we have data, we don't need to check for carrier. 11709578Ssam */ 117117545Skarels s = spltty(); 11729578Ssam if (qp->c_cc <= 0) { 117340712Skarels int carrier; 117440712Skarels 117540712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 117640712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 11779859Ssam splx(s); 117840712Skarels return (0); /* EOF */ 11797502Sroot } 118037728Smckusick if (flag & IO_NDELAY) { 118137584Smarc splx(s); 118237584Smarc return (EWOULDBLOCK); 118337584Smarc } 118443377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 118540712Skarels carrier ? ttyin : ttopen, 0); 11869859Ssam splx(s); 118743377Smarc if (error) 118840712Skarels return (error); 11899578Ssam goto loop; 11909578Ssam } 11919859Ssam splx(s); 119240712Skarels 11939578Ssam /* 119435811Smarc * Input present, check for input mapping and processing. 11959578Ssam */ 11969578Ssam first = 1; 11979578Ssam while ((c = getc(qp)) >= 0) { 11989578Ssam /* 119935811Smarc * delayed suspend (^Y) 12009578Ssam */ 120135811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 120242882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12039578Ssam if (first) { 120443377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 120543377Smarc TTIPRI | PCATCH, ttybg, 0)) 120640712Skarels break; 12079578Ssam goto loop; 12089578Ssam } 12099578Ssam break; 12107502Sroot } 12119578Ssam /* 121235811Smarc * Interpret EOF only in canonical mode. 12139578Ssam */ 121435811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12159578Ssam break; 12169578Ssam /* 12179578Ssam * Give user character. 12189578Ssam */ 121940712Skarels error = ureadc(c, uio); 12209578Ssam if (error) 12219578Ssam break; 122214938Smckusick if (uio->uio_resid == 0) 12239578Ssam break; 12249578Ssam /* 122535811Smarc * In canonical mode check for a "break character" 12269578Ssam * marking the end of a "line of input". 12279578Ssam */ 122840712Skarels if (lflag&ICANON && ttbreakc(c)) 12299578Ssam break; 12309578Ssam first = 0; 12317502Sroot } 12329578Ssam /* 12339578Ssam * Look to unblock output now that (presumably) 12349578Ssam * the input queue has gone down. 12359578Ssam */ 123635811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 123747545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 123847545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12397502Sroot tp->t_state &= ~TS_TBLOCK; 12407502Sroot ttstart(tp); 12417502Sroot } 124235811Smarc } 12438520Sroot return (error); 12447502Sroot } 12457502Sroot 12467502Sroot /* 124725391Skarels * Check the output queue on tp for space for a kernel message 124825391Skarels * (from uprintf/tprintf). Allow some space over the normal 124925391Skarels * hiwater mark so we don't lose messages due to normal flow 125025391Skarels * control, but don't let the tty run amok. 125130695Skarels * Sleeps here are not interruptible, but we return prematurely 125230695Skarels * if new signals come in. 125325391Skarels */ 125425391Skarels ttycheckoutq(tp, wait) 125525391Skarels register struct tty *tp; 125625391Skarels int wait; 125725391Skarels { 125830695Skarels int hiwat, s, oldsig; 125948439Skarels extern int wakeup(); 126025391Skarels 126135811Smarc hiwat = tp->t_hiwat; 126225391Skarels s = spltty(); 126347545Skarels oldsig = curproc->p_sig; 126425391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126529946Skarels while (tp->t_outq.c_cc > hiwat) { 126629946Skarels ttstart(tp); 126747545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 126829946Skarels splx(s); 126929946Skarels return (0); 127029946Skarels } 127130695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 127229946Skarels tp->t_state |= TS_ASLEEP; 127330695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 127425391Skarels } 127525391Skarels splx(s); 127625391Skarels return (1); 127725391Skarels } 127825391Skarels 127925391Skarels /* 128049380Skarels * Process a write call on a tty device. 12817502Sroot */ 128237584Smarc ttwrite(tp, uio, flag) 12837625Ssam register struct tty *tp; 12849578Ssam register struct uio *uio; 12857502Sroot { 12867502Sroot register char *cp; 128740712Skarels register int cc = 0, ce; 128847545Skarels register struct proc *p = curproc; 12899578Ssam int i, hiwat, cnt, error, s; 12907502Sroot char obuf[OBUFSIZ]; 12917502Sroot 129235811Smarc hiwat = tp->t_hiwat; 12939578Ssam cnt = uio->uio_resid; 12949578Ssam error = 0; 12957502Sroot loop: 129637584Smarc s = spltty(); 129740712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 129837584Smarc if (tp->t_state&TS_ISOPEN) { 129937584Smarc splx(s); 130037584Smarc return (EIO); 130137728Smckusick } else if (flag & IO_NDELAY) { 130237584Smarc splx(s); 130340712Skarels error = EWOULDBLOCK; 130440712Skarels goto out; 130537584Smarc } else { 130637584Smarc /* 130737584Smarc * sleep awaiting carrier 130837584Smarc */ 130943377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 131043377Smarc TTIPRI | PCATCH,ttopen, 0); 131137584Smarc splx(s); 131243377Smarc if (error) 131340712Skarels goto out; 131437584Smarc goto loop; 131537584Smarc } 131637584Smarc } 131737584Smarc splx(s); 13189578Ssam /* 13199578Ssam * Hang the process if it's in the background. 13209578Ssam */ 132147545Skarels if (isbackground(p, tp) && 132247545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 132347545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 132447545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 132547545Skarels p->p_pgrp->pg_jobc) { 132647545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 132743377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 132843377Smarc ttybg, 0)) 132940712Skarels goto out; 133021776Sbloom goto loop; 13317502Sroot } 13329578Ssam /* 13339578Ssam * Process the user's data in at most OBUFSIZ 133440712Skarels * chunks. Perform any output translation. 133540712Skarels * Keep track of high water mark, sleep on overflow 133640712Skarels * awaiting device aid in acquiring new space. 13379578Ssam */ 133840712Skarels while (uio->uio_resid > 0 || cc > 0) { 133940712Skarels if (tp->t_lflag&FLUSHO) { 134040712Skarels uio->uio_resid = 0; 134140712Skarels return (0); 134240712Skarels } 134340712Skarels if (tp->t_outq.c_cc > hiwat) 134432067Skarels goto ovhiwat; 13459578Ssam /* 134640712Skarels * Grab a hunk of data from the user, 134740712Skarels * unless we have some leftover from last time. 13489578Ssam */ 13497822Sroot if (cc == 0) { 135040712Skarels cc = min(uio->uio_resid, OBUFSIZ); 135140712Skarels cp = obuf; 135240712Skarels error = uiomove(cp, cc, uio); 135340712Skarels if (error) { 135440712Skarels cc = 0; 135540712Skarels break; 135640712Skarels } 13577822Sroot } 13589578Ssam /* 13599578Ssam * If nothing fancy need be done, grab those characters we 13609578Ssam * can handle without any of ttyoutput's processing and 13619578Ssam * just transfer them to the output q. For those chars 13629578Ssam * which require special processing (as indicated by the 13639578Ssam * bits in partab), call ttyoutput. After processing 13649578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13659578Ssam * immediately. 13669578Ssam */ 13679578Ssam while (cc > 0) { 136840712Skarels if ((tp->t_oflag&OPOST) == 0) 13697502Sroot ce = cc; 13707502Sroot else { 137134492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 137249380Skarels (u_char *)partab, CCLASSMASK); 13739578Ssam /* 13749578Ssam * If ce is zero, then we're processing 13759578Ssam * a special character through ttyoutput. 13769578Ssam */ 13779578Ssam if (ce == 0) { 13787502Sroot tp->t_rocount = 0; 13797502Sroot if (ttyoutput(*cp, tp) >= 0) { 138021776Sbloom /* no c-lists, wait a bit */ 138121776Sbloom ttstart(tp); 138243377Smarc if (error = ttysleep(tp, 138343377Smarc (caddr_t)&lbolt, 138443377Smarc TTOPRI | PCATCH, ttybuf, 0)) 138540712Skarels break; 138621776Sbloom goto loop; 13877502Sroot } 13889578Ssam cp++, cc--; 138935811Smarc if ((tp->t_lflag&FLUSHO) || 13909578Ssam tp->t_outq.c_cc > hiwat) 13917502Sroot goto ovhiwat; 13929578Ssam continue; 13937502Sroot } 13947502Sroot } 13959578Ssam /* 13969578Ssam * A bunch of normal characters have been found, 13979578Ssam * transfer them en masse to the output queue and 13989578Ssam * continue processing at the top of the loop. 13999578Ssam * If there are any further characters in this 14009578Ssam * <= OBUFSIZ chunk, the first should be a character 14019578Ssam * requiring special handling by ttyoutput. 14029578Ssam */ 14037502Sroot tp->t_rocount = 0; 14049578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14059578Ssam ce -= i; 14069578Ssam tp->t_col += ce; 14079578Ssam cp += ce, cc -= ce, tk_nout += ce; 140835811Smarc tp->t_outcc += ce; 14099578Ssam if (i > 0) { 14109578Ssam /* out of c-lists, wait a bit */ 14117502Sroot ttstart(tp); 141243377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 141343377Smarc TTOPRI | PCATCH, ttybuf, 0)) 141440712Skarels break; 141521776Sbloom goto loop; 14167502Sroot } 141735811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 141840712Skarels break; 14197502Sroot } 142035811Smarc ttstart(tp); 14217502Sroot } 142240712Skarels out: 142340712Skarels /* 142440712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 142540712Skarels * as the offset and iov pointers have moved forward, 142640712Skarels * but it doesn't matter (the call will either return short 142740712Skarels * or restart with a new uio). 142840712Skarels */ 142940712Skarels uio->uio_resid += cc; 14308520Sroot return (error); 143140712Skarels 14327502Sroot ovhiwat: 143332067Skarels ttstart(tp); 143432067Skarels s = spltty(); 14359578Ssam /* 143635811Smarc * This can only occur if FLUSHO is set in t_lflag, 143732067Skarels * or if ttstart/oproc is synchronous (or very fast). 14389578Ssam */ 14397502Sroot if (tp->t_outq.c_cc <= hiwat) { 14409578Ssam splx(s); 14417502Sroot goto loop; 14427502Sroot } 144337728Smckusick if (flag & IO_NDELAY) { 144417545Skarels splx(s); 144540712Skarels uio->uio_resid += cc; 14467822Sroot if (uio->uio_resid == cnt) 14478520Sroot return (EWOULDBLOCK); 14488520Sroot return (0); 14497502Sroot } 14507502Sroot tp->t_state |= TS_ASLEEP; 145143377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14529578Ssam splx(s); 145343377Smarc if (error) 145440712Skarels goto out; 14557502Sroot goto loop; 14567502Sroot } 14577502Sroot 14587502Sroot /* 14597502Sroot * Rubout one character from the rawq of tp 14607502Sroot * as cleanly as possible. 14617502Sroot */ 14627502Sroot ttyrub(c, tp) 14637625Ssam register c; 14647625Ssam register struct tty *tp; 14657502Sroot { 14667502Sroot register char *cp; 14677502Sroot register int savecol; 14687502Sroot int s; 14697502Sroot char *nextc(); 14707502Sroot 147142882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 14727502Sroot return; 147335811Smarc tp->t_lflag &= ~FLUSHO; 147435811Smarc if (tp->t_lflag&ECHOE) { 14757502Sroot if (tp->t_rocount == 0) { 14767502Sroot /* 14777502Sroot * Screwed by ttwrite; retype 14787502Sroot */ 14797502Sroot ttyretype(tp); 14807502Sroot return; 14817502Sroot } 148235811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 14837502Sroot ttyrubo(tp, 2); 148449380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 14857502Sroot 14867502Sroot case ORDINARY: 148735811Smarc ttyrubo(tp, 1); 14887502Sroot break; 14897502Sroot 14907502Sroot case VTAB: 14917502Sroot case BACKSPACE: 14927502Sroot case CONTROL: 14937502Sroot case RETURN: 149447545Skarels case NEWLINE: 149535811Smarc if (tp->t_lflag&ECHOCTL) 14967502Sroot ttyrubo(tp, 2); 14977502Sroot break; 14987502Sroot 149935811Smarc case TAB: { 150035811Smarc int c; 150135811Smarc 15027502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15037502Sroot ttyretype(tp); 15047502Sroot return; 15057502Sroot } 150617545Skarels s = spltty(); 15077502Sroot savecol = tp->t_col; 15089578Ssam tp->t_state |= TS_CNTTB; 150935811Smarc tp->t_lflag |= FLUSHO; 15107502Sroot tp->t_col = tp->t_rocol; 15119578Ssam cp = tp->t_rawq.c_cf; 151239407Smarc if (cp) 151339407Smarc c = *cp; /* XXX FIX NEXTC */ 151435811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 151535811Smarc ttyecho(c, tp); 151635811Smarc tp->t_lflag &= ~FLUSHO; 15179578Ssam tp->t_state &= ~TS_CNTTB; 15187502Sroot splx(s); 15197502Sroot /* 15207502Sroot * savecol will now be length of the tab 15217502Sroot */ 15227502Sroot savecol -= tp->t_col; 15237502Sroot tp->t_col += savecol; 15247502Sroot if (savecol > 8) 15257502Sroot savecol = 8; /* overflow screw */ 15267502Sroot while (--savecol >= 0) 15277502Sroot (void) ttyoutput('\b', tp); 15287502Sroot break; 152935811Smarc } 15307502Sroot 15317502Sroot default: 153237584Smarc /* XXX */ 153335811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 153449380Skarels c, CCLASS(c)); 153535811Smarc /*panic("ttyrub");*/ 15367502Sroot } 153735811Smarc } else if (tp->t_lflag&ECHOPRT) { 15389578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15397502Sroot (void) ttyoutput('\\', tp); 15409578Ssam tp->t_state |= TS_ERASE; 15417502Sroot } 15427502Sroot ttyecho(c, tp); 15437502Sroot } else 154435811Smarc ttyecho(tp->t_cc[VERASE], tp); 15457502Sroot tp->t_rocount--; 15467502Sroot } 15477502Sroot 15487502Sroot /* 15497502Sroot * Crt back over cnt chars perhaps 15507502Sroot * erasing them. 15517502Sroot */ 15527502Sroot ttyrubo(tp, cnt) 15537625Ssam register struct tty *tp; 15547625Ssam int cnt; 15557502Sroot { 15567502Sroot 15577502Sroot while (--cnt >= 0) 155840712Skarels ttyoutstr("\b \b", tp); 15597502Sroot } 15607502Sroot 15617502Sroot /* 15627502Sroot * Reprint the rawq line. 15637502Sroot * We assume c_cc has already been checked. 15647502Sroot */ 15657502Sroot ttyretype(tp) 15667625Ssam register struct tty *tp; 15677502Sroot { 15687502Sroot register char *cp; 15697502Sroot char *nextc(); 157035811Smarc int s, c; 15717502Sroot 157235811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 157335811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15747502Sroot (void) ttyoutput('\n', tp); 157517545Skarels s = spltty(); 157635811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 157735811Smarc BIT OF FIRST CHAR ****/ 157835811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 157935811Smarc ttyecho(c, tp); 158035811Smarc } 158135811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 158235811Smarc ttyecho(c, tp); 158335811Smarc } 15849578Ssam tp->t_state &= ~TS_ERASE; 15857502Sroot splx(s); 15867502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15877502Sroot tp->t_rocol = 0; 15887502Sroot } 15897502Sroot 15907502Sroot /* 159135811Smarc * Echo a typed character to the terminal. 15927502Sroot */ 15937502Sroot ttyecho(c, tp) 15947625Ssam register c; 15957625Ssam register struct tty *tp; 15967502Sroot { 15979578Ssam if ((tp->t_state&TS_CNTTB) == 0) 159835811Smarc tp->t_lflag &= ~FLUSHO; 159947545Skarels if (((tp->t_lflag&ECHO) == 0 && 160047545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16017502Sroot return; 160235811Smarc if (tp->t_lflag&ECHOCTL) { 160340712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 160440712Skarels c == 0177) { 16057502Sroot (void) ttyoutput('^', tp); 160635811Smarc c &= TTY_CHARMASK; 16077502Sroot if (c == 0177) 16087502Sroot c = '?'; 16097502Sroot else 16107502Sroot c += 'A' - 1; 16117502Sroot } 16127502Sroot } 161335811Smarc (void) ttyoutput(c, tp); 16147502Sroot } 16157502Sroot 16167502Sroot /* 16177502Sroot * send string cp to tp 16187502Sroot */ 161940712Skarels ttyoutstr(cp, tp) 16207625Ssam register char *cp; 16217625Ssam register struct tty *tp; 16227502Sroot { 16237502Sroot register char c; 16247502Sroot 16257502Sroot while (c = *cp++) 16267502Sroot (void) ttyoutput(c, tp); 16277502Sroot } 16287502Sroot 162949380Skarels /* 163049380Skarels * Wake up any readers on a tty. 163149380Skarels */ 16327502Sroot ttwakeup(tp) 163347545Skarels register struct tty *tp; 16347502Sroot { 16357502Sroot 16367502Sroot if (tp->t_rsel) { 16377502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16387502Sroot tp->t_state &= ~TS_RCOLL; 16397502Sroot tp->t_rsel = 0; 16407502Sroot } 164112752Ssam if (tp->t_state & TS_ASYNC) 164242882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16437502Sroot wakeup((caddr_t)&tp->t_rawq); 16447502Sroot } 164535811Smarc 164635811Smarc /* 164748439Skarels * Look up a code for a specified speed in a conversion table; 164848439Skarels * used by drivers to map software speed values to hardware parameters. 164948439Skarels */ 165048439Skarels ttspeedtab(speed, table) 165148439Skarels register struct speedtab *table; 165248439Skarels { 165348439Skarels 165448439Skarels for ( ; table->sp_speed != -1; table++) 165548439Skarels if (table->sp_speed == speed) 165648439Skarels return (table->sp_code); 165748439Skarels return (-1); 165848439Skarels } 165948439Skarels 166048439Skarels /* 166135811Smarc * set tty hi and low water marks 166235811Smarc * 166335811Smarc * Try to arrange the dynamics so there's about one second 166435811Smarc * from hi to low water. 166535811Smarc * 166635811Smarc */ 166735811Smarc ttsetwater(tp) 166835811Smarc struct tty *tp; 166935811Smarc { 167035811Smarc register cps = tp->t_ospeed / 10; 167135811Smarc register x; 167235811Smarc 167335811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 167435811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 167535811Smarc x += cps; 167635811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 167735811Smarc tp->t_hiwat = roundup(x, CBSIZE); 167835811Smarc #undef clamp 167935811Smarc } 168035811Smarc 168139407Smarc /* 168239407Smarc * (^T) 168339407Smarc * Report on state of foreground process group. 168439407Smarc */ 168539407Smarc ttyinfo(tp) 168639407Smarc struct tty *tp; 168739407Smarc { 168841177Smarc register struct proc *p, *pick = NULL; 168941177Smarc int x, s; 169041177Smarc struct timeval utime, stime; 169142350Smckusick #define pgtok(a) (((a)*NBPG)/1024) 169239407Smarc 169339407Smarc if (ttycheckoutq(tp,0) == 0) 169439407Smarc return; 169541177Smarc /* 169641177Smarc * load average 169741177Smarc */ 169841177Smarc x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT; 169941177Smarc ttyprintf(tp, "load: %d.", x/100); 170041177Smarc ttyoutint(x%100, 10, 2, tp); 170139555Smarc if (tp->t_session == NULL) 170241177Smarc ttyprintf(tp, " not a controlling terminal\n"); 170341177Smarc else if (tp->t_pgrp == NULL) 170441177Smarc ttyprintf(tp, " no foreground process group\n"); 170541177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 170641177Smarc ttyprintf(tp, " empty foreground process group\n"); 170739407Smarc else { 170841177Smarc /* pick interesting process */ 170939407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 171041177Smarc if (proc_compare(pick, p)) 171141177Smarc pick = p; 171239407Smarc } 171341177Smarc ttyprintf(tp, " cmd: %s %d [%s] ", 171441177Smarc pick->p_comm, pick->p_pid, 171548439Skarels pick->p_stat == SRUN ? "running" : 171648439Skarels pick->p_wmesg ? pick->p_wmesg : "iowait"); 171741177Smarc /* 171841177Smarc * cpu time 171941177Smarc */ 172047545Skarels if (curproc == pick) 172141177Smarc s = splclock(); 172241177Smarc utime = pick->p_utime; 172341177Smarc stime = pick->p_stime; 172447545Skarels if (curproc == pick) 172541177Smarc splx(s); 172641177Smarc /* user time */ 172741177Smarc x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */ 172841177Smarc ttyoutint(utime.tv_sec, 10, 1, tp); 172941177Smarc tputchar('.', tp); 173041177Smarc ttyoutint(x, 10, 2, tp); 173141177Smarc tputchar('u', tp); 173241177Smarc tputchar(' ', tp); 173341177Smarc /* system time */ 173441177Smarc x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */ 173541177Smarc ttyoutint(stime.tv_sec, 10, 1, tp); 173641177Smarc tputchar('.', tp); 173741177Smarc ttyoutint(x, 10, 2, tp); 173841177Smarc tputchar('s', tp); 173941177Smarc tputchar(' ', tp); 174041177Smarc /* 174141177Smarc * pctcpu 174241177Smarc */ 174341177Smarc x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT; 174441177Smarc ttyoutint(x/100, 10, 1, tp); 174541177Smarc #ifdef notdef /* do we really want this ??? */ 174641177Smarc tputchar('.', tp); 174741177Smarc ttyoutint(x%100, 10, 2, tp); 174841177Smarc #endif 174947545Skarels ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize)); 175039407Smarc } 175141177Smarc tp->t_rocount = 0; /* so pending input will be retyped if BS */ 175239407Smarc } 175339407Smarc 175441177Smarc ttyoutint(n, base, min, tp) 175541177Smarc register int n, base, min; 175641177Smarc register struct tty *tp; 175741177Smarc { 175841177Smarc char info[16]; 175941177Smarc register char *p = info; 176041177Smarc 176141177Smarc while (--min >= 0 || n) { 176241177Smarc *p++ = "0123456789abcdef"[n%base]; 176341177Smarc n /= base; 176441177Smarc } 176541177Smarc while (p > info) 176641177Smarc ttyoutput(*--p, tp); 176741177Smarc } 176841177Smarc 176941177Smarc /* 177041177Smarc * Returns 1 if p2 is "better" than p1 177141177Smarc * 177241177Smarc * The algorithm for picking the "interesting" process is thus: 177341177Smarc * 177441177Smarc * 1) (Only foreground processes are eligable - implied) 177541177Smarc * 2) Runnable processes are favored over anything 177641177Smarc * else. The runner with the highest cpu 177741177Smarc * utilization is picked (p_cpu). Ties are 177841177Smarc * broken by picking the highest pid. 177941177Smarc * 3 Next, the sleeper with the shortest sleep 178041177Smarc * time is favored. With ties, we pick out 178141177Smarc * just "short-term" sleepers (SSINTR == 0). 178241177Smarc * Further ties are broken by picking the highest 178341177Smarc * pid. 178441177Smarc * 178541177Smarc */ 178641177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 178745723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 178845723Smckusick #define ONLYA 2 178945723Smckusick #define ONLYB 1 179045723Smckusick #define BOTH 3 179145723Smckusick 179241177Smarc proc_compare(p1, p2) 179341177Smarc register struct proc *p1, *p2; 179441177Smarc { 179541177Smarc 179641177Smarc if (p1 == NULL) 179741177Smarc return (1); 179841177Smarc /* 179941177Smarc * see if at least one of them is runnable 180041177Smarc */ 180145723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 180245723Smckusick case ONLYA: 180345723Smckusick return (0); 180445723Smckusick case ONLYB: 180541177Smarc return (1); 180645723Smckusick case BOTH: 180741177Smarc /* 180841177Smarc * tie - favor one with highest recent cpu utilization 180941177Smarc */ 181041177Smarc if (p2->p_cpu > p1->p_cpu) 181141177Smarc return (1); 181241177Smarc if (p1->p_cpu > p2->p_cpu) 181341177Smarc return (0); 181441177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 181541177Smarc } 181645723Smckusick /* 181745723Smckusick * weed out zombies 181845723Smckusick */ 181945723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 182045723Smckusick case ONLYA: 182145723Smckusick return (1); 182245723Smckusick case ONLYB: 182345723Smckusick return (0); 182445723Smckusick case BOTH: 182545723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 182645723Smckusick } 182741177Smarc /* 182841177Smarc * pick the one with the smallest sleep time 182941177Smarc */ 183041177Smarc if (p2->p_slptime > p1->p_slptime) 183141177Smarc return (0); 183241177Smarc if (p1->p_slptime > p2->p_slptime) 183341177Smarc return (1); 183441177Smarc /* 183541177Smarc * favor one sleeping in a non-interruptible sleep 183641177Smarc */ 183741177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 183841177Smarc return (1); 183941177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 184041177Smarc return (0); 184147545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 184241177Smarc } 184345723Smckusick 184439555Smarc /* 184539555Smarc * Output char to tty; console putchar style. 184639555Smarc */ 184739555Smarc tputchar(c, tp) 184839555Smarc int c; 184939555Smarc struct tty *tp; 185039555Smarc { 185139555Smarc register s = spltty(); 185239555Smarc 185347545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 185439555Smarc if (c == '\n') 185539555Smarc (void) ttyoutput('\r', tp); 185639555Smarc (void) ttyoutput(c, tp); 185739555Smarc ttstart(tp); 185839555Smarc splx(s); 185939555Smarc return (0); 186039555Smarc } 186139555Smarc splx(s); 186239555Smarc return (-1); 186339555Smarc } 186443377Smarc 186544419Smarc /* 186649380Skarels * Sleep on chan, returning ERESTART if tty changed 186749380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 186849380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 186949380Skarels * call will redo validation done at the start of the call. 187044419Smarc */ 187143377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187243377Smarc struct tty *tp; 187343377Smarc caddr_t chan; 187443377Smarc int pri; 187543377Smarc char *wmesg; 187643377Smarc int timo; 187743377Smarc { 187843377Smarc int error; 187943377Smarc short gen = tp->t_gen; 188043377Smarc 188143377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188243377Smarc return (error); 188343377Smarc if (tp->t_gen != gen) 188443377Smarc return (ERESTART); 188543377Smarc return (0); 188643377Smarc } 1887