Page MenuHomeFreeBSD

D43456.diff
No OneTemporary

D43456.diff

diff --git a/sys/kern/tty.c b/sys/kern/tty.c
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1705,6 +1705,7 @@
case TIOCSETAW:
case TIOCSETAF: {
struct termios *t = data;
+ bool canonicalize = false;
/*
* Who makes up these funny rules? According to POSIX,
@@ -1754,6 +1755,19 @@
return (error);
}
+ /*
+ * We'll canonicalize any partial input if we're transitioning
+ * ICANON one way or the other. If we're going from -ICANON ->
+ * ICANON, then in the worst case scenario we're in the middle
+ * of a line but both ttydisc_read() and FIONREAD will search
+ * for one of our line terminals.
+ */
+ if ((t->c_lflag & ICANON) != (tp->t_termios.c_lflag & ICANON))
+ canonicalize = true;
+ else if (tp->t_termios.c_cc[VEOF] != t->c_cc[VEOF] ||
+ tp->t_termios.c_cc[VEOL] != t->c_cc[VEOL])
+ canonicalize = true;
+
/* Copy new non-device driver parameters. */
tp->t_termios.c_iflag = t->c_iflag;
tp->t_termios.c_oflag = t->c_oflag;
@@ -1762,13 +1776,15 @@
ttydisc_optimize(tp);
+ if (canonicalize)
+ ttydisc_canonicalize(tp);
if ((t->c_lflag & ICANON) == 0) {
/*
* When in non-canonical mode, wake up all
- * readers. Canonicalize any partial input. VMIN
- * and VTIME could also be adjusted.
+ * readers. Any partial input has already been
+ * canonicalized above if we were in canonical mode.
+ * VMIN and VTIME could also be adjusted.
*/
- ttyinq_canonicalize(&tp->t_inq);
tty_wakeup(tp, FREAD);
}
diff --git a/sys/kern/tty_inq.c b/sys/kern/tty_inq.c
--- a/sys/kern/tty_inq.c
+++ b/sys/kern/tty_inq.c
@@ -354,6 +354,55 @@
ti->ti_startblock = ti->ti_reprintblock = ti->ti_lastblock;
}
+/*
+ * Canonicalize at one of the break characters; we'll work backwards from the
+ * lastblock to firstblock to try and find the latest one.
+ */
+void
+ttyinq_canonicalize_break(struct ttyinq *ti, const char *breakc)
+{
+ struct ttyinq_block *tib = ti->ti_lastblock;
+ unsigned int canon, off;
+ unsigned int boff;
+
+ /* No block, no change needed. */
+ if (tib == NULL || ti->ti_end == 0)
+ return;
+
+ /* Start just past the end... */
+ off = ti->ti_end;
+ canon = 0;
+
+ while (off > 0) {
+ if ((off % TTYINQ_DATASIZE) == 0)
+ tib = tib->tib_prev;
+
+ off--;
+ boff = off % TTYINQ_DATASIZE;
+
+ if (strchr(breakc, tib->tib_data[boff]) && !GETBIT(tib, boff)) {
+ canon = off + 1;
+ break;
+ }
+ }
+
+ MPASS(canon > 0 || off == 0);
+
+ /*
+ * We should only be able to hit bcanon == 0 if we walked everything we
+ * have and didn't find any of the break characters, so if bcanon == 0
+ * then tib is already the correct block and we should avoid touching
+ * it.
+ *
+ * For all other scenarios, if canon lies on a block boundary then tib
+ * has already advanced to the previous block.
+ */
+ if (canon != 0 && (canon % TTYINQ_DATASIZE) == 0)
+ tib = tib->tib_next;
+ ti->ti_linestart = ti->ti_reprint = canon;
+ ti->ti_startblock = ti->ti_reprintblock = tib;
+}
+
size_t
ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen,
char *lastc)
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
@@ -166,6 +166,28 @@
return (clen);
}
+void
+ttydisc_canonicalize(struct tty *tp)
+{
+ char breakc[4];
+
+ /*
+ * If we're in non-canonical mode, it's as easy as just canonicalizing
+ * the current partial line.
+ */
+ if (!CMP_FLAG(l, ICANON)) {
+ ttyinq_canonicalize(&tp->t_inq);
+ return;
+ }
+
+ /*
+ * For canonical mode, we need to rescan the buffer for the last EOL
+ * indicator.
+ */
+ ttydisc_read_break(tp, &breakc[0], sizeof(breakc));
+ ttyinq_canonicalize_break(&tp->t_inq, breakc);
+}
+
static int
ttydisc_read_canonical(struct tty *tp, struct uio *uio, int ioflag)
{
diff --git a/sys/sys/ttydisc.h b/sys/sys/ttydisc.h
--- a/sys/sys/ttydisc.h
+++ b/sys/sys/ttydisc.h
@@ -47,6 +47,7 @@
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_canonicalize(struct tty *tp);
void ttydisc_optimize(struct tty *tp);
/* Bottom half routines. */
diff --git a/sys/sys/ttyqueue.h b/sys/sys/ttyqueue.h
--- a/sys/sys/ttyqueue.h
+++ b/sys/sys/ttyqueue.h
@@ -78,6 +78,7 @@
int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t len,
int quote);
void ttyinq_canonicalize(struct ttyinq *ti);
+void ttyinq_canonicalize_break(struct ttyinq *ti, const char *breakc);
size_t ttyinq_findchar(struct ttyinq *ti, const char *breakc, size_t maxlen,
char *lastc);
void ttyinq_flush(struct ttyinq *ti);

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 10, 1:08 AM (10 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28608925
Default Alt Text
D43456.diff (4 KB)

Event Timeline