Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144512284
D43456.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D43456.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D43456: kern: tty: recanonicalize the buffer on ICANON/VEOF/VEOL changes
Attached
Detach File
Event Timeline
Log In to Comment