Linux Terminals Overview & Input Flags (c_iflag)

 

Linux Terminals โ€“ Chapter 62.5
Terminal Flags Deep Dive | Part 1: Overview & Input Flags (c_iflag)
๐Ÿ“š Part 1 of 4
๐Ÿ”ง c_iflag Flags
๐ŸŽฏ Beginner Friendly

What are Terminal Flags?

When you type something in a Linux terminal, a lot of invisible processing happens behind the scenes. The terminal driver controls this processing using a set of flags stored inside a structure called struct termios.

Think of terminal flags as a list of ON/OFF switches. Each switch controls one small behavior โ€” like “should input characters be echoed back?”, “should CR be converted to NL?”, “should parity errors be ignored?” etc.

The struct termios has four flag fields:

Field Full Name Controls
c_iflag Input flags How incoming characters are processed before being given to the program
c_oflag Output flags How characters going out to the terminal screen are processed
c_cflag Control flags Hardware-level settings: baud rate, parity, stop bits, character size
c_lflag Local flags High-level input behavior: echo, canonical mode, signal generation

These flags are read and written using two system calls: tcgetattr() (to fetch current settings) and tcsetattr() (to push new settings).

How Terminal Flags Fit Into Data Flow

Here is how data flows between your keyboard, the terminal driver, and your program:

Keyboard Input โ†’ c_iflag processing โ†’ Line Buffer / Program read()
(Input side: c_iflag transforms characters coming IN)
Program write() โ†’ c_oflag processing โ†’ Terminal Screen Output
(Output side: c_oflag transforms characters going OUT)

The c_cflag handles serial-line level things (baud rate, parity), and c_lflag sits above all of them managing line discipline behavior (echo, canonical mode, etc.).

Keywords in This Part:

struct termios c_iflag tcgetattr tcsetattr ICRNL IXON IGNBRK BRKINT INPCK ISTRIP

Input Flags โ€” c_iflag

These flags control what happens to characters after they arrive at the terminal driver from the keyboard but before they reach your program. Think of it as pre-processing for input.

Flag Default What it does (plain English)
BRKINT ON When a BREAK condition occurs on the line, send SIGINT to the foreground process group
ICRNL ON Convert Carriage Return (CR, \r) to Newline (NL, \n) on input. This is why pressing Enter works correctly even on terminals that send CR.
IGNBRK OFF Completely ignore BREAK conditions (if ON, BRKINT is irrelevant)
IGNCR OFF Ignore (throw away) CR characters on input
IGNPAR OFF Ignore characters that have parity errors
IMAXBEL (ON) Ring the terminal bell when the input queue is full โ€” not widely used today
INLCR OFF Convert NL to CR on input (opposite of ICRNL)
INPCK OFF Enable input parity checking. Works with PARENB in c_cflag.
ISTRIP OFF Strip the 8th bit (bit 7) from every input character. Useful for 7-bit ASCII terminals.
IUTF8 OFF Tell the driver input is in UTF-8 encoding (Linux 2.6.4+). Helps correct backspace in multibyte sequences.
IUCLC OFF Map uppercase to lowercase on input. Only works if IEXTEN is also set. Legacy flag for old uppercase-only terminals.
IXANY OFF Allow any character (not just XON/START) to restart stopped output
IXOFF OFF Enable start/stop input flow control. Driver sends STOP/START bytes to sender when buffer is full/empty.
IXON ON Enable start/stop output flow control. Ctrl+S pauses output, Ctrl+Q resumes it.
PARMRK OFF Mark parity errors with a 2-byte prefix (0377 + 0) so the program can detect them

Most Important Input Flags Explained

ICRNL โ€” CR to NL Mapping

When you press Enter on a keyboard, the terminal physically sends a Carriage Return (CR, ASCII 13, \r). But Unix programs expect a Newline (NL, ASCII 10, \n) to mark end-of-line. When ICRNL is ON (default), the terminal driver silently converts every incoming CR into NL. This is why Unix programs work normally even though the keyboard hardware sends CR.

Keyboard sends: CR (\r) ย โ†’ย  ICRNL converts to: NL (\n) ย โ†’ย  Program receives: \n

IXON โ€” Output Flow Control (Ctrl+S / Ctrl+Q)

When IXON is set (default ON), the terminal supports software flow control for output. If output is scrolling too fast:

  • Press Ctrl+S โ†’ sends STOP character โ†’ terminal pauses output
  • Press Ctrl+Q โ†’ sends START character โ†’ terminal resumes output

This is a pure software mechanism. The characters are not passed to the program โ€” the driver handles them internally.

ISTRIP โ€” Strip 8th Bit

Old 7-bit terminals could not send or receive 8-bit characters. When ISTRIP is ON, the driver sets the 8th bit of every input character to 0 (strips it). Modern terminals are 8-bit, so this is usually OFF.

