Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 09 Jun 2026 18:08:33 +0000
From:      Nuno Teixeira <eduardo@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-branches@FreeBSD.org
Cc:        PS <ps@mu.org>
Subject:   git: f227afeb3bcc - 2026Q2 - net/eternalterminal: Fix etserver crashes
Message-ID:  <6a2856a1.37824.51ec96a2@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch 2026Q2 has been updated by eduardo:

URL: https://cgit.FreeBSD.org/ports/commit/?id=f227afeb3bcc53fd49cda480d604fe3a1bef5d0c

commit f227afeb3bcc53fd49cda480d604fe3a1bef5d0c
Author:     PS <ps@mu.org>
AuthorDate: 2026-06-09 17:31:36 +0000
Commit:     Nuno Teixeira <eduardo@FreeBSD.org>
CommitDate: 2026-06-09 17:51:04 +0000

    net/eternalterminal: Fix etserver crashes
    
    Add backports to fix etserver crashes on session end and transient errors.
    
    PR:             295956
    MFH:            2026Q2
    (cherry picked from commit db15a1e6558a0fe310a8174ee2381ab8e98d4f60)
---
 net/eternalterminal/Makefile                       |   2 +-
 net/eternalterminal/files/patch-fix-crash-PR295956 | 113 +++++++++++++++++++++
 2 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/net/eternalterminal/Makefile b/net/eternalterminal/Makefile
index b364268b2cef..a905efe559b0 100644
--- a/net/eternalterminal/Makefile
+++ b/net/eternalterminal/Makefile
@@ -1,7 +1,7 @@
 PORTNAME=	eternalterminal
 DISTVERSIONPREFIX=	et-v
 DISTVERSION=	6.2.11
-PORTREVISION=	3
+PORTREVISION=	5
 CATEGORIES=	net
 
 MAINTAINER=	eduardo@FreeBSD.org
