367 lines
13 KiB
C
367 lines
13 KiB
C
#ifndef VLIBC_TERMIOS_H
|
|
#define VLIBC_TERMIOS_H
|
|
|
|
/*
|
|
* vlibc — <termios.h>.
|
|
*
|
|
* 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 <sys/ioctl.h>).
|
|
*
|
|
* 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 <fcntl.h>).
|
|
*/
|
|
|
|
#include <vlibc/features.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#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 */
|