INPCK / IGNPAR / PARMRK โ€” Parity Handling

Parity is an error-detection mechanism used in serial communications. These three flags work together:

Flag Effect on parity error
IGNPAR ON Discard the bad character entirely
PARMRK ON Pass the bad character to the program prefixed by \377\0 so program knows it was bad
Neither Replace the bad character with a NUL byte (\0)

Code Example: Reading and Modifying c_iflag

Below is a complete C example showing how to read current terminal input flags, disable CR-to-NL mapping (ICRNL), and restore original settings on exit.

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    struct termios orig, modified;

    /* Step 1: Read current terminal attributes */
    if (tcgetattr(STDIN_FILENO, &orig) == -1) {
        perror("tcgetattr");
        exit(EXIT_FAILURE);
    }

    /* Step 2: Copy original and modify c_iflag */
    modified = orig;

    /*
     * Disable ICRNL: stop the driver from mapping CR (\r) to NL (\n).
     * After this, pressing Enter sends \r to the program, not \n.
     */
    modified.c_iflag &= ~ICRNL;

    /*
     * Also disable IXON: stop Ctrl+S / Ctrl+Q from working.
     * Now those keystrokes will be passed to the program.
     */
    modified.c_iflag &= ~IXON;

    /* Step 3: Apply the modified settings (take effect after output flushed) */
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &modified) == -1) {
        perror("tcsetattr");
        exit(EXIT_FAILURE);
    }

    printf("ICRNL disabled. Enter sends CR (\\r) now.\n");
    printf("Press any key (Ctrl+C to test if IXON is really off):\n");

    char buf[10];
    ssize_t n = read(STDIN_FILENO, buf, sizeof(buf));
    if (n > 0) {
        printf("Read %zd bytes. First byte = 0x%02X\n", n, (unsigned char)buf[0]);
        /* 0x0D = CR (\r), 0x0A = NL (\n) */
    }

    /* Step 4: Always restore original settings before exit */
    if (tcsetattr(STDIN_FILENO, TCSANOW, &orig) == -1) {
        perror("tcsetattr restore");
    }

    return 0;
}

Compile and run:

gcc -o iflag_demo iflag_demo.c
./iflag_demo
Key point: Always save the original struct termios and restore it when done. Failing to restore leaves the terminal in a broken state for the user.

TCSAFLUSH vs TCSANOW vs TCSADRAIN

The second argument to tcsetattr() controls when the new settings take effect:

Constant Meaning When to use
TCSANOW Change takes effect immediately Quick changes that can apply right away (e.g., restoring settings)
TCSADRAIN Change takes effect after all pending output is written When output must finish before changing (safe for output flags)
TCSAFLUSH Change after pending output written; discard unread input Best choice when changing input flags โ€” discards stale input

Interview Questions โ€” Terminal Flags & c_iflag

Q1. What is struct termios and what are its four flag fields?

struct termios is the data structure used by Linux to store all terminal I/O settings. Its four flag fields are: c_iflag (input processing), c_oflag (output processing), c_cflag (hardware/control settings), and c_lflag (local/line discipline settings like echo and canonical mode).

Q2. Why does pressing Enter on a Linux terminal typically send \n to programs, even though the keyboard sends \r?

Because the ICRNL flag in c_iflag is ON by default. The terminal driver automatically converts CR (\r, ASCII 13) into NL (\n, ASCII 10) before passing the character to the reading process.

Q3. What does Ctrl+S do in a Linux terminal and how is it implemented?

Ctrl+S pauses terminal output. It is implemented through software flow control using the IXON flag in c_iflag. When IXON is ON, pressing Ctrl+S sends a STOP character which tells the driver to halt output. Pressing Ctrl+Q sends the START character to resume output.

Q4. What is the difference between TCSANOW, TCSADRAIN, and TCSAFLUSH?

TCSANOW applies changes immediately. TCSADRAIN waits until all pending output has been transmitted, then applies changes. TCSAFLUSH does the same as TCSADRAIN but also discards any unread input โ€” making it the safest choice when changing input-related flags.

Q5. What is the purpose of ISTRIP flag and when would you use it?

ISTRIP strips the 8th bit (makes it 0) from every incoming character. It was needed for old 7-bit ASCII terminals that couldn’t handle 8-bit data. On modern 8-bit terminals it should be OFF. It is rarely needed today but may appear in legacy serial communication code.

Q6. How do IGNPAR, PARMRK, and INPCK interact for parity error handling?

INPCK must be ON to enable parity checking. If IGNPAR is ON, characters with parity errors are silently discarded. If PARMRK is ON (and IGNPAR is OFF), the bad character is passed to the program prefixed by the two bytes 0377 and 0, so the program can identify it. If neither flag is set, parity-error characters are replaced with NUL (\0).

Leave a Reply

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