diff --git a/net/eternalterminal/files/patch-fix-crash-PR295956 b/net/eternalterminal/files/patch-fix-crash-PR295956
new file mode 100644
index 000000000000..cfe3a864bc9b
--- /dev/null
+++ b/net/eternalterminal/files/patch-fix-crash-PR295956
@@ -0,0 +1,113 @@
+Add backports to fix etserver crashes on session end and transient errors.
+
+Backport from:
+- a2d2e62d8d7b ("terminal: Fix etserver crash on session end due to ECHILD (#748)")
+- c6650d9577f5 ("base: Fix etserver crash on transient accept() errors (#756)")
+
+--- src/base/UnixSocketHandler.cpp.orig	2025-07-22 01:37:18 UTC
++++ src/base/UnixSocketHandler.cpp
+@@ -142,12 +142,28 @@ int UnixSocketHandler::accept(int sockFd) {
+     initSocket(client_sock);
+     VLOG(3) << "Client_socket inserted to activeSockets";
+     return client_sock;
+-  } else if (acceptErrno != EAGAIN && acceptErrno != EWOULDBLOCK) {
++  } else if (isTransientAcceptError(acceptErrno)) {
++    // Transient, per-connection failure: fall through and return -1; the
++    // server loop simply retries on the next iteration.
++  } else {
+     FATAL_FAIL(-1);  // STFATAL with the error
+   }
+ 
+   SetErrno(acceptErrno);
+   return -1;
++}
++
++bool UnixSocketHandler::isTransientAcceptError(int err) {
++  // accept(2) routinely fails for benign, per-connection reasons that must
++  // not abort the whole server:
++  //  - EAGAIN/EWOULDBLOCK: non-blocking socket with no pending connection.
++  //  - ECONNABORTED: the peer reset the connection between landing in the
++  //    listen queue and our accept() call.  Surfaced readily on FreeBSD by
++  //    clients that connect and immediately disconnect (keepalive/reconnect
++  //    churn) and previously aborted etserver.
++  //  - EINTR: the call was interrupted by a signal.
++  return err == EAGAIN || err == EWOULDBLOCK || err == ECONNABORTED ||
++         err == EINTR;
+ }
+ 
+ void UnixSocketHandler::close(int fd) {
+--- src/base/UnixSocketHandler.hpp.orig	2025-07-22 01:37:18 UTC
++++ src/base/UnixSocketHandler.hpp
+@@ -14,6 +14,7 @@ class UnixSocketHandler : public SocketHandler {
+   virtual ssize_t read(int fd, void* buf, size_t count);
+   virtual ssize_t write(int fd, const void* buf, size_t count);
+   virtual int accept(int fd);
++  static bool isTransientAcceptError(int err);
+   virtual void close(int fd);
+   virtual vector<int> getActiveSockets();
+ 
+--- src/terminal/PsuedoUserTerminal.hpp.orig	2025-07-22 01:37:18 UTC
++++ src/terminal/PsuedoUserTerminal.hpp
+@@ -96,7 +96,11 @@ class PsuedoUserTerminal : public UserTerminal {
+     FATAL_FAIL(waitpid(getPid(), &throwaway, WUNTRACED));
+ #else
+     siginfo_t childInfo;
+-    FATAL_FAIL(waitid(P_PID, getPid(), &childInfo, WEXITED));
++    if (getPid() > 0) {
++      if (waitid(P_PID, getPid(), &childInfo, WEXITED) == -1) {
++        LOG(ERROR) << "waitid failed, child already reaped.";
++      }
++    }
+ #endif
+   }
+ 
+--- test/unit_tests/UnixSocketHandlerTest.cpp.orig	2026-06-09 03:43:36 UTC
++++ test/unit_tests/UnixSocketHandlerTest.cpp
+@@ -0,0 +1,47 @@
++#include "PipeSocketHandler.hpp"
++#include "TestHeaders.hpp"
++
++using namespace et;
++
++TEST_CASE("AcceptTransientErrorClassification", "[UnixSocketHandler]") {
++  // The errnos that must be tolerated rather than aborting the server.
++  // ECONNABORTED is the case that crashed etserver on FreeBSD.
++  REQUIRE(UnixSocketHandler::isTransientAcceptError(EAGAIN));
++  REQUIRE(UnixSocketHandler::isTransientAcceptError(EWOULDBLOCK));
++  REQUIRE(UnixSocketHandler::isTransientAcceptError(ECONNABORTED));
++  REQUIRE(UnixSocketHandler::isTransientAcceptError(EINTR));
++
++  // Genuine logic errors must still be treated as fatal.
++  REQUIRE_FALSE(UnixSocketHandler::isTransientAcceptError(EBADF));
++  REQUIRE_FALSE(UnixSocketHandler::isTransientAcceptError(EINVAL));
++  REQUIRE_FALSE(UnixSocketHandler::isTransientAcceptError(ENOTSOCK));
++  REQUIRE_FALSE(UnixSocketHandler::isTransientAcceptError(EFAULT));
++}
++
++TEST_CASE("AcceptDoesNotAbortWhenNoPendingConnection", "[UnixSocketHandler]") {
++  // End-to-end check: accept() on a non-blocking listening socket with no
++  // pending connection fails with EAGAIN/EWOULDBLOCK and must return -1 to the
++  // caller instead of hitting FATAL_FAIL.
++  shared_ptr<PipeSocketHandler> socketHandler(new PipeSocketHandler());
++
++  string tmpPath = GetTempDirectory() + string("et_test_XXXXXXXX");
++  string pipeDirectory = string(mkdtemp(&tmpPath[0]));
++  string pipePath = pipeDirectory + "/pipe";
++
++  SocketEndpoint endpoint;
++  endpoint.set_name(pipePath);
++
++  set<int> serverFds = socketHandler->listen(endpoint);
++  REQUIRE(!serverFds.empty());
++  int serverFd = *serverFds.begin();
++
++  int clientFd = socketHandler->accept(serverFd);
++  REQUIRE(clientFd == -1);
++  REQUIRE((GetErrno() == EAGAIN || GetErrno() == EWOULDBLOCK));
++
++  socketHandler->stopListening(endpoint);
++  // stopListening() only closes the fd; the bound socket file remains, so
++  // remove it before the (now empty) directory.
++  FATAL_FAIL(::remove(pipePath.c_str()));
++  FATAL_FAIL(::remove(pipeDirectory.c_str()));
++}


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a2856a1.37824.51ec96a2>