Page MenuHomeFreeBSD

D43378.id132772.diff
No OneTemporary

D43378.id132772.diff

diff --git a/sys/kern/tty.c b/sys/kern/tty.c
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1673,7 +1673,7 @@
/* This device supports non-blocking operation. */
return (0);
case FIONREAD:
- *(int *)data = ttyinq_bytescanonicalized(&tp->t_inq);
+ *(int *)data = ttydisc_bytesavail(tp);
return (0);
case FIONWRITE:
case TIOCOUTQ:
diff --git a/sys/kern/tty_ttydisc.c b/sys/kern/tty_ttydisc.c
--- a/sys/kern/tty_ttydisc.c
+++ b/sys/kern/tty_ttydisc.c
@@ -112,15 +112,20 @@
ttyhook_close(tp);
}
-static int
-ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag)
+/*
+ * Populate our break array; it should likely be at least 4 bytes in size to
+ * allow for \n, VEOF, and VEOL.
+ */
+static void
+ttydisc_read_break(struct tty *tp, char *breakc, size_t breaksz)
{
- char breakc[4] = { CNL }; /* enough to hold \n, VEOF and VEOL. */
- int error;
- size_t clen, flen = 0, n = 1;
- unsigned char lastc = _POSIX_VDISABLE;
+ size_t n = 0;
+ MPASS(breaksz != 0);
+
+ breakc[n++] = CNL;
#define BREAK_ADD(c) do { \
+ MPASS(n < breaksz - 1); /* NUL terminated */ \
if (tp->t_termios.c_cc[c] != _POSIX_VDISABLE) \
breakc[n++] = tp->t_termios.c_cc[c]; \
} while (0)
@@ -128,7 +133,48 @@
BREAK_ADD(VEOF);
BREAK_ADD(VEOL);
#undef BREAK_ADD
+
breakc[n] = '\0';
+}
+
+size_t
+ttydisc_bytesavail(struct tty *tp)
+{
+ size_t clen;
+ char breakc[4];
+ unsigned char lastc = _POSIX_VDISABLE;
+
+ clen = ttyinq_bytescanonicalized(&tp->t_inq);
+ if (!CMP_FLAG(l, ICANON) || clen == 0)
+ return (clen);
+
+ ttydisc_read_break(tp, &breakc[0], sizeof(breakc));
+ clen = ttyinq_findchar(&tp->t_inq, breakc, clen, &lastc);
+
+ /*
+ * We might have a partial line canonicalized in the input queue if we,
+ * for instance, switched to ICANON after taking some input in raw mode.
+ * In this case, read(2) will block because we only have a partial line.
+ */
+ if (lastc == _POSIX_VDISABLE)
+ return (0);
+
+ /* If VEOF was our terminal, it must be discarded (not counted). */
+ if (CMP_CC(VEOF, lastc))
+ clen--;
+
+ return (clen);
+}
+
+static int
+ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag)
+{
+ char breakc[4]; /* enough to hold \n, VEOF and VEOL. */
+ int error;
+ size_t clen, flen = 0;
+ unsigned char lastc = _POSIX_VDISABLE;
+
+ ttydisc_read_break(tp, &breakc[0], sizeof(breakc));
do {
error = tty_wait_background(tp, curthread, SIGTTIN);
@@ -153,7 +199,7 @@
* cause the TTY layer to return data in chunks using
* the blocksize (except the first and last blocks).
*/
- clen = ttyinq_findchar(&tp->t_inq, breakc, uio->uio_resid,
+ clen = ttyinq_findchar(&tp->t_inq, breakc, uio->uio_resid + 1,
&lastc);
/* No more data. */
@@ -169,10 +215,20 @@
continue;
}
- /* Don't send the EOF char back to userspace. */
+ /*
+ * Don't send the EOF char back to userspace. Our above call to
+ * ttyinq_findchar overreads by 1 character in case we would
+ * otherwise be leaving an EOF for the next read(). We'll trim
+ * clen back down to uio_resid whether we find our EOF or not.
+ */
if (CMP_CC(VEOF, lastc))
flen = 1;
+ /*
+ * Trim clen back down to the buffer size, since we had
+ * intentionally over-read.
+ */
+ clen = MIN(uio->uio_resid + flen, clen);
MPASS(flen <= clen);
/* Read and throw away the EOF character. */
diff --git a/sys/sys/ttydisc.h b/sys/sys/ttydisc.h
--- a/sys/sys/ttydisc.h
+++ b/sys/sys/ttydisc.h
@@ -44,6 +44,7 @@
/* Top half routines. */
void ttydisc_open(struct tty *tp);
void ttydisc_close(struct tty *tp);
+size_t ttydisc_bytesavail(struct tty *tp);
int ttydisc_read(struct tty *tp, struct uio *uio, int ioflag);
int ttydisc_write(struct tty *tp, struct uio *uio, int ioflag);
void ttydisc_optimize(struct tty *tp);

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 28, 5:48 AM (8 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28063661
Default Alt Text
D43378.id132772.diff (3 KB)

Event Timeline