POSIX terminal interface
The POSIX terminal interface is the generalized abstraction, comprising both an Application Programming Interface for programs, and a set of behavioural expectations for users of a terminal, as defined by the POSIX standard and the Single Unix Specification. It is a historical development from the terminal interfaces of BSD version 4 and Seventh Edition Unix.
General underlying concepts
Hardware
A multiplicity of I/O devices are regarded as "terminals" in Unix systems. These include:- serial devices connected by a serial port such as printers/teleprinters, teletypewriters, modems supporting remote terminals via dial-up access, and directly-connected local terminals
- display adapter and keyboard hardware directly incorporated into the system unit, taken together to form a local "console", which may be presented to users and to programs as a single CRT terminal or as multiple virtual terminals
- software terminal emulators, such as the xterm, Konsole, GNOME Terminal, and Terminal programs, and network servers such as the rlogin daemon and the SSH daemon, which make use of pseudoterminals
Terminal intelligence and capabilities
Intelligence: terminals are dumb, not intelligent
Unlike its mainframe and minicomputer contemporaries, the original Unix system was developed solely for dumb terminals, and that remains the case today. A terminal is a character-oriented device, comprising streams of characters received from and sent to the device. Although the streams of characters are structured, incorporating control characters, escape codes, and special characters, the I/O protocol is not structured as would be the I/O protocol of smart, or intelligent, terminals. There are no field format specifications. There's no block transmission of entire screens of input data.By contrast mainframes and minicomputers in closed architectures commonly use Block-oriented terminals.
Capabilities: terminfo, termcap, curses, et al.
The "capabilities" of a terminal comprise various dumb terminal features that are above and beyond what is available from a pure teletypewriter, which programs can make use of. They comprise escape codes that can be sent to or received from the terminal. The escape codes sent to the terminal perform various functions that a CRT terminal is capable of that a teletypewriter is not, such as moving the terminal's cursor to positions on the screen, clearing and scrolling all or parts of the screen, turning on and off attached printer devices, programmable function keys, changing display colours and attributes, and setting display title strings. The escape codes received from the terminal signify things such as function key, arrow key, and other special keystrokes.These capabilities are encoded in databases that are configured by a system administrator and accessed from programs via the terminfo library, upon which in turn are built libraries such as the curses and ncurses libraries. Application programs use the terminal capabilities to provide textual user interfaces with windows, dialogue boxes, buttons, labels, input fields, menus, and so forth.
Controlling environment variables: TERM
et al.
The particular set of capabilities for the terminal that a program's input and output uses is obtained from the database rather than hardwired into programs and libraries, and is controlled by the TERM
environment variable. This variable is set by whatever terminal monitor program spawns the programs that then use that terminal for its input and output, or sometimes explicitly. For example:- The getty program sets the
TERM
environment variable according to a system database defining what local terminals are attached to what serial ports and what terminal types are provided by local virtual terminals or the local system console. - A dial-up user on a remote terminal is not using the type of terminal that the system commonly expects on that dial-up line, and so manually sets the
TERM
environment variable immediately after login to the correct type. - The SSH server daemon sets the
TERM
environment variable to the same terminal type as the SSH client. - The software terminal emulator, using a pseudoterminal, sets the
TERM
environment variable to specify the type of terminal that it is emulating. Emulated terminals often do not exactly match real terminal hardware, and terminal emulators have type names dedicated for their use. The xterm program setsxterm
as the terminal type, for example. The GNU Screen program setsscreen
as the terminal type.Job control
Line disciplines
Strictly speaking, in Unices a terminal device comprises the underlying tty device driver, responsible for the physical control of the device hardware via I/O instructions and handling device interrupt requests for character input and output, and the line discipline. A line discipline is independent of the actual device hardware, and the same line discipline can be used for a terminal concentrator device responsible for multiple controlling terminals as for a pseudoterminal. In fact, the line discipline are the same across all terminal devices. It is the line discipline that is responsible for local echo, line editing, processing of input modes, processing of output modes, and character mapping. All these things are independent of the actual hardware, dealing as they do in the simple abstractions provided by tty device drivers: transmit a character, receive a character, set various hardware states.In Seventh Edition Unix, BSD systems and derivatives including macOS, and Linux, each terminal device can be switched amongst multiple line disciplines. In the AT&T STREAMS system, line disciplines are STREAMS modules that may be pushed onto and popped off a STREAMS I/O stack.
History
The POSIX terminal interface is derived from the terminal interfaces of various Unix systems.Early Unices: Seventh Edition Unix
The terminal interface provided by Unix 32V and Seventh Edition Unix, and also presented by BSD version 4 as the old terminal driver, was a simple one, largely geared towards teletypewriters as terminals. Input was entered a line at a time, with the terminal driver in the operating system providing simple line editing capabilities. A buffer was maintained by the kernel in which editing took place. Applications reading terminal input would receive the contents of the buffer only when the key was pressed on the terminal to end line editing. The key sent from the terminal to the system would erase the entire current contents of the editing buffer, and would be normally displayed as an '@' symbol followed by a newline sequence to move the print position to a fresh blank line. The key sent from the terminal to the system would erase the last character from the end of the editing buffer, and would be normally displayed as an '#' symbol, which users would have to recognize as denoting a "rubout" of the preceding character.From a programming point of view, a terminal device had transmit and receive baud rates, "erase" and "kill" characters, "interrupt" and "quit" characters, "start" and "stop" characters, an "end of file" character and various basic mode flags determining whether local echo was emulated by the kernel's terminal driver, whether modem flow control was enabled, the lengths of various output delays, mapping for the carriage return character, and the three input modes.
The three input modes were:
;line mode :
In line mode the line discipline performs all line editing functions and recognizes the "interrupt" and "quit" control characters and transforms them into signals sent to processes. Applications programs reading from the terminal receive entire lines, after line editing has been completed by the user pressing return.
;cbreak mode:
cbreak mode is one of two character-at-a-time modes. The line discipline performs no line editing, and the control sequences for line editing functions are treated as normal character input. Applications programs reading from the terminal receive characters immediately, as soon as they are available in the input queue to be read. However, the "interrupt" and "quit" control characters, as well as modem flow control characters, are still handled specially and stripped from the input stream.
;raw mode:raw mode is the other of the two character-at-a-time modes. The line discipline performs no line editing, and the control sequences for both line editing functions and the various special characters are treated as normal character input. Applications programs reading from the terminal receive characters immediately, and receive the entire character stream unaltered, just as it came from the terminal device itself.
The programmatic interface for querying and modifying all of these modes and control characters was the
ioctl
system call. and gtty
system calls of Sixth Edition Unix.) Although the "erase" and "kill" characters were modifiable from their defaults of and, for many years they were the pre-set defaults in the terminal device drivers, and on many Unix systems, which only altered terminal device settings as part of the login process, in system login scripts that ran after the user had entered username and password, any mistakes at the login and password prompts had to be corrected using the historical editing key characters inherited from teletypewriter terminals.BSD: the advent of job control
With the BSD Unices came job control, and a new terminal driver with extended capabilities. These extensions comprised additional special characters:- The "suspend" and "delayed suspend" characters caused the generation of a new
SIGTSTP
signal to processes in the terminal's controlling process group. - The "word erase", "literal next", and "reprint" characters performed additional line editing functions. "word erase" erased the last word at the end of the line editing buffer. "literal next" allowed any special character to be entered into the line editing buffer. "reprint" caused the line discipline to reprint the current contents of the line editing buffer on a new line.
ioctl
system call, which its creators described as a "rather cluttered interface". All of the original Seventh Edition Unix functionality was retained, and the new functionality was added via additional ioctl
operation codes, resulting in a programmatic interface that had clearly grown, and that presented some duplication of functionality.System III and System V
introduced a new programming interface that combined Seventh Edition's separateioctl
operations to get and set flags and to get and set control characters into calls that used a termio
structure to hold both flags and control characters and that could get them in a single operation and set them in another single operation. It also split some of the flags from the Seventh Edition interface into multiple separate flags, and added some additional capabilities, although it did not support job control or the cooked-mode enhancements of 4BSD. For example, it replaced the "cooked", "cbreak", and "raw" modes of Seventh Edition with different abstractions. The recognition of signal-generating characters is independent of input mode, and there are only the two input modes: canonical and non-canonical. System III's successors, including System V, used the same interface.
POSIX: Consolidation and abstraction
One of the major problems that the POSIX standard addressed with its definition of a general terminal interface was the plethora of programmatic interfaces. Although by the time of the standard the behaviour of terminals was fairly uniform from system to system, most Unices having adopted the notions of line disciplines and the BSD job control capabilities, the programmatic interface to terminals via theioctl
system call was a mess. Different Unices supplied different ioctl
operations, with different names, and different flags. Portable source code had to contain a significant amount of conditional compilation to accommodate the differences across software platforms, even though they were all notionally Unix.The POSIX standard replaces the
ioctl
system entirely, with a set of library functions with standardized names and parameters. The termio
data structure of System V Unix was used as a template for the POSIX termios
data structure, whose fields were largely unchanged except that they now used alias data types for specifying the fields, allowing them to be easily ported across multiple processor architectures by implementors, rather than explicitly requiring the unsigned short
and char
data types of the C and C++ programming languages.POSIX also introduced support for job control, with the
termios
structure containing suspend and delayed-suspend characters in addition to the control characters supported by System III and System V. It did not add any of the cooked-mode extensions from BSD.What the standard defines
Controlling terminals and process groups
Each process in the system has either a single controlling terminal, or no controlling terminal at all. A process inherits its controlling terminal from its parent, and the only operations upon a process are acquiring a controlling terminal, by a process that has no controlling terminal, and relinquishing it, by a process that has a controlling terminal.No portable way of acquiring a controlling terminal is defined, the method being implementation defined. The standard defines the
O_NOCTTY
flag for the open
system call, which is the way of preventing what is otherwise the conventional way of acquiring a controlling terminal but leaves its conventional semantics optional.Each process also is a member of a process group. Each terminal device records a process group that is termed its foreground process group. The process groups control terminal access and signal delivery. Signals generated at the terminal are sent to all processes that are members of the terminal's foreground process group.
read
and write
I/O operations on a terminal by a process that is not a member of the terminal's foreground process group will and may optionally cause signals to be sent to the invoking process. Various terminal-mode-altering library functions have the same behaviour as write
, except that they always generate the signals, even if that functionality is turned off for write
itself.The termios
data structure
The data structure used by all of the terminal library calls is the termios
structure, whose C and C++ programming language definition is as follows:The order of the fields within the
termios
structure is not defined, and implementations are allowed to add non-standard fields. Indeed, implementations have to add non-standard fields for recording input and output baud rates. These are recorded in the structure, in an implementation-defined form, and accessed via accessor functions, rather than by direct manipulation of the field values, as is the case for the standardized structure fields.The data type aliases
tcflag_t
and cc_t
, as well as the symbolic constant NCCS
and a whole load of symbolic constants for the various mode flags, control character names, and baud rates, are all defined in a standard header termios.h
. The structure's fields are :
;
c_iflag
:input mode flags for controlling input parity, input newline translation, modem flow control, 8-bit cleanliness, and response to a "break" condition;
c_oflag
:output mode flags for controlling implementation-defined output postprocessing, output newline translation, and output delays after various control characters have been sent;
c_cflag
:terminal hardware control flags for controlling the actual terminal device rather than the line discipline: the number of bits in a character, parity type, hangup control, and serial line flow control;
c_lflag
:local control flags for controlling the line discipline rather than the terminal hardware: canonical mode, echo modes, signal-generation character recognition and handling, and enabling the generation of the SIGTTOU
signal by the write
system callThe library functions are :
;
tcgetattr
:query a terminal device's current attribute settings into a termios
structure;
tcsetattr
:set a terminal device's current attribute settings from a termios
structure, optionally waiting for queued output to drain and flushing queued input;
cfgetispeed
:query the input baud rate from the implementation-defined fields in a termios
structure;
cfgetospeed
:query the output baud rate from the implementation-defined fields in a termios
structure;
cfsetispeed
:set the input baud rate in the implementation-defined fields in a termios
structure;
cfsetospeed
:set the output baud rate in the implementation-defined fields in a termios
structure;
tcsendbreak
:send a modem "break" signal on a serial device terminal;
tcdrain
:wait for queued output to drain;
tcflush
:discard queued input;
tcflow
:change flow control;
tcgetpgrp
:query the terminal's foreground process group;
tcsetpgrp
:set the terminal's foreground process groupSpecial characters
Thec_cc[]
array member of the termios
data structure specifies all of the special characters. The indexes into the array are symbolic constants, one for each special character type, as in the table at right. Non-programmatically modifiable special characters are linefeed and carriage return.
Input processing
Input processing determines the behaviour of theread
system call on a terminal device and the line editing and signal-generation characteristics of the line discipline. Unlike the case of Seventh Edition Unix and BSD version 4, and like the case of System III and System V, line editing operates in one of just two modes: canonical mode and non-canonical mode. The basic difference between them is when, from the point of view of the blocking/non-blocking requirements of the read
system call or fcntl
), data "are available for reading".Canonical mode processing
In canonical mode, data are accumulated in a line editing buffer, and do not become "available for reading" until line editing has been terminated by the user sending a line delimiter character. Line delimiter characters are special characters, and they are end of file, end of line, and linefeed. The former two are settable programmatically, whilst the latter is fixed. The latter two are included in the line editing buffer, whilst the former one is not.More strictly, zero or more lines are accumulated in the line editing buffer, separated by line delimiters, and line editing operates upon the part of the line editing buffer that follows the last line delimiter in the buffer. So, for example, the "erase" character will erase the last character in the line buffer only up to a preceding line delimiter.
Non-canonical mode processing
In non-canonical mode, data are accumulated in a buffer and become "available for reading" according to the values of two input control parameters, thec_cc[MIN]
and c_cc[TIME]
members of the termios
data structure. Both are unsigned quantities. The former specifies a minimum number of characters, and the latter specifies a timeout in tenths of a second. There are four possibilities:;
c_cc[TIME]
and c_cc[MIN]
are both zero;
c_cc[TIME]
is non-zero and c_cc[MIN]
is zero;
c_cc[TIME]
is zero and c_cc[MIN]
is non-zero;
c_cc[TIME]
and c_cc[MIN]
are both non-zeroOutput processing
Output processing is largely unchanged from its System III/System V roots. Output mode control flags determine various options:- Carriage returns may be inserted before each linefeed character, to translate Unix newline semantics to the ASCII semantics that many terminals expect.
- Terminals may be given time to exercise various control codes that would result in physical movements of the carriage that may take significant amounts of time, such as backspaces, horizontal tabs, carriage returns, form feeds, and line feeds.