This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 81b320b972415095739fd689e49a01626e21240e Author: Marco Casaroli <[email protected]> AuthorDate: Tue Oct 27 09:24:45 2026 +0100 drivers/serial, drivers/net/telnet: Give the special characters in c_cc. TCGETS of a serial port, a pty and a telnet session set only c_cc[VMIN] and c_cc[VTIME] (serial) or nothing: the other entries of c_cc kept what the caller had in its buffer. A program that reads the special characters (readline, stty and getty do) got random values. Now TCGETS gives every entry of c_cc: the INTR and SUSP characters (CONFIG_TTY_SIGINT_CHAR and CONFIG_TTY_SIGTSTP_CHAR at the start), ERASE (DEL) on a serial port, MIN and TIME, and _POSIX_VDISABLE for the characters that the terminal does not act on. TCSETS sets the INTR and SUSP characters, and _POSIX_VDISABLE disables them. A pty pair keeps one set for both ends. <unistd.h> now defines _POSIX_VDISABLE as '\0' (as Linux), which POSIX.1-2008 requires, and fpathconf(_PC_VDISABLE) returns it. This also lets <sys/ttydefaults.h> with TTYDEFCHARS compile. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- Documentation/standards/posix.rst | 2 +- drivers/net/telnet.c | 40 ++++++++++++++++++++++++++++++++++++--- drivers/serial/Kconfig | 6 +++++- drivers/serial/pty.c | 37 ++++++++++++++++++++++++++++++++++-- drivers/serial/serial.c | 37 ++++++++++++++++++++++++++++++++++-- include/nuttx/serial/serial.h | 6 ++++++ include/unistd.h | 7 ++++++- libs/libc/unistd/lib_pathconf.c | 3 +++ 8 files changed, 128 insertions(+), 10 deletions(-) diff --git a/Documentation/standards/posix.rst b/Documentation/standards/posix.rst index 929a1e72e3c..d005b18a510 100644 --- a/Documentation/standards/posix.rst +++ b/Documentation/standards/posix.rst @@ -251,7 +251,7 @@ POSIX.1 Option Requirements +-----------------------------+---------+---------+ | `_POSIX_SAVED_IDS`_ | No | | +-----------------------------+---------+---------+ -| `_POSIX_VDISABLE`_ | No | | +| `_POSIX_VDISABLE`_ | Yes | | +-----------------------------+---------+---------+ | `_POSIX2_CHAR_TERM`_ | ? | | +-----------------------------+---------+---------+ diff --git a/drivers/net/telnet.c b/drivers/net/telnet.c index d227117f69d..b7dd8226aa6 100644 --- a/drivers/net/telnet.c +++ b/drivers/net/telnet.c @@ -32,9 +32,10 @@ #include <fcntl.h> #include <poll.h> #include <errno.h> -#include <nuttx/debug.h> #include <termios.h> +#include <unistd.h> +#include <nuttx/debug.h> #include <nuttx/kmalloc.h> #include <nuttx/kthread.h> #include <nuttx/lib/lib.h> @@ -132,6 +133,12 @@ struct telnet_dev_s #endif #ifdef HAVE_SIGNALS pid_t td_pid; +#endif +#ifdef CONFIG_TTY_SIGINT + cc_t td_vintr; /* c_cc[VINTR] */ +#endif +#ifdef CONFIG_TTY_SIGTSTP + cc_t td_vsusp; /* c_cc[VSUSP] */ #endif tcflag_t td_lflag; /* Local modes */ FAR struct socket td_psock; /* A clone of the internal socket structure */ @@ -268,7 +275,8 @@ static void telnet_check_ctrlchar(FAR struct telnet_dev_s *priv, * signal? */ - if (*buffer == CONFIG_TTY_SIGINT_CHAR) + if (priv->td_vintr != _POSIX_VDISABLE && + (cc_t)*buffer == priv->td_vintr) { /* Yes.. note that the kill is needed and do not put the character * into the Rx buffer. It should not be read as normal data. @@ -284,7 +292,8 @@ static void telnet_check_ctrlchar(FAR struct telnet_dev_s *priv, * signal? */ - if (*buffer == CONFIG_TTY_SIGTSTP_CHAR) + if (priv->td_vsusp != _POSIX_VDISABLE && + (cc_t)*buffer == priv->td_vsusp) { /* Note that the kill is needed and do not put the character * into the Rx buffer. It should not be read as normal data. @@ -1108,6 +1117,12 @@ static int telnet_session(FAR struct telnet_session_s *session) /* Setting terminal attributes */ priv->td_lflag = ECHO; +#ifdef CONFIG_TTY_SIGINT + priv->td_vintr = CONFIG_TTY_SIGINT_CHAR; +#endif +#ifdef CONFIG_TTY_SIGTSTP + priv->td_vsusp = CONFIG_TTY_SIGTSTP_CHAR; +#endif /* Register the driver */ @@ -1221,6 +1236,19 @@ static int telnet_ioctl(FAR struct file *filep, int cmd, unsigned long arg) cfmakeraw(termiosp); termiosp->c_lflag = priv->td_lflag; + + /* The special characters that the session acts on. The others + * are disabled. + */ + + memset(termiosp->c_cc, _POSIX_VDISABLE, sizeof(termiosp->c_cc)); +#ifdef CONFIG_TTY_SIGINT + termiosp->c_cc[VINTR] = priv->td_vintr; +#endif +#ifdef CONFIG_TTY_SIGTSTP + termiosp->c_cc[VSUSP] = priv->td_vsusp; +#endif + termiosp->c_cc[VMIN] = 1; } break; @@ -1232,6 +1260,12 @@ static int telnet_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* Save the termios settings */ priv->td_lflag = termiosp->c_lflag; +#ifdef CONFIG_TTY_SIGINT + priv->td_vintr = termiosp->c_cc[VINTR]; +#endif +#ifdef CONFIG_TTY_SIGTSTP + priv->td_vsusp = termiosp->c_cc[VSUSP]; +#endif if ((priv->td_lflag & ECHO) != 0) { diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3b368991099..5df44cf3e8f 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -451,6 +451,8 @@ config TTY_SIGINT_CHAR ---help--- Use ASCII 0x03 (Ctrl-c) or 0x04 (ctrl-d) inputs to determine whether to send a SIGINT event. Other characters may also be selected. + This is the INTR character (c_cc[VINTR]) of a terminal when it + starts; tcsetattr() can change or disable it. REVISIT: Traditionally Ctrl-C would generate SIGINT. Ctrl-D is the End-of-File character that should close the stream. @@ -489,7 +491,9 @@ config TTY_SIGTSTP_CHAR depends on TTY_SIGTSTP ---help--- Use ASCII 0x1a (Ctrl-z) input to determine whether to send a SIGTSTP - event. Other characters may also be selected. + event. Other characters may also be selected. This is the SUSP + character (c_cc[VSUSP]) of a terminal when it starts; tcsetattr() + can change or disable it. # # Serial console selection diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c index e005afbfbd6..1a0f096ea0f 100644 --- a/drivers/serial/pty.c +++ b/drivers/serial/pty.c @@ -114,6 +114,12 @@ struct pty_devpair_s struct pty_dev_s pp_master; /* Maseter device */ struct pty_dev_s pp_slave; /* Slave device */ +#ifdef CONFIG_TTY_SIGINT + cc_t pp_vintr; /* c_cc[VINTR] */ +#endif +#ifdef CONFIG_TTY_SIGTSTP + cc_t pp_vsusp; /* c_cc[VSUSP] */ +#endif bool pp_susv1; /* SUSv1 or BSD style */ bool pp_locked; /* Slave is locked */ bool pp_unlinked; /* File has been unlinked */ @@ -667,7 +673,8 @@ static ssize_t pty_write(FAR struct file *filep, } #ifdef CONFIG_TTY_SIGINT - if (pid > 0 && ch == CONFIG_TTY_SIGINT_CHAR) + if (pid > 0 && dev->pd_devpair->pp_vintr != _POSIX_VDISABLE && + (cc_t)ch == dev->pd_devpair->pp_vintr) { nxsig_kill(pid, SIGINT); return 1; @@ -675,7 +682,8 @@ static ssize_t pty_write(FAR struct file *filep, #endif #ifdef CONFIG_TTY_SIGTSTP - if (pid > 0 && ch == CONFIG_TTY_SIGTSTP_CHAR) + if (pid > 0 && dev->pd_devpair->pp_vsusp != _POSIX_VDISABLE && + (cc_t)ch == dev->pd_devpair->pp_vsusp) { nxsig_kill(pid, SIGTSTP); return 1; @@ -836,6 +844,19 @@ static int pty_ioctl(FAR struct file *filep, int cmd, unsigned long arg) termiosp->c_iflag = dev->pd_iflag; termiosp->c_oflag = dev->pd_oflag; termiosp->c_lflag = dev->pd_lflag; + + /* The special characters that the pair acts on (one set for + * both ends). The others are disabled. + */ + + memset(termiosp->c_cc, _POSIX_VDISABLE, sizeof(termiosp->c_cc)); +#ifdef CONFIG_TTY_SIGINT + termiosp->c_cc[VINTR] = dev->pd_devpair->pp_vintr; +#endif +#ifdef CONFIG_TTY_SIGTSTP + termiosp->c_cc[VSUSP] = dev->pd_devpair->pp_vsusp; +#endif + termiosp->c_cc[VMIN] = 1; ret = OK; } break; @@ -855,6 +876,12 @@ static int pty_ioctl(FAR struct file *filep, int cmd, unsigned long arg) dev->pd_iflag = termiosp->c_iflag; dev->pd_oflag = termiosp->c_oflag; dev->pd_lflag = termiosp->c_lflag; +#ifdef CONFIG_TTY_SIGINT + dev->pd_devpair->pp_vintr = termiosp->c_cc[VINTR]; +#endif +#ifdef CONFIG_TTY_SIGTSTP + dev->pd_devpair->pp_vsusp = termiosp->c_cc[VSUSP]; +#endif ret = OK; } break; @@ -1183,6 +1210,12 @@ int pty_register2(int minor, bool susv1) devpair->pp_master.pd_pid = INVALID_PROCESS_ID; devpair->pp_slave.pd_pid = INVALID_PROCESS_ID; #endif +#ifdef CONFIG_TTY_SIGINT + devpair->pp_vintr = CONFIG_TTY_SIGINT_CHAR; +#endif +#ifdef CONFIG_TTY_SIGTSTP + devpair->pp_vsusp = CONFIG_TTY_SIGTSTP_CHAR; +#endif /* Register the master device * diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index c151bf194b1..46943e5382a 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -2061,9 +2061,26 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) termiosp->c_iflag = dev->tc_iflag; termiosp->c_oflag = dev->tc_oflag; termiosp->c_lflag = dev->tc_lflag; + + /* The special characters that this layer acts on. The + * others are disabled. ERASE cannot be changed: ICANON + * erases with DEL and with BS. + */ + + memset(termiosp->c_cc, _POSIX_VDISABLE, + sizeof(termiosp->c_cc)); + termiosp->c_cc[VERASE] = ASCII_DEL; +#ifdef CONFIG_TTY_SIGINT + termiosp->c_cc[VINTR] = dev->tc_vintr; +#endif +#ifdef CONFIG_TTY_SIGTSTP + termiosp->c_cc[VSUSP] = dev->tc_vsusp; +#endif #ifdef CONFIG_SERIAL_TERMIOS termiosp->c_cc[VTIME] = dev->timeout; termiosp->c_cc[VMIN] = dev->minread; +#else + termiosp->c_cc[VMIN] = 1; #endif ret = 0; @@ -2083,6 +2100,12 @@ static int uart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) dev->tc_iflag = termiosp->c_iflag; dev->tc_oflag = termiosp->c_oflag; dev->tc_lflag = termiosp->c_lflag; +#ifdef CONFIG_TTY_SIGINT + dev->tc_vintr = termiosp->c_cc[VINTR]; +#endif +#ifdef CONFIG_TTY_SIGTSTP + dev->tc_vsusp = termiosp->c_cc[VSUSP]; +#endif #ifdef CONFIG_SERIAL_TERMIOS dev->timeout = termiosp->c_cc[VTIME]; dev->minread = termiosp->c_cc[VMIN]; @@ -2366,6 +2389,14 @@ int uart_register(FAR const char *path, FAR uart_dev_t *dev) dev->pid = INVALID_PROCESS_ID; #endif +#ifdef CONFIG_TTY_SIGINT + dev->tc_vintr = CONFIG_TTY_SIGINT_CHAR; +#endif + +#ifdef CONFIG_TTY_SIGTSTP + dev->tc_vsusp = CONFIG_TTY_SIGTSTP_CHAR; +#endif + #ifdef CONFIG_TTY_FORCE_PANIC dev->panic_count = 0; #endif @@ -2606,14 +2637,16 @@ int uart_check_special(FAR uart_dev_t *dev, FAR const char *buf, size_t size) #endif #ifdef CONFIG_TTY_SIGINT - if (dev->pid > 0 && buf[i] == CONFIG_TTY_SIGINT_CHAR) + if (dev->pid > 0 && dev->tc_vintr != _POSIX_VDISABLE && + (cc_t)buf[i] == dev->tc_vintr) { return SIGINT; } #endif #ifdef CONFIG_TTY_SIGTSTP - if (dev->pid > 0 && buf[i] == CONFIG_TTY_SIGTSTP_CHAR) + if (dev->pid > 0 && dev->tc_vsusp != _POSIX_VDISABLE && + (cc_t)buf[i] == dev->tc_vsusp) { return SIGTSTP; } diff --git a/include/nuttx/serial/serial.h b/include/nuttx/serial/serial.h index e4238d40a21..66532289862 100644 --- a/include/nuttx/serial/serial.h +++ b/include/nuttx/serial/serial.h @@ -354,6 +354,12 @@ struct uart_dev_s tcflag_t tc_iflag; /* Input modes */ tcflag_t tc_oflag; /* Output modes */ tcflag_t tc_lflag; /* Local modes */ +#ifdef CONFIG_TTY_SIGINT + cc_t tc_vintr; /* c_cc[VINTR] */ +#endif +#ifdef CONFIG_TTY_SIGTSTP + cc_t tc_vsusp; /* c_cc[VSUSP] */ +#endif /* Semaphores & mutex */ diff --git a/include/unistd.h b/include/unistd.h index da114528e14..c7eafe7ed17 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -97,7 +97,12 @@ #undef _POSIX_CHOWN_RESTRICTED #undef _POSIX_NO_TRUNC -#undef _POSIX_VDISABLE + +/* The value of a c_cc entry of struct termios that disables the special + * character. + */ + +#define _POSIX_VDISABLE '\0' #define _POSIX_SYNC_IO 1 #undef _POSIX_ASYNC_IO diff --git a/libs/libc/unistd/lib_pathconf.c b/libs/libc/unistd/lib_pathconf.c index 394d158f616..70078f1969c 100644 --- a/libs/libc/unistd/lib_pathconf.c +++ b/libs/libc/unistd/lib_pathconf.c @@ -139,6 +139,9 @@ long fpathconf(int fildes, int name) case _PC_PRIO_IO: return _POSIX_PRIO_IO; + case _PC_VDISABLE: + return _POSIX_VDISABLE; + default: /* Assume valid but not implemented for the time being */
