[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ed doesn't handle SIGPIPE
From: |
Andrew L. Moore |
Subject: |
ed doesn't handle SIGPIPE |
Date: |
Thu, 2 Jan 2025 04:53:49 -0500 |
User-agent: |
Mozilla Thunderbird Beta |
Hi Antonio,
ed doesn't handle SIGPIPE and so ungracefully exits upon receiving it.
To illustrate, write a file larger than the pipe buffer (64K on Linux)
to a shell command that terminates before writing can be completed. The
following script demonstrates the issue. Note that if the script is
run interactively, the size of the file that triggers SIGPIPE might be
greater than 64K + 1, i.e., there may be additional buffering.
==== CUT HERE ====
#!/usr/bin/env bash
#
buf_size=$(
{
timeout -s2 1 dd if=<(yes) bs=1 |
sleep 1.1
} 2>&1 |
sed -En 's/^([0-9]+).*out$/\1/p'
)
fallocate -l "$buf_size" buf_size.tmp
fallocate -l $(( ++buf_size )) buf_size_over.tmp
ed buf_size.tmp <<EOF
w !exit
!echo This is reached!
EOF
ed buf_size_over.tmp <<EOF
w !exit
!echo Never reached!
EOF
rm -f buf_size{,_over}.tmp
==== CUT HERE ====
A simple fix is to just ignore SIGPIPE, although I also record the cause
of the interrupted system call. A patch follows. While you're at it,
you might want to revisit your file I/O. For example,
$ /bin/ed -p '* '
* ! exit 1
!
*
does not generate an ed error (as it shouldn't), but
$ /bin/ed -p '* '
* r ! exit 1
! exit 1: Success
?
* h
Cannot close input file
*
That's not right.
-AM
diff --git a/src/io.c b/src/io.c
index 36b2dd9..35b9b65 100644
--- a/src/io.c
+++ b/src/io.c
@@ -540,6 +548,11 @@ get_stream_line (FILE *fp, size_t *len, ed_buffer_t
*ed)
clearerr (fp);
errno = 0;
goto top;
+ case EPIPE:
+ ed->exec->err = _("Broken pipe");
+
+ /* Propagate stream status - don't call clearerr(3). */
+ return NULL;
default:
#ifdef F_GETPATH
@@ -765,6 +786,11 @@ put_stream_line (FILE *fp, const char *s, size_t
len, ed_buffer_t *ed)
clearerr (fp);
errno = 0;
goto top;
+ case EPIPE:
+ ed->exec->err = _("Broken pipe");
+
+ /* Propagate stream status - don't call clearerr(3). */
+ return ERR;
default:
fprintf (stderr, "%s\n", strerror (errno));
ed->exec->err = _("File write error");
diff --git a/src/signal.c b/src/signal.c
index 6929962..6b5f39a 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -126,6 +141,7 @@ init_signal_handler (ed_buffer_t *ed)
if (reliable_signal (SIGCHLD, SIG_DFL) == SIG_ERR
|| reliable_signal (SIGHUP, signal_handler) == SIG_ERR
|| reliable_signal (SIGINT, signal_handler) == SIG_ERR
+ || reliable_signal (SIGPIPE, SIG_IGN) == SIG_ERR
#ifdef SIGWINCH
|| (isatty (0) && reliable_signal (SIGWINCH, signal_handler) ==
SIG_ERR)
#endif
- ed doesn't handle SIGPIPE,
Andrew L. Moore <=