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.
This commit is contained in:
Joshua M. Clulow 2020-04-04 09:53:26 -07:00
parent 08e8a3ae8f
commit 5b6a3335ca
1 changed files with 21 additions and 6 deletions

View File

@ -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(