#ifndef VLIBC_TERMIOS_H #define VLIBC_TERMIOS_H /* * vlibc — . * * General terminal interface (POSIX.1-2008 base): the termios structure and * the tcgetattr/tcsetattr/tcsendbreak/tcdrain/tcflush/tcflow query-and-set * functions plus the cfgetispeed/cfgetospeed/cfsetispeed/cfsetospeed baud * helpers, over the kernel's TCGETS/TCSETS ioctls (SYS_ioctl). * * Level 1 (onlyposix): tcgetattr, tcsetattr, tcsendbreak, tcdrain, * tcflush, tcflow, cfgetispeed, cfgetospeed, * cfsetispeed, cfsetospeed (POSIX base). * Level 2 (muslmimic): cfmakeraw, cfsetspeed (BSD/glibc extensions), * tcgetsid (XSI [CX] — glibc declares it only under * __USE_XOPEN2K8, not base __USE_POSIX). * * struct termios is a byte-for-byte copy of the x86_64 kernel termios * (asm-generic/termbits.h), pinned by the static assertions below. The * kernel TCGETS/TCSETS ioctls copy exactly sizeof(struct termios) bytes of * this layout (verified empirically on this host: TCGETS writes 36 bytes); * any divergence would silently corrupt c_cc. Unlike glibc's 60-byte * userspace struct (NCCS 32 + trailing ispeed/ospeed members), the speed * is carried only in the c_cflag CBAUD/CIBAUD bit fields, exactly as the * kernel encodes it — so the ioctl copies the whole structure both ways * with nothing left stale. * * The baud-rate constants B0..B4000000 are the KERNEL CBAUD encodings * (B9600 is 0x0d, B38400 is 0x0f, B57600 is 0x1001, ...), NOT glibc's * real-numbers-in-speed_t scheme. cfgetospeed()/cfgetispeed() return these * constants and cfsetospeed()/cfsetispeed()/cfsetspeed() accept them, so * a speed round-trips through the c_cflag bits untouched. This is the same * choice musl makes. * * All flag, control-character, baud, and action constants below are Linux * x86_64 kernel-UAPI facts transcribed from asm-generic/termbits.h and * asm-generic/termbits-common.h. The ioctl request numbers (TCGETS, * TCSETS, TCSBRK, TCXONC, TCFLSH, TIOCGSID) are Linux-only and stay * private to src/termios/termios.c, matching the sys/ioctl.h-less layout * of the tree today (they belong to a future ). * * No declaration carries an intent attribute: tcgetattr/tcsetattr &c * perform I/O, and the cf* speed helpers read or write the caller's * termios through a pointer that may alias arbitrary memory — const/pure * would be unsound (same rationale as ). */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* ---- Basic types ---- */ typedef unsigned char cc_t; /* control-character value */ typedef unsigned int speed_t; /* baud rate (a B* constant) */ typedef unsigned int tcflag_t; /* mode-flag bit mask */ /* ---- struct termios (x86_64 kernel layout) ---- */ #define NCCS 19 /* control-character slots (kernel UAPI) */ struct termios { tcflag_t c_iflag; /* 0: input mode flags */ tcflag_t c_oflag; /* 4: output mode flags */ tcflag_t c_cflag; /* 8: control mode flags */ tcflag_t c_lflag; /* 12: local mode flags */ cc_t c_line; /* 16: line discipline */ cc_t c_cc[NCCS]; /* 17: control characters */ }; /* Pin the kernel layout (TCGETS/TCSETS copy this exact size and shape). */ _Static_assert(sizeof(struct termios) == 36, "struct termios must match the x86_64 kernel layout"); _Static_assert(offsetof(struct termios, c_lflag) == 12, "c_lflag must sit at offset 12"); _Static_assert(offsetof(struct termios, c_line) == 16, "c_line must sit at offset 16"); _Static_assert(offsetof(struct termios, c_cc) == 17, "c_cc must sit at offset 17"); /* ---- Control characters (indices into c_cc) ---- */ #define VINTR 0 /* interrupt character */ #define VQUIT 1 /* quit character */ #define VERASE 2 /* erase character */ #define VKILL 3 /* kill character */ #define VEOF 4 /* end-of-file character */ #define VTIME 5 /* timeout for non-canonical read */ #define VMIN 6 /* min characters for non-canonical read */ #define VSWTC 7 /* switch character (System V) */ #define VSTART 8 /* start character */ #define VSTOP 9 /* stop character */ #define VSUSP 10 /* suspend character */ #define VEOL 11 /* alternate end-of-line character */ #define VREPRINT 12 /* reprint character */ #define VDISCARD 13 /* discard character */ #define VWERASE 14 /* word-erase character */ #define VLNEXT 15 /* literal-next character */ #define VEOL2 16 /* alternate end-of-line character */ /* ---- c_iflag: input mode flags ---- */ #define IGNBRK 0x0001 /* ignore break condition */ #define BRKINT 0x0002 /* signal interrupt on break */ #define IGNPAR 0x0004 /* ignore characters with parity errors */ #define PARMRK 0x0008 /* mark parity and framing errors */ #define INPCK 0x0010 /* enable input parity check */ #define ISTRIP 0x0020 /* strip 8th bit off characters */ #define INLCR 0x0040 /* map NL to CR on input */ #define IGNCR 0x0080 /* ignore CR */ #define ICRNL 0x0100 /* map CR to NL on input */ #define IUCLC 0x0200 /* map uppercase to lowercase on input */ #define IXON 0x0400 /* enable start/stop output control */ #define IXANY 0x0800 /* any character will restart after stop */ #define IXOFF 0x1000 /* enable start/stop input control */ #define IMAXBEL 0x2000 /* ring bell on input queue full */ #define IUTF8 0x4000 /* input is UTF-8 */ /* ---- c_oflag: output mode flags ---- */ #define OPOST 0x0001 /* perform output processing */ #define OLCUC 0x0002 /* map lowercase to uppercase on output */ #define ONLCR 0x0004 /* map NL to CR-NL on output */ #define OCRNL 0x0008 /* map CR to NL on output */ #define ONOCR 0x0010 /* no CR output at column 0 */ #define ONLRET 0x0020 /* NL performs CR function on output */ #define OFILL 0x0040 /* use fill characters for delay */ #define OFDEL 0x0080 /* fill is DEL, else NUL */ #define NLDLY 0x0100 /* newline delay mask */ #define NL0 0x0000 #define NL1 0x0100 #define CRDLY 0x0600 /* carriage-return delay mask */ #define CR0 0x0000 #define CR1 0x0200 #define CR2 0x0400 #define CR3 0x0600 #define TABDLY 0x1800 /* horizontal-tab delay mask */ #define TAB0 0x0000 #define TAB1 0x0800 #define TAB2 0x1000 #define TAB3 0x1800 #define XTABS 0x1800 /* TAB3: expand tabs to spaces */ #define BSDLY 0x2000 /* backspace delay mask */ #define BS0 0x0000 #define BS1 0x2000 #define VTDLY 0x4000 /* vertical-tab delay mask */ #define VT0 0x0000 #define VT1 0x4000 #define FFDLY 0x8000 /* form-feed delay mask */ #define FF0 0x0000 #define FF1 0x8000 /* ---- c_cflag: control mode flags ---- */ #define CBAUD 0x100f /* baud-rate mask (includes CBAUDEX) */ #define CSIZE 0x0030 /* character-size mask */ #define CS5 0x0000 /* 5 bits */ #define CS6 0x0010 /* 6 bits */ #define CS7 0x0020 /* 7 bits */ #define CS8 0x0030 /* 8 bits */ #define CSTOPB 0x0040 /* two stop bits, else one */ #define CREAD 0x0080 /* enable receiver */ #define PARENB 0x0100 /* enable parity */ #define PARODD 0x0200 /* odd parity, else even */ #define HUPCL 0x0400 /* hang up on last close */ #define CLOCAL 0x0800 /* ignore modem status lines */ #define CBAUDEX 0x1000 /* extended baud-rate mask (above B38400) */ #define CRTSCTS 0x80000000 /* enable RTS/CTS flow control */ /* ---- c_lflag: local mode flags ---- */ #define ISIG 0x0001 /* enable signals */ #define ICANON 0x0002 /* canonical mode (line-buffered) */ #define XCASE 0x0004 /* canonical uppercase/lowercase presentation */ #define ECHO 0x0008 /* enable echo */ #define ECHOE 0x0010 /* echo erase as backspace */ #define ECHOK 0x0020 /* echo KILL */ #define ECHONL 0x0040 /* echo NL */ #define NOFLSH 0x0080 /* disable flush after interrupt/quit/suspend */ #define TOSTOP 0x0100 /* send SIGTTOU on background output */ #define ECHOCTL 0x0200 /* echo control characters as ^X */ #define ECHOPRT 0x0400 /* echo erase as backspace-print-backspace */ #define ECHOKE 0x0800 /* BSD: erase entire line on KILL */ #define FLUSHO 0x1000 /* output is being flushed */ #define PENDIN 0x4000 /* reprint pending input at next read */ #define IEXTEN 0x8000 /* enable implementation-defined input processing */ #define EXTPROC 0x10000 /* external processing */ /* ---- Baud rates (kernel CBAUD encodings — see the header comment) ---- */ #define B0 0x00000000 /* hang up */ #define B50 0x00000001 #define B75 0x00000002 #define B110 0x00000003 #define B134 0x00000004 #define B150 0x00000005 #define B200 0x00000006 #define B300 0x00000007 #define B600 0x00000008 #define B1200 0x00000009 #define B1800 0x0000000a #define B2400 0x0000000b #define B4800 0x0000000c #define B9600 0x0000000d #define B19200 0x0000000e #define B38400 0x0000000f #define B57600 0x00001001 /* CBAUDEX | 1 */ #define B115200 0x00001002 #define B230400 0x00001003 #define B460800 0x00001004 #define B500000 0x00001005 #define B576000 0x00001006 #define B921600 0x00001007 #define B1000000 0x00001008 #define B1152000 0x00001009 #define B1500000 0x0000100a #define B2000000 0x0000100b #define B2500000 0x0000100c #define B3000000 0x0000100d #define B3500000 0x0000100e #define B4000000 0x0000100f /* ---- tcsetattr optional_actions ---- */ #define TCSANOW 0 /* change immediately */ #define TCSADRAIN 1 /* change after output drains */ #define TCSAFLUSH 2 /* drain output and discard input */ /* ---- tcflush queue_selector ---- */ #define TCIFLUSH 0 /* discard data received but not yet read */ #define TCOFLUSH 1 /* discard data written but not yet transmitted */ #define TCIOFLUSH 2 /* discard both */ /* ---- tcflow action ---- */ #define TCOOFF 0 /* suspend output */ #define TCOON 1 /* restart suspended output */ #define TCIOFF 2 /* transmit a STOP character */ #define TCION 3 /* transmit a START character */ /* ---- Level 1 (POSIX base) ---- */ /* * Store the terminal attributes of the terminal open on fildes into * *termios_p. Return 0 on success, or -1 with errno set (ENOTTY when * fildes is not a terminal, EBADF on a bad descriptor). */ int tcgetattr(int fildes, struct termios *termios_p); /* * Set the terminal attributes of the terminal open on fildes from * *termios_p, applying optional_actions (TCSANOW apply immediately, * TCSADRAIN wait for output to drain, TCSAFLUSH drain and then discard * unread input). Return 0 on success, or -1 with errno set (EINVAL for an * invalid optional_actions, ENOTTY/EBADF as for tcgetattr). */ int tcsetattr(int fildes, int optional_actions, const struct termios *termios_p); /* * Transmit a break condition on the terminal open on fildes. The duration * argument is ignored (POSIX leaves a nonzero duration * implementation-defined). Return 0 on success or -1 with errno set. */ int tcsendbreak(int fildes, int duration); /* * Wait until all output written to the terminal open on fildes has been * transmitted. Return 0 on success or -1 with errno set. */ int tcdrain(int fildes); /* * Discard data written but not yet transmitted (TCOFLUSH), data received * but not yet read (TCIFLUSH), or both (TCIOFLUSH) on the terminal open on * fildes. Return 0 on success or -1 with errno set (EINVAL for an invalid * queue_selector). */ int tcflush(int fildes, int queue_selector); /* * Suspend or restart transmission (TCOOFF/TCOON) or transmit a STOP/START * character (TCIOFF/TCION) on the terminal open on fildes. Return 0 on * success or -1 with errno set (EINVAL for an invalid action). */ int tcflow(int fildes, int action); /* * Return the input baud rate stored in *termios_p (a B* constant), as * encoded in the c_cflag CIBAUD field, or B0 when the input rate is not * separately stored (the kernel then treats it as equal to the output * rate, and cfsetispeed with B0 selects exactly that). */ speed_t cfgetispeed(const struct termios *termios_p); /* * Return the output baud rate stored in *termios_p (a B* constant), as * encoded in the c_cflag CBAUD field. */ speed_t cfgetospeed(const struct termios *termios_p); /* * Store speed as the input baud rate of *termios_p. Accept any value that * fits the CBAUD encoding (B0 means "input rate follows the output rate"); * an out-of-range speed yields -1 with errno EINVAL. */ int cfsetispeed(struct termios *termios_p, speed_t speed); /* * Store speed as the output baud rate of *termios_p. Accept any value that * fits the CBAUD encoding (see cfsetispeed); an out-of-range speed yields * -1 with errno EINVAL. */ int cfsetospeed(struct termios *termios_p, speed_t speed); #if VLIBC_LEVEL_GE(2) /* Level 2 (muslmimic): BSD/glibc extensions and XSI [CX] additions. */ /* * Set *termios_p to the "raw" mode of the old Version-7 terminal driver: * input available character by character, echoing and all special * processing of input and output characters disabled (clear IGNBRK BRKINT * PARMRK ISTRIP INLCR IGNCR ICRNL IXON, clear OPOST, clear ECHO ECHONL * ICANON ISIG IEXTEN, select CS8 and no parity). Does not report errors. */ void cfmakeraw(struct termios *termios_p); /* * Store speed as both the input and the output baud rate of *termios_p * (cfsetospeed then cfsetispeed with the same value). Return 0 on success * or -1 with errno EINVAL for an out-of-range speed. */ int cfsetspeed(struct termios *termios_p, speed_t speed); /* * Return the session id of the session that has the terminal open on * fildes as its controlling terminal, or -1 with errno set when fildes is * not a controlling terminal (ENOTTY). */ pid_t tcgetsid(int fildes); #endif /* VLIBC_LEVEL_GE(2) */ #ifdef __cplusplus } #endif #endif /* VLIBC_TERMIOS_H */