Linux Terminals Terminal Local Flags & termios Fields

 

Linux Terminals – Part 1
Chapter 62 | Terminal Local Flags & termios Fields
8
Flags Covered
c_lflag
termios Field
Part 1/4
Series

What are Terminal Flags?

When you type something in a Linux terminal, the Linux kernel’s terminal driver processes your keystrokes before they reach your program. This processing is controlled by a set of flags stored inside a structure called struct termios.

Think of terminal flags as on/off switches that tell the terminal driver: “Should I echo characters back? Should I handle backspace? Should I check for parity errors?” Each flag controls one specific behavior.

This part focuses on the local flags (stored in the c_lflag field) and output/parity flags found in the termios structure.

Keywords in This Part

termios c_lflag ICANON IEXTEN IMAXBEL IUTF8 NOFLSH OPOST PARENB PARODD IGNPAR INPCK PARMRK

The termios Structure – Quick Refresher

All terminal settings live in a struct termios. Here is what it looks like:

#include <termios.h>

struct termios {
    tcflag_t  c_iflag;   /* Input flags    - control how input arrives */
    tcflag_t  c_oflag;   /* Output flags   - control how output goes out */
    tcflag_t  c_cflag;   /* Control flags  - baud rate, parity bits etc */
    tcflag_t  c_lflag;   /* Local flags    - echo, canonical mode etc */
    cc_t      c_cc[NCCS];/* Special characters - EOF, INTR, ERASE ... */
};
termios Fields Overview
c_iflag
Input control
e.g. strip parity, CR→NL
c_oflag
Output postprocessing
e.g. NL→CR+NL
c_cflag
Line discipline
baud rate, stop bits
c_lflag
Local / line flags
echo, ICANON, signals
c_cc[]
Special characters
EOF, ERASE, INTR…

In this part, most flags we discuss are c_lflag (local flags), but we also touch c_oflag (OPOST) and c_iflag (parity-related flags).

ICANON – Enable Canonical (Line) Mode
c_lflag

ICANON – When set, the terminal collects your keystrokes into a full line before sending them to the program. When cleared, each keystroke goes to the program immediately.

Think of it this way. Imagine you are chatting with someone through a window that has a mail slot. With ICANON set, the window only opens once you have written an entire sentence and pressed Enter — the program gets the whole line. With ICANON clear, every single letter you write slips through the slot instantly — the program sees it right away.

ICANON ON vs OFF – Data Flow
ICANON = 1 (Canonical Mode)
User Types: h e l l o Enter
Line Buffer
→ (on Enter)
Program gets “hello\n”
ICANON = 0 (Noncanonical Mode)
User Types: h
→ immediately
Program gets ‘h’
User Types: e
→ immediately
Program gets ‘e’

When ICANON is set, the following special characters also become active: EOF, EOL, EOL2, ERASE, LNEXT, KILL, REPRINT, WERASE. These let you delete words, kill the whole line, reprint it etc.

Real World Use: Editors like vi, less, and nano turn ICANON off so they can react to single key presses without waiting for Enter. Shell prompts (bash, zsh) normally keep ICANON on.
/* Turning ICANON off programmatically */
#include <termios.h>
#include <unistd.h>

struct termios t;
tcgetattr(STDIN_FILENO, &t);

t.c_lflag &= ~ICANON;   /* Clear ICANON bit - go noncanonical */
t.c_cc[VMIN]  = 1;      /* Read at least 1 byte at a time */
t.c_cc[VTIME] = 0;      /* No timeout */

tcsetattr(STDIN_FILENO, TCSANOW, &t);

IEXTEN – Enable Extended Input Processing
c_lflag

IEXTEN – Enables extra (implementation-defined) input processing. Required for certain special characters to work.

IEXTEN is like an “extras” switch. Some special characters only work when both ICANON and IEXTEN are turned on together. If IEXTEN is off, these characters lose their special meaning.

Characters That Need Both ICANON + IEXTEN
EOL2
Alternate end-of-line character
LNEXT
Literal next (escape special char)
REPRINT
Reprint current input line
WERASE
Erase last word (like Alt+Backspace)
Note: IEXTEN is also needed for the IUCLC flag to take effect. SUSv3 says IEXTEN enables “implementation-defined” functions, so exact behavior can differ between Linux and other UNIX systems.
/* Check if IEXTEN is set */
struct termios t;
tcgetattr(STDIN_FILENO, &t);

if (t.c_lflag & IEXTEN)
    printf("IEXTEN is ON - extended processing active\n");
else
    printf("IEXTEN is OFF\n");

IMAXBEL – Bell on Input Queue Full
c_lflag

IMAXBEL – Supposed to ring the terminal bell (beep) when the input queue fills up. On Linux, this flag is ignored — the bell always rings on a console login when the queue is full.

The input queue is a small buffer where keystrokes wait to be read by your program. If you type very fast and the program is slow to read, this buffer fills up. On Linux, IMAXBEL has no actual effect — the bell always rings in this situation regardless of the flag’s value.

Linux Specific: On Linux, IMAXBEL is effectively a no-op. The bell always rings when the input queue is full during a console login session. Do not rely on this flag for portable code.

