Terminals 1293
When changing terminal attributes with tcsetattr(), the optional_actions argument
determines when the change takes effect. This argument is specified as one of the
following values:
TCSANOW
The change is carried out immediately.
TCSADRAIN
The change takes effect after all currently queued output has been trans-
mitted to the terminal. Normally, this flag should be specified when making
changes that affect terminal output, so that we don’t affect output that has
already been queued but not yet displayed.
TCSAFLUSH
The change takes effect as for TCSADRAIN, but, in addition, any input that is
still pending at the time the change takes effect is discarded. This is useful,
for example, when reading a password, where we wish to disable terminal
echoing and prevent user type-ahead.
The usual (and recommended) way to change terminal attributes is to use tcgetattr()
to retrieve a termios structure containing a copy of the current settings, change the
desired attributes, and then use tcsetattr() to push the updated structure back to the
driver. (This approach ensures that we pass a fully initialized structure to tcsetattr().)
For example, we can use the following sequence to turn terminal echoing off:
struct termios tp;
if (tcgetattr(STDIN_FILENO, &tp) == -1)
errExit("tcgetattr");
tp.c_lflag &= ~ECHO;
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tp) == -1)
errExit("tcsetattr");
The tcsetattr() function returns successfully if any of the requested changes to terminal
attributes could be performed; it fails only if none of the requested changes could
be made. This means that, when making multiple attribute changes, it may some-
times be necessary to make a further call to tcgetattr() to retrieve the new terminal
attributes and compare them against the requested changes.
In Section 34.7.2, we noted that if tcsetattr() is called from a process in a back-
ground process group, then the terminal driver suspends the process group by
delivering a SIGTTOU signal, and that, if called from an orphaned process group,
tcsetattr() fails with the error EIO. The same statements apply for various other
functions described in this chapter, including tcflush(), tcflow(), tcsendbreak(),
and tcdrain().
In earlier UNIX implementations, terminal attributes were accessed using
ioctl() calls. Like several other functions described in this chapter, the tcgetattr() and
tcsetattr() functions are POSIX inventions designed to address the problem that
type checking of the third argument of ioctl() isn’t possible. On Linux, as in many
other UNIX implementations, these are library functions layered on top of ioctl().