New option sitout-eio

This commit is contained in:
Gerhard Rieger 2023-10-26 18:43:40 +02:00
parent c2196d6f15
commit d10dd8a03e
9 changed files with 59 additions and 14 deletions

View file

@ -45,6 +45,11 @@ Features:
before exit. Signal USR1 logs actual values. before exit. Signal USR1 logs actual values.
Tests: OPTION_STATISTICS SIGUSR1_STATISTICS Tests: OPTION_STATISTICS SIGUSR1_STATISTICS
Added option sitout-eio to specify a timerange in which EIO on the pty
of a sub process is tolerated.
Red Hat issue 1853102 related.
Thanks to Jonathan Casiot for sending an initial patch.
Corrections: Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than When a sub process (EXEC, SYSTEM) terminated with exit code other than
0, its last sent data might have been lost depending on timing of read/ 0, its last sent data might have been lost depending on timing of read/

View file

@ -2823,6 +2823,12 @@ label(OPTION_PTY_INTERVAL)dit(bf(tt(pty-interval=<seconds>)))
periodically checks the HUP condition using tt(poll()) to find if the pty's periodically checks the HUP condition using tt(poll()) to find if the pty's
slave side has been opened. The default polling interval is 1s. Use the slave side has been opened. The default polling interval is 1s. Use the
pty-interval option [link(timeval)(TYPE_TIMEVAL)] to change this value. pty-interval option [link(timeval)(TYPE_TIMEVAL)] to change this value.
label(OPTION_SITOUT_EIO)dit(bf(tt(sitout-eio=<timeval>)))
The login program in Linux closes its tty/pty and reopens it for security
reasons. During this time the pty master would get EIO on I/O operations and
might terminate. With this option socat() tolerates EIO for the specified
time. Please note that in this state socat() blocks traffic in both
directions, even when it is not related to this channel.
enddit() enddit()

View file

@ -547,7 +547,11 @@ ssize_t Read(int fd, void *buf, size_t count) {
_errno = errno; _errno = errno;
if (!diag_in_handler) diag_flush(); if (!diag_in_handler) diag_flush();
#if WITH_SYCLS #if WITH_SYCLS
if (result < 0) {
Debug2("read -> "F_Zd" (errno=%d)", result, _errno);
} else {
Debug1("read -> "F_Zd, result); Debug1("read -> "F_Zd, result);
}
#endif /* WITH_SYCLS */ #endif /* WITH_SYCLS */
errno = _errno; errno = _errno;
return result; return result;

View file

@ -21,6 +21,7 @@ const struct optdesc opt_openpty = { "openpty", NULL, OPT_OPENPTY, GROUP_P
#if HAVE_DEV_PTMX || HAVE_DEV_PTC #if HAVE_DEV_PTMX || HAVE_DEV_PTC
const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC }; const struct optdesc opt_ptmx = { "ptmx", NULL, OPT_PTMX, GROUP_PTY, PH_BIGEN, TYPE_BOOL, OFUNC_SPEC };
#endif #endif
const struct optdesc opt_sitout_eio = { "sitout-eio", NULL, OPT_SITOUT_EIO, GROUP_PTY, PH_INIT, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.exec.sitout_eio), XIO_SIZEOF(para.exec.sitout_eio) };
#if WITH_EXEC || WITH_SYSTEM #if WITH_EXEC || WITH_SYSTEM

View file

@ -10,6 +10,7 @@ extern const struct optdesc opt_fdout;
extern const struct optdesc opt_path; extern const struct optdesc opt_path;
extern const struct optdesc opt_pipes; extern const struct optdesc opt_pipes;
extern const struct optdesc opt_pty; extern const struct optdesc opt_pty;
extern const struct optdesc opt_sitout_eio;
extern const struct optdesc opt_openpty; extern const struct optdesc opt_openpty;
extern const struct optdesc opt_ptmx; extern const struct optdesc opt_ptmx;
extern const struct optdesc opt_stderr; extern const struct optdesc opt_stderr;