IUTF8 – Correct UTF-8 Line Editing
c_lflag

IUTF8 – Enables the terminal driver to correctly handle UTF-8 multi-byte characters during line editing (cooked/canonical mode).

UTF-8 characters like “é”, “ñ”, “中” are stored as 2–4 bytes. Without IUTF8, pressing Backspace might delete only one byte of a multi-byte character, leaving broken bytes in the input buffer. With IUTF8, the terminal driver understands that one character may be multiple bytes, so Backspace deletes the whole character.

Backspace Behavior: IUTF8 OFF vs ON
IUTF8 = 0 (Problem)
Input: “é” (2 bytes: 0xC3 0xA9)
Backspace
Deletes only 0xA9 → broken char!
IUTF8 = 1 (Correct)
Input: “é” (2 bytes: 0xC3 0xA9)
Backspace
Deletes both bytes → clean!
When to use: If your application accepts UTF-8 input in canonical mode (for example, a command-line tool that accepts non-ASCII filenames or text), make sure IUTF8 is set. Most modern Linux terminals set this automatically.
/* Enable IUTF8 for correct multi-byte character handling */
struct termios t;
tcgetattr(STDIN_FILENO, &t);

t.c_lflag |= IUTF8;  /* Set IUTF8 bit */

tcsetattr(STDIN_FILENO, TCSANOW, &t);

NOFLSH – Prevent Queue Flush on Signal
c_lflag

NOFLSH – By default, when Ctrl+C (INTR), Ctrl+\ (QUIT), or Ctrl+Z (SUSP) is typed, both the input and output queues are flushed. Setting NOFLSH prevents this flush.

Think of the input queue as a pipe. When a signal like SIGINT arrives (you pressed Ctrl+C), Linux normally empties the pipe — throwing away any data already typed but not yet read. This makes sense for interactive shells but may cause data loss in certain applications. NOFLSH tells Linux: “Do not throw away queued data when a signal arrives.”

Signal + Queue Flush Behavior
NOFLSH = 0 (Default – flush happens)
User types Ctrl+C
SIGINT sent to program
+
Input & Output queues cleared
NOFLSH = 1 (No flush – queues preserved)
User types Ctrl+C
SIGINT sent to program
+
Queues kept as-is

Signals that trigger this flush: INTR (Ctrl+C → SIGINT), QUIT (Ctrl+\ → SIGQUIT), SUSP (Ctrl+Z → SIGTSTP). This flush happens even if the application has set the signal to be ignored.

/* Prevent queue flush on signals */
struct termios t;
tcgetattr(STDIN_FILENO, &t);

t.c_lflag |= NOFLSH;  /* Set NOFLSH - queues survive signals */

tcsetattr(STDIN_FILENO, TCSANOW, &t);

/* Now even if user presses Ctrl+C, buffered input is not lost */
Use Carefully: NOFLSH is rarely needed. Turning it on means buffered input from before a Ctrl+C will still be read by the program after signal handling — which can confuse interactive programs.

OPOST – Enable Output Postprocessing
c_oflag

OPOST – Master switch for output processing. When set, the flags in c_oflag are applied to output characters. When cleared, output goes to the terminal exactly as written — raw bytes, no translation.

Output postprocessing means the terminal driver can automatically transform your output. The most common example: when your program writes \n (newline), the terminal driver translates it to \r\n (carriage return + newline) because that is what hardware terminals need to move to the start of the next line.

OPOST Effect on Newline Output
OPOST = 1 (Default – translation active)
Program writes “\n”
c_oflag processing
Terminal sees “\r\n”
OPOST = 0 (Raw – no translation)
Program writes “\n”
Terminal sees “\n” only
/* Disable output postprocessing - raw output */
struct termios t;
tcgetattr(STDOUT_FILENO, &t);

t.c_oflag &= ~OPOST;  /* Turn off ALL output processing */

tcsetattr(STDOUT_FILENO, TCSANOW, &t);

/* Now you must write \r\n manually for proper line movement */
write(STDOUT_FILENO, "Hello\r\n", 7);
Key Point: If OPOST is off, all c_oflag flags (ONLCR, OCRNL, ONOCR, etc.) are ignored — they only work when OPOST is set. OPOST is a master gate for output processing.

Parity Flags – PARENB, PARODD, INPCK, IGNPAR, PARMRK

Parity is an error-detection mechanism used in serial communication. A “parity bit” is added to each character to help detect transmission errors. These five flags control whether parity is generated, how it is checked, and what happens when a parity error is detected.

When does this matter? Parity flags are mainly relevant when your Linux system is talking to a serial device (modem, microcontroller, RS-232 device) over a physical serial port (like /dev/ttyS0 or /dev/ttyUSB0). For a normal terminal or SSH session, parity is rarely used.
PARENB
Master enable for parity. Generates parity bits on output, enables checking on input.
PARODD
If set → odd parity. If clear → even parity. Works with PARENB.
INPCK
Enable input parity checking. Without this, parity bits are ignored on input even if PARENB is set.
IGNPAR
Silently discard characters with parity errors. They never reach the reading process.
PARMRK
Mark parity-error chars with prefix bytes 0377 + 0 before passing to the reading process.
Parity Error Handling Decision Tree
Parity error on input char
IGNPAR set? → YES: Character silently discarded
IGNPAR not set, PARMRK set? → YES: Passed as 0377 + 0 + char
PARMRK not set, INPCK set? → YES: Character replaced with NUL (0)
None of the above → Character passed as-is (no checking)
/* Example: Enable even parity on a serial port */
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>

