38#include <sys/kernel.h>
39#include <sys/signal.h>
40#include <sys/sysctl.h>
43#include <sys/ttycom.h>
44#include <sys/ttydefaults.h>
55 &
tty_nin, 0,
"Total amount of bytes received");
58 &
tty_nout, 0,
"Total amount of bytes transmitted");
61#define CMP_CC(v,c) (tp->t_termios.c_cc[v] != _POSIX_VDISABLE && \
62 tp->t_termios.c_cc[v] == (c))
63#define CMP_FLAG(field,opt) (tp->t_termios.c_ ## field ## flag & (opt))
71#define CTL_VALID(c) ((c) == 0x7f || (unsigned char)(c) < 0x20)
73#define CTL_ECHO(c,q) (!(q) && ((c) == CERASE2 || (c) == CTAB || \
74 (c) == CNL || (c) == CCR))
76#define CTL_PRINT(c,q) ((c) == 0x7f || ((unsigned char)(c) < 0x20 && \
77 ((q) || ((c) != CTAB && (c) != CNL))))
79#define CTL_WHITE(c) ((c) == ' ' || (c) == CTAB)
81#define CTL_ALNUM(c) (((c) >= '0' && (c) <= '9') || \
82 ((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
84#define TTY_STACKBUF 256
97 tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE);
98 tp->t_termios.c_lflag &= ~FLUSHO;
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_assert_locked(tp);
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) {
354static __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_assert_locked(tp);
464 if (tp->t_flags & TF_ZOMBIE)
473 while (uio->uio_resid > 0) {
479 uio->uio_offset += uio->uio_resid;
486 nlen = MIN(uio->uio_resid,
sizeof ob);
488 error =
uiomove(ob, nlen, uio);
503 unsigned int plen, wlen;
506 uio->uio_offset += uio->uio_resid;
527 tp->t_writepos = tp->t_column;
536 tp->t_column += wlen;
538 tp->t_writepos = tp->t_column;
546 tp->t_flags |= TF_HIWAT_OUT;
548 if (ioflag & IO_NDELAY) {
558 ttydevsw_outwakeup(tp);
559 if ((tp->t_flags & TF_HIWAT_OUT) == 0)
562 error =
tty_wait(tp, &tp->t_outwait);
566 if (tp->t_flags & TF_ZOMBIE) {
575 ttydevsw_outwakeup(tp);
582 uio->uio_resid += oblen;
589 tty_assert_locked(tp);
591 if (ttyhook_hashook(tp, rint_bypass)) {
592 tp->t_flags |= TF_BYPASS;
593 }
else if (ttyhook_hashook(tp, rint)) {
594 tp->t_flags &= ~TF_BYPASS;
595 }
else if (!
CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) &&
598 CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) &&
599 !
CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) {
600 tp->t_flags |= TF_BYPASS;
602 tp->t_flags &= ~TF_BYPASS;
610 tty_assert_locked(tp);
613 cv_broadcast(&tp->t_dcdwait);
621 if (!tty_opened(tp) ||
CMP_FLAG(c, CLOCAL))
628 tp->t_flags |= TF_ZOMBIE;
661 char ob[4] =
"^?\b\b";
667 if (!quote &&
CMP_CC(VEOF, c)) {
709 c = tp->t_termios.c_cc[VREPRINT];
710 if (c != _POSIX_VDISABLE)
727 struct tty *tp =
data->tp;
732 }
else if (c ==
CTAB) {
733 data->curlen += 8 - (
data->curlen & 7);
746 return (
data.curlen);
754 unsigned int prevpos, tablen;
766 if (
tp->t_writepos >=
tp->t_column) {
777 }
else if (c ==
' ') {
781 }
else if (c ==
CTAB) {
794 if (prevpos >=
tp->t_column)
797 tablen =
tp->t_column - prevpos;
801 tp->t_column = prevpos;
803 "\b\b\b\b\b\b\b\b", tablen);
857 int signal, quote = 0;
858 char ob[3] = { 0xff, 0x00 };
861 tty_assert_locked(
tp);
865 if (ttyhook_hashook(
tp, rint))
866 return ttyhook_rint(
tp, c,
flags);
868 if (
tp->t_flags & TF_BYPASS)
872 if (
flags & TRE_BREAK) {
885 }
else if (
flags & TRE_FRAMING ||
899 tp->t_flags &= ~TF_STOPPED;
900 tp->t_termios.c_lflag &= ~FLUSHO;
908 if (
tp->t_flags & TF_LITERAL) {
909 tp->t_flags &= ~TF_LITERAL;
924 tp->t_flags |= TF_LITERAL;
928 if (
CMP_CC(VDISCARD, c)) {
930 tp->t_termios.c_lflag &= ~FLUSHO;
934 if (
tp->t_inq.ti_end > 0)
936 tp->t_termios.c_lflag |= FLUSHO;
945 if (
CMP_FLAG(l, ICANON|IEXTEN) == (ICANON|IEXTEN)) {
961 }
else if (
CMP_CC(VQUIT, c)) {
963 }
else if (
CMP_CC(VSUSP, c)) {
986 if ((
tp->t_flags & TF_STOPPED) == 0) {
987 tp->t_flags |= TF_STOPPED;
999 tp->t_flags &= ~TF_STOPPED;
1023 }
else if (
CMP_CC(VKILL, c)) {
1027 if (
CMP_CC(VWERASE, c)) {
1030 }
else if (
CMP_CC(VREPRINT, c)) {
1038 if (
CMP_FLAG(i, PARMRK) && (
unsigned char)c == 0xff) {
1075 if (ttyinq_bytescanonicalized(&
tp->t_inq) == 0)
1102 if (ttydisc_can_bypass(
tp))
1105 for (cbuf =
buf; len-- > 0; cbuf++) {
1110 return (cbuf - (
const char *)
buf);
1118 tty_assert_locked(
tp);
1120 MPASS(
tp->t_flags & TF_BYPASS);
1122 atomic_add_long(&
tty_nin, len);
1124 if (ttyhook_hashook(
tp, rint_bypass))
1125 return ttyhook_rint_bypass(
tp,
buf, len);
1139 tty_assert_locked(
tp);
1141 if (ttyhook_hashook(
tp, rint_done))
1142 ttyhook_rint_done(
tp);
1147 ttydevsw_outwakeup(
tp);
1155 tty_assert_locked(
tp);
1157 if (ttyhook_hashook(
tp, rint_poll))
1158 return ttyhook_rint_poll(
tp);
1166 l = ttyinq_bytesleft(&
tp->t_inq);
1167 if (l == 0 && (
tp->t_flags & TF_HIWAT_IN) == 0)
1178 c = ttyoutq_bytesleft(&
tp->t_outq);
1179 if (
tp->t_flags & TF_HIWAT_OUT) {
1181 if (c < tp->t_outlow)
1185 tp->t_flags &= ~TF_HIWAT_OUT;
1198 tty_assert_locked(
tp);
1200 if (
tp->t_flags & TF_STOPPED)
1203 if (ttyhook_hashook(
tp, getc_inject))
1204 return ttyhook_getc_inject(
tp,
buf, len);
1208 if (ttyhook_hashook(
tp, getc_capture))
1209 ttyhook_getc_capture(
tp,
buf, len);
1221 ssize_t obytes = uio->uio_resid;
1225 tty_assert_locked(
tp);
1227 if (
tp->t_flags & TF_STOPPED)
1235 if (ttyhook_hashook(
tp, getc_capture) ||
1236 ttyhook_hashook(
tp, getc_inject)) {
1237 while (uio->uio_resid > 0) {
1240 MIN(uio->uio_resid,
sizeof buf));
1256 atomic_add_long(&
tty_nout, obytes - uio->uio_resid);
1266 tty_assert_locked(
tp);
1268 if (
tp->t_flags & TF_STOPPED)
1271 if (ttyhook_hashook(
tp, getc_poll))
1272 return ttyhook_getc_poll(
tp);
1274 return ttyoutq_bytesused(&
tp->t_outq);
1288 tty_assert_locked(
tp);
1293 for (i = 0; i < n; i++)
1296 tp->t_writepos =
tp->t_column;
1299 ttydevsw_outwakeup(
tp);
int tvtohz(struct timeval *tv)
void getmicrotime(struct timeval *tvp)
void timevaladd(struct timeval *t1, const struct timeval *t2)
void timevalsub(struct timeval *t1, const struct timeval *t2)
int uiomove(void *cp, int n, struct uio *uio)
void tty_hiwat_in_block(struct tty *tp)
int tty_wait(struct tty *tp, struct cv *cv)
int tty_timedwait(struct tty *tp, struct cv *cv, int hz)
int tty_wait_background(struct tty *tp, struct thread *td, int sig)
void tty_flush(struct tty *tp, int flags)
void tty_signal_pgrp(struct tty *tp, int sig)
void tty_signal_sessleader(struct tty *tp, int sig)
void tty_hiwat_in_unblock(struct tty *tp)
void tty_wakeup(struct tty *tp, int flags)
void ttyinq_canonicalize(struct ttyinq *ti)
size_t ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
int ttyinq_peekchar(struct ttyinq *ti, char *c, int *quote)
int ttyinq_read_uio(struct ttyinq *ti, struct tty *tp, struct uio *uio, size_t rlen, size_t flen)
int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t nbytes, int quote)
void ttyinq_line_iterate_from_linestart(struct ttyinq *ti, ttyinq_line_iterator_t *iterator, void *data)
void ttyinq_reprintpos_reset(struct ttyinq *ti)
void ttyinq_unputchar(struct ttyinq *ti)
void ttyinq_reprintpos_set(struct ttyinq *ti)
size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen, char *lastc)
void ttyinq_line_iterate_from_reprintpos(struct ttyinq *ti, ttyinq_line_iterator_t *iterator, void *data)
int ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t nbytes)
int ttyoutq_read_uio(struct ttyoutq *to, struct tty *tp, struct uio *uio)
size_t ttyoutq_read(struct ttyoutq *to, void *buf, size_t len)
size_t ttyoutq_write(struct ttyoutq *to, const void *buf, size_t nbytes)
static int ttydisc_rubchar(struct tty *tp)
size_t ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len)
void ttydisc_close(struct tty *tp)
static void ttydisc_recalc_charlength(void *d, char c, int quote)
static unsigned int ttydisc_recalc_linelength(struct tty *tp)
static __inline unsigned int ttydisc_findchar(const char *obstart, unsigned int oblen)
size_t ttydisc_getc_poll(struct tty *tp)
void ttydisc_modem(struct tty *tp, int open)
int tty_putstrn(struct tty *tp, const char *p, size_t n)
static int ttydisc_echo(struct tty *tp, char c, int quote)
int ttydisc_rint(struct tty *tp, char c, int flags)
static int ttydisc_read_raw_read_timer(struct tty *tp, struct uio *uio, int ioflag, int oresid)
static int ttydisc_write_oproc(struct tty *tp, char c)
static int ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag)
int ttydisc_getc_uio(struct tty *tp, struct uio *uio)
static int ttydisc_read_raw_interbyte_timer(struct tty *tp, struct uio *uio, int ioflag)
static void ttydisc_wakeup_watermark(struct tty *tp)
void ttydisc_optimize(struct tty *tp)
void ttydisc_open(struct tty *tp)
int ttydisc_read(struct tty *tp, struct uio *uio, int ioflag)
size_t ttydisc_rint_poll(struct tty *tp)
static int ttydisc_read_raw_no_timer(struct tty *tp, struct uio *uio, int ioflag)
static unsigned long tty_nout
#define CMP_FLAG(field, opt)
void ttydisc_rint_done(struct tty *tp)
static unsigned long tty_nin
size_t ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len)
static void ttydisc_rubword(struct tty *tp)
int tty_putchar(struct tty *tp, char c)
static void ttydisc_reprint(struct tty *tp)
static int ttydisc_echo_force(struct tty *tp, char c, int quote)
static void ttydisc_reprint_char(void *d, char c, int quote)
SYSCTL_ULONG(_kern, OID_AUTO, tty_nin, CTLFLAG_RD, &tty_nin, 0, "Total amount of bytes received")
size_t ttydisc_getc(struct tty *tp, void *buf, size_t len)
int ttydisc_write(struct tty *tp, struct uio *uio, int ioflag)