30 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/fcntl.h>
35 #include <sys/filio.h>
36 #include <sys/kernel.h>
37 #include <sys/signal.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
41 #include <sys/ttycom.h>
42 #include <sys/ttydefaults.h>
44 #include <sys/vnode.h>
53 &
tty_nin, 0,
"Total amount of bytes received");
56 &
tty_nout, 0,
"Total amount of bytes transmitted");
59 #define CMP_CC(v,c) (tp->t_termios.c_cc[v] != _POSIX_VDISABLE && \
60 tp->t_termios.c_cc[v] == (c))
61 #define CMP_FLAG(field,opt) (tp->t_termios.c_ ## field ## flag & (opt))
69 #define CTL_VALID(c) ((c) == 0x7f || (unsigned char)(c) < 0x20)
71 #define CTL_ECHO(c,q) (!(q) && ((c) == CERASE2 || (c) == CTAB || \
72 (c) == CNL || (c) == CCR))
74 #define CTL_PRINT(c,q) ((c) == 0x7f || ((unsigned char)(c) < 0x20 && \
75 ((q) || ((c) != CTAB && (c) != CNL))))
77 #define CTL_WHITE(c) ((c) == ' ' || (c) == CTAB)
79 #define CTL_ALNUM(c) (((c) >= '0' && (c) <= '9') || \
80 ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
82 #define TTY_STACKBUF 256
95 tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE);
102 ttydevsw_inwakeup(tp);
103 ttydevsw_outwakeup(tp);
106 if (ttyhook_hashook(tp, close))
113 char breakc[4] = {
CNL };
115 size_t clen, flen = 0, n = 1;
116 unsigned char lastc = _POSIX_VDISABLE;
118 #define BREAK_ADD(c) do { \
119 if (tp->t_termios.c_cc[c] != _POSIX_VDISABLE) \
120 breakc[n++] = tp->t_termios.c_cc[c]; \
156 if (tp->t_flags & TF_ZOMBIE)
158 else if (ioflag & IO_NDELAY)
159 return (EWOULDBLOCK);
161 error =
tty_wait(tp, &tp->t_inwait);
178 }
while (uio->uio_resid > 0 && lastc == _POSIX_VDISABLE);
186 size_t vmin = tp->t_termios.c_cc[VMIN];
187 ssize_t oresid = uio->uio_resid;
190 MPASS(tp->t_termios.c_cc[VTIME] == 0);
207 if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin)
211 if (tp->t_flags & TF_ZOMBIE)
213 else if (ioflag & IO_NDELAY)
214 return (EWOULDBLOCK);
216 error =
tty_wait(tp, &tp->t_inwait);
226 size_t vmin = MAX(tp->t_termios.c_cc[VMIN], 1);
227 unsigned int vtime = tp->t_termios.c_cc[VTIME];
228 struct timeval end, now, left;
231 MPASS(tp->t_termios.c_cc[VTIME] != 0);
234 end.tv_sec = vtime / 10;
235 end.tv_usec = (vtime % 10) * 100000;
248 if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin)
253 if (timevalcmp(&now, &end, >))
263 if (tp->t_flags & TF_ZOMBIE)
265 else if (ioflag & IO_NDELAY)
266 return (EWOULDBLOCK);
270 return (error == EWOULDBLOCK ? 0 : error);
279 size_t vmin = tp->t_termios.c_cc[VMIN];
280 ssize_t oresid = uio->uio_resid;
283 MPASS(tp->t_termios.c_cc[VMIN] != 0);
284 MPASS(tp->t_termios.c_cc[VTIME] != 0);
301 if (uio->uio_resid == 0 || (oresid - uio->uio_resid) >= vmin)
308 if (oresid != uio->uio_resid)
312 if (tp->t_flags & TF_ZOMBIE)
314 else if (ioflag & IO_NDELAY)
315 return (EWOULDBLOCK);
317 error =
tty_wait(tp, &tp->t_inwait);
330 tty_lock_assert(tp, MA_OWNED);
332 if (uio->uio_resid == 0)
337 else if (tp->t_termios.c_cc[VTIME] == 0)
339 else if (tp->t_termios.c_cc[VMIN] == 0)
345 if (ttyinq_bytesleft(&tp->t_inq) >= tp->t_inlow ||
346 ttyinq_bytescanonicalized(&tp->t_inq) == 0) {
354 static __inline
unsigned int
357 const char *c = obstart;
365 return (c - obstart);
371 unsigned int scnt, error;
376 #define PRINT_NORMAL() ttyoutq_write_nofrag(&tp->t_outq, &c, 1)
388 if (tp->t_column > 0)
394 scnt = 8 - (tp->t_column & 7);
404 tp->t_column += scnt;
405 MPASS((tp->t_column % 8) == 0);
420 tp->t_column = tp->t_writepos = 0;
430 if (
CMP_FLAG(o, ONOCR) && tp->t_column == 0)
435 tp->t_column = tp->t_writepos = 0;
460 unsigned int oblen = 0;
462 tty_lock_assert(tp, MA_OWNED);
464 if (tp->t_flags & TF_ZOMBIE)
473 while (uio->uio_resid > 0) {
480 nlen = MIN(uio->uio_resid,
sizeof ob);
482 error =
uiomove(ob, nlen, uio);
497 unsigned int plen, wlen;
515 tp->t_writepos = tp->t_column;
524 tp->t_column += wlen;
526 tp->t_writepos = tp->t_column;
534 tp->t_flags |= TF_HIWAT_OUT;
536 if (ioflag & IO_NDELAY) {
546 ttydevsw_outwakeup(tp);
547 if ((tp->t_flags & TF_HIWAT_OUT) == 0)
550 error =
tty_wait(tp, &tp->t_outwait);
554 if (tp->t_flags & TF_ZOMBIE) {
563 ttydevsw_outwakeup(tp);
570 uio->uio_resid += oblen;
577 tty_lock_assert(tp, MA_OWNED);
579 if (ttyhook_hashook(tp, rint_bypass)) {
580 tp->t_flags |= TF_BYPASS;
581 }
else if (ttyhook_hashook(tp, rint)) {
582 tp->t_flags &= ~TF_BYPASS;
583 }
else if (!
CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) &&
586 CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) &&
587 !
CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) {
588 tp->t_flags |= TF_BYPASS;
590 tp->t_flags &= ~TF_BYPASS;
598 tty_lock_assert(tp, MA_OWNED);
601 cv_broadcast(&tp->t_dcdwait);
609 if (!tty_opened(tp) ||
CMP_FLAG(c, CLOCAL))
616 tp->t_flags |= TF_ZOMBIE;
646 char ob[4] =
"^?\b\b";
652 if (!quote &&
CMP_CC(VEOF, c)) {
695 c = tp->t_termios.c_cc[VREPRINT];
696 if (c != _POSIX_VDISABLE)
713 struct tty *tp = data->
tp;
718 }
else if (c ==
CTAB) {
740 unsigned int prevpos, tablen;
752 if (tp->t_writepos >= tp->t_column) {
763 }
else if (c ==
' ') {
767 }
else if (c ==
CTAB) {
780 if (prevpos >= tp->t_column)
783 tablen = tp->t_column - prevpos;
787 tp->t_column = prevpos;
789 "\b\b\b\b\b\b\b\b", tablen);
843 int signal, quote = 0;
844 char ob[3] = { 0xff, 0x00 };
847 tty_lock_assert(tp, MA_OWNED);
851 if (ttyhook_hashook(tp, rint))
852 return ttyhook_rint(tp, c, flags);
854 if (tp->t_flags & TF_BYPASS)
858 if (flags & TRE_BREAK) {
871 }
else if (flags & TRE_FRAMING ||
872 (flags & TRE_PARITY &&
CMP_FLAG(i, INPCK))) {
885 tp->t_flags &= ~TF_STOPPED;
892 if (tp->t_flags & TF_LITERAL) {
893 tp->t_flags &= ~TF_LITERAL;
908 tp->t_flags |= TF_LITERAL;
917 if (
CMP_FLAG(l, ICANON|IEXTEN) == (ICANON|IEXTEN)) {
933 }
else if (
CMP_CC(VQUIT, c)) {
935 }
else if (
CMP_CC(VSUSP, c)) {
958 if ((tp->t_flags & TF_STOPPED) == 0) {
959 tp->t_flags |= TF_STOPPED;
971 tp->t_flags &= ~TF_STOPPED;
995 }
else if (
CMP_CC(VKILL, c)) {
1002 }
else if (
CMP_CC(VREPRINT, c)) {
1010 if (
CMP_FLAG(i, PARMRK) && (
unsigned char)c == 0xff) {
1047 if (ttyinq_bytescanonicalized(&tp->t_inq) == 0)
1074 if (ttydisc_can_bypass(tp))
1077 for (cbuf = buf; len-- > 0; cbuf++) {
1082 return (cbuf - (
const char *)buf);
1090 tty_lock_assert(tp, MA_OWNED);
1092 MPASS(tp->t_flags & TF_BYPASS);
1094 atomic_add_long(&
tty_nin, len);
1096 if (ttyhook_hashook(tp, rint_bypass))
1097 return ttyhook_rint_bypass(tp, buf, len);
1111 tty_lock_assert(tp, MA_OWNED);
1113 if (ttyhook_hashook(tp, rint_done))
1114 ttyhook_rint_done(tp);
1119 ttydevsw_outwakeup(tp);
1127 tty_lock_assert(tp, MA_OWNED);
1129 if (ttyhook_hashook(tp, rint_poll))
1130 return ttyhook_rint_poll(tp);
1138 l = ttyinq_bytesleft(&tp->t_inq);
1139 if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0)
1150 c = ttyoutq_bytesleft(&tp->t_outq);
1151 if (tp->t_flags & TF_HIWAT_OUT) {
1153 if (c < tp->t_outlow)
1157 tp->t_flags &= ~TF_HIWAT_OUT;
1170 tty_lock_assert(tp, MA_OWNED);
1172 if (tp->t_flags & TF_STOPPED)
1175 if (ttyhook_hashook(tp, getc_inject))
1176 return ttyhook_getc_inject(tp, buf, len);
1180 if (ttyhook_hashook(tp, getc_capture))
1181 ttyhook_getc_capture(tp, buf, len);
1193 ssize_t obytes = uio->uio_resid;
1197 tty_lock_assert(tp, MA_OWNED);
1199 if (tp->t_flags & TF_STOPPED)
1207 if (ttyhook_hashook(tp, getc_capture) ||
1208 ttyhook_hashook(tp, getc_inject)) {
1209 while (uio->uio_resid > 0) {
1212 MIN(uio->uio_resid,
sizeof buf));
1218 error =
uiomove(buf, len, uio);
1228 atomic_add_long(&
tty_nout, obytes - uio->uio_resid);
1238 tty_lock_assert(tp, MA_OWNED);
1240 if (tp->t_flags & TF_STOPPED)
1243 if (ttyhook_hashook(tp, getc_poll))
1244 return ttyhook_getc_poll(tp);
1246 return ttyoutq_bytesused(&tp->t_outq);
1258 tty_lock_assert(tp, MA_OWNED);
1264 tp->t_writepos = tp->t_column;
1267 ttydevsw_outwakeup(tp);
static int ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag)
#define CMP_FLAG(field, opt)
int tvtohz(struct timeval *tv)
void ttyinq_line_iterate_from_reprintpos(struct ttyinq *ti, ttyinq_line_iterator_t *iterator, void *data)
void tty_hiwat_in_unblock(struct tty *tp)
static void ttydisc_rubword(struct tty *tp)
static void ttydisc_recalc_charlength(void *d, char c, int quote)
void ttyinq_flush(struct ttyinq *ti)
static int ttydisc_write_oproc(struct tty *tp, char c)
int ttydisc_read(struct tty *tp, struct uio *uio, int ioflag)
size_t ttyoutq_write(struct ttyoutq *to, const void *buf, size_t nbytes)
int ttyinq_peekchar(struct ttyinq *ti, char *c, int *quote)
void ttyinq_canonicalize(struct ttyinq *ti)
size_t ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len)
static int ttydisc_read_raw_interbyte_timer(struct tty *tp, struct uio *uio, int ioflag)
void ttyinq_reprintpos_reset(struct ttyinq *ti)
void ttydisc_optimize(struct tty *tp)
void ttydisc_close(struct tty *tp)
static int ttydisc_read_raw_read_timer(struct tty *tp, struct uio *uio, int ioflag, int oresid)
void ttyinq_unputchar(struct ttyinq *ti)
void ttydisc_rint_done(struct tty *tp)
static void ttydisc_reprint(struct tty *tp)
void ttydisc_modem(struct tty *tp, int open)
void timevalsub(struct timeval *t1, const struct timeval *t2)
static unsigned long tty_nout
size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen, char *lastc)
void tty_wakeup(struct tty *tp, int flags)
int tty_wait(struct tty *tp, struct cv *cv)
void tty_signal_sessleader(struct tty *tp, int sig)
static __inline unsigned int ttydisc_findchar(const char *obstart, unsigned int oblen)
size_t ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len)
void tty_flush(struct tty *tp, int flags)
size_t ttydisc_getc_poll(struct tty *tp)
size_t ttyoutq_read(struct ttyoutq *to, void *buf, size_t len)
static unsigned int ttydisc_recalc_linelength(struct tty *tp)
int tty_timedwait(struct tty *tp, struct cv *cv, int hz)
void timevaladd(struct timeval *t1, const struct timeval *t2)
static void ttydisc_wakeup_watermark(struct tty *tp)
int tty_putchar(struct tty *tp, char c)
void getmicrotime(struct timeval *tvp)
void ttyinq_reprintpos_set(struct ttyinq *ti)
int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
int ttydisc_rint(struct tty *tp, char c, int flags)
size_t ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
int ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
void tty_hiwat_in_block(struct tty *tp)
int uiomove(void *cp, int n, struct uio *uio)
size_t ttydisc_getc(struct tty *tp, void *buf, size_t len)
size_t ttydisc_rint_poll(struct tty *tp)
void ttyoutq_flush(struct ttyoutq *to)
int tty_wait_background(struct tty *tp, struct thread *td, int sig)
static int ttydisc_rubchar(struct tty *tp)
SYSCTL_ULONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD,&tty_nin, 0,"Total amount of bytes received")
int ttydisc_getc_uio(struct tty *tp, struct uio *uio)
static int ttydisc_echo_force(struct tty *tp, char c, int quote)
int ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio, size_t rlen, size_t flen)
static int ttydisc_read_raw_no_timer(struct tty *tp, struct uio *uio, int ioflag)
int ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t nbytes)
static unsigned long tty_nin
static int ttydisc_echo(struct tty *tp, char c, int quote)
int ttydisc_write(struct tty *tp, struct uio *uio, int ioflag)
static void ttydisc_reprint_char(void *d, char c, int quote)
void tty_signal_pgrp(struct tty *tp, int sig)
void ttyinq_line_iterate_from_linestart(struct ttyinq *ti, ttyinq_line_iterator_t *iterator, void *data)
void ttydisc_open(struct tty *tp)