From 5b6a3335cac79730d20860b3b9aa5738d0c40377 Mon Sep 17 00:00:00 2001 From: "Joshua M. Clulow" <jmc@oxide.computer> Date: Sat, 4 Apr 2020 09:53:26 -0700 Subject: [PATCH] fix cfmakeraw() for illumos and Solaris This change fixes two issues. First, the current cfmakeraw() implementation in this crate appears to be making a stack copy of the input "struct termios" before modifying it, rather than correctly modifying the original through the pointer. Before this modification the routine did not, thus, set the flags for raw mode. Second, we address the default settings of the MIN and TIME terminal options. On at least FreeBSD and Linux systems, the modern default value for MIN appears to be 1; i.e., block and wait for at least one input byte. On most Solaris and illumos systems, the MIN control character slot overlaps with EOF, and thus has a default value of 4. This breaks at least the examples in the "termion" crate, and probably quite a lot of other software written first and foremost for Linux systems. We need to force the MIN value to 1 while switching to raw mode. --- src/unix/solarish/compat.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/unix/solarish/compat.rs b/src/unix/solarish/compat.rs index a3364521..610dd109 100644 --- a/src/unix/solarish/compat.rs +++ b/src/unix/solarish/compat.rs @@ -4,8 +4,7 @@ use unix::solarish::*; pub unsafe fn cfmakeraw(termios: *mut ::termios) { - let mut t = *termios as ::termios; - t.c_iflag &= !(IMAXBEL + (*termios).c_iflag &= !(IMAXBEL | IGNBRK | BRKINT | PARMRK @@ -14,10 +13,26 @@ pub unsafe fn cfmakeraw(termios: *mut ::termios) { | IGNCR | ICRNL | IXON); - t.c_oflag &= !OPOST; - t.c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - t.c_cflag &= !(CSIZE | PARENB); - t.c_cflag |= CS8; + (*termios).c_oflag &= !OPOST; + (*termios).c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + (*termios).c_cflag &= !(CSIZE | PARENB); + (*termios).c_cflag |= CS8; + + // By default, most software expects a pending read to block until at + // least one byte becomes available. As per termio(7I), this requires + // setting the MIN and TIME parameters appropriately. + // + // As a somewhat unfortunate artefact of history, the MIN and TIME slots + // in the control character array overlap with the EOF and EOL slots used + // for canonical mode processing. Because the EOF character needs to be + // the ASCII EOT value (aka Control-D), it has the byte value 4. When + // switching to raw mode, this is interpreted as a MIN value of 4; i.e., + // reads will block until at least four bytes have been input. + // + // Other platforms with a distinct MIN slot like Linux and FreeBSD appear + // to default to a MIN value of 1, so we'll force that value here: + (*termios).c_cc[VMIN] = 1; + (*termios).c_cc[VTIME] = 0; } pub unsafe fn cfsetspeed( -- GitLab