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*52485Storek * @(#)tty.c 7.48 (Berkeley) 02/14/92 923387Smckusick */ 1039Sbill 1117095Sbloom #include "param.h" 1217095Sbloom #include "systm.h" 1317095Sbloom #include "ioctl.h" 1439407Smarc #define TTYDEFCHARS 1517095Sbloom #include "tty.h" 1635811Smarc #undef TTYDEFCHARS 1717095Sbloom #include "proc.h" 1817095Sbloom #include "file.h" 1917095Sbloom #include "conf.h" 2029946Skarels #include "dkstat.h" 2117095Sbloom #include "uio.h" 2217095Sbloom #include "kernel.h" 2337728Smckusick #include "vnode.h" 2435811Smarc #include "syslog.h" 2539Sbill 2648439Skarels #include "vm/vm.h" 2737525Smckusick 2849907Sbostic static int proc_compare __P((struct proc *p1, struct proc *p2)); 2949907Sbostic 3040712Skarels /* symbolic sleep message strings */ 3140712Skarels char ttyin[] = "ttyin"; 3240712Skarels char ttyout[] = "ttyout"; 3341370Smarc char ttopen[] = "ttyopn"; 3441370Smarc char ttclos[] = "ttycls"; 3540712Skarels char ttybg[] = "ttybg"; 3640712Skarels char ttybuf[] = "ttybuf"; 3740712Skarels 387436Skre /* 397436Skre * Table giving parity for characters and indicating 4035811Smarc * character classes to tty driver. The 8th bit 4135811Smarc * indicates parity, the 7th bit indicates the character 4235811Smarc * is an alphameric or underscore (for ALTWERASE), and the 4335811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 4449380Skarels * then the character needs no special processing on output; 4549380Skarels * classes other than 0 might be translated or (not currently) 4649380Skarels * require delays. 477436Skre */ 4849380Skarels #define PARITY(c) (partab[c] & 0x80) 4949380Skarels #define ISALPHA(c) (partab[(c)&TTY_CHARMASK] & 0x40) 5049380Skarels #define CCLASSMASK 0x3f 5149380Skarels #define CCLASS(c) (partab[c] & CCLASSMASK) 5239Sbill 5349380Skarels #define E 0x00 /* even parity */ 5449380Skarels #define O 0x80 /* odd parity */ 5549380Skarels #define ALPHA 0x40 /* alpha or underscore */ 5649380Skarels 5749380Skarels #define NO ORDINARY 5849380Skarels #define NA ORDINARY|ALPHA 5949380Skarels #define CC CONTROL 6049380Skarels #define BS BACKSPACE 6149380Skarels #define NL NEWLINE 6249380Skarels #define TB TAB 6349380Skarels #define VT VTAB 6449380Skarels #define CR RETURN 6549380Skarels 667436Skre char partab[] = { 6749380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* nul - bel */ 6849380Skarels O|BS, E|TB, E|NL, O|CC, E|VT, O|CR, O|CC, E|CC, /* bs - si */ 6949380Skarels O|CC, E|CC, E|CC, O|CC, E|CC, O|CC, O|CC, E|CC, /* dle - etb */ 7049380Skarels E|CC, O|CC, O|CC, E|CC, O|CC, E|CC, E|CC, O|CC, /* can - us */ 7149380Skarels O|NO, E|NO, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* sp - ' */ 7249380Skarels E|NO, O|NO, O|NO, E|NO, O|NO, E|NO, E|NO, O|NO, /* ( - / */ 7349380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* 0 - 7 */ 7449380Skarels O|NA, E|NA, E|NO, O|NO, E|NO, O|NO, O|NO, E|NO, /* 8 - ? */ 7549380Skarels O|NO, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* @ - G */ 7649380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* H - O */ 7749380Skarels E|NA, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* P - W */ 7849380Skarels O|NA, E|NA, E|NA, O|NO, E|NO, O|NO, O|NO, O|NA, /* X - _ */ 7949380Skarels E|NO, O|NA, O|NA, E|NA, O|NA, E|NA, E|NA, O|NA, /* ` - g */ 8049380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* h - o */ 8149380Skarels O|NA, E|NA, E|NA, O|NA, E|NA, O|NA, O|NA, E|NA, /* p - w */ 8249380Skarels E|NA, O|NA, O|NA, E|NO, O|NO, E|NO, E|NO, O|CC, /* x - del */ 837436Skre /* 8449380Skarels * "meta" chars; should be settable per charset. 8549380Skarels * For now, treat all as normal characters. 867436Skre */ 8749380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 8849380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 8949380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9049380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9149380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9249380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9349380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9449380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9549380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9649380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9749380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9849380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 9949380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10049380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10149380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 10249380Skarels NA, NA, NA, NA, NA, NA, NA, NA, 1037436Skre }; 10449380Skarels #undef NO 10549380Skarels #undef NA 10649380Skarels #undef CC 10749380Skarels #undef BS 10849380Skarels #undef NL 10949380Skarels #undef TB 11049380Skarels #undef VT 11149380Skarels #undef CR 1127436Skre 11335811Smarc extern struct tty *constty; /* temporary virtual console */ 11435811Smarc 115146Sbill /* 11635811Smarc * Is 'c' a line delimiter ("break" character)? 11739Sbill */ 11840712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ 11940712Skarels (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 12039Sbill 12139Sbill ttychars(tp) 1229578Ssam struct tty *tp; 12339Sbill { 12447545Skarels 12535811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 12639Sbill } 12739Sbill 12839Sbill /* 12949380Skarels * Flush tty after output has drained. 13039Sbill */ 13112752Ssam ttywflush(tp) 13237584Smarc struct tty *tp; 13339Sbill { 13440712Skarels int error; 13539Sbill 13640712Skarels if ((error = ttywait(tp)) == 0) 13740712Skarels ttyflush(tp, FREAD); 13840712Skarels return (error); 13912752Ssam } 14012752Ssam 14135811Smarc /* 14235811Smarc * Wait for output to drain. 14335811Smarc */ 14412752Ssam ttywait(tp) 14512752Ssam register struct tty *tp; 14612752Ssam { 14740712Skarels int error = 0, s = spltty(); 14812752Ssam 14913809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 15037584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 15137584Smarc tp->t_oproc) { 152903Sbill (*tp->t_oproc)(tp); 1535408Swnj tp->t_state |= TS_ASLEEP; 15443377Smarc if (error = ttysleep(tp, (caddr_t)&tp->t_outq, 15543377Smarc TTOPRI | PCATCH, ttyout, 0)) 15640712Skarels break; 157903Sbill } 1589859Ssam splx(s); 15940712Skarels return (error); 16039Sbill } 16139Sbill 162*52485Storek #define flushq(q) { \ 163*52485Storek if ((q)->c_cc) \ 164*52485Storek ndflush(q, (q)->c_cc); \ 16549380Skarels } 16649380Skarels 16739Sbill /* 16849380Skarels * Flush TTY read and/or write queues, 16949380Skarels * notifying anyone waiting. 17039Sbill */ 17112752Ssam ttyflush(tp, rw) 1727625Ssam register struct tty *tp; 173*52485Storek int rw; 17439Sbill { 175*52485Storek register int s; 176903Sbill 17717545Skarels s = spltty(); 178903Sbill if (rw & FREAD) { 17949380Skarels flushq(&tp->t_canq); 18049380Skarels flushq(&tp->t_rawq); 18149380Skarels tp->t_rocount = 0; 18249380Skarels tp->t_rocol = 0; 18349380Skarels tp->t_state &= ~TS_LOCAL; 18437584Smarc ttwakeup(tp); 185903Sbill } 186903Sbill if (rw & FWRITE) { 1875408Swnj tp->t_state &= ~TS_TTSTOP; 188*52485Storek #ifdef sun4c /* XXX */ 189*52485Storek (*tp->t_stop)(tp, rw); 190*52485Storek #else 1915426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 192*52485Storek #endif 19349380Skarels flushq(&tp->t_outq); 19449380Skarels wakeup((caddr_t)&tp->t_outq); 19549380Skarels if (tp->t_wsel) { 19649380Skarels selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 19749380Skarels tp->t_wsel = 0; 19849380Skarels tp->t_state &= ~TS_WCOLL; 19949380Skarels } 200903Sbill } 201903Sbill splx(s); 20239Sbill } 20339Sbill 204903Sbill /* 205903Sbill * Send stop character on input overflow. 206903Sbill */ 207903Sbill ttyblock(tp) 2087625Ssam register struct tty *tp; 20939Sbill { 210903Sbill register x; 2119578Ssam 212903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 213903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 21412752Ssam ttyflush(tp, FREAD|FWRITE); 2155408Swnj tp->t_state &= ~TS_TBLOCK; 216903Sbill } 21715118Skarels /* 21815118Skarels * Block further input iff: 21915118Skarels * Current input > threshold AND input is available to user program 22015118Skarels */ 22142350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 22240712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 22335811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 22442350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 22515118Skarels tp->t_state |= TS_TBLOCK; 22615118Skarels ttstart(tp); 22715118Skarels } 228903Sbill } 22939Sbill } 23039Sbill 23147545Skarels ttstart(tp) 23237584Smarc struct tty *tp; 233121Sbill { 234121Sbill 23547545Skarels if (tp->t_oproc) /* kludge for pty */ 23647545Skarels (*tp->t_oproc)(tp); 23747545Skarels } 23847545Skarels 23947545Skarels ttrstrt(tp) /* XXX */ 24047545Skarels struct tty *tp; 24147545Skarels { 242*52485Storek int s; 24347545Skarels 24440712Skarels #ifdef DIAGNOSTIC 2459578Ssam if (tp == 0) 2469578Ssam panic("ttrstrt"); 24740712Skarels #endif 248*52485Storek s = spltty(); 2495408Swnj tp->t_state &= ~TS_TIMEOUT; 250903Sbill ttstart(tp); 251*52485Storek splx(s); 252121Sbill } 253121Sbill 25439Sbill 25539Sbill /* 25649380Skarels * Common code for ioctls on tty devices. 25749380Skarels * Called after line-discipline-specific ioctl 25849380Skarels * has been called to do discipline-specific functions 25949380Skarels * and/or reject any of these ioctl commands. 26039Sbill */ 2611780Sbill /*ARGSUSED*/ 2627625Ssam ttioctl(tp, com, data, flag) 2637625Ssam register struct tty *tp; 264*52485Storek int com; 2657625Ssam caddr_t data; 266*52485Storek int flag; 26739Sbill { 26847545Skarels register struct proc *p = curproc; /* XXX */ 26939Sbill extern int nldisp; 27037554Smckusick int s, error; 27139Sbill 272903Sbill /* 273903Sbill * If the ioctl involves modification, 27417545Skarels * hang if in the background. 275903Sbill */ 2767625Ssam switch (com) { 27739Sbill 27835811Smarc case TIOCSETD: 279903Sbill case TIOCFLUSH: 28035811Smarc /*case TIOCSPGRP:*/ 2819325Ssam case TIOCSTI: 28217598Sbloom case TIOCSWINSZ: 28335811Smarc case TIOCSETA: 28435811Smarc case TIOCSETAW: 28535811Smarc case TIOCSETAF: 286*52485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 28740030Smarc case TIOCSETP: 28840030Smarc case TIOCSETN: 28940030Smarc case TIOCSETC: 29040030Smarc case TIOCSLTC: 29140030Smarc case TIOCLBIS: 29240030Smarc case TIOCLBIC: 29340030Smarc case TIOCLSET: 29440030Smarc case OTIOCSETD: 29540030Smarc #endif 29647545Skarels while (isbackground(curproc, tp) && 29747545Skarels p->p_pgrp->pg_jobc && (p->p_flag&SPPWAIT) == 0 && 29847545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 29947545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0) { 30047545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 30143377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 30243377Smarc TTOPRI | PCATCH, ttybg, 0)) 30340712Skarels return (error); 304903Sbill } 305903Sbill break; 306903Sbill } 307903Sbill 3089578Ssam /* 3099578Ssam * Process the ioctl. 3109578Ssam */ 3117625Ssam switch (com) { 312903Sbill 3138556Sroot /* get discipline number */ 31439Sbill case TIOCGETD: 3157625Ssam *(int *)data = tp->t_line; 31639Sbill break; 31739Sbill 3188556Sroot /* set line discipline */ 3197625Ssam case TIOCSETD: { 3207625Ssam register int t = *(int *)data; 32135811Smarc dev_t dev = tp->t_dev; 3227625Ssam 32335811Smarc if ((unsigned)t >= nldisp) 32410851Ssam return (ENXIO); 32525584Skarels if (t != tp->t_line) { 32625584Skarels s = spltty(); 32749752Smarc (*linesw[tp->t_line].l_close)(tp, flag); 32825584Skarels error = (*linesw[t].l_open)(dev, tp); 32925584Skarels if (error) { 33035811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 33125584Skarels splx(s); 33225584Skarels return (error); 33325584Skarels } 33425584Skarels tp->t_line = t; 33510851Ssam splx(s); 33610851Ssam } 33739Sbill break; 3387625Ssam } 33939Sbill 3408556Sroot /* prevent more opens on channel */ 3415614Swnj case TIOCEXCL: 342*52485Storek s = spltty(); 3435614Swnj tp->t_state |= TS_XCLUDE; 344*52485Storek splx(s); 3455614Swnj break; 3465614Swnj 3475614Swnj case TIOCNXCL: 348*52485Storek s = spltty(); 3495614Swnj tp->t_state &= ~TS_XCLUDE; 350*52485Storek splx(s); 3515614Swnj break; 3525614Swnj 353*52485Storek #ifdef TIOCHPCL 35439Sbill case TIOCHPCL: 355*52485Storek s = spltty(); 35635811Smarc tp->t_cflag |= HUPCL; 357*52485Storek splx(s); 35839Sbill break; 359*52485Storek #endif 36039Sbill 3613942Sbugs case TIOCFLUSH: { 3627625Ssam register int flags = *(int *)data; 3637625Ssam 3647625Ssam if (flags == 0) 3653942Sbugs flags = FREAD|FWRITE; 3667625Ssam else 3677625Ssam flags &= FREAD|FWRITE; 36812752Ssam ttyflush(tp, flags); 36939Sbill break; 3703944Sbugs } 37139Sbill 37237584Smarc case FIOASYNC: 373*52485Storek s = spltty(); 37437584Smarc if (*(int *)data) 37537584Smarc tp->t_state |= TS_ASYNC; 37637584Smarc else 37737584Smarc tp->t_state &= ~TS_ASYNC; 378*52485Storek splx(s); 37937584Smarc break; 38037584Smarc 38137584Smarc case FIONBIO: 38237584Smarc break; /* XXX remove */ 38337584Smarc 3848556Sroot /* return number of characters immediately available */ 3857625Ssam case FIONREAD: 3867625Ssam *(off_t *)data = ttnread(tp); 387174Sbill break; 388174Sbill 38913077Ssam case TIOCOUTQ: 39013077Ssam *(int *)data = tp->t_outq.c_cc; 39113077Ssam break; 39213077Ssam 3938589Sroot case TIOCSTOP: 39417545Skarels s = spltty(); 3959578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3965573Swnj tp->t_state |= TS_TTSTOP; 397*52485Storek #ifdef sun4c /* XXX */ 398*52485Storek (*tp->t_stop)(tp, 0); 399*52485Storek #else 4005573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 401*52485Storek #endif 4025573Swnj } 4037625Ssam splx(s); 4045573Swnj break; 4055573Swnj 4068589Sroot case TIOCSTART: 40717545Skarels s = spltty(); 40835811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 4095573Swnj tp->t_state &= ~TS_TTSTOP; 41035811Smarc tp->t_lflag &= ~FLUSHO; 4115573Swnj ttstart(tp); 4125573Swnj } 4137625Ssam splx(s); 4145573Swnj break; 4155573Swnj 4169325Ssam /* 4179325Ssam * Simulate typing of a character at the terminal. 4189325Ssam */ 4199325Ssam case TIOCSTI: 42047545Skarels if (p->p_ucred->cr_uid && (flag & FREAD) == 0) 42117183Smckusick return (EPERM); 42247545Skarels if (p->p_ucred->cr_uid && !isctty(p, tp)) 4239325Ssam return (EACCES); 4249578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 4259325Ssam break; 4269325Ssam 42735811Smarc case TIOCGETA: { 42835811Smarc struct termios *t = (struct termios *)data; 42912752Ssam 43035811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 43135811Smarc break; 43235811Smarc } 43335811Smarc 43435811Smarc case TIOCSETA: 43535811Smarc case TIOCSETAW: 43637584Smarc case TIOCSETAF: { 43735811Smarc register struct termios *t = (struct termios *)data; 43840712Skarels 43917545Skarels s = spltty(); 44039407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 44140712Skarels if (error = ttywait(tp)) { 44240712Skarels splx(s); 44340712Skarels return (error); 44440712Skarels } 44545007Smarc if (com == TIOCSETAF) 44639407Smarc ttyflush(tp, FREAD); 44739407Smarc } 44840712Skarels if ((t->c_cflag&CIGNORE) == 0) { 44935811Smarc /* 45035811Smarc * set device hardware 45135811Smarc */ 45237584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 45337584Smarc splx(s); 45435811Smarc return (error); 45537584Smarc } else { 45640712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 45737584Smarc (tp->t_cflag&CLOCAL) && 45840712Skarels (t->c_cflag&CLOCAL) == 0) { 45937584Smarc tp->t_state &= ~TS_ISOPEN; 46037584Smarc tp->t_state |= TS_WOPEN; 46137584Smarc ttwakeup(tp); 46237584Smarc } 46335811Smarc tp->t_cflag = t->c_cflag; 46435811Smarc tp->t_ispeed = t->c_ispeed; 46535811Smarc tp->t_ospeed = t->c_ospeed; 46634492Skarels } 46735811Smarc ttsetwater(tp); 46812752Ssam } 46939407Smarc if (com != TIOCSETAF) { 47035811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 47135811Smarc if (t->c_lflag&ICANON) { 47235811Smarc tp->t_lflag |= PENDIN; 47335811Smarc ttwakeup(tp); 47435811Smarc } 47535811Smarc else { 47635811Smarc struct clist tq; 47735811Smarc 47835811Smarc catq(&tp->t_rawq, &tp->t_canq); 47935811Smarc tq = tp->t_rawq; 48035811Smarc tp->t_rawq = tp->t_canq; 48135811Smarc tp->t_canq = tq; 48235811Smarc } 48312752Ssam } 48435811Smarc tp->t_iflag = t->c_iflag; 48535811Smarc tp->t_oflag = t->c_oflag; 48642882Smarc /* 48742882Smarc * Make the EXTPROC bit read only. 48842882Smarc */ 48942882Smarc if (tp->t_lflag&EXTPROC) 49042882Smarc t->c_lflag |= EXTPROC; 49142882Smarc else 49242882Smarc t->c_lflag &= ~EXTPROC; 49335811Smarc tp->t_lflag = t->c_lflag; 49435811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 49512752Ssam splx(s); 49612752Ssam break; 49712752Ssam } 49812752Ssam 49912752Ssam /* 50039555Smarc * Set controlling terminal. 50139555Smarc * Session ctty vnode pointer set in vnode layer. 50234492Skarels */ 50347545Skarels case TIOCSCTTY: 50439555Smarc if (!SESS_LEADER(p) || 50539555Smarc (p->p_session->s_ttyvp || tp->t_session) && 50639555Smarc (tp->t_session != p->p_session)) 50739407Smarc return (EPERM); 50835811Smarc tp->t_session = p->p_session; 50939555Smarc tp->t_pgrp = p->p_pgrp; 51039555Smarc p->p_session->s_ttyp = tp; 51139555Smarc p->p_flag |= SCTTY; 51234492Skarels break; 51339555Smarc 51434492Skarels /* 51535811Smarc * Set terminal process group. 51617545Skarels */ 51718650Sbloom case TIOCSPGRP: { 51835811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 51917545Skarels 52039555Smarc if (!isctty(p, tp)) 52139555Smarc return (ENOTTY); 52240030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 52339555Smarc return (EPERM); 52439555Smarc tp->t_pgrp = pgrp; 52512752Ssam break; 52618650Sbloom } 52712752Ssam 52812752Ssam case TIOCGPGRP: 52947545Skarels if (!isctty(p, tp)) 53039555Smarc return (ENOTTY); 53145007Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; 53212752Ssam break; 53312752Ssam 53417598Sbloom case TIOCSWINSZ: 53518650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 53618650Sbloom sizeof (struct winsize))) { 53717598Sbloom tp->t_winsize = *(struct winsize *)data; 53842882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 53917598Sbloom } 54017598Sbloom break; 54117598Sbloom 54217598Sbloom case TIOCGWINSZ: 54317598Sbloom *(struct winsize *)data = tp->t_winsize; 54417598Sbloom break; 54517598Sbloom 54630534Skarels case TIOCCONS: 54730534Skarels if (*(int *)data) { 54842141Smckusick if (constty && constty != tp && 54942141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 55042141Smckusick (TS_CARR_ON|TS_ISOPEN)) 55130534Skarels return (EBUSY); 55230534Skarels #ifndef UCONSOLE 55347545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55437554Smckusick return (error); 55530534Skarels #endif 55630534Skarels constty = tp; 55730534Skarels } else if (tp == constty) 55833404Skarels constty = NULL; 55930534Skarels break; 56030534Skarels 56148439Skarels case TIOCDRAIN: 56248439Skarels if (error = ttywait(tp)) 56348439Skarels return (error); 56448439Skarels break; 56548439Skarels 56647545Skarels default: 567*52485Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 56847545Skarels return (ttcompat(tp, com, data, flag)); 56947545Skarels #else 57047545Skarels return (-1); 57135811Smarc #endif 57239Sbill } 5738556Sroot return (0); 57439Sbill } 5754484Swnj 5764484Swnj ttnread(tp) 5774484Swnj struct tty *tp; 5784484Swnj { 5794484Swnj int nread = 0; 5804484Swnj 58135811Smarc if (tp->t_lflag & PENDIN) 5824484Swnj ttypend(tp); 5834484Swnj nread = tp->t_canq.c_cc; 58435811Smarc if ((tp->t_lflag & ICANON) == 0) 5854484Swnj nread += tp->t_rawq.c_cc; 5864484Swnj return (nread); 5874484Swnj } 5884484Swnj 5895408Swnj ttselect(dev, rw) 5904484Swnj dev_t dev; 5915408Swnj int rw; 5924484Swnj { 5934484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5944484Swnj int nread; 59517545Skarels int s = spltty(); 5964484Swnj 5975408Swnj switch (rw) { 5984484Swnj 5994484Swnj case FREAD: 6004484Swnj nread = ttnread(tp); 60137584Smarc if (nread > 0 || 60240712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 6035408Swnj goto win; 6044938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 6055408Swnj tp->t_state |= TS_RCOLL; 6064484Swnj else 60747545Skarels tp->t_rsel = curproc; 6085408Swnj break; 6094484Swnj 6105408Swnj case FWRITE: 61135811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 6125408Swnj goto win; 6135408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 6145408Swnj tp->t_state |= TS_WCOLL; 6155408Swnj else 61647545Skarels tp->t_wsel = curproc; 6175408Swnj break; 6184484Swnj } 6195408Swnj splx(s); 6205408Swnj return (0); 6215408Swnj win: 6225408Swnj splx(s); 6235408Swnj return (1); 6244484Swnj } 6257436Skre 6267502Sroot /* 62749380Skarels * Initial open of tty, or (re)entry to standard tty line discipline. 6287502Sroot */ 6297502Sroot ttyopen(dev, tp) 6307625Ssam dev_t dev; 6317625Ssam register struct tty *tp; 6327502Sroot { 633*52485Storek int s = spltty(); 6347502Sroot 6357502Sroot tp->t_dev = dev; 63635811Smarc 6377502Sroot tp->t_state &= ~TS_WOPEN; 63817545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 63917545Skarels tp->t_state |= TS_ISOPEN; 64017598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 64117545Skarels } 642*52485Storek splx(s); 6438556Sroot return (0); 6447502Sroot } 6457502Sroot 6467502Sroot /* 64725391Skarels * "close" a line discipline 64825391Skarels */ 64949752Smarc ttylclose(tp, flag) 65049752Smarc struct tty *tp; 65149752Smarc int flag; 65225391Skarels { 65325391Skarels 65449752Smarc if (flag&IO_NDELAY) 65549752Smarc ttyflush(tp, FREAD|FWRITE); 65649752Smarc else 65749752Smarc ttywflush(tp); 65825391Skarels } 65925391Skarels 66025391Skarels /* 66149380Skarels * Handle close() on a tty line: flush and set to initial state, 66249380Skarels * bumping generation number so that pending read/write calls 66349380Skarels * can detect recycling of the tty. 6647502Sroot */ 6657502Sroot ttyclose(tp) 6667625Ssam register struct tty *tp; 6677502Sroot { 66830534Skarels if (constty == tp) 66930534Skarels constty = NULL; 67025391Skarels ttyflush(tp, FREAD|FWRITE); 67139555Smarc tp->t_session = NULL; 67239555Smarc tp->t_pgrp = NULL; 6737502Sroot tp->t_state = 0; 67443377Smarc tp->t_gen++; 67540712Skarels return (0); 6767502Sroot } 6777502Sroot 6787502Sroot /* 67925391Skarels * Handle modem control transition on a tty. 68025391Skarels * Flag indicates new state of carrier. 68125391Skarels * Returns 0 if the line should be turned off, otherwise 1. 68225391Skarels */ 68325391Skarels ttymodem(tp, flag) 68425391Skarels register struct tty *tp; 685*52485Storek int flag; 68625391Skarels { 68725391Skarels 68842193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 68925391Skarels /* 69025391Skarels * MDMBUF: do flow control according to carrier flag 69125391Skarels */ 69225391Skarels if (flag) { 69325391Skarels tp->t_state &= ~TS_TTSTOP; 69425391Skarels ttstart(tp); 69525391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 69625391Skarels tp->t_state |= TS_TTSTOP; 697*52485Storek #ifdef sun4c /* XXX */ 698*52485Storek (*tp->t_stop)(tp, 0); 699*52485Storek #else 70025391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 701*52485Storek #endif 70225391Skarels } 70325391Skarels } else if (flag == 0) { 70425391Skarels /* 70525391Skarels * Lost carrier. 70625391Skarels */ 70725391Skarels tp->t_state &= ~TS_CARR_ON; 70842193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 70942193Smarc if (tp->t_session && tp->t_session->s_leader) 71042193Smarc psignal(tp->t_session->s_leader, SIGHUP); 71142193Smarc ttyflush(tp, FREAD|FWRITE); 71242193Smarc return (0); 71325391Skarels } 71425391Skarels } else { 71525391Skarels /* 71625391Skarels * Carrier now on. 71725391Skarels */ 71825391Skarels tp->t_state |= TS_CARR_ON; 71937584Smarc ttwakeup(tp); 72025391Skarels } 72125391Skarels return (1); 72225391Skarels } 72325391Skarels 72425391Skarels /* 72525404Skarels * Default modem control routine (for other line disciplines). 72625404Skarels * Return argument flag, to turn off device on carrier drop. 72725404Skarels */ 72825415Skarels nullmodem(tp, flag) 72925415Skarels register struct tty *tp; 73025404Skarels int flag; 73125404Skarels { 73225404Skarels 73325404Skarels if (flag) 73425404Skarels tp->t_state |= TS_CARR_ON; 73539407Smarc else { 73625404Skarels tp->t_state &= ~TS_CARR_ON; 73742193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 73842193Smarc if (tp->t_session && tp->t_session->s_leader) 73942193Smarc psignal(tp->t_session->s_leader, SIGHUP); 74042193Smarc return (0); 74142193Smarc } 74239407Smarc } 74342193Smarc return (1); 74425404Skarels } 74525404Skarels 74625404Skarels /* 7477502Sroot * reinput pending characters after state switch 74817545Skarels * call at spltty(). 7497502Sroot */ 7507502Sroot ttypend(tp) 7517625Ssam register struct tty *tp; 7527502Sroot { 7537502Sroot struct clist tq; 7547502Sroot register c; 7557502Sroot 75635811Smarc tp->t_lflag &= ~PENDIN; 7579578Ssam tp->t_state |= TS_TYPEN; 7587502Sroot tq = tp->t_rawq; 7597502Sroot tp->t_rawq.c_cc = 0; 7607502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7617502Sroot while ((c = getc(&tq)) >= 0) 7627502Sroot ttyinput(c, tp); 7639578Ssam tp->t_state &= ~TS_TYPEN; 7647502Sroot } 7657502Sroot 7667502Sroot /* 76749380Skarels * Process input of a single character received on a tty. 7687502Sroot */ 7697502Sroot ttyinput(c, tp) 7707625Ssam register c; 7717625Ssam register struct tty *tp; 7727502Sroot { 77335811Smarc register int iflag = tp->t_iflag; 77435811Smarc register int lflag = tp->t_lflag; 77535811Smarc register u_char *cc = tp->t_cc; 77635811Smarc int i, err; 7777502Sroot 7789578Ssam /* 7799578Ssam * If input is pending take it first. 7809578Ssam */ 78135811Smarc if (lflag&PENDIN) 7827502Sroot ttypend(tp); 78335811Smarc /* 78435811Smarc * Gather stats. 78535811Smarc */ 7867502Sroot tk_nin++; 78735811Smarc if (lflag&ICANON) { 78835811Smarc tk_cancc++; 78935811Smarc tp->t_cancc++; 79035811Smarc } else { 79135811Smarc tk_rawcc++; 79235811Smarc tp->t_rawcc++; 79335811Smarc } 7949578Ssam /* 79535811Smarc * Handle exceptional conditions (break, parity, framing). 7969578Ssam */ 79735811Smarc if (err = (c&TTY_ERRORMASK)) { 79835811Smarc c &= ~TTY_ERRORMASK; 79935811Smarc if (err&TTY_FE && !c) { /* break */ 80035811Smarc if (iflag&IGNBRK) 80135811Smarc goto endcase; 80235811Smarc else if (iflag&BRKINT && lflag&ISIG && 80335811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 80435811Smarc c = cc[VINTR]; 80547545Skarels else if (iflag&PARMRK) 80647545Skarels goto parmrk; 80735811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 80835811Smarc if (iflag&IGNPAR) 80935811Smarc goto endcase; 81035811Smarc else if (iflag&PARMRK) { 81135811Smarc parmrk: 81235811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 81335811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 81435811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 81535811Smarc goto endcase; 81635811Smarc } else 81735811Smarc c = 0; 8187502Sroot } 8199578Ssam } 8209578Ssam /* 82135811Smarc * In tandem mode, check high water mark. 8229578Ssam */ 82335811Smarc if (iflag&IXOFF) 82435811Smarc ttyblock(tp); 82535811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 82649380Skarels c &= ~0x80; 82744419Smarc if ((tp->t_lflag&EXTPROC) == 0) { 82844419Smarc /* 82944419Smarc * Check for literal nexting very first 83044419Smarc */ 83144419Smarc if (tp->t_state&TS_LNCH) { 83244419Smarc c |= TTY_QUOTE; 83344419Smarc tp->t_state &= ~TS_LNCH; 83444419Smarc } 83544419Smarc /* 83644419Smarc * Scan for special characters. This code 83744419Smarc * is really just a big case statement with 83844419Smarc * non-constant cases. The bottom of the 83944419Smarc * case statement is labeled ``endcase'', so goto 84044419Smarc * it after a case match, or similar. 84144419Smarc */ 84244419Smarc 84344419Smarc /* 84444419Smarc * Control chars which aren't controlled 84544419Smarc * by ICANON, ISIG, or IXON. 84644419Smarc */ 84744419Smarc if (lflag&IEXTEN) { 84844419Smarc if (CCEQ(cc[VLNEXT], c)) { 84944419Smarc if (lflag&ECHO) { 85044419Smarc if (lflag&ECHOE) 85144419Smarc ttyoutstr("^\b", tp); 85244419Smarc else 85344419Smarc ttyecho(c, tp); 85444419Smarc } 85544419Smarc tp->t_state |= TS_LNCH; 85644419Smarc goto endcase; 85744419Smarc } 85844419Smarc if (CCEQ(cc[VDISCARD], c)) { 85944419Smarc if (lflag&FLUSHO) 86044419Smarc tp->t_lflag &= ~FLUSHO; 86144419Smarc else { 86244419Smarc ttyflush(tp, FWRITE); 86335811Smarc ttyecho(c, tp); 86444419Smarc if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 86544419Smarc ttyretype(tp); 86644419Smarc tp->t_lflag |= FLUSHO; 86744419Smarc } 86844419Smarc goto startoutput; 86935811Smarc } 8709578Ssam } 87144419Smarc /* 87244419Smarc * Signals. 87344419Smarc */ 87444419Smarc if (lflag&ISIG) { 87544419Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 87644419Smarc if ((lflag&NOFLSH) == 0) 87744419Smarc ttyflush(tp, FREAD|FWRITE); 8787502Sroot ttyecho(c, tp); 87944419Smarc pgsignal(tp->t_pgrp, 88044419Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 88144419Smarc goto endcase; 8827502Sroot } 88344419Smarc if (CCEQ(cc[VSUSP], c)) { 88444419Smarc if ((lflag&NOFLSH) == 0) 88544419Smarc ttyflush(tp, FREAD); 88644419Smarc ttyecho(c, tp); 88744419Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 88844419Smarc goto endcase; 88944419Smarc } 8909578Ssam } 89144419Smarc /* 89244419Smarc * Handle start/stop characters. 89344419Smarc */ 89444419Smarc if (iflag&IXON) { 89544419Smarc if (CCEQ(cc[VSTOP], c)) { 89644419Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 89744419Smarc tp->t_state |= TS_TTSTOP; 898*52485Storek #ifdef sun4c /* XXX */ 899*52485Storek (*tp->t_stop)(tp, 0); 900*52485Storek #else 90144419Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 90244419Smarc 0); 903*52485Storek #endif 90444419Smarc return; 90544419Smarc } 90644419Smarc if (!CCEQ(cc[VSTART], c)) 90744419Smarc return; 90844419Smarc /* 90944419Smarc * if VSTART == VSTOP then toggle 91044419Smarc */ 91144419Smarc goto endcase; 91235811Smarc } 91344419Smarc if (CCEQ(cc[VSTART], c)) 91444419Smarc goto restartoutput; 9159578Ssam } 91644419Smarc /* 91744419Smarc * IGNCR, ICRNL, & INLCR 91844419Smarc */ 91944419Smarc if (c == '\r') { 92044419Smarc if (iflag&IGNCR) 92144419Smarc goto endcase; 92244419Smarc else if (iflag&ICRNL) 92344419Smarc c = '\n'; 92444419Smarc } else if (c == '\n' && iflag&INLCR) 92544419Smarc c = '\r'; 9269578Ssam } 92747545Skarels if ((tp->t_lflag&EXTPROC) == 0 && lflag&ICANON) { 92844419Smarc /* 92944419Smarc * From here on down canonical mode character 93044419Smarc * processing takes place. 93144419Smarc */ 93244419Smarc /* 93344419Smarc * erase (^H / ^?) 93444419Smarc */ 93544419Smarc if (CCEQ(cc[VERASE], c)) { 93644419Smarc if (tp->t_rawq.c_cc) 9379578Ssam ttyrub(unputc(&tp->t_rawq), tp); 93844419Smarc goto endcase; 9399578Ssam } 94044419Smarc /* 94144419Smarc * kill (^U) 94244419Smarc */ 94344419Smarc if (CCEQ(cc[VKILL], c)) { 94444419Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 94544419Smarc (lflag&ECHOPRT) == 0) { 94644419Smarc while (tp->t_rawq.c_cc) 94744419Smarc ttyrub(unputc(&tp->t_rawq), tp); 94844419Smarc } else { 94944419Smarc ttyecho(c, tp); 95044419Smarc if (lflag&ECHOK || lflag&ECHOKE) 95144419Smarc ttyecho('\n', tp); 952*52485Storek flushq(&tp->t_rawq); 95344419Smarc tp->t_rocount = 0; 95444419Smarc } 95544419Smarc tp->t_state &= ~TS_LOCAL; 95644419Smarc goto endcase; 95744419Smarc } 95844419Smarc /* 95944419Smarc * word erase (^W) 96044419Smarc */ 96144419Smarc if (CCEQ(cc[VWERASE], c)) { 96244419Smarc int ctype; 96347545Skarels int alt = lflag&ALTWERASE; 96435811Smarc 96544419Smarc /* 96644419Smarc * erase whitespace 96744419Smarc */ 96844419Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 96944419Smarc ttyrub(c, tp); 97044419Smarc if (c == -1) 97144419Smarc goto endcase; 97244419Smarc /* 97347545Skarels * erase last char of word and remember the 97447545Skarels * next chars type (for ALTWERASE) 97544419Smarc */ 97635811Smarc ttyrub(c, tp); 97744419Smarc c = unputc(&tp->t_rawq); 97847545Skarels if (c == -1) 97944419Smarc goto endcase; 98051003Sbostic if (c == ' ' || c == '\t') { 98151003Sbostic putc(c, &tp->t_rawq); 98251003Sbostic goto endcase; 98351003Sbostic } 98449380Skarels ctype = ISALPHA(c); 98544419Smarc /* 98647545Skarels * erase rest of word 98744419Smarc */ 98844419Smarc do { 98944419Smarc ttyrub(c, tp); 99044419Smarc c = unputc(&tp->t_rawq); 99144419Smarc if (c == -1) 99244419Smarc goto endcase; 99347545Skarels } while (c != ' ' && c != '\t' && 99449380Skarels (alt == 0 || ISALPHA(c) == ctype)); 99544419Smarc (void) putc(c, &tp->t_rawq); 99634492Skarels goto endcase; 99744419Smarc } 99835811Smarc /* 99944419Smarc * reprint line (^R) 100035811Smarc */ 100144419Smarc if (CCEQ(cc[VREPRINT], c)) { 100244419Smarc ttyretype(tp); 100334492Skarels goto endcase; 100434492Skarels } 100535811Smarc /* 100644419Smarc * ^T - kernel info and generate SIGINFO 100735811Smarc */ 100844419Smarc if (CCEQ(cc[VSTATUS], c)) { 100951068Smarc if (lflag&ISIG) 101051068Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 101144419Smarc if ((lflag&NOKERNINFO) == 0) 101244419Smarc ttyinfo(tp); 101344419Smarc goto endcase; 101444419Smarc } 10159578Ssam } 10169578Ssam /* 10179578Ssam * Check for input buffer overflow 10189578Ssam */ 101947545Skarels if (tp->t_rawq.c_cc + tp->t_canq.c_cc >= TTYHOG) { 102035811Smarc if (iflag&IMAXBEL) { 102135811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 102235811Smarc (void) ttyoutput(CTRL('g'), tp); 102335811Smarc } else 102435811Smarc ttyflush(tp, FREAD | FWRITE); 10259578Ssam goto endcase; 102610391Ssam } 10279578Ssam /* 10289578Ssam * Put data char in q for user and 10299578Ssam * wakeup on seeing a line delimiter. 10309578Ssam */ 10319578Ssam if (putc(c, &tp->t_rawq) >= 0) { 103247545Skarels if ((lflag&ICANON) == 0) { 103347545Skarels ttwakeup(tp); 103447545Skarels ttyecho(c, tp); 103547545Skarels goto endcase; 103647545Skarels } 103735811Smarc if (ttbreakc(c)) { 10389578Ssam tp->t_rocount = 0; 10399578Ssam catq(&tp->t_rawq, &tp->t_canq); 10407502Sroot ttwakeup(tp); 10419578Ssam } else if (tp->t_rocount++ == 0) 10429578Ssam tp->t_rocol = tp->t_col; 10439578Ssam if (tp->t_state&TS_ERASE) { 104435811Smarc /* 104535811Smarc * end of prterase \.../ 104635811Smarc */ 10479578Ssam tp->t_state &= ~TS_ERASE; 10489578Ssam (void) ttyoutput('/', tp); 10499578Ssam } 10509578Ssam i = tp->t_col; 10517502Sroot ttyecho(c, tp); 105235811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 105335811Smarc /* 105435811Smarc * Place the cursor over the '^' of the ^D. 105535811Smarc */ 10569578Ssam i = MIN(2, tp->t_col - i); 10579578Ssam while (i > 0) { 10589578Ssam (void) ttyoutput('\b', tp); 10599578Ssam i--; 10609578Ssam } 10619578Ssam } 10627502Sroot } 10639578Ssam endcase: 10649578Ssam /* 106535811Smarc * IXANY means allow any character to restart output. 10669578Ssam */ 106740712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 106840712Skarels cc[VSTART] != cc[VSTOP]) 10697502Sroot return; 10709578Ssam restartoutput: 10717502Sroot tp->t_state &= ~TS_TTSTOP; 107235811Smarc tp->t_lflag &= ~FLUSHO; 10739578Ssam startoutput: 10747502Sroot ttstart(tp); 10757502Sroot } 10767502Sroot 10777502Sroot /* 107849380Skarels * Output a single character on a tty, doing output processing 107949380Skarels * as needed (expanding tabs, newline processing, etc.). 108049380Skarels * Returns < 0 if putc succeeds, otherwise returns char to resend. 10817502Sroot * Must be recursive. 10827502Sroot */ 10837502Sroot ttyoutput(c, tp) 10847502Sroot register c; 10857502Sroot register struct tty *tp; 10867502Sroot { 108749380Skarels register int col; 108835811Smarc register long oflag = tp->t_oflag; 108935811Smarc 109040712Skarels if ((oflag&OPOST) == 0) { 109135811Smarc if (tp->t_lflag&FLUSHO) 10927502Sroot return (-1); 10937502Sroot if (putc(c, &tp->t_outq)) 10947625Ssam return (c); 10957502Sroot tk_nout++; 109635811Smarc tp->t_outcc++; 10977502Sroot return (-1); 10987502Sroot } 109935811Smarc c &= TTY_CHARMASK; 11007502Sroot /* 110149380Skarels * Do tab expansion if OXTABS is set. 110242882Smarc * Special case if we have external processing, we don't 110342882Smarc * do the tab expansion because we'll probably get it 110442882Smarc * wrong. If tab expansion needs to be done, let it 110542882Smarc * happen externally. 11067502Sroot */ 110747545Skarels if (c == '\t' && oflag&OXTABS && (tp->t_lflag&EXTPROC) == 0) { 11087502Sroot register int s; 11097502Sroot 11107502Sroot c = 8 - (tp->t_col&7); 111135811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 111217545Skarels s = spltty(); /* don't interrupt tabs */ 11137502Sroot c -= b_to_q(" ", c, &tp->t_outq); 11147502Sroot tk_nout += c; 111535811Smarc tp->t_outcc += c; 11167502Sroot splx(s); 11177502Sroot } 11187502Sroot tp->t_col += c; 11197502Sroot return (c ? -1 : '\t'); 11207502Sroot } 112135811Smarc if (c == CEOT && oflag&ONOEOT) 112247545Skarels return (-1); 11237502Sroot tk_nout++; 112435811Smarc tp->t_outcc++; 11257502Sroot /* 112649380Skarels * Newline translation: if ONLCR is set, 112749380Skarels * translate newline into "\r\n". 11287502Sroot */ 112935811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 11307502Sroot return (c); 113135811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 113235811Smarc return (c); 113347545Skarels 113449380Skarels col = tp->t_col; 113549380Skarels switch (CCLASS(c)) { 11367502Sroot 11377502Sroot case ORDINARY: 113849380Skarels col++; 11397502Sroot 11407502Sroot case CONTROL: 11417502Sroot break; 11427502Sroot 11437502Sroot case BACKSPACE: 114449380Skarels if (col > 0) 114549380Skarels col--; 11467502Sroot break; 11477502Sroot 11487502Sroot case NEWLINE: 114949380Skarels col = 0; 11507502Sroot break; 11517502Sroot 11527502Sroot case TAB: 115349380Skarels col = (col + 8) &~ 0x7; 11547502Sroot break; 11557502Sroot 11567502Sroot case RETURN: 115749380Skarels col = 0; 11587502Sroot } 115949380Skarels tp->t_col = col; 11607502Sroot return (-1); 11617502Sroot } 11627502Sroot 11637502Sroot /* 116449380Skarels * Process a read call on a tty device. 11657502Sroot */ 116637584Smarc ttread(tp, uio, flag) 11677625Ssam register struct tty *tp; 11687722Swnj struct uio *uio; 1169*52485Storek int flag; 11707502Sroot { 11717502Sroot register struct clist *qp; 117235811Smarc register int c; 117341383Smarc register long lflag; 117435811Smarc register u_char *cc = tp->t_cc; 117547545Skarels register struct proc *p = curproc; 11769859Ssam int s, first, error = 0; 11777502Sroot 11787502Sroot loop: 117941383Smarc lflag = tp->t_lflag; 118037584Smarc s = spltty(); 11819578Ssam /* 118237584Smarc * take pending input first 11839578Ssam */ 118435811Smarc if (lflag&PENDIN) 11857502Sroot ttypend(tp); 11869859Ssam splx(s); 118740712Skarels 11889578Ssam /* 11899578Ssam * Hang process if it's in the background. 11909578Ssam */ 119147545Skarels if (isbackground(p, tp)) { 119247545Skarels if ((p->p_sigignore & sigmask(SIGTTIN)) || 119347545Skarels (p->p_sigmask & sigmask(SIGTTIN)) || 119447545Skarels p->p_flag&SPPWAIT || p->p_pgrp->pg_jobc == 0) 11958520Sroot return (EIO); 119647545Skarels pgsignal(p->p_pgrp, SIGTTIN, 1); 119743377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 119843377Smarc ttybg, 0)) 119940712Skarels return (error); 120023165Sbloom goto loop; 12017502Sroot } 120240712Skarels 12039578Ssam /* 120435811Smarc * If canonical, use the canonical queue, 120535811Smarc * else use the raw queue. 120637584Smarc * 120747545Skarels * (should get rid of clists...) 12089578Ssam */ 120935811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 121040712Skarels 12119578Ssam /* 121240712Skarels * If there is no input, sleep on rawq 121340712Skarels * awaiting hardware receipt and notification. 121440712Skarels * If we have data, we don't need to check for carrier. 12159578Ssam */ 121617545Skarels s = spltty(); 12179578Ssam if (qp->c_cc <= 0) { 121840712Skarels int carrier; 121940712Skarels 122040712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 122140712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 12229859Ssam splx(s); 122340712Skarels return (0); /* EOF */ 12247502Sroot } 122537728Smckusick if (flag & IO_NDELAY) { 122637584Smarc splx(s); 122737584Smarc return (EWOULDBLOCK); 122837584Smarc } 122943377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 123040712Skarels carrier ? ttyin : ttopen, 0); 12319859Ssam splx(s); 123243377Smarc if (error) 123340712Skarels return (error); 12349578Ssam goto loop; 12359578Ssam } 12369859Ssam splx(s); 123740712Skarels 12389578Ssam /* 123935811Smarc * Input present, check for input mapping and processing. 12409578Ssam */ 12419578Ssam first = 1; 12429578Ssam while ((c = getc(qp)) >= 0) { 12439578Ssam /* 124435811Smarc * delayed suspend (^Y) 12459578Ssam */ 124635811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 124742882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12489578Ssam if (first) { 124943377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 125043377Smarc TTIPRI | PCATCH, ttybg, 0)) 125140712Skarels break; 12529578Ssam goto loop; 12539578Ssam } 12549578Ssam break; 12557502Sroot } 12569578Ssam /* 125735811Smarc * Interpret EOF only in canonical mode. 12589578Ssam */ 125935811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12609578Ssam break; 12619578Ssam /* 12629578Ssam * Give user character. 12639578Ssam */ 126440712Skarels error = ureadc(c, uio); 12659578Ssam if (error) 12669578Ssam break; 126714938Smckusick if (uio->uio_resid == 0) 12689578Ssam break; 12699578Ssam /* 127035811Smarc * In canonical mode check for a "break character" 12719578Ssam * marking the end of a "line of input". 12729578Ssam */ 127340712Skarels if (lflag&ICANON && ttbreakc(c)) 12749578Ssam break; 12759578Ssam first = 0; 12767502Sroot } 12779578Ssam /* 12789578Ssam * Look to unblock output now that (presumably) 12799578Ssam * the input queue has gone down. 12809578Ssam */ 1281*52485Storek s = spltty(); 128235811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 128347545Skarels if (cc[VSTART] != _POSIX_VDISABLE && 128447545Skarels putc(cc[VSTART], &tp->t_outq) == 0) { 12857502Sroot tp->t_state &= ~TS_TBLOCK; 12867502Sroot ttstart(tp); 12877502Sroot } 128835811Smarc } 1289*52485Storek splx(s); 12908520Sroot return (error); 12917502Sroot } 12927502Sroot 12937502Sroot /* 129425391Skarels * Check the output queue on tp for space for a kernel message 129525391Skarels * (from uprintf/tprintf). Allow some space over the normal 129625391Skarels * hiwater mark so we don't lose messages due to normal flow 129725391Skarels * control, but don't let the tty run amok. 129830695Skarels * Sleeps here are not interruptible, but we return prematurely 129930695Skarels * if new signals come in. 130025391Skarels */ 130125391Skarels ttycheckoutq(tp, wait) 130225391Skarels register struct tty *tp; 130325391Skarels int wait; 130425391Skarels { 130530695Skarels int hiwat, s, oldsig; 130648439Skarels extern int wakeup(); 130725391Skarels 130835811Smarc hiwat = tp->t_hiwat; 130925391Skarels s = spltty(); 1310*52485Storek oldsig = wait ? curproc->p_sig : 0; 131125391Skarels if (tp->t_outq.c_cc > hiwat + 200) 131229946Skarels while (tp->t_outq.c_cc > hiwat) { 131329946Skarels ttstart(tp); 131447545Skarels if (wait == 0 || curproc->p_sig != oldsig) { 131529946Skarels splx(s); 131629946Skarels return (0); 131729946Skarels } 131830695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 131929946Skarels tp->t_state |= TS_ASLEEP; 132030695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 132125391Skarels } 132225391Skarels splx(s); 132325391Skarels return (1); 132425391Skarels } 132525391Skarels 132625391Skarels /* 132749380Skarels * Process a write call on a tty device. 13287502Sroot */ 132937584Smarc ttwrite(tp, uio, flag) 13307625Ssam register struct tty *tp; 13319578Ssam register struct uio *uio; 1332*52485Storek int flag; 13337502Sroot { 13347502Sroot register char *cp; 133540712Skarels register int cc = 0, ce; 133647545Skarels register struct proc *p = curproc; 13379578Ssam int i, hiwat, cnt, error, s; 13387502Sroot char obuf[OBUFSIZ]; 13397502Sroot 134035811Smarc hiwat = tp->t_hiwat; 13419578Ssam cnt = uio->uio_resid; 13429578Ssam error = 0; 13437502Sroot loop: 134437584Smarc s = spltty(); 134540712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 134637584Smarc if (tp->t_state&TS_ISOPEN) { 134737584Smarc splx(s); 134837584Smarc return (EIO); 134937728Smckusick } else if (flag & IO_NDELAY) { 135037584Smarc splx(s); 135140712Skarels error = EWOULDBLOCK; 135240712Skarels goto out; 135337584Smarc } else { 135437584Smarc /* 135537584Smarc * sleep awaiting carrier 135637584Smarc */ 135743377Smarc error = ttysleep(tp, (caddr_t)&tp->t_rawq, 135843377Smarc TTIPRI | PCATCH,ttopen, 0); 135937584Smarc splx(s); 136043377Smarc if (error) 136140712Skarels goto out; 136237584Smarc goto loop; 136337584Smarc } 136437584Smarc } 136537584Smarc splx(s); 13669578Ssam /* 13679578Ssam * Hang the process if it's in the background. 13689578Ssam */ 136947545Skarels if (isbackground(p, tp) && 137047545Skarels tp->t_lflag&TOSTOP && (p->p_flag&SPPWAIT) == 0 && 137147545Skarels (p->p_sigignore & sigmask(SIGTTOU)) == 0 && 137247545Skarels (p->p_sigmask & sigmask(SIGTTOU)) == 0 && 137347545Skarels p->p_pgrp->pg_jobc) { 137447545Skarels pgsignal(p->p_pgrp, SIGTTOU, 1); 137543377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH, 137643377Smarc ttybg, 0)) 137740712Skarels goto out; 137821776Sbloom goto loop; 13797502Sroot } 13809578Ssam /* 13819578Ssam * Process the user's data in at most OBUFSIZ 138240712Skarels * chunks. Perform any output translation. 138340712Skarels * Keep track of high water mark, sleep on overflow 138440712Skarels * awaiting device aid in acquiring new space. 13859578Ssam */ 138640712Skarels while (uio->uio_resid > 0 || cc > 0) { 138740712Skarels if (tp->t_lflag&FLUSHO) { 138840712Skarels uio->uio_resid = 0; 138940712Skarels return (0); 139040712Skarels } 139140712Skarels if (tp->t_outq.c_cc > hiwat) 139232067Skarels goto ovhiwat; 13939578Ssam /* 139440712Skarels * Grab a hunk of data from the user, 139540712Skarels * unless we have some leftover from last time. 13969578Ssam */ 13977822Sroot if (cc == 0) { 139840712Skarels cc = min(uio->uio_resid, OBUFSIZ); 139940712Skarels cp = obuf; 140040712Skarels error = uiomove(cp, cc, uio); 140140712Skarels if (error) { 140240712Skarels cc = 0; 140340712Skarels break; 140440712Skarels } 14057822Sroot } 14069578Ssam /* 14079578Ssam * If nothing fancy need be done, grab those characters we 14089578Ssam * can handle without any of ttyoutput's processing and 14099578Ssam * just transfer them to the output q. For those chars 14109578Ssam * which require special processing (as indicated by the 14119578Ssam * bits in partab), call ttyoutput. After processing 14129578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14139578Ssam * immediately. 14149578Ssam */ 14159578Ssam while (cc > 0) { 141640712Skarels if ((tp->t_oflag&OPOST) == 0) 14177502Sroot ce = cc; 14187502Sroot else { 141934492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 142049380Skarels (u_char *)partab, CCLASSMASK); 14219578Ssam /* 14229578Ssam * If ce is zero, then we're processing 14239578Ssam * a special character through ttyoutput. 14249578Ssam */ 14259578Ssam if (ce == 0) { 14267502Sroot tp->t_rocount = 0; 14277502Sroot if (ttyoutput(*cp, tp) >= 0) { 142821776Sbloom /* no c-lists, wait a bit */ 142921776Sbloom ttstart(tp); 143043377Smarc if (error = ttysleep(tp, 143143377Smarc (caddr_t)&lbolt, 143243377Smarc TTOPRI | PCATCH, ttybuf, 0)) 143340712Skarels break; 143421776Sbloom goto loop; 14357502Sroot } 14369578Ssam cp++, cc--; 143735811Smarc if ((tp->t_lflag&FLUSHO) || 14389578Ssam tp->t_outq.c_cc > hiwat) 14397502Sroot goto ovhiwat; 14409578Ssam continue; 14417502Sroot } 14427502Sroot } 14439578Ssam /* 14449578Ssam * A bunch of normal characters have been found, 14459578Ssam * transfer them en masse to the output queue and 14469578Ssam * continue processing at the top of the loop. 14479578Ssam * If there are any further characters in this 14489578Ssam * <= OBUFSIZ chunk, the first should be a character 14499578Ssam * requiring special handling by ttyoutput. 14509578Ssam */ 14517502Sroot tp->t_rocount = 0; 14529578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14539578Ssam ce -= i; 14549578Ssam tp->t_col += ce; 14559578Ssam cp += ce, cc -= ce, tk_nout += ce; 145635811Smarc tp->t_outcc += ce; 14579578Ssam if (i > 0) { 14589578Ssam /* out of c-lists, wait a bit */ 14597502Sroot ttstart(tp); 146043377Smarc if (error = ttysleep(tp, (caddr_t)&lbolt, 146143377Smarc TTOPRI | PCATCH, ttybuf, 0)) 146240712Skarels break; 146321776Sbloom goto loop; 14647502Sroot } 146535811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 146640712Skarels break; 14677502Sroot } 146835811Smarc ttstart(tp); 14697502Sroot } 147040712Skarels out: 147140712Skarels /* 147240712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 147340712Skarels * as the offset and iov pointers have moved forward, 147440712Skarels * but it doesn't matter (the call will either return short 147540712Skarels * or restart with a new uio). 147640712Skarels */ 147740712Skarels uio->uio_resid += cc; 14788520Sroot return (error); 147940712Skarels 14807502Sroot ovhiwat: 148132067Skarels ttstart(tp); 148232067Skarels s = spltty(); 14839578Ssam /* 148435811Smarc * This can only occur if FLUSHO is set in t_lflag, 148532067Skarels * or if ttstart/oproc is synchronous (or very fast). 14869578Ssam */ 14877502Sroot if (tp->t_outq.c_cc <= hiwat) { 14889578Ssam splx(s); 14897502Sroot goto loop; 14907502Sroot } 149137728Smckusick if (flag & IO_NDELAY) { 149217545Skarels splx(s); 149340712Skarels uio->uio_resid += cc; 14947822Sroot if (uio->uio_resid == cnt) 14958520Sroot return (EWOULDBLOCK); 14968520Sroot return (0); 14977502Sroot } 14987502Sroot tp->t_state |= TS_ASLEEP; 149943377Smarc error = ttysleep(tp, (caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 15009578Ssam splx(s); 150143377Smarc if (error) 150240712Skarels goto out; 15037502Sroot goto loop; 15047502Sroot } 15057502Sroot 15067502Sroot /* 15077502Sroot * Rubout one character from the rawq of tp 15087502Sroot * as cleanly as possible. 15097502Sroot */ 15107502Sroot ttyrub(c, tp) 15117625Ssam register c; 15127625Ssam register struct tty *tp; 15137502Sroot { 15147502Sroot register char *cp; 15157502Sroot register int savecol; 15167502Sroot int s; 15177502Sroot char *nextc(); 15187502Sroot 151942882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 15207502Sroot return; 152135811Smarc tp->t_lflag &= ~FLUSHO; 152235811Smarc if (tp->t_lflag&ECHOE) { 15237502Sroot if (tp->t_rocount == 0) { 15247502Sroot /* 15257502Sroot * Screwed by ttwrite; retype 15267502Sroot */ 15277502Sroot ttyretype(tp); 15287502Sroot return; 15297502Sroot } 153035811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15317502Sroot ttyrubo(tp, 2); 153249380Skarels else switch (CCLASS(c &= TTY_CHARMASK)) { 15337502Sroot 15347502Sroot case ORDINARY: 153535811Smarc ttyrubo(tp, 1); 15367502Sroot break; 15377502Sroot 15387502Sroot case VTAB: 15397502Sroot case BACKSPACE: 15407502Sroot case CONTROL: 15417502Sroot case RETURN: 154247545Skarels case NEWLINE: 154335811Smarc if (tp->t_lflag&ECHOCTL) 15447502Sroot ttyrubo(tp, 2); 15457502Sroot break; 15467502Sroot 154735811Smarc case TAB: { 154835811Smarc int c; 154935811Smarc 15507502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15517502Sroot ttyretype(tp); 15527502Sroot return; 15537502Sroot } 155417545Skarels s = spltty(); 15557502Sroot savecol = tp->t_col; 15569578Ssam tp->t_state |= TS_CNTTB; 155735811Smarc tp->t_lflag |= FLUSHO; 15587502Sroot tp->t_col = tp->t_rocol; 15599578Ssam cp = tp->t_rawq.c_cf; 156039407Smarc if (cp) 156139407Smarc c = *cp; /* XXX FIX NEXTC */ 156235811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 156335811Smarc ttyecho(c, tp); 156435811Smarc tp->t_lflag &= ~FLUSHO; 15659578Ssam tp->t_state &= ~TS_CNTTB; 15667502Sroot splx(s); 15677502Sroot /* 15687502Sroot * savecol will now be length of the tab 15697502Sroot */ 15707502Sroot savecol -= tp->t_col; 15717502Sroot tp->t_col += savecol; 15727502Sroot if (savecol > 8) 15737502Sroot savecol = 8; /* overflow screw */ 15747502Sroot while (--savecol >= 0) 15757502Sroot (void) ttyoutput('\b', tp); 15767502Sroot break; 157735811Smarc } 15787502Sroot 15797502Sroot default: 158037584Smarc /* XXX */ 158135811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 158249380Skarels c, CCLASS(c)); 158335811Smarc /*panic("ttyrub");*/ 15847502Sroot } 158535811Smarc } else if (tp->t_lflag&ECHOPRT) { 15869578Ssam if ((tp->t_state&TS_ERASE) == 0) { 15877502Sroot (void) ttyoutput('\\', tp); 15889578Ssam tp->t_state |= TS_ERASE; 15897502Sroot } 15907502Sroot ttyecho(c, tp); 15917502Sroot } else 159235811Smarc ttyecho(tp->t_cc[VERASE], tp); 15937502Sroot tp->t_rocount--; 15947502Sroot } 15957502Sroot 15967502Sroot /* 15977502Sroot * Crt back over cnt chars perhaps 15987502Sroot * erasing them. 15997502Sroot */ 16007502Sroot ttyrubo(tp, cnt) 16017625Ssam register struct tty *tp; 16027625Ssam int cnt; 16037502Sroot { 16047502Sroot 16057502Sroot while (--cnt >= 0) 160640712Skarels ttyoutstr("\b \b", tp); 16077502Sroot } 16087502Sroot 16097502Sroot /* 16107502Sroot * Reprint the rawq line. 16117502Sroot * We assume c_cc has already been checked. 16127502Sroot */ 16137502Sroot ttyretype(tp) 16147625Ssam register struct tty *tp; 16157502Sroot { 16167502Sroot register char *cp; 16177502Sroot char *nextc(); 161835811Smarc int s, c; 16197502Sroot 162035811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 162135811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16227502Sroot (void) ttyoutput('\n', tp); 162317545Skarels s = spltty(); 162435811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 162535811Smarc BIT OF FIRST CHAR ****/ 162635811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 162735811Smarc ttyecho(c, tp); 162835811Smarc } 162935811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 163035811Smarc ttyecho(c, tp); 163135811Smarc } 16329578Ssam tp->t_state &= ~TS_ERASE; 16337502Sroot splx(s); 16347502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16357502Sroot tp->t_rocol = 0; 16367502Sroot } 16377502Sroot 16387502Sroot /* 163935811Smarc * Echo a typed character to the terminal. 16407502Sroot */ 16417502Sroot ttyecho(c, tp) 16427625Ssam register c; 16437625Ssam register struct tty *tp; 16447502Sroot { 16459578Ssam if ((tp->t_state&TS_CNTTB) == 0) 164635811Smarc tp->t_lflag &= ~FLUSHO; 164747545Skarels if (((tp->t_lflag&ECHO) == 0 && 164847545Skarels ((tp->t_lflag&ECHONL) == 0 || c == '\n')) || (tp->t_lflag&EXTPROC)) 16497502Sroot return; 165035811Smarc if (tp->t_lflag&ECHOCTL) { 165140712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 165240712Skarels c == 0177) { 16537502Sroot (void) ttyoutput('^', tp); 165435811Smarc c &= TTY_CHARMASK; 16557502Sroot if (c == 0177) 16567502Sroot c = '?'; 16577502Sroot else 16587502Sroot c += 'A' - 1; 16597502Sroot } 16607502Sroot } 166135811Smarc (void) ttyoutput(c, tp); 16627502Sroot } 16637502Sroot 16647502Sroot /* 16657502Sroot * send string cp to tp 16667502Sroot */ 166740712Skarels ttyoutstr(cp, tp) 16687625Ssam register char *cp; 16697625Ssam register struct tty *tp; 16707502Sroot { 16717502Sroot register char c; 16727502Sroot 16737502Sroot while (c = *cp++) 16747502Sroot (void) ttyoutput(c, tp); 16757502Sroot } 16767502Sroot 167749380Skarels /* 167849380Skarels * Wake up any readers on a tty. 167949380Skarels */ 16807502Sroot ttwakeup(tp) 168147545Skarels register struct tty *tp; 16827502Sroot { 16837502Sroot 16847502Sroot if (tp->t_rsel) { 16857502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 16867502Sroot tp->t_state &= ~TS_RCOLL; 16877502Sroot tp->t_rsel = 0; 16887502Sroot } 168912752Ssam if (tp->t_state & TS_ASYNC) 169042882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 16917502Sroot wakeup((caddr_t)&tp->t_rawq); 16927502Sroot } 169335811Smarc 169435811Smarc /* 169548439Skarels * Look up a code for a specified speed in a conversion table; 169648439Skarels * used by drivers to map software speed values to hardware parameters. 169748439Skarels */ 169848439Skarels ttspeedtab(speed, table) 1699*52485Storek int speed; 170048439Skarels register struct speedtab *table; 170148439Skarels { 170248439Skarels 170348439Skarels for ( ; table->sp_speed != -1; table++) 170448439Skarels if (table->sp_speed == speed) 170548439Skarels return (table->sp_code); 170648439Skarels return (-1); 170748439Skarels } 170848439Skarels 170948439Skarels /* 171035811Smarc * set tty hi and low water marks 171135811Smarc * 171235811Smarc * Try to arrange the dynamics so there's about one second 171335811Smarc * from hi to low water. 171435811Smarc * 171535811Smarc */ 171635811Smarc ttsetwater(tp) 171735811Smarc struct tty *tp; 171835811Smarc { 171935811Smarc register cps = tp->t_ospeed / 10; 172035811Smarc register x; 172135811Smarc 172235811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 172335811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 172435811Smarc x += cps; 172535811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 172635811Smarc tp->t_hiwat = roundup(x, CBSIZE); 172735811Smarc #undef clamp 172835811Smarc } 172935811Smarc 173039407Smarc /* 173139407Smarc * Report on state of foreground process group. 173239407Smarc */ 173339407Smarc ttyinfo(tp) 173449907Sbostic register struct tty *tp; 173539407Smarc { 173649907Sbostic register struct proc *p, *pick; 173741177Smarc struct timeval utime, stime; 173849907Sbostic int tmp; 173939407Smarc 174039407Smarc if (ttycheckoutq(tp,0) == 0) 174139407Smarc return; 174249907Sbostic 174349907Sbostic /* Print load average. */ 174449907Sbostic tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; 174549907Sbostic ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); 174649907Sbostic 174739555Smarc if (tp->t_session == NULL) 174849907Sbostic ttyprintf(tp, "not a controlling terminal\n"); 174941177Smarc else if (tp->t_pgrp == NULL) 175049907Sbostic ttyprintf(tp, "no foreground process group\n"); 175141177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 175249907Sbostic ttyprintf(tp, "empty foreground process group\n"); 175339407Smarc else { 175449907Sbostic /* Pick interesting process. */ 175549907Sbostic for (pick = NULL; p != NULL; p = p->p_pgrpnxt) 175641177Smarc if (proc_compare(pick, p)) 175741177Smarc pick = p; 175849907Sbostic 175949907Sbostic ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, 176049907Sbostic pick->p_stat == SRUN ? "running" : 176149907Sbostic pick->p_wmesg ? pick->p_wmesg : "iowait"); 176249907Sbostic 176349907Sbostic /* 176449907Sbostic * Lock out clock if process is running; get user/system 176549907Sbostic * cpu time. 176641177Smarc */ 176747545Skarels if (curproc == pick) 176849907Sbostic tmp = splclock(); 176941177Smarc utime = pick->p_utime; 177041177Smarc stime = pick->p_stime; 177147545Skarels if (curproc == pick) 177249907Sbostic splx(tmp); 177339407Smarc 177449907Sbostic /* Print user time. */ 177549907Sbostic ttyprintf(tp, "%d.%02du ", 177649907Sbostic utime.tv_sec, (utime.tv_usec + 5000) / 10000); 177741177Smarc 177849907Sbostic /* Print system time. */ 177949907Sbostic ttyprintf(tp, "%d.%02ds ", 178049907Sbostic stime.tv_sec, (stime.tv_usec + 5000) / 10000); 178149907Sbostic 178249907Sbostic #define pgtok(a) (((a) * NBPG) / 1024) 178349907Sbostic /* Print percentage cpu, resident set size. */ 178449907Sbostic tmp = pick->p_pctcpu * 10000 + FSCALE / 2 >> FSHIFT; 178549907Sbostic ttyprintf(tp, "%d%% %dk\n", 1786*52485Storek tmp / 100, 1787*52485Storek pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 : 1788*52485Storek pgtok(pick->p_vmspace->vm_rssize)); 178941177Smarc } 179049907Sbostic tp->t_rocount = 0; /* so pending input will be retyped if BS */ 179141177Smarc } 179241177Smarc 179341177Smarc /* 179441177Smarc * Returns 1 if p2 is "better" than p1 179541177Smarc * 179641177Smarc * The algorithm for picking the "interesting" process is thus: 179741177Smarc * 179841177Smarc * 1) (Only foreground processes are eligable - implied) 179941177Smarc * 2) Runnable processes are favored over anything 180041177Smarc * else. The runner with the highest cpu 180141177Smarc * utilization is picked (p_cpu). Ties are 180241177Smarc * broken by picking the highest pid. 180341177Smarc * 3 Next, the sleeper with the shortest sleep 180441177Smarc * time is favored. With ties, we pick out 180541177Smarc * just "short-term" sleepers (SSINTR == 0). 180641177Smarc * Further ties are broken by picking the highest 180741177Smarc * pid. 180841177Smarc * 180941177Smarc */ 181041177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 181145723Smckusick #define TESTAB(a, b) ((a)<<1 | (b)) 181245723Smckusick #define ONLYA 2 181345723Smckusick #define ONLYB 1 181445723Smckusick #define BOTH 3 181545723Smckusick 181649907Sbostic static int 181741177Smarc proc_compare(p1, p2) 181841177Smarc register struct proc *p1, *p2; 181941177Smarc { 182041177Smarc 182141177Smarc if (p1 == NULL) 182241177Smarc return (1); 182341177Smarc /* 182441177Smarc * see if at least one of them is runnable 182541177Smarc */ 182645723Smckusick switch (TESTAB(isrun(p1), isrun(p2))) { 182745723Smckusick case ONLYA: 182845723Smckusick return (0); 182945723Smckusick case ONLYB: 183041177Smarc return (1); 183145723Smckusick case BOTH: 183241177Smarc /* 183341177Smarc * tie - favor one with highest recent cpu utilization 183441177Smarc */ 183541177Smarc if (p2->p_cpu > p1->p_cpu) 183641177Smarc return (1); 183741177Smarc if (p1->p_cpu > p2->p_cpu) 183841177Smarc return (0); 183941177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 184041177Smarc } 184145723Smckusick /* 184245723Smckusick * weed out zombies 184345723Smckusick */ 184445723Smckusick switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) { 184545723Smckusick case ONLYA: 184645723Smckusick return (1); 184745723Smckusick case ONLYB: 184845723Smckusick return (0); 184945723Smckusick case BOTH: 185045723Smckusick return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 185145723Smckusick } 185241177Smarc /* 185341177Smarc * pick the one with the smallest sleep time 185441177Smarc */ 185541177Smarc if (p2->p_slptime > p1->p_slptime) 185641177Smarc return (0); 185741177Smarc if (p1->p_slptime > p2->p_slptime) 185841177Smarc return (1); 185941177Smarc /* 186041177Smarc * favor one sleeping in a non-interruptible sleep 186141177Smarc */ 186241177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 186341177Smarc return (1); 186441177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 186541177Smarc return (0); 186647545Skarels return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 186741177Smarc } 186845723Smckusick 186939555Smarc /* 187039555Smarc * Output char to tty; console putchar style. 187139555Smarc */ 187239555Smarc tputchar(c, tp) 187339555Smarc int c; 187439555Smarc struct tty *tp; 187539555Smarc { 187639555Smarc register s = spltty(); 187739555Smarc 187847545Skarels if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) { 187939555Smarc if (c == '\n') 188039555Smarc (void) ttyoutput('\r', tp); 188139555Smarc (void) ttyoutput(c, tp); 188239555Smarc ttstart(tp); 188339555Smarc splx(s); 188439555Smarc return (0); 188539555Smarc } 188639555Smarc splx(s); 188739555Smarc return (-1); 188839555Smarc } 188943377Smarc 189044419Smarc /* 189149380Skarels * Sleep on chan, returning ERESTART if tty changed 189249380Skarels * while we napped and returning any errors (e.g. EINTR/ETIMEDOUT) 189349380Skarels * reported by tsleep. If the tty is revoked, restarting a pending 189449380Skarels * call will redo validation done at the start of the call. 189544419Smarc */ 189643377Smarc ttysleep(tp, chan, pri, wmesg, timo) 189743377Smarc struct tty *tp; 189843377Smarc caddr_t chan; 189943377Smarc int pri; 190043377Smarc char *wmesg; 190143377Smarc int timo; 190243377Smarc { 190343377Smarc int error; 190443377Smarc short gen = tp->t_gen; 190543377Smarc 190643377Smarc if (error = tsleep(chan, pri, wmesg, timo)) 190743377Smarc return (error); 190843377Smarc if (tp->t_gen != gen) 190943377Smarc return (ERESTART); 191043377Smarc return (0); 191143377Smarc } 1912