Skip to content

Commit

Permalink
write_or_die: raise SIGPIPE when we get EPIPE
Browse files Browse the repository at this point in the history
The write_or_die function will always die on an error,
including EPIPE. However, it currently treats EPIPE
specially by suppressing any error message, and by exiting
with exit code 0.

Suppressing the error message makes some sense; a pipe death
may just be a sign that the other side is not interested in
what we have to say. However, exiting with a successful
error code is not a good idea, as write_or_die is frequently
used in cases where we want to be careful about having
written all of the output, and we may need to signal to our
caller that we have done so (e.g., you would not want a push
whose other end has hung up to report success).

This distinction doesn't typically matter in git, because we
do not ignore SIGPIPE in the first place. Which means that
we will not get EPIPE, but instead will just die when we get
a SIGPIPE. But it's possible for a default handler to be set
by a parent process, or for us to add a callsite inside one
of our few SIGPIPE-ignoring blocks of code.

This patch converts write_or_die to actually raise SIGPIPE
when we see EPIPE, rather than exiting with zero. This
brings the behavior in line with the "normal" case that we
die from SIGPIPE (and any callers who want to check why we
died will see the same thing). We also give the same
treatment to other related functions, including
write_or_whine_pipe and maybe_flush_or_die.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jeff King authored and Junio C Hamano committed Feb 20, 2013
1 parent 090fd4f commit 756e676
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions write_or_die.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
#include "cache.h"

static void check_pipe(int err)
{
if (err == EPIPE) {
signal(SIGPIPE, SIG_DFL);
raise(SIGPIPE);
/* Should never happen, but just in case... */
exit(141);
}
}

/*
* Some cases use stdio, but want to flush after the write
* to get error handling (and to get better interactive
Expand Down Expand Up @@ -34,8 +44,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
return;
}
if (fflush(f)) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
die_errno("write failure on '%s'", desc);
}
}
Expand All @@ -50,17 +59,15 @@ void fsync_or_die(int fd, const char *msg)
void write_or_die(int fd, const void *buf, size_t count)
{
if (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
die_errno("write error");
}
}

int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg)
{
if (write_in_full(fd, buf, count) < 0) {
if (errno == EPIPE)
exit(0);
check_pipe(errno);
fprintf(stderr, "%s: write error (%s)\n",
msg, strerror(errno));
return 0;
Expand Down

0 comments on commit 756e676

Please sign in to comment.