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*42882Smarc * @(#)tty.c 7.28 (Berkeley) 06/05/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; 12340712Skarels if (error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, 12440712Skarels ttyout, 0)) 12540712Skarels break; 126903Sbill } 1279859Ssam splx(s); 12840712Skarels return (error); 12939Sbill } 13039Sbill 13139Sbill /* 1329578Ssam * Flush all TTY queues 13339Sbill */ 13412752Ssam ttyflush(tp, rw) 1357625Ssam register struct tty *tp; 13639Sbill { 137903Sbill register s; 138903Sbill 13917545Skarels s = spltty(); 140903Sbill if (rw & FREAD) { 141903Sbill while (getc(&tp->t_canq) >= 0) 142903Sbill ; 14337584Smarc ttwakeup(tp); 144903Sbill } 145903Sbill if (rw & FWRITE) { 14637584Smarc wakeup((caddr_t)&tp->t_outq); /* XXX? what about selwakeup? */ 1475408Swnj tp->t_state &= ~TS_TTSTOP; 1485426Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, rw); 149903Sbill while (getc(&tp->t_outq) >= 0) 150903Sbill ; 151903Sbill } 152903Sbill if (rw & FREAD) { 153903Sbill while (getc(&tp->t_rawq) >= 0) 154903Sbill ; 1559578Ssam tp->t_rocount = 0; 156903Sbill tp->t_rocol = 0; 1579578Ssam tp->t_state &= ~TS_LOCAL; 158903Sbill } 159903Sbill splx(s); 16039Sbill } 16139Sbill 162903Sbill /* 163903Sbill * Send stop character on input overflow. 164903Sbill */ 165903Sbill ttyblock(tp) 1667625Ssam register struct tty *tp; 16739Sbill { 168903Sbill register x; 1699578Ssam 170903Sbill x = tp->t_rawq.c_cc + tp->t_canq.c_cc; 171903Sbill if (tp->t_rawq.c_cc > TTYHOG) { 17212752Ssam ttyflush(tp, FREAD|FWRITE); 1735408Swnj tp->t_state &= ~TS_TBLOCK; 174903Sbill } 17515118Skarels /* 17615118Skarels * Block further input iff: 17715118Skarels * Current input > threshold AND input is available to user program 17815118Skarels */ 17942350Smckusick if (x >= TTYHOG/2 && (tp->t_state & TS_TBLOCK) == 0 && 18040712Skarels ((tp->t_lflag&ICANON) == 0) || (tp->t_canq.c_cc > 0) && 18135811Smarc tp->t_cc[VSTOP] != _POSIX_VDISABLE) { 18242350Smckusick if (putc(tp->t_cc[VSTOP], &tp->t_outq) == 0) { 18315118Skarels tp->t_state |= TS_TBLOCK; 18415118Skarels ttstart(tp); 18515118Skarels } 186903Sbill } 18739Sbill } 18839Sbill 18939Sbill /* 190903Sbill * Restart typewriter output following a delay 191903Sbill * timeout. 192903Sbill * The name of the routine is passed to the timeout 193903Sbill * subroutine and it is called during a clock interrupt. 194121Sbill */ 195903Sbill ttrstrt(tp) 19637584Smarc struct tty *tp; 197121Sbill { 198121Sbill 19940712Skarels #ifdef DIAGNOSTIC 2009578Ssam if (tp == 0) 2019578Ssam panic("ttrstrt"); 20240712Skarels #endif 2035408Swnj tp->t_state &= ~TS_TIMEOUT; 204903Sbill ttstart(tp); 205121Sbill } 206121Sbill 207121Sbill /* 208903Sbill * Start output on the typewriter. It is used from the top half 209903Sbill * after some characters have been put on the output queue, 210903Sbill * from the interrupt routine to transmit the next 211903Sbill * character, and after a timeout has finished. 21239Sbill */ 213903Sbill ttstart(tp) 21437584Smarc struct tty *tp; 21539Sbill { 21639Sbill 21732067Skarels if (tp->t_oproc) /* kludge for pty */ 218903Sbill (*tp->t_oproc)(tp); 21939Sbill } 22039Sbill 22139Sbill /* 222903Sbill * Common code for tty ioctls. 22339Sbill */ 2241780Sbill /*ARGSUSED*/ 2257625Ssam ttioctl(tp, com, data, flag) 2267625Ssam register struct tty *tp; 2277625Ssam caddr_t data; 22839Sbill { 22939Sbill extern int nldisp; 23037554Smckusick int s, error; 23139Sbill 232903Sbill /* 233903Sbill * If the ioctl involves modification, 23417545Skarels * hang if in the background. 235903Sbill */ 2367625Ssam switch (com) { 23739Sbill 23835811Smarc case TIOCSETD: 239903Sbill case TIOCFLUSH: 24035811Smarc /*case TIOCSPGRP:*/ 2419325Ssam case TIOCSTI: 24217598Sbloom case TIOCSWINSZ: 24335811Smarc case TIOCSETA: 24435811Smarc case TIOCSETAW: 24535811Smarc case TIOCSETAF: 24639407Smarc /**** these get removed **** 24735811Smarc case TIOCSETAS: 24835811Smarc case TIOCSETAWS: 24935811Smarc case TIOCSETAFS: 25039407Smarc /***************************/ 25140030Smarc #ifdef COMPAT_43 25240030Smarc case TIOCSETP: 25340030Smarc case TIOCSETN: 25440030Smarc case TIOCSETC: 25540030Smarc case TIOCSLTC: 25640030Smarc case TIOCLBIS: 25740030Smarc case TIOCLBIC: 25840030Smarc case TIOCLSET: 25940030Smarc case OTIOCSETD: 26040030Smarc #endif 26139555Smarc while (isbackground(u.u_procp, tp) && 26235811Smarc u.u_procp->p_pgrp->pg_jobc && 263903Sbill (u.u_procp->p_flag&SVFORK) == 0 && 26440712Skarels (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 && 26540712Skarels (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0) { 266*42882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU, 1); 26740712Skarels if (error = tsleep((caddr_t)&lbolt, TTOPRI | PCATCH, 26840712Skarels ttybg, 0)) 26940712Skarels return (error); 270903Sbill } 271903Sbill break; 272903Sbill } 273903Sbill 2749578Ssam /* 2759578Ssam * Process the ioctl. 2769578Ssam */ 2777625Ssam switch (com) { 278903Sbill 2798556Sroot /* get discipline number */ 28039Sbill case TIOCGETD: 2817625Ssam *(int *)data = tp->t_line; 28239Sbill break; 28339Sbill 2848556Sroot /* set line discipline */ 2857625Ssam case TIOCSETD: { 2867625Ssam register int t = *(int *)data; 28735811Smarc dev_t dev = tp->t_dev; 2887625Ssam 28935811Smarc if ((unsigned)t >= nldisp) 29010851Ssam return (ENXIO); 29125584Skarels if (t != tp->t_line) { 29225584Skarels s = spltty(); 29325584Skarels (*linesw[tp->t_line].l_close)(tp); 29425584Skarels error = (*linesw[t].l_open)(dev, tp); 29525584Skarels if (error) { 29635811Smarc (void)(*linesw[tp->t_line].l_open)(dev, tp); 29725584Skarels splx(s); 29825584Skarels return (error); 29925584Skarels } 30025584Skarels tp->t_line = t; 30110851Ssam splx(s); 30210851Ssam } 30339Sbill break; 3047625Ssam } 30539Sbill 3068556Sroot /* prevent more opens on channel */ 3075614Swnj case TIOCEXCL: 3085614Swnj tp->t_state |= TS_XCLUDE; 3095614Swnj break; 3105614Swnj 3115614Swnj case TIOCNXCL: 3125614Swnj tp->t_state &= ~TS_XCLUDE; 3135614Swnj break; 3145614Swnj 31539Sbill case TIOCHPCL: 31635811Smarc tp->t_cflag |= HUPCL; 31739Sbill break; 31839Sbill 3193942Sbugs case TIOCFLUSH: { 3207625Ssam register int flags = *(int *)data; 3217625Ssam 3227625Ssam if (flags == 0) 3233942Sbugs flags = FREAD|FWRITE; 3247625Ssam else 3257625Ssam flags &= FREAD|FWRITE; 32612752Ssam ttyflush(tp, flags); 32739Sbill break; 3283944Sbugs } 32939Sbill 33037584Smarc case FIOASYNC: 33137584Smarc if (*(int *)data) 33237584Smarc tp->t_state |= TS_ASYNC; 33337584Smarc else 33437584Smarc tp->t_state &= ~TS_ASYNC; 33537584Smarc break; 33637584Smarc 33737584Smarc case FIONBIO: 33837584Smarc break; /* XXX remove */ 33937584Smarc 3408556Sroot /* return number of characters immediately available */ 3417625Ssam case FIONREAD: 3427625Ssam *(off_t *)data = ttnread(tp); 343174Sbill break; 344174Sbill 34513077Ssam case TIOCOUTQ: 34613077Ssam *(int *)data = tp->t_outq.c_cc; 34713077Ssam break; 34813077Ssam 3498589Sroot case TIOCSTOP: 35017545Skarels s = spltty(); 3519578Ssam if ((tp->t_state&TS_TTSTOP) == 0) { 3525573Swnj tp->t_state |= TS_TTSTOP; 3535573Swnj (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 3545573Swnj } 3557625Ssam splx(s); 3565573Swnj break; 3575573Swnj 3588589Sroot case TIOCSTART: 35917545Skarels s = spltty(); 36035811Smarc if ((tp->t_state&TS_TTSTOP) || (tp->t_lflag&FLUSHO)) { 3615573Swnj tp->t_state &= ~TS_TTSTOP; 36235811Smarc tp->t_lflag &= ~FLUSHO; 3635573Swnj ttstart(tp); 3645573Swnj } 3657625Ssam splx(s); 3665573Swnj break; 3675573Swnj 3689325Ssam /* 3699325Ssam * Simulate typing of a character at the terminal. 3709325Ssam */ 3719325Ssam case TIOCSTI: 37217183Smckusick if (u.u_uid && (flag & FREAD) == 0) 37317183Smckusick return (EPERM); 37439555Smarc if (u.u_uid && !isctty(u.u_procp, tp)) 3759325Ssam return (EACCES); 3769578Ssam (*linesw[tp->t_line].l_rint)(*(char *)data, tp); 3779325Ssam break; 3789325Ssam 37935811Smarc case TIOCGETA: { 38035811Smarc struct termios *t = (struct termios *)data; 38112752Ssam 38235811Smarc bcopy(&tp->t_termios, t, sizeof(struct termios)); 38335811Smarc break; 38435811Smarc } 38535811Smarc 38639407Smarc /*** THIS ALL GETS REMOVED ***/ 38739407Smarc case JUNK_TIOCSETAS: 38839407Smarc case JUNK_TIOCSETAWS: 38939407Smarc case JUNK_TIOCSETAFS: 39039407Smarc ((struct termios *)data)->c_cflag |= CIGNORE; 39139407Smarc switch(com) { 39239407Smarc case JUNK_TIOCSETAS: 39339407Smarc com = TIOCSETA; 39439407Smarc break; 39539407Smarc case JUNK_TIOCSETAWS: 39639407Smarc com = TIOCSETAW; 39739407Smarc break; 39839407Smarc case JUNK_TIOCSETAFS: 39939407Smarc com = TIOCSETAF; 40039407Smarc break; 40139407Smarc } 40239407Smarc /*******************************/ 40339407Smarc /*FALLTHROGH*/ 40435811Smarc case TIOCSETA: 40535811Smarc case TIOCSETAW: 40637584Smarc case TIOCSETAF: { 40735811Smarc register struct termios *t = (struct termios *)data; 40840712Skarels 40917545Skarels s = spltty(); 41039407Smarc if (com == TIOCSETAW || com == TIOCSETAF) { 41140712Skarels if (error = ttywait(tp)) { 41240712Skarels splx(s); 41340712Skarels return (error); 41440712Skarels } 41539407Smarc if (com == TIOCSETAF); 41639407Smarc ttyflush(tp, FREAD); 41739407Smarc } 41840712Skarels if ((t->c_cflag&CIGNORE) == 0) { 41935811Smarc /* 42035811Smarc * set device hardware 42135811Smarc */ 42237584Smarc if (tp->t_param && (error = (*tp->t_param)(tp, t))) { 42337584Smarc splx(s); 42435811Smarc return (error); 42537584Smarc } else { 42640712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && 42737584Smarc (tp->t_cflag&CLOCAL) && 42840712Skarels (t->c_cflag&CLOCAL) == 0) { 42937584Smarc tp->t_state &= ~TS_ISOPEN; 43037584Smarc tp->t_state |= TS_WOPEN; 43137584Smarc ttwakeup(tp); 43237584Smarc } 43335811Smarc tp->t_cflag = t->c_cflag; 43435811Smarc tp->t_ispeed = t->c_ispeed; 43535811Smarc tp->t_ospeed = t->c_ospeed; 43634492Skarels } 43735811Smarc ttsetwater(tp); 43812752Ssam } 43939407Smarc if (com != TIOCSETAF) { 44035811Smarc if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) 44135811Smarc if (t->c_lflag&ICANON) { 44235811Smarc tp->t_lflag |= PENDIN; 44335811Smarc ttwakeup(tp); 44435811Smarc } 44535811Smarc else { 44635811Smarc struct clist tq; 44735811Smarc 44835811Smarc catq(&tp->t_rawq, &tp->t_canq); 44935811Smarc tq = tp->t_rawq; 45035811Smarc tp->t_rawq = tp->t_canq; 45135811Smarc tp->t_canq = tq; 45235811Smarc } 45312752Ssam } 45435811Smarc tp->t_iflag = t->c_iflag; 45535811Smarc tp->t_oflag = t->c_oflag; 456*42882Smarc /* 457*42882Smarc * Make the EXTPROC bit read only. 458*42882Smarc */ 459*42882Smarc if (tp->t_lflag&EXTPROC) 460*42882Smarc t->c_lflag |= EXTPROC; 461*42882Smarc else 462*42882Smarc t->c_lflag &= ~EXTPROC; 46335811Smarc tp->t_lflag = t->c_lflag; 46435811Smarc bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc)); 46512752Ssam splx(s); 46612752Ssam break; 46712752Ssam } 46812752Ssam 46912752Ssam /* 47039555Smarc * Set controlling terminal. 47139555Smarc * Session ctty vnode pointer set in vnode layer. 47234492Skarels */ 47335811Smarc case TIOCSCTTY: { 47435811Smarc register struct proc *p = u.u_procp; 47534492Skarels 47639555Smarc if (!SESS_LEADER(p) || 47739555Smarc (p->p_session->s_ttyvp || tp->t_session) && 47839555Smarc (tp->t_session != p->p_session)) 47939407Smarc return (EPERM); 48035811Smarc tp->t_session = p->p_session; 48139555Smarc tp->t_pgrp = p->p_pgrp; 48239555Smarc p->p_session->s_ttyp = tp; 48339555Smarc p->p_flag |= SCTTY; 48434492Skarels break; 48535811Smarc } 48639555Smarc 48734492Skarels /* 48835811Smarc * Set terminal process group. 48917545Skarels */ 49018650Sbloom case TIOCSPGRP: { 49135811Smarc register struct proc *p = u.u_procp; 49235811Smarc register struct pgrp *pgrp = pgfind(*(int *)data); 49317545Skarels 49439555Smarc if (!isctty(p, tp)) 49539555Smarc return (ENOTTY); 49640030Smarc else if (pgrp == NULL || pgrp->pg_session != p->p_session) 49739555Smarc return (EPERM); 49839555Smarc tp->t_pgrp = pgrp; 49912752Ssam break; 50018650Sbloom } 50112752Ssam 50212752Ssam case TIOCGPGRP: 50339555Smarc if (!isctty(u.u_procp, tp)) 50439555Smarc return (ENOTTY); 50539555Smarc *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; 50612752Ssam break; 50712752Ssam 50817598Sbloom case TIOCSWINSZ: 50918650Sbloom if (bcmp((caddr_t)&tp->t_winsize, data, 51018650Sbloom sizeof (struct winsize))) { 51117598Sbloom tp->t_winsize = *(struct winsize *)data; 512*42882Smarc pgsignal(tp->t_pgrp, SIGWINCH, 1); 51317598Sbloom } 51417598Sbloom break; 51517598Sbloom 51617598Sbloom case TIOCGWINSZ: 51717598Sbloom *(struct winsize *)data = tp->t_winsize; 51817598Sbloom break; 51917598Sbloom 52030534Skarels case TIOCCONS: 52130534Skarels if (*(int *)data) { 52242141Smckusick if (constty && constty != tp && 52342141Smckusick (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) == 52442141Smckusick (TS_CARR_ON|TS_ISOPEN)) 52530534Skarels return (EBUSY); 52630534Skarels #ifndef UCONSOLE 52737554Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 52837554Smckusick return (error); 52930534Skarels #endif 53030534Skarels constty = tp; 53130534Skarels } else if (tp == constty) 53233404Skarels constty = NULL; 53330534Skarels break; 53430534Skarels 53535811Smarc #ifdef COMPAT_43 53635811Smarc case TIOCGETP: 53735811Smarc case TIOCSETP: 53835811Smarc case TIOCSETN: 53935811Smarc case TIOCGETC: 54035811Smarc case TIOCSETC: 54135811Smarc case TIOCSLTC: 54235811Smarc case TIOCGLTC: 54335811Smarc case TIOCLBIS: 54435811Smarc case TIOCLBIC: 54535811Smarc case TIOCLSET: 54635811Smarc case TIOCLGET: 54739407Smarc case OTIOCGETD: 54839407Smarc case OTIOCSETD: 54935811Smarc return(ttcompat(tp, com, data, flag)); 55035811Smarc #endif 55135811Smarc 55239Sbill default: 5538556Sroot return (-1); 55439Sbill } 5558556Sroot return (0); 55639Sbill } 5574484Swnj 5584484Swnj ttnread(tp) 5594484Swnj struct tty *tp; 5604484Swnj { 5614484Swnj int nread = 0; 5624484Swnj 56335811Smarc if (tp->t_lflag & PENDIN) 5644484Swnj ttypend(tp); 5654484Swnj nread = tp->t_canq.c_cc; 56635811Smarc if ((tp->t_lflag & ICANON) == 0) 5674484Swnj nread += tp->t_rawq.c_cc; 5684484Swnj return (nread); 5694484Swnj } 5704484Swnj 5715408Swnj ttselect(dev, rw) 5724484Swnj dev_t dev; 5735408Swnj int rw; 5744484Swnj { 5754484Swnj register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)]; 5764484Swnj int nread; 57717545Skarels int s = spltty(); 5784484Swnj 5795408Swnj switch (rw) { 5804484Swnj 5814484Swnj case FREAD: 5824484Swnj nread = ttnread(tp); 58337584Smarc if (nread > 0 || 58440712Skarels ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 5855408Swnj goto win; 5864938Swnj if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait) 5875408Swnj tp->t_state |= TS_RCOLL; 5884484Swnj else 5894484Swnj tp->t_rsel = u.u_procp; 5905408Swnj break; 5914484Swnj 5925408Swnj case FWRITE: 59335811Smarc if (tp->t_outq.c_cc <= tp->t_lowat) 5945408Swnj goto win; 5955408Swnj if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait) 5965408Swnj tp->t_state |= TS_WCOLL; 5975408Swnj else 5985408Swnj tp->t_wsel = u.u_procp; 5995408Swnj break; 6004484Swnj } 6015408Swnj splx(s); 6025408Swnj return (0); 6035408Swnj win: 6045408Swnj splx(s); 6055408Swnj return (1); 6064484Swnj } 6077436Skre 6087502Sroot /* 60925391Skarels * Initial open of tty, or (re)entry to line discipline. 6107502Sroot */ 6117502Sroot ttyopen(dev, tp) 6127625Ssam dev_t dev; 6137625Ssam register struct tty *tp; 6147502Sroot { 6157502Sroot 6167502Sroot tp->t_dev = dev; 61735811Smarc 6187502Sroot tp->t_state &= ~TS_WOPEN; 61917545Skarels if ((tp->t_state & TS_ISOPEN) == 0) { 62017545Skarels tp->t_state |= TS_ISOPEN; 62117598Sbloom bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize)); 62217545Skarels } 6238556Sroot return (0); 6247502Sroot } 6257502Sroot 6267502Sroot /* 62725391Skarels * "close" a line discipline 62825391Skarels */ 62925391Skarels ttylclose(tp) 63025391Skarels register struct tty *tp; 63125391Skarels { 63225391Skarels 63325391Skarels ttywflush(tp); 63425391Skarels } 63525391Skarels 63625391Skarels /* 6377502Sroot * clean tp on last close 6387502Sroot */ 6397502Sroot ttyclose(tp) 6407625Ssam register struct tty *tp; 6417502Sroot { 64230534Skarels if (constty == tp) 64330534Skarels constty = NULL; 64425391Skarels ttyflush(tp, FREAD|FWRITE); 64539555Smarc tp->t_session = NULL; 64639555Smarc tp->t_pgrp = NULL; 6477502Sroot tp->t_state = 0; 64840712Skarels return (0); 6497502Sroot } 6507502Sroot 6517502Sroot /* 65225391Skarels * Handle modem control transition on a tty. 65325391Skarels * Flag indicates new state of carrier. 65425391Skarels * Returns 0 if the line should be turned off, otherwise 1. 65525391Skarels */ 65625391Skarels ttymodem(tp, flag) 65725391Skarels register struct tty *tp; 65825391Skarels { 65925391Skarels 66042193Smarc if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { 66125391Skarels /* 66225391Skarels * MDMBUF: do flow control according to carrier flag 66325391Skarels */ 66425391Skarels if (flag) { 66525391Skarels tp->t_state &= ~TS_TTSTOP; 66625391Skarels ttstart(tp); 66725391Skarels } else if ((tp->t_state&TS_TTSTOP) == 0) { 66825391Skarels tp->t_state |= TS_TTSTOP; 66925391Skarels (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 67025391Skarels } 67125391Skarels } else if (flag == 0) { 67225391Skarels /* 67325391Skarels * Lost carrier. 67425391Skarels */ 67525391Skarels tp->t_state &= ~TS_CARR_ON; 67642193Smarc if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) { 67742193Smarc if (tp->t_session && tp->t_session->s_leader) 67842193Smarc psignal(tp->t_session->s_leader, SIGHUP); 67942193Smarc ttyflush(tp, FREAD|FWRITE); 68042193Smarc return (0); 68125391Skarels } 68225391Skarels } else { 68325391Skarels /* 68425391Skarels * Carrier now on. 68525391Skarels */ 68625391Skarels tp->t_state |= TS_CARR_ON; 68737584Smarc ttwakeup(tp); 68825391Skarels } 68925391Skarels return (1); 69025391Skarels } 69125391Skarels 69225391Skarels /* 69325404Skarels * Default modem control routine (for other line disciplines). 69425404Skarels * Return argument flag, to turn off device on carrier drop. 69525404Skarels */ 69625415Skarels nullmodem(tp, flag) 69725415Skarels register struct tty *tp; 69825404Skarels int flag; 69925404Skarels { 70025404Skarels 70125404Skarels if (flag) 70225404Skarels tp->t_state |= TS_CARR_ON; 70339407Smarc else { 70425404Skarels tp->t_state &= ~TS_CARR_ON; 70542193Smarc if ((tp->t_cflag&CLOCAL) == 0) { 70642193Smarc if (tp->t_session && tp->t_session->s_leader) 70742193Smarc psignal(tp->t_session->s_leader, SIGHUP); 70842193Smarc return (0); 70942193Smarc } 71039407Smarc } 71142193Smarc return (1); 71225404Skarels } 71325404Skarels 71425404Skarels /* 7157502Sroot * reinput pending characters after state switch 71617545Skarels * call at spltty(). 7177502Sroot */ 7187502Sroot ttypend(tp) 7197625Ssam register struct tty *tp; 7207502Sroot { 7217502Sroot struct clist tq; 7227502Sroot register c; 7237502Sroot 72435811Smarc tp->t_lflag &= ~PENDIN; 7259578Ssam tp->t_state |= TS_TYPEN; 7267502Sroot tq = tp->t_rawq; 7277502Sroot tp->t_rawq.c_cc = 0; 7287502Sroot tp->t_rawq.c_cf = tp->t_rawq.c_cl = 0; 7297502Sroot while ((c = getc(&tq)) >= 0) 7307502Sroot ttyinput(c, tp); 7319578Ssam tp->t_state &= ~TS_TYPEN; 7327502Sroot } 7337502Sroot 7347502Sroot /* 73535811Smarc * 7369578Ssam * Place a character on raw TTY input queue, 7379578Ssam * putting in delimiters and waking up top 7389578Ssam * half as needed. Also echo if required. 7399578Ssam * The arguments are the character and the 7409578Ssam * appropriate tty structure. 7417502Sroot */ 7427502Sroot ttyinput(c, tp) 7437625Ssam register c; 7447625Ssam register struct tty *tp; 7457502Sroot { 74635811Smarc register int iflag = tp->t_iflag; 74735811Smarc register int lflag = tp->t_lflag; 74835811Smarc register u_char *cc = tp->t_cc; 74935811Smarc int i, err; 7507502Sroot 7519578Ssam /* 7529578Ssam * If input is pending take it first. 7539578Ssam */ 75435811Smarc if (lflag&PENDIN) 7557502Sroot ttypend(tp); 75635811Smarc /* 75735811Smarc * Gather stats. 75835811Smarc */ 7597502Sroot tk_nin++; 76035811Smarc if (lflag&ICANON) { 76135811Smarc tk_cancc++; 76235811Smarc tp->t_cancc++; 76335811Smarc } else { 76435811Smarc tk_rawcc++; 76535811Smarc tp->t_rawcc++; 76635811Smarc } 7679578Ssam /* 76835811Smarc * Handle exceptional conditions (break, parity, framing). 7699578Ssam */ 77035811Smarc if (err = (c&TTY_ERRORMASK)) { 77135811Smarc c &= ~TTY_ERRORMASK; 77235811Smarc if (err&TTY_FE && !c) { /* break */ 77335811Smarc if (iflag&IGNBRK) 77435811Smarc goto endcase; 77535811Smarc else if (iflag&BRKINT && lflag&ISIG && 77635811Smarc (cc[VINTR] != _POSIX_VDISABLE)) 77735811Smarc c = cc[VINTR]; 77835811Smarc else { 77935811Smarc c = 0; 78035811Smarc if (iflag&PARMRK) 78135811Smarc goto parmrk; 78235811Smarc } 78335811Smarc } else if ((err&TTY_PE && iflag&INPCK) || err&TTY_FE) { 78435811Smarc if (iflag&IGNPAR) 78535811Smarc goto endcase; 78635811Smarc else if (iflag&PARMRK) { 78735811Smarc parmrk: 78835811Smarc putc(0377|TTY_QUOTE, &tp->t_rawq); 78935811Smarc putc(0|TTY_QUOTE, &tp->t_rawq); 79035811Smarc putc(c|TTY_QUOTE, &tp->t_rawq); 79135811Smarc goto endcase; 79235811Smarc } else 79335811Smarc c = 0; 7947502Sroot } 7959578Ssam } 7969578Ssam /* 79735811Smarc * In tandem mode, check high water mark. 7989578Ssam */ 79935811Smarc if (iflag&IXOFF) 80035811Smarc ttyblock(tp); 80135811Smarc if ((tp->t_state&TS_TYPEN) == 0 && (iflag&ISTRIP)) 8029578Ssam c &= 0177; 803*42882Smarc if ((tp->t_lflag&EXTPROC) == 0) { 8049578Ssam /* 8059578Ssam * Check for literal nexting very first 8069578Ssam */ 8079578Ssam if (tp->t_state&TS_LNCH) { 80835811Smarc c |= TTY_QUOTE; 8099578Ssam tp->t_state &= ~TS_LNCH; 8109578Ssam } 8119578Ssam /* 8129578Ssam * Scan for special characters. This code 8139578Ssam * is really just a big case statement with 8149578Ssam * non-constant cases. The bottom of the 8159578Ssam * case statement is labeled ``endcase'', so goto 8169578Ssam * it after a case match, or similar. 8179578Ssam */ 81835811Smarc /* 81935811Smarc * Control chars which aren't controlled 82035811Smarc * by ICANON, ISIG, or IXON. 82135811Smarc */ 82239407Smarc if (lflag&IEXTEN) { 82340712Skarels if (CCEQ(cc[VLNEXT], c)) { 82435811Smarc if (lflag&ECHO) { 82535811Smarc if (lflag&ECHOE) 82640712Skarels ttyoutstr("^\b", tp); 82735811Smarc else 82835811Smarc ttyecho(c, tp); 82935811Smarc } 8309578Ssam tp->t_state |= TS_LNCH; 8319578Ssam goto endcase; 8329578Ssam } 83340712Skarels if (CCEQ(cc[VFLUSHO], c)) { 83435811Smarc if (lflag&FLUSHO) 83535811Smarc tp->t_lflag &= ~FLUSHO; 8367502Sroot else { 83712752Ssam ttyflush(tp, FWRITE); 8387502Sroot ttyecho(c, tp); 8399578Ssam if (tp->t_rawq.c_cc + tp->t_canq.c_cc) 8407502Sroot ttyretype(tp); 84135811Smarc tp->t_lflag |= FLUSHO; 8427502Sroot } 8439578Ssam goto startoutput; 8449578Ssam } 84535811Smarc } 84635811Smarc /* 84735811Smarc * Signals. 84835811Smarc */ 84935811Smarc if (lflag&ISIG) { 85035811Smarc if (CCEQ(cc[VINTR], c) || CCEQ(cc[VQUIT], c)) { 85135811Smarc if ((lflag&NOFLSH) == 0) 85235811Smarc ttyflush(tp, FREAD|FWRITE); 85335811Smarc ttyecho(c, tp); 85439555Smarc pgsignal(tp->t_pgrp, 855*42882Smarc CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); 85635811Smarc goto endcase; 85735811Smarc } 85840712Skarels if (CCEQ(cc[VSUSP], c)) { 85935811Smarc if ((lflag&NOFLSH) == 0) 86012752Ssam ttyflush(tp, FREAD); 8619578Ssam ttyecho(c, tp); 862*42882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 8639578Ssam goto endcase; 8649578Ssam } 8659578Ssam } 8669578Ssam /* 8679578Ssam * Handle start/stop characters. 8689578Ssam */ 86935811Smarc if (iflag&IXON) { 87040712Skarels if (CCEQ(cc[VSTOP], c)) { 87135811Smarc if ((tp->t_state&TS_TTSTOP) == 0) { 87235811Smarc tp->t_state |= TS_TTSTOP; 87335811Smarc (*cdevsw[major(tp->t_dev)].d_stop)(tp, 0); 87435811Smarc return; 87535811Smarc } 87635811Smarc if (!CCEQ(cc[VSTART], c)) 87735811Smarc return; 87835811Smarc /* 87935811Smarc * if VSTART == VSTOP then toggle 88035811Smarc */ 88135811Smarc goto endcase; 8829578Ssam } 88335811Smarc if (CCEQ(cc[VSTART], c)) 88435811Smarc goto restartoutput; 8859578Ssam } 8869578Ssam /* 88735811Smarc * IGNCR, ICRNL, & INLCR 8889578Ssam */ 88935811Smarc if (c == '\r') { 89035811Smarc if (iflag&IGNCR) 89135811Smarc goto endcase; 89235811Smarc else if (iflag&ICRNL) 89335811Smarc c = '\n'; 8949578Ssam } 89535811Smarc else if (c == '\n' && iflag&INLCR) 89635811Smarc c = '\r'; 897*42882Smarc } 8989578Ssam /* 89935811Smarc * Non canonical mode; don't process line editing 9009578Ssam * characters; check high water mark for wakeup. 90135811Smarc * 9029578Ssam */ 90340712Skarels if ((lflag&ICANON) == 0) { 9049578Ssam if (tp->t_rawq.c_cc > TTYHOG) { 90535811Smarc if (iflag&IMAXBEL) { 90635811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 90735811Smarc (void) ttyoutput(CTRL('g'), tp); 90835811Smarc } else 90935811Smarc ttyflush(tp, FREAD | FWRITE); 91035811Smarc } else { 91135811Smarc if (putc(c, &tp->t_rawq) >= 0) { 91235811Smarc ttwakeup(tp); 91335811Smarc ttyecho(c, tp); 91435811Smarc } 9157502Sroot } 9169578Ssam goto endcase; 9179578Ssam } 918*42882Smarc if ((tp->t_lflag&EXTPROC) == 0) { 9199578Ssam /* 92035811Smarc * From here on down canonical mode character 9219578Ssam * processing takes place. 9229578Ssam */ 92335811Smarc /* 92435811Smarc * erase (^H / ^?) 92535811Smarc */ 92639407Smarc if (CCEQ(cc[VERASE], c)) { 9279578Ssam if (tp->t_rawq.c_cc) 9289578Ssam ttyrub(unputc(&tp->t_rawq), tp); 9299578Ssam goto endcase; 9309578Ssam } 93135811Smarc /* 93235811Smarc * kill (^U) 93335811Smarc */ 93435811Smarc if (CCEQ(cc[VKILL], c)) { 93537584Smarc if (lflag&ECHOKE && tp->t_rawq.c_cc == tp->t_rocount && 93640712Skarels (lflag&ECHOPRT) == 0) { 9379578Ssam while (tp->t_rawq.c_cc) 9389578Ssam ttyrub(unputc(&tp->t_rawq), tp); 9399578Ssam } else { 9409578Ssam ttyecho(c, tp); 94135811Smarc if (lflag&ECHOK || lflag&ECHOKE) 94235811Smarc ttyecho('\n', tp); 9439578Ssam while (getc(&tp->t_rawq) > 0) 9449578Ssam ; 9459578Ssam tp->t_rocount = 0; 9469578Ssam } 9479578Ssam tp->t_state &= ~TS_LOCAL; 9489578Ssam goto endcase; 9499578Ssam } 9509578Ssam /* 95135811Smarc * word erase (^W) 9529578Ssam */ 95335811Smarc if (CCEQ(cc[VWERASE], c)) { 95435811Smarc int ctype; 95535811Smarc 95635811Smarc #define CTYPE(c) ((lflag&ALTWERASE) ? (partab[(c)&TTY_CHARMASK]&0100) : 0) 95735811Smarc /* 95835811Smarc * erase whitespace 95935811Smarc */ 96035811Smarc while ((c = unputc(&tp->t_rawq)) == ' ' || c == '\t') 96135811Smarc ttyrub(c, tp); 96235811Smarc if (c == -1) 96334492Skarels goto endcase; 96435811Smarc /* 96535811Smarc * special case last char of token 96635811Smarc */ 96735811Smarc ttyrub(c, tp); 96835811Smarc c = unputc(&tp->t_rawq); 96935811Smarc if (c == -1 || c == ' ' || c == '\t') { 97035811Smarc if (c != -1) 97135811Smarc (void) putc(c, &tp->t_rawq); 97234492Skarels goto endcase; 97334492Skarels } 97435811Smarc /* 97535811Smarc * erase rest of token 97635811Smarc */ 97735811Smarc ctype = CTYPE(c); 97835811Smarc do { 97935811Smarc ttyrub(c, tp); 98035811Smarc c = unputc(&tp->t_rawq); 98135811Smarc if (c == -1) 98235811Smarc goto endcase; 98335811Smarc } while (c != ' ' && c != '\t' && CTYPE(c) == ctype); 98435811Smarc (void) putc(c, &tp->t_rawq); 98535811Smarc goto endcase; 98635811Smarc #undef CTYPE 9879578Ssam } 9889578Ssam /* 98935811Smarc * reprint line (^R) 99035811Smarc */ 99135811Smarc if (CCEQ(cc[VREPRINT], c)) { 99235811Smarc ttyretype(tp); 99335811Smarc goto endcase; 99435811Smarc } 99542141Smckusick if (CCEQ(cc[VINFO], c)) { 996*42882Smarc pgsignal(tp->t_pgrp, SIGINFO, 1); 99742141Smckusick if ((lflag&NOKERNINFO) == 0) 99842141Smckusick ttyinfo(tp); 99942141Smckusick goto endcase; 100042141Smckusick } 1001*42882Smarc } 100235811Smarc /* 10039578Ssam * Check for input buffer overflow 10049578Ssam */ 100510391Ssam if (tp->t_rawq.c_cc+tp->t_canq.c_cc >= TTYHOG) { 100635811Smarc if (iflag&IMAXBEL) { 100735811Smarc if (tp->t_outq.c_cc < tp->t_hiwat) 100835811Smarc (void) ttyoutput(CTRL('g'), tp); 100935811Smarc } else 101035811Smarc ttyflush(tp, FREAD | FWRITE); 10119578Ssam goto endcase; 101210391Ssam } 10139578Ssam /* 10149578Ssam * Put data char in q for user and 10159578Ssam * wakeup on seeing a line delimiter. 10169578Ssam */ 10179578Ssam if (putc(c, &tp->t_rawq) >= 0) { 101835811Smarc if (ttbreakc(c)) { 10199578Ssam tp->t_rocount = 0; 10209578Ssam catq(&tp->t_rawq, &tp->t_canq); 10217502Sroot ttwakeup(tp); 10229578Ssam } else if (tp->t_rocount++ == 0) 10239578Ssam tp->t_rocol = tp->t_col; 10249578Ssam if (tp->t_state&TS_ERASE) { 102535811Smarc /* 102635811Smarc * end of prterase \.../ 102735811Smarc */ 10289578Ssam tp->t_state &= ~TS_ERASE; 10299578Ssam (void) ttyoutput('/', tp); 10309578Ssam } 10319578Ssam i = tp->t_col; 10327502Sroot ttyecho(c, tp); 103335811Smarc if (CCEQ(cc[VEOF], c) && lflag&ECHO) { 103435811Smarc /* 103535811Smarc * Place the cursor over the '^' of the ^D. 103635811Smarc */ 10379578Ssam i = MIN(2, tp->t_col - i); 10389578Ssam while (i > 0) { 10399578Ssam (void) ttyoutput('\b', tp); 10409578Ssam i--; 10419578Ssam } 10429578Ssam } 10437502Sroot } 10449578Ssam endcase: 10459578Ssam /* 104635811Smarc * IXANY means allow any character to restart output. 10479578Ssam */ 104840712Skarels if ((tp->t_state&TS_TTSTOP) && (iflag&IXANY) == 0 && 104940712Skarels cc[VSTART] != cc[VSTOP]) 10507502Sroot return; 10519578Ssam restartoutput: 10527502Sroot tp->t_state &= ~TS_TTSTOP; 105335811Smarc tp->t_lflag &= ~FLUSHO; 10549578Ssam startoutput: 10557502Sroot ttstart(tp); 10567502Sroot } 10577502Sroot 10587502Sroot /* 10599578Ssam * Put character on TTY output queue, adding delays, 10607502Sroot * expanding tabs, and handling the CR/NL bit. 10619578Ssam * This is called both from the top half for output, 10629578Ssam * and from interrupt level for echoing. 10637502Sroot * The arguments are the character and the tty structure. 10647502Sroot * Returns < 0 if putc succeeds, otherwise returns char to resend 10657502Sroot * Must be recursive. 10667502Sroot */ 10677502Sroot ttyoutput(c, tp) 10687502Sroot register c; 10697502Sroot register struct tty *tp; 10707502Sroot { 10717502Sroot register char *colp; 10727502Sroot register ctype; 107335811Smarc register long oflag = tp->t_oflag; 107435811Smarc 107540712Skarels if ((oflag&OPOST) == 0) { 107635811Smarc if (tp->t_lflag&FLUSHO) 10777502Sroot return (-1); 10787502Sroot if (putc(c, &tp->t_outq)) 10797625Ssam return (c); 10807502Sroot tk_nout++; 108135811Smarc tp->t_outcc++; 10827502Sroot return (-1); 10837502Sroot } 108435811Smarc c &= TTY_CHARMASK; 10857502Sroot /* 10867502Sroot * Turn tabs to spaces as required 1087*42882Smarc * 1088*42882Smarc * Special case if we have external processing, we don't 1089*42882Smarc * do the tab expansion because we'll probably get it 1090*42882Smarc * wrong. If tab expansion needs to be done, let it 1091*42882Smarc * happen externally. 10927502Sroot */ 1093*42882Smarc if ((tp->t_lflag&EXTPROC) == 0 && 1094*42882Smarc c == '\t' && oflag&OXTABS ) { 10957502Sroot register int s; 10967502Sroot 10977502Sroot c = 8 - (tp->t_col&7); 109835811Smarc if ((tp->t_lflag&FLUSHO) == 0) { 109917545Skarels s = spltty(); /* don't interrupt tabs */ 11007502Sroot c -= b_to_q(" ", c, &tp->t_outq); 11017502Sroot tk_nout += c; 110235811Smarc tp->t_outcc += c; 11037502Sroot splx(s); 11047502Sroot } 11057502Sroot tp->t_col += c; 11067502Sroot return (c ? -1 : '\t'); 11077502Sroot } 110835811Smarc if (c == CEOT && oflag&ONOEOT) 110935811Smarc return(-1); 11107502Sroot tk_nout++; 111135811Smarc tp->t_outcc++; 11127502Sroot /* 11137502Sroot * turn <nl> to <cr><lf> if desired. 11147502Sroot */ 111535811Smarc if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0) 11167502Sroot return (c); 111735811Smarc if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_outq)) 111835811Smarc return (c); 11197502Sroot /* 11207502Sroot * Calculate delays. 11217502Sroot * The numbers here represent clock ticks 11227502Sroot * and are not necessarily optimal for all terminals. 11239578Ssam * 11249578Ssam * SHOULD JUST ALLOW USER TO SPECIFY DELAYS 112535811Smarc * 112635811Smarc * (actually, should THROW AWAY terminals which need delays) 11277502Sroot */ 11287502Sroot colp = &tp->t_col; 11297502Sroot ctype = partab[c]; 11307502Sroot c = 0; 11317502Sroot switch (ctype&077) { 11327502Sroot 11337502Sroot case ORDINARY: 11347502Sroot (*colp)++; 11357502Sroot 11367502Sroot case CONTROL: 11377502Sroot break; 11387502Sroot 11397502Sroot case BACKSPACE: 11407502Sroot if (*colp) 11417502Sroot (*colp)--; 11427502Sroot break; 11437502Sroot 114413821Ssam /* 114513821Ssam * This macro is close enough to the correct thing; 114613821Ssam * it should be replaced by real user settable delays 114713821Ssam * in any event... 114813821Ssam */ 114913821Ssam #define mstohz(ms) (((ms) * hz) >> 10) 11507502Sroot case NEWLINE: 11517502Sroot ctype = (tp->t_flags >> 8) & 03; 11527625Ssam if (ctype == 1) { /* tty 37 */ 115326357Skarels if (*colp > 0) { 115426357Skarels c = (((unsigned)*colp) >> 4) + 3; 115526357Skarels if ((unsigned)c > 6) 115626357Skarels c = 6; 115726357Skarels } 11589578Ssam } else if (ctype == 2) /* vt05 */ 115913821Ssam c = mstohz(100); 11607502Sroot *colp = 0; 11617502Sroot break; 11627502Sroot 11637502Sroot case TAB: 11647502Sroot ctype = (tp->t_flags >> 10) & 03; 11657625Ssam if (ctype == 1) { /* tty 37 */ 11667502Sroot c = 1 - (*colp | ~07); 11677625Ssam if (c < 5) 11687502Sroot c = 0; 11697502Sroot } 11707502Sroot *colp |= 07; 11717502Sroot (*colp)++; 11727502Sroot break; 11737502Sroot 11747502Sroot case VTAB: 11759578Ssam if (tp->t_flags&VTDELAY) /* tty 37 */ 11767502Sroot c = 0177; 11777502Sroot break; 11787502Sroot 11797502Sroot case RETURN: 11807502Sroot ctype = (tp->t_flags >> 12) & 03; 11819578Ssam if (ctype == 1) /* tn 300 */ 118213821Ssam c = mstohz(83); 11839578Ssam else if (ctype == 2) /* ti 700 */ 118413821Ssam c = mstohz(166); 11859578Ssam else if (ctype == 3) { /* concept 100 */ 11867502Sroot int i; 11879578Ssam 11887502Sroot if ((i = *colp) >= 0) 11899578Ssam for (; i < 9; i++) 11907502Sroot (void) putc(0177, &tp->t_outq); 11917502Sroot } 11927502Sroot *colp = 0; 11937502Sroot } 119435811Smarc if (c && (tp->t_lflag&FLUSHO) == 0) 119535811Smarc (void) putc(c|TTY_QUOTE, &tp->t_outq); 11967502Sroot return (-1); 11977502Sroot } 119813821Ssam #undef mstohz 11997502Sroot 12007502Sroot /* 12017502Sroot * Called from device's read routine after it has 12027502Sroot * calculated the tty-structure given as argument. 12037502Sroot */ 120437584Smarc ttread(tp, uio, flag) 12057625Ssam register struct tty *tp; 12067722Swnj struct uio *uio; 12077502Sroot { 12087502Sroot register struct clist *qp; 120935811Smarc register int c; 121041383Smarc register long lflag; 121135811Smarc register u_char *cc = tp->t_cc; 12129859Ssam int s, first, error = 0; 12137502Sroot 12147502Sroot loop: 121541383Smarc lflag = tp->t_lflag; 121637584Smarc s = spltty(); 12179578Ssam /* 121837584Smarc * take pending input first 12199578Ssam */ 122035811Smarc if (lflag&PENDIN) 12217502Sroot ttypend(tp); 12229859Ssam splx(s); 122340712Skarels 12249578Ssam /* 12259578Ssam * Hang process if it's in the background. 12269578Ssam */ 122739555Smarc if (isbackground(u.u_procp, tp)) { 122824392Skarels if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 122924392Skarels (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 123035811Smarc u.u_procp->p_flag&SVFORK || u.u_procp->p_pgrp->pg_jobc == 0) 12318520Sroot return (EIO); 1232*42882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1); 123340712Skarels if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0)) 123440712Skarels return (error); 123523165Sbloom goto loop; 12367502Sroot } 123740712Skarels 12389578Ssam /* 123935811Smarc * If canonical, use the canonical queue, 124035811Smarc * else use the raw queue. 124137584Smarc * 124237584Smarc * XXX - should get rid of canonical queue. 124337584Smarc * (actually, should get rid of clists...) 12449578Ssam */ 124535811Smarc qp = lflag&ICANON ? &tp->t_canq : &tp->t_rawq; 124640712Skarels 12479578Ssam /* 124840712Skarels * If there is no input, sleep on rawq 124940712Skarels * awaiting hardware receipt and notification. 125040712Skarels * If we have data, we don't need to check for carrier. 12519578Ssam */ 125217545Skarels s = spltty(); 12539578Ssam if (qp->c_cc <= 0) { 125440712Skarels int carrier; 125540712Skarels 125640712Skarels carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); 125740712Skarels if (!carrier && tp->t_state&TS_ISOPEN) { 12589859Ssam splx(s); 125940712Skarels return (0); /* EOF */ 12607502Sroot } 126137728Smckusick if (flag & IO_NDELAY) { 126237584Smarc splx(s); 126337584Smarc return (EWOULDBLOCK); 126437584Smarc } 126540712Skarels error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 126640712Skarels carrier ? ttyin : ttopen, 0); 12679859Ssam splx(s); 126840712Skarels if (error) 126940712Skarels return (error); 12709578Ssam goto loop; 12719578Ssam } 12729859Ssam splx(s); 127340712Skarels 12749578Ssam /* 127535811Smarc * Input present, check for input mapping and processing. 12769578Ssam */ 12779578Ssam first = 1; 12789578Ssam while ((c = getc(qp)) >= 0) { 12799578Ssam /* 128035811Smarc * delayed suspend (^Y) 12819578Ssam */ 128235811Smarc if (CCEQ(cc[VDSUSP], c) && lflag&ISIG) { 1283*42882Smarc pgsignal(tp->t_pgrp, SIGTSTP, 1); 12849578Ssam if (first) { 128540712Skarels if (error = tsleep((caddr_t)&lbolt, 128640712Skarels TTIPRI | PCATCH, ttybg, 0)) 128740712Skarels break; 12889578Ssam goto loop; 12899578Ssam } 12909578Ssam break; 12917502Sroot } 12929578Ssam /* 129335811Smarc * Interpret EOF only in canonical mode. 12949578Ssam */ 129535811Smarc if (CCEQ(cc[VEOF], c) && lflag&ICANON) 12969578Ssam break; 12979578Ssam /* 12989578Ssam * Give user character. 12999578Ssam */ 130040712Skarels error = ureadc(c, uio); 13019578Ssam if (error) 13029578Ssam break; 130314938Smckusick if (uio->uio_resid == 0) 13049578Ssam break; 13059578Ssam /* 130635811Smarc * In canonical mode check for a "break character" 13079578Ssam * marking the end of a "line of input". 13089578Ssam */ 130940712Skarels if (lflag&ICANON && ttbreakc(c)) 13109578Ssam break; 13119578Ssam first = 0; 13127502Sroot } 13139578Ssam /* 13149578Ssam * Look to unblock output now that (presumably) 13159578Ssam * the input queue has gone down. 13169578Ssam */ 131735811Smarc if (tp->t_state&TS_TBLOCK && tp->t_rawq.c_cc < TTYHOG/5) { 131835811Smarc if (cc[VSTART] != _POSIX_VDISABLE 131935811Smarc && putc(cc[VSTART], &tp->t_outq) == 0) { 13207502Sroot tp->t_state &= ~TS_TBLOCK; 13217502Sroot ttstart(tp); 13227502Sroot } 132335811Smarc } 13248520Sroot return (error); 13257502Sroot } 13267502Sroot 13277502Sroot /* 132825391Skarels * Check the output queue on tp for space for a kernel message 132925391Skarels * (from uprintf/tprintf). Allow some space over the normal 133025391Skarels * hiwater mark so we don't lose messages due to normal flow 133125391Skarels * control, but don't let the tty run amok. 133230695Skarels * Sleeps here are not interruptible, but we return prematurely 133330695Skarels * if new signals come in. 133425391Skarels */ 133525391Skarels ttycheckoutq(tp, wait) 133625391Skarels register struct tty *tp; 133725391Skarels int wait; 133825391Skarels { 133930695Skarels int hiwat, s, oldsig; 134025391Skarels 134135811Smarc hiwat = tp->t_hiwat; 134225391Skarels s = spltty(); 134330695Skarels oldsig = u.u_procp->p_sig; 134425391Skarels if (tp->t_outq.c_cc > hiwat + 200) 134529946Skarels while (tp->t_outq.c_cc > hiwat) { 134629946Skarels ttstart(tp); 134730695Skarels if (wait == 0 || u.u_procp->p_sig != oldsig) { 134829946Skarels splx(s); 134929946Skarels return (0); 135029946Skarels } 135130695Skarels timeout(wakeup, (caddr_t)&tp->t_outq, hz); 135229946Skarels tp->t_state |= TS_ASLEEP; 135330695Skarels sleep((caddr_t)&tp->t_outq, PZERO - 1); 135425391Skarels } 135525391Skarels splx(s); 135625391Skarels return (1); 135725391Skarels } 135825391Skarels 135925391Skarels /* 13607502Sroot * Called from the device's write routine after it has 13617502Sroot * calculated the tty-structure given as argument. 13627502Sroot */ 136337584Smarc ttwrite(tp, uio, flag) 13647625Ssam register struct tty *tp; 13659578Ssam register struct uio *uio; 13667502Sroot { 13677502Sroot register char *cp; 136840712Skarels register int cc = 0, ce; 13699578Ssam int i, hiwat, cnt, error, s; 13707502Sroot char obuf[OBUFSIZ]; 13717502Sroot 137235811Smarc hiwat = tp->t_hiwat; 13739578Ssam cnt = uio->uio_resid; 13749578Ssam error = 0; 13757502Sroot loop: 137637584Smarc s = spltty(); 137740712Skarels if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) { 137837584Smarc if (tp->t_state&TS_ISOPEN) { 137937584Smarc splx(s); 138037584Smarc return (EIO); 138137728Smckusick } else if (flag & IO_NDELAY) { 138237584Smarc splx(s); 138340712Skarels error = EWOULDBLOCK; 138440712Skarels goto out; 138537584Smarc } else { 138637584Smarc /* 138737584Smarc * sleep awaiting carrier 138837584Smarc */ 138940712Skarels error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 139040712Skarels ttopen, 0); 139137584Smarc splx(s); 139240712Skarels if (error) 139340712Skarels goto out; 139437584Smarc goto loop; 139537584Smarc } 139637584Smarc } 139737584Smarc splx(s); 13989578Ssam /* 13999578Ssam * Hang the process if it's in the background. 14009578Ssam */ 140139555Smarc if (isbackground(u.u_procp, tp) && 140235811Smarc (tp->t_lflag&TOSTOP) && (u.u_procp->p_flag&SVFORK)==0 && 140340712Skarels (u.u_procp->p_sigignore & sigmask(SIGTTOU)) == 0 && 140440712Skarels (u.u_procp->p_sigmask & sigmask(SIGTTOU)) == 0 && 140535811Smarc u.u_procp->p_pgrp->pg_jobc) { 1406*42882Smarc pgsignal(u.u_procp->p_pgrp, SIGTTOU, 1); 140740712Skarels if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, ttybg, 0)) 140840712Skarels goto out; 140921776Sbloom goto loop; 14107502Sroot } 14119578Ssam /* 14129578Ssam * Process the user's data in at most OBUFSIZ 141340712Skarels * chunks. Perform any output translation. 141440712Skarels * Keep track of high water mark, sleep on overflow 141540712Skarels * awaiting device aid in acquiring new space. 14169578Ssam */ 141740712Skarels while (uio->uio_resid > 0 || cc > 0) { 141840712Skarels if (tp->t_lflag&FLUSHO) { 141940712Skarels uio->uio_resid = 0; 142040712Skarels return (0); 142140712Skarels } 142240712Skarels if (tp->t_outq.c_cc > hiwat) 142332067Skarels goto ovhiwat; 14249578Ssam /* 142540712Skarels * Grab a hunk of data from the user, 142640712Skarels * unless we have some leftover from last time. 14279578Ssam */ 14287822Sroot if (cc == 0) { 142940712Skarels cc = min(uio->uio_resid, OBUFSIZ); 143040712Skarels cp = obuf; 143140712Skarels error = uiomove(cp, cc, uio); 143240712Skarels if (error) { 143340712Skarels cc = 0; 143440712Skarels break; 143540712Skarels } 14367822Sroot } 14379578Ssam /* 14389578Ssam * If nothing fancy need be done, grab those characters we 14399578Ssam * can handle without any of ttyoutput's processing and 14409578Ssam * just transfer them to the output q. For those chars 14419578Ssam * which require special processing (as indicated by the 14429578Ssam * bits in partab), call ttyoutput. After processing 14439578Ssam * a hunk of data, look for FLUSHO so ^O's will take effect 14449578Ssam * immediately. 14459578Ssam */ 14469578Ssam while (cc > 0) { 144740712Skarels if ((tp->t_oflag&OPOST) == 0) 14487502Sroot ce = cc; 14497502Sroot else { 145034492Skarels ce = cc - scanc((unsigned)cc, (u_char *)cp, 145134492Skarels (u_char *)partab, 077); 14529578Ssam /* 14539578Ssam * If ce is zero, then we're processing 14549578Ssam * a special character through ttyoutput. 14559578Ssam */ 14569578Ssam if (ce == 0) { 14577502Sroot tp->t_rocount = 0; 14587502Sroot if (ttyoutput(*cp, tp) >= 0) { 145921776Sbloom /* no c-lists, wait a bit */ 146021776Sbloom ttstart(tp); 146140712Skarels if (error = tsleep((caddr_t)&lbolt, 146240712Skarels TTOPRI | PCATCH, ttybuf, 0)) 146340712Skarels break; 146421776Sbloom goto loop; 14657502Sroot } 14669578Ssam cp++, cc--; 146735811Smarc if ((tp->t_lflag&FLUSHO) || 14689578Ssam tp->t_outq.c_cc > hiwat) 14697502Sroot goto ovhiwat; 14709578Ssam continue; 14717502Sroot } 14727502Sroot } 14739578Ssam /* 14749578Ssam * A bunch of normal characters have been found, 14759578Ssam * transfer them en masse to the output queue and 14769578Ssam * continue processing at the top of the loop. 14779578Ssam * If there are any further characters in this 14789578Ssam * <= OBUFSIZ chunk, the first should be a character 14799578Ssam * requiring special handling by ttyoutput. 14809578Ssam */ 14817502Sroot tp->t_rocount = 0; 14829578Ssam i = b_to_q(cp, ce, &tp->t_outq); 14839578Ssam ce -= i; 14849578Ssam tp->t_col += ce; 14859578Ssam cp += ce, cc -= ce, tk_nout += ce; 148635811Smarc tp->t_outcc += ce; 14879578Ssam if (i > 0) { 14889578Ssam /* out of c-lists, wait a bit */ 14897502Sroot ttstart(tp); 149040712Skarels if (error = tsleep((caddr_t)&lbolt, 149140712Skarels TTOPRI | PCATCH, ttybuf, 0)) 149240712Skarels break; 149321776Sbloom goto loop; 14947502Sroot } 149535811Smarc if (tp->t_lflag&FLUSHO || tp->t_outq.c_cc > hiwat) 149640712Skarels break; 14977502Sroot } 149835811Smarc ttstart(tp); 14997502Sroot } 150040712Skarels out: 150140712Skarels /* 150240712Skarels * If cc is nonzero, we leave the uio structure inconsistent, 150340712Skarels * as the offset and iov pointers have moved forward, 150440712Skarels * but it doesn't matter (the call will either return short 150540712Skarels * or restart with a new uio). 150640712Skarels */ 150740712Skarels uio->uio_resid += cc; 15088520Sroot return (error); 150940712Skarels 15107502Sroot ovhiwat: 151132067Skarels ttstart(tp); 151232067Skarels s = spltty(); 15139578Ssam /* 151435811Smarc * This can only occur if FLUSHO is set in t_lflag, 151532067Skarels * or if ttstart/oproc is synchronous (or very fast). 15169578Ssam */ 15177502Sroot if (tp->t_outq.c_cc <= hiwat) { 15189578Ssam splx(s); 15197502Sroot goto loop; 15207502Sroot } 152137728Smckusick if (flag & IO_NDELAY) { 152217545Skarels splx(s); 152340712Skarels uio->uio_resid += cc; 15247822Sroot if (uio->uio_resid == cnt) 15258520Sroot return (EWOULDBLOCK); 15268520Sroot return (0); 15277502Sroot } 15287502Sroot tp->t_state |= TS_ASLEEP; 152940712Skarels error = tsleep((caddr_t)&tp->t_outq, TTOPRI | PCATCH, ttyout, 0); 15309578Ssam splx(s); 153140712Skarels if (error) 153240712Skarels goto out; 15337502Sroot goto loop; 15347502Sroot } 15357502Sroot 15367502Sroot /* 15377502Sroot * Rubout one character from the rawq of tp 15387502Sroot * as cleanly as possible. 15397502Sroot */ 15407502Sroot ttyrub(c, tp) 15417625Ssam register c; 15427625Ssam register struct tty *tp; 15437502Sroot { 15447502Sroot register char *cp; 15457502Sroot register int savecol; 15467502Sroot int s; 15477502Sroot char *nextc(); 15487502Sroot 1549*42882Smarc if ((tp->t_lflag&ECHO) == 0 || (tp->t_lflag&EXTPROC)) 15507502Sroot return; 155135811Smarc tp->t_lflag &= ~FLUSHO; 155235811Smarc if (tp->t_lflag&ECHOE) { 15537502Sroot if (tp->t_rocount == 0) { 15547502Sroot /* 15557502Sroot * Screwed by ttwrite; retype 15567502Sroot */ 15577502Sroot ttyretype(tp); 15587502Sroot return; 15597502Sroot } 156035811Smarc if (c == ('\t'|TTY_QUOTE) || c == ('\n'|TTY_QUOTE)) 15617502Sroot ttyrubo(tp, 2); 156235811Smarc else switch (partab[c&=0377]&077) { 15637502Sroot 15647502Sroot case ORDINARY: 156535811Smarc ttyrubo(tp, 1); 15667502Sroot break; 15677502Sroot 15687502Sroot case VTAB: 15697502Sroot case BACKSPACE: 15707502Sroot case CONTROL: 15717502Sroot case RETURN: 157235811Smarc if (tp->t_lflag&ECHOCTL) 15737502Sroot ttyrubo(tp, 2); 15747502Sroot break; 15757502Sroot 157635811Smarc case TAB: { 157735811Smarc int c; 157835811Smarc 15797502Sroot if (tp->t_rocount < tp->t_rawq.c_cc) { 15807502Sroot ttyretype(tp); 15817502Sroot return; 15827502Sroot } 158317545Skarels s = spltty(); 15847502Sroot savecol = tp->t_col; 15859578Ssam tp->t_state |= TS_CNTTB; 158635811Smarc tp->t_lflag |= FLUSHO; 15877502Sroot tp->t_col = tp->t_rocol; 15889578Ssam cp = tp->t_rawq.c_cf; 158939407Smarc if (cp) 159039407Smarc c = *cp; /* XXX FIX NEXTC */ 159135811Smarc for (; cp; cp = nextc(&tp->t_rawq, cp, &c)) 159235811Smarc ttyecho(c, tp); 159335811Smarc tp->t_lflag &= ~FLUSHO; 15949578Ssam tp->t_state &= ~TS_CNTTB; 15957502Sroot splx(s); 15967502Sroot /* 15977502Sroot * savecol will now be length of the tab 15987502Sroot */ 15997502Sroot savecol -= tp->t_col; 16007502Sroot tp->t_col += savecol; 16017502Sroot if (savecol > 8) 16027502Sroot savecol = 8; /* overflow screw */ 16037502Sroot while (--savecol >= 0) 16047502Sroot (void) ttyoutput('\b', tp); 16057502Sroot break; 160635811Smarc } 16077502Sroot 16087502Sroot default: 160937584Smarc /* XXX */ 161035811Smarc printf("ttyrub: would panic c = %d, val = %d\n", 161135811Smarc c, partab[c&=0377]&077); 161235811Smarc /*panic("ttyrub");*/ 16137502Sroot } 161435811Smarc } else if (tp->t_lflag&ECHOPRT) { 16159578Ssam if ((tp->t_state&TS_ERASE) == 0) { 16167502Sroot (void) ttyoutput('\\', tp); 16179578Ssam tp->t_state |= TS_ERASE; 16187502Sroot } 16197502Sroot ttyecho(c, tp); 16207502Sroot } else 162135811Smarc ttyecho(tp->t_cc[VERASE], tp); 16227502Sroot tp->t_rocount--; 16237502Sroot } 16247502Sroot 16257502Sroot /* 16267502Sroot * Crt back over cnt chars perhaps 16277502Sroot * erasing them. 16287502Sroot */ 16297502Sroot ttyrubo(tp, cnt) 16307625Ssam register struct tty *tp; 16317625Ssam int cnt; 16327502Sroot { 16337502Sroot 16347502Sroot while (--cnt >= 0) 163540712Skarels ttyoutstr("\b \b", tp); 16367502Sroot } 16377502Sroot 16387502Sroot /* 16397502Sroot * Reprint the rawq line. 16407502Sroot * We assume c_cc has already been checked. 16417502Sroot */ 16427502Sroot ttyretype(tp) 16437625Ssam register struct tty *tp; 16447502Sroot { 16457502Sroot register char *cp; 16467502Sroot char *nextc(); 164735811Smarc int s, c; 16487502Sroot 164935811Smarc if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) 165035811Smarc ttyecho(tp->t_cc[VREPRINT], tp); 16517502Sroot (void) ttyoutput('\n', tp); 165217545Skarels s = spltty(); 165335811Smarc /*** XXX *** FIX *** NEXTC IS BROKEN - DOESN'T CHECK QUOTE 165435811Smarc BIT OF FIRST CHAR ****/ 165535811Smarc for (cp = tp->t_canq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_canq, cp, &c)) { 165635811Smarc ttyecho(c, tp); 165735811Smarc } 165835811Smarc for (cp = tp->t_rawq.c_cf, c=(cp?*cp:0); cp; cp = nextc(&tp->t_rawq, cp, &c)) { 165935811Smarc ttyecho(c, tp); 166035811Smarc } 16619578Ssam tp->t_state &= ~TS_ERASE; 16627502Sroot splx(s); 16637502Sroot tp->t_rocount = tp->t_rawq.c_cc; 16647502Sroot tp->t_rocol = 0; 16657502Sroot } 16667502Sroot 16677502Sroot /* 166835811Smarc * Echo a typed character to the terminal. 16697502Sroot */ 16707502Sroot ttyecho(c, tp) 16717625Ssam register c; 16727625Ssam register struct tty *tp; 16737502Sroot { 16749578Ssam if ((tp->t_state&TS_CNTTB) == 0) 167535811Smarc tp->t_lflag &= ~FLUSHO; 1676*42882Smarc if (((tp->t_lflag&ECHO) == 0 && ((tp->t_lflag&ECHONL) == 0 || 1677*42882Smarc c == '\n')) || (tp->t_lflag&EXTPROC)) 16787502Sroot return; 167935811Smarc if (tp->t_lflag&ECHOCTL) { 168040712Skarels if ((c&TTY_CHARMASK) <= 037 && c != '\t' && c != '\n' || 168140712Skarels c == 0177) { 16827502Sroot (void) ttyoutput('^', tp); 168335811Smarc c &= TTY_CHARMASK; 16847502Sroot if (c == 0177) 16857502Sroot c = '?'; 16867502Sroot else 16877502Sroot c += 'A' - 1; 16887502Sroot } 16897502Sroot } 169035811Smarc (void) ttyoutput(c, tp); 16917502Sroot } 16927502Sroot 16937502Sroot /* 16947502Sroot * send string cp to tp 16957502Sroot */ 169640712Skarels ttyoutstr(cp, tp) 16977625Ssam register char *cp; 16987625Ssam register struct tty *tp; 16997502Sroot { 17007502Sroot register char c; 17017502Sroot 17027502Sroot while (c = *cp++) 17037502Sroot (void) ttyoutput(c, tp); 17047502Sroot } 17057502Sroot 17067502Sroot ttwakeup(tp) 17077502Sroot struct tty *tp; 17087502Sroot { 17097502Sroot 17107502Sroot if (tp->t_rsel) { 17117502Sroot selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL); 17127502Sroot tp->t_state &= ~TS_RCOLL; 17137502Sroot tp->t_rsel = 0; 17147502Sroot } 171512752Ssam if (tp->t_state & TS_ASYNC) 1716*42882Smarc pgsignal(tp->t_pgrp, SIGIO, 1); 17177502Sroot wakeup((caddr_t)&tp->t_rawq); 17187502Sroot } 171935811Smarc 172035811Smarc /* 172135811Smarc * set tty hi and low water marks 172235811Smarc * 172335811Smarc * Try to arrange the dynamics so there's about one second 172435811Smarc * from hi to low water. 172535811Smarc * 172635811Smarc */ 172735811Smarc ttsetwater(tp) 172835811Smarc struct tty *tp; 172935811Smarc { 173035811Smarc register cps = tp->t_ospeed / 10; 173135811Smarc register x; 173235811Smarc 173335811Smarc #define clamp(x, h, l) ((x)>h ? h : ((x)<l) ? l : (x)) 173435811Smarc tp->t_lowat = x = clamp(cps/2, TTMAXLOWAT, TTMINLOWAT); 173535811Smarc x += cps; 173635811Smarc x = clamp(x, TTMAXHIWAT, TTMINHIWAT); 173735811Smarc tp->t_hiwat = roundup(x, CBSIZE); 173835811Smarc #undef clamp 173935811Smarc } 174035811Smarc 174135811Smarc ttspeedtab(speed, table) 174235811Smarc struct speedtab table[]; 174335811Smarc { 174435811Smarc register int i; 174535811Smarc 174635811Smarc for (i = 0; table[i].sp_speed != -1; i++) 174735811Smarc if (table[i].sp_speed == speed) 174835811Smarc return(table[i].sp_code); 174935811Smarc return(-1); 175035811Smarc } 175139407Smarc 175241177Smarc int ttyhostname = 0; 175339407Smarc /* 175439407Smarc * (^T) 175539407Smarc * Report on state of foreground process group. 175639407Smarc */ 175739407Smarc ttyinfo(tp) 175839407Smarc struct tty *tp; 175939407Smarc { 176041177Smarc register struct proc *p, *pick = NULL; 176141177Smarc register char *cp = hostname; 176241177Smarc int x, s; 176341177Smarc struct timeval utime, stime; 176442350Smckusick #define pgtok(a) (((a)*NBPG)/1024) 176539407Smarc 176639407Smarc if (ttycheckoutq(tp,0) == 0) 176739407Smarc return; 176841177Smarc /* 176941177Smarc * hostname 177041177Smarc */ 177141177Smarc if (ttyhostname) { 177241177Smarc if (*cp == '\0') 177341177Smarc ttyprintf(tp, "amnesia"); 177441177Smarc else 177541177Smarc while (*cp && *cp != '.') 177641177Smarc tputchar(*cp++, tp); 177741177Smarc tputchar(' '); 177841177Smarc } 177941177Smarc /* 178041177Smarc * load average 178141177Smarc */ 178241177Smarc x = (averunnable[0] * 100 + FSCALE/2) >> FSHIFT; 178341177Smarc ttyprintf(tp, "load: %d.", x/100); 178441177Smarc ttyoutint(x%100, 10, 2, tp); 178539555Smarc if (tp->t_session == NULL) 178641177Smarc ttyprintf(tp, " not a controlling terminal\n"); 178741177Smarc else if (tp->t_pgrp == NULL) 178841177Smarc ttyprintf(tp, " no foreground process group\n"); 178941177Smarc else if ((p = tp->t_pgrp->pg_mem) == NULL) 179041177Smarc ttyprintf(tp, " empty foreground process group\n"); 179139407Smarc else { 179241177Smarc /* pick interesting process */ 179339407Smarc for (; p != NULL; p = p->p_pgrpnxt) { 179441177Smarc if (proc_compare(pick, p)) 179541177Smarc pick = p; 179639407Smarc } 179741177Smarc ttyprintf(tp, " cmd: %s %d [%s] ", 179841177Smarc pick->p_comm, pick->p_pid, 179941177Smarc pick->p_wmesg ? pick->p_wmesg : "running"); 180041177Smarc /* 180141177Smarc * cpu time 180241177Smarc */ 180341177Smarc if (u.u_procp == pick) 180441177Smarc s = splclock(); 180541177Smarc utime = pick->p_utime; 180641177Smarc stime = pick->p_stime; 180741177Smarc if (u.u_procp == pick) 180841177Smarc splx(s); 180941177Smarc /* user time */ 181041177Smarc x = (utime.tv_usec + 5000) / 10000; /* scale to 100's */ 181141177Smarc ttyoutint(utime.tv_sec, 10, 1, tp); 181241177Smarc tputchar('.', tp); 181341177Smarc ttyoutint(x, 10, 2, tp); 181441177Smarc tputchar('u', tp); 181541177Smarc tputchar(' ', tp); 181641177Smarc /* system time */ 181741177Smarc x = (stime.tv_usec + 5000) / 10000; /* scale to 100's */ 181841177Smarc ttyoutint(stime.tv_sec, 10, 1, tp); 181941177Smarc tputchar('.', tp); 182041177Smarc ttyoutint(x, 10, 2, tp); 182141177Smarc tputchar('s', tp); 182241177Smarc tputchar(' ', tp); 182341177Smarc /* 182441177Smarc * pctcpu 182541177Smarc */ 182641177Smarc x = pick->p_pctcpu * 10000 + FSCALE/2 >> FSHIFT; 182741177Smarc ttyoutint(x/100, 10, 1, tp); 182841177Smarc #ifdef notdef /* do we really want this ??? */ 182941177Smarc tputchar('.', tp); 183041177Smarc ttyoutint(x%100, 10, 2, tp); 183141177Smarc #endif 183241177Smarc ttyprintf(tp, "%% %dk\n", pgtok(pick->p_ssize + pick->p_dsize)); 183339407Smarc } 183441177Smarc tp->t_rocount = 0; /* so pending input will be retyped if BS */ 183539407Smarc } 183639407Smarc 183741177Smarc ttyoutint(n, base, min, tp) 183841177Smarc register int n, base, min; 183941177Smarc register struct tty *tp; 184041177Smarc { 184141177Smarc char info[16]; 184241177Smarc register char *p = info; 184341177Smarc 184441177Smarc while (--min >= 0 || n) { 184541177Smarc *p++ = "0123456789abcdef"[n%base]; 184641177Smarc n /= base; 184741177Smarc } 184841177Smarc while (p > info) 184941177Smarc ttyoutput(*--p, tp); 185041177Smarc } 185141177Smarc 185241177Smarc /* 185341177Smarc * Returns 1 if p2 is "better" than p1 185441177Smarc * 185541177Smarc * The algorithm for picking the "interesting" process is thus: 185641177Smarc * 185741177Smarc * 1) (Only foreground processes are eligable - implied) 185841177Smarc * 2) Runnable processes are favored over anything 185941177Smarc * else. The runner with the highest cpu 186041177Smarc * utilization is picked (p_cpu). Ties are 186141177Smarc * broken by picking the highest pid. 186241177Smarc * 3 Next, the sleeper with the shortest sleep 186341177Smarc * time is favored. With ties, we pick out 186441177Smarc * just "short-term" sleepers (SSINTR == 0). 186541177Smarc * Further ties are broken by picking the highest 186641177Smarc * pid. 186741177Smarc * 186841177Smarc */ 186941177Smarc #define isrun(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL)) 187041177Smarc proc_compare(p1, p2) 187141177Smarc register struct proc *p1, *p2; 187241177Smarc { 187341177Smarc 187441177Smarc if (p1 == NULL) 187541177Smarc return (1); 187641177Smarc /* 187741177Smarc * see if at least one of them is runnable 187841177Smarc */ 187941177Smarc switch (isrun(p1)<<1 | isrun(p2)) { 188041177Smarc case 0x01: 188141177Smarc return (1); 188241177Smarc case 0x10: 188341177Smarc return (0); 188441177Smarc case 0x11: 188541177Smarc /* 188641177Smarc * tie - favor one with highest recent cpu utilization 188741177Smarc */ 188841177Smarc if (p2->p_cpu > p1->p_cpu) 188941177Smarc return (1); 189041177Smarc if (p1->p_cpu > p2->p_cpu) 189141177Smarc return (0); 189241177Smarc return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ 189341177Smarc } 189441177Smarc /* 189541177Smarc * pick the one with the smallest sleep time 189641177Smarc */ 189741177Smarc if (p2->p_slptime > p1->p_slptime) 189841177Smarc return (0); 189941177Smarc if (p1->p_slptime > p2->p_slptime) 190041177Smarc return (1); 190141177Smarc /* 190241177Smarc * favor one sleeping in a non-interruptible sleep 190341177Smarc */ 190441177Smarc if (p1->p_flag&SSINTR && (p2->p_flag&SSINTR) == 0) 190541177Smarc return (1); 190641177Smarc if (p2->p_flag&SSINTR && (p1->p_flag&SSINTR) == 0) 190741177Smarc return (0); 190841177Smarc return(p2->p_pid > p1->p_pid); /* tie - return highest pid */ 190941177Smarc } 191039407Smarc #define TOTTY 0x2 /* XXX should be in header */ 191139407Smarc /*VARARGS2*/ 191239407Smarc ttyprintf(tp, fmt, x1) 191339555Smarc struct tty *tp; 191439407Smarc char *fmt; 191539407Smarc unsigned x1; 191639407Smarc { 191739555Smarc prf(fmt, &x1, TOTTY, (caddr_t)tp); 191839407Smarc } 191939555Smarc 192039555Smarc /* 192139555Smarc * Output char to tty; console putchar style. 192239555Smarc */ 192339555Smarc tputchar(c, tp) 192439555Smarc int c; 192539555Smarc struct tty *tp; 192639555Smarc { 192739555Smarc register s = spltty(); 192839555Smarc 192939555Smarc if ((tp->t_state & (TS_CARR_ON | TS_ISOPEN)) 193039555Smarc == (TS_CARR_ON | TS_ISOPEN)) { 193139555Smarc if (c == '\n') 193239555Smarc (void) ttyoutput('\r', tp); 193339555Smarc (void) ttyoutput(c, tp); 193439555Smarc ttstart(tp); 193539555Smarc splx(s); 193639555Smarc return (0); 193739555Smarc } 193839555Smarc splx(s); 193939555Smarc return (-1); 194039555Smarc } 1941