What goes into the terminal's 'cbreak' and 'raw' modes
Recently, Eevee tweeted:
things i never thought i'd need to know: the difference between 'raw' and 'cbreak' is not just some flag. it's like 20! [link]
This inspires me to talk about what 'cbreak' and 'raw' modes are, both at a high level and then at the low level of exactly what terminal settings go into each mode.
The traditional 'raw' mode is the easier one to explain; it does no
in-kernel processing of input or output at all. All characters are
returned immediately when typed and all output is produced as-is. The
traditional 'cbreak' mode is used for things like password entry;
it returns characters immediately as they're typed, doesn't echo
characters, and doesn't do any in-kernel line editing (which mostly means
that your program can actually see the various editing characters).
At a high level, there are two major differences between 'cbreak' and
'raw'. First, cbreak leaves output handling unchanged, which may be
relatively 'cooked'. Second, cbreak still allows you to interrupt the
program with ^C, suspend it, and so on. You can see this in action
with most programs (such as
sudo) that ask for a
password; you can immediately interrupt them with ^C in a way that, eg,
vi does not respond to.
The low-level settings for cbreak are:
ECHO; this stops typed characters from being echoed.
ICANON; this turns off line editing.
VMINto 1 and
VTIMEto 0; this makes it so that a
read()returns immediately once there's (at least) one character available.
This is about the minimum you can do to have anything like this so pretty much everyone is going to agree on them. The low-level settings for raw mode start with cbreak's changes and add a bunch more, but there can be some variation in exactly what settings get added; I'm going to use the Python version from eevee's link. This disables a bunch of additional tty options:
BRKINT: serial breaks are ignored and converted to null bytes. In the modern world where most ttys are pseudo-ttys instead of serial lines, this generally isn't going to make any difference.
ICRNL: with this disabled, carriage returns (
\r') are not turned into newlines (
\n') on input (normally you can't tell them apart and both will terminate the current line).
INPCK: input parity checking is disabled. Again, not an option that is relevant on pseudo-ttys.
IXON: with this disabled, ^S and ^Q do not pause and then restart output.
OPOST: disables any 'implementation-defined' output processing. On Linux (and probably many others) this is the setting that normally turns a newline into a CR-NL sequence.
PARENB: disables parity generation on output and apparently also parity checking on input, making it overlap a bit with
IEXTEN: disables extra additional input processing and line editing characters. Things like word erase were not part of the original Unix tty line editing, so they have to be enabled separately from the basic line editing characters that are covered by
ICANON. It's common for extended line editing to only be enabled only if both
(Unixes vary on what effect
IEXTENhas beyond enabling the additional line editing characters. Linux pretty much only uses it for that, but Solaris does additional stuff with it.)
ISIG: with this disabled, things like ^C do not generate interrupts when they're typed.
Raw mode also does stuff with
CSIZE, which is unusual because it's
a mask instead of a flag; it's the set of bits in one of the fields
that are used to determine the bitsize of characters. You mask off the
CSIZE bits first and then set one of the available settings of bits;
'raw' mode sets
CS8, for 8-bit characters.
(This is a little bit confusing in the Python code, which masks off the
CSIZE bits at the same time as it's disabling
Because Unix tty handling has a huge amount of historical baggage this collection of flags is split across four fields (input, output, 'control', and 'local'). Which field a flag is in is somewhat arbitrary and generally confusing.
(Update: as eevee notes, pretty much all
the detailed documentation you could ask for is in
Update, July 1st 2014: I've now noticed that I flipped ^J and ^M in my description of ICRNL. Oops. Fixed.