1
xio.h
View file

@ -234,6 +234,7 @@ typedef struct single {
struct { struct {
pid_t pid; /* child PID, with EXEC: */ pid_t pid; /* child PID, with EXEC: */
int fdout; /* use fd for output if two pipes */ int fdout; /* use fd for output if two pipes */
struct timeval sitout_eio;
} exec; } exec;
#if WITH_READLINE #if WITH_READLINE
struct { struct {

View file

@ -1482,6 +1482,7 @@ const struct optname optionnames[] = {
#ifdef SIOCSPGRP #ifdef SIOCSPGRP
IF_SOCKET ("siocspgrp", &opt_siocspgrp) IF_SOCKET ("siocspgrp", &opt_siocspgrp)
#endif #endif
IF_PTY ("sitout-eio", &opt_sitout_eio)
IF_TUN ("slave", &opt_iff_slave) IF_TUN ("slave", &opt_iff_slave)
IF_SOCKET ("sndbuf", &opt_so_sndbuf) IF_SOCKET ("sndbuf", &opt_so_sndbuf)
IF_SOCKET ("sndbuf-late", &opt_so_sndbuf_late) IF_SOCKET ("sndbuf-late", &opt_so_sndbuf_late)

View file

@ -644,6 +644,7 @@ enum e_optcode {
#ifdef SIOCSPGRP #ifdef SIOCSPGRP
OPT_SIOCSPGRP, OPT_SIOCSPGRP,
#endif #endif
OPT_SITOUT_EIO,
#ifdef SO_ACCEPTCONN #ifdef SO_ACCEPTCONN
OPT_SO_ACCEPTCONN, OPT_SO_ACCEPTCONN,
#endif /* SO_ACCEPTCONN */ #endif /* SO_ACCEPTCONN */

View file

@ -75,22 +75,47 @@ ssize_t xioread(xiofile_t *file, void *buff, size_t bufsiz) {
break; break;
case XIOREAD_PTY: case XIOREAD_PTY:
{
int eio = 0;
bool m = false; /* loop message printed? */
while (true) {
do { do {
bytes = Read(pipe->fd, buff, bufsiz); bytes = Read(pipe->fd, buff, bufsiz);
} while (bytes < 0 && errno == EINTR); } while (bytes < 0 && errno == EINTR);
if (bytes < 0) { if (bytes < 0) {
_errno = errno; _errno = errno;
if (_errno == EIO) { if (_errno != EIO) {
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)", Error4("read(%d, %p, "F_Zu"): %s", pipe->fd, buff, bufsiz, strerror(_errno));
pipe->fd, buff, bufsiz, strerror(_errno));
return 0;
} else {
Error4("read(%d, %p, "F_Zu"): %s",
pipe->fd, buff, bufsiz, strerror(_errno));
}
errno = _errno; errno = _errno;
return -1; return -1;
} }
if (pipe->para.exec.sitout_eio.tv_sec == 0 &&
pipe->para.exec.sitout_eio.tv_usec == 0) {
Notice4("read(%d, %p, "F_Zu"): %s (probably PTY closed)",
pipe->fd, buff, bufsiz, strerror(_errno));
return 0;
}
if (!m) {
/* Starting first iteration: calc and report */
/* Round up to 10ms */
eio = 100*pipe->para.exec.sitout_eio.tv_sec +
(pipe->para.exec.sitout_eio.tv_usec+9999)/10000;
Notice3("xioread(fd=%d): EIO, sitting out %u.%02lus for recovery", pipe->fd, eio/100, (unsigned long)eio%100);
m = true;
}
poll(NULL, 0, 10);
if (--eio <= 0) {
/* Timeout */
Error4("read(%d, %p, "F_Zu"): %s", pipe->fd, buff, bufsiz, strerror(_errno));
errno = _errno;
return -1;
}
/* Not reached */
} else
break; /* no error */
}
}
return bytes;
break; break;
#if WITH_READLINE #if WITH_READLINE