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*49752Smarc * @(#)tty.c 7.43 (Berkeley) 05/16/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(); 316*49752Smarc (*linesw[tp->t_line].l_close)(tp, flag); 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 */ 622*49752Smarc ttylclose(tp, flag) 623*49752Smarc struct tty *tp; 624*49752Smarc int flag; 62525391Skarels { 62625391Skarels 627*49752Smarc if (flag&IO_NDELAY) 628*49752Smarc ttyflush(tp, FREAD|FWRITE); 629*49752Smarc else 630*49752Smarc ttywflush(tp); 63125391Skarels } 63225391Skarels 63325391Skarels /* 63449380Skarels * Handle close() on a tty line: flush and set to initial state, 63549380Skarels * bumping generation number so that pending read/write calls 63649380Skarels * can detect recycling of the tty. 6377502Sroot */ 6387502Sroot ttyclose(tp) 6397625Ssam register struct tty *tp; 6407502Sroot { 64130534Skarels if (constty == tp) 64230534Skarels constty = NULL; 64325391Skarels ttyflush(tp, FREAD|FWRITE); 64439555Smarc tp->t_session = NULL; 64539555Smarc tp->t_pgrp = NULL; 6467502Sroot tp->t_state = 0; 64743377Smarc tp->t_gen++; 64840712Skarels return (0); 6497502Sroot } 6507502Sroot 6517502Sroot /* 65225391Skarels * Handle modem control transition on a tty. 65325391Skarels * Flag indicates new state of carrier. 65425391Skarels * Returns 0 if the line should be turned off, otherwise 1. 65525391Skarels */ 65625391Skarels ttymodem(tp, flag) 65725391Skarels register struct tty *tp; 65825391Skarels { 65925391Skarels 66042193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 66125391Skarels /* 66225391Skarels * MDMBUF: do flow control according to carrier flag 66325391Skarels */ 66425391Skarels if (flag) { 66525391Skarels tp->t_state &= ~TS_TTSTOP; 66625391Skarels ttstart(tp); 66725391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 66825391Skarels tp->t_state |= TS_TTSTOP; 66925391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 67025391Skarels } 67125391Skarels } else if (flag == 0) { 67225391Skarels /* 67325391Skarels * Lost carrier. 67425391Skarels */ 67525391Skarels tp->t_state &= ~TS_CARR_ON; 67642193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 67742193Smarc if (tp->t_session && tp->t_session->s_leader) 67842193Smarc psignal(tp->t_session->s_leader, SIGHUP); 67942193Smarc ttyflush(tp, FREAD|FWRITE); 68042193Smarc return (0); 68125391Skarels } 68225391Skarels } else { 68325391Skarels /* 68425391Skarels * Carrier now on. 68525391Skarels */ 68625391Skarels tp->t_state |= TS_CARR_ON; 68737584Smarc ttwakeup(tp); 68825391Skarels } 68925391Skarels return (1); 69025391Skarels } 69125391Skarels 69225391Skarels /* 69325404Skarels * Default modem control routine (for other line disciplines). 69425404Skarels * Return argument flag, to turn off device on carrier drop. 69525404Skarels */ 69625415Skarels nullmodem(tp, flag) 69725415Skarels register struct tty *tp; 69825404Skarels int flag; 69925404Skarels { 70025404Skarels 70125404Skarels if (flag) 70225404Skarels tp->t_state |= TS_CARR_ON; 70339407Smarc else { 70425404Skarels tp->t_state &= ~TS_CARR_ON; 70542193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 70642193Smarc if (tp->t_session && tp->t_session->s_leader) 70742193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70842193Smarc return (0); 70942193Smarc } 71039407Smarc } 71142193Smarc return (1); 71225404Skarels } 71325404Skarels 71425404Skarels /* 7157502Sroot * reinput pending characters after state switch 71617545Skarels * call at spltty(). 7177502Sroot */ 7187502Sroot ttypend(tp) 7197625Ssam register struct tty *tp; 7207502Sroot { 7217502Sroot struct clist tq; 7227502Sroot register c; 7237502Sroot 72435811Smarc tp->t_lflag &= ~PENDIN; 7259578Ssam tp->t_state |= TS_TYPEN; 7267502Sroot tq = tp->t_rawq; 7277502Sroot tp->t_rawq.c_cc = 0; 7287502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7297502Sroot while ((c = getc(&tq)) >= 0) 7307502Sroot ttyinput(c, tp); 7319578Ssam tp->t_state &= ~TS_TYPEN; 7327502Sroot } 7337502Sroot 7347502Sroot /* 73549380Skarels * Process input of a single character received on a tty. 7367502Sroot */ 7377502Sroot ttyinput(c, tp) 7387625Ssam register c; 7397625Ssam register struct tty *tp; 7407502Sroot { 74135811Smarc register int iflag = tp->t_iflag; 74235811Smarc register int lflag = tp->t_lflag; 74335811Smarc register u_char *cc = tp->t_cc; 74435811Smarc int i, err; 7457502Sroot 7469578Ssam /* 7479578Ssam * If input is pending take it first. 7489578Ssam */ 74935811Smarc if (lflag&PENDIN) 7507502Sroot ttypend(tp); 75135811Smarc /* 75235811Smarc * Gather stats. 75335811Smarc */ 7547502Sroot tk_nin++; 75535811Smarc if (lflag&ICANON) { 75635811Smarc tk_cancc++; 75735811Smarc tp->t_cancc++; 75835811Smarc } else { 75935811Smarc tk_rawcc++; 76035811Smarc tp->t_rawcc++; 76135811Smarc } 7629578Ssam /* 76335811Smarc * Handle exceptional conditions (break, parity, framing). 7649578Ssam */ 76535811Smarc if (err = (c&TTY_ERRORMASK)) { 76635811Smarc c &= ~TTY_ERRORMASK; 76735811Smarc if (err&TTY_FE && !c) { /* break */ 76835811Smarc if (iflag&IGNBRK) 76935811Smarc goto endcase; 77035811Smarc else if (iflag&BRKINT && lflag&ISIG && 77135811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 77235811Smarc c = cc[VINTR]; 77347545Skarels else if (iflag&PARMRK) 77447545Skarels goto parmrk; 77535811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 77635811Smarc if (iflag&IGNPAR) 77735811Smarc goto endcase; 77835811Smarc else if (iflag&PARMRK) { 77935811Smarc parmrk: 78035811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 78135811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 78235811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 78335811Smarc goto endcase; 78435811Smarc } else 78535811Smarc c = 0; 7867502Sroot } 7879578Ssam } 7889578Ssam /* 78935811Smarc * In tandem mode, check high water mark. 7909578Ssam */ 79135811Smarc if (iflag&IXOFF) 79235811Smarc ttyblock(tp); 79335811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 79449380Skarels c &= ~0x80; 79544419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 79644419Smarc /* 79744419Smarc * Check for literal nexting very first 79844419Smarc */ 79944419Smarc if (tp->t_state&TS_LNCH) { 80044419Smarc c |= TTY_QUOTE; 80144419Smarc tp->t_state &= ~TS_LNCH; 80244419Smarc } 80344419Smarc /* 80444419Smarc * Scan for special characters. This code 80544419Smarc * is really just a big case statement with 80644419Smarc * non-constant cases. The bottom of the 80744419Smarc * case statement is labeled ``endcase'', so goto 80844419Smarc * it after a case match, or similar. 80944419Smarc */ 81044419Smarc 81144419Smarc /* 81244419Smarc * Control chars which aren't controlled 81344419Smarc * by ICANON, ISIG, or IXON. 81444419Smarc */ 81544419Smarc if (lflag&IEXTEN) { 81644419Smarc if (CCEQ(cc[VLNEXT], c)) { 81744419Smarc if (lflag&ECHO) { 81844419Smarc if (lflag&ECHOE) 81944419Smarc ttyoutstr("^\b", tp); 82044419Smarc else 82144419Smarc ttyecho(c, tp); 82244419Smarc } 82344419Smarc tp->t_state |= TS_LNCH; 82444419Smarc goto endcase; 82544419Smarc } 82644419Smarc if (CCEQ(cc[VDISCARD], c)) { 82744419Smarc if (lflag&FLUSHO) 82844419Smarc tp->t_lflag &= ~FLUSHO; 82944419Smarc else { 83044419Smarc ttyflush(tp, FWRITE); 83135811Smarc ttyecho(c, tp); 83244419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 83344419Smarc ttyretype(tp); 83444419Smarc tp->t_lflag |= FLUSHO; 83544419Smarc } 83644419Smarc goto startoutput; 83735811Smarc } 8389578Ssam } 83944419Smarc /* 84044419Smarc * Signals. 84144419Smarc */ 84244419Smarc if (lflag&ISIG) { 84344419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 84444419Smarc if ((lflag&NOFLSH) == 0) 84544419Smarc ttyflush(tp, FREAD|FWRITE); 8467502Sroot ttyecho(c, tp); 84744419Smarc pgsignal(tp->t_pgrp, 84844419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 84944419Smarc goto endcase; 8507502Sroot } 85144419Smarc if (CCEQ(cc[VSUSP], c)) { 85244419Smarc if ((lflag&NOFLSH) == 0) 85344419Smarc ttyflush(tp, FREAD); 85444419Smarc ttyecho(c, tp); 85544419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 85644419Smarc goto endcase; 85744419Smarc } 8589578Ssam } 85944419Smarc /* 86044419Smarc * Handle start/stop characters. 86144419Smarc */ 86244419Smarc if (iflag&IXON) { 86344419Smarc if (CCEQ(cc[VSTOP], c)) { 86444419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 86544419Smarc tp->t_state |= TS_TTSTOP; 86644419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 86744419Smarc 0); 86844419Smarc return; 86944419Smarc } 87044419Smarc if (!CCEQ(cc[VSTART], c)) 87144419Smarc return; 87244419Smarc /* 87344419Smarc * if VSTART == VSTOP then toggle 87444419Smarc */ 87544419Smarc goto endcase; 87635811Smarc } 87744419Smarc if (CCEQ(cc[VSTART], c)) 87844419Smarc goto restartoutput; 8799578Ssam } 88044419Smarc /* 88144419Smarc * IGNCR, ICRNL, & INLCR 88244419Smarc */ 88344419Smarc if (c == '\r') { 88444419Smarc if (iflag&IGNCR) 88544419Smarc goto endcase; 88644419Smarc else if (iflag&ICRNL) 88744419Smarc c = '\n'; 88844419Smarc } else if (c == '\n' && iflag&INLCR) 88944419Smarc c = '\r'; 8909578Ssam } 89147545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 89244419Smarc /* 89344419Smarc * From here on down canonical mode character 89444419Smarc * processing takes place. 89544419Smarc */ 89644419Smarc /* 89744419Smarc * erase (^H / ^?) 89844419Smarc */ 89944419Smarc if (CCEQ(cc[VERASE], c)) { 90044419Smarc if (tp->t_rawq.c_cc) 9019578Ssam ttyrub(unputc(&tp->t_rawq), tp); 90244419Smarc goto endcase; 9039578Ssam } 90444419Smarc /* 90544419Smarc * kill (^U) 90644419Smarc */ 90744419Smarc if (CCEQ(cc[VKILL], c)) { 90844419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 90944419Smarc (lflag&ECHOPRT) == 0) { 91044419Smarc while (tp->t_rawq.c_cc) 91144419Smarc ttyrub(unputc(&tp->t_rawq), tp); 91244419Smarc } else { 91344419Smarc ttyecho(c, tp); 91444419Smarc if (lflag&ECHOK || lflag&ECHOKE) 91544419Smarc ttyecho('\n', tp); 91644419Smarc while (getc(&tp->t_rawq) > 0) 91744419Smarc ; 91844419Smarc tp->t_rocount = 0; 91944419Smarc } 92044419Smarc tp->t_state &= ~TS_LOCAL; 92144419Smarc goto endcase; 92244419Smarc } 92344419Smarc /* 92444419Smarc * word erase (^W) 92544419Smarc */ 92644419Smarc if (CCEQ(cc[VWERASE], c)) { 92744419Smarc int ctype; 92847545Skarels int alt = lflag&ALTWERASE; 92935811Smarc 93044419Smarc /* 93144419Smarc * erase whitespace 93244419Smarc */ 93344419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 93444419Smarc ttyrub(c, tp); 93544419Smarc if (c == -1) 93644419Smarc goto endcase; 93744419Smarc /* 93847545Skarels * erase last char of word and remember the 93947545Skarels * next chars type (for ALTWERASE) 94044419Smarc */ 94135811Smarc ttyrub(c, tp); 94244419Smarc c = unputc(&tp->t_rawq); 94347545Skarels if (c == -1) 94444419Smarc goto endcase; 94549380Skarels ctype = ISALPHA(c); 94644419Smarc /* 94747545Skarels * erase rest of word 94844419Smarc */ 94944419Smarc do { 95044419Smarc ttyrub(c, tp); 95144419Smarc c = unputc(&tp->t_rawq); 95244419Smarc if (c == -1) 95344419Smarc goto endcase; 95447545Skarels } while (c != ' ' && c != '\t' && 95549380Skarels (alt == 0 || ISALPHA(c) == ctype)); 95644419Smarc (void) putc(c, &tp->t_rawq); 95734492Skarels goto endcase; 95844419Smarc } 95935811Smarc /* 96044419Smarc * reprint line (^R) 96135811Smarc */ 96244419Smarc if (CCEQ(cc[VREPRINT], c)) { 96344419Smarc ttyretype(tp); 96434492Skarels goto endcase; 96534492Skarels } 96635811Smarc /* 96744419Smarc * ^T - kernel info and generate SIGINFO 96835811Smarc */ 96944419Smarc if (CCEQ(cc[VSTATUS], c)) { 97044419Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 97144419Smarc if ((lflag&NOKERNINFO) == 0) 97244419Smarc ttyinfo(tp); 97344419Smarc goto endcase; 97444419Smarc } 9759578Ssam } 9769578Ssam /* 9779578Ssam * Check for input buffer overflow 9789578Ssam */ 97947545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 98035811Smarc if (iflag&IMAXBEL) { 98135811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 98235811Smarc (void) ttyoutput(CTRL('g'), tp); 98335811Smarc } else 98435811Smarc ttyflush(tp, FREAD | FWRITE); 9859578Ssam goto endcase; 98610391Ssam } 9879578Ssam /* 9889578Ssam * Put data char in q for user and 9899578Ssam * wakeup on seeing a line delimiter. 9909578Ssam */ 9919578Ssam if (putc(c, &tp->t_rawq) >= 0) { 99247545Skarels if ((lflag&ICANON) == 0) { 99347545Skarels ttwakeup(tp); 99447545Skarels ttyecho(c, tp); 99547545Skarels goto endcase; 99647545Skarels } 99735811Smarc if (ttbreakc(c)) { 9989578Ssam tp->t_rocount = 0; 9999578Ssam catq(&tp->t_rawq, &tp->t_canq); 10007502Sroot ttwakeup(tp); 10019578Ssam } else if (tp->t_rocount++ == 0) 10029578Ssam tp->t_rocol = tp->t_col; 10039578Ssam if (tp->t_state&TS_ERASE) { 100435811Smarc /* 100535811Smarc * end of prterase \.../ 100635811Smarc */ 10079578Ssam tp->t_state &= ~TS_ERASE; 10089578Ssam (void) ttyoutput('/', tp); 10099578Ssam } 10109578Ssam i = tp->t_col; 10117502Sroot ttyecho(c, tp); 101235811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 101335811Smarc /* 101435811Smarc * Place the cursor over the '^' of the ^D. 101535811Smarc */ 10169578Ssam i = MIN(2, tp->t_col - i); 10179578Ssam while (i > 0) { 10189578Ssam (void) ttyoutput('\b', tp); 10199578Ssam i--; 10209578Ssam } 10219578Ssam } 10227502Sroot } 10239578Ssam endcase: 10249578Ssam /* 102535811Smarc * IXANY means allow any character to restart output. 10269578Ssam */ 102740712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 102840712Skarels cc[VSTART] != cc[VSTOP]) 10297502Sroot return; 10309578Ssam restartoutput: 10317502Sroot tp->t_state &= ~TS_TTSTOP; 103235811Smarc tp->t_lflag &= ~FLUSHO; 10339578Ssam startoutput: 10347502Sroot ttstart(tp); 10357502Sroot } 10367502Sroot 10377502Sroot /* 103849380Skarels * Output a single character on a tty, doing output processing 103949380Skarels * as needed (expanding tabs, newline processing, etc.). 104049380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10417502Sroot * Must be recursive. 10427502Sroot */ 10437502Sroot ttyoutput(c, tp) 10447502Sroot register c; 10457502Sroot register struct tty *tp; 10467502Sroot { 104749380Skarels register int col; 104835811Smarc register long oflag = tp->t_oflag; 104935811Smarc 105040712Skarels if ((oflag&OPOST) == 0) { 105135811Smarc if (tp->t_lflag&FLUSHO) 10527502Sroot return (-1); 10537502Sroot if (putc(c, &tp->t_outq)) 10547625Ssam return (c); 10557502Sroot tk_nout++; 105635811Smarc tp->t_outcc++; 10577502Sroot return (-1); 10587502Sroot } 105935811Smarc c &= TTY_CHARMASK; 10607502Sroot /* 106149380Skarels * Do tab expansion if OXTABS is set. 106242882Smarc * Special case if we have external processing, we don't 106342882Smarc * do the tab expansion because we'll probably get it 106442882Smarc * wrong. If tab expansion needs to be done, let it 106542882Smarc * happen externally. 10667502Sroot */ 106747545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 10687502Sroot register int s; 10697502Sroot 10707502Sroot c = 8 - (tp->t_col&7); 107135811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 107217545Skarels s = spltty(); /* don't interrupt tabs */ 10737502Sroot c -= b_to_q(" ", c, &tp->t_outq); 10747502Sroot tk_nout += c; 107535811Smarc tp->t_outcc += c; 10767502Sroot splx(s); 10777502Sroot } 10787502Sroot tp->t_col += c; 10797502Sroot return (c ? -1 : '\t'); 10807502Sroot } 108135811Smarc if (c == CEOT && oflag&ONOEOT) 108247545Skarels return (-1); 10837502Sroot tk_nout++; 108435811Smarc tp->t_outcc++; 10857502Sroot /* 108649380Skarels * Newline translation: if ONLCR is set, 108749380Skarels * translate newline into "\r\n". 10887502Sroot */ 108935811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 10907502Sroot return (c); 109135811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 109235811Smarc return (c); 109347545Skarels 109449380Skarels col = tp->t_col; 109549380Skarels switch (CCLASS(c)) { 10967502Sroot 10977502Sroot case ORDINARY: 109849380Skarels col++; 10997502Sroot 11007502Sroot case CONTROL: 11017502Sroot break; 11027502Sroot 11037502Sroot case BACKSPACE: 110449380Skarels if (col > 0) 110549380Skarels col--; 11067502Sroot break; 11077502Sroot 11087502Sroot case NEWLINE: 110949380Skarels col = 0; 11107502Sroot break; 11117502Sroot 11127502Sroot case TAB: 111349380Skarels col = (col + 8) &~ 0x7; 11147502Sroot break; 11157502Sroot 11167502Sroot case RETURN: 111749380Skarels col = 0; 11187502Sroot } 111949380Skarels tp->t_col = col; 11207502Sroot return (-1); 11217502Sroot } 11227502Sroot 11237502Sroot /* 112449380Skarels * Process a read call on a tty device. 11257502Sroot */ 112637584Smarc ttread(tp, uio, flag) 11277625Ssam register struct tty *tp; 11287722Swnj struct uio *uio; 11297502Sroot { 11307502Sroot register struct clist *qp; 113135811Smarc register int c; 113241383Smarc register long lflag; 113335811Smarc register u_char *cc = tp->t_cc; 113447545Skarels register struct proc *p = curproc; 11359859Ssam int s, first, error = 0; 11367502Sroot 11377502Sroot loop: 113841383Smarc lflag = tp->t_lflag; 113937584Smarc s = spltty(); 11409578Ssam /* 114137584Smarc * take pending input first 11429578Ssam */ 114335811Smarc if (lflag&PENDIN) 11447502Sroot ttypend(tp); 11459859Ssam splx(s); 114640712Skarels 11479578Ssam /* 11489578Ssam * Hang process if it's in the background. 11499578Ssam */ 115047545Skarels if (isbackground(p, tp)) { 115147545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 115247545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 115347545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11548520Sroot return (EIO); 115547545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 115643377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 115743377Smarc ttybg, 0)) 115840712Skarels return (error); 115923165Sbloom goto loop; 11607502Sroot } 116140712Skarels 11629578Ssam /* 116335811Smarc * If canonical, use the canonical queue, 116435811Smarc * else use the raw queue. 116537584Smarc * 116647545Skarels * (should get rid of clists...) 11679578Ssam */ 116835811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 116940712Skarels 11709578Ssam /* 117140712Skarels * If there is no input, sleep on rawq 117240712Skarels * awaiting hardware receipt and notification. 117340712Skarels * If we have data, we don't need to check for carrier. 11749578Ssam */ 117517545Skarels s = spltty(); 11769578Ssam if (qp->c_cc <= 0) { 117740712Skarels int carrier; 117840712Skarels 117940712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 118040712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 11819859Ssam splx(s); 118240712Skarels return (0); /* EOF */ 11837502Sroot } 118437728Smckusick if (flag & IO_NDELAY) { 118537584Smarc splx(s); 118637584Smarc return (EWOULDBLOCK); 118737584Smarc } 118843377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 118940712Skarels carrier ? ttyin : ttopen, 0); 11909859Ssam splx(s); 119143377Smarc if (error) 119240712Skarels return (error); 11939578Ssam goto loop; 11949578Ssam } 11959859Ssam splx(s); 119640712Skarels 11979578Ssam /* 119835811Smarc * Input present, check for input mapping and processing. 11999578Ssam */ 12009578Ssam first = 1; 12019578Ssam while ((c = getc(qp)) >= 0) { 12029578Ssam /* 120335811Smarc * delayed suspend (^Y) 12049578Ssam */ 120535811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 120642882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12079578Ssam if (first) { 120843377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 120943377Smarc TTIPRI | PCATCH, ttybg, 0)) 121040712Skarels break; 12119578Ssam goto loop; 12129578Ssam } 12139578Ssam break; 12147502Sroot } 12159578Ssam /* 121635811Smarc * Interpret EOF only in canonical mode. 12179578Ssam */ 121835811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12199578Ssam break; 12209578Ssam /* 12219578Ssam * Give user character. 12229578Ssam */ 122340712Skarels error = ureadc(c, uio); 12249578Ssam if (error) 12259578Ssam break; 122614938Smckusick if (uio->uio_resid == 0) 12279578Ssam break; 12289578Ssam /* 122935811Smarc * In canonical mode check for a "break character" 12309578Ssam * marking the end of a "line of input". 12319578Ssam */ 123240712Skarels if (lflag&ICANON && ttbreakc(c)) 12339578Ssam break; 12349578Ssam first = 0; 12357502Sroot } 12369578Ssam /* 12379578Ssam * Look to unblock output now that (presumably) 12389578Ssam * the input queue has gone down. 12399578Ssam */ 124035811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 124147545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 124247545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12437502Sroot tp->t_state &= ~TS_TBLOCK; 12447502Sroot ttstart(tp); 12457502Sroot } 124635811Smarc } 12478520Sroot return (error); 12487502Sroot } 12497502Sroot 12507502Sroot /* 125125391Skarels * Check the output queue on tp for space for a kernel message 125225391Skarels * (from uprintf/tprintf). Allow some space over the normal 125325391Skarels * hiwater mark so we don't lose messages due to normal flow 125425391Skarels * control, but don't let the tty run amok. 125530695Skarels * Sleeps here are not interruptible, but we return prematurely 125630695Skarels * if new signals come in. 125725391Skarels */ 125825391Skarels ttycheckoutq(tp, wait) 125925391Skarels register struct tty *tp; 126025391Skarels int wait; 126125391Skarels { 126230695Skarels int hiwat, s, oldsig; 126348439Skarels extern int wakeup(); 126425391Skarels 126535811Smarc hiwat = tp->t_hiwat; 126625391Skarels s = spltty(); 126747545Skarels oldsig = curproc->p_sig; 126825391Skarels if (tp->t_outq.c_cc > hiwat + 200) 126929946Skarels while (tp->t_outq.c_cc > hiwat) { 127029946Skarels ttstart(tp); 127147545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 127229946Skarels splx(s); 127329946Skarels return (0); 127429946Skarels } 127530695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 127629946Skarels tp->t_state |= TS_ASLEEP; 127730695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 127825391Skarels } 127925391Skarels splx(s); 128025391Skarels return (1); 128125391Skarels } 128225391Skarels 128325391Skarels /* 128449380Skarels * Process a write call on a tty device. 12857502Sroot */ 128637584Smarc ttwrite(tp, uio, flag) 12877625Ssam register struct tty *tp; 12889578Ssam register struct uio *uio; 12897502Sroot { 12907502Sroot register char *cp; 129140712Skarels register int cc = 0, ce; 129247545Skarels register struct proc *p = curproc; 12939578Ssam int i, hiwat, cnt, error, s; 12947502Sroot char obuf[OBUFSIZ]; 12957502Sroot 129635811Smarc hiwat = tp->t_hiwat; 12979578Ssam cnt = uio->uio_resid; 12989578Ssam error = 0; 12997502Sroot loop: 130037584Smarc s = spltty(); 130140712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 130237584Smarc if (tp->t_state&TS_ISOPEN) { 130337584Smarc splx(s); 130437584Smarc return (EIO); 130537728Smckusick } else if (flag & IO_NDELAY) { 130637584Smarc splx(s); 130740712Skarels error = EWOULDBLOCK; 130840712Skarels goto out; 130937584Smarc } else { 131037584Smarc /* 131137584Smarc * sleep awaiting carrier 131237584Smarc */ 131343377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 131443377Smarc TTIPRI | PCATCH,ttopen, 0); 131537584Smarc splx(s); 131643377Smarc if (error) 131740712Skarels goto out; 131837584Smarc goto loop; 131937584Smarc } 132037584Smarc } 132137584Smarc splx(s); 13229578Ssam /* 13239578Ssam * Hang the process if it's in the background. 13249578Ssam */ 132547545Skarels if (isbackground(p, tp) && 132647545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 132747545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 132847545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 132947545Skarels p->p_pgrp->pg_jobc) { 133047545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 133143377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 133243377Smarc ttybg, 0)) 133340712Skarels goto out; 133421776Sbloom goto loop; 13357502Sroot } 13369578Ssam /* 13379578Ssam * Process the user's data in at most OBUFSIZ 133840712Skarels * chunks. Perform any output translation. 133940712Skarels * Keep track of high water mark, sleep on overflow 134040712Skarels * awaiting device aid in acquiring new space. 13419578Ssam */ 134240712Skarels while (uio->uio_resid > 0 || cc > 0) { 134340712Skarels if (tp->t_lflag&FLUSHO) { 134440712Skarels uio->uio_resid = 0; 134540712Skarels return (0); 134640712Skarels } 134740712Skarels if (tp->t_outq.c_cc > hiwat) 134832067Skarels goto ovhiwat; 13499578Ssam /* 135040712Skarels * Grab a hunk of data from the user, 135140712Skarels * unless we have some leftover from last time. 13529578Ssam */ 13537822Sroot if (cc == 0) { 135440712Skarels cc = min(uio->uio_resid, OBUFSIZ); 135540712Skarels cp = obuf; 135640712Skarels error = uiomove(cp, cc, uio); 135740712Skarels if (error) { 135840712Skarels cc = 0; 135940712Skarels break; 136040712Skarels } 13617822Sroot } 13629578Ssam /* 13639578Ssam * If nothing fancy need be done, grab those characters we 13649578Ssam * can handle without any of ttyoutput's processing and 13659578Ssam * just transfer them to the output q. For those chars 13669578Ssam * which require special processing (as indicated by the 13679578Ssam * bits in partab), call ttyoutput. After processing 13689578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 13699578Ssam * immediately. 13709578Ssam */ 13719578Ssam while (cc > 0) { 137240712Skarels if ((tp->t_oflag&OPOST) == 0) 13737502Sroot ce = cc; 13747502Sroot else { 137534492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 137649380Skarels (u_char *)partab, CCLASSMASK); 13779578Ssam /* 13789578Ssam * If ce is zero, then we're processing 13799578Ssam * a special character through ttyoutput. 13809578Ssam */ 13819578Ssam if (ce == 0) { 13827502Sroot tp->t_rocount = 0; 13837502Sroot if (ttyoutput(*cp, tp) >= 0) { 138421776Sbloom /* no c-lists, wait a bit */ 138521776Sbloom ttstart(tp); 138643377Smarc if (error = ttysleep(tp, 138743377Smarc (caddr_t)&lbolt, 138843377Smarc TTOPRI | PCATCH, ttybuf, 0)) 138940712Skarels break; 139021776Sbloom goto loop; 13917502Sroot } 13929578Ssam cp++, cc--; 139335811Smarc if ((tp->t_lflag&FLUSHO) || 13949578Ssam tp->t_outq.c_cc > hiwat) 13957502Sroot goto ovhiwat; 13969578Ssam continue; 13977502Sroot } 13987502Sroot } 13999578Ssam /* 14009578Ssam * A bunch of normal characters have been found, 14019578Ssam * transfer them en masse to the output queue and 14029578Ssam * continue processing at the top of the loop. 14039578Ssam * If there are any further characters in this 14049578Ssam * <= OBUFSIZ chunk, the first should be a character 14059578Ssam * requiring special handling by ttyoutput. 14069578Ssam */ 14077502Sroot tp->t_rocount = 0; 14089578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14099578Ssam ce -= i; 14109578Ssam tp->t_col += ce; 14119578Ssam cp += ce, cc -= ce, tk_nout += ce; 141235811Smarc tp->t_outcc += ce; 14139578Ssam if (i > 0) { 14149578Ssam /* out of c-lists, wait a bit */ 14157502Sroot ttstart(tp); 141643377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 141743377Smarc TTOPRI | PCATCH, ttybuf, 0)) 141840712Skarels break; 141921776Sbloom goto loop; 14207502Sroot } 142135811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 142240712Skarels break; 14237502Sroot } 142435811Smarc ttstart(tp); 14257502Sroot } 142640712Skarels out: 142740712Skarels /* 142840712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 142940712Skarels * as the offset and iov pointers have moved forward, 143040712Skarels * but it doesn't matter (the call will either return short 143140712Skarels * or restart with a new uio). 143240712Skarels */ 143340712Skarels uio->uio_resid += cc; 14348520Sroot return (error); 143540712Skarels 14367502Sroot ovhiwat: 143732067Skarels ttstart(tp); 143832067Skarels s = spltty(); 14399578Ssam /* 144035811Smarc * This can only occur if FLUSHO is set in t_lflag, 144132067Skarels * or if ttstart/oproc is synchronous (or very fast). 14429578Ssam */ 14437502Sroot if (tp->t_outq.c_cc <= hiwat) { 14449578Ssam splx(s); 14457502Sroot goto loop; 14467502Sroot } 144737728Smckusick if (flag & IO_NDELAY) { 144817545Skarels splx(s); 144940712Skarels uio->uio_resid += cc; 14507822Sroot if (uio->uio_resid == cnt) 14518520Sroot return (EWOULDBLOCK); 14528520Sroot return (0); 14537502Sroot } 14547502Sroot tp->t_state |= TS_ASLEEP; 145543377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 14569578Ssam splx(s); 145743377Smarc if (error) 145840712Skarels goto out; 14597502Sroot goto loop; 14607502Sroot } 14617502Sroot 14627502Sroot /* 14637502Sroot * Rubout one character from the rawq of tp 14647502Sroot * as cleanly as possible. 14657502Sroot */ 14667502Sroot ttyrub(c, tp) 14677625Ssam register c; 14687625Ssam register struct tty *tp; 14697502Sroot { 14707502Sroot register char *cp; 14717502Sroot register int savecol; 14727502Sroot int s; 14737502Sroot char *nextc(); 14747502Sroot 147542882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 14767502Sroot return; 147735811Smarc tp->t_lflag &= ~FLUSHO; 147835811Smarc if (tp->t_lflag&ECHOE) { 14797502Sroot if (tp->t_rocount == 0) { 14807502Sroot /* 14817502Sroot * Screwed by ttwrite; retype 14827502Sroot */ 14837502Sroot ttyretype(tp); 14847502Sroot return; 14857502Sroot } 148635811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 14877502Sroot ttyrubo(tp, 2); 148849380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 14897502Sroot 14907502Sroot case ORDINARY: 149135811Smarc ttyrubo(tp, 1); 14927502Sroot break; 14937502Sroot 14947502Sroot case VTAB: 14957502Sroot case BACKSPACE: 14967502Sroot case CONTROL: 14977502Sroot case RETURN: 149847545Skarels case NEWLINE: 149935811Smarc if (tp->t_lflag&ECHOCTL) 15007502Sroot ttyrubo(tp, 2); 15017502Sroot break; 15027502Sroot 150335811Smarc case TAB: { 150435811Smarc int c; 150535811Smarc 15067502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15077502Sroot ttyretype(tp); 15087502Sroot return; 15097502Sroot } 151017545Skarels s = spltty(); 15117502Sroot savecol = tp->t_col; 15129578Ssam tp->t_state |= TS_CNTTB; 151335811Smarc tp->t_lflag |= FLUSHO; 15147502Sroot tp->t_col = tp->t_rocol; 15159578Ssam cp = tp->t_rawq.c_cf; 151639407Smarc if (cp) 151739407Smarc c = *cp; /* XXX FIX NEXTC */ 151835811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 151935811Smarc ttyecho(c, tp); 152035811Smarc tp->t_lflag &= ~FLUSHO; 15219578Ssam tp->t_state &= ~TS_CNTTB; 15227502Sroot splx(s); 15237502Sroot /* 15247502Sroot * savecol will now be length of the tab 15257502Sroot */ 15267502Sroot savecol -= tp->t_col; 15277502Sroot tp->t_col += savecol; 15287502Sroot if (savecol > 8) 15297502Sroot savecol = 8; /* overflow screw */ 15307502Sroot while (--savecol >= 0) 15317502Sroot (void) ttyoutput('\b', tp); 15327502Sroot break; 153335811Smarc } 15347502Sroot 15357502Sroot default: 153637584Smarc /* XXX */ 153735811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 153849380Skarels c, CCLASS(c)); 153935811Smarc /*panic("ttyrub");*/ 15407502Sroot } 154135811Smarc } else if (tp->t_lflag&ECHOPRT) { 15429578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15437502Sroot (void) ttyoutput('\\', tp); 15449578Ssam tp->t_state |= TS_ERASE; 15457502Sroot } 15467502Sroot ttyecho(c, tp); 15477502Sroot } else 154835811Smarc ttyecho(tp->t_cc[VERASE], tp); 15497502Sroot tp->t_rocount--; 15507502Sroot } 15517502Sroot 15527502Sroot /* 15537502Sroot * Crt back over cnt chars perhaps 15547502Sroot * erasing them. 15557502Sroot */ 15567502Sroot ttyrubo(tp, cnt) 15577625Ssam register struct tty *tp; 15587625Ssam int cnt; 15597502Sroot { 15607502Sroot 15617502Sroot while (--cnt >= 0) 156240712Skarels ttyoutstr("\b \b", tp); 15637502Sroot } 15647502Sroot 15657502Sroot /* 15667502Sroot * Reprint the rawq line. 15677502Sroot * We assume c_cc has already been checked. 15687502Sroot */ 15697502Sroot ttyretype(tp) 15707625Ssam register struct tty *tp; 15717502Sroot { 15727502Sroot register char *cp; 15737502Sroot char *nextc(); 157435811Smarc int s, c; 15757502Sroot 157635811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 157735811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 15787502Sroot (void) ttyoutput('\n', tp); 157917545Skarels s = spltty(); 158035811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 158135811Smarc BIT OF FIRST CHAR ****/ 158235811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 158335811Smarc ttyecho(c, tp); 158435811Smarc } 158535811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 158635811Smarc ttyecho(c, tp); 158735811Smarc } 15889578Ssam tp->t_state &= ~TS_ERASE; 15897502Sroot splx(s); 15907502Sroot tp->t_rocount = tp->t_rawq.c_cc; 15917502Sroot tp->t_rocol = 0; 15927502Sroot } 15937502Sroot 15947502Sroot /* 159535811Smarc * Echo a typed character to the terminal. 15967502Sroot */ 15977502Sroot ttyecho(c, tp) 15987625Ssam register c; 15997625Ssam register struct tty *tp; 16007502Sroot { 16019578Ssam if ((tp->t_state&TS_CNTTB) == 0) 160235811Smarc tp->t_lflag &= ~FLUSHO; 160347545Skarels if (((tp->t_lflag&ECHO) == 0 && 160447545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16057502Sroot return; 160635811Smarc if (tp->t_lflag&ECHOCTL) { 160740712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 160840712Skarels c == 0177) { 16097502Sroot (void) ttyoutput('^', tp); 161035811Smarc c &= TTY_CHARMASK; 16117502Sroot if (c == 0177) 16127502Sroot c = '?'; 16137502Sroot else 16147502Sroot c += 'A' - 1; 16157502Sroot } 16167502Sroot } 161735811Smarc (void) ttyoutput(c, tp); 16187502Sroot } 16197502Sroot 16207502Sroot /* 16217502Sroot * send string cp to tp 16227502Sroot */ 162340712Skarels ttyoutstr(cp, tp) 16247625Ssam register char *cp; 16257625Ssam register struct tty *tp; 16267502Sroot { 16277502Sroot register char c; 16287502Sroot 16297502Sroot while (c = *cp++) 16307502Sroot (void) ttyoutput(c, tp); 16317502Sroot } 16327502Sroot 163349380Skarels /* 163449380Skarels * Wake up any readers on a tty. 163549380Skarels */ 16367502Sroot ttwakeup(tp) 163747545Skarels register struct tty *tp; 16387502Sroot { 16397502Sroot 16407502Sroot if (tp->t_rsel) { 16417502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16427502Sroot tp->t_state &= ~TS_RCOLL; 16437502Sroot tp->t_rsel = 0; 16447502Sroot } 164512752Ssam if (tp->t_state & TS_ASYNC) 164642882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16477502Sroot wakeup((caddr_t)&tp->t_rawq); 16487502Sroot } 164935811Smarc 165035811Smarc /* 165148439Skarels * Look up a code for a specified speed in a conversion table; 165248439Skarels * used by drivers to map software speed values to hardware parameters. 165348439Skarels */ 165448439Skarels ttspeedtab(speed, table) 165548439Skarels register struct speedtab *table; 165648439Skarels { 165748439Skarels 165848439Skarels for ( ; table->sp_speed != -1; table++) 165948439Skarels if (table->sp_speed == speed) 166048439Skarels return (table->sp_code); 166148439Skarels return (-1); 166248439Skarels } 166348439Skarels 166448439Skarels /* 166535811Smarc * set tty hi and low water marks 166635811Smarc * 166735811Smarc * Try to arrange the dynamics so there's about one second 166835811Smarc * from hi to low water. 166935811Smarc * 167035811Smarc */ 167135811Smarc ttsetwater(tp) 167235811Smarc struct tty *tp; 167335811Smarc { 167435811Smarc register cps = tp->t_ospeed / 10; 167535811Smarc register x; 167635811Smarc 167735811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 167835811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 167935811Smarc x += cps; 168035811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 168135811Smarc tp->t_hiwat = roundup(x, CBSIZE); 168235811Smarc #undef clamp 168335811Smarc } 168435811Smarc 168539407Smarc /* 168639407Smarc * (^T) 168739407Smarc * Report on state of foreground process group. 168839407Smarc */ 168939407Smarc ttyinfo(tp) 169039407Smarc struct tty *tp; 169139407Smarc { 169241177Smarc register struct proc *p, *pick = NULL; 169341177Smarc int x, s; 169441177Smarc struct timeval utime, stime; 169542350Smckusick #define pgtok(a) (((a)*NBPG)/1024) 169639407Smarc 169739407Smarc if (ttycheckoutq(tp,0) == 0) 169839407Smarc return; 169941177Smarc /* 170041177Smarc * load average 170141177Smarc */ 170241177Smarc x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT; 170341177Smarc ttyprintf(tp, "load: %d.", x/100); 170441177Smarc ttyoutint(x%100, 10, 2, tp); 170539555Smarc if (tp->t_session == NULL) 170641177Smarc ttyprintf(tp, " not a controlling terminal\n"); 170741177Smarc else if (tp->t_pgrp == NULL) 170841177Smarc ttyprintf(tp, " no foreground process group\n"); 170941177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 171041177Smarc ttyprintf(tp, " empty foreground process group\n"); 171139407Smarc else { 171241177Smarc /* pick interesting process */ 171339407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 171441177Smarc if (proc_compare(pick, p)) 171541177Smarc pick = p; 171639407Smarc } 171741177Smarc ttyprintf(tp, " cmd: %s %d [%s] ", 171841177Smarc pick->p_comm, pick->p_pid, 171948439Skarels pick->p_stat == SRUN ? "running" : 172048439Skarels pick->p_wmesg ? pick->p_wmesg : "iowait"); 172141177Smarc /* 172241177Smarc * cpu time 172341177Smarc */ 172447545Skarels if (curproc == pick) 172541177Smarc s = splclock(); 172641177Smarc utime = pick->p_utime; 172741177Smarc stime = pick->p_stime; 172847545Skarels if (curproc == pick) 172941177Smarc splx(s); 173041177Smarc /* user time */ 173141177Smarc x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */ 173241177Smarc ttyoutint(utime.tv_sec, 10, 1, tp); 173341177Smarc tputchar('.', tp); 173441177Smarc ttyoutint(x, 10, 2, tp); 173541177Smarc tputchar('u', tp); 173641177Smarc tputchar(' ', tp); 173741177Smarc /* system time */ 173841177Smarc x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */ 173941177Smarc ttyoutint(stime.tv_sec, 10, 1, tp); 174041177Smarc tputchar('.', tp); 174141177Smarc ttyoutint(x, 10, 2, tp); 174241177Smarc tputchar('s', tp); 174341177Smarc tputchar(' ', tp); 174441177Smarc /* 174541177Smarc * pctcpu 174641177Smarc */ 174741177Smarc x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT; 174841177Smarc ttyoutint(x/100, 10, 1, tp); 174941177Smarc #ifdef notdef /* do we really want this ??? */ 175041177Smarc tputchar('.', tp); 175141177Smarc ttyoutint(x%100, 10, 2, tp); 175241177Smarc #endif 175347545Skarels ttyprintf(tp, "%% %dk\n", pgtok(pick->p_vmspace->vm_rssize)); 175439407Smarc } 175541177Smarc tp->t_rocount = 0; /* so pending input will be retyped if BS */ 175639407Smarc } 175739407Smarc 175841177Smarc ttyoutint(n, base, min, tp) 175941177Smarc register int n, base, min; 176041177Smarc register struct tty *tp; 176141177Smarc { 176241177Smarc char info[16]; 176341177Smarc register char *p = info; 176441177Smarc 176541177Smarc while (--min >= 0 || n) { 176641177Smarc *p++ = "0123456789abcdef"[n%base]; 176741177Smarc n /= base; 176841177Smarc } 176941177Smarc while (p > info) 177041177Smarc ttyoutput(*--p, tp); 177141177Smarc } 177241177Smarc 177341177Smarc /* 177441177Smarc * Returns 1 if p2 is "better" than p1 177541177Smarc * 177641177Smarc * The algorithm for picking the "interesting" process is thus: 177741177Smarc * 177841177Smarc * 1) (Only foreground processes are eligable - implied) 177941177Smarc * 2) Runnable processes are favored over anything 178041177Smarc * else. The runner with the highest cpu 178141177Smarc * utilization is picked (p_cpu). Ties are 178241177Smarc * broken by picking the highest pid. 178341177Smarc * 3 Next, the sleeper with the shortest sleep 178441177Smarc * time is favored. With ties, we pick out 178541177Smarc * just "short-term" sleepers (SSINTR == 0). 178641177Smarc * Further ties are broken by picking the highest 178741177Smarc * pid. 178841177Smarc * 178941177Smarc */ 179041177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 179145723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 179245723Smckusick #define ONLYA 2 179345723Smckusick #define ONLYB 1 179445723Smckusick #define BOTH 3 179545723Smckusick 179641177Smarc proc_compare(p1, p2) 179741177Smarc register struct proc *p1, *p2; 179841177Smarc { 179941177Smarc 180041177Smarc if (p1 == NULL) 180141177Smarc return (1); 180241177Smarc /* 180341177Smarc * see if at least one of them is runnable 180441177Smarc */ 180545723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 180645723Smckusick case ONLYA: 180745723Smckusick return (0); 180845723Smckusick case ONLYB: 180941177Smarc return (1); 181045723Smckusick case BOTH: 181141177Smarc /* 181241177Smarc * tie - favor one with highest recent cpu utilization 181341177Smarc */ 181441177Smarc if (p2->p_cpu > p1->p_cpu) 181541177Smarc return (1); 181641177Smarc if (p1->p_cpu > p2->p_cpu) 181741177Smarc return (0); 181841177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 181941177Smarc } 182045723Smckusick /* 182145723Smckusick * weed out zombies 182245723Smckusick */ 182345723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 182445723Smckusick case ONLYA: 182545723Smckusick return (1); 182645723Smckusick case ONLYB: 182745723Smckusick return (0); 182845723Smckusick case BOTH: 182945723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 183045723Smckusick } 183141177Smarc /* 183241177Smarc * pick the one with the smallest sleep time 183341177Smarc */ 183441177Smarc if (p2->p_slptime > p1->p_slptime) 183541177Smarc return (0); 183641177Smarc if (p1->p_slptime > p2->p_slptime) 183741177Smarc return (1); 183841177Smarc /* 183941177Smarc * favor one sleeping in a non-interruptible sleep 184041177Smarc */ 184141177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 184241177Smarc return (1); 184341177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 184441177Smarc return (0); 184547545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 184641177Smarc } 184745723Smckusick 184839555Smarc /* 184939555Smarc * Output char to tty; console putchar style. 185039555Smarc */ 185139555Smarc tputchar(c, tp) 185239555Smarc int c; 185339555Smarc struct tty *tp; 185439555Smarc { 185539555Smarc register s = spltty(); 185639555Smarc 185747545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 185839555Smarc if (c == '\n') 185939555Smarc (void) ttyoutput('\r', tp); 186039555Smarc (void) ttyoutput(c, tp); 186139555Smarc ttstart(tp); 186239555Smarc splx(s); 186339555Smarc return (0); 186439555Smarc } 186539555Smarc splx(s); 186639555Smarc return (-1); 186739555Smarc } 186843377Smarc 186944419Smarc /* 187049380Skarels * Sleep on chan, returning ERESTART if tty changed 187149380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 187249380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 187349380Skarels * call will redo validation done at the start of the call. 187444419Smarc */ 187543377Smarc ttysleep(tp, chan, pri, wmesg, timo) 187643377Smarc struct tty *tp; 187743377Smarc caddr_t chan; 187843377Smarc int pri; 187943377Smarc char *wmesg; 188043377Smarc int timo; 188143377Smarc { 188243377Smarc int error; 188343377Smarc short gen = tp->t_gen; 188443377Smarc 188543377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 188643377Smarc return (error); 188743377Smarc if (tp->t_gen != gen) 188843377Smarc return (ERESTART); 188943377Smarc return (0); 189043377Smarc } 1891