int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);

struct termios t;
tcgetattr(fd, &t);

/* Enable parity generation + checking */
t.c_cflag |= PARENB;   /* Enable parity */
t.c_cflag &= ~PARODD;  /* Even parity (PARODD cleared) */

/* Enable input parity checking */
t.c_iflag |= INPCK;

/* If parity error: mark with 0377+0 prefix */
t.c_iflag |= PARMRK;
t.c_iflag &= ~IGNPAR;  /* Do not ignore - we want to detect errors */

tcsetattr(fd, TCSANOW, &t);
PARMRK trick for 0377: If PARMRK is set and ISTRIP is cleared, a real 0377 (0xFF) byte in the input is doubled to 0377 0377 so the reading process can tell apart a real 0xFF from a parity-error marker.

Quick Summary Table – All Flags in This Part
Flag Field What It Does Default
ICANON c_lflag Collect input into lines; enables backspace, line kill etc. ON
IEXTEN c_lflag Enable extended chars (EOL2, LNEXT, REPRINT, WERASE) ON
IMAXBEL c_lflag Bell on full input queue (ignored on Linux) ON (ignored)
IUTF8 c_lflag Correct UTF-8 multi-byte char handling in line editing Varies
NOFLSH c_lflag Prevent queue flush when INTR/QUIT/SUSP signal is generated OFF
OPOST c_oflag Master gate: enables all output postprocessing ON
PARENB c_cflag Enable parity generation (output) and checking (input) OFF
PARODD c_cflag Use odd parity (if clear: even parity) OFF
INPCK c_iflag Enable input parity checking OFF
IGNPAR c_iflag Silently discard chars with parity errors OFF
PARMRK c_iflag Prefix parity-error chars with 0377+0 OFF

Interview Questions – Terminal Flags
Q1. What is the difference between ICANON and noncanonical mode in Linux terminals?
With ICANON set, the terminal driver buffers input into lines and delivers them to the application only after a line delimiter (Enter, EOF, etc.) is received. Special editing keys like Backspace and Ctrl+U work. With ICANON cleared, each character is made available immediately without waiting for a newline. Applications like text editors use noncanonical mode to handle single keystrokes.
Q2. Why does IEXTEN need to be set along with ICANON for some special characters to work?
IEXTEN enables “extended” input processing. Characters like EOL2, LNEXT, REPRINT, and WERASE are only interpreted by the terminal driver when both ICANON and IEXTEN are active. ICANON enables line-mode processing, and IEXTEN enables the extended set of control characters within that line mode.
Q3. What happens to terminal input and output queues when the user presses Ctrl+C, and how can you prevent it?
By default, when INTR, QUIT, or SUSP characters are typed, the terminal driver sends the corresponding signal AND flushes (discards) both the input and output queues. This happens even if the signal is being ignored. You can prevent this queue flush by setting the NOFLSH flag in c_lflag.
Q4. What is OPOST and what happens if you clear it?
OPOST is the master enable flag for output postprocessing stored in c_oflag. When OPOST is set, the terminal driver applies transformations to output data (e.g., converting \n to \r\n). If OPOST is cleared, all output processing is bypassed — raw bytes are sent directly to the terminal. All other c_oflag flags become inactive when OPOST is off.
Q5. How does the terminal driver handle a character with a parity error when PARMRK is set?
When PARMRK is set and IGNPAR is clear, a character with a parity error is passed to the reading process but prefixed with the two-byte sequence 0377 (0xFF) followed by 0 (NUL). The actual character follows. This allows the application to detect parity errors. As a special case, a real 0377 byte in the input is doubled (0377 0377) to distinguish it from the error marker.
Q6. Why is IUTF8 important for modern applications?
Without IUTF8, the terminal driver treats each byte independently. When a user presses Backspace to delete a multi-byte UTF-8 character (like é = 0xC3 0xA9), only one byte would be removed, leaving a broken incomplete character in the line buffer. IUTF8 tells the driver to treat multi-byte UTF-8 sequences as a single logical character for editing operations like backspace and word-erase.
Q7. What is the difference between PARENB and INPCK?
PARENB (stored in c_cflag) is the master switch that enables parity bit generation for output and allows parity bits to exist on input. INPCK (stored in c_iflag) controls whether the kernel actually checks the parity of incoming characters. You can have PARENB set (generating parity on output) but INPCK clear (not checking incoming parity), which is useful when you want one-directional parity only.

Continue Learning

Next: See these flags in action with tcgetattr() and tcsetattr() — including a real no-echo password input example.

Part 2: tcgetattr / tcsetattr → Visit EmbeddedPathashala

Leave a Reply

Your email address will not be published. Required fields are marked *