This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit f933738a0b91ea31c8b586667740186e17478fa6
Author: Ricard Rosson <[email protected]>
AuthorDate: Mon Oct 26 20:25:46 2026 +0000

    netutils/telnetd: Anchor 0..2 to /dev/null instead of closing them.
    
    When the daemon is started without standard streams (e.g. spawned by
    nsh_telnetstart() before a USB console device exists), descriptors 0..2
    are free, so socket() can return the listen socket in that range.  The
    "go silent" close(0)..close(2) at the top of the accept loop then closes
    the listen socket itself: every subsequent accept4() fails and the
    daemon serves nothing, while still appearing to run.  The same applies
    to an accepted socket or session driver landing in 0..2, which the
    per-session dup2(0..2) would clobber.
    
    Fix the cause rather than relocating the one descriptor: anchor any free
    slot in 0..2 to /dev/null before creating the listen socket, and in the
    accept loop re-anchor 0..2 to /dev/null instead of closing them.  0..2
    are then always occupied, so no descriptor the daemon creates can be
    allocated in the standard-stream range.
    
    Select DEV_NULL, which DEFAULT_SMALL configurations otherwise leave
    out: without /dev/null the daemon cannot start.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Ricard Rosson <[email protected]>
---
 netutils/telnetd/Kconfig          |  1 +
 netutils/telnetd/telnetd_daemon.c | 47 +++++++++++++++++++++++++++++++++++----
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/netutils/telnetd/Kconfig b/netutils/telnetd/Kconfig
index 896bbd62f..423d218b9 100644
--- a/netutils/telnetd/Kconfig
+++ b/netutils/telnetd/Kconfig
@@ -8,5 +8,6 @@ config NETUTILS_TELNETD
        default n
        depends on NET && NET_TCP
        select NETDEV_TELNET
+       select DEV_NULL
        ---help---
                Enable support for the Telnet daemon.
diff --git a/netutils/telnetd/telnetd_daemon.c 
b/netutils/telnetd/telnetd_daemon.c
index c1512113c..18dfbe5f7 100644
--- a/netutils/telnetd/telnetd_daemon.c
+++ b/netutils/telnetd/telnetd_daemon.c
@@ -81,6 +81,7 @@ int telnetd_daemon(FAR const struct telnetd_config_s *config)
   socklen_t addrlen;
   int listensd;
   int acceptsd;
+  int nullfd;
 #ifdef CONFIG_NET_SOCKOPTS
   int optval;
 #endif
@@ -115,6 +116,31 @@ int telnetd_daemon(FAR const struct telnetd_config_s 
*config)
     }
 #endif /* CONFIG_SCHED_HAVE_PARENT && CONFIG_ENABLE_ALL_SIGNALS */
 
+  /* If the daemon was started without standard streams (e.g. spawned by
+   * nsh_telnetstart() before a USB console exists), descriptors 0..2 are
+   * free and any descriptor created below -- the listen socket, an
+   * accepted socket or a session driver -- could be allocated in the
+   * standard-stream range, where the per-session dup2(0..2) would clobber
+   * it.  Anchor any free slot in 0..2 to /dev/null first so that can
+   * never happen.
+   */
+
+  for (; ; )
+    {
+      nullfd = open("/dev/null", O_RDWR);
+      if (nullfd < 0)
+        {
+          nerr("ERROR: open(/dev/null) failed: %d\n", errno);
+          goto errout;
+        }
+
+      if (nullfd > 2)
+        {
+          close(nullfd);
+          break;
+        }
+    }
+
   /* Create a new TCP socket to use to listen for connections */
 
   listensd = socket(config->d_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
@@ -190,11 +216,24 @@ int telnetd_daemon(FAR const struct telnetd_config_s 
*config)
 #endif
       int drvrfd;
 
-      /* Now go silent. */
+      /* Now go silent: detach from the previous session's driver (or the
+       * startup streams) by re-anchoring 0..2 to /dev/null instead of
+       * closing them.  Closing would leave 0..2 free, and accept4() or
+       * open() below could then allocate into the standard-stream range
+       * where the dup2(0..2) for the next session would clobber it.
+       */
 
-      close(0);
-      close(1);
-      close(2);
+      nullfd = open("/dev/null", O_RDWR);
+      if (nullfd >= 0)
+        {
+          dup2(nullfd, 0);
+          dup2(nullfd, 1);
+          dup2(nullfd, 2);
+          if (nullfd > 2)
+            {
+              close(nullfd);
+            }
+        }
 
       ninfo("Accepting connections on port %d\n", ntohs(config->d_port));
 

Reply via email to