123387Smckusick /* 240712Skarels * Copyright (c) 1982, 1986, 1990 Regents of the University of California. 323387Smckusick * All rights reserved. The Berkeley software License Agreement 423387Smckusick * specifies the terms and conditions for redistribution. 523387Smckusick * 6*43322Smarc * @(#)tty.c 7.32 (Berkeley) 06/20/90 723387Smckusick */ 839Sbill 917095Sbloom #include "param.h" 1017095Sbloom #include "systm.h" 1117095Sbloom #include "user.h" 1217095Sbloom #include "ioctl.h" 1339407Smarc #define TTYDEFCHARS 1417095Sbloom #include "tty.h" 1535811Smarc #undef TTYDEFCHARS 1617095Sbloom #include "proc.h" 1717095Sbloom #include "file.h" 1817095Sbloom #include "conf.h" 1929946Skarels #include "dkstat.h" 2017095Sbloom #include "uio.h" 2117095Sbloom #include "kernel.h" 2237728Smckusick #include "vnode.h" 2335811Smarc #include "syslog.h" 2439Sbill 2537525Smckusick #include "machine/reg.h" 2637525Smckusick 2740712Skarels /* symbolic sleep message strings */ 2840712Skarels char ttyin[] = "ttyin"; 2940712Skarels char ttyout[] = "ttyout"; 3041370Smarc char ttopen[] = "ttyopn"; 3141370Smarc char ttclos[] = "ttycls"; 3240712Skarels char ttybg[] = "ttybg"; 3340712Skarels char ttybuf[] = "ttybuf"; 3440712Skarels 357436Skre /* 367436Skre * Table giving parity for characters and indicating 3735811Smarc * character classes to tty driver. The 8th bit 3835811Smarc * indicates parity, the 7th bit indicates the character 3935811Smarc * is an alphameric or underscore (for ALTWERASE), and the 4035811Smarc * low 6 bits indicate delay type. If the low 6 bits are 0 4135811Smarc * then the character needs no special processing on output. 427436Skre */ 4339Sbill 447436Skre char partab[] = { 4535811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 4635811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 4735811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 4835811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 4935811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 5035811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 5135811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 5235811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 5335811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 5435811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 5535811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 5635811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 5735811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 5835811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 5935811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 6035811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 617436Skre /* 6235811Smarc * meta chars 637436Skre */ 6435811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* nul - bel */ 6535811Smarc 0202,0004,0003,0201,0005,0206,0201,0001, /* bs - si */ 6635811Smarc 0201,0001,0001,0201,0001,0201,0201,0001, /* dle - etb */ 6735811Smarc 0001,0201,0201,0001,0201,0001,0001,0201, /* can - us */ 6835811Smarc 0200,0000,0000,0200,0000,0200,0200,0000, /* sp - ' */ 6935811Smarc 0000,0200,0200,0000,0200,0000,0000,0200, /* ( - / */ 7035811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* 0 - 7 */ 7135811Smarc 0300,0100,0000,0200,0000,0200,0200,0000, /* 8 - ? */ 7235811Smarc 0200,0100,0100,0300,0100,0300,0300,0100, /* @ - G */ 7335811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* H - O */ 7435811Smarc 0100,0300,0300,0100,0300,0100,0100,0300, /* P - W */ 7535811Smarc 0300,0100,0100,0200,0000,0200,0200,0300, /* X - _ */ 7635811Smarc 0000,0300,0300,0100,0300,0100,0100,0300, /* ` - g */ 7735811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* h - o */ 7835811Smarc 0300,0100,0100,0300,0100,0300,0300,0100, /* p - w */ 7935811Smarc 0100,0300,0300,0000,0200,0000,0000,0201, /* x - del */ 807436Skre }; 817436Skre 8235811Smarc extern struct tty *constty; /* temporary virtual console */ 8335811Smarc extern char partab[], maptab[]; 8435811Smarc 85146Sbill /* 8635811Smarc * Is 'c' a line delimiter ("break" character)? 8739Sbill */ 8840712Skarels #define ttbreakc(c) ((c) == '\n' || ((c) == cc[VEOF] || \ 8940712Skarels (c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE) 9039Sbill 9139Sbill ttychars(tp) 929578Ssam struct tty *tp; 9339Sbill { 9435811Smarc bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars)); 9539Sbill } 9639Sbill 9739Sbill /* 98903Sbill * Wait for output to drain, then flush input waiting. 9939Sbill */ 10012752Ssam ttywflush(tp) 10137584Smarc struct tty *tp; 10239Sbill { 10340712Skarels int error; 10439Sbill 10540712Skarels if ((error = ttywait(tp)) == 0) 10640712Skarels ttyflush(tp, FREAD); 10740712Skarels return (error); 10812752Ssam } 10912752Ssam 11035811Smarc /* 11135811Smarc * Wait for output to drain. 11235811Smarc */ 11312752Ssam ttywait(tp) 11412752Ssam register struct tty *tp; 11512752Ssam { 11640712Skarels int error = 0, s = spltty(); 11712752Ssam 11813809Ssam while ((tp->t_outq.c_cc || tp->t_state&TS_BUSY) && 11937584Smarc (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) && 12037584Smarc tp->t_oproc) { 121903Sbill (*tp->t_oproc)(tp); 1225408Swnj tp->t_state |= TS_ASLEEP; 12343092Smarc if ((error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, 12443092Smarc ttyout, 0)) || 12543092Smarc (error = ttclosed(tp))) 12640712Skarels break; 127903Sbill } 1289859Ssam splx(s); 12940712Skarels return (error); 13039Sbill } 13139Sbill 13239Sbill /* 1339578Ssam * Flush all TTY queues 13439Sbill */ 13512752Ssam ttyflush(tp, rw) 1367625Ssam register struct tty *tp; 13739Sbill { 138903Sbill register s; 139903Sbill 14017545Skarels s = spltty(); 141903Sbill if (rw & FREAD) { 142903Sbill while (getc(&tp->t_canq) >= 0) 143903Sbill ; 14437584Smarc ttwakeup(tp); 145903Sbill } 146903Sbill if (rw & FWRITE) { 14737584Smarc wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */ 1485408Swnj tp->t_state &= ~TS_TTSTOP; 1495426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 150903Sbill while (getc(&tp->t_outq) >= 0) 151903Sbill ; 152903Sbill } 153903Sbill if (rw & FREAD) { 154903Sbill while (getc(&tp->t_rawq) >= 0) 155903Sbill ; 1569578Ssam tp->t_rocount = 0; 157903Sbill tp->t_rocol = 0; 1589578Ssam tp->t_state &= ~TS_LOCAL; 159903Sbill } 160903Sbill splx(s); 16139Sbill } 16239Sbill 163903Sbill /* 164903Sbill * Send stop character on input overflow. 165903Sbill */ 166903Sbill ttyblock(tp) 1677625Ssam register struct tty *tp; 16839Sbill { 169903Sbill register x; 1709578Ssam 171903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 172903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17312752Ssam ttyflush(tp, FREAD|FWRITE); 1745408Swnj tp->t_state &= ~TS_TBLOCK; 175903Sbill } 17615118Skarels /* 17715118Skarels * Block further input iff: 17815118Skarels * Current input > threshold AND input is available to user program 17915118Skarels */ 18042350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 18140712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 18235811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 18342350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 18415118Skarels tp->t_state |= TS_TBLOCK; 18515118Skarels ttstart(tp); 18615118Skarels } 187903Sbill } 18839Sbill } 18939Sbill 19039Sbill /* 191903Sbill * Restart typewriter output following a delay 192903Sbill * timeout. 193903Sbill * The name of the routine is passed to the timeout 194903Sbill * subroutine and it is called during a clock interrupt. 195121Sbill */ 196903Sbill ttrstrt(tp) 19737584Smarc struct tty *tp; 198121Sbill { 199121Sbill 20040712Skarels #ifdef DIAGNOSTIC 2019578Ssam if (tp == 0) 2029578Ssam panic("ttrstrt"); 20340712Skarels #endif 2045408Swnj tp->t_state &= ~TS_TIMEOUT; 205903Sbill ttstart(tp); 206121Sbill } 207121Sbill 208121Sbill /* 209903Sbill * Start output on the typewriter. It is used from the top half 210903Sbill * after some characters have been put on the output queue, 211903Sbill * from the interrupt routine to transmit the next 212903Sbill * character, and after a timeout has finished. 21339Sbill */ 214903Sbill ttstart(tp) 21537584Smarc struct tty *tp; 21639Sbill { 21739Sbill 21832067Skarels if (tp->t_oproc) /* kludge for pty */ 219903Sbill (*tp->t_oproc)(tp); 22039Sbill } 22139Sbill 22239Sbill /* 223903Sbill * Common code for tty ioctls. 22439Sbill */ 2251780Sbill /*ARGSUSED*/ 2267625Ssam ttioctl(tp, com, data, flag) 2277625Ssam register struct tty *tp; 2287625Ssam caddr_t data; 22939Sbill { 23039Sbill extern int nldisp; 23137554Smckusick int s, error; 23239Sbill 233903Sbill /* 234903Sbill * If the ioctl involves modification, 23517545Skarels * hang if in the background. 236903Sbill */ 2377625Ssam switch (com) { 23839Sbill 23935811Smarc case TIOCSETD: 240903Sbill case TIOCFLUSH: 24135811Smarc /*case TIOCSPGRP:*/ 2429325Ssam case TIOCSTI: 24317598Sbloom case TIOCSWINSZ: 24435811Smarc case TIOCSETA: 24535811Smarc case TIOCSETAW: 24635811Smarc case TIOCSETAF: 24739407Smarc /**** these get removed **** 24835811Smarc case TIOCSETAS: 24935811Smarc case TIOCSETAWS: 25035811Smarc case TIOCSETAFS: 25139407Smarc /***************************/ 25240030Smarc #ifdef COMPAT_43 25340030Smarc case TIOCSETP: 25440030Smarc case TIOCSETN: 25540030Smarc case TIOCSETC: 25640030Smarc case TIOCSLTC: 25740030Smarc case TIOCLBIS: 25840030Smarc case TIOCLBIC: 25940030Smarc case TIOCLSET: 26040030Smarc case OTIOCSETD: 26143321Shibler case OTIOCCONS: 26240030Smarc #endif 26339555Smarc while (isbackground(u.u_procp, tp) && 26435811Smarc u.u_procp->p_pgrp->pg_jobc && 265903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26640712Skarels (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 && 26740712Skarels (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0) { 26842882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU, 1); 26943092Smarc if ((error = tsleep((caddr_t)&lbolt, TTOPRI | PCATCH, 27043092Smarc ttybg, 0)) || 27143092Smarc (error = ttclosed(tp))) 27240712Skarels return (error); 273903Sbill } 274903Sbill break; 275903Sbill } 276903Sbill 2779578Ssam /* 2789578Ssam * Process the ioctl. 2799578Ssam */ 2807625Ssam switch (com) { 281903Sbill 2828556Sroot /* get discipline number */ 28339Sbill case TIOCGETD: 2847625Ssam *(int *)data = tp->t_line; 28539Sbill break; 28639Sbill 2878556Sroot /* set line discipline */ 2887625Ssam case TIOCSETD: { 2897625Ssam register int t = *(int *)data; 29035811Smarc dev_t dev = tp->t_dev; 2917625Ssam 29235811Smarc if ((unsigned)t >= nldisp) 29310851Ssam return (ENXIO); 29425584Skarels if (t != tp->t_line) { 29525584Skarels s = spltty(); 29625584Skarels (*linesw[tp->t_line].l_close)(tp); 29725584Skarels error = (*linesw[t].l_open)(dev, tp); 29825584Skarels if (error) { 29935811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 30025584Skarels splx(s); 30125584Skarels return (error); 30225584Skarels } 30325584Skarels tp->t_line = t; 30410851Ssam splx(s); 30510851Ssam } 30639Sbill break; 3077625Ssam } 30839Sbill 3098556Sroot /* prevent more opens on channel */ 3105614Swnj case TIOCEXCL: 3115614Swnj tp->t_state |= TS_XCLUDE; 3125614Swnj break; 3135614Swnj 3145614Swnj case TIOCNXCL: 3155614Swnj tp->t_state &= ~TS_XCLUDE; 3165614Swnj break; 3175614Swnj 31839Sbill case TIOCHPCL: 31935811Smarc tp->t_cflag |= HUPCL; 32039Sbill break; 32139Sbill 3223942Sbugs case TIOCFLUSH: { 3237625Ssam register int flags = *(int *)data; 3247625Ssam 3257625Ssam if (flags == 0) 3263942Sbugs flags = FREAD|FWRITE; 3277625Ssam else 3287625Ssam flags &= FREAD|FWRITE; 32912752Ssam ttyflush(tp, flags); 33039Sbill break; 3313944Sbugs } 33239Sbill 33337584Smarc case FIOASYNC: 33437584Smarc if (*(int *)data) 33537584Smarc tp->t_state |= TS_ASYNC; 33637584Smarc else 33737584Smarc tp->t_state &= ~TS_ASYNC; 33837584Smarc break; 33937584Smarc 34037584Smarc case FIONBIO: 34137584Smarc break; /* XXX remove */ 34237584Smarc 3438556Sroot /* return number of characters immediately available */ 3447625Ssam case FIONREAD: 3457625Ssam *(off_t *)data = ttnread(tp); 346174Sbill break; 347174Sbill 34813077Ssam case TIOCOUTQ: 34913077Ssam *(int *)data = tp->t_outq.c_cc; 35013077Ssam break; 35113077Ssam 3528589Sroot case TIOCSTOP: 35317545Skarels s = spltty(); 3549578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3555573Swnj tp->t_state |= TS_TTSTOP; 3565573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3575573Swnj } 3587625Ssam splx(s); 3595573Swnj break; 3605573Swnj 3618589Sroot case TIOCSTART: 36217545Skarels s = spltty(); 36335811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3645573Swnj tp->t_state &= ~TS_TTSTOP; 36535811Smarc tp->t_lflag &= ~FLUSHO; 3665573Swnj ttstart(tp); 3675573Swnj } 3687625Ssam splx(s); 3695573Swnj break; 3705573Swnj 3719325Ssam /* 3729325Ssam * Simulate typing of a character at the terminal. 3739325Ssam */ 3749325Ssam case TIOCSTI: 37517183Smckusick if (u.u_uid && (flag & FREAD) == 0) 37617183Smckusick return (EPERM); 37739555Smarc if (u.u_uid && !isctty(u.u_procp, tp)) 3789325Ssam return (EACCES); 3799578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3809325Ssam break; 3819325Ssam 38235811Smarc case TIOCGETA: { 38335811Smarc struct termios *t = (struct termios *)data; 38412752Ssam 38535811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 38635811Smarc break; 38735811Smarc } 38835811Smarc 38939407Smarc /*** THIS ALL GETS REMOVED ***/ 39039407Smarc case JUNK_TIOCSETAS: 39139407Smarc case JUNK_TIOCSETAWS: 39239407Smarc case JUNK_TIOCSETAFS: 39339407Smarc ((struct termios *)data)->c_cflag |= CIGNORE; 39439407Smarc switch(com) { 39539407Smarc case JUNK_TIOCSETAS: 39639407Smarc com = TIOCSETA; 39739407Smarc break; 39839407Smarc case JUNK_TIOCSETAWS: 39939407Smarc com = TIOCSETAW; 40039407Smarc break; 40139407Smarc case JUNK_TIOCSETAFS: 40239407Smarc com = TIOCSETAF; 40339407Smarc break; 40439407Smarc } 40539407Smarc /*******************************/ 40639407Smarc /*FALLTHROGH*/ 40735811Smarc case TIOCSETA: 40835811Smarc case TIOCSETAW: 40937584Smarc case TIOCSETAF: { 41035811Smarc register struct termios *t = (struct termios *)data; 41140712Skarels 41217545Skarels s = spltty(); 41339407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 41440712Skarels if (error = ttywait(tp)) { 41540712Skarels splx(s); 41640712Skarels return (error); 41740712Skarels } 41839407Smarc if (com == TIOCSETAF); 41939407Smarc ttyflush(tp, FREAD); 42039407Smarc } 42140712Skarels if ((t->c_cflag&CIGNORE) == 0) { 42235811Smarc /* 42335811Smarc * set device hardware 42435811Smarc */ 42537584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 42637584Smarc splx(s); 42735811Smarc return (error); 42837584Smarc } else { 42940712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 43037584Smarc (tp->t_cflag&CLOCAL) && 43140712Skarels (t->c_cflag&CLOCAL) == 0) { 43237584Smarc tp->t_state &= ~TS_ISOPEN; 43337584Smarc tp->t_state |= TS_WOPEN; 43437584Smarc ttwakeup(tp); 43537584Smarc } 43635811Smarc tp->t_cflag = t->c_cflag; 43735811Smarc tp->t_ispeed = t->c_ispeed; 43835811Smarc tp->t_ospeed = t->c_ospeed; 43934492Skarels } 44035811Smarc ttsetwater(tp); 44112752Ssam } 44239407Smarc if (com != TIOCSETAF) { 44335811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 44435811Smarc if (t->c_lflag&ICANON) { 44535811Smarc tp->t_lflag |= PENDIN; 44635811Smarc ttwakeup(tp); 44735811Smarc } 44835811Smarc else { 44935811Smarc struct clist tq; 45035811Smarc 45135811Smarc catq(&tp->t_rawq, &tp->t_canq); 45235811Smarc tq = tp->t_rawq; 45335811Smarc tp->t_rawq = tp->t_canq; 45435811Smarc tp->t_canq = tq; 45535811Smarc } 45612752Ssam } 45735811Smarc tp->t_iflag = t->c_iflag; 45835811Smarc tp->t_oflag = t->c_oflag; 45942882Smarc /* 46042882Smarc * Make the EXTPROC bit read only. 46142882Smarc */ 46242882Smarc if (tp->t_lflag&EXTPROC) 46342882Smarc t->c_lflag |= EXTPROC; 46442882Smarc else 46542882Smarc t->c_lflag &= ~EXTPROC; 46635811Smarc tp->t_lflag = t->c_lflag; 46735811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 46812752Ssam splx(s); 46912752Ssam break; 47012752Ssam } 47112752Ssam 47212752Ssam /* 47339555Smarc * Set controlling terminal. 47439555Smarc * Session ctty vnode pointer set in vnode layer. 47534492Skarels */ 47635811Smarc case TIOCSCTTY: { 47735811Smarc register struct proc *p = u.u_procp; 47834492Skarels 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; 48835811Smarc } 48939555Smarc 49034492Skarels /* 49135811Smarc * Set terminal process group. 49217545Skarels */ 49318650Sbloom case TIOCSPGRP: { 49435811Smarc register struct proc *p = u.u_procp; 49535811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 49617545Skarels 49739555Smarc if (!isctty(p, tp)) 49839555Smarc return (ENOTTY); 49940030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 50039555Smarc return (EPERM); 50139555Smarc tp->t_pgrp = pgrp; 50212752Ssam break; 50318650Sbloom } 50412752Ssam 50512752Ssam case TIOCGPGRP: 50639555Smarc if (!isctty(u.u_procp, tp)) 50739555Smarc return (ENOTTY); 50839555Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 50912752Ssam break; 51012752Ssam 51117598Sbloom case TIOCSWINSZ: 51218650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 51318650Sbloom sizeof (struct winsize))) { 51417598Sbloom tp->t_winsize = *(struct winsize *)data; 51542882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 51617598Sbloom } 51717598Sbloom break; 51817598Sbloom 51917598Sbloom case TIOCGWINSZ: 52017598Sbloom *(struct winsize *)data = tp->t_winsize; 52117598Sbloom break; 52217598Sbloom 52330534Skarels case TIOCCONS: 52430534Skarels if (*(int *)data) { 52542141Smckusick if (constty && constty != tp && 52642141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 52742141Smckusick (TS_CARR_ON|TS_ISOPEN)) 52830534Skarels return (EBUSY); 52930534Skarels #ifndef UCONSOLE 53037554Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 53137554Smckusick return (error); 53230534Skarels #endif 53330534Skarels constty = tp; 53430534Skarels } else if (tp == constty) 53533404Skarels constty = NULL; 53630534Skarels break; 53730534Skarels 53835811Smarc #ifdef COMPAT_43 53935811Smarc case TIOCGETP: 54035811Smarc case TIOCSETP: 54135811Smarc case TIOCSETN: 54235811Smarc case TIOCGETC: 54335811Smarc case TIOCSETC: 54435811Smarc case TIOCSLTC: 54535811Smarc case TIOCGLTC: 54635811Smarc case TIOCLBIS: 54735811Smarc case TIOCLBIC: 54835811Smarc case TIOCLSET: 54935811Smarc case TIOCLGET: 55039407Smarc case OTIOCGETD: 55139407Smarc case OTIOCSETD: 55235811Smarc return(ttcompat(tp, com, data, flag)); 55335811Smarc #endif 55435811Smarc 55539Sbill default: 5568556Sroot return (-1); 55739Sbill } 5588556Sroot return (0); 55939Sbill } 5604484Swnj 5614484Swnj ttnread(tp) 5624484Swnj struct tty *tp; 5634484Swnj { 5644484Swnj int nread = 0; 5654484Swnj 56635811Smarc if (tp->t_lflag & PENDIN) 5674484Swnj ttypend(tp); 5684484Swnj nread = tp->t_canq.c_cc; 56935811Smarc if ((tp->t_lflag & ICANON) == 0) 5704484Swnj nread += tp->t_rawq.c_cc; 5714484Swnj return (nread); 5724484Swnj } 5734484Swnj 5745408Swnj ttselect(dev, rw) 5754484Swnj dev_t dev; 5765408Swnj int rw; 5774484Swnj { 5784484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5794484Swnj int nread; 58017545Skarels int s = spltty(); 5814484Swnj 5825408Swnj switch (rw) { 5834484Swnj 5844484Swnj case FREAD: 5854484Swnj nread = ttnread(tp); 58637584Smarc if (nread > 0 || 58740712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 5885408Swnj goto win; 5894938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5905408Swnj tp->t_state |= TS_RCOLL; 5914484Swnj else 5924484Swnj tp->t_rsel = u.u_procp; 5935408Swnj break; 5944484Swnj 5955408Swnj case FWRITE: 59635811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5975408Swnj goto win; 5985408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5995408Swnj tp->t_state |= TS_WCOLL; 6005408Swnj else 6015408Swnj tp->t_wsel = u.u_procp; 6025408Swnj break; 6034484Swnj } 6045408Swnj splx(s); 6055408Swnj return (0); 6065408Swnj win: 6075408Swnj splx(s); 6085408Swnj return (1); 6094484Swnj } 6107436Skre 6117502Sroot /* 61225391Skarels * Initial open of tty, or (re)entry to line discipline. 6137502Sroot */ 6147502Sroot ttyopen(dev, tp) 6157625Ssam dev_t dev; 6167625Ssam register struct tty *tp; 6177502Sroot { 6187502Sroot 6197502Sroot tp->t_dev = dev; 62035811Smarc 62143092Smarc if (ttclosed(tp)) /* XXX is this still needed? (drivers do it) */ 62243092Smarc return (ERESTART); 6237502Sroot tp->t_state &= ~TS_WOPEN; 62417545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 62517545Skarels tp->t_state |= TS_ISOPEN; 62617598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 62717545Skarels } 6288556Sroot return (0); 6297502Sroot } 6307502Sroot 6317502Sroot /* 63225391Skarels * "close" a line discipline 63325391Skarels */ 63425391Skarels ttylclose(tp) 63525391Skarels register struct tty *tp; 63625391Skarels { 63725391Skarels 63825391Skarels ttywflush(tp); 63925391Skarels } 64025391Skarels 64125391Skarels /* 6427502Sroot * clean tp on last close 6437502Sroot */ 6447502Sroot ttyclose(tp) 6457625Ssam register struct tty *tp; 6467502Sroot { 64730534Skarels if (constty == tp) 64830534Skarels constty = NULL; 64925391Skarels ttyflush(tp, FREAD|FWRITE); 65039555Smarc tp->t_session = NULL; 65139555Smarc tp->t_pgrp = NULL; 6527502Sroot tp->t_state = 0; 65340712Skarels return (0); 6547502Sroot } 6557502Sroot 6567502Sroot /* 65725391Skarels * Handle modem control transition on a tty. 65825391Skarels * Flag indicates new state of carrier. 65925391Skarels * Returns 0 if the line should be turned off, otherwise 1. 66025391Skarels */ 66125391Skarels ttymodem(tp, flag) 66225391Skarels register struct tty *tp; 66325391Skarels { 66425391Skarels 66542193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 66625391Skarels /* 66725391Skarels * MDMBUF: do flow control according to carrier flag 66825391Skarels */ 66925391Skarels if (flag) { 67025391Skarels tp->t_state &= ~TS_TTSTOP; 67125391Skarels ttstart(tp); 67225391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 67325391Skarels tp->t_state |= TS_TTSTOP; 67425391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 67525391Skarels } 67625391Skarels } else if (flag == 0) { 67725391Skarels /* 67825391Skarels * Lost carrier. 67925391Skarels */ 68025391Skarels tp->t_state &= ~TS_CARR_ON; 68142193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 68242193Smarc if (tp->t_session && tp->t_session->s_leader) 68342193Smarc psignal(tp->t_session->s_leader, SIGHUP); 68442193Smarc ttyflush(tp, FREAD|FWRITE); 68542193Smarc return (0); 68625391Skarels } 68725391Skarels } else { 68825391Skarels /* 68925391Skarels * Carrier now on. 69025391Skarels */ 69125391Skarels tp->t_state |= TS_CARR_ON; 69237584Smarc ttwakeup(tp); 69325391Skarels } 69425391Skarels return (1); 69525391Skarels } 69625391Skarels 69725391Skarels /* 69825404Skarels * Default modem control routine (for other line disciplines). 69925404Skarels * Return argument flag, to turn off device on carrier drop. 70025404Skarels */ 70125415Skarels nullmodem(tp, flag) 70225415Skarels register struct tty *tp; 70325404Skarels int flag; 70425404Skarels { 70525404Skarels 70625404Skarels if (flag) 70725404Skarels tp->t_state |= TS_CARR_ON; 70839407Smarc else { 70925404Skarels tp->t_state &= ~TS_CARR_ON; 71042193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 71142193Smarc if (tp->t_session && tp->t_session->s_leader) 71242193Smarc psignal(tp->t_session->s_leader, SIGHUP); 71342193Smarc return (0); 71442193Smarc } 71539407Smarc } 71642193Smarc return (1); 71725404Skarels } 71825404Skarels 71925404Skarels /* 7207502Sroot * reinput pending characters after state switch 72117545Skarels * call at spltty(). 7227502Sroot */ 7237502Sroot ttypend(tp) 7247625Ssam register struct tty *tp; 7257502Sroot { 7267502Sroot struct clist tq; 7277502Sroot register c; 7287502Sroot 72935811Smarc tp->t_lflag &= ~PENDIN; 7309578Ssam tp->t_state |= TS_TYPEN; 7317502Sroot tq = tp->t_rawq; 7327502Sroot tp->t_rawq.c_cc = 0; 7337502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7347502Sroot while ((c = getc(&tq)) >= 0) 7357502Sroot ttyinput(c, tp); 7369578Ssam tp->t_state &= ~TS_TYPEN; 7377502Sroot } 7387502Sroot 7397502Sroot /* 74035811Smarc * 7419578Ssam * Place a character on raw TTY input queue, 7429578Ssam * putting in delimiters and waking up top 7439578Ssam * half as needed. Also echo if required. 7449578Ssam * The arguments are the character and the 7459578Ssam * appropriate tty structure. 7467502Sroot */ 7477502Sroot ttyinput(c, tp) 7487625Ssam register c; 7497625Ssam register struct tty *tp; 7507502Sroot { 75135811Smarc register int iflag = tp->t_iflag; 75235811Smarc register int lflag = tp->t_lflag; 75335811Smarc register u_char *cc = tp->t_cc; 75435811Smarc int i, err; 7557502Sroot 7569578Ssam /* 7579578Ssam * If input is pending take it first. 7589578Ssam */ 75935811Smarc if (lflag&PENDIN) 7607502Sroot ttypend(tp); 76135811Smarc /* 76235811Smarc * Gather stats. 76335811Smarc */ 7647502Sroot tk_nin++; 76535811Smarc if (lflag&ICANON) { 76635811Smarc tk_cancc++; 76735811Smarc tp->t_cancc++; 76835811Smarc } else { 76935811Smarc tk_rawcc++; 77035811Smarc tp->t_rawcc++; 77135811Smarc } 7729578Ssam /* 77335811Smarc * Handle exceptional conditions (break, parity, framing). 7749578Ssam */ 77535811Smarc if (err = (c&TTY_ERRORMASK)) { 77635811Smarc c &= ~TTY_ERRORMASK; 77735811Smarc if (err&TTY_FE && !c) { /* break */ 77835811Smarc if (iflag&IGNBRK) 77935811Smarc goto endcase; 78035811Smarc else if (iflag&BRKINT && lflag&ISIG && 78135811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 78235811Smarc c = cc[VINTR]; 78335811Smarc else { 78435811Smarc c = 0; 78535811Smarc if (iflag&PARMRK) 78635811Smarc goto parmrk; 78735811Smarc } 78835811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 78935811Smarc if (iflag&IGNPAR) 79035811Smarc goto endcase; 79135811Smarc else if (iflag&PARMRK) { 79235811Smarc parmrk: 79335811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 79435811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 79535811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 79635811Smarc goto endcase; 79735811Smarc } else 79835811Smarc c = 0; 7997502Sroot } 8009578Ssam } 8019578Ssam /* 80235811Smarc * In tandem mode, check high water mark. 8039578Ssam */ 80435811Smarc if (iflag&IXOFF) 80535811Smarc ttyblock(tp); 80635811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 8079578Ssam c &= 0177; 80842882Smarc if ((tp->t_lflag&EXTPROC) == 0) { 8099578Ssam /* 8109578Ssam * Check for literal nexting very first 8119578Ssam */ 8129578Ssam if (tp->t_state&TS_LNCH) { 81335811Smarc c |= TTY_QUOTE; 8149578Ssam tp->t_state &= ~TS_LNCH; 8159578Ssam } 8169578Ssam /* 8179578Ssam * Scan for special characters. This code 8189578Ssam * is really just a big case statement with 8199578Ssam * non-constant cases. The bottom of the 8209578Ssam * case statement is labeled ``endcase'', so goto 8219578Ssam * it after a case match, or similar. 8229578Ssam */ 82335811Smarc /* 82435811Smarc * Control chars which aren't controlled 82535811Smarc * by ICANON, ISIG, or IXON. 82635811Smarc */ 82739407Smarc if (lflag&IEXTEN) { 82840712Skarels if (CCEQ(cc[VLNEXT], c)) { 82935811Smarc if (lflag&ECHO) { 83035811Smarc if (lflag&ECHOE) 83140712Skarels ttyoutstr("^\b", tp); 83235811Smarc else 83335811Smarc ttyecho(c, tp); 83435811Smarc } 8359578Ssam tp->t_state |= TS_LNCH; 8369578Ssam goto endcase; 8379578Ssam } 83843093Smarc if (CCEQ(cc[VDISCARD], c)) { 83935811Smarc if (lflag&FLUSHO) 84035811Smarc tp->t_lflag &= ~FLUSHO; 8417502Sroot else { 84212752Ssam ttyflush(tp, FWRITE); 8437502Sroot ttyecho(c, tp); 8449578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 8457502Sroot ttyretype(tp); 84635811Smarc tp->t_lflag |= FLUSHO; 8477502Sroot } 8489578Ssam goto startoutput; 8499578Ssam } 85035811Smarc } 85135811Smarc /* 85235811Smarc * Signals. 85335811Smarc */ 85435811Smarc if (lflag&ISIG) { 85535811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 85635811Smarc if ((lflag&NOFLSH) == 0) 85735811Smarc ttyflush(tp, FREAD|FWRITE); 85835811Smarc ttyecho(c, tp); 85939555Smarc pgsignal(tp->t_pgrp, 86042882Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 86135811Smarc goto endcase; 86235811Smarc } 86340712Skarels if (CCEQ(cc[VSUSP], c)) { 86435811Smarc if ((lflag&NOFLSH) == 0) 86512752Ssam ttyflush(tp, FREAD); 8669578Ssam ttyecho(c, tp); 86742882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 8689578Ssam goto endcase; 8699578Ssam } 8709578Ssam } 8719578Ssam /* 8729578Ssam * Handle start/stop characters. 8739578Ssam */ 87435811Smarc if (iflag&IXON) { 87540712Skarels if (CCEQ(cc[VSTOP], c)) { 87635811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 87735811Smarc tp->t_state |= TS_TTSTOP; 87835811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 87935811Smarc return; 88035811Smarc } 88135811Smarc if (!CCEQ(cc[VSTART], c)) 88235811Smarc return; 88335811Smarc /* 88435811Smarc * if VSTART == VSTOP then toggle 88535811Smarc */ 88635811Smarc goto endcase; 8879578Ssam } 88835811Smarc if (CCEQ(cc[VSTART], c)) 88935811Smarc goto restartoutput; 8909578Ssam } 8919578Ssam /* 89235811Smarc * IGNCR, ICRNL, & INLCR 8939578Ssam */ 89435811Smarc if (c == '\r') { 89535811Smarc if (iflag&IGNCR) 89635811Smarc goto endcase; 89735811Smarc else if (iflag&ICRNL) 89835811Smarc c = '\n'; 8999578Ssam } 90035811Smarc else if (c == '\n' && iflag&INLCR) 90135811Smarc c = '\r'; 90242882Smarc } 9039578Ssam /* 90435811Smarc * Non canonical mode; don't process line editing 9059578Ssam * characters; check high water mark for wakeup. 90635811Smarc * 9079578Ssam */ 90840712Skarels if ((lflag&ICANON) == 0) { 9099578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 91035811Smarc if (iflag&IMAXBEL) { 91135811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 91235811Smarc (void) ttyoutput(CTRL('g'), tp); 91335811Smarc } else 91435811Smarc ttyflush(tp, FREAD | FWRITE); 91535811Smarc } else { 91635811Smarc if (putc(c, &tp->t_rawq) >= 0) { 91735811Smarc ttwakeup(tp); 91835811Smarc ttyecho(c, tp); 91935811Smarc } 9207502Sroot } 9219578Ssam goto endcase; 9229578Ssam } 92342882Smarc if ((tp->t_lflag&EXTPROC) == 0) { 9249578Ssam /* 92535811Smarc * From here on down canonical mode character 9269578Ssam * processing takes place. 9279578Ssam */ 92835811Smarc /* 92935811Smarc * erase (^H / ^?) 93035811Smarc */ 93139407Smarc if (CCEQ(cc[VERASE], c)) { 9329578Ssam if (tp->t_rawq.c_cc) 9339578Ssam ttyrub(unputc(&tp->t_rawq), tp); 9349578Ssam goto endcase; 9359578Ssam } 93635811Smarc /* 93735811Smarc * kill (^U) 93835811Smarc */ 93935811Smarc if (CCEQ(cc[VKILL], c)) { 94037584Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 94140712Skarels (lflag&ECHOPRT) == 0) { 9429578Ssam while (tp->t_rawq.c_cc) 9439578Ssam ttyrub(unputc(&tp->t_rawq), tp); 9449578Ssam } else { 9459578Ssam ttyecho(c, tp); 94635811Smarc if (lflag&ECHOK || lflag&ECHOKE) 94735811Smarc ttyecho('\n', tp); 9489578Ssam while (getc(&tp->t_rawq) > 0) 9499578Ssam ; 9509578Ssam tp->t_rocount = 0; 9519578Ssam } 9529578Ssam tp->t_state &= ~TS_LOCAL; 9539578Ssam goto endcase; 9549578Ssam } 9559578Ssam /* 95635811Smarc * word erase (^W) 9579578Ssam */ 95835811Smarc if (CCEQ(cc[VWERASE], c)) { 95935811Smarc int ctype; 96035811Smarc 96135811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 96235811Smarc /* 96335811Smarc * erase whitespace 96435811Smarc */ 96535811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 96635811Smarc ttyrub(c, tp); 96735811Smarc if (c == -1) 96834492Skarels goto endcase; 96935811Smarc /* 97035811Smarc * special case last char of token 97135811Smarc */ 97235811Smarc ttyrub(c, tp); 97335811Smarc c = unputc(&tp->t_rawq); 97435811Smarc if (c == -1 || c == ' ' || c == '\t') { 97535811Smarc if (c != -1) 97635811Smarc (void) putc(c, &tp->t_rawq); 97734492Skarels goto endcase; 97834492Skarels } 97935811Smarc /* 98035811Smarc * erase rest of token 98135811Smarc */ 98235811Smarc ctype = CTYPE(c); 98335811Smarc do { 98435811Smarc ttyrub(c, tp); 98535811Smarc c = unputc(&tp->t_rawq); 98635811Smarc if (c == -1) 98735811Smarc goto endcase; 98835811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 98935811Smarc (void) putc(c, &tp->t_rawq); 99035811Smarc goto endcase; 99135811Smarc #undef CTYPE 9929578Ssam } 9939578Ssam /* 99435811Smarc * reprint line (^R) 99535811Smarc */ 99635811Smarc if (CCEQ(cc[VREPRINT], c)) { 99735811Smarc ttyretype(tp); 99835811Smarc goto endcase; 99935811Smarc } 1000*43322Smarc if (CCEQ(cc[VSTATUS], c)) { 100142882Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 100242141Smckusick if ((lflag&NOKERNINFO) == 0) 100342141Smckusick ttyinfo(tp); 100442141Smckusick goto endcase; 100542141Smckusick } 100642882Smarc } 100735811Smarc /* 10089578Ssam * Check for input buffer overflow 10099578Ssam */ 101010391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 101135811Smarc if (iflag&IMAXBEL) { 101235811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 101335811Smarc (void) ttyoutput(CTRL('g'), tp); 101435811Smarc } else 101535811Smarc ttyflush(tp, FREAD | FWRITE); 10169578Ssam goto endcase; 101710391Ssam } 10189578Ssam /* 10199578Ssam * Put data char in q for user and 10209578Ssam * wakeup on seeing a line delimiter. 10219578Ssam */ 10229578Ssam if (putc(c, &tp->t_rawq) >= 0) { 102335811Smarc if (ttbreakc(c)) { 10249578Ssam tp->t_rocount = 0; 10259578Ssam catq(&tp->t_rawq, &tp->t_canq); 10267502Sroot ttwakeup(tp); 10279578Ssam } else if (tp->t_rocount++ == 0) 10289578Ssam tp->t_rocol = tp->t_col; 10299578Ssam if (tp->t_state&TS_ERASE) { 103035811Smarc /* 103135811Smarc * end of prterase \.../ 103235811Smarc */ 10339578Ssam tp->t_state &= ~TS_ERASE; 10349578Ssam (void) ttyoutput('/', tp); 10359578Ssam } 10369578Ssam i = tp->t_col; 10377502Sroot ttyecho(c, tp); 103835811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 103935811Smarc /* 104035811Smarc * Place the cursor over the '^' of the ^D. 104135811Smarc */ 10429578Ssam i = MIN(2, tp->t_col - i); 10439578Ssam while (i > 0) { 10449578Ssam (void) ttyoutput('\b', tp); 10459578Ssam i--; 10469578Ssam } 10479578Ssam } 10487502Sroot } 10499578Ssam endcase: 10509578Ssam /* 105135811Smarc * IXANY means allow any character to restart output. 10529578Ssam */ 105340712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 105440712Skarels cc[VSTART] != cc[VSTOP]) 10557502Sroot return; 10569578Ssam restartoutput: 10577502Sroot tp->t_state &= ~TS_TTSTOP; 105835811Smarc tp->t_lflag &= ~FLUSHO; 10599578Ssam startoutput: 10607502Sroot ttstart(tp); 10617502Sroot } 10627502Sroot 10637502Sroot /* 10649578Ssam * Put character on TTY output queue, adding delays, 10657502Sroot * expanding tabs, and handling the CR/NL bit. 10669578Ssam * This is called both from the top half for output, 10679578Ssam * and from interrupt level for echoing. 10687502Sroot * The arguments are the character and the tty structure. 10697502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10707502Sroot * Must be recursive. 10717502Sroot */ 10727502Sroot ttyoutput(c, tp) 10737502Sroot register c; 10747502Sroot register struct tty *tp; 10757502Sroot { 10767502Sroot register char *colp; 10777502Sroot register ctype; 107835811Smarc register long oflag = tp->t_oflag; 107935811Smarc 108040712Skarels if ((oflag&OPOST) == 0) { 108135811Smarc if (tp->t_lflag&FLUSHO) 10827502Sroot return (-1); 10837502Sroot if (putc(c, &tp->t_outq)) 10847625Ssam return (c); 10857502Sroot tk_nout++; 108635811Smarc tp->t_outcc++; 10877502Sroot return (-1); 10887502Sroot } 108935811Smarc c &= TTY_CHARMASK; 10907502Sroot /* 10917502Sroot * Turn tabs to spaces as required 109242882Smarc * 109342882Smarc * Special case if we have external processing, we don't 109442882Smarc * do the tab expansion because we'll probably get it 109542882Smarc * wrong. If tab expansion needs to be done, let it 109642882Smarc * happen externally. 10977502Sroot */ 109842882Smarc if ((tp->t_lflag&EXTPROC) == 0 && 109942882Smarc c == '\t' && oflag&OXTABS ) { 11007502Sroot register int s; 11017502Sroot 11027502Sroot c = 8 - (tp->t_col&7); 110335811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 110417545Skarels s = spltty(); /* don't interrupt tabs */ 11057502Sroot c -= b_to_q(" ", c, &tp->t_outq); 11067502Sroot tk_nout += c; 110735811Smarc tp->t_outcc += c; 11087502Sroot splx(s); 11097502Sroot } 11107502Sroot tp->t_col += c; 11117502Sroot return (c ? -1 : '\t'); 11127502Sroot } 111335811Smarc if (c == CEOT && oflag&ONOEOT) 111435811Smarc return(-1); 11157502Sroot tk_nout++; 111635811Smarc tp->t_outcc++; 11177502Sroot /* 11187502Sroot * turn <nl> to <cr><lf> if desired. 11197502Sroot */ 112035811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 11217502Sroot return (c); 112235811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 112335811Smarc return (c); 11247502Sroot /* 11257502Sroot * Calculate delays. 11267502Sroot * The numbers here represent clock ticks 11277502Sroot * and are not necessarily optimal for all terminals. 11289578Ssam * 11299578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 113035811Smarc * 113135811Smarc * (actually, should THROW AWAY terminals which need delays) 11327502Sroot */ 11337502Sroot colp = &tp->t_col; 11347502Sroot ctype = partab[c]; 11357502Sroot c = 0; 11367502Sroot switch (ctype&077) { 11377502Sroot 11387502Sroot case ORDINARY: 11397502Sroot (*colp)++; 11407502Sroot 11417502Sroot case CONTROL: 11427502Sroot break; 11437502Sroot 11447502Sroot case BACKSPACE: 11457502Sroot if (*colp) 11467502Sroot (*colp)--; 11477502Sroot break; 11487502Sroot 114913821Ssam /* 115013821Ssam * This macro is close enough to the correct thing; 115113821Ssam * it should be replaced by real user settable delays 115213821Ssam * in any event... 115313821Ssam */ 115413821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 11557502Sroot case NEWLINE: 11567502Sroot ctype = (tp->t_flags >> 8) & 03; 11577625Ssam if (ctype == 1) { /* tty 37 */ 115826357Skarels if (*colp > 0) { 115926357Skarels c = (((unsigned)*colp) >> 4) + 3; 116026357Skarels if ((unsigned)c > 6) 116126357Skarels c = 6; 116226357Skarels } 11639578Ssam } else if (ctype == 2) /* vt05 */ 116413821Ssam c = mstohz(100); 11657502Sroot *colp = 0; 11667502Sroot break; 11677502Sroot 11687502Sroot case TAB: 11697502Sroot ctype = (tp->t_flags >> 10) & 03; 11707625Ssam if (ctype == 1) { /* tty 37 */ 11717502Sroot c = 1 - (*colp | ~07); 11727625Ssam if (c < 5) 11737502Sroot c = 0; 11747502Sroot } 11757502Sroot *colp |= 07; 11767502Sroot (*colp)++; 11777502Sroot break; 11787502Sroot 11797502Sroot case VTAB: 11809578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11817502Sroot c = 0177; 11827502Sroot break; 11837502Sroot 11847502Sroot case RETURN: 11857502Sroot ctype = (tp->t_flags >> 12) & 03; 11869578Ssam if (ctype == 1) /* tn 300 */ 118713821Ssam c = mstohz(83); 11889578Ssam else if (ctype == 2) /* ti 700 */ 118913821Ssam c = mstohz(166); 11909578Ssam else if (ctype == 3) { /* concept 100 */ 11917502Sroot int i; 11929578Ssam 11937502Sroot if ((i = *colp) >= 0) 11949578Ssam for (; i < 9; i++) 11957502Sroot (void) putc(0177, &tp->t_outq); 11967502Sroot } 11977502Sroot *colp = 0; 11987502Sroot } 119935811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 120035811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 12017502Sroot return (-1); 12027502Sroot } 120313821Ssam #undef mstohz 12047502Sroot 12057502Sroot /* 12067502Sroot * Called from device's read routine after it has 12077502Sroot * calculated the tty-structure given as argument. 12087502Sroot */ 120937584Smarc ttread(tp, uio, flag) 12107625Ssam register struct tty *tp; 12117722Swnj struct uio *uio; 12127502Sroot { 12137502Sroot register struct clist *qp; 121435811Smarc register int c; 121541383Smarc register long lflag; 121635811Smarc register u_char *cc = tp->t_cc; 12179859Ssam int s, first, error = 0; 12187502Sroot 12197502Sroot loop: 122041383Smarc lflag = tp->t_lflag; 122137584Smarc s = spltty(); 12229578Ssam /* 122337584Smarc * take pending input first 12249578Ssam */ 122535811Smarc if (lflag&PENDIN) 12267502Sroot ttypend(tp); 12279859Ssam splx(s); 122840712Skarels 12299578Ssam /* 12309578Ssam * Hang process if it's in the background. 12319578Ssam */ 123239555Smarc if (isbackground(u.u_procp, tp)) { 123324392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 123424392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 123535811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 12368520Sroot return (EIO); 123742882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1); 123843092Smarc if ((error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, 123943092Smarc ttybg, 0)) || 124043092Smarc (error = ttclosed(tp))) 124140712Skarels return (error); 124223165Sbloom goto loop; 12437502Sroot } 124440712Skarels 12459578Ssam /* 124635811Smarc * If canonical, use the canonical queue, 124735811Smarc * else use the raw queue. 124837584Smarc * 124937584Smarc * XXX - should get rid of canonical queue. 125037584Smarc * (actually, should get rid of clists...) 12519578Ssam */ 125235811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 125340712Skarels 12549578Ssam /* 125540712Skarels * If there is no input, sleep on rawq 125640712Skarels * awaiting hardware receipt and notification. 125740712Skarels * If we have data, we don't need to check for carrier. 12589578Ssam */ 125917545Skarels s = spltty(); 12609578Ssam if (qp->c_cc <= 0) { 126140712Skarels int carrier; 126240712Skarels 126340712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 126440712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 12659859Ssam splx(s); 126640712Skarels return (0); /* EOF */ 12677502Sroot } 126837728Smckusick if (flag & IO_NDELAY) { 126937584Smarc splx(s); 127037584Smarc return (EWOULDBLOCK); 127137584Smarc } 127240712Skarels error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 127340712Skarels carrier ? ttyin : ttopen, 0); 12749859Ssam splx(s); 127543092Smarc if (error || (error = ttclosed(tp))) 127640712Skarels return (error); 12779578Ssam goto loop; 12789578Ssam } 12799859Ssam splx(s); 128040712Skarels 12819578Ssam /* 128235811Smarc * Input present, check for input mapping and processing. 12839578Ssam */ 12849578Ssam first = 1; 12859578Ssam while ((c = getc(qp)) >= 0) { 12869578Ssam /* 128735811Smarc * delayed suspend (^Y) 12889578Ssam */ 128935811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 129042882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12919578Ssam if (first) { 129243092Smarc if ((error = tsleep((caddr_t)&lbolt, 129343092Smarc TTIPRI | PCATCH, ttybg, 0)) || 129443092Smarc (error = ttclosed(tp))) 129540712Skarels break; 12969578Ssam goto loop; 12979578Ssam } 12989578Ssam break; 12997502Sroot } 13009578Ssam /* 130135811Smarc * Interpret EOF only in canonical mode. 13029578Ssam */ 130335811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 13049578Ssam break; 13059578Ssam /* 13069578Ssam * Give user character. 13079578Ssam */ 130840712Skarels error = ureadc(c, uio); 13099578Ssam if (error) 13109578Ssam break; 131114938Smckusick if (uio->uio_resid == 0) 13129578Ssam break; 13139578Ssam /* 131435811Smarc * In canonical mode check for a "break character" 13159578Ssam * marking the end of a "line of input". 13169578Ssam */ 131740712Skarels if (lflag&ICANON && ttbreakc(c)) 13189578Ssam break; 13199578Ssam first = 0; 13207502Sroot } 13219578Ssam /* 13229578Ssam * Look to unblock output now that (presumably) 13239578Ssam * the input queue has gone down. 13249578Ssam */ 132535811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 132635811Smarc if (cc[VSTART] != _POSIX_VDISABLE 132735811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 13287502Sroot tp->t_state &= ~TS_TBLOCK; 13297502Sroot ttstart(tp); 13307502Sroot } 133135811Smarc } 13328520Sroot return (error); 13337502Sroot } 13347502Sroot 13357502Sroot /* 133625391Skarels * Check the output queue on tp for space for a kernel message 133725391Skarels * (from uprintf/tprintf). Allow some space over the normal 133825391Skarels * hiwater mark so we don't lose messages due to normal flow 133925391Skarels * control, but don't let the tty run amok. 134030695Skarels * Sleeps here are not interruptible, but we return prematurely 134130695Skarels * if new signals come in. 134225391Skarels */ 134325391Skarels ttycheckoutq(tp, wait) 134425391Skarels register struct tty *tp; 134525391Skarels int wait; 134625391Skarels { 134730695Skarels int hiwat, s, oldsig; 134825391Skarels 134935811Smarc hiwat = tp->t_hiwat; 135025391Skarels s = spltty(); 135130695Skarels oldsig = u.u_procp->p_sig; 135225391Skarels if (tp->t_outq.c_cc > hiwat + 200) 135329946Skarels while (tp->t_outq.c_cc > hiwat) { 135429946Skarels ttstart(tp); 135530695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 135629946Skarels splx(s); 135729946Skarels return (0); 135829946Skarels } 135930695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 136029946Skarels tp->t_state |= TS_ASLEEP; 136130695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 136225391Skarels } 136325391Skarels splx(s); 136425391Skarels return (1); 136525391Skarels } 136625391Skarels 136725391Skarels /* 13687502Sroot * Called from the device's write routine after it has 13697502Sroot * calculated the tty-structure given as argument. 13707502Sroot */ 137137584Smarc ttwrite(tp, uio, flag) 13727625Ssam register struct tty *tp; 13739578Ssam register struct uio *uio; 13747502Sroot { 13757502Sroot register char *cp; 137640712Skarels register int cc = 0, ce; 13779578Ssam int i, hiwat, cnt, error, s; 13787502Sroot char obuf[OBUFSIZ]; 13797502Sroot 138035811Smarc hiwat = tp->t_hiwat; 13819578Ssam cnt = uio->uio_resid; 13829578Ssam error = 0; 13837502Sroot loop: 138437584Smarc s = spltty(); 138540712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 138637584Smarc if (tp->t_state&TS_ISOPEN) { 138737584Smarc splx(s); 138837584Smarc return (EIO); 138937728Smckusick } else if (flag & IO_NDELAY) { 139037584Smarc splx(s); 139140712Skarels error = EWOULDBLOCK; 139240712Skarels goto out; 139337584Smarc } else { 139437584Smarc /* 139537584Smarc * sleep awaiting carrier 139637584Smarc */ 139740712Skarels error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 139840712Skarels ttopen, 0); 139937584Smarc splx(s); 140043092Smarc if (error || (error = ttclosed(tp))) 140140712Skarels goto out; 140237584Smarc goto loop; 140337584Smarc } 140437584Smarc } 140537584Smarc splx(s); 14069578Ssam /* 14079578Ssam * Hang the process if it's in the background. 14089578Ssam */ 140939555Smarc if (isbackground(u.u_procp, tp) && 141035811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 141140712Skarels (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 && 141240712Skarels (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0 && 141335811Smarc u.u_procp->p_pgrp->pg_jobc) { 141442882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU, 1); 141543092Smarc if ((error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, 141643092Smarc ttybg, 0)) || 141743092Smarc (error = ttclosed(tp))) 141840712Skarels goto out; 141921776Sbloom goto loop; 14207502Sroot } 14219578Ssam /* 14229578Ssam * Process the user's data in at most OBUFSIZ 142340712Skarels * chunks. Perform any output translation. 142440712Skarels * Keep track of high water mark, sleep on overflow 142540712Skarels * awaiting device aid in acquiring new space. 14269578Ssam */ 142740712Skarels while (uio->uio_resid > 0 || cc > 0) { 142840712Skarels if (tp->t_lflag&FLUSHO) { 142940712Skarels uio->uio_resid = 0; 143040712Skarels return (0); 143140712Skarels } 143240712Skarels if (tp->t_outq.c_cc > hiwat) 143332067Skarels goto ovhiwat; 14349578Ssam /* 143540712Skarels * Grab a hunk of data from the user, 143640712Skarels * unless we have some leftover from last time. 14379578Ssam */ 14387822Sroot if (cc == 0) { 143940712Skarels cc = min(uio->uio_resid, OBUFSIZ); 144040712Skarels cp = obuf; 144140712Skarels error = uiomove(cp, cc, uio); 144240712Skarels if (error) { 144340712Skarels cc = 0; 144440712Skarels break; 144540712Skarels } 14467822Sroot } 14479578Ssam /* 14489578Ssam * If nothing fancy need be done, grab those characters we 14499578Ssam * can handle without any of ttyoutput's processing and 14509578Ssam * just transfer them to the output q. For those chars 14519578Ssam * which require special processing (as indicated by the 14529578Ssam * bits in partab), call ttyoutput. After processing 14539578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14549578Ssam * immediately. 14559578Ssam */ 14569578Ssam while (cc > 0) { 145740712Skarels if ((tp->t_oflag&OPOST) == 0) 14587502Sroot ce = cc; 14597502Sroot else { 146034492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 146134492Skarels (u_char *)partab, 077); 14629578Ssam /* 14639578Ssam * If ce is zero, then we're processing 14649578Ssam * a special character through ttyoutput. 14659578Ssam */ 14669578Ssam if (ce == 0) { 14677502Sroot tp->t_rocount = 0; 14687502Sroot if (ttyoutput(*cp, tp) >= 0) { 146921776Sbloom /* no c-lists, wait a bit */ 147021776Sbloom ttstart(tp); 147143092Smarc if ((error = tsleep((caddr_t)&lbolt, 147243092Smarc TTOPRI | PCATCH, ttybuf, 0)) || 147343092Smarc (error = ttclosed(tp))) 147440712Skarels break; 147521776Sbloom goto loop; 14767502Sroot } 14779578Ssam cp++, cc--; 147835811Smarc if ((tp->t_lflag&FLUSHO) || 14799578Ssam tp->t_outq.c_cc > hiwat) 14807502Sroot goto ovhiwat; 14819578Ssam continue; 14827502Sroot } 14837502Sroot } 14849578Ssam /* 14859578Ssam * A bunch of normal characters have been found, 14869578Ssam * transfer them en masse to the output queue and 14879578Ssam * continue processing at the top of the loop. 14889578Ssam * If there are any further characters in this 14899578Ssam * <= OBUFSIZ chunk, the first should be a character 14909578Ssam * requiring special handling by ttyoutput. 14919578Ssam */ 14927502Sroot tp->t_rocount = 0; 14939578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14949578Ssam ce -= i; 14959578Ssam tp->t_col += ce; 14969578Ssam cp += ce, cc -= ce, tk_nout += ce; 149735811Smarc tp->t_outcc += ce; 14989578Ssam if (i > 0) { 14999578Ssam /* out of c-lists, wait a bit */ 15007502Sroot ttstart(tp); 150143092Smarc if ((error = tsleep((caddr_t)&lbolt, 150243092Smarc TTOPRI | PCATCH, ttybuf, 0)) || 150343092Smarc (error = ttclosed(tp))) 150440712Skarels break; 150521776Sbloom goto loop; 15067502Sroot } 150735811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 150840712Skarels break; 15097502Sroot } 151035811Smarc ttstart(tp); 15117502Sroot } 151240712Skarels out: 151340712Skarels /* 151440712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 151540712Skarels * as the offset and iov pointers have moved forward, 151640712Skarels * but it doesn't matter (the call will either return short 151740712Skarels * or restart with a new uio). 151840712Skarels */ 151940712Skarels uio->uio_resid += cc; 15208520Sroot return (error); 152140712Skarels 15227502Sroot ovhiwat: 152332067Skarels ttstart(tp); 152432067Skarels s = spltty(); 15259578Ssam /* 152635811Smarc * This can only occur if FLUSHO is set in t_lflag, 152732067Skarels * or if ttstart/oproc is synchronous (or very fast). 15289578Ssam */ 15297502Sroot if (tp->t_outq.c_cc <= hiwat) { 15309578Ssam splx(s); 15317502Sroot goto loop; 15327502Sroot } 153337728Smckusick if (flag & IO_NDELAY) { 153417545Skarels splx(s); 153540712Skarels uio->uio_resid += cc; 15367822Sroot if (uio->uio_resid == cnt) 15378520Sroot return (EWOULDBLOCK); 15388520Sroot return (0); 15397502Sroot } 15407502Sroot tp->t_state |= TS_ASLEEP; 154140712Skarels error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 15429578Ssam splx(s); 154343092Smarc if (error || (error = ttclosed(tp))) 154440712Skarels goto out; 15457502Sroot goto loop; 15467502Sroot } 15477502Sroot 15487502Sroot /* 15497502Sroot * Rubout one character from the rawq of tp 15507502Sroot * as cleanly as possible. 15517502Sroot */ 15527502Sroot ttyrub(c, tp) 15537625Ssam register c; 15547625Ssam register struct tty *tp; 15557502Sroot { 15567502Sroot register char *cp; 15577502Sroot register int savecol; 15587502Sroot int s; 15597502Sroot char *nextc(); 15607502Sroot 156142882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 15627502Sroot return; 156335811Smarc tp->t_lflag &= ~FLUSHO; 156435811Smarc if (tp->t_lflag&ECHOE) { 15657502Sroot if (tp->t_rocount == 0) { 15667502Sroot /* 15677502Sroot * Screwed by ttwrite; retype 15687502Sroot */ 15697502Sroot ttyretype(tp); 15707502Sroot return; 15717502Sroot } 157235811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15737502Sroot ttyrubo(tp, 2); 157435811Smarc else switch (partab[c&=0377]&077) { 15757502Sroot 15767502Sroot case ORDINARY: 157735811Smarc ttyrubo(tp, 1); 15787502Sroot break; 15797502Sroot 15807502Sroot case VTAB: 15817502Sroot case BACKSPACE: 15827502Sroot case CONTROL: 15837502Sroot case RETURN: 158435811Smarc if (tp->t_lflag&ECHOCTL) 15857502Sroot ttyrubo(tp, 2); 15867502Sroot break; 15877502Sroot 158835811Smarc case TAB: { 158935811Smarc int c; 159035811Smarc 15917502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15927502Sroot ttyretype(tp); 15937502Sroot return; 15947502Sroot } 159517545Skarels s = spltty(); 15967502Sroot savecol = tp->t_col; 15979578Ssam tp->t_state |= TS_CNTTB; 159835811Smarc tp->t_lflag |= FLUSHO; 15997502Sroot tp->t_col = tp->t_rocol; 16009578Ssam cp = tp->t_rawq.c_cf; 160139407Smarc if (cp) 160239407Smarc c = *cp; /* XXX FIX NEXTC */ 160335811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 160435811Smarc ttyecho(c, tp); 160535811Smarc tp->t_lflag &= ~FLUSHO; 16069578Ssam tp->t_state &= ~TS_CNTTB; 16077502Sroot splx(s); 16087502Sroot /* 16097502Sroot * savecol will now be length of the tab 16107502Sroot */ 16117502Sroot savecol -= tp->t_col; 16127502Sroot tp->t_col += savecol; 16137502Sroot if (savecol > 8) 16147502Sroot savecol = 8; /* overflow screw */ 16157502Sroot while (--savecol >= 0) 16167502Sroot (void) ttyoutput('\b', tp); 16177502Sroot break; 161835811Smarc } 16197502Sroot 16207502Sroot default: 162137584Smarc /* XXX */ 162235811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 162335811Smarc c, partab[c&=0377]&077); 162435811Smarc /*panic("ttyrub");*/ 16257502Sroot } 162635811Smarc } else if (tp->t_lflag&ECHOPRT) { 16279578Ssam if ((tp->t_state&TS_ERASE) == 0) { 16287502Sroot (void) ttyoutput('\\', tp); 16299578Ssam tp->t_state |= TS_ERASE; 16307502Sroot } 16317502Sroot ttyecho(c, tp); 16327502Sroot } else 163335811Smarc ttyecho(tp->t_cc[VERASE], tp); 16347502Sroot tp->t_rocount--; 16357502Sroot } 16367502Sroot 16377502Sroot /* 16387502Sroot * Crt back over cnt chars perhaps 16397502Sroot * erasing them. 16407502Sroot */ 16417502Sroot ttyrubo(tp, cnt) 16427625Ssam register struct tty *tp; 16437625Ssam int cnt; 16447502Sroot { 16457502Sroot 16467502Sroot while (--cnt >= 0) 164740712Skarels ttyoutstr("\b \b", tp); 16487502Sroot } 16497502Sroot 16507502Sroot /* 16517502Sroot * Reprint the rawq line. 16527502Sroot * We assume c_cc has already been checked. 16537502Sroot */ 16547502Sroot ttyretype(tp) 16557625Ssam register struct tty *tp; 16567502Sroot { 16577502Sroot register char *cp; 16587502Sroot char *nextc(); 165935811Smarc int s, c; 16607502Sroot 166135811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 166235811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16637502Sroot (void) ttyoutput('\n', tp); 166417545Skarels s = spltty(); 166535811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 166635811Smarc BIT OF FIRST CHAR ****/ 166735811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 166835811Smarc ttyecho(c, tp); 166935811Smarc } 167035811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 167135811Smarc ttyecho(c, tp); 167235811Smarc } 16739578Ssam tp->t_state &= ~TS_ERASE; 16747502Sroot splx(s); 16757502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16767502Sroot tp->t_rocol = 0; 16777502Sroot } 16787502Sroot 16797502Sroot /* 168035811Smarc * Echo a typed character to the terminal. 16817502Sroot */ 16827502Sroot ttyecho(c, tp) 16837625Ssam register c; 16847625Ssam register struct tty *tp; 16857502Sroot { 16869578Ssam if ((tp->t_state&TS_CNTTB) == 0) 168735811Smarc tp->t_lflag &= ~FLUSHO; 168842882Smarc if (((tp->t_lflag&ECHO) == 0 && ((tp->t_lflag&ECHONL) == 0 || 168942882Smarc c == '\n')) || (tp->t_lflag&EXTPROC)) 16907502Sroot return; 169135811Smarc if (tp->t_lflag&ECHOCTL) { 169240712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 169340712Skarels c == 0177) { 16947502Sroot (void) ttyoutput('^', tp); 169535811Smarc c &= TTY_CHARMASK; 16967502Sroot if (c == 0177) 16977502Sroot c = '?'; 16987502Sroot else 16997502Sroot c += 'A' - 1; 17007502Sroot } 17017502Sroot } 170235811Smarc (void) ttyoutput(c, tp); 17037502Sroot } 17047502Sroot 17057502Sroot /* 17067502Sroot * send string cp to tp 17077502Sroot */ 170840712Skarels ttyoutstr(cp, tp) 17097625Ssam register char *cp; 17107625Ssam register struct tty *tp; 17117502Sroot { 17127502Sroot register char c; 17137502Sroot 17147502Sroot while (c = *cp++) 17157502Sroot (void) ttyoutput(c, tp); 17167502Sroot } 17177502Sroot 17187502Sroot ttwakeup(tp) 17197502Sroot struct tty *tp; 17207502Sroot { 17217502Sroot 17227502Sroot if (tp->t_rsel) { 17237502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 17247502Sroot tp->t_state &= ~TS_RCOLL; 17257502Sroot tp->t_rsel = 0; 17267502Sroot } 172712752Ssam if (tp->t_state & TS_ASYNC) 172842882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 17297502Sroot wakeup((caddr_t)&tp->t_rawq); 17307502Sroot } 173135811Smarc 173235811Smarc /* 173335811Smarc * set tty hi and low water marks 173435811Smarc * 173535811Smarc * Try to arrange the dynamics so there's about one second 173635811Smarc * from hi to low water. 173735811Smarc * 173835811Smarc */ 173935811Smarc ttsetwater(tp) 174035811Smarc struct tty *tp; 174135811Smarc { 174235811Smarc register cps = tp->t_ospeed / 10; 174335811Smarc register x; 174435811Smarc 174535811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 174635811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 174735811Smarc x += cps; 174835811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 174935811Smarc tp->t_hiwat = roundup(x, CBSIZE); 175035811Smarc #undef clamp 175135811Smarc } 175235811Smarc 175335811Smarc ttspeedtab(speed, table) 175435811Smarc struct speedtab table[]; 175535811Smarc { 175635811Smarc register int i; 175735811Smarc 175835811Smarc for (i = 0; table[i].sp_speed != -1; i++) 175935811Smarc if (table[i].sp_speed == speed) 176035811Smarc return(table[i].sp_code); 176135811Smarc return(-1); 176235811Smarc } 176339407Smarc 176441177Smarc int ttyhostname = 0; 176539407Smarc /* 176639407Smarc * (^T) 176739407Smarc * Report on state of foreground process group. 176839407Smarc */ 176939407Smarc ttyinfo(tp) 177039407Smarc struct tty *tp; 177139407Smarc { 177241177Smarc register struct proc *p, *pick = NULL; 177341177Smarc register char *cp = hostname; 177441177Smarc int x, s; 177541177Smarc struct timeval utime, stime; 177642350Smckusick #define pgtok(a) (((a)*NBPG)/1024) 177739407Smarc 177839407Smarc if (ttycheckoutq(tp,0) == 0) 177939407Smarc return; 178041177Smarc /* 178141177Smarc * hostname 178241177Smarc */ 178341177Smarc if (ttyhostname) { 178441177Smarc if (*cp == '\0') 178541177Smarc ttyprintf(tp, "amnesia"); 178641177Smarc else 178741177Smarc while (*cp && *cp != '.') 178841177Smarc tputchar(*cp++, tp); 178941177Smarc tputchar(' '); 179041177Smarc } 179141177Smarc /* 179241177Smarc * load average 179341177Smarc */ 179441177Smarc x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT; 179541177Smarc ttyprintf(tp, "load: %d.", x/100); 179641177Smarc ttyoutint(x%100, 10, 2, tp); 179739555Smarc if (tp->t_session == NULL) 179841177Smarc ttyprintf(tp, " not a controlling terminal\n"); 179941177Smarc else if (tp->t_pgrp == NULL) 180041177Smarc ttyprintf(tp, " no foreground process group\n"); 180141177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 180241177Smarc ttyprintf(tp, " empty foreground process group\n"); 180339407Smarc else { 180441177Smarc /* pick interesting process */ 180539407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 180641177Smarc if (proc_compare(pick, p)) 180741177Smarc pick = p; 180839407Smarc } 180941177Smarc ttyprintf(tp, " cmd: %s %d [%s] ", 181041177Smarc pick->p_comm, pick->p_pid, 181141177Smarc pick->p_wmesg ? pick->p_wmesg : "running"); 181241177Smarc /* 181341177Smarc * cpu time 181441177Smarc */ 181541177Smarc if (u.u_procp == pick) 181641177Smarc s = splclock(); 181741177Smarc utime = pick->p_utime; 181841177Smarc stime = pick->p_stime; 181941177Smarc if (u.u_procp == pick) 182041177Smarc splx(s); 182141177Smarc /* user time */ 182241177Smarc x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */ 182341177Smarc ttyoutint(utime.tv_sec, 10, 1, tp); 182441177Smarc tputchar('.', tp); 182541177Smarc ttyoutint(x, 10, 2, tp); 182641177Smarc tputchar('u', tp); 182741177Smarc tputchar(' ', tp); 182841177Smarc /* system time */ 182941177Smarc x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */ 183041177Smarc ttyoutint(stime.tv_sec, 10, 1, tp); 183141177Smarc tputchar('.', tp); 183241177Smarc ttyoutint(x, 10, 2, tp); 183341177Smarc tputchar('s', tp); 183441177Smarc tputchar(' ', tp); 183541177Smarc /* 183641177Smarc * pctcpu 183741177Smarc */ 183841177Smarc x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT; 183941177Smarc ttyoutint(x/100, 10, 1, tp); 184041177Smarc #ifdef notdef /* do we really want this ??? */ 184141177Smarc tputchar('.', tp); 184241177Smarc ttyoutint(x%100, 10, 2, tp); 184341177Smarc #endif 184441177Smarc ttyprintf(tp, "%% %dk\n", pgtok(pick->p_ssize + pick->p_dsize)); 184539407Smarc } 184641177Smarc tp->t_rocount = 0; /* so pending input will be retyped if BS */ 184739407Smarc } 184839407Smarc 184941177Smarc ttyoutint(n, base, min, tp) 185041177Smarc register int n, base, min; 185141177Smarc register struct tty *tp; 185241177Smarc { 185341177Smarc char info[16]; 185441177Smarc register char *p = info; 185541177Smarc 185641177Smarc while (--min >= 0 || n) { 185741177Smarc *p++ = "0123456789abcdef"[n%base]; 185841177Smarc n /= base; 185941177Smarc } 186041177Smarc while (p > info) 186141177Smarc ttyoutput(*--p, tp); 186241177Smarc } 186341177Smarc 186441177Smarc /* 186541177Smarc * Returns 1 if p2 is "better" than p1 186641177Smarc * 186741177Smarc * The algorithm for picking the "interesting" process is thus: 186841177Smarc * 186941177Smarc * 1) (Only foreground processes are eligable - implied) 187041177Smarc * 2) Runnable processes are favored over anything 187141177Smarc * else. The runner with the highest cpu 187241177Smarc * utilization is picked (p_cpu). Ties are 187341177Smarc * broken by picking the highest pid. 187441177Smarc * 3 Next, the sleeper with the shortest sleep 187541177Smarc * time is favored. With ties, we pick out 187641177Smarc * just "short-term" sleepers (SSINTR == 0). 187741177Smarc * Further ties are broken by picking the highest 187841177Smarc * pid. 187941177Smarc * 188041177Smarc */ 188141177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 188241177Smarc proc_compare(p1, p2) 188341177Smarc register struct proc *p1, *p2; 188441177Smarc { 188541177Smarc 188641177Smarc if (p1 == NULL) 188741177Smarc return (1); 188841177Smarc /* 188941177Smarc * see if at least one of them is runnable 189041177Smarc */ 189141177Smarc switch (isrun(p1)<<1 | isrun(p2)) { 189241177Smarc case 0x01: 189341177Smarc return (1); 189441177Smarc case 0x10: 189541177Smarc return (0); 189641177Smarc case 0x11: 189741177Smarc /* 189841177Smarc * tie - favor one with highest recent cpu utilization 189941177Smarc */ 190041177Smarc if (p2->p_cpu > p1->p_cpu) 190141177Smarc return (1); 190241177Smarc if (p1->p_cpu > p2->p_cpu) 190341177Smarc return (0); 190441177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 190541177Smarc } 190641177Smarc /* 190741177Smarc * pick the one with the smallest sleep time 190841177Smarc */ 190941177Smarc if (p2->p_slptime > p1->p_slptime) 191041177Smarc return (0); 191141177Smarc if (p1->p_slptime > p2->p_slptime) 191241177Smarc return (1); 191341177Smarc /* 191441177Smarc * favor one sleeping in a non-interruptible sleep 191541177Smarc */ 191641177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 191741177Smarc return (1); 191841177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 191941177Smarc return (0); 192041177Smarc return(p2->p_pid > p1->p_pid); /* tie - return highest pid */ 192141177Smarc } 192239407Smarc #define TOTTY 0x2 /* XXX should be in header */ 192339407Smarc /*VARARGS2*/ 192439407Smarc ttyprintf(tp, fmt, x1) 192539555Smarc struct tty *tp; 192639407Smarc char *fmt; 192739407Smarc unsigned x1; 192839407Smarc { 192939555Smarc prf(fmt, &x1, TOTTY, (caddr_t)tp); 193039407Smarc } 193139555Smarc 193239555Smarc /* 193339555Smarc * Output char to tty; console putchar style. 193439555Smarc */ 193539555Smarc tputchar(c, tp) 193639555Smarc int c; 193739555Smarc struct tty *tp; 193839555Smarc { 193939555Smarc register s = spltty(); 194039555Smarc 194139555Smarc if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN)) 194239555Smarc == (TS_CARR_ON | TS_ISOPEN)) { 194339555Smarc if (c == '\n') 194439555Smarc (void) ttyoutput('\r', tp); 194539555Smarc (void) ttyoutput(c, tp); 194639555Smarc ttstart(tp); 194739555Smarc splx(s); 194839555Smarc return (0); 194939555Smarc } 195039555Smarc splx(s); 195139555Smarc return (-1); 195239555Smarc } 1953